@brytdesigns/web-component-keen-slider 1.2.3 → 3.1.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 +188 -124
- package/dist/main/KeenSlider.js.map +1 -1
- package/dist/main/components/index.js +1 -4
- package/dist/main/components/keen-slider.js +24 -25
- package/dist/main/components/keen-slider.js.map +1 -1
- package/dist/main/hooks/index.js +2 -3
- package/dist/main/hooks/useKeenSlider.js +88 -120
- package/dist/main/hooks/useKeenSlider.js.map +1 -1
- package/dist/main/index.d.ts +21 -6
- package/dist/main/index.js +15 -14
- package/dist/main/index.js.map +1 -1
- package/dist/main/utils.js +18 -13
- package/dist/main/utils.js.map +1 -1
- package/dist/styles.css +55 -51
- package/package.json +7 -8
- package/dist/esm/index.js +0 -307
- package/dist/esm/index.js.map +0 -1
- package/dist/main/components/index.js.map +0 -1
- package/dist/main/hooks/index.js.map +0 -1
package/dist/main/KeenSlider.js
CHANGED
|
@@ -1,129 +1,193 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import { constrain, formatSlideLabel } from "./utils.js";
|
|
2
|
+
import _KeenSlider from "keen-slider";
|
|
3
|
+
//#region src/KeenSlider.ts
|
|
4
4
|
function attachMoreDetails(prevSlide) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
return (slider) => {
|
|
6
|
+
if (slider.track.details.rel !== slider.animator.targetIdx) return;
|
|
7
|
+
slider.direction = slider.track.details.rel > prevSlide ? "forward" : "backward";
|
|
8
|
+
prevSlide = slider.track.details.rel;
|
|
9
|
+
};
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
+
/**
|
|
23
|
+
* APG's carousel pattern: a labelled group whose role description tells
|
|
24
|
+
* assistive tech what it is, with each slide a group of its own.
|
|
25
|
+
*
|
|
26
|
+
* What this replaces was `role="listbox"` with `role="option"` slides, which
|
|
27
|
+
* told a screen-reader user they were inside a form control they could select
|
|
28
|
+
* from. It also made `aria-valuemin/max/now` invalid — a listbox has no value —
|
|
29
|
+
* and left `aria-required-children` permanently unsatisfiable.
|
|
30
|
+
*
|
|
31
|
+
* The slide attributes used to be applied only from `created`, `slideChanged`,
|
|
32
|
+
* `optionsChanged` and `updated`. `created` fires inside `super()`, before the
|
|
33
|
+
* constructor gets here to subscribe, so on a carousel nobody ever interacted
|
|
34
|
+
* with the slides got no ARIA at all — which is exactly why the container
|
|
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.
|
|
40
|
+
*/
|
|
41
|
+
var attachAriaAttributes = (slider, slideLabel) => {
|
|
42
|
+
const container = slider.container;
|
|
43
|
+
const authoredContainerLabel = container.hasAttribute("aria-label");
|
|
44
|
+
const authoredSlideLabels = /* @__PURE__ */ new WeakSet();
|
|
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
|
+
}
|
|
49
|
+
container.setAttribute("role", "group");
|
|
50
|
+
container.setAttribute("aria-roledescription", "carousel");
|
|
51
|
+
if (!authoredContainerLabel) container.setAttribute("aria-label", "Carousel");
|
|
52
|
+
container.setAttribute("aria-atomic", "false");
|
|
53
|
+
if (!container.hasAttribute("tabindex")) container.setAttribute("tabindex", "0");
|
|
54
|
+
for (const attribute of [
|
|
55
|
+
"aria-multiselectable",
|
|
56
|
+
"aria-valuemin",
|
|
57
|
+
"aria-valuemax",
|
|
58
|
+
"aria-valuenow",
|
|
59
|
+
"aria-orientation",
|
|
60
|
+
"aria-busy"
|
|
61
|
+
]) container.removeAttribute(attribute);
|
|
62
|
+
/** The fraction of a slide that is in view, 0 when it is fully outside. */
|
|
63
|
+
function visiblePortion(index) {
|
|
64
|
+
return slider.track?.details?.slides?.[index]?.portion ?? 0;
|
|
65
|
+
}
|
|
66
|
+
function updateTabIndexes(slide, tabindex) {
|
|
67
|
+
const focusable = Array.from(slide.querySelectorAll("input, a, button:not(:disabled), textarea, select, [tabindex]"));
|
|
68
|
+
for (const element of focusable) element.setAttribute("tabindex", tabindex);
|
|
69
|
+
}
|
|
70
|
+
function updateSlideAriaAttributes(slider) {
|
|
71
|
+
const total = slider.slides.length;
|
|
72
|
+
const disabled = Boolean(slider.options?.disabled);
|
|
73
|
+
slider.slides.forEach((slide, index) => {
|
|
74
|
+
slide.setAttribute("role", "group");
|
|
75
|
+
slide.setAttribute("aria-roledescription", "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
|
+
}
|
|
81
|
+
slide.removeAttribute("aria-selected");
|
|
82
|
+
slide.removeAttribute("tabindex");
|
|
83
|
+
const visible = disabled || visiblePortion(index) > 0;
|
|
84
|
+
slide.setAttribute("data-slide-visible", `${visible}`);
|
|
85
|
+
const holdsFocus = document.activeElement !== null && slide.contains(document.activeElement);
|
|
86
|
+
if (!visible && !holdsFocus) slide.setAttribute("aria-hidden", "true");
|
|
87
|
+
else slide.removeAttribute("aria-hidden");
|
|
88
|
+
updateTabIndexes(slide, visible ? "0" : "-1");
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
slider.on("slideChanged", updateSlideAriaAttributes);
|
|
92
|
+
slider.on("created", updateSlideAriaAttributes);
|
|
93
|
+
slider.on("optionsChanged", updateSlideAriaAttributes);
|
|
94
|
+
slider.on("updated", updateSlideAriaAttributes);
|
|
95
|
+
updateSlideAriaAttributes(slider);
|
|
78
96
|
};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Anything that takes typed input. Arrow keys inside one of these belong to
|
|
99
|
+
* the field, not the carousel — without this guard a search box inside a slide
|
|
100
|
+
* cannot be navigated with the keyboard.
|
|
101
|
+
*/
|
|
102
|
+
var TEXT_ENTRY = "input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"]";
|
|
103
|
+
/**
|
|
104
|
+
* Arrow-key navigation, and the `aria-live` rule for auto-rotation.
|
|
105
|
+
*
|
|
106
|
+
* The container has carried `tabindex="0"` for as long as the ARIA plugin has
|
|
107
|
+
* existed, with nothing listening — so it took a tab stop and did nothing with
|
|
108
|
+
* it, which is worse than not being focusable. This is the handler that makes
|
|
109
|
+
* the tab stop worth having.
|
|
110
|
+
*
|
|
111
|
+
* `aria-live` was previously hardcoded to `polite` on the container (twice).
|
|
112
|
+
* APG is explicit that a live region on an auto-rotating carousel announces
|
|
113
|
+
* slides the user never asked for, so the announcement is tied to the rotation
|
|
114
|
+
* state instead: silent while rotating, polite once paused and the user is
|
|
115
|
+
* driving.
|
|
116
|
+
*/
|
|
117
|
+
var attachKeyboardNavigation = (slider) => {
|
|
118
|
+
const container = slider.container;
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const isVertical = () => Boolean(slider.options?.vertical);
|
|
121
|
+
function handleKeydown(event) {
|
|
122
|
+
if (slider.options?.disabled) return;
|
|
123
|
+
const target = event.target;
|
|
124
|
+
if (target instanceof Element && target.closest(TEXT_ENTRY)) return;
|
|
125
|
+
const back = isVertical() ? "ArrowUp" : "ArrowLeft";
|
|
126
|
+
const forward = isVertical() ? "ArrowDown" : "ArrowRight";
|
|
127
|
+
switch (event.key) {
|
|
128
|
+
case back:
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
slider.prev();
|
|
131
|
+
return;
|
|
132
|
+
case forward:
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
slider.next();
|
|
135
|
+
return;
|
|
136
|
+
case "Home":
|
|
137
|
+
event.preventDefault();
|
|
138
|
+
slider.moveToIdx(0);
|
|
139
|
+
return;
|
|
140
|
+
case "End": {
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
const details = slider.track?.details;
|
|
143
|
+
const last = Number.isFinite(details?.maxIdx) ? details?.maxIdx ?? 0 : slider.slides.length - 1;
|
|
144
|
+
slider.moveToIdx(last);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* `keen-slider-auto-switch` already dispatches this, and the autoplay
|
|
151
|
+
* package publishes its pause state the same way, so both drive one code
|
|
152
|
+
* path here rather than each teaching the carousel about itself.
|
|
153
|
+
*/
|
|
154
|
+
function handleRotationChange(event) {
|
|
155
|
+
const rotating = event.detail?.isPaused === false;
|
|
156
|
+
container.setAttribute("aria-live", rotating ? "off" : "polite");
|
|
157
|
+
}
|
|
158
|
+
container.addEventListener("keydown", handleKeydown, { signal: controller.signal });
|
|
159
|
+
container.addEventListener("autoswitch:update", handleRotationChange, { signal: controller.signal });
|
|
160
|
+
container.addEventListener("autoplay:update", handleRotationChange, { signal: controller.signal });
|
|
161
|
+
if (!container.hasAttribute("aria-live")) container.setAttribute("aria-live", "polite");
|
|
162
|
+
slider.on("destroyed", () => controller.abort());
|
|
163
|
+
};
|
|
164
|
+
var KeenSlider = class extends _KeenSlider {
|
|
165
|
+
direction = null;
|
|
166
|
+
constructor(element, config, plugins = [], accessibility = {}) {
|
|
167
|
+
super(element, config, plugins);
|
|
168
|
+
const prevSlide = 0;
|
|
169
|
+
this.direction = null;
|
|
170
|
+
this.on("slideChanged", attachMoreDetails(prevSlide));
|
|
171
|
+
attachAriaAttributes(this, accessibility.slideLabel);
|
|
172
|
+
attachKeyboardNavigation(this);
|
|
173
|
+
const _next = this.next, _prev = this.prev;
|
|
174
|
+
this.next = function() {
|
|
175
|
+
if (typeof this.options.slides === "number" || typeof this.options.slides === "function") return _next();
|
|
176
|
+
let amount = 1;
|
|
177
|
+
if (this.options?.slides && "perScroll" in this.options.slides === true) amount = this.options?.slides?.perScroll || 1;
|
|
178
|
+
if (!this.options.loop) return this.moveToIdx(constrain(this.track.details.rel + amount, 0, this.track.details.maxIdx));
|
|
179
|
+
return this.moveToIdx(constrain(this.track.details.abs + amount), true);
|
|
180
|
+
};
|
|
181
|
+
this.prev = function() {
|
|
182
|
+
if (typeof this.options.slides === "number" || typeof this.options.slides === "function") return _prev();
|
|
183
|
+
let amount = 1;
|
|
184
|
+
if (this.options?.slides && "perScroll" in this.options.slides === true) amount = this.options?.slides?.perScroll || 1;
|
|
185
|
+
if (!this.options.loop) this.moveToIdx(constrain(this.track.details.rel - amount, 0, this.track.details.maxIdx));
|
|
186
|
+
return this.moveToIdx(constrain(this.track.details.abs - amount), true);
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
//#endregion
|
|
127
191
|
export { KeenSlider as default };
|
|
128
|
-
|
|
192
|
+
|
|
129
193
|
//# sourceMappingURL=KeenSlider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/KeenSlider.ts"],"names":["slider"],"mappings":";;;AAgDA,SAAS,kBAAkB,SAAmB,EAAA;AAC5C,EAAA,OAAO,SAAU,MAA4B,EAAA;AAC3C,IAAA,IAAI,OAAO,KAAM,CAAA,OAAA,CAAQ,GAAO,IAAA,MAAA,CAAO,SAAS,SAAW,EAAA;AAE3D,IAAC,OAAsB,SACrB,GAAA,MAAA,CAAO,MAAM,OAAQ,CAAA,GAAA,GAAM,YAAY,SAAY,GAAA,UAAA;AAErD,IAAY,SAAA,GAAA,MAAA,CAAO,MAAM,OAAQ,CAAA,GAAA;AAAA,GACnC;AACF;AAEA,MAAM,oBAAA,GAAyC,CAAC,MAAW,KAAA;AACzD,EAAA,MAAM,MACJ,GAAA,MAAA,EAAQ,KAAO,EAAA,OAAA,EAAS,MAAW,KAAA,QAAA,GAC/B,MAAO,CAAA,KAAA,CAAM,OAAQ,CAAA,MAAA,GACrB,MAAQ,EAAA,KAAA,EAAO,SAAS,MAAU,IAAA,CAAA;AACxC,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,MAAA,EAAQ,SAAS,CAAA;AAC/C,EAAA,MAAA,CAAO,SAAU,CAAA,YAAA;AAAA,IACf,kBAAA;AAAA,IACA,MAAA,CAAO,OAAS,EAAA,QAAA,GAAW,UAAa,GAAA;AAAA,GAC1C;AACA,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,sBAAA,EAAwB,OAAO,CAAA;AAC7D,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,YAAA,EAAc,QAAQ,CAAA;AACpD,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,UAAA,EAAY,GAAG,CAAA;AAC7C,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,WAAA,EAAa,QAAQ,CAAA;AACnD,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,aAAA,EAAe,MAAM,CAAA;AACnD,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,WAAA,EAAa,QAAQ,CAAA;AACnD,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,WAAA,EAAa,OAAO,CAAA;AAClD,EAAO,MAAA,CAAA,SAAA,CAAU,YAAa,CAAA,eAAA,EAAiB,GAAG,CAAA;AAClD,EAAA,MAAA,CAAO,SAAU,CAAA,YAAA,CAAa,eAAiB,EAAA,CAAA,EAAG,MAAM,CAAE,CAAA,CAAA;AAC1D,EAAA,MAAA,CAAO,SAAU,CAAA,YAAA;AAAA,IACf,eAAA;AAAA,IACA,CAAG,EAAA,MAAA,EAAQ,KAAO,EAAA,OAAA,EAAS,OAAO,CAAC,CAAA;AAAA,GACrC;AAEA,EAAS,SAAA,SAAA,CAAU,GAAa,EAAA,OAAA,GAAU,CAAG,EAAA;AAC3C,IAAA,OAAO,IAAK,CAAA,KAAA,CAAM,GAAM,GAAA,OAAA,GAAU,CAAC,CAAA;AAAA;AAGrC,EAAA,SAAS,cAAc,GAAa,EAAA;AAClC,IAAA,MAAM,OAAY,GAAA,MAAA,CAAO,OAAS,EAAA,MAAA,EAAgB,WAAsB,CACtE,EAAA,GAAA,GAAM,MAAO,CAAA,KAAA,CAAM,OAAQ,CAAA,GAAA,EAC3B,MAAS,GAAA,SAAA,CAAU,KAAK,OAAO,CAAA;AAEjC,IAAO,OAAA,GAAA,IAAO,OAAO,GAAO,IAAA,MAAA;AAAA;AAG9B,EAAe,eAAA,gBAAA,CAAiB,OAAoB,QAAkB,EAAA;AACpE,IAAA,MAAM,oBAAoB,KAAM,CAAA,IAAA;AAAA,MAC9B,KAAM,CAAA,gBAAA;AAAA,QACJ;AAAA;AACF,KACF;AACA,IAAkB,iBAAA,CAAA,OAAA,CAAQ,CAAC,OAAY,KAAA;AACrC,MAAQ,OAAA,CAAA,YAAA,CAAa,YAAY,QAAQ,CAAA;AAAA,KAC1C,CAAA;AAAA;AAGH,EAAA,SAAS,sBAAsB,KAAoB,EAAA;AACjD,IAAM,KAAA,CAAA,YAAA,CAAa,iBAAiB,MAAM,CAAA;AAC1C,IAAM,KAAA,CAAA,YAAA,CAAa,eAAe,OAAO,CAAA;AACzC,IAAM,KAAA,CAAA,YAAA,CAAa,YAAY,GAAG,CAAA;AAClC,IAAA,gBAAA,CAAiB,OAAO,GAAG,CAAA;AAAA;AAG7B,EAAA,SAAS,wBAAwB,KAAoB,EAAA;AACnD,IAAM,KAAA,CAAA,YAAA,CAAa,iBAAiB,OAAO,CAAA;AAC3C,IAAM,KAAA,CAAA,YAAA,CAAa,eAAe,MAAM,CAAA;AACxC,IAAM,KAAA,CAAA,YAAA,CAAa,YAAY,IAAI,CAAA;AACnC,IAAA,gBAAA,CAAiB,OAAO,IAAI,CAAA;AAAA;AAG9B,EAAA,SAAS,0BAA0BA,OAA6B,EAAA;AAC9D,IAAIA,IAAAA,OAAAA,CAAO,SAAS,QAAU,EAAA;AAC5B,MAAAA,OAAO,CAAA,MAAA,CAAO,OAAQ,CAAA,CAAC,OAAO,CAAM,KAAA;AAClC,QAAM,KAAA,CAAA,YAAA,CAAa,QAAQ,QAAQ,CAAA;AACnC,QAAA,qBAAA,CAAsB,KAAK,CAAA;AAAA,OAC5B,CAAA;AACD,MAAA;AAAA;AAGF,IAAAA,OAAO,CAAA,MAAA,CAAO,OAAQ,CAAA,CAAC,OAAO,CAAM,KAAA;AAClC,MAAM,KAAA,CAAA,YAAA,CAAa,QAAQ,QAAQ,CAAA;AACnC,MAAA,IAAI,aAAc,CAAA,CAAC,CAAG,EAAA,qBAAA,CAAsB,KAAK,CAAA;AAAA,mCACpB,KAAK,CAAA;AAAA,KACnC,CAAA;AAAA;AAGH,EAAO,MAAA,CAAA,EAAA,CAAG,gBAAgB,yBAAyB,CAAA;AACnD,EAAO,MAAA,CAAA,EAAA,CAAG,WAAW,yBAAyB,CAAA;AAC9C,EAAO,MAAA,CAAA,EAAA,CAAG,kBAAkB,yBAAyB,CAAA;AACrD,EAAO,MAAA,CAAA,EAAA,CAAG,WAAW,yBAAyB,CAAA;AAChD,CAAA;AAEA,MAAO,mBAAiC,WAAY,CAAA;AAAA,EAClD,SAA2C,GAAA,IAAA;AAAA,EAC3C,WACE,CAAA,OAAA,EACA,MACA,EAAA,OAAA,GAA+B,EAC/B,EAAA;AACA,IAAM,KAAA,CAAA,OAAA,EAAS,QAAQ,OAAO,CAAA;AAC9B,IAAA,IAAI,SAAY,GAAA,CAAA;AAEhB,IAAA,IAAA,CAAK,SAAY,GAAA,IAAA;AACjB,IAAA,IAAA,CAAK,EAAG,CAAA,cAAA,EAAgB,iBAAkB,CAAA,SAAS,CAAQ,CAAA;AAE3D,IAAA,oBAAA,CAAqB,IAAI,CAAA;AAEzB,IAAA,MAAM,KAAQ,GAAA,IAAA,CAAK,IACjB,EAAA,KAAA,GAAQ,IAAK,CAAA,IAAA;AAEf,IAAA,IAAA,CAAK,OAAO,WAAY;AACtB,MACE,IAAA,OAAO,KAAK,OAAQ,CAAA,MAAA,KAAW,YAC/B,OAAO,IAAA,CAAK,QAAQ,MAAW,KAAA,UAAA;AAE/B,QAAA,OAAO,KAAM,EAAA;AACf,MAAA,IAAI,MAAiB,GAAA,CAAA;AACrB,MAAA,IAAI,KAAK,OAAS,EAAA,MAAA,IAAU,eAAe,IAAK,CAAA,OAAA,CAAQ,WAAW,IAAM,EAAA;AACvE,QAAU,MAAA,GAAA,IAAA,CAAK,OAAS,EAAA,MAAA,EAAQ,SAAwB,IAAA,CAAA;AAAA;AAE1D,MAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA;AACtB,QAAA,OAAO,IAAK,CAAA,SAAA;AAAA,UACV,SAAA;AAAA,YACE,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,GAAM,GAAA,MAAA;AAAA,YACzB,CAAA;AAAA,YACA,IAAA,CAAK,MAAM,OAAQ,CAAA;AAAA;AACrB,SACF;AAAA;AAEF,MAAO,OAAA,IAAA,CAAK,UAAU,SAAU,CAAA,IAAA,CAAK,MAAM,OAAQ,CAAA,GAAA,GAAM,MAAM,CAAA,EAAG,IAAI,CAAA;AAAA,KACxE;AAEA,IAAA,IAAA,CAAK,OAAO,WAAY;AACtB,MACE,IAAA,OAAO,KAAK,OAAQ,CAAA,MAAA,KAAW,YAC/B,OAAO,IAAA,CAAK,QAAQ,MAAW,KAAA,UAAA;AAE/B,QAAA,OAAO,KAAM,EAAA;AACf,MAAA,IAAI,MAAiB,GAAA,CAAA;AACrB,MAAA,IAAI,KAAK,OAAS,EAAA,MAAA,IAAU,eAAe,IAAK,CAAA,OAAA,CAAQ,WAAW,IAAM,EAAA;AACvE,QAAU,MAAA,GAAA,IAAA,CAAK,OAAS,EAAA,MAAA,EAAQ,SAAwB,IAAA,CAAA;AAAA;AAE1D,MAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA;AACtB,QAAK,IAAA,CAAA,SAAA;AAAA,UACH,SAAA;AAAA,YACE,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,GAAM,GAAA,MAAA;AAAA,YACzB,CAAA;AAAA,YACA,IAAA,CAAK,MAAM,OAAQ,CAAA;AAAA;AACrB,SACF;AAAA;AAEF,MAAO,OAAA,IAAA,CAAK,UAAU,SAAU,CAAA,IAAA,CAAK,MAAM,OAAQ,CAAA,GAAA,GAAM,MAAM,CAAA,EAAG,IAAI,CAAA;AAAA,KACxE;AAAA;AAEJ","file":"KeenSlider.js","sourcesContent":["import type { ICustomElement } from \"component-register\";\r\n\r\nimport _KeenSlider, {\r\n type KeenSliderOptions as _KeenSliderOptions,\r\n type KeenSliderPlugin as _KeenSliderPlugin,\r\n type KeenSliderInstance as _KeenSliderInstance,\r\n type KeenSliderHooks as _KeenSliderHooks,\r\n} from \"keen-slider\";\r\n\r\nimport { constrain } from \"./utils\";\r\n\r\nexport type KeenSliderHooks = _KeenSliderHooks;\r\n\r\nexport type KeenSliderInstance<\r\n O = {},\r\n P = {},\r\n H extends _KeenSliderHooks = _KeenSliderHooks,\r\n> = _KeenSliderInstance<O, P, H>;\r\n\r\ntype ExtendedSlidesOption = NonNullable<\r\n _KeenSliderInstance[\"options\"][\"slides\"]\r\n> & {\r\n perScroll?: number;\r\n};\r\n\r\ntype ExtendedKeenSliderOptions = Omit<\r\n _KeenSliderInstance[\"options\"],\r\n \"slides\"\r\n> & {\r\n slides?: ExtendedSlidesOption;\r\n};\r\n\r\nexport type KeenSliderOptions<\r\n O = {},\r\n P = {},\r\n H extends _KeenSliderHooks = _KeenSliderHooks,\r\n> = _KeenSliderOptions<O, P, H> & {\r\n slides: {\r\n perScroll?: number;\r\n } & _KeenSliderOptions<O, P, H>[\"slides\"];\r\n};\r\n\r\nexport type KeenSliderPlugin<\r\n O = {},\r\n P = {},\r\n H extends _KeenSliderHooks = _KeenSliderHooks,\r\n> = _KeenSliderPlugin<O, P, H>;\r\n\r\nfunction attachMoreDetails(prevSlide: number) {\r\n return function (slider: KeenSliderInstance) {\r\n if (slider.track.details.rel != slider.animator.targetIdx) return;\r\n\r\n (slider as KeenSlider).direction =\r\n slider.track.details.rel > prevSlide ? \"forward\" : \"backward\";\r\n\r\n prevSlide = slider.track.details.rel;\r\n };\r\n}\r\n\r\nconst attachAriaAttributes: KeenSliderPlugin = (slider) => {\r\n const maxIdx =\r\n slider?.track?.details?.maxIdx === Infinity\r\n ? slider.track.details.length\r\n : slider?.track?.details?.maxIdx || 0;\r\n slider.container.setAttribute(\"role\", \"listbox\");\r\n slider.container.setAttribute(\r\n \"aria-orientation\",\r\n slider.options?.vertical ? \"vertical\" : \"horizontal\",\r\n );\r\n slider.container.setAttribute(\"aria-multiselectable\", \"false\");\r\n slider.container.setAttribute(\"aria-label\", \"Slider\");\r\n slider.container.setAttribute(\"tabindex\", \"0\");\r\n slider.container.setAttribute(\"aria-live\", \"polite\");\r\n slider.container.setAttribute(\"aria-atomic\", \"true\");\r\n slider.container.setAttribute(\"aria-live\", \"polite\");\r\n slider.container.setAttribute(\"aria-busy\", \"false\");\r\n slider.container.setAttribute(\"aria-valuemin\", \"0\");\r\n slider.container.setAttribute(\"aria-valuemax\", `${maxIdx}`);\r\n slider.container.setAttribute(\r\n \"aria-valuenow\",\r\n `${slider?.track?.details?.rel || 0}`,\r\n );\r\n\r\n function getMaxRel(rel: number, perView = 1) {\r\n return Math.floor(rel + perView - 1);\r\n }\r\n\r\n function slideIsActive(idx: number) {\r\n const perView = ((slider.options?.slides as any)?.perView as number) || 1,\r\n rel = slider.track.details.rel,\r\n maxRel = getMaxRel(rel, perView);\r\n\r\n return rel <= idx && idx <= maxRel;\r\n }\r\n\r\n async function updateTabIndexes(slide: HTMLElement, tabindex: string) {\r\n const focusableElements = Array.from(\r\n slide.querySelectorAll(\r\n \"input, a, button:not(:disabled), textarea, select, textarea, [tabindex]\",\r\n ),\r\n );\r\n focusableElements.forEach((element) => {\r\n element.setAttribute(\"tabindex\", tabindex);\r\n });\r\n }\r\n\r\n function updateAriaActiveSlide(slide: HTMLElement) {\r\n slide.setAttribute(\"aria-selected\", \"true\");\r\n slide.setAttribute(\"aria-hidden\", \"false\");\r\n slide.setAttribute(\"tabindex\", \"0\");\r\n updateTabIndexes(slide, \"0\");\r\n }\r\n\r\n function updateAriaInActiveSlide(slide: HTMLElement) {\r\n slide.setAttribute(\"aria-selected\", \"false\");\r\n slide.setAttribute(\"aria-hidden\", \"true\");\r\n slide.setAttribute(\"tabindex\", \"-1\");\r\n updateTabIndexes(slide, \"-1\");\r\n }\r\n\r\n function updateSlideAriaAttributes(slider: _KeenSliderInstance) {\r\n if (slider.options?.disabled) {\r\n slider.slides.forEach((slide, i) => {\r\n slide.setAttribute(\"role\", \"option\");\r\n updateAriaActiveSlide(slide);\r\n });\r\n return;\r\n }\r\n\r\n slider.slides.forEach((slide, i) => {\r\n slide.setAttribute(\"role\", \"option\");\r\n if (slideIsActive(i)) updateAriaActiveSlide(slide);\r\n else updateAriaInActiveSlide(slide);\r\n });\r\n }\r\n\r\n slider.on(\"slideChanged\", updateSlideAriaAttributes);\r\n slider.on(\"created\", updateSlideAriaAttributes);\r\n slider.on(\"optionsChanged\", updateSlideAriaAttributes);\r\n slider.on(\"updated\", updateSlideAriaAttributes);\r\n};\r\n\r\nexport default class KeenSlider extends _KeenSlider {\r\n direction: \"forward\" | \"backward\" | null = null;\r\n constructor(\r\n element: ICustomElement & HTMLElement,\r\n config: KeenSliderOptions,\r\n plugins: _KeenSliderPlugin[] = [],\r\n ) {\r\n super(element, config, plugins);\r\n let prevSlide = 0;\r\n\r\n this.direction = null;\r\n this.on(\"slideChanged\", attachMoreDetails(prevSlide) as any);\r\n\r\n attachAriaAttributes(this);\r\n\r\n const _next = this.next,\r\n _prev = this.prev;\r\n\r\n this.next = function () {\r\n if (\r\n typeof this.options.slides === \"number\" ||\r\n typeof this.options.slides === \"function\"\r\n )\r\n return _next();\r\n let amount: number = 1;\r\n if (this.options?.slides && \"perScroll\" in this.options.slides === true) {\r\n amount = (this.options?.slides?.perScroll as number) || 1;\r\n }\r\n if (!this.options.loop) {\r\n return this.moveToIdx(\r\n constrain(\r\n this.track.details.rel + amount,\r\n 0,\r\n this.track.details.maxIdx,\r\n ),\r\n );\r\n }\r\n return this.moveToIdx(constrain(this.track.details.abs + amount), true);\r\n };\r\n\r\n this.prev = function () {\r\n if (\r\n typeof this.options.slides === \"number\" ||\r\n typeof this.options.slides === \"function\"\r\n )\r\n return _prev();\r\n let amount: number = 1;\r\n if (this.options?.slides && \"perScroll\" in this.options.slides === true) {\r\n amount = (this.options?.slides?.perScroll as number) || 1;\r\n }\r\n if (!this.options.loop) {\r\n this.moveToIdx(\r\n constrain(\r\n this.track.details.rel - amount,\r\n 0,\r\n this.track.details.maxIdx,\r\n ),\r\n );\r\n }\r\n return this.moveToIdx(constrain(this.track.details.abs - amount), true);\r\n };\r\n }\r\n}\r\n"]}
|
|
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,28 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Object.assign(element, { addPlugin: methods.addPlugin });
|
|
1
|
+
import "../KeenSlider.js";
|
|
2
|
+
import { provideKeenSliderContext, useKeenSliderContext } from "../hooks/useKeenSlider.js";
|
|
3
|
+
import "../hooks/index.js";
|
|
4
|
+
import { createGuardedEffect } from "@brytdesigns/web-component-core/utils";
|
|
5
|
+
import { createRoot } from "solid-js";
|
|
6
|
+
//#region src/components/keen-slider.ts
|
|
7
|
+
var Name = `keen-slider`;
|
|
8
|
+
var Component = (props, { element }) => {
|
|
9
|
+
const context = provideKeenSliderContext(props, element);
|
|
10
|
+
const [slider, methods] = useKeenSliderContext(context);
|
|
11
|
+
Object.assign(element, { subscribe(callback = (_) => null) {
|
|
12
|
+
function listen(slider) {
|
|
13
|
+
const cleanup = callback(slider);
|
|
14
|
+
slider.on("destroyed", typeof cleanup === "function" ? cleanup : () => null);
|
|
15
|
+
}
|
|
16
|
+
return createRoot((dispose) => {
|
|
17
|
+
createGuardedEffect(slider, listen);
|
|
18
|
+
return dispose;
|
|
19
|
+
});
|
|
20
|
+
} });
|
|
21
|
+
Object.assign(element, { slider });
|
|
22
|
+
Object.assign(element, { addPlugin: methods.addPlugin });
|
|
24
23
|
};
|
|
25
|
-
|
|
24
|
+
//#endregion
|
|
26
25
|
export { Component, Name };
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
//# sourceMappingURL=keen-slider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
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"}
|
package/dist/main/hooks/index.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import { addPlugin, getKeenSliderContext, provideKeenSliderContext, useKeenSlider, useKeenSliderAt, useKeenSliderContext } from "./useKeenSlider.js";
|
|
2
|
+
export { addPlugin, getKeenSliderContext, provideKeenSliderContext, useKeenSlider, useKeenSliderAt, useKeenSliderContext };
|