@brytdesigns/web-component-keen-slider 3.0.0 → 3.2.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/dist/main/KeenSlider.js +28 -6
- package/dist/main/KeenSlider.js.map +1 -1
- package/dist/main/components/keen-slider.js.map +1 -1
- package/dist/main/hooks/useKeenSlider.js +2 -2
- package/dist/main/hooks/useKeenSlider.js.map +1 -1
- package/dist/main/index.d.ts +11 -1
- package/dist/main/index.js +3 -1
- package/dist/main/index.js.map +1 -1
- package/dist/main/utils.js +16 -1
- package/dist/main/utils.js.map +1 -1
- package/package.json +2 -2
package/dist/main/KeenSlider.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { constrain } from "./utils.js";
|
|
1
|
+
import { constrain, formatSlideLabel } from "./utils.js";
|
|
2
2
|
import _KeenSlider from "keen-slider";
|
|
3
3
|
//#region src/KeenSlider.ts
|
|
4
4
|
function attachMoreDetails(prevSlide) {
|
|
@@ -9,6 +9,17 @@ function attachMoreDetails(prevSlide) {
|
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
+
* The `aria-label` this package last wrote on each slide.
|
|
13
|
+
*
|
|
14
|
+
* Module-level because the slider is rebuilt - by every `addPlugin`, by
|
|
15
|
+
* `refresh-on-children-change`, and by a new `config` or `slide-label` - and
|
|
16
|
+
* each rebuild is a fresh plugin with no memory of the last. Without this, a
|
|
17
|
+
* rebuilt slider saw the labels its predecessor had written, took every one
|
|
18
|
+
* for an authored label, and never touched them again: a changed template was
|
|
19
|
+
* ignored, and a slide count that changed left "1 of 3" on a carousel of four.
|
|
20
|
+
*/
|
|
21
|
+
var writtenSlideLabels = /* @__PURE__ */ new WeakMap();
|
|
22
|
+
/**
|
|
12
23
|
* APG's carousel pattern: a labelled group whose role description tells
|
|
13
24
|
* assistive tech what it is, with each slide a group of its own.
|
|
14
25
|
*
|
|
@@ -22,12 +33,19 @@ function attachMoreDetails(prevSlide) {
|
|
|
22
33
|
* constructor gets here to subscribe, so on a carousel nobody ever interacted
|
|
23
34
|
* with the slides got no ARIA at all — which is exactly why the container
|
|
24
35
|
* advertised owned `option` children it did not have.
|
|
36
|
+
*
|
|
37
|
+
* `slideLabel` is the `slide-label` template. Each slide's `aria-label` was
|
|
38
|
+
* hard-coded English, so a theme on any other locale could only translate it
|
|
39
|
+
* by authoring a label on every slide by hand.
|
|
25
40
|
*/
|
|
26
|
-
var attachAriaAttributes = (slider) => {
|
|
41
|
+
var attachAriaAttributes = (slider, slideLabel) => {
|
|
27
42
|
const container = slider.container;
|
|
28
43
|
const authoredContainerLabel = container.hasAttribute("aria-label");
|
|
29
44
|
const authoredSlideLabels = /* @__PURE__ */ new WeakSet();
|
|
30
|
-
for (const slide of slider.slides)
|
|
45
|
+
for (const slide of slider.slides) {
|
|
46
|
+
const label = slide.getAttribute("aria-label");
|
|
47
|
+
if (label !== null && label !== writtenSlideLabels.get(slide)) authoredSlideLabels.add(slide);
|
|
48
|
+
}
|
|
31
49
|
container.setAttribute("role", "group");
|
|
32
50
|
container.setAttribute("aria-roledescription", "carousel");
|
|
33
51
|
if (!authoredContainerLabel) container.setAttribute("aria-label", "Carousel");
|
|
@@ -55,7 +73,11 @@ var attachAriaAttributes = (slider) => {
|
|
|
55
73
|
slider.slides.forEach((slide, index) => {
|
|
56
74
|
slide.setAttribute("role", "group");
|
|
57
75
|
slide.setAttribute("aria-roledescription", "slide");
|
|
58
|
-
if (!authoredSlideLabels.has(slide))
|
|
76
|
+
if (!authoredSlideLabels.has(slide)) {
|
|
77
|
+
const label = formatSlideLabel(slideLabel, index + 1, total);
|
|
78
|
+
slide.setAttribute("aria-label", label);
|
|
79
|
+
writtenSlideLabels.set(slide, label);
|
|
80
|
+
}
|
|
59
81
|
slide.removeAttribute("aria-selected");
|
|
60
82
|
slide.removeAttribute("tabindex");
|
|
61
83
|
const visible = disabled || visiblePortion(index) > 0;
|
|
@@ -141,12 +163,12 @@ var attachKeyboardNavigation = (slider) => {
|
|
|
141
163
|
};
|
|
142
164
|
var KeenSlider = class extends _KeenSlider {
|
|
143
165
|
direction = null;
|
|
144
|
-
constructor(element, config, plugins = []) {
|
|
166
|
+
constructor(element, config, plugins = [], accessibility = {}) {
|
|
145
167
|
super(element, config, plugins);
|
|
146
168
|
const prevSlide = 0;
|
|
147
169
|
this.direction = null;
|
|
148
170
|
this.on("slideChanged", attachMoreDetails(prevSlide));
|
|
149
|
-
attachAriaAttributes(this);
|
|
171
|
+
attachAriaAttributes(this, accessibility.slideLabel);
|
|
150
172
|
attachKeyboardNavigation(this);
|
|
151
173
|
const _next = this.next, _prev = this.prev;
|
|
152
174
|
this.next = function() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeenSlider.js","names":[],"sources":["../../src/KeenSlider.ts"],"sourcesContent":["import type { ICustomElement } from \"component-register\";\n\nimport _KeenSlider, {\n\ttype KeenSliderHooks as _KeenSliderHooks,\n\ttype KeenSliderInstance as _KeenSliderInstance,\n\ttype KeenSliderOptions as _KeenSliderOptions,\n\ttype KeenSliderPlugin as _KeenSliderPlugin,\n} from \"keen-slider\";\n\nimport { constrain } from \"./utils\";\n\nexport type KeenSliderHooks = _KeenSliderHooks;\n\nexport type KeenSliderInstance<\n\tO = {},\n\tP = {},\n\tH extends _KeenSliderHooks = _KeenSliderHooks,\n> = _KeenSliderInstance<O, P, H>;\n\ntype ExtendedSlidesOption = NonNullable<\n\t_KeenSliderInstance[\"options\"][\"slides\"]\n> & {\n\tperScroll?: number;\n};\n\ntype ExtendedKeenSliderOptions = Omit<\n\t_KeenSliderInstance[\"options\"],\n\t\"slides\"\n> & {\n\tslides?: ExtendedSlidesOption;\n};\n\nexport type KeenSliderOptions<\n\tO = {},\n\tP = {},\n\tH extends _KeenSliderHooks = _KeenSliderHooks,\n> = _KeenSliderOptions<O, P, H> & {\n\tslides: {\n\t\tperScroll?: number;\n\t} & _KeenSliderOptions<O, P, H>[\"slides\"];\n};\n\nexport type KeenSliderPlugin<\n\tO = {},\n\tP = {},\n\tH extends _KeenSliderHooks = _KeenSliderHooks,\n> = _KeenSliderPlugin<O, P, H>;\n\nfunction attachMoreDetails(prevSlide: number) {\n\treturn (slider: KeenSliderInstance) => {\n\t\tif (slider.track.details.rel !== slider.animator.targetIdx) return;\n\n\t\t(slider as KeenSlider).direction =\n\t\t\tslider.track.details.rel > prevSlide ? \"forward\" : \"backward\";\n\n\t\tprevSlide = slider.track.details.rel;\n\t};\n}\n\n/**\n * APG's carousel pattern: a labelled group whose role description tells\n * assistive tech what it is, with each slide a group of its own.\n *\n * What this replaces was `role=\"listbox\"` with `role=\"option\"` slides, which\n * told a screen-reader user they were inside a form control they could select\n * from. It also made `aria-valuemin/max/now` invalid — a listbox has no value —\n * and left `aria-required-children` permanently unsatisfiable.\n *\n * The slide attributes used to be applied only from `created`, `slideChanged`,\n * `optionsChanged` and `updated`. `created` fires inside `super()`, before the\n * constructor gets here to subscribe, so on a carousel nobody ever interacted\n * with the slides got no ARIA at all — which is exactly why the container\n * advertised owned `option` children it did not have.\n */\nconst attachAriaAttributes: KeenSliderPlugin = (slider) => {\n\tconst container = slider.container;\n\n\t// Anything the markup already said is the author's. Recorded before the\n\t// first write, because after that every label looks authored.\n\tconst authoredContainerLabel = container.hasAttribute(\"aria-label\");\n\tconst authoredSlideLabels = new WeakSet<Element>();\n\tfor (const slide of slider.slides) {\n\t\tif (slide.hasAttribute(\"aria-label\")) authoredSlideLabels.add(slide);\n\t}\n\n\tcontainer.setAttribute(\"role\", \"group\");\n\tcontainer.setAttribute(\"aria-roledescription\", \"carousel\");\n\tif (!authoredContainerLabel) {\n\t\tcontainer.setAttribute(\"aria-label\", \"Carousel\");\n\t}\n\t// `false`, so moving a slide announces that slide rather than re-reading\n\t// the whole carousel. `aria-live` itself belongs to the auto-rotation\n\t// handling, which knows whether announcing is wanted at all.\n\tcontainer.setAttribute(\"aria-atomic\", \"false\");\n\tif (!container.hasAttribute(\"tabindex\")) {\n\t\tcontainer.setAttribute(\"tabindex\", \"0\");\n\t}\n\n\t// These were written by the previous version of this plugin and are not\n\t// valid on `group`. A theme has no reason to have set them itself.\n\tfor (const attribute of [\n\t\t\"aria-multiselectable\",\n\t\t\"aria-valuemin\",\n\t\t\"aria-valuemax\",\n\t\t\"aria-valuenow\",\n\t\t\"aria-orientation\",\n\t\t\"aria-busy\",\n\t]) {\n\t\tcontainer.removeAttribute(attribute);\n\t}\n\n\t/** The fraction of a slide that is in view, 0 when it is fully outside. */\n\tfunction visiblePortion(index: number) {\n\t\treturn slider.track?.details?.slides?.[index]?.portion ?? 0;\n\t}\n\n\tfunction updateTabIndexes(slide: HTMLElement, tabindex: string) {\n\t\tconst focusable = Array.from(\n\t\t\tslide.querySelectorAll(\n\t\t\t\t\"input, a, button:not(:disabled), textarea, select, [tabindex]\",\n\t\t\t),\n\t\t);\n\t\tfor (const element of focusable) {\n\t\t\telement.setAttribute(\"tabindex\", tabindex);\n\t\t}\n\t}\n\n\tfunction updateSlideAriaAttributes(slider: _KeenSliderInstance) {\n\t\tconst total = slider.slides.length;\n\t\tconst disabled = Boolean(slider.options?.disabled);\n\n\t\tslider.slides.forEach((slide, index) => {\n\t\t\tslide.setAttribute(\"role\", \"group\");\n\t\t\tslide.setAttribute(\"aria-roledescription\", \"slide\");\n\t\t\tif (!authoredSlideLabels.has(slide)) {\n\t\t\t\tslide.setAttribute(\"aria-label\", `${index + 1} of ${total}`);\n\t\t\t}\n\t\t\t// Carried over from the listbox model; meaningless on a slide.\n\t\t\tslide.removeAttribute(\"aria-selected\");\n\t\t\t// A slide is a group, not a tab stop. Its contents still are.\n\t\t\tslide.removeAttribute(\"tabindex\");\n\n\t\t\tconst visible = disabled || visiblePortion(index) > 0;\n\n\t\t\t// The styling contract. ARIA is not one: keying CSS off `aria-hidden`\n\t\t\t// is what made removing it a silent breaking change for every theme\n\t\t\t// descended from the skeleton.\n\t\t\tslide.setAttribute(\"data-slide-visible\", `${visible}`);\n\n\t\t\t// `aria-hidden` only where the slide is genuinely out of view, and\n\t\t\t// never over the focused element — hiding focused content strands the\n\t\t\t// user, which is what axe's `aria-hidden-focus` rule is about. The\n\t\t\t// old code hid every inactive slide, so in any multi-slide-per-view\n\t\t\t// carousel it hid slides the user could plainly see.\n\t\t\tconst holdsFocus =\n\t\t\t\tdocument.activeElement !== null &&\n\t\t\t\tslide.contains(document.activeElement);\n\t\t\tif (!visible && !holdsFocus) slide.setAttribute(\"aria-hidden\", \"true\");\n\t\t\telse slide.removeAttribute(\"aria-hidden\");\n\n\t\t\tupdateTabIndexes(slide, visible ? \"0\" : \"-1\");\n\t\t});\n\t}\n\n\tslider.on(\"slideChanged\", updateSlideAriaAttributes);\n\tslider.on(\"created\", updateSlideAriaAttributes);\n\tslider.on(\"optionsChanged\", updateSlideAriaAttributes);\n\tslider.on(\"updated\", updateSlideAriaAttributes);\n\n\t// `created` has already fired by the time this plugin is attached, so the\n\t// subscriptions above would otherwise leave the first render unwritten.\n\tupdateSlideAriaAttributes(slider);\n};\n\n/**\n * Anything that takes typed input. Arrow keys inside one of these belong to\n * the field, not the carousel — without this guard a search box inside a slide\n * cannot be navigated with the keyboard.\n */\nconst TEXT_ENTRY =\n\t'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"]';\n\n/**\n * Arrow-key navigation, and the `aria-live` rule for auto-rotation.\n *\n * The container has carried `tabindex=\"0\"` for as long as the ARIA plugin has\n * existed, with nothing listening — so it took a tab stop and did nothing with\n * it, which is worse than not being focusable. This is the handler that makes\n * the tab stop worth having.\n *\n * `aria-live` was previously hardcoded to `polite` on the container (twice).\n * APG is explicit that a live region on an auto-rotating carousel announces\n * slides the user never asked for, so the announcement is tied to the rotation\n * state instead: silent while rotating, polite once paused and the user is\n * driving.\n */\nconst attachKeyboardNavigation: KeenSliderPlugin = (slider) => {\n\tconst container = slider.container;\n\tconst controller = new AbortController();\n\n\tconst isVertical = () => Boolean(slider.options?.vertical);\n\n\tfunction handleKeydown(event: KeyboardEvent) {\n\t\tif (slider.options?.disabled) return;\n\n\t\tconst target = event.target;\n\t\tif (target instanceof Element && target.closest(TEXT_ENTRY)) return;\n\n\t\tconst back = isVertical() ? \"ArrowUp\" : \"ArrowLeft\";\n\t\tconst forward = isVertical() ? \"ArrowDown\" : \"ArrowRight\";\n\n\t\tswitch (event.key) {\n\t\t\tcase back:\n\t\t\t\tevent.preventDefault();\n\t\t\t\tslider.prev();\n\t\t\t\treturn;\n\t\t\tcase forward:\n\t\t\t\tevent.preventDefault();\n\t\t\t\tslider.next();\n\t\t\t\treturn;\n\t\t\tcase \"Home\":\n\t\t\t\tevent.preventDefault();\n\t\t\t\tslider.moveToIdx(0);\n\t\t\t\treturn;\n\t\t\tcase \"End\": {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst details = slider.track?.details;\n\t\t\t\tconst last = Number.isFinite(details?.maxIdx)\n\t\t\t\t\t? (details?.maxIdx ?? 0)\n\t\t\t\t\t: slider.slides.length - 1;\n\t\t\t\tslider.moveToIdx(last);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * `keen-slider-auto-switch` already dispatches this, and the autoplay\n\t * package publishes its pause state the same way, so both drive one code\n\t * path here rather than each teaching the carousel about itself.\n\t */\n\tfunction handleRotationChange(event: Event) {\n\t\tconst detail = (event as CustomEvent<{ isPaused?: boolean }>).detail;\n\t\tconst rotating = detail?.isPaused === false;\n\t\tcontainer.setAttribute(\"aria-live\", rotating ? \"off\" : \"polite\");\n\t}\n\n\tcontainer.addEventListener(\"keydown\", handleKeydown, {\n\t\tsignal: controller.signal,\n\t});\n\tcontainer.addEventListener(\"autoswitch:update\", handleRotationChange, {\n\t\tsignal: controller.signal,\n\t});\n\tcontainer.addEventListener(\"autoplay:update\", handleRotationChange, {\n\t\tsignal: controller.signal,\n\t});\n\n\t// Nothing is auto-rotating until something says so, and a carousel the user\n\t// drives should announce where they have got to.\n\tif (!container.hasAttribute(\"aria-live\")) {\n\t\tcontainer.setAttribute(\"aria-live\", \"polite\");\n\t}\n\n\tslider.on(\"destroyed\", () => controller.abort());\n};\n\nexport default class KeenSlider extends _KeenSlider {\n\tdirection: \"forward\" | \"backward\" | null = null;\n\tconstructor(\n\t\telement: ICustomElement & HTMLElement,\n\t\tconfig: KeenSliderOptions,\n\t\tplugins: _KeenSliderPlugin[] = [],\n\t) {\n\t\tsuper(element, config, plugins);\n\t\tconst prevSlide = 0;\n\n\t\tthis.direction = null;\n\t\tthis.on(\"slideChanged\", attachMoreDetails(prevSlide) as any);\n\n\t\tattachAriaAttributes(this);\n\t\tattachKeyboardNavigation(this);\n\n\t\tconst _next = this.next,\n\t\t\t_prev = this.prev;\n\n\t\tthis.next = function () {\n\t\t\tif (\n\t\t\t\ttypeof this.options.slides === \"number\" ||\n\t\t\t\ttypeof this.options.slides === \"function\"\n\t\t\t)\n\t\t\t\treturn _next();\n\t\t\tlet amount: number = 1;\n\t\t\tif (this.options?.slides && \"perScroll\" in this.options.slides === true) {\n\t\t\t\tamount = (this.options?.slides?.perScroll as number) || 1;\n\t\t\t}\n\t\t\tif (!this.options.loop) {\n\t\t\t\treturn this.moveToIdx(\n\t\t\t\t\tconstrain(\n\t\t\t\t\t\tthis.track.details.rel + amount,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tthis.track.details.maxIdx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn this.moveToIdx(constrain(this.track.details.abs + amount), true);\n\t\t};\n\n\t\tthis.prev = function () {\n\t\t\tif (\n\t\t\t\ttypeof this.options.slides === \"number\" ||\n\t\t\t\ttypeof this.options.slides === \"function\"\n\t\t\t)\n\t\t\t\treturn _prev();\n\t\t\tlet amount: number = 1;\n\t\t\tif (this.options?.slides && \"perScroll\" in this.options.slides === true) {\n\t\t\t\tamount = (this.options?.slides?.perScroll as number) || 1;\n\t\t\t}\n\t\t\tif (!this.options.loop) {\n\t\t\t\tthis.moveToIdx(\n\t\t\t\t\tconstrain(\n\t\t\t\t\t\tthis.track.details.rel - amount,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tthis.track.details.maxIdx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn this.moveToIdx(constrain(this.track.details.abs - amount), true);\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KeenSlider.js","names":[],"sources":["../../src/KeenSlider.ts"],"sourcesContent":["import type { ICustomElement } from \"component-register\";\n\nimport _KeenSlider, {\n\ttype KeenSliderHooks as _KeenSliderHooks,\n\ttype KeenSliderInstance as _KeenSliderInstance,\n\ttype KeenSliderOptions as _KeenSliderOptions,\n\ttype KeenSliderPlugin as _KeenSliderPlugin,\n} from \"keen-slider\";\n\nimport { constrain, formatSlideLabel } from \"./utils\";\n\nexport type KeenSliderHooks = _KeenSliderHooks;\n\nexport type KeenSliderInstance<\n\tO = {},\n\tP = {},\n\tH extends _KeenSliderHooks = _KeenSliderHooks,\n> = _KeenSliderInstance<O, P, H>;\n\ntype ExtendedSlidesOption = NonNullable<\n\t_KeenSliderInstance[\"options\"][\"slides\"]\n> & {\n\tperScroll?: number;\n};\n\ntype ExtendedKeenSliderOptions = Omit<\n\t_KeenSliderInstance[\"options\"],\n\t\"slides\"\n> & {\n\tslides?: ExtendedSlidesOption;\n};\n\nexport type KeenSliderOptions<\n\tO = {},\n\tP = {},\n\tH extends _KeenSliderHooks = _KeenSliderHooks,\n> = _KeenSliderOptions<O, P, H> & {\n\tslides: {\n\t\tperScroll?: number;\n\t} & _KeenSliderOptions<O, P, H>[\"slides\"];\n};\n\nexport type KeenSliderPlugin<\n\tO = {},\n\tP = {},\n\tH extends _KeenSliderHooks = _KeenSliderHooks,\n> = _KeenSliderPlugin<O, P, H>;\n\nfunction attachMoreDetails(prevSlide: number) {\n\treturn (slider: KeenSliderInstance) => {\n\t\tif (slider.track.details.rel !== slider.animator.targetIdx) return;\n\n\t\t(slider as KeenSlider).direction =\n\t\t\tslider.track.details.rel > prevSlide ? \"forward\" : \"backward\";\n\n\t\tprevSlide = slider.track.details.rel;\n\t};\n}\n\n/**\n * The `aria-label` this package last wrote on each slide.\n *\n * Module-level because the slider is rebuilt - by every `addPlugin`, by\n * `refresh-on-children-change`, and by a new `config` or `slide-label` - and\n * each rebuild is a fresh plugin with no memory of the last. Without this, a\n * rebuilt slider saw the labels its predecessor had written, took every one\n * for an authored label, and never touched them again: a changed template was\n * ignored, and a slide count that changed left \"1 of 3\" on a carousel of four.\n */\nconst writtenSlideLabels = new WeakMap<Element, string>();\n\n/**\n * APG's carousel pattern: a labelled group whose role description tells\n * assistive tech what it is, with each slide a group of its own.\n *\n * What this replaces was `role=\"listbox\"` with `role=\"option\"` slides, which\n * told a screen-reader user they were inside a form control they could select\n * from. It also made `aria-valuemin/max/now` invalid — a listbox has no value —\n * and left `aria-required-children` permanently unsatisfiable.\n *\n * The slide attributes used to be applied only from `created`, `slideChanged`,\n * `optionsChanged` and `updated`. `created` fires inside `super()`, before the\n * constructor gets here to subscribe, so on a carousel nobody ever interacted\n * with the slides got no ARIA at all — which is exactly why the container\n * advertised owned `option` children it did not have.\n *\n * `slideLabel` is the `slide-label` template. Each slide's `aria-label` was\n * hard-coded English, so a theme on any other locale could only translate it\n * by authoring a label on every slide by hand.\n */\nconst attachAriaAttributes = (\n\tslider: KeenSliderInstance,\n\tslideLabel: string | undefined,\n) => {\n\tconst container = slider.container;\n\n\t// Anything the markup already said is the author's. Recorded before the\n\t// first write, and checked against what an earlier instance wrote, because\n\t// otherwise every label this package wrote looks authored.\n\tconst authoredContainerLabel = container.hasAttribute(\"aria-label\");\n\tconst authoredSlideLabels = new WeakSet<Element>();\n\tfor (const slide of slider.slides) {\n\t\tconst label = slide.getAttribute(\"aria-label\");\n\t\tif (label !== null && label !== writtenSlideLabels.get(slide)) {\n\t\t\tauthoredSlideLabels.add(slide);\n\t\t}\n\t}\n\n\tcontainer.setAttribute(\"role\", \"group\");\n\tcontainer.setAttribute(\"aria-roledescription\", \"carousel\");\n\tif (!authoredContainerLabel) {\n\t\tcontainer.setAttribute(\"aria-label\", \"Carousel\");\n\t}\n\t// `false`, so moving a slide announces that slide rather than re-reading\n\t// the whole carousel. `aria-live` itself belongs to the auto-rotation\n\t// handling, which knows whether announcing is wanted at all.\n\tcontainer.setAttribute(\"aria-atomic\", \"false\");\n\tif (!container.hasAttribute(\"tabindex\")) {\n\t\tcontainer.setAttribute(\"tabindex\", \"0\");\n\t}\n\n\t// These were written by the previous version of this plugin and are not\n\t// valid on `group`. A theme has no reason to have set them itself.\n\tfor (const attribute of [\n\t\t\"aria-multiselectable\",\n\t\t\"aria-valuemin\",\n\t\t\"aria-valuemax\",\n\t\t\"aria-valuenow\",\n\t\t\"aria-orientation\",\n\t\t\"aria-busy\",\n\t]) {\n\t\tcontainer.removeAttribute(attribute);\n\t}\n\n\t/** The fraction of a slide that is in view, 0 when it is fully outside. */\n\tfunction visiblePortion(index: number) {\n\t\treturn slider.track?.details?.slides?.[index]?.portion ?? 0;\n\t}\n\n\tfunction updateTabIndexes(slide: HTMLElement, tabindex: string) {\n\t\tconst focusable = Array.from(\n\t\t\tslide.querySelectorAll(\n\t\t\t\t\"input, a, button:not(:disabled), textarea, select, [tabindex]\",\n\t\t\t),\n\t\t);\n\t\tfor (const element of focusable) {\n\t\t\telement.setAttribute(\"tabindex\", tabindex);\n\t\t}\n\t}\n\n\tfunction updateSlideAriaAttributes(slider: _KeenSliderInstance) {\n\t\tconst total = slider.slides.length;\n\t\tconst disabled = Boolean(slider.options?.disabled);\n\n\t\tslider.slides.forEach((slide, index) => {\n\t\t\tslide.setAttribute(\"role\", \"group\");\n\t\t\tslide.setAttribute(\"aria-roledescription\", \"slide\");\n\t\t\tif (!authoredSlideLabels.has(slide)) {\n\t\t\t\tconst label = formatSlideLabel(slideLabel, index + 1, total);\n\t\t\t\tslide.setAttribute(\"aria-label\", label);\n\t\t\t\twrittenSlideLabels.set(slide, label);\n\t\t\t}\n\t\t\t// Carried over from the listbox model; meaningless on a slide.\n\t\t\tslide.removeAttribute(\"aria-selected\");\n\t\t\t// A slide is a group, not a tab stop. Its contents still are.\n\t\t\tslide.removeAttribute(\"tabindex\");\n\n\t\t\tconst visible = disabled || visiblePortion(index) > 0;\n\n\t\t\t// The styling contract. ARIA is not one: keying CSS off `aria-hidden`\n\t\t\t// is what made removing it a silent breaking change for every theme\n\t\t\t// descended from the skeleton.\n\t\t\tslide.setAttribute(\"data-slide-visible\", `${visible}`);\n\n\t\t\t// `aria-hidden` only where the slide is genuinely out of view, and\n\t\t\t// never over the focused element — hiding focused content strands the\n\t\t\t// user, which is what axe's `aria-hidden-focus` rule is about. The\n\t\t\t// old code hid every inactive slide, so in any multi-slide-per-view\n\t\t\t// carousel it hid slides the user could plainly see.\n\t\t\tconst holdsFocus =\n\t\t\t\tdocument.activeElement !== null &&\n\t\t\t\tslide.contains(document.activeElement);\n\t\t\tif (!visible && !holdsFocus) slide.setAttribute(\"aria-hidden\", \"true\");\n\t\t\telse slide.removeAttribute(\"aria-hidden\");\n\n\t\t\tupdateTabIndexes(slide, visible ? \"0\" : \"-1\");\n\t\t});\n\t}\n\n\tslider.on(\"slideChanged\", updateSlideAriaAttributes);\n\tslider.on(\"created\", updateSlideAriaAttributes);\n\tslider.on(\"optionsChanged\", updateSlideAriaAttributes);\n\tslider.on(\"updated\", updateSlideAriaAttributes);\n\n\t// `created` has already fired by the time this plugin is attached, so the\n\t// subscriptions above would otherwise leave the first render unwritten.\n\tupdateSlideAriaAttributes(slider);\n};\n\n/**\n * Anything that takes typed input. Arrow keys inside one of these belong to\n * the field, not the carousel — without this guard a search box inside a slide\n * cannot be navigated with the keyboard.\n */\nconst TEXT_ENTRY =\n\t'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"]';\n\n/**\n * Arrow-key navigation, and the `aria-live` rule for auto-rotation.\n *\n * The container has carried `tabindex=\"0\"` for as long as the ARIA plugin has\n * existed, with nothing listening — so it took a tab stop and did nothing with\n * it, which is worse than not being focusable. This is the handler that makes\n * the tab stop worth having.\n *\n * `aria-live` was previously hardcoded to `polite` on the container (twice).\n * APG is explicit that a live region on an auto-rotating carousel announces\n * slides the user never asked for, so the announcement is tied to the rotation\n * state instead: silent while rotating, polite once paused and the user is\n * driving.\n */\nconst attachKeyboardNavigation: KeenSliderPlugin = (slider) => {\n\tconst container = slider.container;\n\tconst controller = new AbortController();\n\n\tconst isVertical = () => Boolean(slider.options?.vertical);\n\n\tfunction handleKeydown(event: KeyboardEvent) {\n\t\tif (slider.options?.disabled) return;\n\n\t\tconst target = event.target;\n\t\tif (target instanceof Element && target.closest(TEXT_ENTRY)) return;\n\n\t\tconst back = isVertical() ? \"ArrowUp\" : \"ArrowLeft\";\n\t\tconst forward = isVertical() ? \"ArrowDown\" : \"ArrowRight\";\n\n\t\tswitch (event.key) {\n\t\t\tcase back:\n\t\t\t\tevent.preventDefault();\n\t\t\t\tslider.prev();\n\t\t\t\treturn;\n\t\t\tcase forward:\n\t\t\t\tevent.preventDefault();\n\t\t\t\tslider.next();\n\t\t\t\treturn;\n\t\t\tcase \"Home\":\n\t\t\t\tevent.preventDefault();\n\t\t\t\tslider.moveToIdx(0);\n\t\t\t\treturn;\n\t\t\tcase \"End\": {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tconst details = slider.track?.details;\n\t\t\t\tconst last = Number.isFinite(details?.maxIdx)\n\t\t\t\t\t? (details?.maxIdx ?? 0)\n\t\t\t\t\t: slider.slides.length - 1;\n\t\t\t\tslider.moveToIdx(last);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * `keen-slider-auto-switch` already dispatches this, and the autoplay\n\t * package publishes its pause state the same way, so both drive one code\n\t * path here rather than each teaching the carousel about itself.\n\t */\n\tfunction handleRotationChange(event: Event) {\n\t\tconst detail = (event as CustomEvent<{ isPaused?: boolean }>).detail;\n\t\tconst rotating = detail?.isPaused === false;\n\t\tcontainer.setAttribute(\"aria-live\", rotating ? \"off\" : \"polite\");\n\t}\n\n\tcontainer.addEventListener(\"keydown\", handleKeydown, {\n\t\tsignal: controller.signal,\n\t});\n\tcontainer.addEventListener(\"autoswitch:update\", handleRotationChange, {\n\t\tsignal: controller.signal,\n\t});\n\tcontainer.addEventListener(\"autoplay:update\", handleRotationChange, {\n\t\tsignal: controller.signal,\n\t});\n\n\t// Nothing is auto-rotating until something says so, and a carousel the user\n\t// drives should announce where they have got to.\n\tif (!container.hasAttribute(\"aria-live\")) {\n\t\tcontainer.setAttribute(\"aria-live\", \"polite\");\n\t}\n\n\tslider.on(\"destroyed\", () => controller.abort());\n};\n\nexport type KeenSliderAccessibilityOptions = {\n\t/** Template for each slide's `aria-label`: `{n}` and `{total}`. */\n\tslideLabel?: string;\n};\n\nexport default class KeenSlider extends _KeenSlider {\n\tdirection: \"forward\" | \"backward\" | null = null;\n\tconstructor(\n\t\telement: ICustomElement & HTMLElement,\n\t\tconfig: KeenSliderOptions,\n\t\tplugins: _KeenSliderPlugin[] = [],\n\t\taccessibility: KeenSliderAccessibilityOptions = {},\n\t) {\n\t\tsuper(element, config, plugins);\n\t\tconst prevSlide = 0;\n\n\t\tthis.direction = null;\n\t\tthis.on(\"slideChanged\", attachMoreDetails(prevSlide) as any);\n\n\t\tattachAriaAttributes(this, accessibility.slideLabel);\n\t\tattachKeyboardNavigation(this);\n\n\t\tconst _next = this.next,\n\t\t\t_prev = this.prev;\n\n\t\tthis.next = function () {\n\t\t\tif (\n\t\t\t\ttypeof this.options.slides === \"number\" ||\n\t\t\t\ttypeof this.options.slides === \"function\"\n\t\t\t)\n\t\t\t\treturn _next();\n\t\t\tlet amount: number = 1;\n\t\t\tif (this.options?.slides && \"perScroll\" in this.options.slides === true) {\n\t\t\t\tamount = (this.options?.slides?.perScroll as number) || 1;\n\t\t\t}\n\t\t\tif (!this.options.loop) {\n\t\t\t\treturn this.moveToIdx(\n\t\t\t\t\tconstrain(\n\t\t\t\t\t\tthis.track.details.rel + amount,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tthis.track.details.maxIdx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn this.moveToIdx(constrain(this.track.details.abs + amount), true);\n\t\t};\n\n\t\tthis.prev = function () {\n\t\t\tif (\n\t\t\t\ttypeof this.options.slides === \"number\" ||\n\t\t\t\ttypeof this.options.slides === \"function\"\n\t\t\t)\n\t\t\t\treturn _prev();\n\t\t\tlet amount: number = 1;\n\t\t\tif (this.options?.slides && \"perScroll\" in this.options.slides === true) {\n\t\t\t\tamount = (this.options?.slides?.perScroll as number) || 1;\n\t\t\t}\n\t\t\tif (!this.options.loop) {\n\t\t\t\tthis.moveToIdx(\n\t\t\t\t\tconstrain(\n\t\t\t\t\t\tthis.track.details.rel - amount,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tthis.track.details.maxIdx,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn this.moveToIdx(constrain(this.track.details.abs - amount), true);\n\t\t};\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keen-slider.js","names":[],"sources":["../../../src/components/keen-slider.ts"],"sourcesContent":["import type { CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\nimport { createGuardedEffect } from \"@brytdesigns/web-component-core/utils\";\n\nimport { createRoot } from \"solid-js\";\nimport {\n\tprovideKeenSliderContext,\n\tuseKeenSliderContext,\n} from \"../hooks/index.js\";\nimport _KeenSlider, {\n\ttype KeenSliderInstance,\n\ttype KeenSliderOptions,\n} from \"../KeenSlider.js\";\n\nexport type Props = {\n\tconfig?: KeenSliderOptions;\n\tcenterSlides: boolean;\n\trefreshOnChildrenChange: boolean;\n};\n\nexport const Name = `keen-slider`;\n\nexport const Component: CorrectComponentType<Props> = (props, { element }) => {\n\tconst context = provideKeenSliderContext(props, element);\n\tconst [slider, methods] = useKeenSliderContext(context);\n\n\tObject.assign(element, {\n\t\t// `observable` is gone in v2; pushing a signal out to an external\n\t\t// subscriber is now an effect inside its own root, so the returned\n\t\t// disposer is the unsubscribe. The public signature is unchanged.\n\t\tsubscribe(callback = (_: KeenSliderInstance) => null) {\n\t\t\tfunction listen(slider: KeenSliderInstance) {\n\t\t\t\tconst cleanup = callback(slider);\n\t\t\t\tslider.on(\n\t\t\t\t\t\"destroyed\",\n\t\t\t\t\ttypeof cleanup === \"function\" ? cleanup : () => null,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn createRoot((dispose) => {\n\t\t\t\tcreateGuardedEffect(slider, listen);\n\t\t\t\treturn dispose;\n\t\t\t});\n\t\t},\n\t});\n\n\tObject.assign(element, { slider });\n\tObject.assign(element, { addPlugin: methods.addPlugin });\n};\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"keen-slider.js","names":[],"sources":["../../../src/components/keen-slider.ts"],"sourcesContent":["import type { CorrectComponentType } from \"@brytdesigns/web-component-core/utils\";\nimport { createGuardedEffect } from \"@brytdesigns/web-component-core/utils\";\n\nimport { createRoot } from \"solid-js\";\nimport {\n\tprovideKeenSliderContext,\n\tuseKeenSliderContext,\n} from \"../hooks/index.js\";\nimport _KeenSlider, {\n\ttype KeenSliderInstance,\n\ttype KeenSliderOptions,\n} from \"../KeenSlider.js\";\n\nexport type Props = {\n\tconfig?: KeenSliderOptions;\n\tcenterSlides: boolean;\n\trefreshOnChildrenChange: boolean;\n\t/**\n\t * Each slide's `aria-label`. `{n}` is replaced with the slide number and\n\t * `{total}` with the slide count. Translate it rather than reaching in from\n\t * a theme. Slides that already carry an `aria-label` keep their own.\n\t */\n\tslideLabel: string;\n};\n\nexport const Name = `keen-slider`;\n\nexport const Component: CorrectComponentType<Props> = (props, { element }) => {\n\tconst context = provideKeenSliderContext(props, element);\n\tconst [slider, methods] = useKeenSliderContext(context);\n\n\tObject.assign(element, {\n\t\t// `observable` is gone in v2; pushing a signal out to an external\n\t\t// subscriber is now an effect inside its own root, so the returned\n\t\t// disposer is the unsubscribe. The public signature is unchanged.\n\t\tsubscribe(callback = (_: KeenSliderInstance) => null) {\n\t\t\tfunction listen(slider: KeenSliderInstance) {\n\t\t\t\tconst cleanup = callback(slider);\n\t\t\t\tslider.on(\n\t\t\t\t\t\"destroyed\",\n\t\t\t\t\ttypeof cleanup === \"function\" ? cleanup : () => null,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn createRoot((dispose) => {\n\t\t\t\tcreateGuardedEffect(slider, listen);\n\t\t\t\treturn dispose;\n\t\t\t});\n\t\t},\n\t});\n\n\tObject.assign(element, { slider });\n\tObject.assign(element, { addPlugin: methods.addPlugin });\n};\n"],"mappings":";;;;;;AAyBA,IAAa,OAAO;AAEpB,IAAa,aAA0C,OAAO,EAAE,cAAc;CAC7E,MAAM,UAAU,yBAAyB,OAAO,OAAO;CACvD,MAAM,CAAC,QAAQ,WAAW,qBAAqB,OAAO;CAEtD,OAAO,OAAO,SAAS,EAItB,UAAU,YAAY,MAA0B,MAAM;EACrD,SAAS,OAAO,QAA4B;GAC3C,MAAM,UAAU,SAAS,MAAM;GAC/B,OAAO,GACN,aACA,OAAO,YAAY,aAAa,gBAAgB,IACjD;EACD;EACA,OAAO,YAAY,YAAY;GAC9B,oBAAoB,QAAQ,MAAM;GAClC,OAAO;EACR,CAAC;CACF,EACD,CAAC;CAED,OAAO,OAAO,SAAS,EAAE,OAAO,CAAC;CACjC,OAAO,OAAO,SAAS,EAAE,WAAW,QAAQ,UAAU,CAAC;AACxD"}
|
|
@@ -4,7 +4,7 @@ import { createMemo, createSignal, merge, omit, onCleanup } from "solid-js";
|
|
|
4
4
|
import { consume, createContext, provide } from "component-register";
|
|
5
5
|
//#region src/hooks/useKeenSlider.ts
|
|
6
6
|
function initializeKeenSliderContext(props) {
|
|
7
|
-
const publicProps = omit(props, "root", "centerSlides", "refreshOnChildrenChange");
|
|
7
|
+
const publicProps = omit(props, "root", "centerSlides", "refreshOnChildrenChange", "slideLabel");
|
|
8
8
|
const [plugins, setPlugins] = createSignal([]);
|
|
9
9
|
const [forceSliderRebuild, setForceSliderRebuild] = createSignal(false);
|
|
10
10
|
const mutObserver = createMemo(() => {
|
|
@@ -17,7 +17,7 @@ function initializeKeenSliderContext(props) {
|
|
|
17
17
|
});
|
|
18
18
|
const slider = createMemo(() => {
|
|
19
19
|
props.root.setAttribute("data-initialized", "true");
|
|
20
|
-
const slider = new KeenSlider(props.root, publicProps.config || {}, plugins());
|
|
20
|
+
const slider = new KeenSlider(props.root, publicProps.config || {}, plugins(), { slideLabel: props.slideLabel });
|
|
21
21
|
const m = mutObserver();
|
|
22
22
|
if (m) {
|
|
23
23
|
m.observe(slider.container, { childList: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useKeenSlider.js","names":[],"sources":["../../../src/hooks/useKeenSlider.ts"],"sourcesContent":["import {\n\tcreateGuardedEffect,\n\tcreateRemoteContext,\n\tgetContextFromProvider,\n\tinvokeOnLoaded,\n} from \"@brytdesigns/web-component-core/utils\";\nimport {\n\tconsume,\n\tcreateContext,\n\ttype ICustomElement,\n\tprovide,\n} from \"component-register\";\nimport { createMemo, createSignal, merge, omit, onCleanup } from \"solid-js\";\n\nimport KeenSlider, {\n\ttype KeenSliderInstance,\n\ttype KeenSliderOptions,\n\ttype KeenSliderPlugin,\n} from \"../KeenSlider\";\n\ntype CreateContextOptions = {\n\troot: HTMLElement & ICustomElement;\n\tconfig?: KeenSliderOptions;\n\tcenterSlides?: boolean;\n\trefreshOnChildrenChange?: boolean;\n};\n\ntype WalkableNode = Parameters<typeof provide>[2];\n\ntype KeenSliderContext = ReturnType<typeof initializeKeenSliderContext>;\n\nfunction initializeKeenSliderContext(props: CreateContextOptions) {\n\t// `omit` returns only the rest; picked keys are read straight off `props`.\n\tconst publicProps = omit(\n\t\tprops,\n\t\t\"root\",\n\t\t\"centerSlides\",\n\t\t\"refreshOnChildrenChange\",\n\t);\n\n\tconst [plugins, setPlugins] = createSignal<KeenSliderPlugin[]>([]);\n\tconst [forceSliderRebuild, setForceSliderRebuild] = createSignal(false);\n\n\tconst mutObserver = createMemo(() => {\n\t\tif (props.refreshOnChildrenChange)\n\t\t\treturn new MutationObserver((mutations) => {\n\t\t\t\tmutations.forEach((_) => {\n\t\t\t\t\tsetForceSliderRebuild((v) => !v);\n\t\t\t\t});\n\t\t\t});\n\t\treturn null;\n\t});\n\n\tconst slider = createMemo(() => {\n\t\tprops.root.setAttribute(\"data-initialized\", \"true\");\n\t\tconst slider = new KeenSlider(\n\t\t\tprops.root,\n\t\t\tpublicProps.config || ({} as any),\n\t\t\tplugins(),\n\t\t);\n\t\tconst m = mutObserver();\n\n\t\tif (m) {\n\t\t\tm.observe(slider.container, { childList: true });\n\t\t\tforceSliderRebuild();\n\t\t}\n\n\t\tonCleanup(() => {\n\t\t\tslider.destroy();\n\t\t\tprops.root.setAttribute(\"data-initialized\", \"false\");\n\t\t\tif (m) m.disconnect();\n\t\t});\n\n\t\treturn slider;\n\t});\n\n\tfunction addPlugin(plugin: KeenSliderPlugin) {\n\t\tlet index = -1;\n\n\t\tsetPlugins((plugins) => {\n\t\t\tindex = plugins.length;\n\t\t\treturn [...plugins, plugin];\n\t\t});\n\n\t\treturn () => {\n\t\t\tsetPlugins((plugins) => {\n\t\t\t\treturn [...plugins.slice(0, index), ...plugins.slice(index + 1)];\n\t\t\t});\n\t\t};\n\t}\n\n\tconst centeredPlugin: KeenSliderPlugin = (slider) => {\n\t\tfunction centerSlides(slider: KeenSliderInstance) {\n\t\t\tif (slider.track.details.maxIdx > 0) {\n\t\t\t\t//@ts-expect-error\n\t\t\t\tslider.container.style.justifyContent = null;\n\t\t\t\t//@ts-expect-error\n\t\t\t\tslider.container.style.transform = null;\n\t\t\t} else {\n\t\t\t\tslider.container.style.cssText = `\n justify-content: center;\n transform: translateX(-${(slider.options.slides as any)?.spacing || 16}px)\n `;\n\t\t\t}\n\t\t}\n\n\t\tslider.on(\"created\", centerSlides);\n\t\tslider.on(\"optionsChanged\", centerSlides);\n\t};\n\n\tcreateGuardedEffect(\n\t\t() => props.centerSlides,\n\t\t(centerSlides) => {\n\t\t\tif (!centerSlides) return;\n\t\t\tconst remove = addPlugin(centeredPlugin);\n\t\t\treturn remove;\n\t\t},\n\t);\n\n\tcreateGuardedEffect(plugins, (plugins) => {\n\t\tif (plugins.length === 0) return;\n\t\tconsole.log(\n\t\t\t`Registered a new plugin on element.\\n`,\n\t\t\t`Total slider plugins: ${plugins.length}`,\n\t\t);\n\t});\n\n\treturn [slider, { addPlugin }] as const;\n}\n\nconst KeenSliderContextState = createContext(initializeKeenSliderContext);\n\nexport const provideKeenSliderContext = (\n\tinitialState: Omit<CreateContextOptions, \"root\">,\n\telement: WalkableNode,\n): KeenSliderContext => {\n\tconst props = merge(initialState, { root: element });\n\treturn provide(KeenSliderContextState, props, element);\n};\n\nexport const useKeenSliderContext = (context: KeenSliderContext) => {\n\treturn context;\n};\n\nexport const useKeenSlider = (element: HTMLElement & ICustomElement) => {\n\tconst context: KeenSliderContext = consume(KeenSliderContextState, element);\n\n\tif (!context) {\n\t\tthrow new Error(\n\t\t\t\"KeenSliderContext not found! Please ensure to wrap your custom element with keen-slider element.\",\n\t\t);\n\t}\n\n\treturn useKeenSliderContext(context);\n};\n\nexport const getKeenSliderContext = (element: Element) => {\n\tconst context = getContextFromProvider<KeenSliderContext>(\n\t\tKeenSliderContextState,\n\t\telement,\n\t);\n\treturn useKeenSliderContext(context);\n};\n\ntype AddPluginOptions = {\n\ttarget: void | HTMLElement;\n\tplugin: KeenSliderPlugin;\n\tcontroller?: AbortController;\n};\n\nexport function addPlugin({ target, plugin, controller }: AddPluginOptions) {\n\tif (!target) return;\n\n\tinvokeOnLoaded(\n\t\t() => {\n\t\t\tconst [_, { addPlugin }] = getKeenSliderContext(target);\n\t\t\tconst removePlugin = addPlugin(plugin);\n\t\t\tcontroller?.signal?.addEventListener(\"abort\", removePlugin);\n\t\t},\n\t\t{\n\t\t\tsignal: controller?.signal,\n\t\t},\n\t);\n}\n\nexport const useKeenSliderAt = createRemoteContext<KeenSliderContext>(\n\tKeenSliderContextState,\n\t{\n\t\t// A target may name the slider itself or an ancestor of it. Stated once\n\t\t// here instead of the identical ten-line thunk that was copy-pasted into\n\t\t// all six extension packages.\n\t\tresolve: (target, host) => {\n\t\t\tconst el = target ? document.querySelector(target) : host;\n\t\t\tif (!el) return null;\n\t\t\treturn el.tagName === \"KEEN-SLIDER\"\n\t\t\t\t? el\n\t\t\t\t: el.querySelector(\"keen-slider\");\n\t\t},\n\t},\n);\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"useKeenSlider.js","names":[],"sources":["../../../src/hooks/useKeenSlider.ts"],"sourcesContent":["import {\n\tcreateGuardedEffect,\n\tcreateRemoteContext,\n\tgetContextFromProvider,\n\tinvokeOnLoaded,\n} from \"@brytdesigns/web-component-core/utils\";\nimport {\n\tconsume,\n\tcreateContext,\n\ttype ICustomElement,\n\tprovide,\n} from \"component-register\";\nimport { createMemo, createSignal, merge, omit, onCleanup } from \"solid-js\";\n\nimport KeenSlider, {\n\ttype KeenSliderInstance,\n\ttype KeenSliderOptions,\n\ttype KeenSliderPlugin,\n} from \"../KeenSlider\";\n\ntype CreateContextOptions = {\n\troot: HTMLElement & ICustomElement;\n\tconfig?: KeenSliderOptions;\n\tcenterSlides?: boolean;\n\trefreshOnChildrenChange?: boolean;\n\tslideLabel?: string;\n};\n\ntype WalkableNode = Parameters<typeof provide>[2];\n\ntype KeenSliderContext = ReturnType<typeof initializeKeenSliderContext>;\n\nfunction initializeKeenSliderContext(props: CreateContextOptions) {\n\t// `omit` returns only the rest; picked keys are read straight off `props`.\n\tconst publicProps = omit(\n\t\tprops,\n\t\t\"root\",\n\t\t\"centerSlides\",\n\t\t\"refreshOnChildrenChange\",\n\t\t\"slideLabel\",\n\t);\n\n\tconst [plugins, setPlugins] = createSignal<KeenSliderPlugin[]>([]);\n\tconst [forceSliderRebuild, setForceSliderRebuild] = createSignal(false);\n\n\tconst mutObserver = createMemo(() => {\n\t\tif (props.refreshOnChildrenChange)\n\t\t\treturn new MutationObserver((mutations) => {\n\t\t\t\tmutations.forEach((_) => {\n\t\t\t\t\tsetForceSliderRebuild((v) => !v);\n\t\t\t\t});\n\t\t\t});\n\t\treturn null;\n\t});\n\n\tconst slider = createMemo(() => {\n\t\tprops.root.setAttribute(\"data-initialized\", \"true\");\n\t\t// Read here, so it is tracked: the template is captured when the\n\t\t// slider is built, so a new one rebuilds it, the same as a new\n\t\t// `config` does.\n\t\tconst slider = new KeenSlider(\n\t\t\tprops.root,\n\t\t\tpublicProps.config || ({} as any),\n\t\t\tplugins(),\n\t\t\t{ slideLabel: props.slideLabel },\n\t\t);\n\t\tconst m = mutObserver();\n\n\t\tif (m) {\n\t\t\tm.observe(slider.container, { childList: true });\n\t\t\tforceSliderRebuild();\n\t\t}\n\n\t\tonCleanup(() => {\n\t\t\tslider.destroy();\n\t\t\tprops.root.setAttribute(\"data-initialized\", \"false\");\n\t\t\tif (m) m.disconnect();\n\t\t});\n\n\t\treturn slider;\n\t});\n\n\tfunction addPlugin(plugin: KeenSliderPlugin) {\n\t\tlet index = -1;\n\n\t\tsetPlugins((plugins) => {\n\t\t\tindex = plugins.length;\n\t\t\treturn [...plugins, plugin];\n\t\t});\n\n\t\treturn () => {\n\t\t\tsetPlugins((plugins) => {\n\t\t\t\treturn [...plugins.slice(0, index), ...plugins.slice(index + 1)];\n\t\t\t});\n\t\t};\n\t}\n\n\tconst centeredPlugin: KeenSliderPlugin = (slider) => {\n\t\tfunction centerSlides(slider: KeenSliderInstance) {\n\t\t\tif (slider.track.details.maxIdx > 0) {\n\t\t\t\t//@ts-expect-error\n\t\t\t\tslider.container.style.justifyContent = null;\n\t\t\t\t//@ts-expect-error\n\t\t\t\tslider.container.style.transform = null;\n\t\t\t} else {\n\t\t\t\tslider.container.style.cssText = `\n justify-content: center;\n transform: translateX(-${(slider.options.slides as any)?.spacing || 16}px)\n `;\n\t\t\t}\n\t\t}\n\n\t\tslider.on(\"created\", centerSlides);\n\t\tslider.on(\"optionsChanged\", centerSlides);\n\t};\n\n\tcreateGuardedEffect(\n\t\t() => props.centerSlides,\n\t\t(centerSlides) => {\n\t\t\tif (!centerSlides) return;\n\t\t\tconst remove = addPlugin(centeredPlugin);\n\t\t\treturn remove;\n\t\t},\n\t);\n\n\tcreateGuardedEffect(plugins, (plugins) => {\n\t\tif (plugins.length === 0) return;\n\t\tconsole.log(\n\t\t\t`Registered a new plugin on element.\\n`,\n\t\t\t`Total slider plugins: ${plugins.length}`,\n\t\t);\n\t});\n\n\treturn [slider, { addPlugin }] as const;\n}\n\nconst KeenSliderContextState = createContext(initializeKeenSliderContext);\n\nexport const provideKeenSliderContext = (\n\tinitialState: Omit<CreateContextOptions, \"root\">,\n\telement: WalkableNode,\n): KeenSliderContext => {\n\tconst props = merge(initialState, { root: element });\n\treturn provide(KeenSliderContextState, props, element);\n};\n\nexport const useKeenSliderContext = (context: KeenSliderContext) => {\n\treturn context;\n};\n\nexport const useKeenSlider = (element: HTMLElement & ICustomElement) => {\n\tconst context: KeenSliderContext = consume(KeenSliderContextState, element);\n\n\tif (!context) {\n\t\tthrow new Error(\n\t\t\t\"KeenSliderContext not found! Please ensure to wrap your custom element with keen-slider element.\",\n\t\t);\n\t}\n\n\treturn useKeenSliderContext(context);\n};\n\nexport const getKeenSliderContext = (element: Element) => {\n\tconst context = getContextFromProvider<KeenSliderContext>(\n\t\tKeenSliderContextState,\n\t\telement,\n\t);\n\treturn useKeenSliderContext(context);\n};\n\ntype AddPluginOptions = {\n\ttarget: void | HTMLElement;\n\tplugin: KeenSliderPlugin;\n\tcontroller?: AbortController;\n};\n\nexport function addPlugin({ target, plugin, controller }: AddPluginOptions) {\n\tif (!target) return;\n\n\tinvokeOnLoaded(\n\t\t() => {\n\t\t\tconst [_, { addPlugin }] = getKeenSliderContext(target);\n\t\t\tconst removePlugin = addPlugin(plugin);\n\t\t\tcontroller?.signal?.addEventListener(\"abort\", removePlugin);\n\t\t},\n\t\t{\n\t\t\tsignal: controller?.signal,\n\t\t},\n\t);\n}\n\nexport const useKeenSliderAt = createRemoteContext<KeenSliderContext>(\n\tKeenSliderContextState,\n\t{\n\t\t// A target may name the slider itself or an ancestor of it. Stated once\n\t\t// here instead of the identical ten-line thunk that was copy-pasted into\n\t\t// all six extension packages.\n\t\tresolve: (target, host) => {\n\t\t\tconst el = target ? document.querySelector(target) : host;\n\t\t\tif (!el) return null;\n\t\t\treturn el.tagName === \"KEEN-SLIDER\"\n\t\t\t\t? el\n\t\t\t\t: el.querySelector(\"keen-slider\");\n\t\t},\n\t},\n);\n"],"mappings":"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"}
|
package/dist/main/index.d.ts
CHANGED
|
@@ -20,14 +20,24 @@ export type KeenSliderOptions<O = {}, P = {}, H extends _KeenSliderHooks = _Keen
|
|
|
20
20
|
} & _KeenSliderOptions<O, P, H>["slides"];
|
|
21
21
|
};
|
|
22
22
|
export type KeenSliderPlugin<O = {}, P = {}, H extends _KeenSliderHooks = _KeenSliderHooks> = _KeenSliderPlugin<O, P, H>;
|
|
23
|
+
export type KeenSliderAccessibilityOptions = {
|
|
24
|
+
/** Template for each slide's `aria-label`: `{n}` and `{total}`. */
|
|
25
|
+
slideLabel?: string;
|
|
26
|
+
};
|
|
23
27
|
declare class KeenSlider extends _KeenSlider {
|
|
24
28
|
direction: "forward" | "backward" | null;
|
|
25
|
-
constructor(element: ICustomElement & HTMLElement, config: KeenSliderOptions, plugins?: _KeenSliderPlugin[]);
|
|
29
|
+
constructor(element: ICustomElement & HTMLElement, config: KeenSliderOptions, plugins?: _KeenSliderPlugin[], accessibility?: KeenSliderAccessibilityOptions);
|
|
26
30
|
}
|
|
27
31
|
export type Props = {
|
|
28
32
|
config?: KeenSliderOptions;
|
|
29
33
|
centerSlides: boolean;
|
|
30
34
|
refreshOnChildrenChange: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Each slide's `aria-label`. `{n}` is replaced with the slide number and
|
|
37
|
+
* `{total}` with the slide count. Translate it rather than reaching in from
|
|
38
|
+
* a theme. Slides that already carry an `aria-label` keep their own.
|
|
39
|
+
*/
|
|
40
|
+
slideLabel: string;
|
|
31
41
|
};
|
|
32
42
|
declare const Name = "keen-slider";
|
|
33
43
|
declare const Component: CorrectComponentType<Props>;
|
package/dist/main/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_SLIDE_LABEL } from "./utils.js";
|
|
1
2
|
import { addPlugin, getKeenSliderContext, useKeenSlider, useKeenSliderAt } from "./hooks/useKeenSlider.js";
|
|
2
3
|
import "./hooks/index.js";
|
|
3
4
|
import { Component, Name } from "./components/keen-slider.js";
|
|
@@ -7,7 +8,8 @@ import { customShadowlessElement } from "@brytdesigns/web-component-core/utils";
|
|
|
7
8
|
customShadowlessElement(Name, {
|
|
8
9
|
config: {},
|
|
9
10
|
centerSlides: false,
|
|
10
|
-
refreshOnChildrenChange: false
|
|
11
|
+
refreshOnChildrenChange: false,
|
|
12
|
+
slideLabel: DEFAULT_SLIDE_LABEL
|
|
11
13
|
}, Component);
|
|
12
14
|
//#endregion
|
|
13
15
|
export { addPlugin, getKeenSliderContext, useKeenSlider, useKeenSliderAt };
|
package/dist/main/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import { customShadowlessElement } from \"@brytdesigns/web-component-core/utils\";\nimport { KeenSlider } from \"./components/index.js\";\n\nexport type {\n\tKeenSliderInstance,\n\tKeenSliderOptions,\n\tKeenSliderPlugin,\n} from \"./KeenSlider.js\";\n\nexport type KeenSliderProps = KeenSlider.Props;\n\nexport {\n\taddPlugin,\n\tgetKeenSliderContext,\n\tuseKeenSlider,\n\tuseKeenSliderAt,\n} from \"./hooks/index.js\";\n\ncustomShadowlessElement(\n\tKeenSlider.Name,\n\t{\n\t\t// @ts-expect-error\n\t\tconfig: {},\n\t\tcenterSlides: false,\n\t\trefreshOnChildrenChange: false,\n\t},\n\tKeenSlider.Component,\n);\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import { customShadowlessElement } from \"@brytdesigns/web-component-core/utils\";\nimport { KeenSlider } from \"./components/index.js\";\nimport { DEFAULT_SLIDE_LABEL } from \"./utils.js\";\n\nexport type {\n\tKeenSliderInstance,\n\tKeenSliderOptions,\n\tKeenSliderPlugin,\n} from \"./KeenSlider.js\";\n\nexport type KeenSliderProps = KeenSlider.Props;\n\nexport {\n\taddPlugin,\n\tgetKeenSliderContext,\n\tuseKeenSlider,\n\tuseKeenSliderAt,\n} from \"./hooks/index.js\";\n\ncustomShadowlessElement(\n\tKeenSlider.Name,\n\t{\n\t\t// @ts-expect-error\n\t\tconfig: {},\n\t\tcenterSlides: false,\n\t\trefreshOnChildrenChange: false,\n\t\tslideLabel: DEFAULT_SLIDE_LABEL,\n\t},\n\tKeenSlider.Component,\n);\n"],"mappings":";;;;;;;AAmBA,wBACC,MACA;CAEC,QAAQ,CAAC;CACT,cAAc;CACd,yBAAyB;CACzB,YAAY;AACb,GACA,SACD"}
|
package/dist/main/utils.js
CHANGED
|
@@ -2,7 +2,22 @@
|
|
|
2
2
|
function constrain(value, min = -Infinity, max = Infinity) {
|
|
3
3
|
return Math.min(Math.max(value, min), max);
|
|
4
4
|
}
|
|
5
|
+
/** What every slide was labelled before `slide-label` existed: "1 of 4". */
|
|
6
|
+
var DEFAULT_SLIDE_LABEL = "{n} of {total}";
|
|
7
|
+
/**
|
|
8
|
+
* Fills a slide-label template. `{n}` is the 1-based slide number and
|
|
9
|
+
* `{total}` the slide count, the same placeholder `dot-label` and
|
|
10
|
+
* `breakpoint-label` use for their own numbers.
|
|
11
|
+
*
|
|
12
|
+
* Every occurrence is replaced, not just the first, so a template may repeat
|
|
13
|
+
* one. Anything that is not a non-empty string falls back to the default: an
|
|
14
|
+
* empty `slide-label=""` would otherwise give every slide an empty accessible
|
|
15
|
+
* name, which is worse than the English one.
|
|
16
|
+
*/
|
|
17
|
+
function formatSlideLabel(template, n, total) {
|
|
18
|
+
return (typeof template === "string" && template.trim() !== "" ? template : DEFAULT_SLIDE_LABEL).replaceAll("{n}", `${n}`).replaceAll("{total}", `${total}`);
|
|
19
|
+
}
|
|
5
20
|
//#endregion
|
|
6
|
-
export { constrain };
|
|
21
|
+
export { DEFAULT_SLIDE_LABEL, constrain, formatSlideLabel };
|
|
7
22
|
|
|
8
23
|
//# sourceMappingURL=utils.js.map
|
package/dist/main/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import type { ICustomElement } from \"component-register\";\n\nexport function constrain(value: number, min = -Infinity, max = Infinity) {\n\treturn Math.min(Math.max(value, min), max);\n}\n\ntype Options = {\n\telement: HTMLElement & ICustomElement;\n};\n\nexport function initializeSliderClasses<Props>(\n\tComponentType = (props: Props, options: Options) => {},\n) {\n\treturn (props: Props, options: Options) => {\n\t\tconst { element } = options;\n\t\telement.classList.add(\"keen-slider\");\n\t\tArray.from(element.children).forEach((child) => {\n\t\t\tchild.classList.add(\"keen-slider__slide\");\n\t\t});\n\t\treturn ComponentType(props, options);\n\t};\n}\n"],"mappings":";AAEA,SAAgB,UAAU,OAAe,MAAM,WAAW,MAAM,UAAU;CACzE,OAAO,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAC1C"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import type { ICustomElement } from \"component-register\";\n\nexport function constrain(value: number, min = -Infinity, max = Infinity) {\n\treturn Math.min(Math.max(value, min), max);\n}\n\n/** What every slide was labelled before `slide-label` existed: \"1 of 4\". */\nexport const DEFAULT_SLIDE_LABEL = \"{n} of {total}\";\n\n/**\n * Fills a slide-label template. `{n}` is the 1-based slide number and\n * `{total}` the slide count, the same placeholder `dot-label` and\n * `breakpoint-label` use for their own numbers.\n *\n * Every occurrence is replaced, not just the first, so a template may repeat\n * one. Anything that is not a non-empty string falls back to the default: an\n * empty `slide-label=\"\"` would otherwise give every slide an empty accessible\n * name, which is worse than the English one.\n */\nexport function formatSlideLabel(\n\ttemplate: string | undefined,\n\tn: number,\n\ttotal: number,\n) {\n\tconst usable =\n\t\ttypeof template === \"string\" && template.trim() !== \"\"\n\t\t\t? template\n\t\t\t: DEFAULT_SLIDE_LABEL;\n\treturn usable.replaceAll(\"{n}\", `${n}`).replaceAll(\"{total}\", `${total}`);\n}\n\ntype Options = {\n\telement: HTMLElement & ICustomElement;\n};\n\nexport function initializeSliderClasses<Props>(\n\tComponentType = (props: Props, options: Options) => {},\n) {\n\treturn (props: Props, options: Options) => {\n\t\tconst { element } = options;\n\t\telement.classList.add(\"keen-slider\");\n\t\tArray.from(element.children).forEach((child) => {\n\t\t\tchild.classList.add(\"keen-slider__slide\");\n\t\t});\n\t\treturn ComponentType(props, options);\n\t};\n}\n"],"mappings":";AAEA,SAAgB,UAAU,OAAe,MAAM,WAAW,MAAM,UAAU;CACzE,OAAO,KAAK,IAAI,KAAK,IAAI,OAAO,GAAG,GAAG,GAAG;AAC1C;;AAGA,IAAa,sBAAsB;;;;;;;;;;;AAYnC,SAAgB,iBACf,UACA,GACA,OACC;CAKD,QAHC,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,KACjD,WACA,oBAAA,CACU,WAAW,OAAO,GAAG,GAAG,CAAC,CAAC,WAAW,WAAW,GAAG,OAAO;AACzE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brytdesigns/web-component-keen-slider",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Keen slider web component",
|
|
5
5
|
"main": "./dist/main/index.js",
|
|
6
6
|
"module": "./dist/main/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"author": "Bryt Designs",
|
|
21
21
|
"license": "ISC",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@brytdesigns/web-component-core": "3.
|
|
23
|
+
"@brytdesigns/web-component-core": "3.2.0",
|
|
24
24
|
"component-register": "0.8.7",
|
|
25
25
|
"keen-slider": "^6.8.6",
|
|
26
26
|
"solid-js": "2.0.0-rc.14"
|