@rcarls/rc-carousel 0.1.0 → 0.7.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.
@@ -1,64 +1,40 @@
1
- import { css as f, LitElement as m, html as h, nothing as d } from "lit";
2
- import { property as l, query as b, state as x } from "lit/decorators.js";
3
- import { DragGestureController as I, findNearestSnapIndex as k, findExtremeSnapIndex as g, findNextSnapIndex as A, keyNavigation as v } from "@rcarls/rc-common";
4
- const C = f`
5
- :host {
6
- display: block;
7
- box-sizing: border-box;
8
- min-inline-size: 0;
9
- min-block-size: 0;
10
- scroll-snap-align: var(--rc-carousel-item-scroll-snap-align, start);
11
- /*
12
- * Without this, a normal-speed swipe carries enough fling momentum to
13
- * sail past the very next item and settle two (or more) items over —
14
- * \`mandatory\` scroll-snap-type on the track alone only guarantees
15
- * landing on *a* snap point, not the nearest one. \`always\` forces the
16
- * browser to stop at each snap point in turn.
17
- */
18
- scroll-snap-stop: always;
19
- overflow: var(--rc-carousel-item-overflow, hidden);
20
- border-radius: var(--rc-carousel-item-border-radius, 0);
21
- background: var(--rc-carousel-item-background, transparent);
22
- color: var(--rc-carousel-item-color, CanvasText);
23
- color-scheme: inherit;
24
- }
25
-
26
- :host([hidden]) {
27
- display: none;
28
- }
29
-
30
- /*
31
- * Peeking/off-screen items are hidden from assistive technology (see
32
- * rc-carousel-item.ts's IntersectionObserver) but must stay visually and
33
- * interactively present — a peek is a legitimate visual affordance, not
34
- * decoration to strip. This only removes it from the accessibility tree
35
- * and, via inert, the tab sequence, matching the same technique proven
36
- * carousels (e.g. Shoelace's sl-carousel) use for exactly this problem.
37
- */
38
- :host([aria-hidden='true']) {
39
- pointer-events: none;
40
- }
41
- `;
42
- var S = Object.defineProperty, E = (c, t, e, s) => {
43
- for (var i = void 0, n = c.length - 1, a; n >= 0; n--)
44
- (a = c[n]) && (i = a(t, e, i) || i);
45
- return i && S(t, e, i), i;
1
+ import { css as k, LitElement as A, html as h, nothing as p } from "lit";
2
+ import { property as c, query as S, state as w } from "lit/decorators.js";
3
+ import { syncDefaultAttribute as _, RafScheduler as E, MessagesController as T, HORIZONTAL_LTR_FLOW as O, DragGestureController as D, logicalDelta as v, findNearestSnapIndex as P, findExtremeSnapIndex as m, resolveFlow as b, clientSize as $, physicalAxis as z, getScrollOffset as N, setScrollOffset as x, findNextSnapIndex as R, keyNavigation as I, numberFormat as y } from "@rcarls/rc-common";
4
+ const L = k`:host{box-sizing:border-box;scroll-snap-align:var(--rc-carousel-item-scroll-snap-align,start);scroll-snap-stop:always;min-block-size:0;min-inline-size:0;overflow:var(--rc-carousel-item-overflow,hidden);border-radius:var(--rc-carousel-item-border-radius,0);background:var(--rc-carousel-item-background,transparent);color:var(--rc-carousel-item-color,CanvasText);color-scheme:inherit;display:block}:host([hidden]){display:none}:host([aria-hidden=true]){pointer-events:none}`;
5
+ var F = Object.defineProperty, C = (l, t, e, i) => {
6
+ for (var s = void 0, n = l.length - 1, o; n >= 0; n--)
7
+ (o = l[n]) && (s = o(t, e, s) || s);
8
+ return s && F(t, e, s), s;
46
9
  };
47
- const p = class p extends m {
10
+ const f = class f extends A {
48
11
  constructor() {
49
- super(), this._intersectionObserver = null, this.position = "", this._internals = this.attachInternals(), this._internals.role = "group";
12
+ super(), this._intersectionObserver = null, this.position = "", this.roleDescription = "slide", this._writtenLabel = null, this._writtenRoleDescription = null, this._internals = this.attachInternals(), this._internals.role = "group";
50
13
  }
51
14
  connectedCallback() {
52
- super.connectedCallback(), this.hasAttribute("role") || this.setAttribute("role", "group"), this.hasAttribute("aria-roledescription") || this.setAttribute("aria-roledescription", "slide"), this._observeIntersection();
15
+ super.connectedCallback(), this.hasAttribute("role") || this.setAttribute("role", "group"), this._syncRoleDescription(), this._observeIntersection();
53
16
  }
54
17
  disconnectedCallback() {
55
18
  super.disconnectedCallback(), this._intersectionObserver?.disconnect(), this._intersectionObserver = null;
56
19
  }
57
20
  updated(t) {
58
- super.updated(t), t.has("position") && this._syncDefaultLabel();
21
+ super.updated(t), t.has("position") && this._syncDefaultLabel(), t.has("roleDescription") && this._syncRoleDescription();
59
22
  }
60
23
  _syncDefaultLabel() {
61
- this.hasAttribute("aria-label") || this.hasAttribute("aria-labelledby") || this.position && this.setAttribute("aria-label", this.position);
24
+ this.hasAttribute("aria-labelledby") || !this.position || (this._writtenLabel = _(
25
+ this,
26
+ "aria-label",
27
+ this.position,
28
+ this._writtenLabel
29
+ ));
30
+ }
31
+ _syncRoleDescription() {
32
+ this._writtenRoleDescription = _(
33
+ this,
34
+ "aria-roledescription",
35
+ this.roleDescription,
36
+ this._writtenRoleDescription
37
+ );
62
38
  }
63
39
  /**
64
40
  * Observes intersection against the parent carousel's own scroll
@@ -83,9 +59,9 @@ const p = class p extends m {
83
59
  return;
84
60
  }
85
61
  this._intersectionObserver = new IntersectionObserver(
86
- ([s]) => {
87
- const i = s !== void 0 && !s.isIntersecting;
88
- i ? (this.contains(this.ownerDocument.activeElement) && t?.trackElement?.focus(), this.setAttribute("aria-hidden", "true")) : this.removeAttribute("aria-hidden"), this.toggleAttribute("inert", i);
62
+ ([i]) => {
63
+ const s = i !== void 0 && !i.isIntersecting;
64
+ s ? (this.contains(this.ownerDocument.activeElement) && t?.trackElement?.focus(), this.setAttribute("aria-hidden", "true")) : this.removeAttribute("aria-hidden"), this.toggleAttribute("inert", s);
89
65
  },
90
66
  // A low/zero threshold would count a peeking neighbor's own sliver
91
67
  // of visible pixels as "intersecting", never hiding it — a peek is
@@ -99,168 +75,76 @@ const p = class p extends m {
99
75
  return h`<slot></slot>`;
100
76
  }
101
77
  };
102
- p.styles = C;
103
- let u = p;
104
- E([
105
- l({ type: String, attribute: !1 })
78
+ f.styles = L;
79
+ let u = f;
80
+ C([
81
+ c({ type: String, attribute: !1 })
106
82
  ], u.prototype, "position");
107
- const w = f`
108
- :host {
109
- display: block;
110
- position: relative;
111
- color: var(--rc-carousel-color, CanvasText);
112
- color-scheme: inherit;
113
- }
114
-
115
- #track {
116
- display: grid;
117
- grid-auto-flow: column;
118
- grid-auto-columns: var(--rc-carousel-slide-size, calc(100% - 4rem));
119
- column-gap: var(--rc-carousel-gap, 8px);
120
- inline-size: 100%;
121
- block-size: 100%;
122
- overflow-x: auto;
123
- overflow-y: hidden;
124
- overscroll-behavior-x: contain;
125
- scroll-snap-type: x mandatory;
126
- /*
127
- * Deliberately no \`scroll-behavior: smooth\` here — _scrollToIndex in
128
- * rc-carousel.ts passes \`behavior: 'smooth'\` explicitly per
129
- * programmatic call instead, which is unaffected either way (an
130
- * explicit argument always overrides this CSS default). Setting it
131
- * here as an ambient default would also apply to the browser's own
132
- * native snap-settle correction after a swipe — a documented
133
- * cross-browser conflict with scroll-snap-stop: always (each
134
- * rc-carousel-item sets that; Firefox bugzilla 1643217, 1959811)
135
- * that produces a jerk-then-snap-back artifact on an ordinary swipe.
136
- */
137
- scrollbar-width: none;
138
- }
139
-
140
- #track::-webkit-scrollbar {
141
- display: none;
142
- }
143
-
144
- :host([mouse-dragging]) #track {
145
- cursor: grab;
146
- }
147
-
148
- :host([mouse-dragging]) #track.dragging {
149
- cursor: grabbing;
150
- /*
151
- * scroll-snap-type itself is toggled imperatively in rc-carousel.ts,
152
- * not here — it must be off before the very first scrollLeft write of
153
- * a drag, and this class only lands on the next reactive render, a
154
- * render pass too late for that first write (the browser eagerly
155
- * resnaps a plain scrollLeft assignment right back to the nearest
156
- * snap point, same as any other programmatic scroll).
157
- */
158
- }
159
-
160
- #navigation {
161
- display: contents;
162
- }
163
-
164
- [part~='navigation-button'] {
165
- position: absolute;
166
- top: 50%;
167
- translate: 0 -50%;
168
- display: inline-flex;
169
- align-items: center;
170
- justify-content: center;
171
- inline-size: var(--rc-carousel-navigation-button-size, 40px);
172
- block-size: var(--rc-carousel-navigation-button-size, 40px);
173
- border: none;
174
- border-radius: 50%;
175
- background: var(
176
- --rc-carousel-navigation-button-background,
177
- color-mix(in srgb, CanvasText 12%, transparent)
178
- );
179
- color: var(--rc-carousel-navigation-button-color, CanvasText);
180
- cursor: pointer;
181
- }
182
-
183
- [part~='navigation-button'][aria-disabled='true'] {
184
- opacity: 0.38;
185
- cursor: default;
186
- }
187
-
188
- [part~='navigation-button-previous'] {
189
- inset-inline-start: var(--rc-carousel-navigation-inset, 8px);
190
- }
191
-
192
- [part~='navigation-button-next'] {
193
- inset-inline-end: var(--rc-carousel-navigation-inset, 8px);
194
- }
195
-
196
- #pagination {
197
- position: absolute;
198
- inset-block-end: var(--rc-carousel-navigation-inset, 8px);
199
- inset-inline: 0;
200
- display: flex;
201
- justify-content: center;
202
- gap: var(--rc-carousel-gap, 8px);
203
- }
204
-
205
- [part~='pagination-item'] {
206
- inline-size: var(--rc-carousel-pagination-item-size, 8px);
207
- block-size: var(--rc-carousel-pagination-item-size, 8px);
208
- padding: 0;
209
- border: none;
210
- border-radius: 50%;
211
- background: var(
212
- --rc-carousel-pagination-item-color,
213
- color-mix(in srgb, CanvasText 40%, transparent)
214
- );
215
- cursor: pointer;
216
- }
217
-
218
- [part~='pagination-item-active'] {
219
- background: var(--rc-carousel-pagination-item-active-color, Highlight);
220
- cursor: default;
221
- }
222
- `;
223
- var T = Object.defineProperty, $ = Object.getOwnPropertyDescriptor, o = (c, t, e, s) => {
224
- for (var i = s > 1 ? void 0 : s ? $(t, e) : t, n = c.length - 1, a; n >= 0; n--)
225
- (a = c[n]) && (i = (s ? a(t, e, i) : a(i)) || i);
226
- return s && i && T(t, e, i), i;
83
+ C([
84
+ c({ type: String, attribute: !1 })
85
+ ], u.prototype, "roleDescription");
86
+ const q = k`:host{color:var(--rc-carousel-color,CanvasText);color-scheme:inherit;display:block;position:relative}#track{grid-auto-flow:column;grid-auto-columns:var(--rc-carousel-slide-size,calc(100% - 4rem));column-gap:var(--rc-carousel-gap,8px);overflow-inline:auto;overflow-block:hidden;overscroll-behavior-inline:contain;scroll-snap-type:inline mandatory;scrollbar-width:none;block-size:100%;inline-size:100%;display:grid;overflow:auto hidden}#track::-webkit-scrollbar{display:none}:host([mouse-dragging]) #track{cursor:grab}:host([mouse-dragging]) #track.dragging{cursor:grabbing}#navigation{display:contents}[part~=navigation-button]{inline-size:var(--rc-carousel-navigation-button-size,40px);block-size:var(--rc-carousel-navigation-button-size,40px);background:var(--rc-carousel-navigation-button-background,color-mix(in srgb, CanvasText 12%, transparent));color:var(--rc-carousel-navigation-button-color,CanvasText);cursor:pointer;border:none;border-radius:50%;justify-content:center;align-items:center;display:inline-flex;position:absolute;top:50%;translate:0 -50%}[part~=navigation-button][aria-disabled=true]{opacity:.38;cursor:default}[part~=navigation-button-previous]{inset-inline-start:var(--rc-carousel-navigation-inset,8px)}[part~=navigation-button-next]{inset-inline-end:var(--rc-carousel-navigation-inset,8px)}#pagination{justify-content:center;gap:var(--rc-carousel-gap,8px);display:flex;position:absolute;inset-block-end:var(--rc-carousel-navigation-inset,8px);inset-inline:0}[part~=pagination-item]{inline-size:var(--rc-carousel-pagination-item-size,8px);block-size:var(--rc-carousel-pagination-item-size,8px);background:var(--rc-carousel-pagination-item-color,color-mix(in srgb, CanvasText 40%, transparent));cursor:pointer;border:none;border-radius:50%;padding:0}[part~=pagination-item-active]{background:var(--rc-carousel-pagination-item-active-color,Highlight);cursor:default}:host(:dir(rtl)) [part~=navigation-button] svg{transform:scaleX(-1)}`;
87
+ var M = Object.defineProperty, U = Object.getOwnPropertyDescriptor, a = (l, t, e, i) => {
88
+ for (var s = i > 1 ? void 0 : i ? U(t, e) : t, n = l.length - 1, o; n >= 0; n--)
89
+ (o = l[n]) && (s = (i ? o(t, e, s) : o(s)) || s);
90
+ return i && s && M(t, e, s), s;
227
91
  };
