@reliability-design/web 1.4.5 → 1.4.7

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 (142) hide show
  1. package/CHANGELOG.md +211 -49
  2. package/dist/components/rel-accordion/README.md +132 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +156 -61
  5. package/dist/components/rel-avatar/README.md +116 -130
  6. package/dist/components/rel-badge/README.md +98 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +160 -130
  9. package/dist/components/rel-calendar/README.md +109 -109
  10. package/dist/components/rel-card/README.md +75 -94
  11. package/dist/components/rel-cardmedia/README.md +100 -127
  12. package/dist/components/rel-carousel/README.md +184 -166
  13. package/dist/components/rel-checkbox/README.md +93 -75
  14. package/dist/components/rel-chip/README.md +132 -121
  15. package/dist/components/rel-container/README.md +107 -99
  16. package/dist/components/rel-date-picker/README.md +200 -289
  17. package/dist/components/rel-divider/README.md +78 -100
  18. package/dist/components/rel-drawer/README.md +187 -200
  19. package/dist/components/rel-kbd/README.md +141 -151
  20. package/dist/components/rel-menu/README.md +178 -151
  21. package/dist/components/rel-menubar/README.md +218 -329
  22. package/dist/components/rel-otp/README.md +170 -440
  23. package/dist/components/rel-pagination/README.md +100 -424
  24. package/dist/components/rel-popover/README.md +203 -568
  25. package/dist/components/rel-progress/README.md +88 -110
  26. package/dist/components/rel-radio/README.md +131 -135
  27. package/dist/components/rel-range-picker/README.md +162 -0
  28. package/dist/components/rel-resizable/README.md +199 -140
  29. package/dist/components/rel-segmented-button/README.md +155 -141
  30. package/dist/components/rel-select/README.md +154 -93
  31. package/dist/components/rel-sheet/README.md +168 -224
  32. package/dist/components/rel-skeleton/README.md +103 -0
  33. package/dist/components/rel-slider/README.md +130 -135
  34. package/dist/components/rel-snackbar/README.md +162 -134
  35. package/dist/components/rel-stepper/README.md +158 -160
  36. package/dist/components/rel-switch/README.md +108 -102
  37. package/dist/components/rel-tab/README.md +171 -163
  38. package/dist/components/rel-textfield/README.md +159 -69
  39. package/dist/components/rel-time-picker/README.md +122 -157
  40. package/dist/components/rel-toast/README.md +157 -148
  41. package/dist/components/rel-tooltip/README.md +108 -103
  42. package/dist/components/rel-upload/README.md +220 -0
  43. package/dist/index.d.mts +1387 -350
  44. package/dist/index.d.ts +1387 -350
  45. package/dist/index.js +5863 -3600
  46. package/dist/index.js.map +1 -1
  47. package/dist/index.mjs +5864 -3592
  48. package/dist/index.mjs.map +1 -1
  49. package/dist/styles/vars.css +877 -866
  50. package/dist/{vars-XNMTSRVN.css → vars-JHTUGNRG.css} +877 -866
  51. package/package.json +4 -3
  52. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  53. package/dist/components/rel-alert/rel-alert.ts +0 -305
  54. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -689
  55. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  56. package/dist/components/rel-badge/rel-badge.ts +0 -170
  57. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  58. package/dist/components/rel-button/rel-button.ts +0 -560
  59. package/dist/components/rel-calendar/index.ts +0 -1
  60. package/dist/components/rel-calendar/rel-calendar.ts +0 -519
  61. package/dist/components/rel-card/rel-card.ts +0 -88
  62. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  63. package/dist/components/rel-carousel/index.ts +0 -1
  64. package/dist/components/rel-carousel/rel-carousel.ts +0 -700
  65. package/dist/components/rel-chart/README.md +0 -286
  66. package/dist/components/rel-chart/index.ts +0 -1
  67. package/dist/components/rel-chart/rel-chart.ts +0 -754
  68. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  69. package/dist/components/rel-chip/rel-chip.ts +0 -472
  70. package/dist/components/rel-container/rel-container.ts +0 -95
  71. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  72. package/dist/components/rel-date-picker/date-format.ts +0 -47
  73. package/dist/components/rel-date-picker/index.ts +0 -1
  74. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1237
  75. package/dist/components/rel-divider/rel-divider.ts +0 -54
  76. package/dist/components/rel-drawer/index.ts +0 -1
  77. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  78. package/dist/components/rel-drawer/rel-drawer.ts +0 -604
  79. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  80. package/dist/components/rel-layout/rel-layout.ts +0 -49
  81. package/dist/components/rel-menu/rel-menu.ts +0 -535
  82. package/dist/components/rel-menubar/index.ts +0 -2
  83. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  84. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  85. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  86. package/dist/components/rel-nav-menu/README.md +0 -289
  87. package/dist/components/rel-nav-menu/index.ts +0 -3
  88. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  89. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  90. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  91. package/dist/components/rel-navbar/README.md +0 -126
  92. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  93. package/dist/components/rel-otp/index.ts +0 -1
  94. package/dist/components/rel-otp/rel-otp.ts +0 -517
  95. package/dist/components/rel-pagination/index.ts +0 -1
  96. package/dist/components/rel-pagination/rel-pagination.ts +0 -509
  97. package/dist/components/rel-popover/index.ts +0 -2
  98. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  99. package/dist/components/rel-popover/rel-popover.ts +0 -444
  100. package/dist/components/rel-progress/rel-progress.ts +0 -225
  101. package/dist/components/rel-radio/rel-radio.ts +0 -305
  102. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1331
  103. package/dist/components/rel-resizable/index.ts +0 -3
  104. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  105. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  106. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  107. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -213
  108. package/dist/components/rel-select/rel-select.ts +0 -1385
  109. package/dist/components/rel-sheet/rel-sheet.ts +0 -465
  110. package/dist/components/rel-sidebar/README.md +0 -209
  111. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1185
  112. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -134
  113. package/dist/components/rel-slider/rel-slider.ts +0 -670
  114. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -325
  115. package/dist/components/rel-stepper/rel-stepper.ts +0 -565
  116. package/dist/components/rel-switch/rel-switch.ts +0 -197
  117. package/dist/components/rel-tab/rel-tab.ts +0 -264
  118. package/dist/components/rel-table/README.md +0 -178
  119. package/dist/components/rel-table/rel-table-body.ts +0 -22
  120. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  121. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  122. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  123. package/dist/components/rel-table/rel-table-head.ts +0 -47
  124. package/dist/components/rel-table/rel-table-header.ts +0 -22
  125. package/dist/components/rel-table/rel-table-row.ts +0 -37
  126. package/dist/components/rel-table/rel-table.ts +0 -62
  127. package/dist/components/rel-textfield/rel-textfield.ts +0 -866
  128. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1126
  129. package/dist/components/rel-toast/rel-toast.ts +0 -204
  130. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -190
  131. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  132. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  133. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  134. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  135. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  136. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  137. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  138. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  139. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  140. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  141. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  142. package/dist/components/rel-upload/rel-upload.ts +0 -943
