Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Carousel: Fix autoplay and enable callback on autoplay index change #33291

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

Mitch-At-Work
Copy link
Contributor

@Mitch-At-Work Mitch-At-Work commented Nov 18, 2024

Previous Behavior

No autoplay callback making controlled scenarios not usable with autoplay.
Autoplay would start with 'stopOnInteraction' based on its autoplay value, this caused three issues:

  • stopOnInteraction: true would stop autoplay and not resume it after interactions
  • stopOnInteraction: false would restart autoplay functionality even if autoplay set to false
  • stopOnInteraction was not updated unless a re-init or recreation of Embla occurred, prevented by ref value not driving updates

New Behavior

Autoplay callback enables controlled autoplay callbacks
Autoplay will now be attached always, but conditionally enabled by stop/start calls, removing need for a reinitialize of carousel
Autoplay logic can be paused/resumed without overriding play button state for temporary interaction pauses like focus or mouse hover

@fabricteam
Copy link
Collaborator

fabricteam commented Nov 18, 2024

🕵 fluentui-web-components-v3 No visual regressions between this PR and main

@fabricteam
Copy link
Collaborator

fabricteam commented Nov 18, 2024

🕵 FluentUIV0 No visual regressions between this PR and main

Copy link

github-actions bot commented Nov 18, 2024

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react
ExtendedPicker
96.873 kB
27.893 kB
96.873 kB
27.892 kB

-1 B
react
FloatingPicker
242.366 kB
69.001 kB
242.366 kB
69.002 kB

1 B
react
Pickers
294.366 kB
82.356 kB
294.366 kB
82.357 kB

1 B
react
Fluent UI React (entire library)
1.014 MB
281.718 kB
1.014 MB
281.721 kB

3 B
react
SelectedItemsList
232.878 kB
67.891 kB
232.878 kB
67.893 kB

