@fluentui/react-carousel 9.3.0 → 9.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/CHANGELOG.md +28 -10
  2. package/dist/index.d.ts +2 -2
  3. package/lib/components/Carousel/useCarousel.js +2 -1
  4. package/lib/components/Carousel/useCarousel.js.map +1 -1
  5. package/lib/components/CarouselAutoplayButton/useCarouselAutoplayButton.js +4 -8
  6. package/lib/components/CarouselAutoplayButton/useCarouselAutoplayButton.js.map +1 -1
  7. package/lib/components/CarouselButton/useCarouselButton.js +1 -2
  8. package/lib/components/CarouselButton/useCarouselButton.js.map +1 -1
  9. package/lib/components/CarouselContext.types.js.map +1 -1
  10. package/lib/components/CarouselViewport/useCarouselViewport.js +45 -2
  11. package/lib/components/CarouselViewport/useCarouselViewport.js.map +1 -1
  12. package/lib/components/useEmblaCarousel.js +102 -83
  13. package/lib/components/useEmblaCarousel.js.map +1 -1
  14. package/lib-commonjs/components/Carousel/useCarousel.js +2 -1
  15. package/lib-commonjs/components/Carousel/useCarousel.js.map +1 -1
  16. package/lib-commonjs/components/CarouselAutoplayButton/useCarouselAutoplayButton.js +3 -7
  17. package/lib-commonjs/components/CarouselAutoplayButton/useCarouselAutoplayButton.js.map +1 -1
  18. package/lib-commonjs/components/CarouselButton/useCarouselButton.js +1 -1
  19. package/lib-commonjs/components/CarouselButton/useCarouselButton.js.map +1 -1
  20. package/lib-commonjs/components/CarouselContext.types.js.map +1 -1
  21. package/lib-commonjs/components/CarouselViewport/useCarouselViewport.js +44 -1
  22. package/lib-commonjs/components/CarouselViewport/useCarouselViewport.js.map +1 -1
  23. package/lib-commonjs/components/useEmblaCarousel.js +101 -83
  24. package/lib-commonjs/components/useEmblaCarousel.js.map +1 -1
  25. package/package.json +6 -5
package/CHANGELOG.md CHANGED
@@ -1,26 +1,44 @@
1
1
  # Change Log - @fluentui/react-carousel
2
2
 
