@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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-carousel-CGHUVDLI.js","sources":["../src/rc-carousel-item.styles.ts","../src/rc-carousel-item.ts","../src/rc-carousel.styles.ts","../src/rc-carousel.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const carouselItemStyles = css`\n :host {\n display: block;\n box-sizing: border-box;\n min-inline-size: 0;\n min-block-size: 0;\n scroll-snap-align: var(--rc-carousel-item-scroll-snap-align, start);\n /*\n * Without this, a normal-speed swipe carries enough fling momentum to\n * sail past the very next item and settle two (or more) items over —\n * \\`mandatory\\` scroll-snap-type on the track alone only guarantees\n * landing on *a* snap point, not the nearest one. \\`always\\` forces the\n * browser to stop at each snap point in turn.\n */\n scroll-snap-stop: always;\n overflow: var(--rc-carousel-item-overflow, hidden);\n border-radius: var(--rc-carousel-item-border-radius, 0);\n background: var(--rc-carousel-item-background, transparent);\n color: var(--rc-carousel-item-color, CanvasText);\n color-scheme: inherit;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n /*\n * Peeking/off-screen items are hidden from assistive technology (see\n * rc-carousel-item.ts's IntersectionObserver) but must stay visually and\n * interactively present — a peek is a legitimate visual affordance, not\n * decoration to strip. This only removes it from the accessibility tree\n * and, via inert, the tab sequence, matching the same technique proven\n * carousels (e.g. Shoelace's sl-carousel) use for exactly this problem.\n */\n :host([aria-hidden='true']) {\n pointer-events: none;\n }\n`;\n\nexport default carouselItemStyles;\n","import { LitElement, html } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { syncDefaultAttribute } from '@rcarls/rc-common';\nimport type { RCCarousel } from './rc-carousel.js';\n\nimport carouselItemStyles from './rc-carousel-item.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-carousel-item': RCCarouselItem;\n }\n}\n\n/**\n * One slide of an `rc-carousel`. Participates directly in the parent's\n * scroll-snap track as a grid-auto-flow child — `rc-carousel-item` owns its\n * own snap alignment and accessibility state, but authored content (an\n * `<img>` with real alt text, arbitrary markup) stays exactly as slotted,\n * never cloned or re-parented, so it remains directly available to forms,\n * labels, and assistive technology.\n *\n * While off-screen (not the intersecting slide, including a partially\n * visible peek), the slide is marked `aria-hidden` and `inert`: it stays\n * visually and pointer-interactively present as a peek affordance, but\n * drops out of the accessibility tree and the Tab sequence, so a slide's\n * interactive descendants (a button, a link) can't be reached by keyboard\n * or announced by a screen reader until their slide is actually active.\n *\n * @slot - Slide content.\n *\n * @cssprop [--rc-carousel-item-color=CanvasText] - Slide foreground color.\n * @cssprop [--rc-carousel-item-scroll-snap-align=start] - Snap alignment\n * within the track. Override for a center-aligned layout.\n * @cssprop [--rc-carousel-item-background=transparent] - Slide surface\n * background, e.g. for an MD3 card-like slide shape.\n * @cssprop [--rc-carousel-item-border-radius=0] - Slide corner radius.\n * @cssprop [--rc-carousel-item-overflow=hidden] - Overflow behavior for\n * slotted content that exceeds the slide's own box. `hidden` clips to\n * the corner radius (matching media-item slides); text-heavy slides\n * that need their own internal scroll may want `auto` instead.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-carousel rc-carousel documentation}\n */\nexport class RCCarouselItem extends LitElement {\n static override styles = carouselItemStyles;\n\n private readonly _internals: ElementInternals;\n\n private _intersectionObserver: IntersectionObserver | null = null;\n\n /**\n * \"N of M\" position assigned by the parent `rc-carousel`. Internal\n * integration point, not a public API — see the `@attr` note above.\n */\n @property({ type: String, attribute: false })\n position = '';\n\n /**\n * `aria-roledescription` assigned by the parent `rc-carousel` in its\n * locale. Internal integration point, not a public API.\n */\n @property({ type: String, attribute: false })\n roleDescription = 'slide';\n\n private _writtenLabel: string | null = null;\n private _writtenRoleDescription: string | null = null;\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n this._internals.role = 'group';\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'group');\n }\n\n this._syncRoleDescription();\n\n this._observeIntersection();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n this._intersectionObserver?.disconnect();\n this._intersectionObserver = null;\n }\n\n protected override updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n\n if (changed.has('position')) {\n this._syncDefaultLabel();\n }\n\n if (changed.has('roleDescription')) {\n this._syncRoleDescription();\n }\n }\n\n private _syncDefaultLabel(): void {\n if (this.hasAttribute('aria-labelledby') || !this.position) {\n return;\n }\n\n this._writtenLabel = syncDefaultAttribute(\n this,\n 'aria-label',\n this.position,\n this._writtenLabel,\n );\n }\n\n private _syncRoleDescription(): void {\n this._writtenRoleDescription = syncDefaultAttribute(\n this,\n 'aria-roledescription',\n this.roleDescription,\n this._writtenRoleDescription,\n );\n }\n\n /**\n * Observes intersection against the parent carousel's own scroll\n * container (not the viewport — a slide can be viewport-visible yet\n * still clipped/off-screen within the track on a page where the\n * carousel isn't the whole viewport). Reads `trackElement` off the\n * parent `rc-carousel`, an internal integration point rather than a\n * public API — awaits the parent's own first render first, since a\n * slotted item's `connectedCallback` isn't guaranteed to run after its\n * host's, and `trackElement` only exists once the host has rendered.\n */\n private async _observeIntersection(): Promise<void> {\n if (this.hasAttribute('data-clone')) {\n this.setAttribute('aria-hidden', 'true');\n this.setAttribute('inert', '');\n\n return;\n }\n\n const $carousel = this.closest('rc-carousel') as RCCarousel | null;\n\n await $carousel?.updateComplete;\n\n const $root = $carousel?.trackElement ?? null;\n\n this._intersectionObserver?.disconnect();\n\n if (typeof IntersectionObserver !== 'function' || !$root) {\n this.removeAttribute('aria-hidden');\n this.removeAttribute('inert');\n\n return;\n }\n\n this._intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n const hidden = entry !== undefined && !entry.isIntersecting;\n\n if (hidden) {\n if (this.contains(this.ownerDocument.activeElement)) {\n $carousel?.trackElement?.focus();\n }\n\n this.setAttribute('aria-hidden', 'true');\n } else {\n this.removeAttribute('aria-hidden');\n }\n\n this.toggleAttribute('inert', hidden);\n },\n // A low/zero threshold would count a peeking neighbor's own sliver\n // of visible pixels as \"intersecting\", never hiding it — a peek is\n // real but not readable/interactive, so it should still hide. 0.5\n // reliably separates \"the active slide\" (near-fully visible) from\n // \"a peeking neighbor\" (a fraction of it showing).\n { root: $root, threshold: 0.5 },\n );\n\n this._intersectionObserver.observe(this);\n }\n\n protected override render() {\n return html`<slot></slot>`;\n }\n}\n","import { css } from 'lit';\n\nexport const carouselStyles = css`\n :host {\n display: block;\n position: relative;\n color: var(--rc-carousel-color, CanvasText);\n color-scheme: inherit;\n }\n\n #track {\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--rc-carousel-slide-size, calc(100% - 4rem));\n column-gap: var(--rc-carousel-gap, 8px);\n inline-size: 100%;\n block-size: 100%;\n /*\n * Slides run along the inline axis, so the track scrolls and snaps along\n * it: horizontally in horizontal text, vertically in vertical text. The\n * physical declarations are a fallback for engines without the logical\n * overflow properties.\n */\n overflow-x: auto;\n overflow-y: hidden;\n overflow-inline: auto;\n overflow-block: hidden;\n overscroll-behavior-inline: contain;\n scroll-snap-type: inline mandatory;\n /*\n * Deliberately no \\`scroll-behavior: smooth\\` here — _scrollToIndex in\n * rc-carousel.ts passes \\`behavior: 'smooth'\\` explicitly per\n * programmatic call instead, which is unaffected either way (an\n * explicit argument always overrides this CSS default). Setting it\n * here as an ambient default would also apply to the browser's own\n * native snap-settle correction after a swipe — a documented\n * cross-browser conflict with scroll-snap-stop: always (each\n * rc-carousel-item sets that; Firefox bugzilla 1643217, 1959811)\n * that produces a jerk-then-snap-back artifact on an ordinary swipe.\n */\n scrollbar-width: none;\n }\n\n #track::-webkit-scrollbar {\n display: none;\n }\n\n :host([mouse-dragging]) #track {\n cursor: grab;\n }\n\n :host([mouse-dragging]) #track.dragging {\n cursor: grabbing;\n /*\n * scroll-snap-type itself is toggled imperatively in rc-carousel.ts,\n * not here — it must be off before the very first scrollLeft write of\n * a drag, and this class only lands on the next reactive render, a\n * render pass too late for that first write (the browser eagerly\n * resnaps a plain scrollLeft assignment right back to the nearest\n * snap point, same as any other programmatic scroll).\n */\n }\n\n #navigation {\n display: contents;\n }\n\n [part~='navigation-button'] {\n position: absolute;\n top: 50%;\n translate: 0 -50%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--rc-carousel-navigation-button-size, 40px);\n block-size: var(--rc-carousel-navigation-button-size, 40px);\n border: none;\n border-radius: 50%;\n background: var(\n --rc-carousel-navigation-button-background,\n color-mix(in srgb, CanvasText 12%, transparent)\n );\n color: var(--rc-carousel-navigation-button-color, CanvasText);\n cursor: pointer;\n }\n\n [part~='navigation-button'][aria-disabled='true'] {\n opacity: 0.38;\n cursor: default;\n }\n\n [part~='navigation-button-previous'] {\n inset-inline-start: var(--rc-carousel-navigation-inset, 8px);\n }\n\n [part~='navigation-button-next'] {\n inset-inline-end: var(--rc-carousel-navigation-inset, 8px);\n }\n\n #pagination {\n position: absolute;\n inset-block-end: var(--rc-carousel-navigation-inset, 8px);\n inset-inline: 0;\n display: flex;\n justify-content: center;\n gap: var(--rc-carousel-gap, 8px);\n }\n\n [part~='pagination-item'] {\n inline-size: var(--rc-carousel-pagination-item-size, 8px);\n block-size: var(--rc-carousel-pagination-item-size, 8px);\n padding: 0;\n border: none;\n border-radius: 50%;\n background: var(\n --rc-carousel-pagination-item-color,\n color-mix(in srgb, CanvasText 40%, transparent)\n );\n cursor: pointer;\n }\n\n [part~='pagination-item-active'] {\n background: var(--rc-carousel-pagination-item-active-color, Highlight);\n cursor: default;\n }\n\n /*\n * The built-in chevrons point toward the previous and next slide, which\n * swap sides in RTL. Slotted replacement icons are the consumer's to mirror\n * or not, since not every icon is directional.\n */\n :host(:dir(rtl)) [part~='navigation-button'] svg {\n transform: scaleX(-1);\n }\n`;\n\nexport default carouselStyles;\n","import { LitElement, html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\n\nimport {\n DragGestureController,\n findExtremeSnapIndex,\n findNearestSnapIndex,\n findNextSnapIndex,\n HORIZONTAL_LTR_FLOW,\n MessagesController,\n RafScheduler,\n clientSize,\n getScrollOffset,\n keyNavigation,\n logicalDelta,\n numberFormat,\n physicalAxis,\n resolveFlow,\n setScrollOffset,\n syncDefaultAttribute,\n warnMissingDirectChild,\n type DragGestureDetail,\n type Flow,\n type KeyboardNavigationAction,\n} from '@rcarls/rc-common';\nimport type { RCCarouselItem } from './rc-carousel-item.js';\n\nimport carouselStyles from './rc-carousel.styles.js';\n\n/** Release velocity (px/s) past which a mouse-drag release is treated as a\n * decisive swipe (advance one further slide) rather than settling to the\n * nearest snap point. */\nconst DECISIVE_DRAG_VELOCITY = 300;\n\n/** Built-in text of `rc-carousel` and its slides. Positions are 1-based. */\nexport interface RCCarouselMessages {\n /** `aria-roledescription` of the carousel. */\n carousel: string;\n /** `aria-roledescription` of each slide. */\n slide: string;\n /** Default accessible name of each slide. */\n position: (position: number, count: number, locale?: string) => string;\n previous: string;\n next: string;\n /** Accessible name of the slide-picker group. */\n picker: string;\n /** Accessible name of each slide-picker button. */\n goToSlide: (position: number, count: number, locale?: string) => string;\n}\n\nexport const DEFAULT_CAROUSEL_MESSAGES: Readonly<RCCarouselMessages> = Object.freeze({\n carousel: 'carousel',\n slide: 'slide',\n position: (position: number, count: number, locale?: string) => {\n const format = numberFormat(locale, { useGrouping: false });\n\n return `${format.format(position)} of ${format.format(count)}`;\n },\n previous: 'Previous slide',\n next: 'Next slide',\n picker: 'Choose slide to display',\n goToSlide: (position: number, _count: number, locale?: string) =>\n `Go to slide ${numberFormat(locale, { useGrouping: false }).format(position)}`,\n});\n\ndeclare module '@rcarls/rc-common' {\n interface RcMessageCatalog {\n 'rc-carousel': RCCarouselMessages;\n }\n}\n\nexport type RCCarouselChangeTrigger = 'api' | 'button' | 'keyboard' | 'swipe';\n\nexport interface RCCarouselChangeDetail {\n index: number;\n trigger: RCCarouselChangeTrigger;\n}\n\ninterface TrackMeasurement {\n track: HTMLDivElement;\n flow: Flow;\n step: number;\n}\n\ninterface InitialPositionSample extends TrackMeasurement {\n offset: number;\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n 'rc-carousel-change': CustomEvent<RCCarouselChangeDetail>;\n }\n interface HTMLElementTagNameMap {\n 'rc-carousel': RCCarousel;\n }\n}\n\nconst SETTLE_DEBOUNCE_MS = 120;\n\n/**\n * WAI-ARIA APG carousel pattern built on native CSS scroll-snap. One\n * `rc-carousel-item` per slide, swiped or paged between; the track's own\n * native scroll-snap settling (not a hand-rolled drag simulation) is the\n * primary interaction, per this monorepo's \"build on native browser\n * behavior\" principle.\n *\n * `activeIndex` is a controlled/uncontrolled property, mirroring\n * `rc-adaptive-menu`'s `open`/`defaultOpen` pair: leave it unset for\n * uncontrolled usage (`default-active-index` seeds the initial slide),\n * or set it directly to drive the carousel externally — a settle from\n * swipe, a keyboard action, or the imperative API all report back through\n * `rc-carousel-change` rather than silently self-correcting a controlled\n * value out from under the consumer.\n *\n * Previous/next navigation and a slide picker are both opt-in\n * (`navigation`/`pagination`), following the WAI-ARIA APG carousel\n * pattern's \"grouped\" (non-tab) picker style deliberately: the tabbed\n * `role=\"tabpanel\"` variant requires cross-references between light-DOM\n * slides and shadow-DOM tab buttons that, in comparable shadow-DOM\n * carousels, has hit real accessibility-tooling failures across the\n * shadow boundary (including non-recognition by some screen readers\n * entirely). `loop` wraps seamlessly via cloned lead/trail slides rather\n * than a discontinuous jump back to the other end.\n *\n * @slot - One or more `rc-carousel-item` elements.\n * @slot previous-icon - Optional icon for the previous button, replacing\n * the default chevron. Only rendered when `navigation` is set.\n * @slot next-icon - Optional icon for the next button, replacing the\n * default chevron. Only rendered when `navigation` is set.\n *\n * @fires rc-carousel-change - Fires when the active slide changes, from a\n * swipe settling, a keyboard action, or the imperative API.\n * `detail: { index, trigger: 'swipe'|'button'|'keyboard'|'api' }`\n *\n * @attr active-index - Controls the active slide. Host writes are silent —\n * listen for `rc-carousel-change` to stay in sync.\n * @attr default-active-index - Initial active slide for uncontrolled usage.\n * @attr loop - Wraps past the first/last slide back to the other end,\n * seamlessly (via cloned lead/trail slides), for swipe, buttons, and\n * keyboard alike. Off by default: the ends are real boundaries, not a\n * loop, unless a consumer opts in.\n * @attr navigation - Shows previous/next buttons.\n * @attr pagination - Shows a slide-picker button group.\n * @attr mouse-dragging - Enables click-and-drag scrolling with a mouse.\n * Touch/pen already get native scroll-snap physics; off by default.\n *\n * Built-in text (button names, role descriptions, slide positions) follows\n * the element's own `lang`, else `<html lang>`: per element through\n * `messages`, or for every carousel through `registerMessages()` from\n * `@rcarls/rc-common` under `rc-carousel`.\n *\n * @cssprop [--rc-carousel-color=CanvasText] - Carousel foreground color.\n * @cssprop [--rc-carousel-gap=8px] - Space between slides.\n * @cssprop [--rc-carousel-slide-size=calc(100% - 4rem)] - Rendered size of\n * each slide along the scroll axis. Set this directly or from a consumer\n * container query to coordinate hero and multi-browse layouts.\n * @cssprop [--rc-carousel-navigation-button-size=40px] - Previous/next\n * button diameter.\n * @cssprop [--rc-carousel-navigation-button-background=color-mix(in srgb, CanvasText 12%, transparent)] -\n * Previous/next button background.\n * @cssprop [--rc-carousel-navigation-button-color=CanvasText] -\n * Previous/next button icon color.\n * @cssprop [--rc-carousel-navigation-inset=8px] - Previous/next button\n * inset from the track edge.\n * @cssprop [--rc-carousel-pagination-item-size=8px] - Slide-picker dot\n * diameter.\n * @cssprop [--rc-carousel-pagination-item-color=color-mix(in srgb, CanvasText 40%, transparent)] -\n * Inactive slide-picker dot color.\n * @cssprop [--rc-carousel-pagination-item-active-color=Highlight] - Active\n * slide-picker dot color.\n *\n * @csspart track - The scrollable slide track.\n * @csspart navigation - Previous/next button wrapper.\n * @csspart navigation-button - A previous or next button.\n * @csspart navigation-button-previous - The previous button specifically.\n * @csspart navigation-button-next - The next button specifically.\n * @csspart pagination - Slide-picker button group wrapper.\n * @csspart pagination-item - A slide-picker button.\n * @csspart pagination-item-active - The active slide's picker button.\n *\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/carousel/ WAI-ARIA APG Carousel pattern}\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-carousel rc-carousel documentation}\n */\nexport class RCCarousel extends LitElement {\n static override styles = carouselStyles;\n\n private readonly _internals: ElementInternals;\n\n @query('#track') private _trackEl?: HTMLDivElement;\n @query('slot:not([name])') private _slotEl?: HTMLSlotElement;\n\n // Seeded from direct children during connection so the first render can\n // build pagination without changing reactive state from firstUpdated().\n private _items: RCCarouselItem[] = [];\n private _cloneItems: RCCarouselItem[] = [];\n private _mounted = false;\n private _suppressSync = false;\n private _pendingInstant = false;\n private _settleTimer: ReturnType<typeof setTimeout> | undefined;\n private readonly _initialPosition = new RafScheduler(this);\n private _writtenRoleDescription: string | null = null;\n\n private readonly _messages = new MessagesController(\n this,\n 'rc-carousel',\n DEFAULT_CAROUSEL_MESSAGES,\n {\n overrides: () => this.messages,\n },\n );\n\n /** Built-in text overrides; unset keys fall back to registered text, then English. */\n @property({ attribute: false })\n messages: Partial<RCCarouselMessages> | undefined;\n\n /** Wraps past the first/last slide back to the other end, seamlessly. */\n @property({ type: Boolean, reflect: true })\n loop = false;\n\n /** Shows previous/next buttons. */\n @property({ type: Boolean, reflect: true })\n navigation = false;\n\n /** Shows a slide-picker button group. */\n @property({ type: Boolean, reflect: true })\n pagination = false;\n\n /**\n * Enables click-and-drag scrolling with a mouse — native scroll-snap\n * touch physics already cover touch/pen, but a mouse has no built-in\n * equivalent. Off by default.\n */\n @property({ type: Boolean, reflect: true, attribute: 'mouse-dragging' })\n mouseDragging = false;\n\n @state() private _dragging = false;\n\n /** Logical inline scroll offset of the track when the current drag began. */\n private _dragStartOffset = 0;\n\n /** Track flow, re-resolved at the start of each drag or scroll operation. */\n private _flow: Flow = HORIZONTAL_LTR_FLOW;\n\n private _dragAxis: 'x' | 'y' = 'x';\n private _suppressNextClick = false;\n\n /**\n * Drives the track's scroll offset directly from pointer deltas while `mouseDragging`\n * is on. `activation: 'axis'` (not `'immediate'`) means a plain click\n * never activates a drag at all — it requires clearing\n * `activationDistance` (8px) of movement first — but a *real* drag still\n * ends in a native `click` on release, on whatever's under the pointer,\n * which `_suppressNextClick` swallows so dragging across an unrelated\n * link or button inside a slide doesn't activate it (the same edge case\n * Shoelace's own `sl-carousel` handles for exactly this reason).\n */\n protected readonly _dragController = new DragGestureController(this, {\n target: () => this._trackEl ?? null,\n axis: 'x',\n activation: 'axis',\n canStart: (event) => {\n if (!this.mouseDragging || event.pointerType !== 'mouse') {\n return false;\n }\n\n // Resolve on pointerdown, before the controller picks the drag axis\n // from the first moves; the flow then holds for the whole gesture.\n this._resolveFlow();\n\n return true;\n },\n onStart: () => {\n this._dragging = true;\n this._dragStartOffset = this._trackOffset();\n this._suppressNextClick = true;\n\n // Imperative, not reactive-class-driven: this must land before\n // onMove's very first scroll offset write below, and a Lit re-render\n // (triggered by _dragging above) is a whole render pass too late for\n // that — with scroll-snap-type still active, the browser eagerly\n // resnaps a plain scroll offset assignment straight back to the\n // nearest snap point, same as it would any other programmatic\n // scroll with no notion this is \"mid-gesture\".\n if (this._trackEl) {\n this._trackEl.style.scrollSnapType = 'none';\n }\n },\n onMove: (detail) => {\n // Dragging toward the inline end drags content with it, which scrolls\n // back toward the start, hence the subtraction. Projecting through the\n // flow makes that hold in RTL and in vertical writing modes.\n this._setTrackOffset(\n this._dragStartOffset -\n logicalDelta({ dx: detail.deltaX, dy: detail.deltaY }, 'inline', this._flow),\n );\n },\n onEnd: (detail) => this._endDrag(detail),\n onCancel: (detail) => this._endDrag(detail),\n });\n\n @state() private _busy = false;\n\n private _activeIndex: number | undefined;\n private _defaultActiveIndex = 0;\n private _uncontrolledActiveIndex: number | undefined;\n private _activeIndexInitialized = false;\n\n /** Controls the active slide. Host writes are silent. */\n @property({ type: Number, attribute: 'active-index' })\n get activeIndex(): number {\n return this._clampIndex(\n this._activeIndex ?? this._uncontrolledActiveIndex ?? this._defaultActiveIndex,\n );\n }\n\n set activeIndex(value: number | undefined) {\n const oldValue = this.activeIndex;\n\n this._activeIndex = value;\n this._activeIndexInitialized = true;\n this.requestUpdate('activeIndex', oldValue);\n }\n\n /** Initial active slide for uncontrolled usage. */\n @property({ type: Number, attribute: 'default-active-index' })\n get defaultActiveIndex(): number {\n return this._defaultActiveIndex;\n }\n\n set defaultActiveIndex(value: number) {\n const oldValue = this._defaultActiveIndex;\n\n this._defaultActiveIndex = value;\n\n if (\n !this._activeIndexInitialized &&\n this._activeIndex === undefined &&\n this._uncontrolledActiveIndex === undefined\n ) {\n this.requestUpdate('activeIndex', oldValue);\n }\n\n this.requestUpdate('defaultActiveIndex', oldValue);\n }\n\n /**\n * The scroll-snap track element. Internal integration point consumed by\n * `rc-carousel-item`'s IntersectionObserver (its `root` must be this\n * track, not the viewport, so peeking/clipped-but-viewport-visible\n * slides are still correctly detected as off-screen) — not a public API.\n */\n get trackElement(): HTMLElement | null {\n return this._trackEl ?? null;\n }\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n this._internals.role = 'group';\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n this._items = this._directItems();\n this._setItemPositions();\n\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'group');\n }\n\n this._syncText();\n\n if (this.hasUpdated && !this._mounted) {\n this._queueInitialPosition();\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n if (this._settleTimer !== undefined) {\n clearTimeout(this._settleTimer);\n }\n }\n\n protected override firstUpdated(): void {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > rc-carousel-item',\n childDescription: '<rc-carousel-item> elements',\n });\n\n if (!this.hasAttribute('aria-label') && !this.hasAttribute('aria-labelledby')) {\n console.warn(\n \"[rc-carousel] No aria-label/aria-labelledby set. Provide one describing this carousel's content.\",\n );\n }\n }\n\n this._syncActiveItemAccessibility(this.activeIndex);\n this._queueInitialPosition();\n }\n\n protected override updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n this._syncText();\n\n this._initPaginationTabIndex();\n\n if (changed.has('loop') && this._mounted) {\n // Live toggle: _syncItems is idempotent (see its own comment) when\n // clone presence already matches, so this is cheap to call even when\n // nothing actually needs to change.\n this._syncItems();\n }\n\n if (!changed.has('activeIndex')) {\n return;\n }\n\n this._syncActiveItemAccessibility(this.activeIndex);\n\n if (!this._mounted) {\n this._queueInitialPosition();\n\n return;\n }\n\n if (this._suppressSync) {\n this._suppressSync = false;\n\n return;\n }\n\n const instant = !this._mounted || this._pendingInstant;\n\n this._pendingInstant = false;\n this._scrollToIndex(this.activeIndex, instant);\n }\n\n /** Moves to the next slide. */\n next(): void {\n this._step(1, 'api');\n }\n\n /** Moves to the previous slide. */\n previous(): void {\n this._step(-1, 'api');\n }\n\n /** Moves directly to a slide index. */\n goToIndex(index: number, instant = false): void {\n this._pendingInstant = instant;\n this._setActiveIndex(index, 'api');\n }\n\n private _step(delta: 1 | -1, trigger: RCCarouselChangeTrigger): void {\n this._setActiveIndex(this.activeIndex + delta, trigger);\n }\n\n /** Whether a previous/next button (or an equivalent keyboard action)\n * currently has anywhere to go — always true when `loop` is set and\n * there's more than one slide. */\n private _canStep(delta: 1 | -1): boolean {\n const count = this._items.length;\n\n if (count <= 1) {\n return false;\n }\n\n if (this.loop) {\n return true;\n }\n\n return delta > 0 ? this.activeIndex < count - 1 : this.activeIndex > 0;\n }\n\n /**\n * Wraps when `loop` is set, otherwise clamps to the real slide range.\n * Wrapping here covers button/keyboard navigation; a swipe wraps\n * seamlessly through `_trackSlots`'s cloned lead/trail slides instead,\n * since that needs the clones' own track positions, not just an index.\n */\n private _clampIndex(index: number): number {\n const count = this._items.length;\n\n if (count === 0) {\n return 0;\n }\n\n if (this.loop) {\n return ((index % count) + count) % count;\n }\n\n return Math.min(count - 1, Math.max(0, index));\n }\n\n private _snapPoints(): number[] {\n const step = this._itemStep();\n\n return this._items.map((_item, index) => index * step);\n }\n\n /**\n * Every scrollable track position in rendered order, including cloned\n * lead/trail slides when `loop` is on — `[lastClone, item0, ..., itemN-1,\n * firstClone]`. Each slot reports which real slide index it represents\n * (a clone mirrors the real slide it duplicates), so both scrolling to\n * an index and reading back a settled scroll position can stay in terms\n * of real indices while the clones do the seamless-wrap work.\n */\n private _trackSlots(\n step = this._itemStep(),\n ): { point: number; index: number; isClone: boolean }[] {\n const count = this._items.length;\n\n if (!this.loop || count < 2) {\n return this._items.map((_item, index) => ({ point: index * step, index, isClone: false }));\n }\n\n return [\n { point: 0, index: count - 1, isClone: true },\n ...this._items.map((_item, index) => ({ point: (index + 1) * step, index, isClone: false })),\n { point: (count + 1) * step, index: 0, isClone: true },\n ];\n }\n\n private _itemStep(): number {\n const measurement = this._measureTrack();\n\n if (!measurement) {\n return 1;\n }\n\n this._applyFlow(measurement.flow);\n\n return measurement.step;\n }\n\n private _measureTrack(): TrackMeasurement | null {\n const track = this._trackEl;\n\n if (!track) {\n return null;\n }\n\n const first = this._items[0];\n const flow = resolveFlow(track);\n const step =\n first instanceof HTMLElement\n ? (flow.inline === 'x' ? first.offsetWidth : first.offsetHeight) +\n (Number.parseFloat(getComputedStyle(track).columnGap || '0') || 0)\n : clientSize(track, 'inline', flow);\n\n return { track, flow, step };\n }\n\n private _applyFlow(flow: Flow): void {\n this._flow = flow;\n\n const axis = physicalAxis('inline', flow);\n\n // Never rebind mid-gesture; the next drag picks the new axis up.\n if (!this._dragging && axis !== this._dragAxis) {\n this._dragAxis = axis;\n this._dragController.setOptions({ axis });\n }\n }\n\n /**\n * Re-reads the track's writing mode and direction. Called at the start of\n * each scroll operation and on each drag's pointerdown rather than cached\n * for the element's life, since neither a `dir` nor a writing-mode change\n * on an ancestor fires an event. The drag gesture's physical axis follows,\n * so a carousel in vertical text drags vertically.\n */\n private _resolveFlow(): Flow {\n if (!this._trackEl) {\n return this._flow;\n }\n\n this._applyFlow(resolveFlow(this._trackEl));\n\n return this._flow;\n }\n\n /** Scroll distance from the track's logical start, never negative. */\n private _trackOffset(): number {\n return this._trackEl ? getScrollOffset(this._trackEl, 'inline', this._flow) : 0;\n }\n\n private _setTrackOffset(offset: number, behavior: ScrollBehavior = 'auto'): void {\n if (this._trackEl) {\n setScrollOffset(this._trackEl, 'inline', offset, this._flow, behavior);\n }\n }\n\n private _setActiveIndex(index: number, trigger: RCCarouselChangeTrigger): void {\n const clamped = this._clampIndex(index);\n const oldValue = this.activeIndex;\n\n if (oldValue === clamped) {\n return;\n }\n\n // Controlled usage (activeIndex currently has a host-owned value)\n // never self-writes here — only the consumer's own activeIndex setter\n // may change it, in response to the event dispatched below. Only\n // genuinely uncontrolled usage updates its own backing state directly.\n if (this._activeIndex === undefined) {\n this._uncontrolledActiveIndex = clamped;\n this.requestUpdate('activeIndex', oldValue);\n }\n\n this.dispatchEvent(\n new CustomEvent<RCCarouselChangeDetail>('rc-carousel-change', {\n bubbles: true,\n composed: true,\n detail: { index: clamped, trigger },\n }),\n );\n }\n\n private _scrollToIndex(index: number, instant: boolean): void {\n if (!this._trackEl) {\n return;\n }\n\n const slot = this._trackSlots().find((s) => !s.isClone && s.index === index);\n const offset = slot ? slot.point : index * this._itemStep();\n const reducedMotion =\n this.ownerDocument.defaultView?.matchMedia('(prefers-reduced-motion: reduce)').matches ??\n false;\n\n // Explicit per call, not an ambient CSS default — see the comment on\n // #track in rc-carousel.styles.ts.\n this._setTrackOffset(offset, instant || reducedMotion ? 'auto' : 'smooth');\n }\n\n private _queueInitialPosition(): void {\n this._initialPosition.schedulePhased(\n () => this._sampleInitialPosition(),\n (sample) => this._applyInitialPosition(sample),\n );\n }\n\n private _sampleInitialPosition(): InitialPositionSample | null {\n const measurement = this._measureTrack();\n\n if (!measurement) {\n return null;\n }\n\n const slot = this._trackSlots(measurement.step).find(\n (candidate) => !candidate.isClone && candidate.index === this.activeIndex,\n );\n\n return {\n ...measurement,\n offset: slot ? slot.point : this.activeIndex * measurement.step,\n };\n }\n\n private _applyInitialPosition(sample: InitialPositionSample | null): void {\n if (!sample || !this.isConnected || this._trackEl !== sample.track) {\n return;\n }\n\n this._applyFlow(sample.flow);\n setScrollOffset(sample.track, 'inline', sample.offset, sample.flow, 'auto');\n this._mounted = true;\n }\n\n /**\n * Keep the authored active slide available to assistive technology even\n * before a programmatic scroll produces its next intersection callback.\n * IntersectionObserver still takes over during direct manipulation, where\n * the visually dominant slide can change before scroll settling updates the\n * public active index.\n */\n private _syncActiveItemAccessibility(index: number): void {\n this._directItems().forEach((item, itemIndex) => {\n const hidden = itemIndex !== index;\n\n item.toggleAttribute('aria-hidden', hidden);\n item.toggleAttribute('inert', hidden);\n });\n }\n\n private _onSlotChange = (): void => {\n this._syncItems();\n };\n\n private _directItems(): RCCarouselItem[] {\n return Array.from(this.children).filter(\n (el): el is RCCarouselItem =>\n el.tagName === 'RC-CAROUSEL-ITEM' && !el.hasAttribute('data-clone'),\n );\n }\n\n private _setItemPositions(): void {\n const messages = this._messages.value;\n\n this._items.forEach((item, index) => {\n item.position = messages.position(index + 1, this._items.length, this._messages.locale);\n item.roleDescription = messages.slide;\n });\n }\n\n /** Re-applies text written outside the template, for a new locale or `messages`. */\n private _syncText(): void {\n this._writtenRoleDescription = syncDefaultAttribute(\n this,\n 'aria-roledescription',\n this._messages.value.carousel,\n this._writtenRoleDescription,\n );\n\n this._setItemPositions();\n }\n\n /**\n * Prepending/appending the loop clones below is itself a light-DOM\n * mutation on this host, which re-fires `slotchange` (asynchronously) —\n * `_onSlotChange` calls back into this method, so a naive unconditional\n * remove-then-recreate would recreate a fresh pair of clones on every\n * pass forever. Clones are always excluded from `nextItems`, so the\n * real item list is byte-for-byte identical on that re-entrant pass;\n * only rebuild clone DOM when either the real items or the desired\n * clone presence has actually changed, so the re-entrant pass is a\n * true no-op and the recursion terminates.\n */\n private _syncItems(): void {\n const assigned = this._slotEl?.assignedElements() ?? [];\n const nextItems = assigned.filter(\n (el): el is RCCarouselItem =>\n el.tagName === 'RC-CAROUSEL-ITEM' && !el.hasAttribute('data-clone'),\n );\n const itemsChanged =\n nextItems.length !== this._items.length ||\n nextItems.some((item, index) => item !== this._items[index]);\n const wantsClones = this.loop && nextItems.length > 1;\n const hasClones = this._cloneItems.length > 0;\n\n this._items = nextItems;\n this._setItemPositions();\n\n if (itemsChanged && this._mounted) {\n this.requestUpdate();\n }\n\n if (!itemsChanged && wantsClones === hasClones) {\n return;\n }\n\n this._removeClones();\n\n if (wantsClones) {\n this._addClones();\n }\n }\n\n /**\n * Clones the first and last slide and prepends/appends them\n * (`data-clone=\"<real index>\"` marks them, excluded from `_items` and\n * from position numbering) so the track has real scrollable content\n * past both visual ends. `_trackSlots`/`_commitSettledIndex` detect\n * when a clone settles and instantly re-anchor to the real slide it\n * mirrors — Shoelace's proven technique for a seamless infinite swipe,\n * rather than a discontinuous index-modulo jump back to the other end.\n */\n private _addClones(): void {\n const first = this._items[0];\n const last = this._items[this._items.length - 1];\n\n if (!first || !last) {\n return;\n }\n\n const leadingClone = last.cloneNode(true) as RCCarouselItem;\n\n leadingClone.setAttribute('data-clone', String(this._items.length - 1));\n this._sanitizeClone(leadingClone);\n this.prepend(leadingClone);\n\n const trailingClone = first.cloneNode(true) as RCCarouselItem;\n\n trailingClone.setAttribute('data-clone', '0');\n this._sanitizeClone(trailingClone);\n this.append(trailingClone);\n\n this._cloneItems = [leadingClone, trailingClone];\n }\n\n /** Keeps visual loop clones out of forms, focus order, and the accessibility tree. */\n private _sanitizeClone($clone: RCCarouselItem): void {\n $clone.setAttribute('aria-hidden', 'true');\n $clone.setAttribute('inert', '');\n\n for (const $element of [$clone, ...$clone.querySelectorAll<HTMLElement>('*')]) {\n $element.removeAttribute('id');\n $element.removeAttribute('name');\n $element.removeAttribute('form');\n }\n }\n\n private _removeClones(): void {\n this._cloneItems.forEach((clone) => clone.remove());\n this._cloneItems = [];\n }\n\n /**\n * On release, a fast enough flick pre-nudges the scroll offset to the next\n * snap point in the drag direction (a \"decisive swipe\" — mirroring\n * `rc-bottom-sheet`'s own velocity-vs-nearest-point settle heuristic,\n * adapted from \"jump to the extreme end\" for a 2-point sheet to \"advance\n * one further point\" for a carousel that can have many). Either way,\n * this hands off to the same debounced settle path a native swipe\n * already goes through — our own scroll offset writes during the drag\n * already fired real `scroll` events, so `_onScroll` just needs to run\n * its usual timer to pick up wherever things ended.\n */\n private _endDrag(detail: DragGestureDetail): void {\n this._dragging = false;\n\n if (this._trackEl) {\n this._trackEl.style.scrollSnapType = '';\n }\n\n const velocity = logicalDelta(\n { dx: detail.velocityX, dy: detail.velocityY },\n 'inline',\n this._flow,\n );\n\n if (this._trackEl && Math.abs(velocity) > DECISIVE_DRAG_VELOCITY) {\n const slots = this._trackSlots();\n // Flicking toward the inline start moves content toward the start,\n // i.e. advances forward — toward higher track points.\n const direction = velocity < 0 ? 1 : -1;\n const targetSlotIndex = findNextSnapIndex(\n slots.map((slot) => slot.point),\n this._trackOffset(),\n direction,\n );\n const targetSlot = slots[targetSlotIndex];\n\n if (targetSlot) {\n this._setTrackOffset(targetSlot.point);\n }\n }\n\n this._onScroll();\n }\n\n /**\n * Debounced, not per-frame: `_scrollToIndex`'s own smooth scroll fires\n * many `scroll` events while still mid-flight, and reading the settled\n * index from an in-progress position would report the wrong slide and\n * immediately fight the very scroll driving it. Waiting for scrolling to\n * actually stop (swipe release or animation end) avoids that oscillation.\n */\n private _onScroll = (): void => {\n if (this._settleTimer !== undefined) {\n clearTimeout(this._settleTimer);\n }\n\n this._busy = true;\n this._settleTimer = setTimeout(this._commitSettledIndex, SETTLE_DEBOUNCE_MS);\n };\n\n private _commitSettledIndex = (): void => {\n this._busy = false;\n\n if (!this._trackEl) {\n return;\n }\n\n const slots = this._trackSlots();\n const settledSlotIndex = findNearestSnapIndex(\n slots.map((slot) => slot.point),\n this._trackOffset(),\n );\n const settledSlot = settledSlotIndex >= 0 ? slots[settledSlotIndex] : undefined;\n\n if (!settledSlot) {\n return;\n }\n\n if (settledSlot.isClone) {\n // Seamless re-anchor: a clone settling means the user scrolled past\n // the real end. Instantly (no animation — this must be invisible)\n // correct to the real slide's own track position, which renders\n // identically to the clone at this scroll offset.\n const realSlot = slots.find((slot) => !slot.isClone && slot.index === settledSlot.index);\n\n if (realSlot) {\n this._setTrackOffset(realSlot.point);\n }\n }\n\n if (settledSlot.index === this.activeIndex) {\n // Already in sync (or the clone correction above just made it so) —\n // no prop change means `updated()` won't run at all, so there's no\n // echo to suppress here.\n return;\n }\n\n // Settling a user swipe reports the new index back up through the same\n // `activeIndex` prop the sync effect (`updated()`) watches. Replaying\n // that through `_scrollToIndex` would still fire a real, non-instant\n // `scrollTo`, not a no-op — if a genuine next swipe starts during that\n // echoed animation, it fights the swipe and can swallow it.\n // `_suppressSync` skips `updated()`'s scroll for exactly that one echo.\n const controlled = this._activeIndex !== undefined;\n\n if (!controlled) {\n this._suppressSync = true;\n }\n\n this._setActiveIndex(settledSlot.index, 'swipe');\n\n // A controlled consumer may reject the requested swipe by leaving the\n // property unchanged. Restore the visual position to the host-owned slide\n // instead of leaving scroll state and public state disagreeing.\n if (controlled && this.activeIndex !== settledSlot.index) {\n this._scrollToIndex(this.activeIndex, true);\n }\n };\n\n private _onNavigate = (action: KeyboardNavigationAction): void => {\n switch (action) {\n case 'next':\n this._step(1, 'keyboard');\n break;\n case 'prev':\n this._step(-1, 'keyboard');\n break;\n\n case 'start': {\n const index = findExtremeSnapIndex(this._snapPoints(), -1);\n\n if (index >= 0) {\n this._setActiveIndex(index, 'keyboard');\n }\n\n break;\n }\n\n case 'end': {\n const index = findExtremeSnapIndex(this._snapPoints(), 1);\n\n if (index >= 0) {\n this._setActiveIndex(index, 'keyboard');\n }\n\n break;\n }\n }\n };\n\n /**\n * A real drag still ends in a native `click` on release (browsers fire\n * one on pointerup as long as pointerdown/pointerup share a target),\n * landing on whatever's currently under the pointer — which, mid-drag,\n * is often unrelated slide content the user was scrolling past, not\n * clicking. Capturing and swallowing exactly one click right after a\n * drag activated (`_suppressNextClick`, set in the drag controller's\n * `onStart`) stops that from reaching a link/button inside a slide.\n */\n private _onTrackClickCapture = (event: MouseEvent): void => {\n if (!this._suppressNextClick) {\n return;\n }\n\n this._suppressNextClick = false;\n event.stopPropagation();\n event.preventDefault();\n };\n\n private _paginationButtons(): HTMLButtonElement[] {\n return Array.from(\n this.shadowRoot?.querySelectorAll<HTMLButtonElement>('[data-pagination-item]') ?? [],\n );\n }\n\n /**\n * Hand-rolled roving tabindex for the pagination row, not\n * `RovingTabIndexMixin`: that mixin collects items from a real\n * `slotchange`-firing `<slot>`, matching its intended use (consumer-\n * authored, slotted content, like `rc-toolbar`'s buttons) — these\n * buttons are shadow-DOM content this component renders itself, so\n * there's no slot to collect from. The pattern is otherwise the same\n * one the mixin itself implements: exactly one button is a tab stop,\n * arrow keys move focus among them (not activeIndex — matching\n * rc-toolbar's own \"arrows move focus, Enter/Space activates\" model,\n * not a tablist's auto-activate-on-arrow), and focus keeps tabindex in\n * sync wherever it lands (click, Tab, or a `.focus()` call below).\n */\n private _onPaginationFocus = (event: FocusEvent): void => {\n const buttons = this._paginationButtons();\n const target = event.composedPath().find((el) => buttons.includes(el as HTMLButtonElement)) as\n | HTMLButtonElement\n | undefined;\n\n if (!target) {\n return;\n }\n\n buttons.forEach((button) => button.setAttribute('tabindex', button === target ? '0' : '-1'));\n };\n\n private _onPaginationNavigate = (action: KeyboardNavigationAction): void => {\n const buttons = this._paginationButtons();\n\n if (!buttons.length) {\n return;\n }\n\n const current = buttons.indexOf(this.shadowRoot?.activeElement as HTMLButtonElement);\n const from = current < 0 ? 0 : current;\n\n switch (action) {\n case 'next':\n buttons[(from + 1) % buttons.length]?.focus();\n break;\n case 'prev':\n buttons[(from - 1 + buttons.length) % buttons.length]?.focus();\n break;\n case 'start':\n buttons[0]?.focus();\n break;\n case 'end':\n buttons[buttons.length - 1]?.focus();\n break;\n }\n };\n\n /**\n * One-time tabindex seed for pagination buttons that have never\n * received focus yet (matching `activeIndex`, the sane default) —\n * `_onPaginationFocus` takes over from there. Safe to call on every\n * render: a no-op once every button already has some tabindex value.\n */\n private _initPaginationTabIndex(): void {\n this._paginationButtons().forEach((button, index) => {\n if (!button.hasAttribute('tabindex')) {\n button.setAttribute('tabindex', index === this.activeIndex ? '0' : '-1');\n }\n });\n }\n\n protected override render() {\n const canPrev = this._canStep(-1);\n const canNext = this._canStep(1);\n const messages = this._messages.value;\n\n return html`\n <div\n id=\"track\"\n part=\"track\"\n tabindex=\"0\"\n class=${this._dragging ? 'dragging' : nothing}\n aria-busy=${this._busy ? 'true' : 'false'}\n aria-atomic=\"true\"\n @scroll=${this._onScroll}\n @click=${{ handleEvent: this._onTrackClickCapture, capture: true }}\n ${keyNavigation(this._onNavigate, { navigationAxis: 'horizontal' })}\n >\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n\n ${this.navigation\n ? html`\n <div id=\"navigation\" part=\"navigation\">\n <button\n type=\"button\"\n part=\"navigation-button navigation-button-previous\"\n aria-label=${messages.previous}\n aria-disabled=${canPrev ? 'false' : 'true'}\n @click=${() => {\n if (canPrev) {\n this._step(-1, 'button');\n }\n }}\n >\n <span aria-hidden=\"true\">\n <slot name=\"previous-icon\">\n <svg\n viewBox=\"0 0 6 10\"\n width=\"10\"\n height=\"16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"5,1 1,5 5,9\" />\n </svg>\n </slot>\n </span>\n </button>\n <button\n type=\"button\"\n part=\"navigation-button navigation-button-next\"\n aria-label=${messages.next}\n aria-disabled=${canNext ? 'false' : 'true'}\n @click=${() => {\n if (canNext) {\n this._step(1, 'button');\n }\n }}\n >\n <span aria-hidden=\"true\">\n <slot name=\"next-icon\">\n <svg\n viewBox=\"0 0 6 10\"\n width=\"10\"\n height=\"16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"1,1 5,5 1,9\" />\n </svg>\n </slot>\n </span>\n </button>\n </div>\n `\n : nothing}\n ${this.pagination\n ? html`\n <div\n id=\"pagination\"\n part=\"pagination\"\n role=\"group\"\n aria-label=${messages.picker}\n @focusin=${this._onPaginationFocus}\n ${keyNavigation(this._onPaginationNavigate, { navigationAxis: 'horizontal' })}\n >\n ${this._items.map(\n (_item, index) => html`\n <button\n type=\"button\"\n data-pagination-item\n part=\"pagination-item${index === this.activeIndex\n ? ' pagination-item-active'\n : ''}\"\n aria-label=${messages.goToSlide(\n index + 1,\n this._items.length,\n this._messages.locale,\n )}\n aria-current=${index === this.activeIndex ? 'true' : 'false'}\n aria-disabled=${index === this.activeIndex ? 'true' : 'false'}\n @click=${() => this._setActiveIndex(index, 'button')}\n ></button>\n `,\n )}\n </div>\n `\n : nothing}\n `;\n }\n}\n"],"names":["carouselItemStyles","css","_RCCarouselItem","LitElement","changed","syncDefaultAttribute","$carousel","$root","entry","hidden","html","RCCarouselItem","__decorateClass","property","carouselStyles","DECISIVE_DRAG_VELOCITY","DEFAULT_CAROUSEL_MESSAGES","position","count","locale","format","numberFormat","_count","SETTLE_DEBOUNCE_MS","_RCCarousel","RafScheduler","MessagesController","HORIZONTAL_LTR_FLOW","DragGestureController","event","detail","logicalDelta","slots","settledSlotIndex","findNearestSnapIndex","slot","settledSlot","realSlot","controlled","action","index","findExtremeSnapIndex","buttons","target","el","button","current","from","value","oldValue","instant","delta","trigger","step","_item","measurement","track","first","flow","resolveFlow","clientSize","axis","physicalAxis","getScrollOffset","offset","behavior","setScrollOffset","clamped","s","reducedMotion","sample","candidate","item","itemIndex","messages","nextItems","itemsChanged","wantsClones","hasClones","last","leadingClone","trailingClone","$clone","$element","clone","velocity","direction","targetSlotIndex","findNextSnapIndex","targetSlot","canPrev","canNext","nothing","keyNavigation","RCCarousel","query","state"],"mappings":"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"}
@@ -1,7 +1,9 @@
1
- import { a as e, R as s } from "./rc-carousel-CdDEH9fb.js";
1
+ import { a as e, R as s } from "./rc-carousel-CGHUVDLI.js";
2
+ import { D as m } from "./rc-carousel-CGHUVDLI.js";
2
3
  customElements.get("rc-carousel-item") || customElements.define("rc-carousel-item", e);