2 B
react-components
react-components: entire library
1.163 MB
291.211 kB
1.164 MB
291.601 kB
1.415 kB
390 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
global-context
createContext
510 B
328 B
global-context
createContextSelector
537 B
339 B
keyboard-key
keyboard-key package
3.746 kB
1.928 kB
keyboard-keys
Multiple keyCodes
50 B
70 B
keyboard-keys
Multiple keys
87 B
94 B
keyboard-keys
Single key
44 B
64 B
keyboard-keys
Single keyCode
39 B
59 B
priority-overflow
createOverflowManager
4.457 kB
1.856 kB
react
ActivityItem
71.236 kB
23.357 kB
react
Announced
38.489 kB
13.296 kB
react
Autofill
15.42 kB
4.766 kB
react
Breadcrumb
202.318 kB
60.388 kB
react
Button
195.791 kB
56.627 kB
react
ButtonGrid
180.722 kB
54.627 kB
react
Calendar
121.875 kB
37.024 kB
react
Callout
84.323 kB
27.64 kB
react
Check
53.204 kB
17.848 kB
react
Checkbox
59.985 kB
19.903 kB
react
ChoiceGroup
65.494 kB
21.489 kB
react
ChoiceGroupOption
58.767 kB
19.362 kB
react
Coachmark
93.144 kB
29.42 kB
react
Color
7.789 kB
3.127 kB
react
ColorPicker
135.292 kB
42.21 kB
react
ComboBox
252.203 kB
72.291 kB
react
CommandBar
203.359 kB
60.141 kB
react
ContextualMenu
155.243 kB
48.202 kB
react
DatePicker
184.295 kB
56.15 kB
react
DateTimeUtilities
5.244 kB
1.849 kB
react
DetailsList
229.909 kB
65.781 kB
react
Dialog
211.717 kB
63.165 kB
react
Divider
19.603 kB
6.845 kB
react
DocumentCard
217.336 kB
64.44 kB
react
DragDrop
8.343 kB
2.724 kB
react
DraggableZone
34.303 kB
11.511 kB
react
Dropdown
234.251 kB
68.619 kB
react
Fabric
41.745 kB
14.366 kB
react
Facepile
210.893 kB
63.167 kB
react
FocusTrapZone
17.023 kB
5.911 kB
react
FocusZone
55.159 kB
17.492 kB
react
Grid
180.722 kB
54.627 kB
react
GroupedList
135.07 kB
40.7 kB
react
GroupedListV2
122.687 kB
37.788 kB
react
HoverCard
97.16 kB
30.787 kB
react
Icon
51.885 kB
17.272 kB
react
Icons
66.361 kB
24.397 kB
react
Image
46.904 kB
15.707 kB
react
Keytip
81.693 kB
26.766 kB
react
KeytipData
14.032 kB
4.582 kB
react
KeytipLayer
103.474 kB
32.015 kB
react
Keytips
106.238 kB
33.013 kB
react
Label
38.347 kB
13.257 kB
react
Layer
48.099 kB
16.367 kB
react
Link
39.682 kB
13.67 kB
react
List
39.371 kB
12.463 kB
react
MarqueeSelection
74.517 kB
22.433 kB
react
MessageBar
190.869 kB
57.103 kB
react
Modal
93.738 kB
30.271 kB
react
Nav
188.306 kB
56.485 kB
react
OverflowSet
33.385 kB
11.314 kB
react
Overlay
40.902 kB
14.095 kB
react
Panel
201.364 kB
59.98 kB
react
Persona
114.948 kB
36.532 kB
react
PersonaCoin
114.948 kB
36.532 kB
react
PersonaPresence
58.074 kB
19.384 kB
react
Pivot
189.226 kB
57.267 kB
react
Popup
12.294 kB
4.195 kB
react
Positioning
22.807 kB
7.701 kB
react
PositioningContainer
73.85 kB
23.765 kB
react
ProgressIndicator
39.494 kB
13.55 kB
react
Rating
82.12 kB
26.127 kB
react
ResizeGroup
13.338 kB
4.377 kB
react
ResponsiveMode
8.13 kB
2.966 kB
react
ScrollablePane
55.557 kB
17.728 kB
react
SearchBox
189.118 kB
56.68 kB
react
SelectableOption
724 B
413 B
react
Selection
42.444 kB
12.278 kB
react
Separator
35.384 kB
12.146 kB
react
Shimmer
49.259 kB
16.268 kB
react
ShimmeredDetailsList
240.691 kB
68.532 kB
react
Slider
57.651 kB
19.217 kB
react
SpinButton
192.821 kB
57.775 kB
react
Spinner
41.775 kB
14.48 kB
react
Stack
41.734 kB
14.268 kB
react
Sticky
32.599 kB
10.504 kB
react
Styling
46.033 kB
15.135 kB
react
SwatchColorPicker
191.136 kB
58.151 kB
react
TeachingBubble
206.116 kB
61.054 kB
react
Text
36.908 kB
12.822 kB
react
TextField
80.79 kB
25.315 kB
react
Theme
43.493 kB
14.173 kB
react
ThemeGenerator
12.392 kB
4.126 kB
react
TimePicker
242.014 kB
70.049 kB
react
Toggle
46.225 kB
15.986 kB
react
Tooltip
87.437 kB
28.26 kB
react
Utilities
82.931 kB
25.148 kB
react
Viewport
23.888 kB
7.656 kB
react
WeeklyDayPicker
102.017 kB
31.834 kB
react
WindowProvider
1.059 kB
541 B
react-accordion
Accordion (including children components)
106.72 kB
32.714 kB
react-aria
ARIA - Default
237 B
181 B
react-avatar
Avatar
49.303 kB
15.815 kB
react-avatar
AvatarGroup
20.106 kB
7.968 kB
react-avatar
AvatarGroupItem
63.447 kB
20.034 kB
react-badge
Badge
25.954 kB
8.595 kB
react-badge
CounterBadge
26.733 kB
8.872 kB
react-badge
PresenceBadge
25.719 kB
9.457 kB
react-breadcrumb
@fluentui/react-breadcrumb - package
114.291 kB
31.695 kB
react-button
Button
37.174 kB
10.803 kB
react-button
CompoundButton
43.588 kB
12.101 kB
react-button
MenuButton
41.989 kB
12.144 kB
react-button
SplitButton
50.006 kB
13.716 kB
react-button
ToggleButton
53.107 kB
12.561 kB
react-calendar-compat
Calendar Compat
150.095 kB
40.026 kB
react-card
Card - All
101.77 kB
28.772 kB
react-card
Card
94.544 kB
26.951 kB
react-card
CardFooter
14.355 kB
5.79 kB
react-card
CardHeader
16.888 kB
6.669 kB
react-card
CardPreview
14.42 kB
5.922 kB
react-checkbox
Checkbox
35.118 kB
12.077 kB
react-combobox
Combobox (including child components)
104.401 kB
34.205 kB
react-combobox
Dropdown (including child components)
105.025 kB
34.13 kB
react-components
react-components: Button, FluentProvider & webLightTheme
69.21 kB
20.174 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
220.63 kB
63.913 kB
react-components
react-components: FluentProvider & webLightTheme
44.447 kB
14.59 kB
react-datepicker-compat
DatePicker Compat
224.187 kB
63.434 kB
react-dialog
Dialog (including children components)
100.285 kB
30.064 kB
react-divider
Divider
21.328 kB
7.953 kB
react-field
Field
23.399 kB
8.898 kB
react-image
Image
15.36 kB
6.236 kB
react-input
Input
28.014 kB
9.444 kB
react-jsx-runtime
Classic Pragma
1.057 kB
530 B
react-jsx-runtime
JSX Dev Runtime
3.771 kB
1.643 kB
react-jsx-runtime
JSX Runtime
4.367 kB
1.874 kB
react-label
Label
14.671 kB
5.99 kB
react-link
Link
17.326 kB
7.032 kB
react-list-preview
List
89.164 kB
26.599 kB
react-list-preview
ListItem
112.731 kB
33.432 kB
react-menu
Menu (including children components)
152.683 kB
46.128 kB
react-menu
Menu (including selectable components)
155.364 kB
46.61 kB
react-message-bar
MessageBar (all components)
24.878 kB
9.264 kB
react-motion
@fluentui/react-motion - createMotionComponent()
4.303 kB
1.899 kB
react-motion
@fluentui/react-motion - createPresenceComponent()
5.034 kB
2.226 kB
react-motion
@fluentui/react-motion - PresenceGroup
1.714 kB
819 B
react-northstar
Accordion
85.38 kB
26.519 kB
react-northstar
Alert
87.435 kB
26.905 kB
react-northstar
Animation
55.331 kB
17.83 kB
react-northstar
Attachment
86.829 kB
26.7 kB
react-northstar
Avatar
80.264 kB
24.633 kB
react-northstar
Box
75.233 kB
23.813 kB
react-northstar
Breadcrumb
79.908 kB
24.717 kB
react-northstar
Button
83.145 kB
25.952 kB
react-northstar
Card
82.693 kB
25.037 kB
react-northstar
Carousel
105.17 kB
31.873 kB
react-northstar
Chat
154.072 kB
46.878 kB
react-northstar
Checkbox
79.792 kB
25.08 kB
react-northstar
Datepicker
186.639 kB
56.99 kB
react-northstar
Debug
8.801 kB
3.594 kB
react-northstar
Design
36.589 kB
12.067 kB
react-northstar
Dialog
112.046 kB
33.622 kB
react-northstar
Divider
76.604 kB
24.135 kB
react-northstar
Dropdown
198.196 kB
60.223 kB
react-northstar
Embed
81.465 kB
25.425 kB
react-northstar
Flex
47.716 kB
15.443 kB
react-northstar
Form
92.515 kB
28.888 kB
react-northstar
Grid
70.569 kB
22.283 kB
react-northstar
Header
74.741 kB
23.465 kB
react-northstar
Image
73.576 kB
23.333 kB
react-northstar
Input
88.334 kB
27.781 kB
react-northstar
ItemLayout
78.213 kB
24.457 kB
react-northstar
Label
77.905 kB
24.414 kB
react-northstar
Layout
75.378 kB
23.803 kB
react-northstar
List
88.475 kB
27.555 kB
react-northstar
Loader
78.601 kB
24.733 kB
react-northstar
Menu
128.587 kB
40.738 kB
react-northstar
MenuButton
162.993 kB
49.614 kB
react-northstar
Pill
83.707 kB
26.069 kB
react-northstar
Popup
135.304 kB
42.259 kB
react-northstar
Portal
58.326 kB
18.851 kB
react-northstar
Provider
93.129 kB
29.627 kB
react-northstar
RadioGroup
83.27 kB
26.053 kB
react-northstar
Reaction
77.265 kB
24.128 kB
react-northstar
Segment
76.194 kB
23.896 kB
react-northstar
Skeleton
77.75 kB
24.205 kB
react-northstar
Slider
84.258 kB
26.757 kB
react-northstar
SplitButton
178.231 kB
53.438 kB
react-northstar
Status
76.257 kB
24.054 kB
react-northstar
SvgIcon
36.811 kB
11.746 kB
react-northstar
Table
80.784 kB
25.157 kB
react-northstar
Text
74.099 kB
23.511 kB
react-northstar
TextArea
74.233 kB
23.496 kB
react-northstar
Toolbar
175.042 kB
52.844 kB
react-northstar
Tooltip
109.961 kB
35.238 kB
react-northstar
Tree
87.84 kB
27.223 kB
react-northstar
Video
75.399 kB
23.796 kB
react-overflow
hooks only
12.808 kB
4.819 kB
react-persona
Persona
56.194 kB
17.695 kB
react-popover
Popover
128.926 kB
40.326 kB
react-portal
Portal
14.563 kB
5.118 kB
react-portal-compat
PortalCompatProvider
8.39 kB
2.64 kB
react-positioning
usePositioning
27.079 kB
9.71 kB
react-progress
ProgressBar
17.084 kB
6.891 kB
react-provider
FluentProvider
24.623 kB
8.893 kB
react-radio
Radio
32.672 kB
10.343 kB
react-radio
RadioGroup
15.762 kB
6.423 kB
react-select
Select
27.732 kB
10.124 kB
react-slider
Slider
37.52 kB
12.621 kB
react-spinbutton
SpinButton
36.06 kB
11.815 kB
react-spinner
Spinner
25.245 kB
8.539 kB
react-swatch-picker
@fluentui/react-swatch-picker - package
105.086 kB
30.516 kB
react-switch
Switch
35.319 kB
11.314 kB
react-table
DataGrid
161.034 kB
45.71 kB
react-table
Table (Primitives only)
42.666 kB
13.854 kB
react-table
Table as DataGrid
131.869 kB
36.57 kB
react-table
Table (Selection only)
70.536 kB
19.999 kB
react-table
Table (Sort only)
69.179 kB
19.61 kB
react-tag-picker
@fluentui/react-tag-picker - package
184.105 kB
55.426 kB
react-tags
InteractionTag
15.199 kB
6.157 kB
react-tags
Tag
29.072 kB
9.55 kB
react-tags
TagGroup
82.719 kB
24.524 kB
react-teaching-popover
TeachingPopover
90.633 kB
27.604 kB
react-text
Text - Default
17.061 kB
6.723 kB
react-text
Text - Wrappers
20.242 kB
7.048 kB
react-textarea
Textarea
26.572 kB
9.755 kB
react-theme
Single theme token import
69 B
89 B
react-theme
Teams: all themes
35.666 kB
7.453 kB
react-theme
Teams: Light theme
19.642 kB
5.549 kB
react-timepicker-compat
TimePicker
107.39 kB
35.763 kB
react-toast
Toast (including Toaster)
98.335 kB
29.587 kB
react-tooltip
Tooltip
55.917 kB
19.611 kB
react-tree
FlatTree
145.102 kB
41.693 kB
react-tree
PersonaFlatTree
145.79 kB
41.805 kB
react-tree
PersonaTree
142.021 kB
40.623 kB
react-tree
Tree
141.333 kB
40.519 kB
react-utilities
SSRProvider
180 B
160 B
🤖 This report was generated against 94f7b85e933d6358cf30094aa584feb94f85c8c6

