@reliability-design/web 1.4.8 → 1.4.10

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/custom-elements.json +18600 -0
  3. package/dist/components/rel-accordion/README.md +9 -2
  4. package/dist/components/rel-alert/README.md +5 -8
  5. package/dist/components/rel-autocomplete/README.md +209 -208
  6. package/dist/components/rel-avatar/README.md +228 -118
  7. package/dist/components/rel-breadcrumb/README.md +1 -0
  8. package/dist/components/rel-button/README.md +9 -9
  9. package/dist/components/rel-calendar/README.md +111 -109
  10. package/dist/components/rel-cardmedia/README.md +1 -1
  11. package/dist/components/rel-carousel/README.md +187 -186
  12. package/dist/components/rel-checkbox/README.md +159 -146
  13. package/dist/components/rel-chip/README.md +141 -138
  14. package/dist/components/rel-container/README.md +1 -1
  15. package/dist/components/rel-date-picker/README.md +221 -200
  16. package/dist/components/rel-drawer/README.md +4 -4
  17. package/dist/components/rel-kbd/README.md +188 -141
  18. package/dist/components/rel-layout/README.md +34 -34
  19. package/dist/components/rel-menu/README.md +17 -10
  20. package/dist/components/rel-menubar/README.md +218 -218
  21. package/dist/components/rel-otp/README.md +4 -8
  22. package/dist/components/rel-pagination/README.md +141 -100
  23. package/dist/components/rel-popover/README.md +220 -203
  24. package/dist/components/rel-radio/README.md +142 -131
  25. package/dist/components/rel-range-picker/README.md +194 -165
  26. package/dist/components/rel-resizable/README.md +220 -199
  27. package/dist/components/rel-segmented-button/README.md +158 -156
  28. package/dist/components/rel-select/README.md +22 -16
  29. package/dist/components/rel-sheet/README.md +3 -2
  30. package/dist/components/rel-signature-pad/README.md +161 -0
  31. package/dist/components/rel-slider/README.md +140 -131
  32. package/dist/components/rel-snackbar/README.md +170 -168
  33. package/dist/components/rel-split-button/README.md +129 -0
  34. package/dist/components/rel-stepper/README.md +171 -162
  35. package/dist/components/rel-switch/README.md +122 -117
  36. package/dist/components/rel-tab/README.md +184 -173
  37. package/dist/components/rel-textfield/README.md +23 -30
  38. package/dist/components/rel-time-picker/README.md +188 -164
  39. package/dist/components/rel-toast/README.md +20 -11
  40. package/dist/components/rel-tooltip/README.md +5 -4
  41. package/dist/components/rel-tree/README.md +157 -0
  42. package/dist/components/rel-upload/README.md +8 -5
  43. package/dist/index.d.mts +1698 -607
  44. package/dist/index.d.ts +1698 -607
  45. package/dist/index.js +12276 -6347
  46. package/dist/index.js.map +1 -1
  47. package/dist/index.mjs +12218 -6296
  48. package/dist/index.mjs.map +1 -1
  49. package/dist/styles/motion.css +31 -0
  50. package/dist/styles/motion.tokens.json +38 -0
  51. package/dist/styles/vars.css +88 -64
  52. package/dist/{vars-DXX6QOAG.css → vars-E22LYFMV.css} +88 -64
  53. package/package.json +60 -37
  54. package/dist/styles/focus-ring.ts +0 -84
@@ -1,186 +1,187 @@
1
- # rel-carousel
2
-
3
- A slide carousel implementing the Figma "Carousel" component and its three axes — `Type` (Default, Only Indicators, Side Arrows, Bottom Arrows), `Orientation` (Horizontal, Vertical) and `Multi Panels` — plus the `Show Dots` property. It shows one or more slotted slides at a time in a horizontal or vertical viewport and moves between them with arrows, dot indicators, pointer drag / swipe, the keyboard, or autoplay. Use it for a small, ordered set of equally important panels (hero images, onboarding cards, testimonials); do not use it as a substitute for tabs or for content the user must read in full — hidden slides are not reachable by page search or by screen readers until they are shown.
4
-
5
- ## Usage
6
-
7
- ```html
8
- <!-- Default type: slides only — swipe, drag or use the arrow keys -->
9
- <rel-carousel label="Product photos">
10
- <img src="/photos/front.jpg" alt="Front view">
11
- <img src="/photos/side.jpg" alt="Side view">
12
- <img src="/photos/back.jpg" alt="Back view">
13
- </rel-carousel>
14
-
15
- <!-- Figma Type axis: overlaid arrows + dots -->
16
- <rel-carousel type="side-arrows" label="Highlights">
17
- <div><h3>Fast setup</h3><p>Up and running in minutes.</p></div>
18
- <div><h3>Secure by default</h3><p>Encrypted at rest and in transit.</p></div>
19
- <div><h3>Works everywhere</h3><p>One component, every framework.</p></div>
20
- </rel-carousel>
21
-
22
- <!-- Dots flanked by arrows under the slide -->
23
- <rel-carousel type="bottom-arrows" label="Testimonials">
24
- <blockquote>"Saved us a week." — Ada</blockquote>
25
- <blockquote>"Zero regressions." — Grace</blockquote>
26
- </rel-carousel>
27
-
28
- <!-- Dots only -->
29
- <rel-carousel type="only-indicators" label="Tips">
30
- <p>Tip 1</p>
31
- <p>Tip 2</p>
32
- <p>Tip 3</p>
33
- </rel-carousel>
34
-
35
- <!-- Arrows on their own: show-dots="false" suppresses the dots the type implies -->
36
- <rel-carousel type="side-arrows" show-dots="false" label="Highlights">
37
- <div>Fast setup</div>
38
- <div>Secure by default</div>
39
- </rel-carousel>
40
-
41
- <!-- Loop and autoplay (3 s), 16px between slides, start on the second slide -->
42
- <rel-carousel type="side-arrows" loop autoplay interval="3000" gap="16" value="1" label="Promotions">
43
- <div>Spring sale</div>
44
- <div>Free shipping</div>
45
- <div>New arrivals</div>
46
- </rel-carousel>
47
-
48
- <!-- Figma Multi Panels: 1.5 panels leaves the next slide peeking in -->
49
- <rel-carousel type="side-arrows" panels="1.5" label="Related products">
50
- <div>Product A</div>
51
- <div>Product B</div>
52
- <div>Product C</div>
53
- <div>Product D</div>
54
- </rel-carousel>
55
-
56
- <!-- Two whole panels at a time, no peek -->
57
- <rel-carousel type="only-indicators" panels="2" label="Case studies">
58
- <div>Case A</div>
59
- <div>Case B</div>
60
- <div>Case C</div>
61
- <div>Case D</div>
62
- </rel-carousel>
63
-
64
- <!-- Vertical: the viewport height comes from --rel-carousel-height -->
65
- <rel-carousel orientation="vertical" type="side-arrows" label="Timeline" style="--rel-carousel-height: 240px">
66
- <div>2024</div>
67
- <div>2025</div>
68
- <div>2026</div>
69
- </rel-carousel>
70
-
71
- <!-- Programmatic control -->
72
- <rel-carousel id="gallery" type="bottom-arrows" label="Gallery">
73
- <div>A</div>
74
- <div>B</div>
75
- <div>C</div>
76
- </rel-carousel>
77
- <script>
78
- const gallery = document.getElementById('gallery');
79
- gallery.value = 2; // jump to the third slide
80
- gallery.pauseOnHover = false; // default-true booleans are switched off via the property
81
- gallery.addEventListener('rel-change', (e) => {
82
- console.log('Current slide:', e.detail.value);
83
- });
84
- </script>
85
- ```
86
-
87
- <!-- readme-gen:start -->
88
-
89
- <!-- Generated from rel-carousel.ts — do not edit; run readme-generate.mjs -->
90
-
91
- ## API
92
-
93
- ### Attributes / Properties
94
-
95
- | Property | Attribute | Type | Default | Description |
96
- | --- | --- | --- | --- | --- |
97
- | `value` | `value` | `number` | `0` | Index of the current slide (0-based). Set it to jump; it is clamped to the slide count and reflected as an attribute. Reflected. |
98
- | `loop` | `loop` | `boolean` | `false` | Wrap from the last slide to the first (and back) with a seamless clone transition instead of stopping at the ends. |
99
- | `autoplay` | `autoplay` | `boolean` | `false` | Advance automatically every `interval` ms; implies looping and pauses while hovered (see `pause-on-hover`) or while focus is inside the carousel. |
100
- | `interval` | `interval` | `number` | `5000` | Autoplay delay between slides, in milliseconds (default 5000). |
101
- | `pauseOnHover` | `pause-on-hover` | `boolean` | `true` | Pause autoplay while the pointer is over the carousel or while dragging (default true; switch off via the property, e.g. `el.pauseOnHover = false`). |
102
- | `showButtons` | `show-buttons` | `boolean` | `false` | Legacy toggle for the overlaid previous / next arrows; ignored whenever `type` is set. |
103
- | `showDots` | `show-dots` | `boolean` | `undefined` | Figma "Show Dots" property. Tri-state: left off it defers to `type` (dots for every type except `default`, and nothing at all when `type` is unset too); `show-dots` turns them on; `show-dots="false"` turns them off even when `type` would have shown them. |
104
- | `type` | `type` | `"default" \| "only-indicators" \| "side-arrows" \| "bottom-arrows"` | `undefined` | Figma "Type" axis. When set it drives which controls render: default = content only · only-indicators = dots · side-arrows = overlaid arrows + dots · bottom-arrows = dots flanked by arrows below the slide. When unset, the legacy show-buttons boolean applies unchanged. The dots a type implies can always be overridden by an explicit `show-dots`. Reflected. |
105
- | `orientation` | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Slide axis: `horizontal` (default) translates the track left / right; `vertical` stacks slides in a fixed-height viewport (`--rel-carousel-height`) and translates up / down. Reflected. |
106
- | `label` | `label` | `string` | `"Carousel"` | Accessible name of the carousel region (`aria-label` on the viewport); default "Carousel". |
107
- | `gap` | `gap` | `number` | `8` | Space between consecutive slides in pixels (applied as the track `gap` and added to each slide step); default 8 (Figma `spacing/xs`), 0 = slides touch. |
108
- | `panels` | `panels` | `number` | `1` | Figma "Multi Panels" axis, as a count: how many slides are visible at once (default 1). Fractions are allowed and produce a peek of the next slide — `panels="1.5"` reproduces the Figma Multi Panels=True variant. Navigation still advances one slide at a time. |
109
- | `disabled` | `disabled` | `boolean` | `false` | Disables arrows, dots, drag and keyboard navigation, stops autoplay and renders the carousel at 60% opacity. Reflected. |
110
-
111
- ## Events
112
-
113
- | Event | Detail | Bubbles / composed | Description |
114
- | --- | --- | --- | --- |
115
- | `rel-change` | `{ value: this.value }` | bubbles / composed | Fired whenever the current slide changes (arrows, dots, drag, keyboard, autoplay or a loop wrap). Detail: `{ value: number }` — the new 0-based slide index. |
116
-
117
- ## Slots
118
-
119
- | Slot | Description |
120
- | --- | --- |
121
- | (default) | The slides: one light-DOM element per slide (each is sized to one panel and given `role="group"` / `aria-roledescription="slide"`). |
122
-
123
- ## CSS Parts
124
-
125
- | Part | Description |
126
- | --- | --- |
127
- | `${direction}-button` | The two arrow buttons, exposed as `prev-button` and `next-button` (`type="side-arrows"` overlays them on the viewport; `type="bottom-arrows"` inlines them in the dots row). |
128
- | `viewport` | The focusable `role="region"` box that clips the track (also the keyboard target). |
129
- | `track` | The flex row / column that translates to reveal the current slide. |
130
- | `dots` | The indicator row under the viewport (also hosts the arrows for `type="bottom-arrows"`). |
131
- | `dot-group` | The row of dots inside `dots` (for `type="bottom-arrows"` it is the middle child, between the two arrows). |
132
- | `dot` | One indicator button per reachable position (per slide at `panels="1"`); the active one carries the `active` class and `aria-current="true"`. |
133
-
134
- ## Tokens / CSS Variables
135
-
136
- ### Component hooks
137
-
138
- Set these on the host (or an ancestor) to customise the element without touching design tokens.
139
-
140
- | Custom property | Default | Description |
141
- | --- | --- | --- |
142
- | `--rel-carousel-dot-size` | `8px` | Diameter of an inactive dot (default 8px). |
143
- | `--rel-carousel-dot-size-active` | `16px` | Width of the active (brand-coloured, pill-shaped) dot (default 16px). |
144
- | `--rel-carousel-height` | `320px` | Viewport height in `orientation="vertical"` (default 320px); the horizontal viewport takes the height of its tallest slide. |
145
- | `--rel-carousel-nav-size` | `32px` | Width / height of the arrow buttons (default 32px, matching Figma; applies to both side and bottom arrows). |
146
- | `--rel-carousel-slide-bg` | `var(--rel-bg-neutral)` | — |
147
- | `--rel-carousel-slide-height` | `100%` | Written by the component on its own host to the computed panel height (used for vertical slides); not meant to be set by consumers. |
148
- | `--rel-carousel-slide-radius` | `var(--rel-border-radius-sm)` | — |
149
- | `--rel-carousel-slide-width` | `100%` | Written by the component on its own host to the computed panel width (viewport width for `panels="1"`, a fraction of it above that); not meant to be set by consumers (an inline value is overwritten on resize). |
150
-
151
- <!-- readme-gen:end -->
152
-
153
- ## Accessibility
154
-
155
- - The viewport renders with `role="region"`, `aria-roledescription="carousel"` and `aria-label` set from the `label` prop (default "Carousel"); give every carousel a meaningful `label`.
156
- - Each slotted slide is decorated with `role="group"`, `aria-roledescription="slide"` and `aria-label="n of N"`; the clone slides used for looping are `aria-hidden="true"`.
157
- - The arrow buttons are labelled "Previous slide" / "Next slide" and their chevrons are `aria-hidden`; each dot is labelled "Go to slide n" and the active dot carries `aria-current="true"`.
158
- - The viewport is a single Tab stop (`tabindex="0"`); the arrows and dots that are rendered are ordinary buttons and follow it in the Tab order.
159
- - Every user-initiated slide change is announced through the shared live region as "Slide n of N"; autoplay ticks are deliberately silent.
160
- - Autoplay pauses while the pointer is over the carousel (`pause-on-hover`, default on) and while keyboard focus is anywhere inside it (WCAG 2.2.2 Pause, Stop, Hide); it resumes when focus leaves.
161
- - Track transitions are disabled under `prefers-reduced-motion: reduce`; drag still snaps to the nearest slide, just without animation.
162
-
163
- | Key | Action |
164
- | --- | --- |
165
- | `ArrowLeft` / `ArrowUp` | Previous slide (wraps when `loop` or `autoplay` is set) |
166
- | `ArrowRight` / `ArrowDown` | Next slide (wraps when `loop` or `autoplay` is set) |
167
- | `Home` | First slide |
168
- | `End` | Last slide |
169
- | `Tab` | Move between the viewport, the arrows and the dots |
170
-
171
- Keys are handled on the viewport (and anything focused inside it) and are ignored while `disabled`.
172
-
173
- ## Notes / Edge Cases
174
-
175
- - `type` is the canonical control switch. When it is unset the legacy `show-buttons` boolean still decides whether arrows render; when it is set `show-buttons` is ignored (`type="default"` hides the arrows).
176
- - `show-dots` is deliberately tri-state, because Figma's `Show Dots` is a property rather than part of the `Type` axis. Omit it and `type` decides, exactly as before; write `show-dots` to force the dots on; write `show-dots="false"` to force them off even for a `type` that would have shown them. Omitting it is what every pre-existing carousel does, so none of them change.
177
- - `panels` implements the Figma `Multi Panels` axis. Each panel measures `(viewport − gap × (ceil(panels) − 1)) / panels` along the scroll axis — a viewport showing `n` panels contains `ceil(n) − 1` whole gaps, so at the Figma frame width of 350px with the default 8px gap, `panels="1.5"` yields exactly the 228px slide the design specifies.
178
- - Navigation always advances one slide per step, never one page. Without `loop`, the track stops once the last slide is flush with the trailing edge instead of scrolling into empty space, so at `panels="1.5"` with three slides the reachable indices are `0` and `1`. The dot row follows that: one dot per reachable position, which is one per slide at `panels="1"` and whenever `loop` is on.
179
- - Slides are sized by the component: every slotted element gets `width: var(--rel-carousel-slide-width)` (or the height equivalent in `orientation="vertical"`) with `!important`, where the variable is written on the host to the computed panel size. Style the inside of a slide freely, but do not rely on a slide's own `width` / `height`.
180
- - `loop` and `autoplay` clone the edge slides into the shadow DOM so the wrap looks continuous — `ceil(panels)` of them at each end, since a viewport showing more than one panel would otherwise run out of slides mid-transition. `rel-change` still reports the real index (`0` … `N-1`) after the silent jump.
181
- - Drag / swipe uses a 20% threshold of the panel size; shorter drags snap back. Dragging pauses autoplay (when `pause-on-hover` is on) and resumes it on release.
182
- - `value` is clamped to the highest reachable index whenever the slot content changes; setting it out of range moves to the nearest valid slide.
183
- - Arrows are 32px circles with a 16px chevron, matching Figma. Side arrows (`type="side-arrows"`) overlay the viewport at the vertical centre, inset 8px from the edge; bottom arrows (`type="bottom-arrows"`) sit inside the indicator row, 20px from the dots. Both are hand-rolled ghost-style buttons, not `<rel-button>`, and both are sized by `--rel-carousel-nav-size`. Per the published Figma set the arrows stay on the left and right edges in `orientation="vertical"` too.
184
- - The active dot is a 16 × 8 fully-rounded brand pill and an inactive dot an 8px circle; `--rel-carousel-dot-size-active` and `--rel-carousel-dot-size` override them.
185
- - The horizontal viewport takes the height of its tallest slide; the vertical viewport is a fixed `--rel-carousel-height` (320px) — set it to fit your content.
186
- - Arrow buttons are exposed as `::part(prev-button)` and `::part(next-button)`; the indicator row is `::part(dots)`, the dots inside it `::part(dot-group)` and `::part(dot)`.
1
+ # rel-carousel
2
+
3
+ A slide carousel implementing the Figma "Carousel" component and its three axes — `Type` (Default, Only Indicators, Side Arrows, Bottom Arrows), `Orientation` (Horizontal, Vertical) and `Multi Panels` — plus the `Show Dots` property. It shows one or more slotted slides at a time in a horizontal or vertical viewport and moves between them with arrows, dot indicators, pointer drag / swipe, the keyboard, or autoplay. Use it for a small, ordered set of equally important panels (hero images, onboarding cards, testimonials); do not use it as a substitute for tabs or for content the user must read in full — hidden slides are not reachable by page search or by screen readers until they are shown.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Default type: slides only — swipe, drag or use the arrow keys -->
9
+ <rel-carousel label="Product photos">
10
+ <img src="/photos/front.jpg" alt="Front view">
11
+ <img src="/photos/side.jpg" alt="Side view">
12
+ <img src="/photos/back.jpg" alt="Back view">
13
+ </rel-carousel>
14
+
15
+ <!-- Figma Type axis: overlaid arrows + dots -->
16
+ <rel-carousel type="side-arrows" label="Highlights">
17
+ <div><h3>Fast setup</h3><p>Up and running in minutes.</p></div>
18
+ <div><h3>Secure by default</h3><p>Encrypted at rest and in transit.</p></div>
19
+ <div><h3>Works everywhere</h3><p>One component, every framework.</p></div>
20
+ </rel-carousel>
21
+
22
+ <!-- Dots flanked by arrows under the slide -->
23
+ <rel-carousel type="bottom-arrows" label="Testimonials">
24
+ <blockquote>"Saved us a week." — Ada</blockquote>
25
+ <blockquote>"Zero regressions." — Grace</blockquote>
26
+ </rel-carousel>
27
+
28
+ <!-- Dots only -->
29
+ <rel-carousel type="only-indicators" label="Tips">
30
+ <p>Tip 1</p>
31
+ <p>Tip 2</p>
32
+ <p>Tip 3</p>
33
+ </rel-carousel>
34
+
35
+ <!-- Arrows on their own: show-dots="false" suppresses the dots the type implies -->
36
+ <rel-carousel type="side-arrows" show-dots="false" label="Highlights">
37
+ <div>Fast setup</div>
38
+ <div>Secure by default</div>
39
+ </rel-carousel>
40
+
41
+ <!-- Loop and autoplay (3 s), 16px between slides, start on the second slide -->
42
+ <rel-carousel type="side-arrows" loop autoplay interval="3000" gap="16" value="1" label="Promotions">
43
+ <div>Spring sale</div>
44
+ <div>Free shipping</div>
45
+ <div>New arrivals</div>
46
+ </rel-carousel>
47
+
48
+ <!-- Figma Multi Panels: 1.5 panels leaves the next slide peeking in -->
49
+ <rel-carousel type="side-arrows" panels="1.5" label="Related products">
50
+ <div>Product A</div>
51
+ <div>Product B</div>
52
+ <div>Product C</div>
53
+ <div>Product D</div>
54
+ </rel-carousel>
55
+
56
+ <!-- Two whole panels at a time, no peek -->
57
+ <rel-carousel type="only-indicators" panels="2" label="Case studies">
58
+ <div>Case A</div>
59
+ <div>Case B</div>
60
+ <div>Case C</div>
61
+ <div>Case D</div>
62
+ </rel-carousel>
63
+
64
+ <!-- Vertical: the viewport height comes from --rel-carousel-height -->
65
+ <rel-carousel orientation="vertical" type="side-arrows" label="Timeline" style="--rel-carousel-height: 240px">
66
+ <div>2024</div>
67
+ <div>2025</div>
68
+ <div>2026</div>
69
+ </rel-carousel>
70
+
71
+ <!-- Programmatic control -->
72
+ <rel-carousel id="gallery" type="bottom-arrows" label="Gallery">
73
+ <div>A</div>
74
+ <div>B</div>
75
+ <div>C</div>
76
+ </rel-carousel>
77
+ <script>
78
+ const gallery = document.getElementById('gallery');
79
+ gallery.value = 2; // jump to the third slide
80
+ gallery.pauseOnHover = false; // default-true booleans are switched off via the property
81
+ gallery.addEventListener('rel-change', (e) => {
82
+ console.log('Current slide:', e.detail.value);
83
+ });
84
+ </script>
85
+ ```
86
+
87
+ <!-- readme-gen:start -->
88
+
89
+ <!-- Generated from rel-carousel.ts — do not edit; run readme-generate.mjs -->
90
+
91
+ ## API
92
+
93
+ ### Attributes / Properties
94
+
95
+ | Property | Attribute | Type | Default | Description |
96
+ | --- | --- | --- | --- | --- |
97
+ | `value` | `value` | `number` | `0` | Index of the current slide (0-based). Set it to jump; it is clamped to the slide count and reflected as an attribute. Reflected. |
98
+ | `loop` | `loop` | `boolean` | `false` | Wrap from the last slide to the first (and back) with a seamless clone transition instead of stopping at the ends. |
99
+ | `autoplay` | `autoplay` | `boolean` | `false` | Advance automatically every `interval` ms; implies looping and pauses while hovered (see `pause-on-hover`) or while focus is inside the carousel. |
100
+ | `interval` | `interval` | `number` | `5000` | Autoplay delay between slides, in milliseconds (default 5000). |
101
+ | `pauseOnHover` | `pause-on-hover` | `boolean` | `true` | Pause autoplay while the pointer is over the carousel or while dragging (default true; switch off with `pause-on-hover="false"` or `el.pauseOnHover = false`). |
102
+ | `showButtons` | `show-buttons` | `boolean` | `false` | Legacy toggle for the overlaid previous / next arrows; ignored whenever `type` is set. |
103
+ | `showDots` | `show-dots` | `boolean` | `undefined` | Figma "Show Dots" property. Tri-state: left off it defers to `type` (dots for every type except `default`, and nothing at all when `type` is unset too); `show-dots` turns them on; `show-dots="false"` turns them off even when `type` would have shown them. |
104
+ | `type` | `type` | `"default" \| "only-indicators" \| "side-arrows" \| "bottom-arrows"` | `undefined` | Figma "Type" axis. When set it drives which controls render: default = content only · only-indicators = dots · side-arrows = overlaid arrows + dots · bottom-arrows = dots flanked by arrows below the slide. When unset, the legacy show-buttons boolean applies unchanged. The dots a type implies can always be overridden by an explicit `show-dots`. Reflected. |
105
+ | `orientation` | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Slide axis: `horizontal` (default) translates the track left / right; `vertical` stacks slides in a fixed-height viewport (`--rel-carousel-height`) and translates up / down. Reflected. |
106
+ | `label` | `label` | `string` | `"Carousel"` | Accessible name of the carousel region (`aria-label` on the viewport); default "Carousel". |
107
+ | `gap` | `gap` | `number` | `8` | Space between consecutive slides in pixels (applied as the track `gap` and added to each slide step); default 8 (Figma `spacing/xs`), 0 = slides touch. |
108
+ | `panels` | `panels` | `number` | `1` | Figma "Multi Panels" axis, as a count: how many slides are visible at once (default 1). Fractions are allowed and produce a peek of the next slide — `panels="1.5"` reproduces the Figma Multi Panels=True variant. Navigation still advances one slide at a time. |
109
+ | `disabled` | `disabled` | `boolean` | `false` | Disables arrows, dots, drag and keyboard navigation, stops autoplay and renders the carousel at 60% opacity. Reflected. |
110
+
111
+ ## Events
112
+
113
+ | Event | Detail | Bubbles / composed | Description |
114
+ | --- | --- | --- | --- |
115
+ | `rel-change` | `{ value: this.value }` | bubbles / composed | Fired whenever the current slide changes (arrows, dots, drag, keyboard, autoplay or a loop wrap). Detail: `{ value: number }` — the new 0-based slide index. |
116
+
117
+ ## Slots
118
+
119
+ | Slot | Description |
120
+ | --- | --- |
121
+ | (default) | The slides: one light-DOM element per slide (each is sized to one panel and given `role="group"` / `aria-roledescription="slide"`). |
122
+
123
+ ## CSS Parts
124
+
125
+ | Part | Description |
126
+ | --- | --- |
127
+ | `${direction}-button` | The two arrow buttons, exposed as `prev-button` and `next-button` (`type="side-arrows"` overlays them on the viewport; `type="bottom-arrows"` inlines them in the dots row). |
128
+ | `viewport` | The focusable `role="region"` box that clips the track (also the keyboard target). |
129
+ | `track` | The flex row / column that translates to reveal the current slide. |
130
+ | `dots` | The indicator row under the viewport (also hosts the arrows for `type="bottom-arrows"`). |
131
+ | `dot-group` | The row of dots inside `dots` (for `type="bottom-arrows"` it is the middle child, between the two arrows). |
132
+ | `dot` | One indicator button per reachable position (per slide at `panels="1"`); the active one carries the `active` class and `aria-current="true"`. Since 1.5.0 the button is a transparent target cell of at least 24 × 24px and the visible dot is its `::before` (style it with `::part(dot)::before`). |
133
+
134
+ ## Tokens / CSS Variables
135
+
136
+ ### Component hooks
137
+
138
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
139
+
140
+ | Custom property | Default | Description |
141
+ | --- | --- | --- |
142
+ | `--rel-carousel-dot-size` | `8px` | Diameter of an inactive dot (default 8px); its target cell is at least 24px. |
143
+ | `--rel-carousel-dot-size-active` | `16px` | Width of the active (brand-coloured, pill-shaped) dot (default 16px); its target cell is at least 24px. |
144
+ | `--rel-carousel-height` | `320px` | Viewport height in `orientation="vertical"` (default 320px); the horizontal viewport takes the height of its tallest slide. |
145
+ | `--rel-carousel-nav-size` | `32px` | Width / height of the arrow buttons (default 32px, matching Figma; applies to both side and bottom arrows). |
146
+ | `--rel-carousel-slide-bg` | `var(--rel-bg-neutral)` | — |
147
+ | `--rel-carousel-slide-display` | `flex` | `display` given to each slide in `orientation="vertical"` only, which is what centres the slide's content in the fixed-height viewport as Figma draws it. Set it to `block` to opt out if forcing flex reflows your slide's own children. Horizontal slides are never touched. |
148
+ | `--rel-carousel-slide-height` | `100%` | Written by the component on its own host to the computed panel height (used for vertical slides); not meant to be set by consumers. |
149
+ | `--rel-carousel-slide-radius` | `var(--rel-border-radius-sm)` | — |
150
+ | `--rel-carousel-slide-width` | `100%` | Written by the component on its own host to the computed panel width (viewport width for `panels="1"`, a fraction of it above that); not meant to be set by consumers (an inline value is overwritten on resize). |
151
+
152
+ <!-- readme-gen:end -->
153
+
154
+ ## Accessibility
155
+
156
+ - The viewport renders with `role="region"`, `aria-roledescription="carousel"` and `aria-label` set from the `label` prop (default "Carousel"); give every carousel a meaningful `label`.
157
+ - Each slotted slide is decorated with `role="group"`, `aria-roledescription="slide"` and `aria-label="n of N"`; the clone slides used for looping are `aria-hidden="true"`.
158
+ - The arrow buttons are labelled "Previous slide" / "Next slide" and their chevrons are `aria-hidden`; each dot is labelled "Go to slide n" and the active dot carries `aria-current="true"`.
159
+ - The viewport is a single Tab stop (`tabindex="0"`); the arrows and dots that are rendered are ordinary buttons and follow it in the Tab order.
160
+ - Every user-initiated slide change is announced through the shared live region as "Slide n of N"; autoplay ticks are deliberately silent.
161
+ - Autoplay pauses while the pointer is over the carousel (`pause-on-hover`, default on) and while keyboard focus is anywhere inside it (WCAG 2.2.2 Pause, Stop, Hide); it resumes when focus leaves.
162
+ - Track transitions are disabled under `prefers-reduced-motion: reduce`; drag still snaps to the nearest slide, just without animation.
163
+
164
+ | Key | Action |
165
+ | --- | --- |
166
+ | `ArrowLeft` / `ArrowUp` | Previous slide (wraps when `loop` or `autoplay` is set) |
167
+ | `ArrowRight` / `ArrowDown` | Next slide (wraps when `loop` or `autoplay` is set) |
168
+ | `Home` | First slide |
169
+ | `End` | Last slide |
170
+ | `Tab` | Move between the viewport, the arrows and the dots |
171
+
172
+ Keys are handled on the viewport (and anything focused inside it) and are ignored while `disabled`.
173
+
174
+ ## Notes / Edge Cases
175
+
176
+ - `type` is the canonical control switch. When it is unset the legacy `show-buttons` boolean still decides whether arrows render; when it is set `show-buttons` is ignored (`type="default"` hides the arrows).
177
+ - `show-dots` is deliberately tri-state, because Figma's `Show Dots` is a property rather than part of the `Type` axis. Omit it and `type` decides, exactly as before; write `show-dots` to force the dots on; write `show-dots="false"` to force them off even for a `type` that would have shown them. Omitting it is what every pre-existing carousel does, so none of them change.
178
+ - `panels` implements the Figma `Multi Panels` axis. Each panel measures `(viewport − gap × (ceil(panels) − 1)) / panels` along the scroll axis — a viewport showing `n` panels contains `ceil(n) − 1` whole gaps, so at the Figma frame width of 350px with the default 8px gap, `panels="1.5"` yields exactly the 228px slide the design specifies.
179
+ - Navigation always advances one slide per step, never one page. Without `loop`, the track stops once the last slide is flush with the trailing edge instead of scrolling into empty space, so at `panels="1.5"` with three slides the reachable indices are `0` and `1`. The dot row follows that: one dot per reachable position, which is one per slide at `panels="1"` and whenever `loop` is on.
180
+ - Slides are sized by the component: every slotted element gets `width: var(--rel-carousel-slide-width)` (or the height equivalent in `orientation="vertical"`) with `!important`, where the variable is written on the host to the computed panel size. Style the inside of a slide freely, but do not rely on a slide's own `width` / `height`.
181
+ - `loop` and `autoplay` clone the edge slides into the shadow DOM so the wrap looks continuous — `ceil(panels)` of them at each end, since a viewport showing more than one panel would otherwise run out of slides mid-transition. `rel-change` still reports the real index (`0` … `N-1`) after the silent jump.
182
+ - Drag / swipe uses a 20% threshold of the panel size; shorter drags snap back. Dragging pauses autoplay (when `pause-on-hover` is on) and resumes it on release.
183
+ - `value` is clamped to the highest reachable index whenever the slot content changes; setting it out of range moves to the nearest valid slide.
184
+ - Arrows are 32px circles with a 16px chevron, matching Figma. Side arrows (`type="side-arrows"`) overlay the viewport at the vertical centre, inset 8px from the edge; bottom arrows (`type="bottom-arrows"`) sit inside the indicator row, 20px from the dots. Both are hand-rolled ghost-style buttons, not `<rel-button>`, and both are sized by `--rel-carousel-nav-size`. Per the published Figma set the arrows stay on the left and right edges in `orientation="vertical"` too.
185
+ - The active dot is a 16 × 8 fully-rounded brand pill and an inactive dot an 8px circle; `--rel-carousel-dot-size-active` and `--rel-carousel-dot-size` override them. Since 1.5.0 each dot sits in a target cell of at least 24 × 24px (WCAG 2.5.8 target size), so the indicator row is 24px tall (it was 8px). The cells touch, with no gap between them, so the visible dots sit 16px apart (three dots make a 72px row). The cell is transparent: `::part(dot)` styles the cell (and carries the focus ring), `::part(dot)::before` the visible dot. Also since 1.5.0, an inactive dot is filled with `--rel-bg-neutral-elevated-3` (it was `--rel-bg-neutral-elevated-2`), and the active pill keeps `--rel-bg-surface-brand` with a 1px inside edge in `--rel-text-default`. In forced-colours mode the dots paint in system colours (inactive `CanvasText`, active `Highlight` with a `CanvasText` edge) instead of disappearing.
186
+ - The horizontal viewport takes the height of its tallest slide; the vertical viewport is a fixed `--rel-carousel-height` (320px) — set it to fit your content.
187
+ - Arrow buttons are exposed as `::part(prev-button)` and `::part(next-button)`; the indicator row is `::part(dots)`, the dots inside it `::part(dot-group)` and `::part(dot)`.