@@ -1,224 +1,168 @@
1
- # rel-sheet
2
-
3
- ## Overview
4
- A slide-in panel component system with multiple helper components. Features four slide directions (top, right, bottom, left), configurable sizes, modal/non-modal modes, focus trapping, scroll locking, and optional overlay. Built with composition: `rel-sheet` (controller), `rel-sheet-trigger` (opener), `rel-sheet-content` (panel), and layout helpers (`rel-sheet-header`, `rel-sheet-footer`, `rel-sheet-title`, `rel-sheet-description`, `rel-sheet-close`).
5
-
6
- ## Components
7
- - **`<rel-sheet>`**: Root wrapper that manages open state
8
- - **`<rel-sheet-trigger>`**: Button to open the sheet
9
- - **`<rel-sheet-content>`**: Slide-in panel with all visual elements
10
- - **`<rel-sheet-header>`**: Header layout helper with bottom border
11
- - **`<rel-sheet-footer>`**: Footer layout helper with top border
12
- - **`<rel-sheet-title>`**: Title text (auto-linked to `aria-labelledby`)
13
- - **`<rel-sheet-description>`**: Description text (auto-linked to `aria-describedby`)
14
- - **`<rel-sheet-close>`**: Custom close button wrapper
15
-
16
- ## Usage
17
- ```html
18
- <!-- Basic right-side sheet -->
19
- <rel-sheet>
20
- <rel-sheet-trigger>
21
- <button>Open Settings</button>
22
- </rel-sheet-trigger>
23
-
24
- <rel-sheet-content>
25
- <rel-sheet-header>
26
- <rel-sheet-title>Settings</rel-sheet-title>
27
- <rel-sheet-description>Configure your preferences</rel-sheet-description>
28
- </rel-sheet-header>
29
-
30
- <p>Sheet content goes here...</p>
31
-
32
- <rel-sheet-footer>
33
- <rel-sheet-close>
34
- <button>Cancel</button>
35
- </rel-sheet-close>
36
- <button>Save</button>
37
- </rel-sheet-footer>
38
- </rel-sheet-content>
39
- </rel-sheet>
40
-
41
- <!-- Left-side sheet, large size -->
42
- <rel-sheet>
43
- <rel-sheet-trigger>
44
- <button>Open Menu</button>
45
- </rel-sheet-trigger>
46
-
47
- <rel-sheet-content side="left" size="lg">
48
- <nav>
49
- <a href="#home">Home</a>
50
- <a href="#about">About</a>
51
- <a href="#contact">Contact</a>
52
- </nav>
53
- </rel-sheet-content>
54
- </rel-sheet>
55
-
56
- <!-- Bottom sheet without overlay -->
57
- <rel-sheet defaultopen>
58
- <rel-sheet-trigger>
59
- <button>Toggle Bottom Sheet</button>
60
- </rel-sheet-trigger>
61
-
62
- <rel-sheet-content side="bottom" hide-overlay>
63
- <p>Bottom sheet content</p>
64
- </rel-sheet-content>
65
- </rel-sheet>
66
-
67
- <!-- Controlled state -->
68
- <rel-sheet id="controlledSheet" open>
69
- <rel-sheet-trigger>
70
- <button>Open</button>
71
- </rel-sheet-trigger>
72
-
73
- <rel-sheet-content>
74
- <p>This sheet is controlled externally</p>
75
- </rel-sheet-content>
76
- </rel-sheet>
77
- <script>
78
- const sheet = document.getElementById('controlledSheet');
79
- sheet.addEventListener('rel-open-change', (e) => {
80
- console.log('Sheet open:', e.detail.open);
81
- console.log('Reason:', e.detail.reason);
82
- });
83
- </script>
84
-
85
- <!-- Without built-in close button -->
86
- <rel-sheet>
87
- <rel-sheet-trigger>
88
- <button>Open</button>
89
- </rel-sheet-trigger>
90
-
91
- <rel-sheet-content show-close="false">
92
- <p>Custom close handling</p>
93
- <rel-sheet-close>
94
- <button>Close Me</button>
95
- </rel-sheet-close>
96
- </rel-sheet-content>
97
- </rel-sheet>
98
- ```
99
-
100
- ## API
101
-
102
- ### rel-sheet Properties
103
- | Name | Type | Default | Description |
104
- |------|------|---------|-------------|
105
- | `open` (reflected) | `boolean?` | `undefined` | Controlled open state |
106
- | `defaultopen` | `boolean` | `false` | Default open state (uncontrolled) |
107
- | `disabled` | `boolean` | `false` | Disable trigger |
108
- | `modal` | `boolean` | `true` | Enable modal behavior (focus trap) |
109
-
110
- ### rel-sheet-content Properties
111
- | Name | Type | Default | Description |
112
- |------|------|---------|-------------|
113
- | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"right"` | Which side the sheet slides from |
114
- | `size` | `"sm" \| "md" \| "lg" \| "xl"` | `"md"` | Sheet width/height (320/420/540/640px) |
115
- | `hide-overlay` | `boolean` | `false` | Hide the backdrop overlay |
116
- | `close-on-overlay` | `boolean` | `true` | Allow closing by clicking overlay |
117
- | `show-close` | `boolean` | `true` | Show built-in close button (✕) |
118
-
119
- ## Events
120
- | Event | Detail | Description |
121
- |-------|--------|-------------|
122
- | `rel-open-change` | `{ open, reason }` | Fired when sheet opens/closes |
123
-
124
- ### Close Reasons
125
- - `"trigger"`: Toggled via trigger button
126
- - `"close"`: Closed via close button
127
- - `"overlay"`: Closed by clicking overlay
128
- - `"escape"`: Closed via Escape key
129
- - `"api"`: Changed via `setOpen()` method
130
-
131
- ## Methods
132
-
133
- ### Sheet Methods
134
- ```typescript
135
- sheet.setOpen(nextOpen: boolean, reason?: string): void
136
- ```
137
-
138
- ## Slots
139
- | Slot | Component | Description |
140
- |------|-----------|-------------|
141
- | (default) | `rel-sheet` | Trigger and content elements |
142
- | (default) | `rel-sheet-trigger` | Trigger button/element |
143
- | (default) | `rel-sheet-content` | Panel content |
144
- | (default) | Layout helpers | Content within headers/footers/titles |
145
-
146
- ## CSS Parts
147
- | Part | Description |
148
- |------|-------------|
149
- | `overlay` | Backdrop overlay element |
150
- | `panel` | Main panel container |
151
-
152
- ## Tokens / CSS Variables
153
-
154
- ### Size Tokens (defined on `<rel-sheet-content>`)
155
- - `--sheet-size-sm`: `320px`
156
- - `--sheet-size-md`: `420px`
157
- - `--sheet-size-lg`: `540px`
158
- - `--sheet-size-xl`: `640px`
159
-
160
- ### Transition Tokens
161
- - `--sheet-transition-duration`: `0.3s`
162
- - `--sheet-transition-timing`: `cubic-bezier(0.32, 0.72, 0, 1)`
163
-
164
- ### Color Tokens
165
- - `--rel-bg-surface` - Panel background
166
- - `--rel-text-label` - Title and close button color
167
- - `--rel-text-body` - Description color
168
- - `--rel-bg-surface-elevated` - Close button hover background
169
- - `--rel-border-default` - Header/footer borders
170
- - `--rel-overlay-scrim` - Overlay background
171
- - `--rel-bg-info` - Close button focus outline
172
-
173
- ### Shadow Tokens
174
- - `--rel-shadows-shadow-500` - Panel shadow
175
-
176
- ### Border Tokens
177
- - `--rel-border-radius-md` - Panel border radius (top corners for bottom, etc.)
178
-
179
- ### Spacing Tokens
180
- - `--rel-spacing-lg` - Panel content padding
181
- - `--rel-spacing-md` - Header/footer padding, close button positioning
182
- - `--rel-spacing-xs` - Close button padding
183
-
184
- ## Accessibility
185
- - Panel uses `role="dialog"` and `aria-modal`
186
- - Auto-links `aria-labelledby` to `<rel-sheet-title>`
187
- - Auto-links `aria-describedby` to `<rel-sheet-description>`
188
- - Focus trap in modal mode
189
- - Escape key closes sheet
190
- - Restores focus to trigger on close
191
-
192
- ### Keyboard Interactions
193
- | Key | Action |
194
- |-----|--------|
195
- | `Escape` | Close sheet |
196
- | `Tab` | Focus trap within sheet (modal mode only) |
197
-
198
- ### Focus Behavior
199
- - On open, focuses first focusable element (or panel if none found)
200
- - Focus trapped within panel in modal mode
201
- - On close, restores focus to trigger button
202
-
203
- ## Notes / Edge Cases
204
- - **Side positioning and transforms**:
205
- - **right**: Slides in from right edge, `translateX(100%)` to `translateX(0)`
206
- - **left**: Slides in from left edge, `translateX(-100%)` to `translateX(0)`
207
- - **bottom**: Slides in from bottom, `translateY(100%)` to `translateY(0)`
208
- - **top**: Slides in from top, `translateY(-100%)` to `translateY(0)`
209
-
210
- - **Size constraints**:
211
- - Left/right: `max-width: 90vw`
212
- - Top/bottom: `max-height: 80vh`
213
-
214
- - **Scroll locking**: Body scroll is locked when sheet is open (with scrollbar width compensation)
215
- - **Close button position**: Top-right by default, but top-left for `side="left"`
216
- - **Reduced motion**: Transitions disabled, panel hidden via `display: none` instead of transform
217
- - The sheet root uses `display: contents`
218
- - Panel is overlaid with `z-index: 1000`, fixed position
219
- - Overlay detection for `aria-labelledby`/`aria-describedby` happens automatically based on slotted `<rel-sheet-title>` and `<rel-sheet-description>` elements
220
- - Built-in close button is "✕" character at font-size 20px
221
-
222
- ### Controlled vs Uncontrolled
223
- - If `open` prop is set, the sheet is controlled and won't manage its own state
224
- - Use `rel-open-change` event to sync controlled state
1
+ # rel-modal
2
+
3
+ `<rel-modal>` is the design system's modal dialog and implements the Figma **Modal Sheet** component (8171:3412): a panel anchored to the bottom, top or centre of the viewport over a scrim, with a title/description header, a scrollable body, an optional right-aligned footer and a built-in loading state. It lives in the `rel-sheet` folder and is exported as the `RelModal` class — there is no separate sheet element; the "sheet" is the `side="bottom"` / `side="top"` presentation of this one element. Use it for confirmations, short forms and messages that must interrupt the page. For edge-anchored panels that hold navigation or longer editing flows use `<rel-drawer>`; for lightweight contextual content anchored to a trigger use `<rel-popover>`.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Bottom sheet (default) with header, body and footer actions -->
9
+ <rel-button id="open-delete">Delete project</rel-button>
10
+
11
+ <rel-modal id="delete-modal" title="Delete project?" description="This action cannot be undone.">
12
+ <p>All files and history for <strong>Acme Rollout</strong> will be removed.</p>
13
+ <rel-button slot="footer" variant="secondary" id="cancel">Cancel</rel-button>
14
+ <rel-button slot="footer" tone="destructive" id="confirm">Delete</rel-button>
15
+ </rel-modal>
16
+
17
+ <script>
18
+ const modal = document.getElementById('delete-modal');
19
+ document.getElementById('open-delete').addEventListener('click', () => { modal.open = true; });
20
+ document.getElementById('cancel').addEventListener('click', () => { modal.open = false; });
21
+ modal.addEventListener('rel-open-change', (e) => {
22
+ console.log('open =', e.detail); // true | false
23
+ });
24
+ </script>
25
+
26
+ <!-- Centred dialog, small width -->
27
+ <rel-modal side="center" size="sm" title="Session expired" description="Sign in again to continue.">
28
+ <rel-button slot="footer" variant="primary">Sign in</rel-button>
29
+ </rel-modal>
30
+
31
+ <!-- Top-anchored sheet with extra header content -->
32
+ <rel-modal side="top" size="lg" title="New release">
33
+ <rel-tab slot="header" size="small">
34
+ <rel-tab-item slot="items" label="Summary"></rel-tab-item>
35
+ <rel-tab-item slot="items" label="Details"></rel-tab-item>
36
+ </rel-tab>
37
+ <p>Release notes go here.</p>
38
+ </rel-modal>
39
+
40
+ <!-- Message-only body (Figma "Text" slot) -->
41
+ <rel-modal variant="text" side="center" title="Saved" open>
42
+ <p>Your changes were saved.</p>
43
+ <p>You can close this window.</p>
44
+ </rel-modal>
45
+
46
+ <!-- Fullscreen, fixed desktop layout at every viewport width -->
47
+ <rel-modal size="fullscreen" breakpoint="web" title="Editor">
48
+ <p>Edge-to-edge content.</p>
49
+ </rel-modal>
50
+
51
+ <!-- Loading and locked states -->
52
+ <rel-modal title="Publishing…" loading open>
53
+ <p>Please wait.</p>
54
+ </rel-modal>
55
+ <rel-modal title="Processing" disabled open>
56
+ <p>Closing is blocked until the job finishes.</p>
57
+ <rel-button slot="footer">Done</rel-button>
58
+ </rel-modal>
59
+
60
+ <!-- Non-dismissible: no close button, backdrop and Escape ignored -->
61
+ <rel-modal id="locked" title="Accept terms">
62
+ <p>You must accept to continue.</p>
63
+ <rel-button slot="footer" variant="primary">Accept</rel-button>
64
+ </rel-modal>
65
+ <script>
66
+ // Boolean props that default to true can only be switched off from JS —
67
+ // an absent attribute leaves the default in place.
68
+ document.getElementById('locked').dismissible = false;
69
+ </script>
70
+ ```
71
+
72
+ <!-- readme-gen:start -->
73
+
74
+ <!-- Generated from rel-sheet.ts — do not edit; run readme-generate.mjs -->
75
+
76
+ ## API
77
+
78
+ ### Attributes / Properties
79
+
80
+ | Property | Attribute | Type | Default | Description |
81
+ | --- | --- | --- | --- | --- |
82
+ | `open` | `open` | `boolean` | `false` | Whether the modal is shown. Toggle it to open/close; every change fires `rel-open-change`. Reflected. |
83
+ | `side` | `side` | `"top" \| "bottom" \| "center"` | `"bottom"` | Where the panel is anchored: `bottom` (48px above the bottom edge, slides up), `top` (48px below the top edge, slides down) or `center` (fades and scales in). Below 480px with `breakpoint="responsive"` every side collapses to a full-width bottom sheet. |
84
+ | `title` | `title` | `string` | `""` | Heading text (rendered as an `<h2>`, linked via `aria-labelledby`). The `title` attribute is stripped from the host after it is read so no native tooltip appears. |
85
+ | `description` | `description` | `string` | `""` | Supporting text under the title (linked via `aria-describedby`). |
86
+ | `subtitle` | `subtitle` | `string` | `""` | Alias for `description`; rendered only when `description` is empty. |
87
+ | `dismissible` | `dismissible` | `boolean` | `true` | Coarse dismissal switch. When false the close button is hidden and backdrop clicks / Escape are ignored regardless of the granular `close-on-*` / `show-close-button` props. |
88
+ | `modal` | `modal` | `boolean` | `true` | Modal mode: renders the scrim, sets `role="dialog"` + `aria-modal`, traps Tab inside the panel and moves focus in on open. When false the panel is a `region` with no scrim and no focus trap. |
89
+ | `size` | `size` | `"sm" \| "md" \| "lg" \| "xl" \| "fullscreen"` | `"md"` | Panel width scale. `md` matches the Figma Modal Sheet width; `fullscreen` covers the viewport. Reflected. |
90
+ | `variant` | `variant` | `"default" \| "text"` | `"default"` | Body treatment — see `ModalVariant`. `"text"` styles the default slot as the Figma "Text" message slot; the header (and its divider) render as usual above it. Default rendering is unchanged. Reflected. |
91
+ | `closeOnBackdropClick` | `close-on-backdrop-click` | `boolean` | `true` | Close when the scrim is clicked. Only effective while `dismissible` is true; ignored while `disabled` or `loading`. |
92
+ | `closeOnEscape` | `close-on-escape` | `boolean` | `true` | Close on the Escape key. Only effective while `dismissible` is true; ignored while `disabled`. |
93
+ | `showCloseButton` | `show-close-button` | `boolean` | `true` | Render the "X" close button in the header. Only effective while `dismissible` is true. |
94
+ | `autoFocus` | `auto-focus` | `boolean` | `true` | Move focus into the panel when opened (modal mode only). |
95
+ | `restoreFocus` | `restore-focus` | `boolean` | `true` | Return focus to the opener when closed. |
96
+ | `scrollable` | `scrollable` | `boolean` | `true` | When false, the body no longer scrolls internally — tall content clips at the panel's max height. |
97
+ | `loading` | `loading` | `boolean` | `false` | Shows a spinner overlay and blocks all interaction inside the panel. Reflected. |
98
+ | `disabled` | `disabled` | `boolean` | `false` | Blocks user-initiated closes (X / backdrop / Escape) and footer actions. Reflected. |
99
+ | `zIndex` | `z-index` | `number` | `1000` | Stacking order of the whole modal (backdrop + panel). |
100
+ | `breakpoint` | `breakpoint` | `"responsive" \| "web"` | `"responsive"` | Figma "Breakpoint" axis. responsive (default) collapses to a full-width bottom sheet below 480px; web keeps the fixed desktop panel at every size. Reflected. |
101
+
102
+ ## Events
103
+
104
+ | Event | Detail | Bubbles / composed | Description |
105
+ | --- | --- | --- | --- |
106
+ | `rel-open-change` | `true / false` | bubbles / composed | Fired whenever `open` changes, from any cause (prop set, close button, backdrop, Escape). Detail: the new `open` boolean. |
107
+
108
+ ## Slots
109
+
110
+ | Slot | Description |
111
+ | --- | --- |
112
+ | (default) | Body content of the modal |
113
+ | `header` | Extra header content rendered under the title/description (e.g. a stepper or tabs) |
114
+ | `footer` | Actions row (right-aligned, 8px gap); the footer only renders when this slot has content |
115
+
116
+ ## CSS Parts
117
+
118
+ | Part | Description |
119
+ | --- | --- |
120
+ | `overlay` | The full-viewport scrim behind the panel |
121
+ | `panel` | The dialog panel (role="dialog") |
122
+ | `header` | Header row holding title, description, header slot and close button |
123
+ | `close-button` | The "X" close button |
124
+ | `content` | Scrollable body wrapper around the default slot |
125
+ | `footer` | Footer wrapper around the `footer` slot |
126
+ | `loading` | Spinner overlay shown while `loading` is set |
127
+
128
+ ## Tokens / CSS Variables
129
+
130
+ ### Component hooks
131
+
132
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
133
+
134
+ | Custom property | Default | Description |
135
+ | --- | --- | --- |
136
+ | `--rel-modal-transition-duration` | `var(--modal-transition-duration)` | Open/close animation duration; default `0.3s` |
137
+ | `--rel-modal-transition-timing` | `var(--modal-transition-timing)` | Open/close animation easing; default `cubic-bezier(0.32, 0.72, 0, 1)` |
138
+ | `--rel-modal-width` | `var(--modal-width)` | Panel width; overrides the `size` scale (md default `clamp(360px, 49vw, 708px)`, sm `min(400px, 100vw - 32px)`, lg `min(900px, 100vw - 48px)`, xl `min(1140px, 100vw - 48px)`). Ignored by `fullscreen` and by the responsive collapse below 480px |
139
+
140
+ <!-- readme-gen:end -->
141
+
142
+ ## Accessibility
143
+
144
+ - The panel is `role="dialog"` with `aria-modal="true"` while `modal` is on; with `modal` off it becomes a `role="region"` without scrim or focus trap.
145
+ - `aria-labelledby` points at the rendered `<h2>` when `title` is set, otherwise the panel carries `aria-label="Dialog"`; `aria-describedby` points at the description paragraph when `description` (or `subtitle`) is set.
146
+ - While `loading` the panel has `aria-busy="true"` and the header, body and footer are made `inert`; while `disabled` only the footer is `inert` and the close button is disabled.
147
+ - The close button is a real `<button>` with `aria-label="Close"`.
148
+ - Focus: on open (modal + `auto-focus`) focus moves to the first focusable element inside the panel, or to the panel itself (`tabindex="-1"`). On close (`restore-focus`) focus returns to the element that was active before opening — resolved through shadow roots, so a `<rel-button>` opener gets focus back.
149
+ - Body scroll is locked while open; the scrollbar width is added as body padding so the page does not shift.
150
+ - `prefers-reduced-motion: reduce` removes the slide/fade transitions and hides the closed panel outright.
151
+
152
+ | Key | Action |
153
+ | --- | --- |
154
+ | `Escape` | Closes the modal when `dismissible` and `close-on-escape` are on and the modal is not `disabled`. |
155
+ | `Tab` / `Shift+Tab` | Cycles focus inside the panel while `modal` is on (focus trap); wraps at either end. |
156
+
157
+ ## Notes / Edge Cases
158
+
159
+ - `title` is also HTML's global tooltip attribute. The component reads the attribute into the property and then removes it from the host, so no native tooltip appears over the modal or its scrim.
160
+ - `subtitle` is an alias for `description` and is only rendered when `description` is empty.
161
+ - The footer is only rendered when the `footer` slot has content; the host gains a `has-footer` attribute while it does.
162
+ - `dismissible` is the coarse switch and is ANDed with `close-on-backdrop-click`, `close-on-escape` and `show-close-button`; turning it off locks all three regardless of their own values.
163
+ - `loading` blocks backdrop clicks and the close button but does **not** block `Escape`; set `disabled` (or `close-on-escape` = false) if Escape must be blocked as well.
164
+ - Boolean props default to `true` (`dismissible`, `modal`, `close-on-*`, `show-close-button`, `auto-focus`, `restore-focus`, `scrollable`); an absent attribute keeps the default, so switch them off from JavaScript (`modal.closeOnEscape = false`).
165
+ - `size` picks the panel width; `--rel-modal-width` overrides it for every size except `fullscreen`. Below 480px with `breakpoint="responsive"` every side and size (except `fullscreen`) collapses to a full-width bottom sheet, ignoring the width hook.
166
+ - `z-index` is applied to the whole fixed container (scrim + panel); use it when the modal must sit above other stacked UI such as a toast region.
167
+ - Legacy hook aliases still honoured: `--modal-transition-duration`, `--modal-transition-timing` and `--modal-width` are read as fallbacks of the `--rel-modal-*` hooks. Note `--modal-width` is also set internally per `size`, so only the canonical `--rel-modal-width` reliably overrides the width from outside.
168
+ - The old `<rel-sheet>` / `<rel-sheet-*>` element family described in earlier docs was never shipped; this element is the only export of the folder.
@@ -0,0 +1,103 @@
1
+ # rel-skeleton
2
+
3
+ Loading placeholder that reserves the space of content still being fetched: a neutral `block`, a `circle` (avatars, icons) or a stack of text `line` bars, animated with a `pulse` or `shimmer` until you set `loaded`, at which point it hides itself. Use it when you know the shape of the incoming content (cards, list rows, avatars); use a spinner for indeterminate waits with no layout to preserve.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Block (default): fills its container, height set explicitly -->
9
+ <rel-skeleton height="160px"></rel-skeleton>
10
+
11
+ <!-- Circle: only a width is needed, the aspect ratio keeps it round -->
12
+ <rel-skeleton shape="circle" width="48px"></rel-skeleton>
13
+
14
+ <!-- Paragraph: three text bars, the last one shorter -->
15
+ <rel-skeleton shape="line" lines="3"></rel-skeleton>
16
+
17
+ <!-- Animation variants -->
18
+ <rel-skeleton shape="line" lines="2" animation="shimmer"></rel-skeleton>
19
+ <rel-skeleton shape="block" height="80px" animation="none"></rel-skeleton>
20
+
21
+ <!-- Custom colours -->
22
+ <rel-skeleton
23
+ shape="block"
24
+ height="120px"
25
+ animation="shimmer"
26
+ style="--rel-skeleton-color: #e5e7eb; --rel-skeleton-highlight: #f9fafb;"
27
+ ></rel-skeleton>
28
+
29
+ <!-- A list-row placeholder that swaps for real content -->
30
+ <div style="display: flex; gap: 12px; align-items: center;">
31
+ <rel-skeleton id="avatar" shape="circle" width="40px"></rel-skeleton>
32
+ <div style="flex: 1;">
33
+ <rel-skeleton id="text" shape="line" lines="2"></rel-skeleton>
34
+ </div>
35
+ </div>
36
+ <script>
37
+ fetchUser().then(() => {
38
+ document.getElementById('avatar').loaded = true;
39
+ document.getElementById('text').loaded = true;
40
+ });
41
+ </script>
42
+ ```
43
+
44
+ <!-- readme-gen:start -->
45
+
46
+ <!-- Generated from rel-skeleton.ts — do not edit; run readme-generate.mjs -->
47
+
48
+ ## API
49
+
50
+ ### Attributes / Properties
51
+
52
+ | Property | Attribute | Type | Default | Description |
53
+ | --- | --- | --- | --- | --- |
54
+ | `shape` | `shape` | `"line" \| "circle" \| "block"` | `"block"` | Placeholder shape: `block` fills the host (min 16px tall), `circle` is a square-aspect disc sized by the host width, `line` renders `lines` 14px text bars with the last one at 65% width. Reflected. |
55
+ | `lines` | `lines` | `number` | `1` | Number of text bars when `shape="line"` (minimum 1, 8px apart); ignored by the other shapes. |
56
+ | `width` | `width` | `string` | `""` | Any CSS width (e.g. `"240px"`, `"50%"`) applied to the host's inline style. Empty leaves the host at its natural block width. |
57
+ | `height` | `height` | `string` | `""` | Any CSS height (e.g. `"120px"`) applied to the host's inline style. Not needed for `circle`, which derives its height from the width. |
58
+ | `animation` | `animation` | `"pulse" \| "shimmer" \| "none"` | `"pulse"` | Motion: `pulse` fades opacity between 100% and 40%, `shimmer` sweeps a highlight band left to right, `none` is static. Both animations are disabled under `prefers-reduced-motion: reduce`. Reflected. |
59
+ | `loaded` | `loaded` | `boolean` | `false` | Set once the real content is ready: hides the skeleton (`display: none`) and removes its `role="status"` / "Loading" label. Reflected. |
60
+
61
+ ## Events
62
+
63
+ | Event | Detail | Bubbles / composed | Description |
64
+ | --- | --- | --- | --- |
65
+ | — | — | — | This element emits no custom events. |
66
+
67
+ ## Slots
68
+
69
+ | Slot | Description |
70
+ | --- | --- |
71
+ | — | This element has no slots. |
72
+
73
+ ## CSS Parts
74
+
75
+ | Part | Description |
76
+ | --- | --- |
77
+ | `base` | Each placeholder surface: the single block/circle, or every bar when `shape="line"`. |
78
+
79
+ ## Tokens / CSS Variables
80
+
81
+ ### Component hooks
82
+
83
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
84
+
85
+ | Custom property | Default | Description |
86
+ | --- | --- | --- |
87
+ | `--rel-skeleton-color` | `var(--rel-bg-neutral-elevated-3)` | Fill colour of the placeholder (defaults to the elevated-3 neutral background token). |
88
+ | `--rel-skeleton-highlight` | `var(--rel-bg-neutral-elevated-2)` | Lighter band that sweeps across the placeholder when `animation="shimmer"` (defaults to the elevated-2 neutral background token). |
89
+
90
+ <!-- readme-gen:end -->
91
+
92
+ ## Accessibility
93
+
94
+ - While not `loaded`, the host carries `role="status"` and `aria-label="Loading"`, so assistive technology announces that the region is loading; both are removed once `loaded` is set (the attributes are managed on each update, so they appear after the first render).
95
+ - The placeholder is not focusable and has no keyboard interaction.
96
+ - Under `prefers-reduced-motion: reduce` both `pulse` and `shimmer` are disabled and the placeholder renders static.
97
+
98
+ ## Notes / Edge Cases
99
+
100
+ - **Sizing.** `width` / `height` are written to the host's inline `style` and accept any CSS length. A `block` with no `height` is 16px tall (its `min-height`); a `circle` needs only a width (`aspect-ratio: 1 / 1`); `line` bars are 14px tall, 8px apart, full width, with the last bar at 65% when there is more than one.
101
+ - **`loaded` hides, it does not remove.** The host switches to `display: none` and stays in the DOM; place the real content as a sibling rather than inside the skeleton (the element has no slot).
102
+ - **Multiple `base` parts.** With `shape="line"` every bar carries `part="base"`, so `::part(base)` styles all of them.
103
+ - **Shimmer overrides the fill.** In `shimmer` mode the background becomes a gradient built from `--rel-skeleton-color` and `--rel-skeleton-highlight`; set both when customising colours.