@Mitch-At-Work Mitch-At-Work force-pushed the user/mifraser/enable-autoplay-callback branch from f1af038 to f427173 Compare November 18, 2024 22:43
Copy link

Pull request demo site: URL

@Mitch-At-Work Mitch-At-Work marked this pull request as ready for review November 18, 2024 23:31
@Mitch-At-Work Mitch-At-Work requested review from a team as code owners November 18, 2024 23:31
@dmytrokirpa dmytrokirpa self-requested a review November 19, 2024 13:05
@layershifter layershifter self-requested a review November 21, 2024 08:55
@Mitch-At-Work Mitch-At-Work marked this pull request as draft November 21, 2024 23:31
@Mitch-At-Work Mitch-At-Work marked this pull request as ready for review November 22, 2024 20:16
@@ -142,22 +189,27 @@ export function useEmblaCarousel(
}
});

const handleIndexChange = React.useCallback(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type EmblaEventHandler = Parameters<EmblaCarouselType['on']>[1];

// ...

and then we can do:

  const handleIndexChange: EmblaEventHandler = useEventCallback((_, eventType) => {
    const newIndex = emblaApi.current?.selectedScrollSnap() ?? 0;
    const slides = emblaApi.current?.slideNodes();
    const actualIndex = emblaApi.current?.internalEngine().slideRegistry[newIndex][0] ?? 0;

    // We set the active or first index of group on-screen as the selected tabster index
    slides?.forEach((slide, slideIndex) => {
      setTabsterDefault(slide, slideIndex === actualIndex);
    });
    setActiveIndex(newIndex);

    if (eventType === 'autoplay:select') {
      onAutoplayIndexChange?.(null, { event: null, type: 'autoplay', index: newIndex });
    }
  });

🐱

Copy link
Contributor

@dmytrokirpa dmytrokirpa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything's looking good on the v-build side!

Comment on lines +122 to +138
const enableAutoplay = React.useCallback(
(_autoplay: boolean, temporary?: boolean) => {
if (!temporary) {
autoplayRef.current = _autoplay;
}

if (_autoplay && autoplayRef.current) {
// Autoplay should only enable in the case where underlying state is true, temporary should not override
emblaApi.current?.plugins().autoplay?.play();
// Reset after play to ensure timing and any focus/mouse pause state is reset.
resetAutoplay();
} else if (!_autoplay) {
emblaApi.current?.plugins().autoplay?.stop();
}
},
[resetAutoplay],
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const enableAutoplay = React.useCallback(
(_autoplay: boolean, temporary?: boolean) => {
if (!temporary) {
autoplayRef.current = _autoplay;
}
if (_autoplay && autoplayRef.current) {
// Autoplay should only enable in the case where underlying state is true, temporary should not override
emblaApi.current?.plugins().autoplay?.play();
// Reset after play to ensure timing and any focus/mouse pause state is reset.
resetAutoplay();
} else if (!_autoplay) {
emblaApi.current?.plugins().autoplay?.stop();
}
},
[resetAutoplay],
);
const enableAutoplay = React.useCallback(
(autoplay: boolean, temporary?: boolean) => {
if (!temporary) {
autoplayRef.current = autoplay;
}
if (autoplay && autoplayRef.current) {
// Autoplay should only enable in the case where underlying state is true, temporary should not override
emblaApi.current?.plugins().autoplay?.play();
// Reset after play to ensure timing and any focus/mouse pause state is reset.
resetAutoplay();
} else if (!autoplay) {
emblaApi.current?.plugins().autoplay?.stop();
}
},
[resetAutoplay],
);

nit: we don't need _ after the latest changes 🐱

Comment on lines +180 to +181
const _event = new Event('autoplay');
onAutoplayIndexChange?.(_event, { event: _event, type: 'autoplay', index: newIndex });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const _event = new Event('autoplay');
onAutoplayIndexChange?.(_event, { event: _event, type: 'autoplay', index: newIndex });
// There is no event object for autoplay as there is no a DOM event
const noopEvent = new Event('autoplay');
onAutoplayIndexChange?.(noopEvent, { event: noopEvent, type: 'autoplay', index: newIndex });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants