@salt-ds/embla-carousel 0.1.5 → 1.0.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.
- package/CHANGELOG.md +51 -0
- package/css/salt-embla-carousel.css +54 -27
- package/dist-cjs/Carousel.js +30 -9
- package/dist-cjs/Carousel.js.map +1 -1
- package/dist-cjs/CarouselAutoplayIndicator.css.js +1 -1
- package/dist-cjs/CarouselAutoplayIndicator.js.map +1 -1
- package/dist-cjs/CarouselAutoplayIndicatorSVG.js +12 -24
- package/dist-cjs/CarouselAutoplayIndicatorSVG.js.map +1 -1
- package/dist-cjs/CarouselCard.css.js +1 -1
- package/dist-cjs/CarouselCard.js +23 -9
- package/dist-cjs/CarouselCard.js.map +1 -1
- package/dist-cjs/CarouselContext.js.map +1 -1
- package/dist-cjs/CarouselNextButton.js +4 -1
- package/dist-cjs/CarouselNextButton.js.map +1 -1
- package/dist-cjs/CarouselPreviousButton.js +4 -1
- package/dist-cjs/CarouselPreviousButton.js.map +1 -1
- package/dist-cjs/CarouselProgressLabel.js +11 -33
- package/dist-cjs/CarouselProgressLabel.js.map +1 -1
- package/dist-cjs/CarouselSlides.css.js +1 -1
- package/dist-cjs/CarouselSlides.js +148 -25
- package/dist-cjs/CarouselSlides.js.map +1 -1
- package/dist-cjs/CarouselTab.css.js +1 -1
- package/dist-cjs/CarouselTab.js +1 -5
- package/dist-cjs/CarouselTab.js.map +1 -1
- package/dist-cjs/CarouselTabList.css.js +1 -1
- package/dist-cjs/CarouselTabList.js +47 -27
- package/dist-cjs/CarouselTabList.js.map +1 -1
- package/dist-cjs/createCustomSettle.js +1 -1
- package/dist-cjs/createCustomSettle.js.map +1 -1
- package/dist-cjs/getSlideDescription.js +32 -0
- package/dist-cjs/getSlideDescription.js.map +1 -0
- package/dist-cjs/getVisibleSlideDescription.js +26 -0
- package/dist-cjs/getVisibleSlideDescription.js.map +1 -0
- package/dist-cjs/getVisibleSlideIndexes.js +33 -0
- package/dist-cjs/getVisibleSlideIndexes.js.map +1 -0
- package/dist-cjs/index.js +0 -3
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/usePrevNextButtons.js +3 -1
- package/dist-cjs/usePrevNextButtons.js.map +1 -1
- package/dist-es/Carousel.js +32 -11
- package/dist-es/Carousel.js.map +1 -1
- package/dist-es/CarouselAutoplayIndicator.css.js +1 -1
- package/dist-es/CarouselAutoplayIndicator.js.map +1 -1
- package/dist-es/CarouselAutoplayIndicatorSVG.js +13 -25
- package/dist-es/CarouselAutoplayIndicatorSVG.js.map +1 -1
- package/dist-es/CarouselCard.css.js +1 -1
- package/dist-es/CarouselCard.js +23 -9
- package/dist-es/CarouselCard.js.map +1 -1
- package/dist-es/CarouselContext.js.map +1 -1
- package/dist-es/CarouselNextButton.js +4 -1
- package/dist-es/CarouselNextButton.js.map +1 -1
- package/dist-es/CarouselPreviousButton.js +4 -1
- package/dist-es/CarouselPreviousButton.js.map +1 -1
- package/dist-es/CarouselProgressLabel.js +12 -34
- package/dist-es/CarouselProgressLabel.js.map +1 -1
- package/dist-es/CarouselSlides.css.js +1 -1
- package/dist-es/CarouselSlides.js +150 -27
- package/dist-es/CarouselSlides.js.map +1 -1
- package/dist-es/CarouselTab.css.js +1 -1
- package/dist-es/CarouselTab.js +1 -5
- package/dist-es/CarouselTab.js.map +1 -1
- package/dist-es/CarouselTabList.css.js +1 -1
- package/dist-es/CarouselTabList.js +48 -28
- package/dist-es/CarouselTabList.js.map +1 -1
- package/dist-es/createCustomSettle.js +1 -1
- package/dist-es/createCustomSettle.js.map +1 -1
- package/dist-es/getSlideDescription.js +30 -0
- package/dist-es/getSlideDescription.js.map +1 -0
- package/dist-es/getVisibleSlideDescription.js +24 -0
- package/dist-es/getVisibleSlideDescription.js.map +1 -0
- package/dist-es/getVisibleSlideIndexes.js +30 -0
- package/dist-es/getVisibleSlideIndexes.js.map +1 -0
- package/dist-es/index.js +0 -1
- package/dist-es/index.js.map +1 -1
- package/dist-es/usePrevNextButtons.js +3 -1
- package/dist-es/usePrevNextButtons.js.map +1 -1
- package/dist-types/Carousel.d.ts +7 -1
- package/dist-types/CarouselContext.d.ts +31 -0
- package/dist-types/CarouselTab.d.ts +0 -6
- package/dist-types/CarouselTabList.d.ts +4 -0
- package/dist-types/getSlideDescription.d.ts +7 -0
- package/dist-types/getVisibleSlideDescription.d.ts +7 -0
- package/dist-types/getVisibleSlideIndexes.d.ts +8 -0
- package/dist-types/index.d.ts +0 -1
- package/package.json +2 -2
- package/dist-cjs/CarouselAnnouncementPlugin.js +0 -52
- package/dist-cjs/CarouselAnnouncementPlugin.js.map +0 -1
- package/dist-cjs/CarouselProgressLabel.css.js +0 -6
- package/dist-cjs/CarouselProgressLabel.css.js.map +0 -1
- package/dist-es/CarouselAnnouncementPlugin.js +0 -49
- package/dist-es/CarouselAnnouncementPlugin.js.map +0 -1
- package/dist-es/CarouselProgressLabel.css.js +0 -4
- package/dist-es/CarouselProgressLabel.css.js.map +0 -1
- package/dist-types/CarouselAnnouncementPlugin.d.ts +0 -24
|
@@ -3,10 +3,12 @@ import { makePrefixer, renderProps } from '@salt-ds/core';
|
|
|
3
3
|
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
4
4
|
import { useWindow } from '@salt-ds/window';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
|
-
import { forwardRef, useRef } from 'react';
|
|
6
|
+
import { forwardRef, useRef, useState, useEffect } from 'react';
|
|
7
7
|
import { useCarouselContext } from './CarouselContext.js';
|
|
8
8
|
import { CarouselTab, useCarouselTab } from './CarouselTab.js';
|
|
9
9
|
import css_248z from './CarouselTabList.css.js';
|
|
10
|
+
import { getSlideDescription } from './getSlideDescription.js';
|
|
11
|
+
import { getVisibleSlideIndexes } from './getVisibleSlideIndexes.js';
|
|
10
12
|
|
|
11
13
|
const withBaseName = makePrefixer("saltCarouselTabList");
|
|
12
14
|
const CarouselTabRenderer = forwardRef((props, ref) => {
|
|
@@ -20,67 +22,85 @@ const CarouselTabList = forwardRef(
|
|
|
20
22
|
css: css_248z,
|
|
21
23
|
window: targetWindow
|
|
22
24
|
});
|
|
23
|
-
const { emblaApi } = useCarouselContext();
|
|
24
|
-
const { selectedIndex, scrollSnaps
|
|
25
|
-
const slideNodes = emblaApi == null ? void 0 : emblaApi.slideNodes();
|
|
26
|
-
const numberOfSlides = (slideNodes == null ? void 0 : slideNodes.length) ?? 0;
|
|
27
|
-
const slidesPerTransition = numberOfSlides ? Math.ceil(numberOfSlides / scrollSnaps.length) : 0;
|
|
25
|
+
const { emblaApi, setAriaVariant, setAnnouncementState } = useCarouselContext();
|
|
26
|
+
const { selectedIndex, scrollSnaps } = useCarouselTab(emblaApi);
|
|
28
27
|
const buttonRefs = useRef([]);
|
|
28
|
+
const [focusedTabIndex, setFocusedTabIndex] = useState(null);
|
|
29
29
|
const handleKeyDown = (event) => {
|
|
30
30
|
var _a;
|
|
31
|
-
let newIndex = selectedIndex;
|
|
31
|
+
let newIndex = focusedTabIndex ?? selectedIndex;
|
|
32
32
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
33
|
+
event.preventDefault();
|
|
33
34
|
const direction = event.key === "ArrowLeft" ? -1 : 1;
|
|
34
|
-
newIndex = (
|
|
35
|
+
newIndex = Math.max(
|
|
36
|
+
0,
|
|
37
|
+
Math.min(newIndex + direction, scrollSnaps.length - 1)
|
|
38
|
+
);
|
|
35
39
|
} else if (event.key === "Home") {
|
|
40
|
+
event.preventDefault();
|
|
36
41
|
newIndex = 0;
|
|
37
42
|
} else if (event.key === "End") {
|
|
43
|
+
event.preventDefault();
|
|
38
44
|
newIndex = scrollSnaps.length - 1;
|
|
39
45
|
}
|
|
40
|
-
if (newIndex !==
|
|
41
|
-
onClick(newIndex);
|
|
46
|
+
if (newIndex !== focusedTabIndex) {
|
|
42
47
|
(_a = buttonRefs.current[newIndex]) == null ? void 0 : _a.focus();
|
|
43
|
-
|
|
44
|
-
event.stopPropagation();
|
|
48
|
+
setFocusedTabIndex(newIndex);
|
|
45
49
|
}
|
|
46
50
|
onKeyDown == null ? void 0 : onKeyDown(event);
|
|
47
51
|
};
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
setAriaVariant("tabpanel");
|
|
54
|
+
}, [setAriaVariant]);
|
|
48
55
|
return /* @__PURE__ */ jsx(
|
|
49
56
|
"div",
|
|
50
57
|
{
|
|
51
58
|
role: "tablist",
|
|
52
|
-
"aria-label": "Choose slide",
|
|
53
|
-
tabIndex: 0,
|
|
54
59
|
className: clsx(withBaseName(), className),
|
|
55
60
|
onKeyDown: handleKeyDown,
|
|
56
61
|
ref,
|
|
57
62
|
...rest,
|
|
58
|
-
children: scrollSnaps.map((_,
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
numberOfSlides
|
|
63
|
+
children: scrollSnaps.map((_, scrollSnapIndex) => {
|
|
64
|
+
const visibleSlides = getVisibleSlideIndexes(
|
|
65
|
+
emblaApi,
|
|
66
|
+
scrollSnapIndex
|
|
63
67
|
);
|
|
64
|
-
const
|
|
65
|
-
const
|
|
68
|
+
const startSlideNumber = visibleSlides.length >= 1 ? visibleSlides[0] : 0;
|
|
69
|
+
const endSlideNumber = visibleSlides.length > 1 ? visibleSlides[visibleSlides.length - 1] : 0;
|
|
70
|
+
const slideNodes = emblaApi == null ? void 0 : emblaApi.slideNodes();
|
|
71
|
+
const numberOfSlides = slideNodes == null ? void 0 : slideNodes.length;
|
|
72
|
+
let ariaLabel;
|
|
73
|
+
if (endSlideNumber >= 1) {
|
|
74
|
+
ariaLabel = `Slide ${startSlideNumber} to ${endSlideNumber} of ${numberOfSlides}`;
|
|
75
|
+
} else {
|
|
76
|
+
const description = getSlideDescription(emblaApi, startSlideNumber);
|
|
77
|
+
ariaLabel = `${description}`;
|
|
78
|
+
}
|
|
79
|
+
const selected = selectedIndex === scrollSnapIndex;
|
|
66
80
|
const ariaControls = (slideNodes == null ? void 0 : slideNodes.length) ? slideNodes[startSlideNumber - 1].id : void 0;
|
|
67
81
|
return /* @__PURE__ */ jsx(
|
|
68
82
|
CarouselTabRenderer,
|
|
69
83
|
{
|
|
70
84
|
ref: (element) => {
|
|
71
|
-
buttonRefs.current[
|
|
85
|
+
buttonRefs.current[scrollSnapIndex] = element;
|
|
72
86
|
},
|
|
73
87
|
render,
|
|
74
88
|
role: "tab",
|
|
75
|
-
onClick: () => onClick(tabIndex),
|
|
76
|
-
"aria-selected": selected,
|
|
77
89
|
selected,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
onBlur: () => {
|
|
91
|
+
setFocusedTabIndex(null);
|
|
92
|
+
},
|
|
93
|
+
onFocus: () => {
|
|
94
|
+
setFocusedTabIndex(scrollSnapIndex);
|
|
95
|
+
setAnnouncementState("tab");
|
|
96
|
+
emblaApi == null ? void 0 : emblaApi.scrollTo(scrollSnapIndex);
|
|
97
|
+
},
|
|
98
|
+
"aria-label": ariaLabel,
|
|
99
|
+
"aria-selected": selected,
|
|
100
|
+
tabIndex: selected && focusedTabIndex === null ? 0 : -1,
|
|
81
101
|
"aria-controls": ariaControls
|
|
82
102
|
},
|
|
83
|
-
`carouselTab-${
|
|
103
|
+
`carouselTab-${scrollSnapIndex}}`
|
|
84
104
|
);
|
|
85
105
|
})
|
|
86
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselTabList.js","sources":["../src/CarouselTabList.tsx"],"sourcesContent":["import { makePrefixer, type RenderPropsType, renderProps } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n forwardRef,\n type HTMLAttributes,\n type KeyboardEventHandler,\n useRef,\n} from \"react\";\nimport { useCarouselContext } from \"./CarouselContext\";\nimport {\n CarouselTab,\n type CarouselTabProps,\n useCarouselTab,\n} from \"./CarouselTab\";\nimport carouselControlsCss from \"./CarouselTabList.css\";\n\nconst withBaseName = makePrefixer(\"saltCarouselTabList\");\n\n/**\n * Props for the CarouselTabList component.\n */\nexport interface CarouselTabListProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Render prop to enable customisation of tab button.\n */\n render?: RenderPropsType[\"render\"];\n}\n\
|
|
1
|
+
{"version":3,"file":"CarouselTabList.js","sources":["../src/CarouselTabList.tsx"],"sourcesContent":["import { makePrefixer, type RenderPropsType, renderProps } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n forwardRef,\n type HTMLAttributes,\n type KeyboardEventHandler,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useCarouselContext } from \"./CarouselContext\";\nimport {\n CarouselTab,\n type CarouselTabProps,\n useCarouselTab,\n} from \"./CarouselTab\";\nimport carouselControlsCss from \"./CarouselTabList.css\";\nimport { getSlideDescription } from \"./getSlideDescription\";\nimport { getVisibleSlideIndexes } from \"./getVisibleSlideIndexes\";\n\nconst withBaseName = makePrefixer(\"saltCarouselTabList\");\n\n/**\n * Props for the CarouselTabList component.\n */\nexport interface CarouselTabListProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Render prop to enable customisation of tab button.\n */\n render?: RenderPropsType[\"render\"];\n}\n\nexport interface CarouselTabRendererProps extends CarouselTabProps {\n render?: CarouselTabListProps[\"render\"];\n}\n\nconst CarouselTabRenderer = forwardRef<\n HTMLButtonElement,\n CarouselTabRendererProps\n>((props, ref) => {\n return renderProps(CarouselTab, { ...props, ref });\n});\n\nexport const CarouselTabList = forwardRef<HTMLDivElement, CarouselTabListProps>(\n function CarouselTabList({ className, render, onKeyDown, ...rest }, ref) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-carousel-controls\",\n css: carouselControlsCss,\n window: targetWindow,\n });\n\n const { emblaApi, setAriaVariant, setAnnouncementState } =\n useCarouselContext();\n const { selectedIndex, scrollSnaps } = useCarouselTab(emblaApi);\n\n const buttonRefs = useRef<(HTMLButtonElement | null)[]>([]);\n\n const [focusedTabIndex, setFocusedTabIndex] = useState<number | null>(null);\n\n const handleKeyDown: KeyboardEventHandler<HTMLDivElement> = (event) => {\n let newIndex = focusedTabIndex ?? selectedIndex;\n\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowRight\") {\n event.preventDefault();\n const direction = event.key === \"ArrowLeft\" ? -1 : 1;\n newIndex = Math.max(\n 0,\n Math.min(newIndex + direction, scrollSnaps.length - 1),\n );\n } else if (event.key === \"Home\") {\n event.preventDefault();\n newIndex = 0;\n } else if (event.key === \"End\") {\n event.preventDefault();\n newIndex = scrollSnaps.length - 1;\n }\n\n if (newIndex !== focusedTabIndex) {\n buttonRefs.current[newIndex]?.focus();\n setFocusedTabIndex(newIndex);\n }\n onKeyDown?.(event);\n };\n\n useEffect(() => {\n setAriaVariant(\"tabpanel\");\n }, [setAriaVariant]);\n\n return (\n <div\n role=\"tablist\"\n className={clsx(withBaseName(), className)}\n onKeyDown={handleKeyDown}\n ref={ref}\n {...rest}\n >\n {scrollSnaps.map((_, scrollSnapIndex) => {\n const visibleSlides = getVisibleSlideIndexes(\n emblaApi,\n scrollSnapIndex,\n );\n const startSlideNumber =\n visibleSlides.length >= 1 ? visibleSlides[0] : 0;\n const endSlideNumber =\n visibleSlides.length > 1\n ? visibleSlides[visibleSlides.length - 1]\n : 0;\n const slideNodes = emblaApi?.slideNodes();\n const numberOfSlides = slideNodes?.length;\n\n let ariaLabel: string;\n if (endSlideNumber >= 1) {\n ariaLabel = `Slide ${startSlideNumber} to ${endSlideNumber} of ${numberOfSlides}`;\n } else {\n const description = getSlideDescription(emblaApi, startSlideNumber);\n ariaLabel = `${description}`;\n }\n\n const selected = selectedIndex === scrollSnapIndex;\n const ariaControls = slideNodes?.length\n ? slideNodes[startSlideNumber - 1].id\n : undefined;\n\n return (\n <CarouselTabRenderer\n key={`carouselTab-${scrollSnapIndex}}`}\n ref={(element: HTMLButtonElement) => {\n buttonRefs.current[scrollSnapIndex] = element;\n }}\n render={render}\n role={\"tab\"}\n selected={selected}\n onBlur={() => {\n setFocusedTabIndex(null);\n }}\n onFocus={() => {\n setFocusedTabIndex(scrollSnapIndex);\n setAnnouncementState(\"tab\");\n emblaApi?.scrollTo(scrollSnapIndex);\n }}\n aria-label={ariaLabel}\n aria-selected={selected}\n tabIndex={selected && focusedTabIndex === null ? 0 : -1}\n aria-controls={ariaControls}\n />\n );\n })}\n </div>\n );\n },\n);\n"],"names":["CarouselTabList","carouselControlsCss"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createCustomSettle.js","sources":["../src/createCustomSettle.ts"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\n\nconst settlePixelThreshold =
|
|
1
|
+
{"version":3,"file":"createCustomSettle.js","sources":["../src/createCustomSettle.ts"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\n\nconst settlePixelThreshold = 25;\n\nexport type SettleCallback = (emblaApi: EmblaCarouselType) => void;\nexport type CreateCustomSettle = (callback: SettleCallback) => SettleCallback;\n\nexport const createCustomSettle: CreateCustomSettle = (callback) =>\n function fireCustomSettle(emblaApi: EmblaCarouselType) {\n const { dragHandler, location, target } = emblaApi.internalEngine();\n if (dragHandler.pointerDown()) return;\n const displacement = target.get() - location.get();\n if (Math.abs(displacement) < settlePixelThreshold) {\n callback(emblaApi);\n }\n };\n"],"names":[],"mappings":"AAEA,MAAM,oBAAA,GAAuB,EAAA;AAKtB,MAAM,kBAAA,GAAyC,CAAC,QAAA,KACrD,SAAS,iBAAiB,QAAA,EAA6B;AACrD,EAAA,MAAM,EAAE,WAAA,EAAa,QAAA,EAAU,MAAA,EAAO,GAAI,SAAS,cAAA,EAAe;AAClE,EAAA,IAAI,WAAA,CAAY,aAAY,EAAG;AAC/B,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,GAAA,EAAI,GAAI,SAAS,GAAA,EAAI;AACjD,EAAA,IAAI,IAAA,CAAK,GAAA,CAAI,YAAY,CAAA,GAAI,oBAAA,EAAsB;AACjD,IAAA,QAAA,CAAS,QAAQ,CAAA;AAAA,EACnB;AACF;;;;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const getSlideDescription = (emblaApi, slideNumber) => {
|
|
2
|
+
if (!emblaApi || slideNumber < 1) {
|
|
3
|
+
return "";
|
|
4
|
+
}
|
|
5
|
+
const slideElement = emblaApi.slideNodes()[slideNumber - 1];
|
|
6
|
+
const { ownerDocument } = emblaApi.internalEngine();
|
|
7
|
+
const resolveAriaLabelledBy = (element) => {
|
|
8
|
+
if (!element) return null;
|
|
9
|
+
const labelledById = element.getAttribute("aria-labelledby");
|
|
10
|
+
let description2 = null;
|
|
11
|
+
if (labelledById) {
|
|
12
|
+
const labelledByElement = ownerDocument.getElementById(labelledById);
|
|
13
|
+
if (labelledByElement) {
|
|
14
|
+
description2 = resolveAriaLabelledBy(labelledByElement);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (!description2) {
|
|
18
|
+
description2 = element.getAttribute("aria-label") || element.textContent || null;
|
|
19
|
+
}
|
|
20
|
+
return description2;
|
|
21
|
+
};
|
|
22
|
+
let description = resolveAriaLabelledBy(slideElement);
|
|
23
|
+
if (!description) {
|
|
24
|
+
description = (slideElement == null ? void 0 : slideElement.getAttribute("aria-label")) ?? null;
|
|
25
|
+
}
|
|
26
|
+
return description || "";
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { getSlideDescription };
|
|
30
|
+
//# sourceMappingURL=getSlideDescription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getSlideDescription.js","sources":["../src/getSlideDescription.ts"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\n\n/** Get a description of the slide.\n * @param emblaApi\n * @param slideIndex\n * @returns A slide description if defined or an empty string\n */\nexport const getSlideDescription = (\n emblaApi: EmblaCarouselType | undefined,\n slideNumber: number,\n): string => {\n if (!emblaApi || slideNumber < 1) {\n return \"\";\n }\n\n const slideElement = emblaApi.slideNodes()[slideNumber - 1];\n const { ownerDocument } = emblaApi.internalEngine();\n\n const resolveAriaLabelledBy = (element: Element | null): string | null => {\n if (!element) return null;\n\n const labelledById = element.getAttribute(\"aria-labelledby\");\n let description = null;\n\n if (labelledById) {\n const labelledByElement = ownerDocument.getElementById(labelledById);\n if (labelledByElement) {\n // Recursively resolve aria-labelledby\n description = resolveAriaLabelledBy(labelledByElement);\n }\n }\n\n // If no description found, use aria-label or text content\n if (!description) {\n description =\n element.getAttribute(\"aria-label\") || element.textContent || null;\n }\n\n return description;\n };\n\n let description = resolveAriaLabelledBy(slideElement);\n\n if (!description) {\n description = slideElement?.getAttribute(\"aria-label\") ?? null;\n }\n\n return description || \"\";\n};\n"],"names":["description"],"mappings":"AAOO,MAAM,mBAAA,GAAsB,CACjC,QAAA,EACA,WAAA,KACW;AACX,EAAA,IAAI,CAAC,QAAA,IAAY,WAAA,GAAc,CAAA,EAAG;AAChC,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,QAAA,CAAS,UAAA,EAAW,CAAE,cAAc,CAAC,CAAA;AAC1D,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,QAAA,CAAS,cAAA,EAAe;AAElD,EAAA,MAAM,qBAAA,GAAwB,CAAC,OAAA,KAA2C;AACxE,IAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,YAAA,CAAa,iBAAiB,CAAA;AAC3D,IAAA,IAAIA,YAAAA,GAAc,IAAA;AAElB,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,MAAM,iBAAA,GAAoB,aAAA,CAAc,cAAA,CAAe,YAAY,CAAA;AACnE,MAAA,IAAI,iBAAA,EAAmB;AAErB,QAAAA,YAAAA,GAAc,sBAAsB,iBAAiB,CAAA;AAAA,MACvD;AAAA,IACF;AAGA,IAAA,IAAI,CAACA,YAAAA,EAAa;AAChB,MAAAA,eACE,OAAA,CAAQ,YAAA,CAAa,YAAY,CAAA,IAAK,QAAQ,WAAA,IAAe,IAAA;AAAA,IACjE;AAEA,IAAA,OAAOA,YAAAA;AAAA,EACT,CAAA;AAEA,EAAA,IAAI,WAAA,GAAc,sBAAsB,YAAY,CAAA;AAEpD,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,WAAA,GAAA,CAAc,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,aAAa,YAAA,CAAA,KAAiB,IAAA;AAAA,EAC5D;AAEA,EAAA,OAAO,WAAA,IAAe,EAAA;AACxB;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getSlideDescription } from './getSlideDescription.js';
|
|
2
|
+
import { getVisibleSlideIndexes } from './getVisibleSlideIndexes.js';
|
|
3
|
+
|
|
4
|
+
const getVisibleSlideDescription = (emblaApi, scrollSnapIndex) => {
|
|
5
|
+
if (!emblaApi) {
|
|
6
|
+
return "";
|
|
7
|
+
}
|
|
8
|
+
const visibleSlideIndexes = getVisibleSlideIndexes(emblaApi, scrollSnapIndex);
|
|
9
|
+
const numberOfSlides = (emblaApi == null ? void 0 : emblaApi.slideNodes().length) ?? 0;
|
|
10
|
+
if (numberOfSlides < 1) {
|
|
11
|
+
return "";
|
|
12
|
+
}
|
|
13
|
+
if (visibleSlideIndexes.length > 1) {
|
|
14
|
+
return `Slide ${visibleSlideIndexes[0]} to ${visibleSlideIndexes[visibleSlideIndexes.length - 1]} of ${numberOfSlides}`;
|
|
15
|
+
}
|
|
16
|
+
const visibleSlideIndex = visibleSlideIndexes[0];
|
|
17
|
+
const description = getSlideDescription(emblaApi, visibleSlideIndex);
|
|
18
|
+
const slide = emblaApi == null ? void 0 : emblaApi.slideNodes()[visibleSlideIndex - 1];
|
|
19
|
+
const slideRoleDescription = (slide == null ? void 0 : slide.ariaRoleDescription) ?? "slide";
|
|
20
|
+
return `${description}, ${slideRoleDescription}, ${visibleSlideIndex} of ${numberOfSlides}`;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { getVisibleSlideDescription };
|
|
24
|
+
//# sourceMappingURL=getVisibleSlideDescription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getVisibleSlideDescription.js","sources":["../src/getVisibleSlideDescription.ts"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\nimport { getSlideDescription } from \"./getSlideDescription\";\nimport { getVisibleSlideIndexes } from \"./getVisibleSlideIndexes\";\n\n/** Get a description of the visible slide(s).\n * @param emblaApi\n * @param slideIndex\n * @returns An array of descriptions for the visible slides\n */\nexport const getVisibleSlideDescription = (\n emblaApi: EmblaCarouselType | undefined,\n scrollSnapIndex: number,\n): string => {\n if (!emblaApi) {\n return \"\";\n }\n\n const visibleSlideIndexes = getVisibleSlideIndexes(emblaApi, scrollSnapIndex);\n const numberOfSlides = emblaApi?.slideNodes().length ?? 0;\n\n if (numberOfSlides < 1) {\n return \"\";\n }\n\n if (visibleSlideIndexes.length > 1) {\n return `Slide ${visibleSlideIndexes[0]} to ${visibleSlideIndexes[visibleSlideIndexes.length - 1]} of ${numberOfSlides}`;\n }\n const visibleSlideIndex = visibleSlideIndexes[0];\n const description = getSlideDescription(emblaApi, visibleSlideIndex);\n const slide = emblaApi?.slideNodes()[visibleSlideIndex - 1];\n const slideRoleDescription = slide?.ariaRoleDescription ?? \"slide\";\n return `${description}, ${slideRoleDescription}, ${visibleSlideIndex} of ${numberOfSlides}`;\n};\n"],"names":[],"mappings":";;;AASO,MAAM,0BAAA,GAA6B,CACxC,QAAA,EACA,eAAA,KACW;AACX,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,mBAAA,GAAsB,sBAAA,CAAuB,QAAA,EAAU,eAAe,CAAA;AAC5E,EAAA,MAAM,cAAA,GAAA,CAAiB,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,UAAA,EAAA,CAAa,MAAA,KAAU,CAAA;AAExD,EAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,IAAI,mBAAA,CAAoB,SAAS,CAAA,EAAG;AAClC,IAAA,OAAO,CAAA,MAAA,EAAS,mBAAA,CAAoB,CAAC,CAAC,CAAA,IAAA,EAAO,mBAAA,CAAoB,mBAAA,CAAoB,MAAA,GAAS,CAAC,CAAC,CAAA,IAAA,EAAO,cAAc,CAAA,CAAA;AAAA,EACvH;AACA,EAAA,MAAM,iBAAA,GAAoB,oBAAoB,CAAC,CAAA;AAC/C,EAAA,MAAM,WAAA,GAAc,mBAAA,CAAoB,QAAA,EAAU,iBAAiB,CAAA;AACnE,EAAA,MAAM,KAAA,GAAQ,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,UAAA,EAAA,CAAa,iBAAA,GAAoB,CAAA,CAAA;AACzD,EAAA,MAAM,oBAAA,GAAA,CAAuB,+BAAO,mBAAA,KAAuB,OAAA;AAC3D,EAAA,OAAO,GAAG,WAAW,CAAA,EAAA,EAAK,oBAAoB,CAAA,EAAA,EAAK,iBAAiB,OAAO,cAAc,CAAA,CAAA;AAC3F;;;;"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const getSlideNumberRange = (startSlideNumber, endSlideNumber) => {
|
|
2
|
+
const slideNumbers = [];
|
|
3
|
+
for (let i = startSlideNumber; i <= endSlideNumber; i++) {
|
|
4
|
+
slideNumbers.push(i);
|
|
5
|
+
}
|
|
6
|
+
return slideNumbers;
|
|
7
|
+
};
|
|
8
|
+
const getVisibleSlideIndexes = (emblaApi, scrollSnapIndex) => {
|
|
9
|
+
if (!emblaApi) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
const numberOfSlides = (emblaApi == null ? void 0 : emblaApi.slideNodes().length) ?? 0;
|
|
13
|
+
const scrollSnaps = (emblaApi == null ? void 0 : emblaApi.scrollSnapList()) ?? [];
|
|
14
|
+
const slidesPerTransition = numberOfSlides ? Math.ceil(numberOfSlides / scrollSnaps.length) : 0;
|
|
15
|
+
const startSlideNumber = Math.min(
|
|
16
|
+
scrollSnapIndex * slidesPerTransition + 1,
|
|
17
|
+
numberOfSlides - (slidesPerTransition - 1)
|
|
18
|
+
);
|
|
19
|
+
const endSlideNumber = Math.min(
|
|
20
|
+
startSlideNumber + slidesPerTransition - 1,
|
|
21
|
+
numberOfSlides
|
|
22
|
+
);
|
|
23
|
+
if (startSlideNumber === endSlideNumber) {
|
|
24
|
+
return [startSlideNumber];
|
|
25
|
+
}
|
|
26
|
+
return getSlideNumberRange(startSlideNumber, endSlideNumber);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { getSlideNumberRange, getVisibleSlideIndexes };
|
|
30
|
+
//# sourceMappingURL=getVisibleSlideIndexes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getVisibleSlideIndexes.js","sources":["../src/getVisibleSlideIndexes.ts"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\n\nexport const getSlideNumberRange = (\n startSlideNumber: number,\n endSlideNumber: number,\n): number[] => {\n const slideNumbers: number[] = [];\n for (let i = startSlideNumber; i <= endSlideNumber; i++) {\n slideNumbers.push(i);\n }\n return slideNumbers;\n};\n\n/** Get the visible slide indexes\n * @param emblaApi\n * @param scrollSnap\n * @returns An array of visible slide indexes\n */\nexport const getVisibleSlideIndexes = (\n emblaApi: EmblaCarouselType | undefined,\n scrollSnapIndex: number,\n): number[] => {\n if (!emblaApi) {\n return [];\n }\n\n const numberOfSlides = emblaApi?.slideNodes().length ?? 0;\n const scrollSnaps = emblaApi?.scrollSnapList() ?? [];\n const slidesPerTransition = numberOfSlides\n ? Math.ceil(numberOfSlides / scrollSnaps.length)\n : 0;\n const startSlideNumber = Math.min(\n scrollSnapIndex * slidesPerTransition + 1,\n numberOfSlides - (slidesPerTransition - 1),\n );\n const endSlideNumber = Math.min(\n startSlideNumber + slidesPerTransition - 1,\n numberOfSlides,\n );\n\n if (startSlideNumber === endSlideNumber) {\n return [startSlideNumber];\n }\n return getSlideNumberRange(startSlideNumber, endSlideNumber);\n};\n"],"names":[],"mappings":"AAEO,MAAM,mBAAA,GAAsB,CACjC,gBAAA,EACA,cAAA,KACa;AACb,EAAA,MAAM,eAAyB,EAAC;AAChC,EAAA,KAAA,IAAS,CAAA,GAAI,gBAAA,EAAkB,CAAA,IAAK,cAAA,EAAgB,CAAA,EAAA,EAAK;AACvD,IAAA,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,EACrB;AACA,EAAA,OAAO,YAAA;AACT;AAOO,MAAM,sBAAA,GAAyB,CACpC,QAAA,EACA,eAAA,KACa;AACb,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,cAAA,GAAA,CAAiB,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,UAAA,EAAA,CAAa,MAAA,KAAU,CAAA;AACxD,EAAA,MAAM,WAAA,GAAA,CAAc,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,cAAA,EAAA,KAAoB,EAAC;AACnD,EAAA,MAAM,sBAAsB,cAAA,GACxB,IAAA,CAAK,KAAK,cAAA,GAAiB,WAAA,CAAY,MAAM,CAAA,GAC7C,CAAA;AACJ,EAAA,MAAM,mBAAmB,IAAA,CAAK,GAAA;AAAA,IAC5B,kBAAkB,mBAAA,GAAsB,CAAA;AAAA,IACxC,kBAAkB,mBAAA,GAAsB,CAAA;AAAA,GAC1C;AACA,EAAA,MAAM,iBAAiB,IAAA,CAAK,GAAA;AAAA,IAC1B,mBAAmB,mBAAA,GAAsB,CAAA;AAAA,IACzC;AAAA,GACF;AAEA,EAAA,IAAI,qBAAqB,cAAA,EAAgB;AACvC,IAAA,OAAO,CAAC,gBAAgB,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,mBAAA,CAAoB,kBAAkB,cAAc,CAAA;AAC7D;;;;"}
|
package/dist-es/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { Carousel } from './Carousel.js';
|
|
2
|
-
export { CarouselAnnouncement, getSlideLabel } from './CarouselAnnouncementPlugin.js';
|
|
3
2
|
export { CarouselAutoplayIndicator } from './CarouselAutoplayIndicator.js';
|
|
4
3
|
export { CarouselCard } from './CarouselCard.js';
|
|
5
4
|
export { CarouselContext, useCarouselContext } from './CarouselContext.js';
|
package/dist-es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -4,11 +4,13 @@ import { useCarouselContext } from './CarouselContext.js';
|
|
|
4
4
|
const usePrevNextButtons = () => {
|
|
5
5
|
const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);
|
|
6
6
|
const [nextBtnDisabled, setNextBtnDisabled] = useState(true);
|
|
7
|
-
const { emblaApi } = useCarouselContext();
|
|
7
|
+
const { emblaApi, setAnnouncementState } = useCarouselContext();
|
|
8
8
|
const handlePrevButtonClick = () => {
|
|
9
|
+
setAnnouncementState("navigation");
|
|
9
10
|
emblaApi == null ? void 0 : emblaApi.scrollPrev();
|
|
10
11
|
};
|
|
11
12
|
const handleNextButtonClick = () => {
|
|
13
|
+
setAnnouncementState("navigation");
|
|
12
14
|
emblaApi == null ? void 0 : emblaApi.scrollNext();
|
|
13
15
|
};
|
|
14
16
|
useEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePrevNextButtons.js","sources":["../src/usePrevNextButtons.tsx"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\nimport { useEffect, useState } from \"react\";\nimport { useCarouselContext } from \"./CarouselContext\";\n\ntype UsePrevNextButtonsType = {\n /**\n * Indicates whether the previous button is disabled.\n */\n prevBtnDisabled: boolean;\n /**\n * Indicates whether the next button is disabled.\n */\n nextBtnDisabled: boolean;\n /**\n * Handles the click event for the previous button.\n */\n onPrevButtonClick: () => void;\n /**\n * Handles the click event for the next button.\n */\n onNextButtonClick: () => void;\n};\n\nexport const usePrevNextButtons = (): UsePrevNextButtonsType => {\n const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);\n const [nextBtnDisabled, setNextBtnDisabled] = useState(true);\n\n const { emblaApi } = useCarouselContext();\n\n const handlePrevButtonClick = () => {\n emblaApi?.scrollPrev();\n };\n\n const handleNextButtonClick = () => {\n emblaApi?.scrollNext();\n };\n\n useEffect(() => {\n const handleSelect = (emblaApi: EmblaCarouselType) => {\n setPrevBtnDisabled(!emblaApi.canScrollPrev());\n setNextBtnDisabled(!emblaApi.canScrollNext());\n };\n\n if (!emblaApi) {\n return;\n }\n handleSelect(emblaApi);\n emblaApi\n .on(\"init\", handleSelect)\n .on(\"reInit\", handleSelect)\n .on(\"select\", handleSelect);\n // Cleanup listener on component unmount\n return () => {\n emblaApi\n .off(\"init\", handleSelect)\n .off(\"reInit\", handleSelect)\n .off(\"select\", handleSelect);\n };\n }, [emblaApi]);\n\n return {\n prevBtnDisabled,\n nextBtnDisabled,\n onPrevButtonClick: handlePrevButtonClick,\n onNextButtonClick: handleNextButtonClick,\n };\n};\n"],"names":["emblaApi"],"mappings":";;;AAuBO,MAAM,qBAAqB,MAA8B;AAC9D,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,IAAI,CAAA;AAC3D,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3D,
|
|
1
|
+
{"version":3,"file":"usePrevNextButtons.js","sources":["../src/usePrevNextButtons.tsx"],"sourcesContent":["import type { EmblaCarouselType } from \"embla-carousel\";\nimport { useEffect, useState } from \"react\";\nimport { useCarouselContext } from \"./CarouselContext\";\n\ntype UsePrevNextButtonsType = {\n /**\n * Indicates whether the previous button is disabled.\n */\n prevBtnDisabled: boolean;\n /**\n * Indicates whether the next button is disabled.\n */\n nextBtnDisabled: boolean;\n /**\n * Handles the click event for the previous button.\n */\n onPrevButtonClick: () => void;\n /**\n * Handles the click event for the next button.\n */\n onNextButtonClick: () => void;\n};\n\nexport const usePrevNextButtons = (): UsePrevNextButtonsType => {\n const [prevBtnDisabled, setPrevBtnDisabled] = useState(true);\n const [nextBtnDisabled, setNextBtnDisabled] = useState(true);\n\n const { emblaApi, setAnnouncementState } = useCarouselContext();\n\n const handlePrevButtonClick = () => {\n setAnnouncementState(\"navigation\");\n emblaApi?.scrollPrev();\n };\n\n const handleNextButtonClick = () => {\n setAnnouncementState(\"navigation\");\n emblaApi?.scrollNext();\n };\n\n useEffect(() => {\n const handleSelect = (emblaApi: EmblaCarouselType) => {\n setPrevBtnDisabled(!emblaApi.canScrollPrev());\n setNextBtnDisabled(!emblaApi.canScrollNext());\n };\n\n if (!emblaApi) {\n return;\n }\n handleSelect(emblaApi);\n emblaApi\n .on(\"init\", handleSelect)\n .on(\"reInit\", handleSelect)\n .on(\"select\", handleSelect);\n // Cleanup listener on component unmount\n return () => {\n emblaApi\n .off(\"init\", handleSelect)\n .off(\"reInit\", handleSelect)\n .off(\"select\", handleSelect);\n };\n }, [emblaApi]);\n\n return {\n prevBtnDisabled,\n nextBtnDisabled,\n onPrevButtonClick: handlePrevButtonClick,\n onNextButtonClick: handleNextButtonClick,\n };\n};\n"],"names":["emblaApi"],"mappings":";;;AAuBO,MAAM,qBAAqB,MAA8B;AAC9D,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,IAAI,CAAA;AAC3D,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,IAAI,CAAA;AAE3D,EAAA,MAAM,EAAE,QAAA,EAAU,oBAAA,EAAqB,GAAI,kBAAA,EAAmB;AAE9D,EAAA,MAAM,wBAAwB,MAAM;AAClC,IAAA,oBAAA,CAAqB,YAAY,CAAA;AACjC,IAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,UAAA,EAAA;AAAA,EACZ,CAAA;AAEA,EAAA,MAAM,wBAAwB,MAAM;AAClC,IAAA,oBAAA,CAAqB,YAAY,CAAA;AACjC,IAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,UAAA,EAAA;AAAA,EACZ,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAA,GAAe,CAACA,SAAAA,KAAgC;AACpD,MAAA,kBAAA,CAAmB,CAACA,SAAAA,CAAS,aAAA,EAAe,CAAA;AAC5C,MAAA,kBAAA,CAAmB,CAACA,SAAAA,CAAS,aAAA,EAAe,CAAA;AAAA,IAC9C,CAAA;AAEA,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA;AAAA,IACF;AACA,IAAA,YAAA,CAAa,QAAQ,CAAA;AACrB,IAAA,QAAA,CACG,EAAA,CAAG,MAAA,EAAQ,YAAY,CAAA,CACvB,EAAA,CAAG,UAAU,YAAY,CAAA,CACzB,EAAA,CAAG,QAAA,EAAU,YAAY,CAAA;AAE5B,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CACG,GAAA,CAAI,MAAA,EAAQ,YAAY,CAAA,CACxB,GAAA,CAAI,UAAU,YAAY,CAAA,CAC1B,GAAA,CAAI,QAAA,EAAU,YAAY,CAAA;AAAA,IAC/B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,eAAA;AAAA,IACA,iBAAA,EAAmB,qBAAA;AAAA,IACnB,iBAAA,EAAmB;AAAA,GACrB;AACF;;;;"}
|
package/dist-types/Carousel.d.ts
CHANGED
|
@@ -20,8 +20,14 @@ export interface CarouselProps extends ComponentPropsWithoutRef<"section"> {
|
|
|
20
20
|
* These options are passed directly to the Embla Carousel instance.
|
|
21
21
|
*/
|
|
22
22
|
emblaPlugins?: CarouselPlugin;
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Get embla API instance, use this to manage the state of the Carousel
|
|
25
|
+
**/
|
|
24
26
|
getEmblaApi?: (embla: CarouselEmblaApiType) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Disable screenreader announcing slide updates, defaults to false.
|
|
29
|
+
*/
|
|
30
|
+
disableSlideAnnouncements?: boolean;
|
|
25
31
|
}
|
|
26
32
|
export declare const Carousel: import("react").ForwardRefExoticComponent<CarouselProps & import("react").RefAttributes<HTMLElement>>;
|
|
27
33
|
export {};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { type Dispatch, type SetStateAction } from "react";
|
|
1
2
|
import type { CarouselEmblaApiType, CarouselEmblaRefType } from "./Carousel";
|
|
3
|
+
export type CarouselAriaVariant = "group" | "tabpanel";
|
|
4
|
+
export type CarouselAnnouncementTrigger = "tab" | "navigation" | "drag" | "focus";
|
|
2
5
|
/**
|
|
3
6
|
* Type definition for the Carousel context.
|
|
4
7
|
* Provides access to the Embla Carousel API and reference.
|
|
@@ -14,6 +17,34 @@ interface CarouselContextType {
|
|
|
14
17
|
* Used to directly interact with the carousel DOM element.
|
|
15
18
|
*/
|
|
16
19
|
emblaRef?: CarouselEmblaRefType;
|
|
20
|
+
/**
|
|
21
|
+
* Aria variant for the Carousel.
|
|
22
|
+
* When used with a `CarouselTabList` the screenreader will be presented as a `tablist` of tabpanels.
|
|
23
|
+
* When used without a `CarouselTabList` the screenreader will be presented as a `group` of slides.
|
|
24
|
+
*/
|
|
25
|
+
ariaVariant: CarouselAriaVariant;
|
|
26
|
+
/**
|
|
27
|
+
* Function to set the aria variant for the Carousel.
|
|
28
|
+
*/
|
|
29
|
+
setAriaVariant: Dispatch<SetStateAction<CarouselAriaVariant>>;
|
|
30
|
+
/**
|
|
31
|
+
* Disable screenreader announcing slide updates, defaults to false.
|
|
32
|
+
*/
|
|
33
|
+
disableSlideAnnouncements?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Id for the carousel
|
|
36
|
+
*/
|
|
37
|
+
carouselId: string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Announcement state, determines whether change is communicated to screenreader.
|
|
40
|
+
* @param trigger
|
|
41
|
+
*/
|
|
42
|
+
announcementState: CarouselAnnouncementTrigger | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Set announcement state, determines whether change is communicated to screenreader.
|
|
45
|
+
* @param trigger
|
|
46
|
+
*/
|
|
47
|
+
setAnnouncementState: (trigger: CarouselAnnouncementTrigger | undefined) => void;
|
|
17
48
|
}
|
|
18
49
|
export declare const CarouselContext: import("react").Context<CarouselContextType | undefined>;
|
|
19
50
|
export declare const useCarouselContext: () => CarouselContextType;
|
|
@@ -13,12 +13,6 @@ type UseCarouselTabProps = {
|
|
|
13
13
|
* An array of scroll snap positions for the carousel slides.
|
|
14
14
|
*/
|
|
15
15
|
scrollSnaps: number[];
|
|
16
|
-
/**
|
|
17
|
-
* Handler function for clicking a tab button to navigate to a specific slide.
|
|
18
|
-
*
|
|
19
|
-
* @param index - The index of the slide to navigate to.
|
|
20
|
-
*/
|
|
21
|
-
onClick: (index: number) => void;
|
|
22
16
|
};
|
|
23
17
|
export declare const useCarouselTab: (emblaApi: EmblaCarouselType | undefined) => UseCarouselTabProps;
|
|
24
18
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type RenderPropsType } from "@salt-ds/core";
|
|
2
2
|
import { type HTMLAttributes } from "react";
|
|
3
|
+
import { type CarouselTabProps } from "./CarouselTab";
|
|
3
4
|
/**
|
|
4
5
|
* Props for the CarouselTabList component.
|
|
5
6
|
*/
|
|
@@ -9,4 +10,7 @@ export interface CarouselTabListProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
9
10
|
*/
|
|
10
11
|
render?: RenderPropsType["render"];
|
|
11
12
|
}
|
|
13
|
+
export interface CarouselTabRendererProps extends CarouselTabProps {
|
|
14
|
+
render?: CarouselTabListProps["render"];
|
|
15
|
+
}
|
|
12
16
|
export declare const CarouselTabList: import("react").ForwardRefExoticComponent<CarouselTabListProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EmblaCarouselType } from "embla-carousel";
|
|
2
|
+
/** Get a description of the slide.
|
|
3
|
+
* @param emblaApi
|
|
4
|
+
* @param slideIndex
|
|
5
|
+
* @returns A slide description if defined or an empty string
|
|
6
|
+
*/
|
|
7
|
+
export declare const getSlideDescription: (emblaApi: EmblaCarouselType | undefined, slideNumber: number) => string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EmblaCarouselType } from "embla-carousel";
|
|
2
|
+
/** Get a description of the visible slide(s).
|
|
3
|
+
* @param emblaApi
|
|
4
|
+
* @param slideIndex
|
|
5
|
+
* @returns An array of descriptions for the visible slides
|
|
6
|
+
*/
|
|
7
|
+
export declare const getVisibleSlideDescription: (emblaApi: EmblaCarouselType | undefined, scrollSnapIndex: number) => string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { EmblaCarouselType } from "embla-carousel";
|
|
2
|
+
export declare const getSlideNumberRange: (startSlideNumber: number, endSlideNumber: number) => number[];
|
|
3
|
+
/** Get the visible slide indexes
|
|
4
|
+
* @param emblaApi
|
|
5
|
+
* @param scrollSnap
|
|
6
|
+
* @returns An array of visible slide indexes
|
|
7
|
+
*/
|
|
8
|
+
export declare const getVisibleSlideIndexes: (emblaApi: EmblaCarouselType | undefined, scrollSnapIndex: number) => number[];
|
package/dist-types/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salt-ds/embla-carousel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"*.css"
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@salt-ds/core": "^1.
|
|
23
|
+
"@salt-ds/core": "^1.51.0",
|
|
24
24
|
"clsx": "^2.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var core = require('@salt-ds/core');
|
|
4
|
-
var react = require('react');
|
|
5
|
-
|
|
6
|
-
const getSlideLabel = (emblaApi) => {
|
|
7
|
-
var _a;
|
|
8
|
-
const slideCount = (emblaApi == null ? void 0 : emblaApi.slideNodes().length) ?? 0;
|
|
9
|
-
const slideIndexInView = ((_a = emblaApi == null ? void 0 : emblaApi.slidesInView()) == null ? void 0 : _a[0]) ?? 0;
|
|
10
|
-
const slideElement = emblaApi == null ? void 0 : emblaApi.slideNodes()[slideIndexInView];
|
|
11
|
-
let description = slideElement == null ? void 0 : slideElement.getAttribute("aria-label");
|
|
12
|
-
if (!description) {
|
|
13
|
-
const labelledById = slideElement == null ? void 0 : slideElement.getAttribute("aria-labelledby");
|
|
14
|
-
const { ownerDocument } = emblaApi.internalEngine();
|
|
15
|
-
if (labelledById) {
|
|
16
|
-
const labelledByElement = ownerDocument.getElementById(labelledById);
|
|
17
|
-
description = (labelledByElement == null ? void 0 : labelledByElement.textContent) || "No description available";
|
|
18
|
-
} else {
|
|
19
|
-
description = "No description available";
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return `slide ${slideIndexInView + 1} of ${slideCount}. ${description}`;
|
|
23
|
-
};
|
|
24
|
-
function CarouselAnnouncement(userOptions = {}) {
|
|
25
|
-
let emblaApi;
|
|
26
|
-
const { announce } = core.useAriaAnnouncer();
|
|
27
|
-
const handleSettle = react.useCallback(
|
|
28
|
-
(emblaApi2) => {
|
|
29
|
-
const slideLabel = getSlideLabel(emblaApi2);
|
|
30
|
-
announce(slideLabel);
|
|
31
|
-
},
|
|
32
|
-
[announce]
|
|
33
|
-
);
|
|
34
|
-
function init(emblaApiInstance) {
|
|
35
|
-
emblaApi = emblaApiInstance;
|
|
36
|
-
emblaApi.on("settle", handleSettle);
|
|
37
|
-
}
|
|
38
|
-
function destroy() {
|
|
39
|
-
emblaApi.off("settle", handleSettle);
|
|
40
|
-
}
|
|
41
|
-
const self = {
|
|
42
|
-
name: "announcement",
|
|
43
|
-
options: userOptions,
|
|
44
|
-
init,
|
|
45
|
-
destroy
|
|
46
|
-
};
|
|
47
|
-
return self;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
exports.CarouselAnnouncement = CarouselAnnouncement;
|
|
51
|
-
exports.getSlideLabel = getSlideLabel;
|
|
52
|
-
//# sourceMappingURL=CarouselAnnouncementPlugin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselAnnouncementPlugin.js","sources":["../src/CarouselAnnouncementPlugin.ts"],"sourcesContent":["import { useAriaAnnouncer } from \"@salt-ds/core\";\nimport type {\n CreateOptionsType,\n CreatePluginType,\n EmblaCarouselType,\n} from \"embla-carousel\";\nimport { useCallback } from \"react\";\n\ndeclare module \"embla-carousel\" {\n interface EmblaPluginsType {\n announcement: CarouselAnnouncementType;\n }\n}\n\n/**\n * Type definition for the parameters of the getSlideLabel function.\n * @returns A string that describes the slide, including its index and total count.\n */\nexport type GetSlideLabelProps = (emblaApi: EmblaCarouselType) => string;\n\n/** * Generates a label for a carousel slide based on ARIA attributes.\n * This function retrieves the slide's ARIA label or text content and formats it into a descriptive string.\n * @param slideElement\n * @param slideIndex\n * @param slideCount\n * @returns A string description of the slide, including its position and ARIA label or text content.\n */\nexport const getSlideLabel: GetSlideLabelProps = (emblaApi): string => {\n const slideCount = emblaApi?.slideNodes().length ?? 0;\n const slideIndexInView = emblaApi?.slidesInView()?.[0] ?? 0;\n const slideElement = emblaApi?.slideNodes()[slideIndexInView];\n\n let description = slideElement?.getAttribute(\"aria-label\");\n if (!description) {\n const labelledById = slideElement?.getAttribute(\"aria-labelledby\");\n const { ownerDocument } = emblaApi.internalEngine();\n if (labelledById) {\n const labelledByElement = ownerDocument.getElementById(labelledById);\n description =\n labelledByElement?.textContent || \"No description available\";\n } else {\n description = \"No description available\";\n }\n }\n return `slide ${slideIndexInView + 1} of ${slideCount}. ${description}`;\n};\n\n// biome-ignore lint/complexity/noBannedTypes: Replicated from embla docs/code\ntype OptionsType = CreateOptionsType<{}>;\n// biome-ignore lint/complexity/noBannedTypes: Replicated from embla docs/code\nexport type CarouselAnnouncementType = CreatePluginType<{}, OptionsType>;\n\nexport type CarouselAnnouncementOptionsType =\n CarouselAnnouncementType[\"options\"];\n\nexport function CarouselAnnouncement(\n userOptions: CarouselAnnouncementOptionsType = {},\n): CarouselAnnouncementType {\n let emblaApi: EmblaCarouselType;\n\n const { announce } = useAriaAnnouncer();\n\n const handleSettle = useCallback(\n (emblaApi: EmblaCarouselType) => {\n const slideLabel = getSlideLabel(emblaApi);\n announce(slideLabel);\n },\n [announce],\n );\n\n function init(emblaApiInstance: EmblaCarouselType): void {\n emblaApi = emblaApiInstance;\n emblaApi.on(\"settle\", handleSettle);\n }\n\n function destroy(): void {\n emblaApi.off(\"settle\", handleSettle);\n }\n\n const self: CarouselAnnouncementType = {\n name: \"announcement\",\n options: userOptions,\n init,\n destroy,\n };\n return self;\n}\n"],"names":["useAriaAnnouncer","useCallback","emblaApi"],"mappings":";;;;;AA2Ba,MAAA,aAAA,GAAoC,CAAC,QAAqB,KAAA;AA3BvE,EAAA,IAAA,EAAA;AA4BE,EAAM,MAAA,UAAA,GAAA,CAAa,QAAU,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAA,UAAA,EAAA,CAAa,MAAU,KAAA,CAAA;AACpD,EAAA,MAAM,gBAAmB,GAAA,CAAA,CAAA,EAAA,GAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAU,YAAV,EAAA,KAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAA2B,CAAM,CAAA,KAAA,CAAA;AAC1D,EAAM,MAAA,YAAA,GAAe,qCAAU,UAAa,EAAA,CAAA,gBAAA,CAAA;AAE5C,EAAI,IAAA,WAAA,GAAc,6CAAc,YAAa,CAAA,YAAA,CAAA;AAC7C,EAAA,IAAI,CAAC,WAAa,EAAA;AAChB,IAAM,MAAA,YAAA,GAAe,6CAAc,YAAa,CAAA,iBAAA,CAAA;AAChD,IAAA,MAAM,EAAE,aAAA,EAAkB,GAAA,QAAA,CAAS,cAAe,EAAA;AAClD,IAAA,IAAI,YAAc,EAAA;AAChB,MAAM,MAAA,iBAAA,GAAoB,aAAc,CAAA,cAAA,CAAe,YAAY,CAAA;AACnE,MAAA,WAAA,GAAA,CACE,uDAAmB,WAAe,KAAA,0BAAA;AAAA,KAC/B,MAAA;AACL,MAAc,WAAA,GAAA,0BAAA;AAAA;AAChB;AAEF,EAAA,OAAO,SAAS,gBAAmB,GAAA,CAAC,CAAO,IAAA,EAAA,UAAU,KAAK,WAAW,CAAA,CAAA;AACvE;AAUgB,SAAA,oBAAA,CACd,WAA+C,GAAA,EACrB,EAAA;AAC1B,EAAI,IAAA,QAAA;AAEJ,EAAM,MAAA,EAAE,QAAS,EAAA,GAAIA,qBAAiB,EAAA;AAEtC,EAAA,MAAM,YAAe,GAAAC,iBAAA;AAAA,IACnB,CAACC,SAAgC,KAAA;AAC/B,MAAM,MAAA,UAAA,GAAa,cAAcA,SAAQ,CAAA;AACzC,MAAA,QAAA,CAAS,UAAU,CAAA;AAAA,KACrB;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,SAAS,KAAK,gBAA2C,EAAA;AACvD,IAAW,QAAA,GAAA,gBAAA;AACX,IAAS,QAAA,CAAA,EAAA,CAAG,UAAU,YAAY,CAAA;AAAA;AAGpC,EAAA,SAAS,OAAgB,GAAA;AACvB,IAAS,QAAA,CAAA,GAAA,CAAI,UAAU,YAAY,CAAA;AAAA;AAGrC,EAAA,MAAM,IAAiC,GAAA;AAAA,IACrC,IAAM,EAAA,cAAA;AAAA,IACN,OAAS,EAAA,WAAA;AAAA,IACT,IAAA;AAAA,IACA;AAAA,GACF;AACA,EAAO,OAAA,IAAA;AACT;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CarouselProgressLabel.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { useAriaAnnouncer } from '@salt-ds/core';
|
|
2
|
-
import { useCallback } from 'react';
|
|
3
|
-
|
|
4
|
-
const getSlideLabel = (emblaApi) => {
|
|
5
|
-
var _a;
|
|
6
|
-
const slideCount = (emblaApi == null ? void 0 : emblaApi.slideNodes().length) ?? 0;
|
|
7
|
-
const slideIndexInView = ((_a = emblaApi == null ? void 0 : emblaApi.slidesInView()) == null ? void 0 : _a[0]) ?? 0;
|
|
8
|
-
const slideElement = emblaApi == null ? void 0 : emblaApi.slideNodes()[slideIndexInView];
|
|
9
|
-
let description = slideElement == null ? void 0 : slideElement.getAttribute("aria-label");
|
|
10
|
-
if (!description) {
|
|
11
|
-
const labelledById = slideElement == null ? void 0 : slideElement.getAttribute("aria-labelledby");
|
|
12
|
-
const { ownerDocument } = emblaApi.internalEngine();
|
|
13
|
-
if (labelledById) {
|
|
14
|
-
const labelledByElement = ownerDocument.getElementById(labelledById);
|
|
15
|
-
description = (labelledByElement == null ? void 0 : labelledByElement.textContent) || "No description available";
|
|
16
|
-
} else {
|
|
17
|
-
description = "No description available";
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return `slide ${slideIndexInView + 1} of ${slideCount}. ${description}`;
|
|
21
|
-
};
|
|
22
|
-
function CarouselAnnouncement(userOptions = {}) {
|
|
23
|
-
let emblaApi;
|
|
24
|
-
const { announce } = useAriaAnnouncer();
|
|
25
|
-
const handleSettle = useCallback(
|
|
26
|
-
(emblaApi2) => {
|
|
27
|
-
const slideLabel = getSlideLabel(emblaApi2);
|
|
28
|
-
announce(slideLabel);
|
|
29
|
-
},
|
|
30
|
-
[announce]
|
|
31
|
-
);
|
|
32
|
-
function init(emblaApiInstance) {
|
|
33
|
-
emblaApi = emblaApiInstance;
|
|
34
|
-
emblaApi.on("settle", handleSettle);
|
|
35
|
-
}
|
|
36
|
-
function destroy() {
|
|
37
|
-
emblaApi.off("settle", handleSettle);
|
|
38
|
-
}
|
|
39
|
-
const self = {
|
|
40
|
-
name: "announcement",
|
|
41
|
-
options: userOptions,
|
|
42
|
-
init,
|
|
43
|
-
destroy
|
|
44
|
-
};
|
|
45
|
-
return self;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export { CarouselAnnouncement, getSlideLabel };
|
|
49
|
-
//# sourceMappingURL=CarouselAnnouncementPlugin.js.map
|