3
4
  customElements.get("rc-carousel") || customElements.define("rc-carousel", s);
4
5
  export {
6
+ m as DEFAULT_CAROUSEL_MESSAGES,
5
7
  s as RCCarousel,
6
8
  e as RCCarouselItem
7
9
  };
@@ -1 +1 @@
1
- {"version":3,"file":"rc-carousel-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCCarousel, RCCarouselItem } from './index.js';\n\ncustomElements.get('rc-carousel-item') || customElements.define('rc-carousel-item', RCCarouselItem);\ncustomElements.get('rc-carousel') || customElements.define('rc-carousel', RCCarousel);\n\nexport * from './index.js';\n"],"names":["RCCarouselItem","RCCarousel"],"mappings":";AAEA,eAAe,IAAI,kBAAkB,KAAK,eAAe,OAAO,oBAAoBA,CAAc;AAClG,eAAe,IAAI,aAAa,KAAK,eAAe,OAAO,eAAeC,CAAU;"}
1
+ {"version":3,"file":"rc-carousel-define.js","sources":["../src/define.ts"],"sourcesContent":["import { RCCarousel, RCCarouselItem } from './index.js';\n\ncustomElements.get('rc-carousel-item') || customElements.define('rc-carousel-item', RCCarouselItem);\ncustomElements.get('rc-carousel') || customElements.define('rc-carousel', RCCarousel);\n\nexport * from './index.js';\n"],"names":["RCCarouselItem","RCCarousel"],"mappings":";;AAEA,eAAe,IAAI,kBAAkB,KAAK,eAAe,OAAO,oBAAoBA,CAAc;AAClG,eAAe,IAAI,aAAa,KAAK,eAAe,OAAO,eAAeC,CAAU;"}
@@ -1,6 +1,7 @@
1
- import { R as o, a as r } from "./rc-carousel-CdDEH9fb.js";
1
+ import { D as C, R as e, a as o } from "./rc-carousel-CGHUVDLI.js";
2
2
  export {
3
- o as RCCarousel,
4
- r as RCCarouselItem
3
+ C as DEFAULT_CAROUSEL_MESSAGES,
4
+ e as RCCarousel,
5
+ o as RCCarouselItem
5
6
  };