228
- const z = 300, P = 120, _ = class _ extends m {
92
+ const B = 300, j = Object.freeze({
93
+ carousel: "carousel",
94
+ slide: "slide",
95
+ position: (l, t, e) => {
96
+ const i = y(e, { useGrouping: !1 });
97
+ return `${i.format(l)} of ${i.format(t)}`;
98
+ },
99
+ previous: "Previous slide",
100
+ next: "Next slide",
101
+ picker: "Choose slide to display",
102
+ goToSlide: (l, t, e) => `Go to slide ${y(e, { useGrouping: !1 }).format(l)}`
103
+ }), G = 120, g = class g extends A {
229
104
  constructor() {
230
- super(), this._items = [], this._cloneItems = [], this._mounted = !1, this._suppressSync = !1, this._pendingInstant = !1, this.loop = !1, this.navigation = !1, this.pagination = !1, this.mouseDragging = !1, this._dragging = !1, this._dragStartLeft = 0, this._suppressNextClick = !1, this._dragController = new I(this, {
105
+ super(), this._items = [], this._cloneItems = [], this._mounted = !1, this._suppressSync = !1, this._pendingInstant = !1, this._initialPosition = new E(this), this._writtenRoleDescription = null, this._messages = new T(
106
+ this,
107
+ "rc-carousel",
108
+ j,
109
+ {
110
+ overrides: () => this.messages
111
+ }
112
+ ), this.loop = !1, this.navigation = !1, this.pagination = !1, this.mouseDragging = !1, this._dragging = !1, this._dragStartOffset = 0, this._flow = O, this._dragAxis = "x", this._suppressNextClick = !1, this._dragController = new D(this, {
231
113
  target: () => this._trackEl ?? null,
232
114
  axis: "x",
233
115
  activation: "axis",
234
- canStart: (t) => this.mouseDragging && t.pointerType === "mouse",
116
+ canStart: (t) => !this.mouseDragging || t.pointerType !== "mouse" ? !1 : (this._resolveFlow(), !0),
235
117
  onStart: () => {
236
- this._dragging = !0, this._dragStartLeft = this._trackEl?.scrollLeft ?? 0, this._suppressNextClick = !0, this._trackEl && (this._trackEl.style.scrollSnapType = "none");
118
+ this._dragging = !0, this._dragStartOffset = this._trackOffset(), this._suppressNextClick = !0, this._trackEl && (this._trackEl.style.scrollSnapType = "none");
237
119
  },
238
120
  onMove: (t) => {
239
- this._trackEl && (this._trackEl.scrollLeft = this._dragStartLeft - t.deltaX);
121
+ this._setTrackOffset(
122
+ this._dragStartOffset - v({ dx: t.deltaX, dy: t.deltaY }, "inline", this._flow)
123
+ );
240
124
  },
241
125
  onEnd: (t) => this._endDrag(t),
242
126
  onCancel: (t) => this._endDrag(t)
243
127
  }), this._busy = !1, this._defaultActiveIndex = 0, this._activeIndexInitialized = !1, this._onSlotChange = () => {
244
128
  this._syncItems();
245
129
  }, this._onScroll = () => {
246
- this._settleTimer !== void 0 && clearTimeout(this._settleTimer), this._busy = !0, this._settleTimer = setTimeout(this._commitSettledIndex, P);
130
+ this._settleTimer !== void 0 && clearTimeout(this._settleTimer), this._busy = !0, this._settleTimer = setTimeout(this._commitSettledIndex, G);
247
131
  }, this._commitSettledIndex = () => {
248
132
  if (this._busy = !1, !this._trackEl)
249
133
  return;
250
- const t = this._trackSlots(), e = k(
134
+ const t = this._trackSlots(), e = P(
251
135
  t.map((n) => n.point),
252
- this._trackEl.scrollLeft
253
- ), s = e >= 0 ? t[e] : void 0;
254
- if (!s)
136
+ this._trackOffset()
137
+ ), i = e >= 0 ? t[e] : void 0;
138
+ if (!i)
255
139
  return;
256
- if (s.isClone) {
257
- const n = t.find((a) => !a.isClone && a.index === s.index);
258
- n && (this._trackEl.scrollLeft = n.point);
140
+ if (i.isClone) {
141
+ const n = t.find((o) => !o.isClone && o.index === i.index);
142
+ n && this._setTrackOffset(n.point);
259
143
  }
260
- if (s.index === this.activeIndex)
144
+ if (i.index === this.activeIndex)
261
145
  return;
262
- const i = this._activeIndex !== void 0;
263
- i || (this._suppressSync = !0), this._setActiveIndex(s.index, "swipe"), i && this.activeIndex !== s.index && this._scrollToIndex(this.activeIndex, !0);
146
+ const s = this._activeIndex !== void 0;
147
+ s || (this._suppressSync = !0), this._setActiveIndex(i.index, "swipe"), s && this.activeIndex !== i.index && this._scrollToIndex(this.activeIndex, !0);
264
148
  }, this._onNavigate = (t) => {
265
149
  switch (t) {
266
150
  case "next":
@@ -270,12 +154,12 @@ const z = 300, P = 120, _ = class _ extends m {
270
154
  this._step(-1, "keyboard");
271
155
  break;
272
156
  case "start": {
273
- const e = g(this._snapPoints(), -1);
157
+ const e = m(this._snapPoints(), -1);
274
158
  e >= 0 && this._setActiveIndex(e, "keyboard");
275
159
  break;
276
160
  }
277
161
  case "end": {
278
- const e = g(this._snapPoints(), 1);
162
+ const e = m(this._snapPoints(), 1);
279
163
  e >= 0 && this._setActiveIndex(e, "keyboard");
280
164
  break;
281
165
  }
@@ -283,19 +167,19 @@ const z = 300, P = 120, _ = class _ extends m {
283
167
  }, this._onTrackClickCapture = (t) => {
284
168
  this._suppressNextClick && (this._suppressNextClick = !1, t.stopPropagation(), t.preventDefault());
285
169
  }, this._onPaginationFocus = (t) => {
286
- const e = this._paginationButtons(), s = t.composedPath().find((i) => e.includes(i));
287
- s && e.forEach((i) => i.setAttribute("tabindex", i === s ? "0" : "-1"));
170
+ const e = this._paginationButtons(), i = t.composedPath().find((s) => e.includes(s));
171
+ i && e.forEach((s) => s.setAttribute("tabindex", s === i ? "0" : "-1"));
288
172
  }, this._onPaginationNavigate = (t) => {
289
173
  const e = this._paginationButtons();
290
174
  if (!e.length)
291
175
  return;
292
- const s = e.indexOf(this.shadowRoot?.activeElement), i = s < 0 ? 0 : s;
176
+ const i = e.indexOf(this.shadowRoot?.activeElement), s = i < 0 ? 0 : i;
293
177
  switch (t) {
294
178
  case "next":
295
- e[(i + 1) % e.length]?.focus();
179
+ e[(s + 1) % e.length]?.focus();
296
180
  break;
297
181
  case "prev":
298
- e[(i - 1 + e.length) % e.length]?.focus();
182
+ e[(s - 1 + e.length) % e.length]?.focus();
299
183
  break;
300
184
  case "start":
301
185
  e[0]?.focus();
@@ -332,17 +216,21 @@ const z = 300, P = 120, _ = class _ extends m {
332
216
  return this._trackEl ?? null;
333
217
  }
334
218
  connectedCallback() {
335
- super.connectedCallback(), this._items = this._directItems(), this._setItemPositions(), this.hasAttribute("role") || this.setAttribute("role", "group"), this.hasAttribute("aria-roledescription") || this.setAttribute("aria-roledescription", "carousel");
219
+ super.connectedCallback(), this._items = this._directItems(), this._setItemPositions(), this.hasAttribute("role") || this.setAttribute("role", "group"), this._syncText(), this.hasUpdated && !this._mounted && this._queueInitialPosition();
336
220
  }
337
221
  disconnectedCallback() {
338
222
  super.disconnectedCallback(), this._settleTimer !== void 0 && clearTimeout(this._settleTimer);
339
223
  }
340
224
  firstUpdated() {
341
- this._scrollToIndex(this.activeIndex, !0), this._mounted = !0;
225
+ this._syncActiveItemAccessibility(this.activeIndex), this._queueInitialPosition();
342
226
  }
343
227
  updated(t) {
344
- if (super.updated(t), this._initPaginationTabIndex(), t.has("loop") && this._mounted && this._syncItems(), !t.has("activeIndex"))
228
+ if (super.updated(t), this._syncText(), this._initPaginationTabIndex(), t.has("loop") && this._mounted && this._syncItems(), !t.has("activeIndex"))
229
+ return;
230
+ if (this._syncActiveItemAccessibility(this.activeIndex), !this._mounted) {
231
+ this._queueInitialPosition();
345
232
  return;
233
+ }
346
234
  if (this._suppressSync) {
347
235
  this._suppressSync = !1;
348
236
  return;
@@ -384,7 +272,7 @@ const z = 300, P = 120, _ = class _ extends m {
384
272
  }
385
273
  _snapPoints() {
386
274
  const t = this._itemStep();
387
- return this._items.map((e, s) => s * t);
275
+ return this._items.map((e, i) => i * t);
388
276
  }
389
277
  /**
390
278
  * Every scrollable track position in rendered order, including cloned
@@ -394,38 +282,96 @@ const z = 300, P = 120, _ = class _ extends m {
394
282
  * an index and reading back a settled scroll position can stay in terms
395
283
  * of real indices while the clones do the seamless-wrap work.
396
284
  */
397
- _trackSlots() {
398
- const t = this._itemStep(), e = this._items.length;
399
- return !this.loop || e < 2 ? this._items.map((s, i) => ({ point: i * t, index: i, isClone: !1 })) : [
285
+ _trackSlots(t = this._itemStep()) {
286
+ const e = this._items.length;
287
+ return !this.loop || e < 2 ? this._items.map((i, s) => ({ point: s * t, index: s, isClone: !1 })) : [
400
288
  { point: 0, index: e - 1, isClone: !0 },
401
- ...this._items.map((s, i) => ({ point: (i + 1) * t, index: i, isClone: !1 })),
289
+ ...this._items.map((i, s) => ({ point: (s + 1) * t, index: s, isClone: !1 })),
402
290
  { point: (e + 1) * t, index: 0, isClone: !0 }
403
291
  ];
404
292
  }
405
293
  _itemStep() {
406
- if (!this._trackEl)
407
- return 1;
408
- const t = this._items[0];
409
- if (!(t instanceof HTMLElement))
410
- return this._trackEl.clientWidth;
411
- const e = Number.parseFloat(getComputedStyle(this._trackEl).columnGap || "0") || 0;
412
- return t.offsetWidth + e;
294
+ const t = this._measureTrack();
295
+ return t ? (this._applyFlow(t.flow), t.step) : 1;
296
+ }
297
+ _measureTrack() {
298
+ const t = this._trackEl;
299
+ if (!t)
300
+ return null;
301
+ const e = this._items[0], i = b(t), s = e instanceof HTMLElement ? (i.inline === "x" ? e.offsetWidth : e.offsetHeight) + (Number.parseFloat(getComputedStyle(t).columnGap || "0") || 0) : $(t, "inline", i);
302
+ return { track: t, flow: i, step: s };
303
+ }
304
+ _applyFlow(t) {
305
+ this._flow = t;
306
+ const e = z("inline", t);
307
+ !this._dragging && e !== this._dragAxis && (this._dragAxis = e, this._dragController.setOptions({ axis: e }));
308
+ }
309
+ /**
310
+ * Re-reads the track's writing mode and direction. Called at the start of
311
+ * each scroll operation and on each drag's pointerdown rather than cached
312
+ * for the element's life, since neither a `dir` nor a writing-mode change
313
+ * on an ancestor fires an event. The drag gesture's physical axis follows,
314
+ * so a carousel in vertical text drags vertically.
315
+ */
316
+ _resolveFlow() {
317
+ return this._trackEl ? (this._applyFlow(b(this._trackEl)), this._flow) : this._flow;
318
+ }
319
+ /** Scroll distance from the track's logical start, never negative. */
320
+ _trackOffset() {
321
+ return this._trackEl ? N(this._trackEl, "inline", this._flow) : 0;
322
+ }
323
+ _setTrackOffset(t, e = "auto") {
324
+ this._trackEl && x(this._trackEl, "inline", t, this._flow, e);
413
325
  }
414
326
  _setActiveIndex(t, e) {
415
- const s = this._clampIndex(t), i = this.activeIndex;
416
- i !== s && (this._activeIndex === void 0 && (this._uncontrolledActiveIndex = s, this.requestUpdate("activeIndex", i)), this.dispatchEvent(
327
+ const i = this._clampIndex(t), s = this.activeIndex;
328
+ s !== i && (this._activeIndex === void 0 && (this._uncontrolledActiveIndex = i, this.requestUpdate("activeIndex", s)), this.dispatchEvent(
417
329
  new CustomEvent("rc-carousel-change", {
418
330
  bubbles: !0,
419
331
  composed: !0,
420
- detail: { index: s, trigger: e }
332
+ detail: { index: i, trigger: e }
421
333
  })
422
334
  ));
423
335
  }
424
336
  _scrollToIndex(t, e) {
425
337
  if (!this._trackEl)
426
338
  return;
427
- const s = this._trackSlots().find((a) => !a.isClone && a.index === t), i = s ? s.point : t * this._itemStep(), n = this.ownerDocument.defaultView?.matchMedia("(prefers-reduced-motion: reduce)").matches ?? !1;
428
- e || n ? this._trackEl.scrollLeft = i : this._trackEl.scrollTo({ left: i, behavior: "smooth" });
339
+ const i = this._trackSlots().find((o) => !o.isClone && o.index === t), s = i ? i.point : t * this._itemStep(), n = this.ownerDocument.defaultView?.matchMedia("(prefers-reduced-motion: reduce)").matches ?? !1;
340
+ this._setTrackOffset(s, e || n ? "auto" : "smooth");
341
+ }
342
+ _queueInitialPosition() {
343
+ this._initialPosition.schedulePhased(
344
+ () => this._sampleInitialPosition(),
345
+ (t) => this._applyInitialPosition(t)
346
+ );
347
+ }
348
+ _sampleInitialPosition() {
349
+ const t = this._measureTrack();
350
+ if (!t)
351
+ return null;
352
+ const e = this._trackSlots(t.step).find(
353
+ (i) => !i.isClone && i.index === this.activeIndex
354
+ );
355
+ return {
356
+ ...t,
357
+ offset: e ? e.point : this.activeIndex * t.step
358
+ };
359
+ }
360
+ _applyInitialPosition(t) {
361
+ !t || !this.isConnected || this._trackEl !== t.track || (this._applyFlow(t.flow), x(t.track, "inline", t.offset, t.flow, "auto"), this._mounted = !0);
362
+ }
363
+ /**
364
+ * Keep the authored active slide available to assistive technology even
365
+ * before a programmatic scroll produces its next intersection callback.
366
+ * IntersectionObserver still takes over during direct manipulation, where
367
+ * the visually dominant slide can change before scroll settling updates the
368
+ * public active index.
369
+ */
370
+ _syncActiveItemAccessibility(t) {
371
+ this._directItems().forEach((e, i) => {
372
+ const s = i !== t;
373
+ e.toggleAttribute("aria-hidden", s), e.toggleAttribute("inert", s);
374
+ });
429
375
  }
430
376
  _directItems() {
431
377
  return Array.from(this.children).filter(
@@ -433,10 +379,20 @@ const z = 300, P = 120, _ = class _ extends m {
433
379
  );
434
380
  }
435
381
  _setItemPositions() {
436
- this._items.forEach((t, e) => {
437
- t.position = `${e + 1} of ${this._items.length}`;
382
+ const t = this._messages.value;
383
+ this._items.forEach((e, i) => {
384
+ e.position = t.position(i + 1, this._items.length, this._messages.locale), e.roleDescription = t.slide;
438
385
  });
439
386
  }
387
+ /** Re-applies text written outside the template, for a new locale or `messages`. */
388
+ _syncText() {
389
+ this._writtenRoleDescription = _(
390
+ this,
391
+ "aria-roledescription",
392
+ this._messages.value.carousel,
393
+ this._writtenRoleDescription
394
+ ), this._setItemPositions();
395
+ }
440
396
  /**
441
397
  * Prepending/appending the loop clones below is itself a light-DOM
442
398
  * mutation on this host, which re-fires `slotchange` (asynchronously) —
@@ -450,9 +406,9 @@ const z = 300, P = 120, _ = class _ extends m {
450
406
  */
451
407
  _syncItems() {
452
408
  const e = (this._slotEl?.assignedElements() ?? []).filter(
453
- (a) => a.tagName === "RC-CAROUSEL-ITEM" && !a.hasAttribute("data-clone")
454
- ), s = e.length !== this._items.length || e.some((a, y) => a !== this._items[y]), i = this.loop && e.length > 1, n = this._cloneItems.length > 0;
455
- this._items = e, this._setItemPositions(), s && this._mounted && this.requestUpdate(), !(!s && i === n) && (this._removeClones(), i && this._addClones());
409
+ (o) => o.tagName === "RC-CAROUSEL-ITEM" && !o.hasAttribute("data-clone")
410
+ ), i = e.length !== this._items.length || e.some((o, d) => o !== this._items[d]), s = this.loop && e.length > 1, n = this._cloneItems.length > 0;
411
+ this._items = e, this._setItemPositions(), i && this._mounted && this.requestUpdate(), !(!i && s === n) && (this._removeClones(), s && this._addClones());
456
412
  }
457
413
  /**
458
414
  * Clones the first and last slide and prepends/appends them
@@ -467,10 +423,10 @@ const z = 300, P = 120, _ = class _ extends m {
467
423
  const t = this._items[0], e = this._items[this._items.length - 1];
468
424
  if (!t || !e)
469
425
  return;
470
- const s = e.cloneNode(!0);
471
- s.setAttribute("data-clone", String(this._items.length - 1)), this._sanitizeClone(s), this.prepend(s);
472
- const i = t.cloneNode(!0);
473
- i.setAttribute("data-clone", "0"), this._sanitizeClone(i), this.append(i), this._cloneItems = [s, i];
426
+ const i = e.cloneNode(!0);
427
+ i.setAttribute("data-clone", String(this._items.length - 1)), this._sanitizeClone(i), this.prepend(i);
428
+ const s = t.cloneNode(!0);
429
+ s.setAttribute("data-clone", "0"), this._sanitizeClone(s), this.append(s), this._cloneItems = [i, s];
474
430
  }
475
431
  /** Keeps visual loop clones out of forms, focus order, and the accessibility tree. */
476
432
  _sanitizeClone(t) {
@@ -482,24 +438,30 @@ const z = 300, P = 120, _ = class _ extends m {
482
438
  this._cloneItems.forEach((t) => t.remove()), this._cloneItems = [];
483
439
  }
484
440
  /**
485
- * On release, a fast enough flick pre-nudges `scrollLeft` to the next
441
+ * On release, a fast enough flick pre-nudges the scroll offset to the next
486
442
  * snap point in the drag direction (a "decisive swipe" — mirroring
487
443
  * `rc-bottom-sheet`'s own velocity-vs-nearest-point settle heuristic,
488
444
  * adapted from "jump to the extreme end" for a 2-point sheet to "advance
489
445
  * one further point" for a carousel that can have many). Either way,
490
446
  * this hands off to the same debounced settle path a native swipe
491
- * already goes through — our own `scrollLeft` writes during the drag
447
+ * already goes through — our own scroll offset writes during the drag
492
448
  * already fired real `scroll` events, so `_onScroll` just needs to run
493
449
  * its usual timer to pick up wherever things ended.
494
450
  */
495
451
  _endDrag(t) {
496
- if (this._dragging = !1, this._trackEl && (this._trackEl.style.scrollSnapType = ""), this._trackEl && Math.abs(t.velocityX) > z) {
497
- const e = this._trackSlots(), s = t.velocityX < 0 ? 1 : -1, i = A(
498
- e.map((a) => a.point),
499
- this._trackEl.scrollLeft,
452
+ this._dragging = !1, this._trackEl && (this._trackEl.style.scrollSnapType = "");
453
+ const e = v(
454
+ { dx: t.velocityX, dy: t.velocityY },
455
+ "inline",
456
+ this._flow
457
+ );
458
+ if (this._trackEl && Math.abs(e) > B) {
459
+ const i = this._trackSlots(), s = e < 0 ? 1 : -1, n = R(
460
+ i.map((d) => d.point),
461
+ this._trackOffset(),
500
462
  s
501
- ), n = e[i];
502
- n && (this._trackEl.scrollLeft = n.point);
463
+ ), o = i[n];
464
+ o && this._setTrackOffset(o.point);
503
465
  }
504
466
  this._onScroll();
505
467
  }
@@ -520,18 +482,18 @@ const z = 300, P = 120, _ = class _ extends m {
520
482
  });
521
483
  }
522
484
  render() {
523
- const t = this._canStep(-1), e = this._canStep(1);
485
+ const t = this._canStep(-1), e = this._canStep(1), i = this._messages.value;
524
486
  return h`
525
487
  <div
526
488
  id="track"
527
489
  part="track"
528
490
  tabindex="0"
529
- class=${this._dragging ? "dragging" : d}
491
+ class=${this._dragging ? "dragging" : p}
530
492
  aria-busy=${this._busy ? "true" : "false"}
531
493
  aria-atomic="true"
532
494
  @scroll=${this._onScroll}
533
495
  @click=${{ handleEvent: this._onTrackClickCapture, capture: !0 }}
534
- ${v(this._onNavigate, { navigationAxis: "horizontal" })}
496
+ ${I(this._onNavigate, { navigationAxis: "horizontal" })}
535
497
  >
536
498
  <slot @slotchange=${this._onSlotChange}></slot>
537
499
  </div>
@@ -541,7 +503,7 @@ const z = 300, P = 120, _ = class _ extends m {
541
503
  <button
542
504
  type="button"
543
505
  part="navigation-button navigation-button-previous"
544
- aria-label="Previous slide"
506
+ aria-label=${i.previous}
545
507
  aria-disabled=${t ? "false" : "true"}
546
508
  @click=${() => {
547
509
  t && this._step(-1, "button");
@@ -567,7 +529,7 @@ const z = 300, P = 120, _ = class _ extends m {
567
529
  <button
568
530
  type="button"
569
531
  part="navigation-button navigation-button-next"
570
- aria-label="Next slide"
532
+ aria-label=${i.next}
571
533
  aria-disabled=${e ? "false" : "true"}
572
534
  @click=${() => {
573
535
  e && this._step(1, "button");
@@ -591,68 +553,76 @@ const z = 300, P = 120, _ = class _ extends m {
591
553
  </span>
592
554
  </button>
593
555
  </div>
594
- ` : d}
556
+ ` : p}
595
557
  ${this.pagination ? h`
596
558
  <div
597
559
  id="pagination"
598
560
  part="pagination"
599
561
  role="group"
600
- aria-label="Choose slide to display"
562
+ aria-label=${i.picker}
601
563
  @focusin=${this._onPaginationFocus}
602
- ${v(this._onPaginationNavigate, { navigationAxis: "horizontal" })}
564
+ ${I(this._onPaginationNavigate, { navigationAxis: "horizontal" })}
603
565
  >
604
566
  ${this._items.map(
605
- (s, i) => h`
567
+ (s, n) => h`
606
568
  <button
607
569
  type="button"
608
570
  data-pagination-item
609
- part="pagination-item${i === this.activeIndex ? " pagination-item-active" : ""}"
610
- aria-label="Go to slide ${i + 1}"
611
- aria-current=${i === this.activeIndex ? "true" : "false"}
612
- aria-disabled=${i === this.activeIndex ? "true" : "false"}
613
- @click=${() => this._setActiveIndex(i, "button")}
571
+ part="pagination-item${n === this.activeIndex ? " pagination-item-active" : ""}"
572
+ aria-label=${i.goToSlide(
573
+ n + 1,
574
+ this._items.length,
575
+ this._messages.locale
576
+ )}
577
+ aria-current=${n === this.activeIndex ? "true" : "false"}
578
+ aria-disabled=${n === this.activeIndex ? "true" : "false"}
579
+ @click=${() => this._setActiveIndex(n, "button")}
614
580
  ></button>
615
581
  `
616
582
  )}
617
583
  </div>
618
- ` : d}
584
+ ` : p}
619
585
  `;
620
586
  }
621
587
  };
622
- _.styles = w;
623
- let r = _;
624
- o([
625
- b("#track")
588
+ g.styles = q;
589
+ let r = g;
590
+ a([
591
+ S("#track")
626
592
  ], r.prototype, "_trackEl", 2);
627
- o([
628
- b("slot:not([name])")
593
+ a([
594
+ S("slot:not([name])")
629
595
  ], r.prototype, "_slotEl", 2);
630
- o([
631
- l({ type: Boolean, reflect: !0 })
596
+ a([
597
+ c({ attribute: !1 })
598
+ ], r.prototype, "messages", 2);
599
+ a([
600
+ c({ type: Boolean, reflect: !0 })
632
601
  ], r.prototype, "loop", 2);
633
- o([
634
- l({ type: Boolean, reflect: !0 })
602
+ a([
603
+ c({ type: Boolean, reflect: !0 })
635
604
  ], r.prototype, "navigation", 2);
636
- o([
637
- l({ type: Boolean, reflect: !0 })
605
+ a([
606
+ c({ type: Boolean, reflect: !0 })
638
607
  ], r.prototype, "pagination", 2);
639
- o([
640
- l({ type: Boolean, reflect: !0, attribute: "mouse-dragging" })
608
+ a([
609
+ c({ type: Boolean, reflect: !0, attribute: "mouse-dragging" })
641
610
  ], r.prototype, "mouseDragging", 2);
642
- o([
643
- x()
611
+ a([
612
+ w()
644
613
  ], r.prototype, "_dragging", 2);
645
- o([
646
- x()
614
+ a([
615
+ w()
647
616
  ], r.prototype, "_busy", 2);
648
- o([
649
- l({ type: Number, attribute: "active-index" })
617
+ a([
618
+ c({ type: Number, attribute: "active-index" })
650
619
  ], r.prototype, "activeIndex", 1);
651
- o([
652
- l({ type: Number, attribute: "default-active-index" })
620
+ a([
621
+ c({ type: Number, attribute: "default-active-index" })
653
622
  ], r.prototype, "defaultActiveIndex", 1);
654
623
  export {
624
+ j as D,
655
625
  r as R,
656
626
  u as a
657
627
  };
658
- //# sourceMappingURL=rc-carousel-CdDEH9fb.js.map
628
+ //# sourceMappingURL=rc-carousel-CGHUVDLI.js.map