3
- This log was last generated on Mon, 11 Nov 2024 09:55:33 GMT and should not be manually modified.
3
+ This log was last generated on Thu, 28 Nov 2024 09:29:40 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.4.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-carousel_v9.4.0)
8
+
9
+ Thu, 28 Nov 2024 09:29:40 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-carousel_v9.3.1..@fluentui/react-carousel_v9.4.0)
11
+
12
+ ### Minor changes
13
+
14
+ - feat: Add autoplay index change callback and fix autoplay pause on interaction ([PR #33291](https://github.com/microsoft/fluentui/pull/33291) by mifraser@microsoft.com)
15
+
16
+ ## [9.3.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-carousel_v9.3.1)
17
+
18
+ Tue, 12 Nov 2024 09:31:25 GMT
19
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-carousel_v9.3.0..@fluentui/react-carousel_v9.3.1)
20
+
21
+ ### Patches
22
+
23
+ - fix: Enable controlled index to be set to a new card when added ([PR #33177](https://github.com/microsoft/fluentui/pull/33177) by mifraser@microsoft.com)
24
+
7
25
  ## [9.3.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-carousel_v9.3.0)
8
26
 
9
- Mon, 11 Nov 2024 09:55:33 GMT
27
+ Mon, 11 Nov 2024 10:01:08 GMT
10
28
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-carousel_v9.2.0..@fluentui/react-carousel_v9.3.0)
11
29
 
12
30
  ### Minor changes
13
31
 
14
32
  - fix: Drag events now trigger onActiveIndexChange with drag/touch event attached ([PR #33092](https://github.com/microsoft/fluentui/pull/33092) by mifraser@microsoft.com)
15
33
  - feat: Add CarouselViewport to correctly define CarouselSlider within a static container ([PR #33155](https://github.com/microsoft/fluentui/pull/33155) by mifraser@microsoft.com)
16
- - Bump @fluentui/react-aria to v9.13.9 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
17
- - Bump @fluentui/react-button to v9.3.95 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
18
- - Bump @fluentui/react-context-selector to v9.1.69 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
19
- - Bump @fluentui/react-jsx-runtime to v9.0.46 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
20
- - Bump @fluentui/react-shared-contexts to v9.21.0 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
21
- - Bump @fluentui/react-tabster to v9.23.0 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
22
- - Bump @fluentui/react-theme to v9.1.22 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
23
- - Bump @fluentui/react-utilities to v9.18.17 ([PR #31887](https://github.com/microsoft/fluentui/pull/31887) by beachball)
34
+ - Bump @fluentui/react-aria to v9.13.9 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
35
+ - Bump @fluentui/react-button to v9.3.95 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
36
+ - Bump @fluentui/react-context-selector to v9.1.69 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
37
+ - Bump @fluentui/react-jsx-runtime to v9.0.46 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
38
+ - Bump @fluentui/react-shared-contexts to v9.21.0 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
39
+ - Bump @fluentui/react-tabster to v9.23.0 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
40
+ - Bump @fluentui/react-theme to v9.1.22 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
41
+ - Bump @fluentui/react-utilities to v9.18.17 ([PR #33238](https://github.com/microsoft/fluentui/pull/33238) by beachball)
24
42
 
25
43
  ### Patches
26
44
 
package/dist/index.d.ts CHANGED
@@ -139,7 +139,7 @@ export declare type CarouselContextValue = {
139
139
  selectPageByDirection: (event: React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>, direction: 'next' | 'prev') => number;
140
140
  selectPageByIndex: (event: React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>, value: number, jump?: boolean) => void;
141
141
  subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;
142
- enableAutoplay: (autoplay: boolean) => void;
142
+ enableAutoplay: (autoplay: boolean, temporary?: boolean) => void;
143
143
  resetAutoplay: () => void;
144
144
  containerRef?: React_2.RefObject<HTMLDivElement>;
145
145
  viewportRef?: React_2.RefObject<HTMLDivElement>;
@@ -152,7 +152,7 @@ export declare type CarouselContextValues = {
152
152
  carousel: CarouselContextValue;
153
153
  };
154
154
 
155
- export declare type CarouselIndexChangeData = (EventData<'click', React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>> | EventData<'focus', React_2.FocusEvent> | EventData<'drag', PointerEvent | MouseEvent>) & {
155
+ export declare type CarouselIndexChangeData = (EventData<'click', React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>> | EventData<'focus', React_2.FocusEvent> | EventData<'drag', PointerEvent | MouseEvent> | EventData<'autoplay', Event>) & {
156
156
  /**
157
157
  * The index to be set after event has occurred.
158
158
  */
@@ -25,7 +25,8 @@ import { useAnnounce } from '@fluentui/react-shared-contexts';
25
25
  watchDrag: draggable,
26
26
  containScroll: whitespace ? false : 'keepSnaps',
27
27
  motion,
28
- onDragIndexChange: onActiveIndexChange
28
+ onDragIndexChange: onActiveIndexChange,
29
+ onAutoplayIndexChange: onActiveIndexChange
29
30
  });
30
31
  const selectPageByElement = useEventCallback((event, element, jump)=>{
31
32
  const foundIndex = carouselApi.scrollToElement(element, jump);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Carousel/useCarousel.ts"],"sourcesContent":["import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport {\n getIntrinsicElementProps,\n slot,\n useEventCallback,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselProps, CarouselState } from './Carousel.types';\nimport type { CarouselContextValue } from '../CarouselContext.types';\nimport { useEmblaCarousel } from '../useEmblaCarousel';\nimport { useAnnounce } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render Carousel.\n *\n * The returned state can be modified with hooks such as useCarouselStyles_unstable,\n * before being passed to renderCarousel_unstable.\n *\n * @param props - props from this instance of Carousel\n * @param ref - reference to root HTMLDivElement of Carousel\n */\nexport function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDivElement>): CarouselState {\n 'use no memo';\n\n const {\n align = 'center',\n circular = false,\n onActiveIndexChange,\n groupSize = 'auto',\n draggable = false,\n whitespace = false,\n announcement,\n motion = 'slide',\n } = props;\n\n const { dir } = useFluent();\n const { activeIndex, carouselApi, containerRef, viewportRef, subscribeForValues, enableAutoplay, resetAutoplay } =\n useEmblaCarousel({\n align,\n direction: dir,\n loop: circular,\n slidesToScroll: groupSize,\n defaultActiveIndex: props.defaultActiveIndex,\n activeIndex: props.activeIndex,\n watchDrag: draggable,\n containScroll: whitespace ? false : 'keepSnaps',\n motion,\n onDragIndexChange: onActiveIndexChange,\n });\n\n const selectPageByElement: CarouselContextValue['selectPageByElement'] = useEventCallback((event, element, jump) => {\n const foundIndex = carouselApi.scrollToElement(element, jump);\n onActiveIndexChange?.(event, { event, type: 'focus', index: foundIndex });\n\n return foundIndex;\n });\n\n const selectPageByIndex: CarouselContextValue['selectPageByIndex'] = useEventCallback((event, index, jump) => {\n carouselApi.scrollToIndex(index, jump);\n\n onActiveIndexChange?.(event, { event, type: 'click', index });\n });\n\n const selectPageByDirection: CarouselContextValue['selectPageByDirection'] = useEventCallback((event, direction) => {\n const nextPageIndex = carouselApi.scrollInDirection(direction);\n onActiveIndexChange?.(event, { event, type: 'click', index: nextPageIndex });\n\n return nextPageIndex;\n });\n\n const mergedContainerRef = useMergedRefs(ref, containerRef);\n\n // Announce carousel updates\n const announcementTextRef = React.useRef<string>('');\n const totalNavLength = React.useRef<number>(0);\n const navGroupRef = React.useRef<number[][]>([]);\n\n const { announce } = useAnnounce();\n\n const updateAnnouncement = useEventCallback(() => {\n if (totalNavLength.current <= 0 || !announcement) {\n // Ignore announcements until slides discovered\n return;\n }\n\n const announcementText = announcement(activeIndex, totalNavLength.current, navGroupRef.current);\n\n if (announcementText !== announcementTextRef.current) {\n announcementTextRef.current = announcementText;\n announce(announcementText, { polite: true });\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n // Subscribe to any non-index carousel state changes\n return subscribeForValues(data => {\n if (totalNavLength.current <= 0 && data.navItemsCount > 0 && announcement) {\n const announcementText = announcement(data.activeIndex, data.navItemsCount, data.groupIndexList);\n // Initialize our string to prevent updateAnnouncement from reading an initial load\n announcementTextRef.current = announcementText;\n }\n totalNavLength.current = data.navItemsCount;\n navGroupRef.current = data.groupIndexList;\n updateAnnouncement();\n });\n }, [subscribeForValues, updateAnnouncement, announcement]);\n\n useIsomorphicLayoutEffect(() => {\n updateAnnouncement();\n }, [activeIndex, updateAnnouncement]);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: mergedContainerRef,\n role: 'region',\n ...props,\n }),\n { elementType: 'div' },\n ),\n\n activeIndex,\n circular,\n containerRef: mergedContainerRef,\n viewportRef,\n selectPageByElement,\n selectPageByDirection,\n selectPageByIndex,\n subscribeForValues,\n enableAutoplay,\n resetAutoplay,\n };\n}\n"],"names":["useFluent_unstable","useFluent","getIntrinsicElementProps","slot","useEventCallback","useIsomorphicLayoutEffect","useMergedRefs","React","useEmblaCarousel","useAnnounce","useCarousel_unstable","props","ref","align","circular","onActiveIndexChange","groupSize","draggable","whitespace","announcement","motion","dir","activeIndex","carouselApi","containerRef","viewportRef","subscribeForValues","enableAutoplay","resetAutoplay","direction","loop","slidesToScroll","defaultActiveIndex","watchDrag","containScroll","onDragIndexChange","selectPageByElement","event","element","jump","foundIndex","scrollToElement","type","index","selectPageByIndex","scrollToIndex","selectPageByDirection","nextPageIndex","scrollInDirection","mergedContainerRef","announcementTextRef","useRef","totalNavLength","navGroupRef","announce","updateAnnouncement","current","announcementText","polite","data","navItemsCount","groupIndexList","components","root","always","role","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../src/components/Carousel/useCarousel.ts"],"sourcesContent":["import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport {\n getIntrinsicElementProps,\n slot,\n useEventCallback,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselProps, CarouselState } from './Carousel.types';\nimport type { CarouselContextValue } from '../CarouselContext.types';\nimport { useEmblaCarousel } from '../useEmblaCarousel';\nimport { useAnnounce } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render Carousel.\n *\n * The returned state can be modified with hooks such as useCarouselStyles_unstable,\n * before being passed to renderCarousel_unstable.\n *\n * @param props - props from this instance of Carousel\n * @param ref - reference to root HTMLDivElement of Carousel\n */\nexport function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDivElement>): CarouselState {\n 'use no memo';\n\n const {\n align = 'center',\n circular = false,\n onActiveIndexChange,\n groupSize = 'auto',\n draggable = false,\n whitespace = false,\n announcement,\n motion = 'slide',\n } = props;\n\n const { dir } = useFluent();\n const { activeIndex, carouselApi, containerRef, viewportRef, subscribeForValues, enableAutoplay, resetAutoplay } =\n useEmblaCarousel({\n align,\n direction: dir,\n loop: circular,\n slidesToScroll: groupSize,\n defaultActiveIndex: props.defaultActiveIndex,\n activeIndex: props.activeIndex,\n watchDrag: draggable,\n containScroll: whitespace ? false : 'keepSnaps',\n motion,\n onDragIndexChange: onActiveIndexChange,\n onAutoplayIndexChange: onActiveIndexChange,\n });\n\n const selectPageByElement: CarouselContextValue['selectPageByElement'] = useEventCallback((event, element, jump) => {\n const foundIndex = carouselApi.scrollToElement(element, jump);\n onActiveIndexChange?.(event, { event, type: 'focus', index: foundIndex });\n\n return foundIndex;\n });\n\n const selectPageByIndex: CarouselContextValue['selectPageByIndex'] = useEventCallback((event, index, jump) => {\n carouselApi.scrollToIndex(index, jump);\n\n onActiveIndexChange?.(event, { event, type: 'click', index });\n });\n\n const selectPageByDirection: CarouselContextValue['selectPageByDirection'] = useEventCallback((event, direction) => {\n const nextPageIndex = carouselApi.scrollInDirection(direction);\n onActiveIndexChange?.(event, { event, type: 'click', index: nextPageIndex });\n\n return nextPageIndex;\n });\n\n const mergedContainerRef = useMergedRefs(ref, containerRef);\n\n // Announce carousel updates\n const announcementTextRef = React.useRef<string>('');\n const totalNavLength = React.useRef<number>(0);\n const navGroupRef = React.useRef<number[][]>([]);\n\n const { announce } = useAnnounce();\n\n const updateAnnouncement = useEventCallback(() => {\n if (totalNavLength.current <= 0 || !announcement) {\n // Ignore announcements until slides discovered\n return;\n }\n\n const announcementText = announcement(activeIndex, totalNavLength.current, navGroupRef.current);\n\n if (announcementText !== announcementTextRef.current) {\n announcementTextRef.current = announcementText;\n announce(announcementText, { polite: true });\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n // Subscribe to any non-index carousel state changes\n return subscribeForValues(data => {\n if (totalNavLength.current <= 0 && data.navItemsCount > 0 && announcement) {\n const announcementText = announcement(data.activeIndex, data.navItemsCount, data.groupIndexList);\n // Initialize our string to prevent updateAnnouncement from reading an initial load\n announcementTextRef.current = announcementText;\n }\n totalNavLength.current = data.navItemsCount;\n navGroupRef.current = data.groupIndexList;\n updateAnnouncement();\n });\n }, [subscribeForValues, updateAnnouncement, announcement]);\n\n useIsomorphicLayoutEffect(() => {\n updateAnnouncement();\n }, [activeIndex, updateAnnouncement]);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: mergedContainerRef,\n role: 'region',\n ...props,\n }),\n { elementType: 'div' },\n ),\n\n activeIndex,\n circular,\n containerRef: mergedContainerRef,\n viewportRef,\n selectPageByElement,\n selectPageByDirection,\n selectPageByIndex,\n subscribeForValues,\n enableAutoplay,\n resetAutoplay,\n };\n}\n"],"names":["useFluent_unstable","useFluent","getIntrinsicElementProps","slot","useEventCallback","useIsomorphicLayoutEffect","useMergedRefs","React","useEmblaCarousel","useAnnounce","useCarousel_unstable","props","ref","align","circular","onActiveIndexChange","groupSize","draggable","whitespace","announcement","motion","dir","activeIndex","carouselApi","containerRef","viewportRef","subscribeForValues","enableAutoplay","resetAutoplay","direction","loop","slidesToScroll","defaultActiveIndex","watchDrag","containScroll","onDragIndexChange","onAutoplayIndexChange","selectPageByElement","event","element","jump","foundIndex","scrollToElement","type","index","selectPageByIndex","scrollToIndex","selectPageByDirection","nextPageIndex","scrollInDirection","mergedContainerRef","announcementTextRef","useRef","totalNavLength","navGroupRef","announce","updateAnnouncement","current","announcementText","polite","data","navItemsCount","groupIndexList","components","root","always","role","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { useToggleButton_unstable } from '@fluentui/react-button';
2
2
  import { PlayCircleRegular, PauseCircleRegular } from '@fluentui/react-icons';
3
- import { mergeCallbacks, slot, useControllableState, useEventCallback, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';
3
+ import { mergeCallbacks, slot, useControllableState, useEventCallback } from '@fluentui/react-utilities';
4
4
  import * as React from 'react';
5
5
  import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
6
6
  /**
@@ -20,16 +20,12 @@ import { useCarouselContext_unstable as useCarouselContext } from '../CarouselCo
20
20
  });
21
21
  const enableAutoplay = useCarouselContext((ctx)=>ctx.enableAutoplay);
22
22
  React.useEffect(()=>{
23
+ // Initialize carousel autoplay based on button state
24
+ enableAutoplay(autoplay);
23
25
  return ()=>{
24
- // We disable autoplay if the button gets unmounted.
26
+ // We uninitialize autoplay if the button gets unmounted.
25
27
  enableAutoplay(false);
26
28
  };
27
- }, [
28
- enableAutoplay
29
- ]);
30
- useIsomorphicLayoutEffect(()=>{
31
- // Enable/disable autoplay on state change
32
- enableAutoplay(autoplay);
33
29
  }, [
34
30
  autoplay,
35
31
  enableAutoplay
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselAutoplayButton/useCarouselAutoplayButton.tsx"],"sourcesContent":["import type { ARIAButtonElement } from '@fluentui/react-aria';\nimport { useToggleButton_unstable } from '@fluentui/react-button';\nimport { PlayCircleRegular, PauseCircleRegular } from '@fluentui/react-icons';\nimport {\n mergeCallbacks,\n slot,\n useControllableState,\n useEventCallback,\n useIsomorphicLayoutEffect,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselAutoplayButtonProps, CarouselAutoplayButtonState } from './CarouselAutoplayButton.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselAutoplayButton.\n *\n * The returned state can be modified with hooks such as useCarouselAutoplayButtonStyles_unstable,\n * before being passed to renderCarouselAutoplayButton_unstable.\n *\n * @param props - props from this instance of CarouselAutoplayButton\n * @param ref - reference to root HTMLDivElement of CarouselAutoplayButton\n */\nexport const useCarouselAutoplayButton_unstable = (\n props: CarouselAutoplayButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselAutoplayButtonState => {\n const { onCheckedChange, checked, defaultChecked } = props;\n\n const [autoplay, setAutoplay] = useControllableState({\n state: checked,\n defaultState: defaultChecked,\n initialState: false,\n });\n const enableAutoplay = useCarouselContext(ctx => ctx.enableAutoplay);\n\n React.useEffect(() => {\n return () => {\n // We disable autoplay if the button gets unmounted.\n enableAutoplay(false);\n };\n }, [enableAutoplay]);\n\n useIsomorphicLayoutEffect(() => {\n // Enable/disable autoplay on state change\n enableAutoplay(autoplay);\n }, [autoplay, enableAutoplay]);\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const newValue = !autoplay;\n\n setAutoplay(newValue);\n onCheckedChange?.(event, { event, type: 'click', checked: newValue });\n };\n\n return {\n // We lean on react-button class to handle styling and icon enhancements\n ...useToggleButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: autoplay ? <PauseCircleRegular /> : <PlayCircleRegular />,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n ...props,\n checked: autoplay,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n ref as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useToggleButton_unstable","PlayCircleRegular","PauseCircleRegular","mergeCallbacks","slot","useControllableState","useEventCallback","useIsomorphicLayoutEffect","React","useCarouselContext_unstable","useCarouselContext","useCarouselAutoplayButton_unstable","props","ref","onCheckedChange","checked","defaultChecked","autoplay","setAutoplay","state","defaultState","initialState","enableAutoplay","ctx","useEffect","handleClick","event","isDefaultPrevented","newValue","type","icon","optional","defaultProps","children","renderByDefault","elementType","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,wBAAwB,QAAQ,yBAAyB;AAClE,SAASC,iBAAiB,EAAEC,kBAAkB,QAAQ,wBAAwB;AAC9E,SACEC,cAAc,EACdC,IAAI,EACJC,oBAAoB,EACpBC,gBAAgB,EAChBC,yBAAyB,QACpB,4BAA4B;AACnC,YAAYC,WAAW,QAAQ;AAG/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,qCAAqC,CAChDC,OACAC;IAEA,MAAM,EAAEC,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAE,GAAGJ;IAErD,MAAM,CAACK,UAAUC,YAAY,GAAGb,qBAAqB;QACnDc,OAAOJ;QACPK,cAAcJ;QACdK,cAAc;IAChB;IACA,MAAMC,iBAAiBZ,mBAAmBa,CAAAA,MAAOA,IAAID,cAAc;IAEnEd,MAAMgB,SAAS,CAAC;QACd,OAAO;YACL,oDAAoD;YACpDF,eAAe;QACjB;IACF,GAAG;QAACA;KAAe;IAEnBf,0BAA0B;QACxB,0CAA0C;QAC1Ce,eAAeL;IACjB,GAAG;QAACA;QAAUK;KAAe;IAE7B,MAAMG,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,WAAW,CAACX;QAElBC,YAAYU;QACZd,4BAAAA,sCAAAA,gBAAkBY,OAAO;YAAEA;YAAOG,MAAM;YAASd,SAASa;QAAS;IACrE;IAEA,OAAO;QACL,wEAAwE;QACxE,GAAG5B,yBACD;YACE8B,MAAM1B,KAAK2B,QAAQ,CAACnB,MAAMkB,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUhB,yBAAW,oBAACf,0CAAwB,oBAACD;gBACjD;gBACAiC,iBAAiB;gBACjBC,aAAa;YACf;YACA,GAAGvB,KAAK;YACRG,SAASE;YACTmB,SAAS9B,iBAAiBH,eAAesB,aAAab,MAAMwB,OAAO;QACrE,GACAvB,IACD;IACH;AACF,EAAE"}
1
+ {"version":3,"sources":["../src/components/CarouselAutoplayButton/useCarouselAutoplayButton.tsx"],"sourcesContent":["import type { ARIAButtonElement } from '@fluentui/react-aria';\nimport { useToggleButton_unstable } from '@fluentui/react-button';\nimport { PlayCircleRegular, PauseCircleRegular } from '@fluentui/react-icons';\nimport { mergeCallbacks, slot, useControllableState, useEventCallback } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselAutoplayButtonProps, CarouselAutoplayButtonState } from './CarouselAutoplayButton.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselAutoplayButton.\n *\n * The returned state can be modified with hooks such as useCarouselAutoplayButtonStyles_unstable,\n * before being passed to renderCarouselAutoplayButton_unstable.\n *\n * @param props - props from this instance of CarouselAutoplayButton\n * @param ref - reference to root HTMLDivElement of CarouselAutoplayButton\n */\nexport const useCarouselAutoplayButton_unstable = (\n props: CarouselAutoplayButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselAutoplayButtonState => {\n const { onCheckedChange, checked, defaultChecked } = props;\n\n const [autoplay, setAutoplay] = useControllableState({\n state: checked,\n defaultState: defaultChecked,\n initialState: false,\n });\n const enableAutoplay = useCarouselContext(ctx => ctx.enableAutoplay);\n\n React.useEffect(() => {\n // Initialize carousel autoplay based on button state\n enableAutoplay(autoplay);\n\n return () => {\n // We uninitialize autoplay if the button gets unmounted.\n enableAutoplay(false);\n };\n }, [autoplay, enableAutoplay]);\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const newValue = !autoplay;\n\n setAutoplay(newValue);\n onCheckedChange?.(event, { event, type: 'click', checked: newValue });\n };\n\n return {\n // We lean on react-button class to handle styling and icon enhancements\n ...useToggleButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: autoplay ? <PauseCircleRegular /> : <PlayCircleRegular />,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n ...props,\n checked: autoplay,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n ref as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useToggleButton_unstable","PlayCircleRegular","PauseCircleRegular","mergeCallbacks","slot","useControllableState","useEventCallback","React","useCarouselContext_unstable","useCarouselContext","useCarouselAutoplayButton_unstable","props","ref","onCheckedChange","checked","defaultChecked","autoplay","setAutoplay","state","defaultState","initialState","enableAutoplay","ctx","useEffect","handleClick","event","isDefaultPrevented","newValue","type","icon","optional","defaultProps","children","renderByDefault","elementType","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,wBAAwB,QAAQ,yBAAyB;AAClE,SAASC,iBAAiB,EAAEC,kBAAkB,QAAQ,wBAAwB;AAC9E,SAASC,cAAc,EAAEC,IAAI,EAAEC,oBAAoB,EAAEC,gBAAgB,QAAQ,4BAA4B;AACzG,YAAYC,WAAW,QAAQ;AAG/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,qCAAqC,CAChDC,OACAC;IAEA,MAAM,EAAEC,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAE,GAAGJ;IAErD,MAAM,CAACK,UAAUC,YAAY,GAAGZ,qBAAqB;QACnDa,OAAOJ;QACPK,cAAcJ;QACdK,cAAc;IAChB;IACA,MAAMC,iBAAiBZ,mBAAmBa,CAAAA,MAAOA,IAAID,cAAc;IAEnEd,MAAMgB,SAAS,CAAC;QACd,qDAAqD;QACrDF,eAAeL;QAEf,OAAO;YACL,yDAAyD;YACzDK,eAAe;QACjB;IACF,GAAG;QAACL;QAAUK;KAAe;IAE7B,MAAMG,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,WAAW,CAACX;QAElBC,YAAYU;QACZd,4BAAAA,sCAAAA,gBAAkBY,OAAO;YAAEA;YAAOG,MAAM;YAASd,SAASa;QAAS;IACrE;IAEA,OAAO;QACL,wEAAwE;QACxE,GAAG3B,yBACD;YACE6B,MAAMzB,KAAK0B,QAAQ,CAACnB,MAAMkB,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUhB,yBAAW,oBAACd,0CAAwB,oBAACD;gBACjD;gBACAgC,iBAAiB;gBACjBC,aAAa;YACf;YACA,GAAGvB,KAAK;YACRG,SAASE;YACTmB,SAAS7B,iBAAiBH,eAAeqB,aAAab,MAAMwB,OAAO;QACrE,GACAvB,IACD;IACH;AACF,EAAE"}
@@ -4,7 +4,6 @@ import { mergeCallbacks, useEventCallback, slot, useIsomorphicLayoutEffect, useM
4
4
  import * as React from 'react';
5
5
  import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
6
6
  import { carouselButtonClassNames } from './useCarouselButtonStyles.styles';
7
- import { useRef } from 'react';
8
7
  import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
9
8
  /**
10
9
  * Create the state required to render CarouselButton.
@@ -19,7 +18,7 @@ import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts
19
18
  // Locally tracks the total number of slides, will only update if this changes.
20
19
  const [totalSlides, setTotalSlides] = React.useState(0);
21
20
  const { dir } = useFluent();
22
- const buttonRef = useRef();
21
+ const buttonRef = React.useRef();
23
22
  const circular = useCarouselContext((ctx)=>ctx.circular);
24
23
  const containerRef = useCarouselContext((ctx)=>ctx.containerRef);
25
24
  const selectPageByDirection = useCarouselContext((ctx)=>ctx.selectPageByDirection);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselButton/useCarouselButton.tsx"],"sourcesContent":["import { type ARIAButtonElement } from '@fluentui/react-aria';\nimport { useButton_unstable } from '@fluentui/react-button';\nimport { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';\nimport {\n mergeCallbacks,\n useEventCallback,\n slot,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\nimport type { CarouselButtonProps, CarouselButtonState } from './CarouselButton.types';\nimport type { CarouselUpdateData } from '../Carousel/Carousel.types';\nimport { carouselButtonClassNames } from './useCarouselButtonStyles.styles';\nimport { useRef } from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render CarouselButton.\n *\n * The returned state can be modified with hooks such as useCarouselButtonStyles_unstable,\n * before being passed to renderCarouselButton_unstable.\n *\n * @param props - props from this instance of CarouselButton\n * @param ref - reference to root HTMLDivElement of CarouselButton\n */\nexport const useCarouselButton_unstable = (\n props: CarouselButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselButtonState => {\n const { navType = 'next' } = props;\n\n // Locally tracks the total number of slides, will only update if this changes.\n const [totalSlides, setTotalSlides] = React.useState(0);\n\n const { dir } = useFluent();\n const buttonRef = useRef<HTMLButtonElement>();\n const circular = useCarouselContext(ctx => ctx.circular);\n const containerRef = useCarouselContext(ctx => ctx.containerRef);\n const selectPageByDirection = useCarouselContext(ctx => ctx.selectPageByDirection);\n const subscribeForValues = useCarouselContext(ctx => ctx.subscribeForValues);\n const resetAutoplay = useCarouselContext(ctx => ctx.resetAutoplay);\n\n const isTrailing = useCarouselContext(ctx => {\n if (circular) {\n return false;\n }\n\n if (navType === 'prev') {\n return ctx.activeIndex === 0;\n }\n\n return ctx.activeIndex === totalSlides - 1;\n });\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const nextIndex = selectPageByDirection(event, navType);\n\n let _trailing = false;\n if (navType === 'prev') {\n _trailing = nextIndex === 0;\n } else {\n _trailing = nextIndex === totalSlides - 1;\n }\n\n if (!circular && _trailing && containerRef?.current) {\n // Focus non-disabled element\n const buttonRefs: NodeListOf<HTMLButtonElement> = containerRef.current.querySelectorAll(\n `.${carouselButtonClassNames.root}`,\n );\n buttonRefs.forEach(_buttonRef => {\n if (_buttonRef !== buttonRef.current) {\n _buttonRef.focus();\n }\n });\n }\n\n resetAutoplay();\n };\n\n useIsomorphicLayoutEffect(() => {\n return subscribeForValues((data: CarouselUpdateData) => {\n setTotalSlides(data.navItemsCount);\n });\n }, [subscribeForValues]);\n\n const nextArrowIcon = dir === 'ltr' ? <ChevronRightRegular /> : <ChevronLeftRegular />;\n const prevArrowIcon = dir === 'ltr' ? <ChevronLeftRegular /> : <ChevronRightRegular />;\n\n return {\n navType,\n // We lean on react-button class to handle styling and icon enhancements\n ...useButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: navType === 'next' ? nextArrowIcon : prevArrowIcon,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n disabled: isTrailing,\n tabIndex: isTrailing ? -1 : 0,\n 'aria-disabled': isTrailing,\n appearance: 'subtle',\n ...props,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n useMergedRefs(ref, buttonRef) as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useButton_unstable","ChevronLeftRegular","ChevronRightRegular","mergeCallbacks","useEventCallback","slot","useIsomorphicLayoutEffect","useMergedRefs","React","useCarouselContext_unstable","useCarouselContext","carouselButtonClassNames","useRef","useFluent_unstable","useFluent","useCarouselButton_unstable","props","ref","navType","totalSlides","setTotalSlides","useState","dir","buttonRef","circular","ctx","containerRef","selectPageByDirection","subscribeForValues","resetAutoplay","isTrailing","activeIndex","handleClick","event","isDefaultPrevented","nextIndex","_trailing","current","buttonRefs","querySelectorAll","root","forEach","_buttonRef","focus","data","navItemsCount","nextArrowIcon","prevArrowIcon","icon","optional","defaultProps","children","renderByDefault","elementType","disabled","tabIndex","appearance","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,kBAAkB,QAAQ,yBAAyB;AAC5D,SAASC,kBAAkB,EAAEC,mBAAmB,QAAQ,wBAAwB;AAChF,SACEC,cAAc,EACdC,gBAAgB,EAChBC,IAAI,EACJC,yBAAyB,EACzBC,aAAa,QACR,4BAA4B;AACnC,YAAYC,WAAW,QAAQ;AAE/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAGvF,SAASC,wBAAwB,QAAQ,mCAAmC;AAC5E,SAASC,MAAM,QAAQ,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF;;;;;;;;CAQC,GACD,OAAO,MAAMC,6BAA6B,CACxCC,OACAC;IAEA,MAAM,EAAEC,UAAU,MAAM,EAAE,GAAGF;IAE7B,+EAA+E;IAC/E,MAAM,CAACG,aAAaC,eAAe,GAAGZ,MAAMa,QAAQ,CAAC;IAErD,MAAM,EAAEC,GAAG,EAAE,GAAGR;IAChB,MAAMS,YAAYX;IAClB,MAAMY,WAAWd,mBAAmBe,CAAAA,MAAOA,IAAID,QAAQ;IACvD,MAAME,eAAehB,mBAAmBe,CAAAA,MAAOA,IAAIC,YAAY;IAC/D,MAAMC,wBAAwBjB,mBAAmBe,CAAAA,MAAOA,IAAIE,qBAAqB;IACjF,MAAMC,qBAAqBlB,mBAAmBe,CAAAA,MAAOA,IAAIG,kBAAkB;IAC3E,MAAMC,gBAAgBnB,mBAAmBe,CAAAA,MAAOA,IAAII,aAAa;IAEjE,MAAMC,aAAapB,mBAAmBe,CAAAA;QACpC,IAAID,UAAU;YACZ,OAAO;QACT;QAEA,IAAIN,YAAY,QAAQ;YACtB,OAAOO,IAAIM,WAAW,KAAK;QAC7B;QAEA,OAAON,IAAIM,WAAW,KAAKZ,cAAc;IAC3C;IAEA,MAAMa,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,YAAYR,sBAAsBM,OAAOf;QAE/C,IAAIkB,YAAY;QAChB,IAAIlB,YAAY,QAAQ;YACtBkB,YAAYD,cAAc;QAC5B,OAAO;YACLC,YAAYD,cAAchB,cAAc;QAC1C;QAEA,IAAI,CAACK,YAAYY,cAAaV,yBAAAA,mCAAAA,aAAcW,OAAO,GAAE;YACnD,6BAA6B;YAC7B,MAAMC,aAA4CZ,aAAaW,OAAO,CAACE,gBAAgB,CACrF,CAAC,CAAC,EAAE5B,yBAAyB6B,IAAI,CAAC,CAAC;YAErCF,WAAWG,OAAO,CAACC,CAAAA;gBACjB,IAAIA,eAAenB,UAAUc,OAAO,EAAE;oBACpCK,WAAWC,KAAK;gBAClB;YACF;QACF;QAEAd;IACF;IAEAvB,0BAA0B;QACxB,OAAOsB,mBAAmB,CAACgB;YACzBxB,eAAewB,KAAKC,aAAa;QACnC;IACF,GAAG;QAACjB;KAAmB;IAEvB,MAAMkB,gBAAgBxB,QAAQ,sBAAQ,oBAACpB,2CAAyB,oBAACD;IACjE,MAAM8C,gBAAgBzB,QAAQ,sBAAQ,oBAACrB,0CAAwB,oBAACC;IAEhE,OAAO;QACLgB;QACA,wEAAwE;QACxE,GAAGlB,mBACD;YACEgD,MAAM3C,KAAK4C,QAAQ,CAACjC,MAAMgC,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUjC,YAAY,SAAS4B,gBAAgBC;gBACjD;gBACAK,iBAAiB;gBACjBC,aAAa;YACf;YACAC,UAAUxB;YACVyB,UAAUzB,aAAa,CAAC,IAAI;YAC5B,iBAAiBA;YACjB0B,YAAY;YACZ,GAAGxC,KAAK;YACRyC,SAASrD,iBAAiBD,eAAe6B,aAAahB,MAAMyC,OAAO;QACrE,GACAlD,cAAcU,KAAKM,WACpB;IACH;AACF,EAAE"}
1
+ {"version":3,"sources":["../src/components/CarouselButton/useCarouselButton.tsx"],"sourcesContent":["import { type ARIAButtonElement } from '@fluentui/react-aria';\nimport { useButton_unstable } from '@fluentui/react-button';\nimport { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';\nimport {\n mergeCallbacks,\n useEventCallback,\n slot,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\nimport type { CarouselButtonProps, CarouselButtonState } from './CarouselButton.types';\nimport type { CarouselUpdateData } from '../Carousel/Carousel.types';\nimport { carouselButtonClassNames } from './useCarouselButtonStyles.styles';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render CarouselButton.\n *\n * The returned state can be modified with hooks such as useCarouselButtonStyles_unstable,\n * before being passed to renderCarouselButton_unstable.\n *\n * @param props - props from this instance of CarouselButton\n * @param ref - reference to root HTMLDivElement of CarouselButton\n */\nexport const useCarouselButton_unstable = (\n props: CarouselButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselButtonState => {\n const { navType = 'next' } = props;\n\n // Locally tracks the total number of slides, will only update if this changes.\n const [totalSlides, setTotalSlides] = React.useState(0);\n\n const { dir } = useFluent();\n const buttonRef = React.useRef<HTMLButtonElement>();\n const circular = useCarouselContext(ctx => ctx.circular);\n const containerRef = useCarouselContext(ctx => ctx.containerRef);\n const selectPageByDirection = useCarouselContext(ctx => ctx.selectPageByDirection);\n const subscribeForValues = useCarouselContext(ctx => ctx.subscribeForValues);\n const resetAutoplay = useCarouselContext(ctx => ctx.resetAutoplay);\n\n const isTrailing = useCarouselContext(ctx => {\n if (circular) {\n return false;\n }\n\n if (navType === 'prev') {\n return ctx.activeIndex === 0;\n }\n\n return ctx.activeIndex === totalSlides - 1;\n });\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const nextIndex = selectPageByDirection(event, navType);\n\n let _trailing = false;\n if (navType === 'prev') {\n _trailing = nextIndex === 0;\n } else {\n _trailing = nextIndex === totalSlides - 1;\n }\n\n if (!circular && _trailing && containerRef?.current) {\n // Focus non-disabled element\n const buttonRefs: NodeListOf<HTMLButtonElement> = containerRef.current.querySelectorAll(\n `.${carouselButtonClassNames.root}`,\n );\n buttonRefs.forEach(_buttonRef => {\n if (_buttonRef !== buttonRef.current) {\n _buttonRef.focus();\n }\n });\n }\n\n resetAutoplay();\n };\n\n useIsomorphicLayoutEffect(() => {\n return subscribeForValues((data: CarouselUpdateData) => {\n setTotalSlides(data.navItemsCount);\n });\n }, [subscribeForValues]);\n\n const nextArrowIcon = dir === 'ltr' ? <ChevronRightRegular /> : <ChevronLeftRegular />;\n const prevArrowIcon = dir === 'ltr' ? <ChevronLeftRegular /> : <ChevronRightRegular />;\n\n return {\n navType,\n // We lean on react-button class to handle styling and icon enhancements\n ...useButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: navType === 'next' ? nextArrowIcon : prevArrowIcon,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n disabled: isTrailing,\n tabIndex: isTrailing ? -1 : 0,\n 'aria-disabled': isTrailing,\n appearance: 'subtle',\n ...props,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n useMergedRefs(ref, buttonRef) as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useButton_unstable","ChevronLeftRegular","ChevronRightRegular","mergeCallbacks","useEventCallback","slot","useIsomorphicLayoutEffect","useMergedRefs","React","useCarouselContext_unstable","useCarouselContext","carouselButtonClassNames","useFluent_unstable","useFluent","useCarouselButton_unstable","props","ref","navType","totalSlides","setTotalSlides","useState","dir","buttonRef","useRef","circular","ctx","containerRef","selectPageByDirection","subscribeForValues","resetAutoplay","isTrailing","activeIndex","handleClick","event","isDefaultPrevented","nextIndex","_trailing","current","buttonRefs","querySelectorAll","root","forEach","_buttonRef","focus","data","navItemsCount","nextArrowIcon","prevArrowIcon","icon","optional","defaultProps","children","renderByDefault","elementType","disabled","tabIndex","appearance","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,kBAAkB,QAAQ,yBAAyB;AAC5D,SAASC,kBAAkB,EAAEC,mBAAmB,QAAQ,wBAAwB;AAChF,SACEC,cAAc,EACdC,gBAAgB,EAChBC,IAAI,EACJC,yBAAyB,EACzBC,aAAa,QACR,4BAA4B;AACnC,YAAYC,WAAW,QAAQ;AAE/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAGvF,SAASC,wBAAwB,QAAQ,mCAAmC;AAC5E,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF;;;;;;;;CAQC,GACD,OAAO,MAAMC,6BAA6B,CACxCC,OACAC;IAEA,MAAM,EAAEC,UAAU,MAAM,EAAE,GAAGF;IAE7B,+EAA+E;IAC/E,MAAM,CAACG,aAAaC,eAAe,GAAGX,MAAMY,QAAQ,CAAC;IAErD,MAAM,EAAEC,GAAG,EAAE,GAAGR;IAChB,MAAMS,YAAYd,MAAMe,MAAM;IAC9B,MAAMC,WAAWd,mBAAmBe,CAAAA,MAAOA,IAAID,QAAQ;IACvD,MAAME,eAAehB,mBAAmBe,CAAAA,MAAOA,IAAIC,YAAY;IAC/D,MAAMC,wBAAwBjB,mBAAmBe,CAAAA,MAAOA,IAAIE,qBAAqB;IACjF,MAAMC,qBAAqBlB,mBAAmBe,CAAAA,MAAOA,IAAIG,kBAAkB;IAC3E,MAAMC,gBAAgBnB,mBAAmBe,CAAAA,MAAOA,IAAII,aAAa;IAEjE,MAAMC,aAAapB,mBAAmBe,CAAAA;QACpC,IAAID,UAAU;YACZ,OAAO;QACT;QAEA,IAAIP,YAAY,QAAQ;YACtB,OAAOQ,IAAIM,WAAW,KAAK;QAC7B;QAEA,OAAON,IAAIM,WAAW,KAAKb,cAAc;IAC3C;IAEA,MAAMc,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,YAAYR,sBAAsBM,OAAOhB;QAE/C,IAAImB,YAAY;QAChB,IAAInB,YAAY,QAAQ;YACtBmB,YAAYD,cAAc;QAC5B,OAAO;YACLC,YAAYD,cAAcjB,cAAc;QAC1C;QAEA,IAAI,CAACM,YAAYY,cAAaV,yBAAAA,mCAAAA,aAAcW,OAAO,GAAE;YACnD,6BAA6B;YAC7B,MAAMC,aAA4CZ,aAAaW,OAAO,CAACE,gBAAgB,CACrF,CAAC,CAAC,EAAE5B,yBAAyB6B,IAAI,CAAC,CAAC;YAErCF,WAAWG,OAAO,CAACC,CAAAA;gBACjB,IAAIA,eAAepB,UAAUe,OAAO,EAAE;oBACpCK,WAAWC,KAAK;gBAClB;YACF;QACF;QAEAd;IACF;IAEAvB,0BAA0B;QACxB,OAAOsB,mBAAmB,CAACgB;YACzBzB,eAAeyB,KAAKC,aAAa;QACnC;IACF,GAAG;QAACjB;KAAmB;IAEvB,MAAMkB,gBAAgBzB,QAAQ,sBAAQ,oBAACnB,2CAAyB,oBAACD;IACjE,MAAM8C,gBAAgB1B,QAAQ,sBAAQ,oBAACpB,0CAAwB,oBAACC;IAEhE,OAAO;QACLe;QACA,wEAAwE;QACxE,GAAGjB,mBACD;YACEgD,MAAM3C,KAAK4C,QAAQ,CAAClC,MAAMiC,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUlC,YAAY,SAAS6B,gBAAgBC;gBACjD;gBACAK,iBAAiB;gBACjBC,aAAa;YACf;YACAC,UAAUxB;YACVyB,UAAUzB,aAAa,CAAC,IAAI;YAC5B,iBAAiBA;YACjB0B,YAAY;YACZ,GAAGzC,KAAK;YACR0C,SAASrD,iBAAiBD,eAAe6B,aAAajB,MAAM0C,OAAO;QACrE,GACAlD,cAAcS,KAAKM,WACpB;IACH;AACF,EAAE"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselContext.types.ts"],"sourcesContent":["import type { EventData } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselUpdateData } from '../Carousel';\n\nexport type CarouselIndexChangeData = (\n | EventData<'click', React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>>\n | EventData<'focus', React.FocusEvent>\n | EventData<'drag', PointerEvent | MouseEvent>\n) & {\n /**\n * The index to be set after event has occurred.\n */\n index: number;\n};\n\nexport type CarouselContextValue = {\n activeIndex: number;\n circular: boolean;\n selectPageByElement: (event: React.FocusEvent, element: HTMLElement, jump?: boolean) => number;\n selectPageByDirection: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n direction: 'next' | 'prev',\n ) => number;\n selectPageByIndex: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n value: number,\n jump?: boolean,\n ) => void;\n subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;\n enableAutoplay: (autoplay: boolean) => void;\n resetAutoplay: () => void;\n // Container with controls passed to carousel engine\n containerRef?: React.RefObject<HTMLDivElement>;\n // Viewport without controls used for interactive functionality (draggable, pause autoplay etc.)\n viewportRef?: React.RefObject<HTMLDivElement>;\n};\n\n/**\n * Context shared between Carousel and its children components\n */\nexport type CarouselContextValues = {\n carousel: CarouselContextValue;\n};\n"],"names":["React"],"rangeMappings":"","mappings":"AACA,YAAYA,WAAW,QAAQ"}
1
+ {"version":3,"sources":["../src/components/CarouselContext.types.ts"],"sourcesContent":["import type { EventData } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselUpdateData } from '../Carousel';\n\nexport type CarouselIndexChangeData = (\n | EventData<'click', React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>>\n | EventData<'focus', React.FocusEvent>\n | EventData<'drag', PointerEvent | MouseEvent>\n | EventData<'autoplay', Event>\n) & {\n /**\n * The index to be set after event has occurred.\n */\n index: number;\n};\n\nexport type CarouselContextValue = {\n activeIndex: number;\n circular: boolean;\n selectPageByElement: (event: React.FocusEvent, element: HTMLElement, jump?: boolean) => number;\n selectPageByDirection: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n direction: 'next' | 'prev',\n ) => number;\n selectPageByIndex: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n value: number,\n jump?: boolean,\n ) => void;\n subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;\n enableAutoplay: (autoplay: boolean, temporary?: boolean) => void;\n resetAutoplay: () => void;\n // Container with controls passed to carousel engine\n containerRef?: React.RefObject<HTMLDivElement>;\n // Viewport without controls used for interactive functionality (draggable, pause autoplay etc.)\n viewportRef?: React.RefObject<HTMLDivElement>;\n};\n\n/**\n * Context shared between Carousel and its children components\n */\nexport type CarouselContextValues = {\n carousel: CarouselContextValue;\n};\n"],"names":["React"],"rangeMappings":"","mappings":"AACA,YAAYA,WAAW,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { getIntrinsicElementProps, slot, useMergedRefs } from '@fluentui/react-utilities';
2
+ import { getIntrinsicElementProps, mergeCallbacks, slot, useMergedRefs } from '@fluentui/react-utilities';
3
3
  import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
4
4
  /**
5
5
  * Create the state required to render CarouselViewport.
@@ -10,7 +10,46 @@ import { useCarouselContext_unstable as useCarouselContext } from '../CarouselCo
10
10
  * @param props - props from this instance of CarouselViewport
11
11
  * @param ref - reference to root HTMLDivElement of CarouselViewport
12
12
  */ export const useCarouselViewport_unstable = (props, ref)=>{
13
+ const hasFocus = React.useRef(false);
14
+ const hasMouse = React.useRef(false);
13
15
  const viewportRef = useCarouselContext((ctx)=>ctx.viewportRef);
16
+ const enableAutoplay = useCarouselContext((ctx)=>ctx.enableAutoplay);
17
+ const handleFocusCapture = React.useCallback((e)=>{
18
+ hasFocus.current = true;
19
+ // Will pause autoplay when focus is captured within viewport (if autoplay is initialized)
20
+ enableAutoplay(false, true);
21
+ }, [
22
+ enableAutoplay
23
+ ]);
24
+ const handleBlurCapture = React.useCallback((e)=>{
25
+ // Will enable autoplay (if initialized) when focus exits viewport
26
+ if (!e.currentTarget.contains(e.relatedTarget)) {
27
+ hasFocus.current = false;
28
+ if (!hasMouse.current) {
29
+ enableAutoplay(true, true);
30
+ }
31
+ }
32
+ }, [
33
+ enableAutoplay
34
+ ]);
35
+ const handleMouseEnter = React.useCallback((event)=>{
36
+ hasMouse.current = true;
37
+ enableAutoplay(false, true);
38
+ }, [
39
+ enableAutoplay
40
+ ]);
41
+ const handleMouseLeave = React.useCallback((event)=>{
42
+ hasMouse.current = false;
43
+ if (!hasFocus.current) {
44
+ enableAutoplay(true, true);
45
+ }
46
+ }, [
47
+ enableAutoplay
48
+ ]);
49
+ const onFocusCapture = mergeCallbacks(props.onFocusCapture, handleFocusCapture);
50
+ const onBlurCapture = mergeCallbacks(props.onBlurCapture, handleBlurCapture);
51
+ const onMouseEnter = mergeCallbacks(props.onMouseEnter, handleMouseEnter);
52
+ const onMouseLeave = mergeCallbacks(props.onMouseLeave, handleMouseLeave);
14
53
  return {
15
54
  components: {
16
55
  root: 'div'
@@ -20,7 +59,11 @@ import { useCarouselContext_unstable as useCarouselContext } from '../CarouselCo
20
59
  role: 'presentation',
21
60
  // Draggable ensures dragging is supported (even if not enabled)
22
61
  draggable: true,
23
- ...props
62
+ ...props,
63
+ onFocusCapture,
64
+ onBlurCapture,
65
+ onMouseEnter,
66
+ onMouseLeave
24
67
  }), {
25
68
  elementType: 'div'
26
69
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselViewport/useCarouselViewport.ts"],"sourcesContent":["import * as React from 'react';\nimport { getIntrinsicElementProps, slot, useMergedRefs } from '@fluentui/react-utilities';\nimport type { CarouselViewportProps, CarouselViewportState } from './CarouselViewport.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselViewport.\n *\n * The returned state can be modified with hooks such as useCarouselViewportStyles_unstable,\n * before being passed to renderCarouselViewport_unstable.\n *\n * @param props - props from this instance of CarouselViewport\n * @param ref - reference to root HTMLDivElement of CarouselViewport\n */\nexport const useCarouselViewport_unstable = (\n props: CarouselViewportProps,\n ref: React.Ref<HTMLDivElement>,\n): CarouselViewportState => {\n const viewportRef = useCarouselContext(ctx => ctx.viewportRef);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, viewportRef),\n role: 'presentation',\n // Draggable ensures dragging is supported (even if not enabled)\n draggable: true,\n ...props,\n }),\n { elementType: 'div' },\n ),\n };\n};\n"],"names":["React","getIntrinsicElementProps","slot","useMergedRefs","useCarouselContext_unstable","useCarouselContext","useCarouselViewport_unstable","props","ref","viewportRef","ctx","components","root","always","role","draggable","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,wBAAwB,EAAEC,IAAI,EAAEC,aAAa,QAAQ,4BAA4B;AAE1F,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,+BAA+B,CAC1CC,OACAC;IAEA,MAAMC,cAAcJ,mBAAmBK,CAAAA,MAAOA,IAAID,WAAW;IAE7D,OAAO;QACLE,YAAY;YACVC,MAAM;QACR;QACAA,MAAMV,KAAKW,MAAM,CACfZ,yBAAyB,OAAO;YAC9BO,KAAKL,cAAcK,KAAKC;YACxBK,MAAM;YACN,gEAAgE;YAChEC,WAAW;YACX,GAAGR,KAAK;QACV,IACA;YAAES,aAAa;QAAM;IAEzB;AACF,EAAE"}
1
+ {"version":3,"sources":["../src/components/CarouselViewport/useCarouselViewport.ts"],"sourcesContent":["import * as React from 'react';\nimport { getIntrinsicElementProps, mergeCallbacks, slot, useMergedRefs } from '@fluentui/react-utilities';\nimport type { CarouselViewportProps, CarouselViewportState } from './CarouselViewport.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselViewport.\n *\n * The returned state can be modified with hooks such as useCarouselViewportStyles_unstable,\n * before being passed to renderCarouselViewport_unstable.\n *\n * @param props - props from this instance of CarouselViewport\n * @param ref - reference to root HTMLDivElement of CarouselViewport\n */\nexport const useCarouselViewport_unstable = (\n props: CarouselViewportProps,\n ref: React.Ref<HTMLDivElement>,\n): CarouselViewportState => {\n const hasFocus = React.useRef(false);\n const hasMouse = React.useRef(false);\n const viewportRef = useCarouselContext(ctx => ctx.viewportRef);\n const enableAutoplay = useCarouselContext(ctx => ctx.enableAutoplay);\n\n const handleFocusCapture = React.useCallback(\n (e: React.FocusEvent) => {\n hasFocus.current = true;\n // Will pause autoplay when focus is captured within viewport (if autoplay is initialized)\n enableAutoplay(false, true);\n },\n [enableAutoplay],\n );\n\n const handleBlurCapture = React.useCallback(\n (e: React.FocusEvent) => {\n // Will enable autoplay (if initialized) when focus exits viewport\n if (!e.currentTarget.contains(e.relatedTarget)) {\n hasFocus.current = false;\n if (!hasMouse.current) {\n enableAutoplay(true, true);\n }\n }\n },\n [enableAutoplay],\n );\n\n const handleMouseEnter = React.useCallback(\n (event: React.MouseEvent) => {\n hasMouse.current = true;\n enableAutoplay(false, true);\n },\n [enableAutoplay],\n );\n const handleMouseLeave = React.useCallback(\n (event: React.MouseEvent) => {\n hasMouse.current = false;\n if (!hasFocus.current) {\n enableAutoplay(true, true);\n }\n },\n [enableAutoplay],\n );\n\n const onFocusCapture = mergeCallbacks(props.onFocusCapture, handleFocusCapture);\n const onBlurCapture = mergeCallbacks(props.onBlurCapture, handleBlurCapture);\n const onMouseEnter = mergeCallbacks(props.onMouseEnter, handleMouseEnter);\n const onMouseLeave = mergeCallbacks(props.onMouseLeave, handleMouseLeave);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, viewportRef),\n role: 'presentation',\n // Draggable ensures dragging is supported (even if not enabled)\n draggable: true,\n ...props,\n onFocusCapture,\n onBlurCapture,\n onMouseEnter,\n onMouseLeave,\n }),\n { elementType: 'div' },\n ),\n };\n};\n"],"names":["React","getIntrinsicElementProps","mergeCallbacks","slot","useMergedRefs","useCarouselContext_unstable","useCarouselContext","useCarouselViewport_unstable","props","ref","hasFocus","useRef","hasMouse","viewportRef","ctx","enableAutoplay","handleFocusCapture","useCallback","e","current","handleBlurCapture","currentTarget","contains","relatedTarget","handleMouseEnter","event","handleMouseLeave","onFocusCapture","onBlurCapture","onMouseEnter","onMouseLeave","components","root","always","role","draggable","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,wBAAwB,EAAEC,cAAc,EAAEC,IAAI,EAAEC,aAAa,QAAQ,4BAA4B;AAE1G,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,+BAA+B,CAC1CC,OACAC;IAEA,MAAMC,WAAWV,MAAMW,MAAM,CAAC;IAC9B,MAAMC,WAAWZ,MAAMW,MAAM,CAAC;IAC9B,MAAME,cAAcP,mBAAmBQ,CAAAA,MAAOA,IAAID,WAAW;IAC7D,MAAME,iBAAiBT,mBAAmBQ,CAAAA,MAAOA,IAAIC,cAAc;IAEnE,MAAMC,qBAAqBhB,MAAMiB,WAAW,CAC1C,CAACC;QACCR,SAASS,OAAO,GAAG;QACnB,0FAA0F;QAC1FJ,eAAe,OAAO;IACxB,GACA;QAACA;KAAe;IAGlB,MAAMK,oBAAoBpB,MAAMiB,WAAW,CACzC,CAACC;QACC,kEAAkE;QAClE,IAAI,CAACA,EAAEG,aAAa,CAACC,QAAQ,CAACJ,EAAEK,aAAa,GAAG;YAC9Cb,SAASS,OAAO,GAAG;YACnB,IAAI,CAACP,SAASO,OAAO,EAAE;gBACrBJ,eAAe,MAAM;YACvB;QACF;IACF,GACA;QAACA;KAAe;IAGlB,MAAMS,mBAAmBxB,MAAMiB,WAAW,CACxC,CAACQ;QACCb,SAASO,OAAO,GAAG;QACnBJ,eAAe,OAAO;IACxB,GACA;QAACA;KAAe;IAElB,MAAMW,mBAAmB1B,MAAMiB,WAAW,CACxC,CAACQ;QACCb,SAASO,OAAO,GAAG;QACnB,IAAI,CAACT,SAASS,OAAO,EAAE;YACrBJ,eAAe,MAAM;QACvB;IACF,GACA;QAACA;KAAe;IAGlB,MAAMY,iBAAiBzB,eAAeM,MAAMmB,cAAc,EAAEX;IAC5D,MAAMY,gBAAgB1B,eAAeM,MAAMoB,aAAa,EAAER;IAC1D,MAAMS,eAAe3B,eAAeM,MAAMqB,YAAY,EAAEL;IACxD,MAAMM,eAAe5B,eAAeM,MAAMsB,YAAY,EAAEJ;IAExD,OAAO;QACLK,YAAY;YACVC,MAAM;QACR;QACAA,MAAM7B,KAAK8B,MAAM,CACfhC,yBAAyB,OAAO;YAC9BQ,KAAKL,cAAcK,KAAKI;YACxBqB,MAAM;YACN,gEAAgE;YAChEC,WAAW;YACX,GAAG3B,KAAK;YACRmB;YACAC;YACAC;YACAC;QACF,IACA;YAAEM,aAAa;QAAM;IAEzB;AACF,EAAE"}
@@ -28,7 +28,7 @@ export function setTabsterDefault(element, isDefault) {
28
28
  }
29
29
  }
30
30
  export function useEmblaCarousel(options) {
31
- const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange } = options;
31
+ const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange, onAutoplayIndexChange } = options;
32
32
  const [activeIndex, setActiveIndex] = useControllableState({
33
33
  defaultState: options.defaultActiveIndex,
34
34
  state: options.activeIndex,
@@ -53,32 +53,17 @@ export function useEmblaCarousel(options) {
53
53
  const emblaApi = React.useRef(null);
54
54
  const autoplayRef = React.useRef(false);
55
55
  const resetAutoplay = React.useCallback(()=>{
56
- var _emblaApi_current;
57
- (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.plugins().autoplay.reset();
56
+ var _emblaApi_current_plugins_autoplay, _emblaApi_current;
57
+ (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.reset();
58
58
  }, []);
59
- /* Our autoplay button, which is required by standards for autoplay to be enabled, will handle controlled state */ const enableAutoplay = React.useCallback((autoplay)=>{
60
- autoplayRef.current = autoplay;
61
- if (autoplay) {
62
- var _emblaApi_current;
63
- (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.plugins().autoplay.play();
64
- // Reset after play to ensure timing and any focus/mouse pause state is reset.
65
- resetAutoplay();
66
- } else {
67
- var _emblaApi_current1;
68
- (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.plugins().autoplay.stop();
69
- }
70
- }, [
71
- resetAutoplay
72
- ]);
73
59
  const getPlugins = React.useCallback(()=>{
74
- const plugins = [
75
- Autoplay({
76
- playOnInit: autoplayRef.current,
77
- stopOnInteraction: !autoplayRef.current,
78
- stopOnMouseEnter: true,
79
- stopOnFocusIn: true
80
- })
81
- ];
60
+ const plugins = [];
61
+ plugins.push(Autoplay({
62
+ playOnInit: autoplayRef.current,
63
+ /* stopOnInteraction: false causes autoplay to restart on interaction end*/ /* we'll handle this logic to ensure autoplay state is respected */ stopOnInteraction: true,
64
+ stopOnFocusIn: false,
65
+ stopOnMouseEnter: false
66
+ }));
82
67
  // Optionally add Fade plugin
83
68
  if (motion === 'fade') {
84
69
  plugins.push(Fade());
@@ -94,6 +79,25 @@ export function useEmblaCarousel(options) {
94
79
  onDragEvent,
95
80
  watchDrag
96
81
  ]);
82
+ /* This function enables autoplay to pause/play without affecting underlying state
83
+ * Useful for pausing on focus etc. without having to reinitialize or set autoplay to off
84
+ */ const enableAutoplay = React.useCallback((autoplay, temporary)=>{
85
+ if (!temporary) {
86
+ autoplayRef.current = autoplay;
87
+ }
88
+ if (autoplay && autoplayRef.current) {
89
+ var // Autoplay should only enable in the case where underlying state is true, temporary should not override
90
+ _emblaApi_current_plugins_autoplay, _emblaApi_current;
91
+ (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.play();
92
+ // Reset after play to ensure timing and any focus/mouse pause state is reset.
93
+ resetAutoplay();
94
+ } else if (!autoplay) {
95
+ var _emblaApi_current_plugins_autoplay1, _emblaApi_current1;
96
+ (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay1 = _emblaApi_current1.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay1 === void 0 ? void 0 : _emblaApi_current_plugins_autoplay1.stop();
97
+ }
98
+ }, [
99
+ resetAutoplay
100
+ ]);
97
101
  // Listeners contains callbacks for UI elements that may require state update based on embla changes
98
102
  const listeners = React.useRef(new Set());
99
103
  const subscribeForValues = React.useCallback((listener)=>{
@@ -102,40 +106,49 @@ export function useEmblaCarousel(options) {
102
106
  listeners.current.delete(listener);
103
107
  };
104
108
  }, []);
109
+ const handleReinit = useEventCallback(()=>{
110
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3;
111
+ var _emblaApi_current_slideNodes;
112
+ const nodes = (_emblaApi_current_slideNodes = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes()) !== null && _emblaApi_current_slideNodes !== void 0 ? _emblaApi_current_slideNodes : [];
113
+ var _emblaApi_current_internalEngine_slideRegistry;
114
+ const groupIndexList = (_emblaApi_current_internalEngine_slideRegistry = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.internalEngine().slideRegistry) !== null && _emblaApi_current_internalEngine_slideRegistry !== void 0 ? _emblaApi_current_internalEngine_slideRegistry : [];
115
+ const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;
116
+ var _emblaApi_current_selectedScrollSnap;
117
+ const data = {
118
+ navItemsCount,
119
+ activeIndex: (_emblaApi_current_selectedScrollSnap = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0,
120
+ groupIndexList,
121
+ slideNodes: nodes
122
+ };
123
+ (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.scrollTo(activeIndex, false);
124
+ for (const listener of listeners.current){
125
+ listener(data);
126
+ }
127
+ });
128
+ const handleIndexChange = useEventCallback((_, eventType)=>{
129
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
130
+ var _emblaApi_current_selectedScrollSnap;
131
+ const newIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
132
+ const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
133
+ var _emblaApi_current_internalEngine_slideRegistry_newIndex_;
134
+ const actualIndex = (_emblaApi_current_internalEngine_slideRegistry_newIndex_ = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.internalEngine().slideRegistry[newIndex][0]) !== null && _emblaApi_current_internalEngine_slideRegistry_newIndex_ !== void 0 ? _emblaApi_current_internalEngine_slideRegistry_newIndex_ : 0;
135
+ // We set the active or first index of group on-screen as the selected tabster index
136
+ slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
137
+ setTabsterDefault(slide, slideIndex === actualIndex);
138
+ });
139
+ setActiveIndex(newIndex);
140
+ if (eventType === 'autoplay:select') {
141
+ const noopEvent = new Event('autoplay');
142
+ onAutoplayIndexChange === null || onAutoplayIndexChange === void 0 ? void 0 : onAutoplayIndexChange(noopEvent, {
143
+ event: noopEvent,
144
+ type: 'autoplay',
145
+ index: newIndex
146
+ });
147
+ }
148
+ });
105
149
  const viewportRef = React.useRef(null);
106
150
  const containerRef = React.useMemo(()=>{
107
151
  let currentElement = null;
108
- const handleIndexChange = ()=>{
109
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
110
- var _emblaApi_current_selectedScrollSnap;
111
- const newIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
112
- const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
113
- var _emblaApi_current_internalEngine_slideRegistry_newIndex_;
114
- const actualIndex = (_emblaApi_current_internalEngine_slideRegistry_newIndex_ = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.internalEngine().slideRegistry[newIndex][0]) !== null && _emblaApi_current_internalEngine_slideRegistry_newIndex_ !== void 0 ? _emblaApi_current_internalEngine_slideRegistry_newIndex_ : 0;
115
- // We set the active or first index of group on-screen as the selected tabster index
116
- slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
117
- setTabsterDefault(slide, slideIndex === actualIndex);
118
- });
119
- setActiveIndex(newIndex);
120
- };
121
- const handleReinit = ()=>{
122
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
123
- var _emblaApi_current_slideNodes;
124
- const nodes = (_emblaApi_current_slideNodes = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes()) !== null && _emblaApi_current_slideNodes !== void 0 ? _emblaApi_current_slideNodes : [];
125
- var _emblaApi_current_internalEngine_slideRegistry;
126
- const groupIndexList = (_emblaApi_current_internalEngine_slideRegistry = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.internalEngine().slideRegistry) !== null && _emblaApi_current_internalEngine_slideRegistry !== void 0 ? _emblaApi_current_internalEngine_slideRegistry : [];
127
- const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;
128
- var _emblaApi_current_selectedScrollSnap;
129
- const data = {
130
- navItemsCount,
131
- activeIndex: (_emblaApi_current_selectedScrollSnap = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0,
132
- groupIndexList,
133
- slideNodes: nodes
134
- };
135
- for (const listener of listeners.current){
136
- listener(data);
137
- }
138
- };
139
152
  const handleVisibilityChange = ()=>{
140
153
  var _emblaApi_current, _emblaApi_current1;
141
154
  const cardElements = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes();
@@ -150,35 +163,38 @@ export function useEmblaCarousel(options) {
150
163
  }));
151
164
  });
152
165
  };
166
+ // Get plugins using autoplayRef to prevent state change recreating EmblaCarousel
153
167
  const plugins = getPlugins();
154
168
  return {
155
169
  set current (newElement){
156
170
  if (currentElement) {
157
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3;
171
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3, _emblaApi_current4;
158
172
  (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.off('slidesInView', handleVisibilityChange);
159
173
  (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.off('select', handleIndexChange);
160
174
  (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.off('reInit', handleReinit);
161
- (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.destroy();
175
+ (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.off('autoplay:select', handleIndexChange);
176
+ (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.destroy();
162
177
  }
163
178
  var _viewportRef_current;
164
179
  // Use direct viewport if available, else fallback to container (includes Carousel controls).
165
- const wrapperElement = (_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement;
166
- if (wrapperElement) {
167
- var _emblaApi_current4, _emblaApi_current5, _emblaApi_current6;
168
- currentElement = wrapperElement;
169
- emblaApi.current = EmblaCarousel(wrapperElement, {
180
+ currentElement = (_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement;
181
+ if (currentElement) {
182
+ var _emblaApi_current5, _emblaApi_current6, _emblaApi_current7, _emblaApi_current8;
183
+ emblaApi.current = EmblaCarousel(currentElement, {
170
184
  ...DEFAULT_EMBLA_OPTIONS,
171
185
  ...emblaOptions.current
172
186
  }, plugins);
173
- (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.on('reInit', handleReinit);
174
- (_emblaApi_current5 = emblaApi.current) === null || _emblaApi_current5 === void 0 ? void 0 : _emblaApi_current5.on('slidesInView', handleVisibilityChange);
175
- (_emblaApi_current6 = emblaApi.current) === null || _emblaApi_current6 === void 0 ? void 0 : _emblaApi_current6.on('select', handleIndexChange);
187
+ (_emblaApi_current5 = emblaApi.current) === null || _emblaApi_current5 === void 0 ? void 0 : _emblaApi_current5.on('reInit', handleReinit);
188
+ (_emblaApi_current6 = emblaApi.current) === null || _emblaApi_current6 === void 0 ? void 0 : _emblaApi_current6.on('slidesInView', handleVisibilityChange);
189
+ (_emblaApi_current7 = emblaApi.current) === null || _emblaApi_current7 === void 0 ? void 0 : _emblaApi_current7.on('select', handleIndexChange);
190
+ (_emblaApi_current8 = emblaApi.current) === null || _emblaApi_current8 === void 0 ? void 0 : _emblaApi_current8.on('autoplay:select', handleIndexChange);
176
191
  }
177
192
  }
178
193
  };
179
194
  }, [
180
195
  getPlugins,
181
- setActiveIndex
196
+ handleIndexChange,
197
+ handleReinit
182
198
  ]);
183
199
  const carouselApi = React.useMemo(()=>({
184
200
  scrollToElement: (element, jump)=>{
@@ -212,19 +228,6 @@ export function useEmblaCarousel(options) {
212
228
  return (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
213
229
  }
214
230
  }), []);
215
- React.useEffect(()=>{
216
- var _emblaApi_current;
217
- var _emblaApi_current_selectedScrollSnap;
218
- // Scroll to controlled values on update
219
- const currentActiveIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
220
- emblaOptions.current.startIndex = activeIndex;
221
- if (activeIndex !== currentActiveIndex) {
222
- var _emblaApi_current1;
223
- (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.scrollTo(activeIndex);
224
- }
225
- }, [
226
- activeIndex
227
- ]);
228
231
  React.useEffect(()=>{
229
232
  var _emblaApi_current;
230
233
  const plugins = getPlugins();
@@ -243,12 +246,28 @@ export function useEmblaCarousel(options) {
243
246
  }, plugins);
244
247
  }, [
245
248
  align,
249
+ containScroll,
246
250
  direction,
251
+ getPlugins,
247
252
  loop,
248
253
  slidesToScroll,
249
- watchDrag,
250
- containScroll,
251
- getPlugins
254
+ watchDrag
255
+ ]);
256
+ React.useEffect(()=>{
257
+ var _emblaApi_current, _emblaApi_current_slideNodes, _emblaApi_current1;
258
+ var _emblaApi_current_selectedScrollSnap;
259
+ // Scroll to controlled values on update
260
+ // If active index is out of bounds, re-init will handle instead
261
+ const currentActiveIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
262
+ var _emblaApi_current_slideNodes_length;
263
+ const slideLength = (_emblaApi_current_slideNodes_length = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : (_emblaApi_current_slideNodes = _emblaApi_current1.slideNodes()) === null || _emblaApi_current_slideNodes === void 0 ? void 0 : _emblaApi_current_slideNodes.length) !== null && _emblaApi_current_slideNodes_length !== void 0 ? _emblaApi_current_slideNodes_length : 0;
264
+ emblaOptions.current.startIndex = activeIndex;
265
+ if (activeIndex < slideLength && activeIndex !== currentActiveIndex) {
266
+ var _emblaApi_current2;
267
+ (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollTo(activeIndex);
268
+ }
269
+ }, [
270
+ activeIndex
252
271
  ]);
253
272
  return {
254
273
  activeIndex,