6
7
  //# sourceMappingURL=rc-carousel.js.map
@@ -43,11 +43,19 @@ export declare class RCCarouselItem extends LitElement {
43
43
  * integration point, not a public API — see the `@attr` note above.
44
44
  */
45
45
  position: string;
46
+ /**
47
+ * `aria-roledescription` assigned by the parent `rc-carousel` in its
48
+ * locale. Internal integration point, not a public API.
49
+ */
50
+ roleDescription: string;
51
+ private _writtenLabel;
52
+ private _writtenRoleDescription;
46
53
  constructor();
47
54
  connectedCallback(): void;
48
55
  disconnectedCallback(): void;
49
56
  protected updated(changed: Map<string, unknown>): void;
50
57
  private _syncDefaultLabel;
58
+ private _syncRoleDescription;
51
59
  /**
52
60
  * Observes intersection against the parent carousel's own scroll
53
61
  * container (not the viewport — a slide can be viewport-visible yet
@@ -59,5 +67,5 @@ export declare class RCCarouselItem extends LitElement {
59
67
  * host's, and `trackElement` only exists once the host has rendered.
60
68
  */
61
69
  private _observeIntersection;
62
- protected render(): import('lit').TemplateResult<1>;
70
+ protected render(): import('lit-html').TemplateResult<1>;
63
71
  }
@@ -1,5 +1,26 @@
1
1
  import { LitElement } from 'lit';
2
2
  import { DragGestureController } from '@rcarls/rc-common';
3
+ /** Built-in text of `rc-carousel` and its slides. Positions are 1-based. */
4
+ export interface RCCarouselMessages {
5
+ /** `aria-roledescription` of the carousel. */
6
+ carousel: string;
7
+ /** `aria-roledescription` of each slide. */
8
+ slide: string;
9
+ /** Default accessible name of each slide. */
10
+ position: (position: number, count: number, locale?: string) => string;
11
+ previous: string;
12
+ next: string;
13
+ /** Accessible name of the slide-picker group. */
14
+ picker: string;
15
+ /** Accessible name of each slide-picker button. */
16
+ goToSlide: (position: number, count: number, locale?: string) => string;
17
+ }
18
+ export declare const DEFAULT_CAROUSEL_MESSAGES: Readonly<RCCarouselMessages>;
19
+ declare module '@rcarls/rc-common' {
20
+ interface RcMessageCatalog {
21
+ 'rc-carousel': RCCarouselMessages;
22
+ }
23
+ }
3
24
  export type RCCarouselChangeTrigger = 'api' | 'button' | 'keyboard' | 'swipe';
4
25
  export interface RCCarouselChangeDetail {
5
26
  index: number;
@@ -60,6 +81,11 @@ declare global {
60
81
  * @attr mouse-dragging - Enables click-and-drag scrolling with a mouse.
61
82
  * Touch/pen already get native scroll-snap physics; off by default.
62
83
  *
84
+ * Built-in text (button names, role descriptions, slide positions) follows
85
+ * the element's own `lang`, else `<html lang>`: per element through
86
+ * `messages`, or for every carousel through `registerMessages()` from
87
+ * `@rcarls/rc-common` under `rc-carousel`.
88
+ *
63
89
  * @cssprop [--rc-carousel-color=CanvasText] - Carousel foreground color.
64
90
  * @cssprop [--rc-carousel-gap=8px] - Space between slides.
65
91
  * @cssprop [--rc-carousel-slide-size=calc(100% - 4rem)] - Rendered size of
@@ -103,6 +129,11 @@ export declare class RCCarousel extends LitElement {
103
129
  private _suppressSync;
104
130
  private _pendingInstant;
105
131
  private _settleTimer;
132
+ private readonly _initialPosition;
133
+ private _writtenRoleDescription;
134
+ private readonly _messages;
135
+ /** Built-in text overrides; unset keys fall back to registered text, then English. */
136
+ messages: Partial<RCCarouselMessages> | undefined;
106
137
  /** Wraps past the first/last slide back to the other end, seamlessly. */
107
138
  loop: boolean;
108
139
  /** Shows previous/next buttons. */
@@ -116,10 +147,14 @@ export declare class RCCarousel extends LitElement {
116
147
  */
117
148
  mouseDragging: boolean;
118
149
  private _dragging;
119
- private _dragStartLeft;
150
+ /** Logical inline scroll offset of the track when the current drag began. */
151
+ private _dragStartOffset;
152
+ /** Track flow, re-resolved at the start of each drag or scroll operation. */
153
+ private _flow;
154
+ private _dragAxis;
120
155
  private _suppressNextClick;
121
156
  /**
122
- * Drives `scrollLeft` directly from pointer deltas while `mouseDragging`
157
+ * Drives the track's scroll offset directly from pointer deltas while `mouseDragging`
123
158
  * is on. `activation: 'axis'` (not `'immediate'`) means a plain click
124
159
  * never activates a drag at all — it requires clearing
125
160
  * `activationDistance` (8px) of movement first — but a *real* drag still
@@ -181,11 +216,37 @@ export declare class RCCarousel extends LitElement {
181
216
  */
182
217
  private _trackSlots;
183
218
  private _itemStep;
219
+ private _measureTrack;
220
+ private _applyFlow;
221
+ /**
222
+ * Re-reads the track's writing mode and direction. Called at the start of
223
+ * each scroll operation and on each drag's pointerdown rather than cached
224
+ * for the element's life, since neither a `dir` nor a writing-mode change
225
+ * on an ancestor fires an event. The drag gesture's physical axis follows,
226
+ * so a carousel in vertical text drags vertically.
227
+ */
228
+ private _resolveFlow;
229
+ /** Scroll distance from the track's logical start, never negative. */
230
+ private _trackOffset;
231
+ private _setTrackOffset;
184
232
  private _setActiveIndex;
185
233
  private _scrollToIndex;
234
+ private _queueInitialPosition;
235
+ private _sampleInitialPosition;
236
+ private _applyInitialPosition;
237
+ /**
238
+ * Keep the authored active slide available to assistive technology even
239
+ * before a programmatic scroll produces its next intersection callback.
240
+ * IntersectionObserver still takes over during direct manipulation, where
241
+ * the visually dominant slide can change before scroll settling updates the
242
+ * public active index.
243
+ */
244
+ private _syncActiveItemAccessibility;
186
245
  private _onSlotChange;
187
246
  private _directItems;
188
247
  private _setItemPositions;
248
+ /** Re-applies text written outside the template, for a new locale or `messages`. */
249
+ private _syncText;
189
250
  /**
190
251
  * Prepending/appending the loop clones below is itself a light-DOM
191
252
  * mutation on this host, which re-fires `slotchange` (asynchronously) —
@@ -212,13 +273,13 @@ export declare class RCCarousel extends LitElement {
212
273
  private _sanitizeClone;
213
274
  private _removeClones;
214
275
  /**
215
- * On release, a fast enough flick pre-nudges `scrollLeft` to the next
276
+ * On release, a fast enough flick pre-nudges the scroll offset to the next
216
277
  * snap point in the drag direction (a "decisive swipe" — mirroring
217
278
  * `rc-bottom-sheet`'s own velocity-vs-nearest-point settle heuristic,
218
279
  * adapted from "jump to the extreme end" for a 2-point sheet to "advance
219
280
  * one further point" for a carousel that can have many). Either way,
220
281
  * this hands off to the same debounced settle path a native swipe
221
- * already goes through — our own `scrollLeft` writes during the drag
282
+ * already goes through — our own scroll offset writes during the drag
222
283
  * already fired real `scroll` events, so `_onScroll` just needs to run
223
284
  * its usual timer to pick up wherever things ended.
224
285
  */
@@ -266,5 +327,5 @@ export declare class RCCarousel extends LitElement {
266
327
  * render: a no-op once every button already has some tabindex value.
267
328
  */
268
329
  private _initPaginationTabIndex;
269
- protected render(): import('lit').TemplateResult<1>;
330
+ protected render(): import('lit-html').TemplateResult<1>;
270
331
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.0",
6
+ "version": "0.7.0",
7
7
  "description": "WAI-ARIA APG carousel pattern built on native CSS scroll-snap and consumer-controlled slide sizing.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -45,7 +45,7 @@
45
45
  "test:browser:firefox": "vitest --run --project=firefox"
46
46
  },
47
47
  "dependencies": {
48
- "@rcarls/rc-common": "0.5.0"
48
+ "@rcarls/rc-common": "0.7.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@custom-elements-manifest/analyzer": "0.11.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-carousel-CdDEH9fb.js","sources":["../src/rc-carousel-item.styles.ts","../src/rc-carousel-item.ts","../src/rc-carousel.styles.ts","../src/rc-carousel.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const carouselItemStyles = css`\n :host {\n display: block;\n box-sizing: border-box;\n min-inline-size: 0;\n min-block-size: 0;\n scroll-snap-align: var(--rc-carousel-item-scroll-snap-align, start);\n /*\n * Without this, a normal-speed swipe carries enough fling momentum to\n * sail past the very next item and settle two (or more) items over —\n * \\`mandatory\\` scroll-snap-type on the track alone only guarantees\n * landing on *a* snap point, not the nearest one. \\`always\\` forces the\n * browser to stop at each snap point in turn.\n */\n scroll-snap-stop: always;\n overflow: var(--rc-carousel-item-overflow, hidden);\n border-radius: var(--rc-carousel-item-border-radius, 0);\n background: var(--rc-carousel-item-background, transparent);\n color: var(--rc-carousel-item-color, CanvasText);\n color-scheme: inherit;\n }\n\n :host([hidden]) {\n display: none;\n }\n\n /*\n * Peeking/off-screen items are hidden from assistive technology (see\n * rc-carousel-item.ts's IntersectionObserver) but must stay visually and\n * interactively present — a peek is a legitimate visual affordance, not\n * decoration to strip. This only removes it from the accessibility tree\n * and, via inert, the tab sequence, matching the same technique proven\n * carousels (e.g. Shoelace's sl-carousel) use for exactly this problem.\n */\n :host([aria-hidden='true']) {\n pointer-events: none;\n }\n`;\n\nexport default carouselItemStyles;\n","import { LitElement, html } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport type { RCCarousel } from './rc-carousel.js';\n\nimport carouselItemStyles from './rc-carousel-item.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-carousel-item': RCCarouselItem;\n }\n}\n\n/**\n * One slide of an `rc-carousel`. Participates directly in the parent's\n * scroll-snap track as a grid-auto-flow child — `rc-carousel-item` owns its\n * own snap alignment and accessibility state, but authored content (an\n * `<img>` with real alt text, arbitrary markup) stays exactly as slotted,\n * never cloned or re-parented, so it remains directly available to forms,\n * labels, and assistive technology.\n *\n * While off-screen (not the intersecting slide, including a partially\n * visible peek), the slide is marked `aria-hidden` and `inert`: it stays\n * visually and pointer-interactively present as a peek affordance, but\n * drops out of the accessibility tree and the Tab sequence, so a slide's\n * interactive descendants (a button, a link) can't be reached by keyboard\n * or announced by a screen reader until their slide is actually active.\n *\n * @slot - Slide content.\n *\n * @cssprop [--rc-carousel-item-color=CanvasText] - Slide foreground color.\n * @cssprop [--rc-carousel-item-scroll-snap-align=start] - Snap alignment\n * within the track. Override for a center-aligned layout.\n * @cssprop [--rc-carousel-item-background=transparent] - Slide surface\n * background, e.g. for an MD3 card-like slide shape.\n * @cssprop [--rc-carousel-item-border-radius=0] - Slide corner radius.\n * @cssprop [--rc-carousel-item-overflow=hidden] - Overflow behavior for\n * slotted content that exceeds the slide's own box. `hidden` clips to\n * the corner radius (matching media-item slides); text-heavy slides\n * that need their own internal scroll may want `auto` instead.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-carousel rc-carousel documentation}\n */\nexport class RCCarouselItem extends LitElement {\n static override styles = carouselItemStyles;\n\n private readonly _internals: ElementInternals;\n\n private _intersectionObserver: IntersectionObserver | null = null;\n\n /**\n * \"N of M\" position assigned by the parent `rc-carousel`. Internal\n * integration point, not a public API — see the `@attr` note above.\n */\n @property({ type: String, attribute: false })\n position = '';\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n this._internals.role = 'group';\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'group');\n }\n\n if (!this.hasAttribute('aria-roledescription')) {\n this.setAttribute('aria-roledescription', 'slide');\n }\n\n this._observeIntersection();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n this._intersectionObserver?.disconnect();\n this._intersectionObserver = null;\n }\n\n protected override updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n\n if (changed.has('position')) {\n this._syncDefaultLabel();\n }\n }\n\n private _syncDefaultLabel(): void {\n if (this.hasAttribute('aria-label') || this.hasAttribute('aria-labelledby')) {\n return;\n }\n\n if (this.position) {\n this.setAttribute('aria-label', this.position);\n }\n }\n\n /**\n * Observes intersection against the parent carousel's own scroll\n * container (not the viewport — a slide can be viewport-visible yet\n * still clipped/off-screen within the track on a page where the\n * carousel isn't the whole viewport). Reads `trackElement` off the\n * parent `rc-carousel`, an internal integration point rather than a\n * public API — awaits the parent's own first render first, since a\n * slotted item's `connectedCallback` isn't guaranteed to run after its\n * host's, and `trackElement` only exists once the host has rendered.\n */\n private async _observeIntersection(): Promise<void> {\n if (this.hasAttribute('data-clone')) {\n this.setAttribute('aria-hidden', 'true');\n this.setAttribute('inert', '');\n\n return;\n }\n\n const $carousel = this.closest('rc-carousel') as RCCarousel | null;\n\n await $carousel?.updateComplete;\n\n const $root = $carousel?.trackElement ?? null;\n\n this._intersectionObserver?.disconnect();\n\n if (typeof IntersectionObserver !== 'function' || !$root) {\n this.removeAttribute('aria-hidden');\n this.removeAttribute('inert');\n\n return;\n }\n\n this._intersectionObserver = new IntersectionObserver(\n ([entry]) => {\n const hidden = entry !== undefined && !entry.isIntersecting;\n\n if (hidden) {\n if (this.contains(this.ownerDocument.activeElement)) {\n $carousel?.trackElement?.focus();\n }\n\n this.setAttribute('aria-hidden', 'true');\n } else {\n this.removeAttribute('aria-hidden');\n }\n\n this.toggleAttribute('inert', hidden);\n },\n // A low/zero threshold would count a peeking neighbor's own sliver\n // of visible pixels as \"intersecting\", never hiding it — a peek is\n // real but not readable/interactive, so it should still hide. 0.5\n // reliably separates \"the active slide\" (near-fully visible) from\n // \"a peeking neighbor\" (a fraction of it showing).\n { root: $root, threshold: 0.5 },\n );\n\n this._intersectionObserver.observe(this);\n }\n\n protected override render() {\n return html`<slot></slot>`;\n }\n}\n","import { css } from 'lit';\n\nexport const carouselStyles = css`\n :host {\n display: block;\n position: relative;\n color: var(--rc-carousel-color, CanvasText);\n color-scheme: inherit;\n }\n\n #track {\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: var(--rc-carousel-slide-size, calc(100% - 4rem));\n column-gap: var(--rc-carousel-gap, 8px);\n inline-size: 100%;\n block-size: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n /*\n * Deliberately no \\`scroll-behavior: smooth\\` here — _scrollToIndex in\n * rc-carousel.ts passes \\`behavior: 'smooth'\\` explicitly per\n * programmatic call instead, which is unaffected either way (an\n * explicit argument always overrides this CSS default). Setting it\n * here as an ambient default would also apply to the browser's own\n * native snap-settle correction after a swipe — a documented\n * cross-browser conflict with scroll-snap-stop: always (each\n * rc-carousel-item sets that; Firefox bugzilla 1643217, 1959811)\n * that produces a jerk-then-snap-back artifact on an ordinary swipe.\n */\n scrollbar-width: none;\n }\n\n #track::-webkit-scrollbar {\n display: none;\n }\n\n :host([mouse-dragging]) #track {\n cursor: grab;\n }\n\n :host([mouse-dragging]) #track.dragging {\n cursor: grabbing;\n /*\n * scroll-snap-type itself is toggled imperatively in rc-carousel.ts,\n * not here — it must be off before the very first scrollLeft write of\n * a drag, and this class only lands on the next reactive render, a\n * render pass too late for that first write (the browser eagerly\n * resnaps a plain scrollLeft assignment right back to the nearest\n * snap point, same as any other programmatic scroll).\n */\n }\n\n #navigation {\n display: contents;\n }\n\n [part~='navigation-button'] {\n position: absolute;\n top: 50%;\n translate: 0 -50%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n inline-size: var(--rc-carousel-navigation-button-size, 40px);\n block-size: var(--rc-carousel-navigation-button-size, 40px);\n border: none;\n border-radius: 50%;\n background: var(\n --rc-carousel-navigation-button-background,\n color-mix(in srgb, CanvasText 12%, transparent)\n );\n color: var(--rc-carousel-navigation-button-color, CanvasText);\n cursor: pointer;\n }\n\n [part~='navigation-button'][aria-disabled='true'] {\n opacity: 0.38;\n cursor: default;\n }\n\n [part~='navigation-button-previous'] {\n inset-inline-start: var(--rc-carousel-navigation-inset, 8px);\n }\n\n [part~='navigation-button-next'] {\n inset-inline-end: var(--rc-carousel-navigation-inset, 8px);\n }\n\n #pagination {\n position: absolute;\n inset-block-end: var(--rc-carousel-navigation-inset, 8px);\n inset-inline: 0;\n display: flex;\n justify-content: center;\n gap: var(--rc-carousel-gap, 8px);\n }\n\n [part~='pagination-item'] {\n inline-size: var(--rc-carousel-pagination-item-size, 8px);\n block-size: var(--rc-carousel-pagination-item-size, 8px);\n padding: 0;\n border: none;\n border-radius: 50%;\n background: var(\n --rc-carousel-pagination-item-color,\n color-mix(in srgb, CanvasText 40%, transparent)\n );\n cursor: pointer;\n }\n\n [part~='pagination-item-active'] {\n background: var(--rc-carousel-pagination-item-active-color, Highlight);\n cursor: default;\n }\n`;\n\nexport default carouselStyles;\n","import { LitElement, html, nothing } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\n\nimport {\n DragGestureController,\n findExtremeSnapIndex,\n findNearestSnapIndex,\n findNextSnapIndex,\n keyNavigation,\n warnMissingDirectChild,\n type DragGestureDetail,\n type KeyboardNavigationAction,\n} from '@rcarls/rc-common';\nimport type { RCCarouselItem } from './rc-carousel-item.js';\n\nimport carouselStyles from './rc-carousel.styles.js';\n\n/** Release velocity (px/s) past which a mouse-drag release is treated as a\n * decisive swipe (advance one further slide) rather than settling to the\n * nearest snap point. */\nconst DECISIVE_DRAG_VELOCITY = 300;\n\nexport type RCCarouselChangeTrigger = 'api' | 'button' | 'keyboard' | 'swipe';\n\nexport interface RCCarouselChangeDetail {\n index: number;\n trigger: RCCarouselChangeTrigger;\n}\n\ndeclare global {\n interface HTMLElementEventMap {\n 'rc-carousel-change': CustomEvent<RCCarouselChangeDetail>;\n }\n interface HTMLElementTagNameMap {\n 'rc-carousel': RCCarousel;\n }\n}\n\nconst SETTLE_DEBOUNCE_MS = 120;\n\n/**\n * WAI-ARIA APG carousel pattern built on native CSS scroll-snap. One\n * `rc-carousel-item` per slide, swiped or paged between; the track's own\n * native scroll-snap settling (not a hand-rolled drag simulation) is the\n * primary interaction, per this monorepo's \"build on native browser\n * behavior\" principle.\n *\n * `activeIndex` is a controlled/uncontrolled property, mirroring\n * `rc-adaptive-menu`'s `open`/`defaultOpen` pair: leave it unset for\n * uncontrolled usage (`default-active-index` seeds the initial slide),\n * or set it directly to drive the carousel externally — a settle from\n * swipe, a keyboard action, or the imperative API all report back through\n * `rc-carousel-change` rather than silently self-correcting a controlled\n * value out from under the consumer.\n *\n * Previous/next navigation and a slide picker are both opt-in\n * (`navigation`/`pagination`), following the WAI-ARIA APG carousel\n * pattern's \"grouped\" (non-tab) picker style deliberately: the tabbed\n * `role=\"tabpanel\"` variant requires cross-references between light-DOM\n * slides and shadow-DOM tab buttons that, in comparable shadow-DOM\n * carousels, has hit real accessibility-tooling failures across the\n * shadow boundary (including non-recognition by some screen readers\n * entirely). `loop` wraps seamlessly via cloned lead/trail slides rather\n * than a discontinuous jump back to the other end.\n *\n * @slot - One or more `rc-carousel-item` elements.\n * @slot previous-icon - Optional icon for the previous button, replacing\n * the default chevron. Only rendered when `navigation` is set.\n * @slot next-icon - Optional icon for the next button, replacing the\n * default chevron. Only rendered when `navigation` is set.\n *\n * @fires rc-carousel-change - Fires when the active slide changes, from a\n * swipe settling, a keyboard action, or the imperative API.\n * `detail: { index, trigger: 'swipe'|'button'|'keyboard'|'api' }`\n *\n * @attr active-index - Controls the active slide. Host writes are silent —\n * listen for `rc-carousel-change` to stay in sync.\n * @attr default-active-index - Initial active slide for uncontrolled usage.\n * @attr loop - Wraps past the first/last slide back to the other end,\n * seamlessly (via cloned lead/trail slides), for swipe, buttons, and\n * keyboard alike. Off by default: the ends are real boundaries, not a\n * loop, unless a consumer opts in.\n * @attr navigation - Shows previous/next buttons.\n * @attr pagination - Shows a slide-picker button group.\n * @attr mouse-dragging - Enables click-and-drag scrolling with a mouse.\n * Touch/pen already get native scroll-snap physics; off by default.\n *\n * @cssprop [--rc-carousel-color=CanvasText] - Carousel foreground color.\n * @cssprop [--rc-carousel-gap=8px] - Space between slides.\n * @cssprop [--rc-carousel-slide-size=calc(100% - 4rem)] - Rendered size of\n * each slide along the scroll axis. Set this directly or from a consumer\n * container query to coordinate hero and multi-browse layouts.\n * @cssprop [--rc-carousel-navigation-button-size=40px] - Previous/next\n * button diameter.\n * @cssprop [--rc-carousel-navigation-button-background=color-mix(in srgb, CanvasText 12%, transparent)] -\n * Previous/next button background.\n * @cssprop [--rc-carousel-navigation-button-color=CanvasText] -\n * Previous/next button icon color.\n * @cssprop [--rc-carousel-navigation-inset=8px] - Previous/next button\n * inset from the track edge.\n * @cssprop [--rc-carousel-pagination-item-size=8px] - Slide-picker dot\n * diameter.\n * @cssprop [--rc-carousel-pagination-item-color=color-mix(in srgb, CanvasText 40%, transparent)] -\n * Inactive slide-picker dot color.\n * @cssprop [--rc-carousel-pagination-item-active-color=Highlight] - Active\n * slide-picker dot color.\n *\n * @csspart track - The scrollable slide track.\n * @csspart navigation - Previous/next button wrapper.\n * @csspart navigation-button - A previous or next button.\n * @csspart navigation-button-previous - The previous button specifically.\n * @csspart navigation-button-next - The next button specifically.\n * @csspart pagination - Slide-picker button group wrapper.\n * @csspart pagination-item - A slide-picker button.\n * @csspart pagination-item-active - The active slide's picker button.\n *\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/carousel/ WAI-ARIA APG Carousel pattern}\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-carousel rc-carousel documentation}\n */\nexport class RCCarousel extends LitElement {\n static override styles = carouselStyles;\n\n private readonly _internals: ElementInternals;\n\n @query('#track') private _trackEl?: HTMLDivElement;\n @query('slot:not([name])') private _slotEl?: HTMLSlotElement;\n\n // Seeded from direct children during connection so the first render can\n // build pagination without changing reactive state from firstUpdated().\n private _items: RCCarouselItem[] = [];\n private _cloneItems: RCCarouselItem[] = [];\n private _mounted = false;\n private _suppressSync = false;\n private _pendingInstant = false;\n private _settleTimer: ReturnType<typeof setTimeout> | undefined;\n\n /** Wraps past the first/last slide back to the other end, seamlessly. */\n @property({ type: Boolean, reflect: true })\n loop = false;\n\n /** Shows previous/next buttons. */\n @property({ type: Boolean, reflect: true })\n navigation = false;\n\n /** Shows a slide-picker button group. */\n @property({ type: Boolean, reflect: true })\n pagination = false;\n\n /**\n * Enables click-and-drag scrolling with a mouse — native scroll-snap\n * touch physics already cover touch/pen, but a mouse has no built-in\n * equivalent. Off by default.\n */\n @property({ type: Boolean, reflect: true, attribute: 'mouse-dragging' })\n mouseDragging = false;\n\n @state() private _dragging = false;\n\n private _dragStartLeft = 0;\n private _suppressNextClick = false;\n\n /**\n * Drives `scrollLeft` directly from pointer deltas while `mouseDragging`\n * is on. `activation: 'axis'` (not `'immediate'`) means a plain click\n * never activates a drag at all — it requires clearing\n * `activationDistance` (8px) of movement first — but a *real* drag still\n * ends in a native `click` on release, on whatever's under the pointer,\n * which `_suppressNextClick` swallows so dragging across an unrelated\n * link or button inside a slide doesn't activate it (the same edge case\n * Shoelace's own `sl-carousel` handles for exactly this reason).\n */\n protected readonly _dragController = new DragGestureController(this, {\n target: () => this._trackEl ?? null,\n axis: 'x',\n activation: 'axis',\n canStart: (event) => this.mouseDragging && event.pointerType === 'mouse',\n onStart: () => {\n this._dragging = true;\n this._dragStartLeft = this._trackEl?.scrollLeft ?? 0;\n this._suppressNextClick = true;\n\n // Imperative, not reactive-class-driven: this must land before\n // onMove's very first scrollLeft write below, and a Lit re-render\n // (triggered by _dragging above) is a whole render pass too late for\n // that — with scroll-snap-type still active, the browser eagerly\n // resnaps a plain scrollLeft assignment straight back to the\n // nearest snap point, same as it would any other programmatic\n // scroll with no notion this is \"mid-gesture\".\n if (this._trackEl) {\n this._trackEl.style.scrollSnapType = 'none';\n }\n },\n onMove: (detail) => {\n if (this._trackEl) {\n this._trackEl.scrollLeft = this._dragStartLeft - detail.deltaX;\n }\n },\n onEnd: (detail) => this._endDrag(detail),\n onCancel: (detail) => this._endDrag(detail),\n });\n\n @state() private _busy = false;\n\n private _activeIndex: number | undefined;\n private _defaultActiveIndex = 0;\n private _uncontrolledActiveIndex: number | undefined;\n private _activeIndexInitialized = false;\n\n /** Controls the active slide. Host writes are silent. */\n @property({ type: Number, attribute: 'active-index' })\n get activeIndex(): number {\n return this._clampIndex(\n this._activeIndex ?? this._uncontrolledActiveIndex ?? this._defaultActiveIndex,\n );\n }\n\n set activeIndex(value: number | undefined) {\n const oldValue = this.activeIndex;\n\n this._activeIndex = value;\n this._activeIndexInitialized = true;\n this.requestUpdate('activeIndex', oldValue);\n }\n\n /** Initial active slide for uncontrolled usage. */\n @property({ type: Number, attribute: 'default-active-index' })\n get defaultActiveIndex(): number {\n return this._defaultActiveIndex;\n }\n\n set defaultActiveIndex(value: number) {\n const oldValue = this._defaultActiveIndex;\n\n this._defaultActiveIndex = value;\n\n if (\n !this._activeIndexInitialized &&\n this._activeIndex === undefined &&\n this._uncontrolledActiveIndex === undefined\n ) {\n this.requestUpdate('activeIndex', oldValue);\n }\n\n this.requestUpdate('defaultActiveIndex', oldValue);\n }\n\n /**\n * The scroll-snap track element. Internal integration point consumed by\n * `rc-carousel-item`'s IntersectionObserver (its `root` must be this\n * track, not the viewport, so peeking/clipped-but-viewport-visible\n * slides are still correctly detected as off-screen) — not a public API.\n */\n get trackElement(): HTMLElement | null {\n return this._trackEl ?? null;\n }\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n this._internals.role = 'group';\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n this._items = this._directItems();\n this._setItemPositions();\n\n if (!this.hasAttribute('role')) {\n this.setAttribute('role', 'group');\n }\n\n if (!this.hasAttribute('aria-roledescription')) {\n this.setAttribute('aria-roledescription', 'carousel');\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n if (this._settleTimer !== undefined) {\n clearTimeout(this._settleTimer);\n }\n }\n\n protected override firstUpdated(): void {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > rc-carousel-item',\n childDescription: '<rc-carousel-item> elements',\n });\n\n if (!this.hasAttribute('aria-label') && !this.hasAttribute('aria-labelledby')) {\n console.warn(\n \"[rc-carousel] No aria-label/aria-labelledby set. Provide one describing this carousel's content.\",\n );\n }\n }\n\n this._scrollToIndex(this.activeIndex, true);\n this._mounted = true;\n }\n\n protected override updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n\n this._initPaginationTabIndex();\n\n if (changed.has('loop') && this._mounted) {\n // Live toggle: _syncItems is idempotent (see its own comment) when\n // clone presence already matches, so this is cheap to call even when\n // nothing actually needs to change.\n this._syncItems();\n }\n\n if (!changed.has('activeIndex')) {\n return;\n }\n\n if (this._suppressSync) {\n this._suppressSync = false;\n\n return;\n }\n\n const instant = !this._mounted || this._pendingInstant;\n\n this._pendingInstant = false;\n this._scrollToIndex(this.activeIndex, instant);\n }\n\n /** Moves to the next slide. */\n next(): void {\n this._step(1, 'api');\n }\n\n /** Moves to the previous slide. */\n previous(): void {\n this._step(-1, 'api');\n }\n\n /** Moves directly to a slide index. */\n goToIndex(index: number, instant = false): void {\n this._pendingInstant = instant;\n this._setActiveIndex(index, 'api');\n }\n\n private _step(delta: 1 | -1, trigger: RCCarouselChangeTrigger): void {\n this._setActiveIndex(this.activeIndex + delta, trigger);\n }\n\n /** Whether a previous/next button (or an equivalent keyboard action)\n * currently has anywhere to go — always true when `loop` is set and\n * there's more than one slide. */\n private _canStep(delta: 1 | -1): boolean {\n const count = this._items.length;\n\n if (count <= 1) {\n return false;\n }\n\n if (this.loop) {\n return true;\n }\n\n return delta > 0 ? this.activeIndex < count - 1 : this.activeIndex > 0;\n }\n\n /**\n * Wraps when `loop` is set, otherwise clamps to the real slide range.\n * Wrapping here covers button/keyboard navigation; a swipe wraps\n * seamlessly through `_trackSlots`'s cloned lead/trail slides instead,\n * since that needs the clones' own track positions, not just an index.\n */\n private _clampIndex(index: number): number {\n const count = this._items.length;\n\n if (count === 0) {\n return 0;\n }\n\n if (this.loop) {\n return ((index % count) + count) % count;\n }\n\n return Math.min(count - 1, Math.max(0, index));\n }\n\n private _snapPoints(): number[] {\n const step = this._itemStep();\n\n return this._items.map((_item, index) => index * step);\n }\n\n /**\n * Every scrollable track position in rendered order, including cloned\n * lead/trail slides when `loop` is on — `[lastClone, item0, ..., itemN-1,\n * firstClone]`. Each slot reports which real slide index it represents\n * (a clone mirrors the real slide it duplicates), so both scrolling to\n * an index and reading back a settled scroll position can stay in terms\n * of real indices while the clones do the seamless-wrap work.\n */\n private _trackSlots(): { point: number; index: number; isClone: boolean }[] {\n const step = this._itemStep();\n const count = this._items.length;\n\n if (!this.loop || count < 2) {\n return this._items.map((_item, index) => ({ point: index * step, index, isClone: false }));\n }\n\n return [\n { point: 0, index: count - 1, isClone: true },\n ...this._items.map((_item, index) => ({ point: (index + 1) * step, index, isClone: false })),\n { point: (count + 1) * step, index: 0, isClone: true },\n ];\n }\n\n private _itemStep(): number {\n if (!this._trackEl) {\n return 1;\n }\n\n const first = this._items[0];\n\n if (!(first instanceof HTMLElement)) {\n return this._trackEl.clientWidth;\n }\n\n const gap = Number.parseFloat(getComputedStyle(this._trackEl).columnGap || '0') || 0;\n\n return first.offsetWidth + gap;\n }\n\n private _setActiveIndex(index: number, trigger: RCCarouselChangeTrigger): void {\n const clamped = this._clampIndex(index);\n const oldValue = this.activeIndex;\n\n if (oldValue === clamped) {\n return;\n }\n\n // Controlled usage (activeIndex currently has a host-owned value)\n // never self-writes here — only the consumer's own activeIndex setter\n // may change it, in response to the event dispatched below. Only\n // genuinely uncontrolled usage updates its own backing state directly.\n if (this._activeIndex === undefined) {\n this._uncontrolledActiveIndex = clamped;\n this.requestUpdate('activeIndex', oldValue);\n }\n\n this.dispatchEvent(\n new CustomEvent<RCCarouselChangeDetail>('rc-carousel-change', {\n bubbles: true,\n composed: true,\n detail: { index: clamped, trigger },\n }),\n );\n }\n\n private _scrollToIndex(index: number, instant: boolean): void {\n if (!this._trackEl) {\n return;\n }\n\n const slot = this._trackSlots().find((s) => !s.isClone && s.index === index);\n const left = slot ? slot.point : index * this._itemStep();\n const reducedMotion =\n this.ownerDocument.defaultView?.matchMedia('(prefers-reduced-motion: reduce)').matches ??\n false;\n\n if (instant || reducedMotion) {\n this._trackEl.scrollLeft = left;\n } else {\n // Explicit per call, not an ambient CSS default — see the comment on\n // #track in rc-carousel.styles.ts.\n this._trackEl.scrollTo({ left, behavior: 'smooth' });\n }\n }\n\n private _onSlotChange = (): void => {\n this._syncItems();\n };\n\n private _directItems(): RCCarouselItem[] {\n return Array.from(this.children).filter(\n (el): el is RCCarouselItem =>\n el.tagName === 'RC-CAROUSEL-ITEM' && !el.hasAttribute('data-clone'),\n );\n }\n\n private _setItemPositions(): void {\n this._items.forEach((item, index) => {\n item.position = `${index + 1} of ${this._items.length}`;\n });\n }\n\n /**\n * Prepending/appending the loop clones below is itself a light-DOM\n * mutation on this host, which re-fires `slotchange` (asynchronously) —\n * `_onSlotChange` calls back into this method, so a naive unconditional\n * remove-then-recreate would recreate a fresh pair of clones on every\n * pass forever. Clones are always excluded from `nextItems`, so the\n * real item list is byte-for-byte identical on that re-entrant pass;\n * only rebuild clone DOM when either the real items or the desired\n * clone presence has actually changed, so the re-entrant pass is a\n * true no-op and the recursion terminates.\n */\n private _syncItems(): void {\n const assigned = this._slotEl?.assignedElements() ?? [];\n const nextItems = assigned.filter(\n (el): el is RCCarouselItem =>\n el.tagName === 'RC-CAROUSEL-ITEM' && !el.hasAttribute('data-clone'),\n );\n const itemsChanged =\n nextItems.length !== this._items.length ||\n nextItems.some((item, index) => item !== this._items[index]);\n const wantsClones = this.loop && nextItems.length > 1;\n const hasClones = this._cloneItems.length > 0;\n\n this._items = nextItems;\n this._setItemPositions();\n\n if (itemsChanged && this._mounted) {\n this.requestUpdate();\n }\n\n if (!itemsChanged && wantsClones === hasClones) {\n return;\n }\n\n this._removeClones();\n\n if (wantsClones) {\n this._addClones();\n }\n }\n\n /**\n * Clones the first and last slide and prepends/appends them\n * (`data-clone=\"<real index>\"` marks them, excluded from `_items` and\n * from position numbering) so the track has real scrollable content\n * past both visual ends. `_trackSlots`/`_commitSettledIndex` detect\n * when a clone settles and instantly re-anchor to the real slide it\n * mirrors — Shoelace's proven technique for a seamless infinite swipe,\n * rather than a discontinuous index-modulo jump back to the other end.\n */\n private _addClones(): void {\n const first = this._items[0];\n const last = this._items[this._items.length - 1];\n\n if (!first || !last) {\n return;\n }\n\n const leadingClone = last.cloneNode(true) as RCCarouselItem;\n\n leadingClone.setAttribute('data-clone', String(this._items.length - 1));\n this._sanitizeClone(leadingClone);\n this.prepend(leadingClone);\n\n const trailingClone = first.cloneNode(true) as RCCarouselItem;\n\n trailingClone.setAttribute('data-clone', '0');\n this._sanitizeClone(trailingClone);\n this.append(trailingClone);\n\n this._cloneItems = [leadingClone, trailingClone];\n }\n\n /** Keeps visual loop clones out of forms, focus order, and the accessibility tree. */\n private _sanitizeClone($clone: RCCarouselItem): void {\n $clone.setAttribute('aria-hidden', 'true');\n $clone.setAttribute('inert', '');\n\n for (const $element of [$clone, ...$clone.querySelectorAll<HTMLElement>('*')]) {\n $element.removeAttribute('id');\n $element.removeAttribute('name');\n $element.removeAttribute('form');\n }\n }\n\n private _removeClones(): void {\n this._cloneItems.forEach((clone) => clone.remove());\n this._cloneItems = [];\n }\n\n /**\n * On release, a fast enough flick pre-nudges `scrollLeft` to the next\n * snap point in the drag direction (a \"decisive swipe\" — mirroring\n * `rc-bottom-sheet`'s own velocity-vs-nearest-point settle heuristic,\n * adapted from \"jump to the extreme end\" for a 2-point sheet to \"advance\n * one further point\" for a carousel that can have many). Either way,\n * this hands off to the same debounced settle path a native swipe\n * already goes through — our own `scrollLeft` writes during the drag\n * already fired real `scroll` events, so `_onScroll` just needs to run\n * its usual timer to pick up wherever things ended.\n */\n private _endDrag(detail: DragGestureDetail): void {\n this._dragging = false;\n\n if (this._trackEl) {\n this._trackEl.style.scrollSnapType = '';\n }\n\n if (this._trackEl && Math.abs(detail.velocityX) > DECISIVE_DRAG_VELOCITY) {\n const slots = this._trackSlots();\n // Dragging left (negative velocityX) moves content right-to-left,\n // i.e. advances forward — toward higher track points.\n const direction = detail.velocityX < 0 ? 1 : -1;\n const targetSlotIndex = findNextSnapIndex(\n slots.map((slot) => slot.point),\n this._trackEl.scrollLeft,\n direction,\n );\n const targetSlot = slots[targetSlotIndex];\n\n if (targetSlot) {\n this._trackEl.scrollLeft = targetSlot.point;\n }\n }\n\n this._onScroll();\n }\n\n /**\n * Debounced, not per-frame: `_scrollToIndex`'s own smooth scroll fires\n * many `scroll` events while still mid-flight, and reading the settled\n * index from an in-progress position would report the wrong slide and\n * immediately fight the very scroll driving it. Waiting for scrolling to\n * actually stop (swipe release or animation end) avoids that oscillation.\n */\n private _onScroll = (): void => {\n if (this._settleTimer !== undefined) {\n clearTimeout(this._settleTimer);\n }\n\n this._busy = true;\n this._settleTimer = setTimeout(this._commitSettledIndex, SETTLE_DEBOUNCE_MS);\n };\n\n private _commitSettledIndex = (): void => {\n this._busy = false;\n\n if (!this._trackEl) {\n return;\n }\n\n const slots = this._trackSlots();\n const settledSlotIndex = findNearestSnapIndex(\n slots.map((slot) => slot.point),\n this._trackEl.scrollLeft,\n );\n const settledSlot = settledSlotIndex >= 0 ? slots[settledSlotIndex] : undefined;\n\n if (!settledSlot) {\n return;\n }\n\n if (settledSlot.isClone) {\n // Seamless re-anchor: a clone settling means the user scrolled past\n // the real end. Instantly (no animation — this must be invisible)\n // correct to the real slide's own track position, which renders\n // identically to the clone at this scroll offset.\n const realSlot = slots.find((slot) => !slot.isClone && slot.index === settledSlot.index);\n\n if (realSlot) {\n this._trackEl.scrollLeft = realSlot.point;\n }\n }\n\n if (settledSlot.index === this.activeIndex) {\n // Already in sync (or the clone correction above just made it so) —\n // no prop change means `updated()` won't run at all, so there's no\n // echo to suppress here.\n return;\n }\n\n // Settling a user swipe reports the new index back up through the same\n // `activeIndex` prop the sync effect (`updated()`) watches. Replaying\n // that through `_scrollToIndex` would still fire a real, non-instant\n // `scrollTo`, not a no-op — if a genuine next swipe starts during that\n // echoed animation, it fights the swipe and can swallow it.\n // `_suppressSync` skips `updated()`'s scroll for exactly that one echo.\n const controlled = this._activeIndex !== undefined;\n\n if (!controlled) {\n this._suppressSync = true;\n }\n\n this._setActiveIndex(settledSlot.index, 'swipe');\n\n // A controlled consumer may reject the requested swipe by leaving the\n // property unchanged. Restore the visual position to the host-owned slide\n // instead of leaving scroll state and public state disagreeing.\n if (controlled && this.activeIndex !== settledSlot.index) {\n this._scrollToIndex(this.activeIndex, true);\n }\n };\n\n private _onNavigate = (action: KeyboardNavigationAction): void => {\n switch (action) {\n case 'next':\n this._step(1, 'keyboard');\n break;\n case 'prev':\n this._step(-1, 'keyboard');\n break;\n\n case 'start': {\n const index = findExtremeSnapIndex(this._snapPoints(), -1);\n\n if (index >= 0) {\n this._setActiveIndex(index, 'keyboard');\n }\n\n break;\n }\n\n case 'end': {\n const index = findExtremeSnapIndex(this._snapPoints(), 1);\n\n if (index >= 0) {\n this._setActiveIndex(index, 'keyboard');\n }\n\n break;\n }\n }\n };\n\n /**\n * A real drag still ends in a native `click` on release (browsers fire\n * one on pointerup as long as pointerdown/pointerup share a target),\n * landing on whatever's currently under the pointer — which, mid-drag,\n * is often unrelated slide content the user was scrolling past, not\n * clicking. Capturing and swallowing exactly one click right after a\n * drag activated (`_suppressNextClick`, set in the drag controller's\n * `onStart`) stops that from reaching a link/button inside a slide.\n */\n private _onTrackClickCapture = (event: MouseEvent): void => {\n if (!this._suppressNextClick) {\n return;\n }\n\n this._suppressNextClick = false;\n event.stopPropagation();\n event.preventDefault();\n };\n\n private _paginationButtons(): HTMLButtonElement[] {\n return Array.from(\n this.shadowRoot?.querySelectorAll<HTMLButtonElement>('[data-pagination-item]') ?? [],\n );\n }\n\n /**\n * Hand-rolled roving tabindex for the pagination row, not\n * `RovingTabIndexMixin`: that mixin collects items from a real\n * `slotchange`-firing `<slot>`, matching its intended use (consumer-\n * authored, slotted content, like `rc-toolbar`'s buttons) — these\n * buttons are shadow-DOM content this component renders itself, so\n * there's no slot to collect from. The pattern is otherwise the same\n * one the mixin itself implements: exactly one button is a tab stop,\n * arrow keys move focus among them (not activeIndex — matching\n * rc-toolbar's own \"arrows move focus, Enter/Space activates\" model,\n * not a tablist's auto-activate-on-arrow), and focus keeps tabindex in\n * sync wherever it lands (click, Tab, or a `.focus()` call below).\n */\n private _onPaginationFocus = (event: FocusEvent): void => {\n const buttons = this._paginationButtons();\n const target = event.composedPath().find((el) => buttons.includes(el as HTMLButtonElement)) as\n | HTMLButtonElement\n | undefined;\n\n if (!target) {\n return;\n }\n\n buttons.forEach((button) => button.setAttribute('tabindex', button === target ? '0' : '-1'));\n };\n\n private _onPaginationNavigate = (action: KeyboardNavigationAction): void => {\n const buttons = this._paginationButtons();\n\n if (!buttons.length) {\n return;\n }\n\n const current = buttons.indexOf(this.shadowRoot?.activeElement as HTMLButtonElement);\n const from = current < 0 ? 0 : current;\n\n switch (action) {\n case 'next':\n buttons[(from + 1) % buttons.length]?.focus();\n break;\n case 'prev':\n buttons[(from - 1 + buttons.length) % buttons.length]?.focus();\n break;\n case 'start':\n buttons[0]?.focus();\n break;\n case 'end':\n buttons[buttons.length - 1]?.focus();\n break;\n }\n };\n\n /**\n * One-time tabindex seed for pagination buttons that have never\n * received focus yet (matching `activeIndex`, the sane default) —\n * `_onPaginationFocus` takes over from there. Safe to call on every\n * render: a no-op once every button already has some tabindex value.\n */\n private _initPaginationTabIndex(): void {\n this._paginationButtons().forEach((button, index) => {\n if (!button.hasAttribute('tabindex')) {\n button.setAttribute('tabindex', index === this.activeIndex ? '0' : '-1');\n }\n });\n }\n\n protected override render() {\n const canPrev = this._canStep(-1);\n const canNext = this._canStep(1);\n\n return html`\n <div\n id=\"track\"\n part=\"track\"\n tabindex=\"0\"\n class=${this._dragging ? 'dragging' : nothing}\n aria-busy=${this._busy ? 'true' : 'false'}\n aria-atomic=\"true\"\n @scroll=${this._onScroll}\n @click=${{ handleEvent: this._onTrackClickCapture, capture: true }}\n ${keyNavigation(this._onNavigate, { navigationAxis: 'horizontal' })}\n >\n <slot @slotchange=${this._onSlotChange}></slot>\n </div>\n\n ${this.navigation\n ? html`\n <div id=\"navigation\" part=\"navigation\">\n <button\n type=\"button\"\n part=\"navigation-button navigation-button-previous\"\n aria-label=\"Previous slide\"\n aria-disabled=${canPrev ? 'false' : 'true'}\n @click=${() => {\n if (canPrev) {\n this._step(-1, 'button');\n }\n }}\n >\n <span aria-hidden=\"true\">\n <slot name=\"previous-icon\">\n <svg\n viewBox=\"0 0 6 10\"\n width=\"10\"\n height=\"16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"5,1 1,5 5,9\" />\n </svg>\n </slot>\n </span>\n </button>\n <button\n type=\"button\"\n part=\"navigation-button navigation-button-next\"\n aria-label=\"Next slide\"\n aria-disabled=${canNext ? 'false' : 'true'}\n @click=${() => {\n if (canNext) {\n this._step(1, 'button');\n }\n }}\n >\n <span aria-hidden=\"true\">\n <slot name=\"next-icon\">\n <svg\n viewBox=\"0 0 6 10\"\n width=\"10\"\n height=\"16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"1,1 5,5 1,9\" />\n </svg>\n </slot>\n </span>\n </button>\n </div>\n `\n : nothing}\n ${this.pagination\n ? html`\n <div\n id=\"pagination\"\n part=\"pagination\"\n role=\"group\"\n aria-label=\"Choose slide to display\"\n @focusin=${this._onPaginationFocus}\n ${keyNavigation(this._onPaginationNavigate, { navigationAxis: 'horizontal' })}\n >\n ${this._items.map(\n (_item, index) => html`\n <button\n type=\"button\"\n data-pagination-item\n part=\"pagination-item${index === this.activeIndex\n ? ' pagination-item-active'\n : ''}\"\n aria-label=\"Go to slide ${index + 1}\"\n aria-current=${index === this.activeIndex ? 'true' : 'false'}\n aria-disabled=${index === this.activeIndex ? 'true' : 'false'}\n @click=${() => this._setActiveIndex(index, 'button')}\n ></button>\n `,\n )}\n </div>\n `\n : nothing}\n `;\n }\n}\n"],"names":["carouselItemStyles","css","_RCCarouselItem","LitElement","changed","$carousel","$root","entry","hidden","html","RCCarouselItem","__decorateClass","property","carouselStyles","DECISIVE_DRAG_VELOCITY","SETTLE_DEBOUNCE_MS","_RCCarousel","DragGestureController","event","detail","slots","settledSlotIndex","findNearestSnapIndex","slot","settledSlot","realSlot","controlled","action","index","findExtremeSnapIndex","buttons","target","el","button","current","from","value","oldValue","instant","delta","trigger","count","step","_item","first","gap","clamped","s","left","reducedMotion","item","nextItems","itemsChanged","wantsClones","hasClones","last","leadingClone","trailingClone","$clone","$element","clone","direction","targetSlotIndex","findNextSnapIndex","targetSlot","canPrev","canNext","nothing","keyNavigation","RCCarousel","query","state"],"mappings":"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"}