@reliability-design/web 1.4.6 → 1.4.8

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 (148) hide show
  1. package/CHANGELOG.md +246 -49
  2. package/dist/components/rel-accordion/README.md +133 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +172 -61
  5. package/dist/components/rel-avatar/README.md +118 -130
  6. package/dist/components/rel-badge/README.md +97 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +190 -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 +186 -166
  13. package/dist/components/rel-checkbox/README.md +96 -75
  14. package/dist/components/rel-chip/README.md +138 -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 +88 -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-layout/README.md +34 -0
  21. package/dist/components/rel-menu/README.md +180 -151
  22. package/dist/components/rel-menubar/README.md +218 -329
  23. package/dist/components/rel-otp/README.md +171 -440
  24. package/dist/components/rel-pagination/README.md +100 -424
  25. package/dist/components/rel-popover/README.md +203 -568
  26. package/dist/components/rel-progress/README.md +88 -110
  27. package/dist/components/rel-radio/README.md +131 -138
  28. package/dist/components/rel-range-picker/README.md +165 -0
  29. package/dist/components/rel-resizable/README.md +199 -140
  30. package/dist/components/rel-segmented-button/README.md +156 -141
  31. package/dist/components/rel-select/README.md +156 -93
  32. package/dist/components/rel-sheet/README.md +168 -224
  33. package/dist/components/rel-skeleton/README.md +104 -0
  34. package/dist/components/rel-slider/README.md +131 -135
  35. package/dist/components/rel-snackbar/README.md +168 -134
  36. package/dist/components/rel-stepper/README.md +162 -160
  37. package/dist/components/rel-switch/README.md +117 -102
  38. package/dist/components/rel-tab/README.md +173 -163
  39. package/dist/components/rel-textfield/README.md +176 -69
  40. package/dist/components/rel-time-picker/README.md +122 -157
  41. package/dist/components/rel-toast/README.md +165 -148
  42. package/dist/components/rel-tooltip/README.md +119 -111
  43. package/dist/components/rel-upload/README.md +220 -0
  44. package/dist/index.d.mts +1726 -447
  45. package/dist/index.d.ts +1726 -447
  46. package/dist/index.js +13715 -10870
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +14018 -11163
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/styles/focus-ring.ts +84 -0
  51. package/dist/styles/vars.css +892 -866
  52. package/dist/{vars-XNMTSRVN.css → vars-DXX6QOAG.css} +892 -866
  53. package/package.json +3 -2
  54. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  55. package/dist/components/rel-alert/rel-alert.ts +0 -305
  56. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -720
  57. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  58. package/dist/components/rel-badge/rel-badge.ts +0 -175
  59. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  60. package/dist/components/rel-button/rel-button.ts +0 -560
  61. package/dist/components/rel-calendar/index.ts +0 -1
  62. package/dist/components/rel-calendar/rel-calendar.ts +0 -565
  63. package/dist/components/rel-card/rel-card.ts +0 -88
  64. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  65. package/dist/components/rel-carousel/index.ts +0 -1
  66. package/dist/components/rel-carousel/rel-carousel.ts +0 -723
  67. package/dist/components/rel-chart/README.md +0 -286
  68. package/dist/components/rel-chart/index.ts +0 -1
  69. package/dist/components/rel-chart/rel-chart.ts +0 -754
  70. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  71. package/dist/components/rel-chip/rel-chip.ts +0 -483
  72. package/dist/components/rel-container/rel-container.ts +0 -95
  73. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  74. package/dist/components/rel-date-picker/date-format.ts +0 -47
  75. package/dist/components/rel-date-picker/date-parse.test.ts +0 -116
  76. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  77. package/dist/components/rel-date-picker/index.ts +0 -1
  78. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  79. package/dist/components/rel-divider/rel-divider.ts +0 -54
  80. package/dist/components/rel-drawer/index.ts +0 -1
  81. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  82. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  83. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  84. package/dist/components/rel-layout/rel-layout.ts +0 -49
  85. package/dist/components/rel-menu/rel-menu.ts +0 -541
  86. package/dist/components/rel-menubar/index.ts +0 -2
  87. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  88. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  89. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  90. package/dist/components/rel-nav-menu/README.md +0 -289
  91. package/dist/components/rel-nav-menu/index.ts +0 -3
  92. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  93. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  94. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  95. package/dist/components/rel-navbar/README.md +0 -126
  96. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  97. package/dist/components/rel-otp/index.ts +0 -1
  98. package/dist/components/rel-otp/rel-otp.ts +0 -527
  99. package/dist/components/rel-pagination/index.ts +0 -1
  100. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  101. package/dist/components/rel-popover/index.ts +0 -2
  102. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  103. package/dist/components/rel-popover/rel-popover.ts +0 -475
  104. package/dist/components/rel-progress/rel-progress.ts +0 -234
  105. package/dist/components/rel-radio/rel-radio.ts +0 -481
  106. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  107. package/dist/components/rel-resizable/index.ts +0 -3
  108. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  109. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  110. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  111. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  112. package/dist/components/rel-select/rel-select.ts +0 -1416
  113. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  114. package/dist/components/rel-sidebar/README.md +0 -209
  115. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  116. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  117. package/dist/components/rel-slider/rel-slider.ts +0 -673
  118. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  119. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  120. package/dist/components/rel-switch/rel-switch.ts +0 -199
  121. package/dist/components/rel-tab/rel-tab.ts +0 -264
  122. package/dist/components/rel-table/README.md +0 -178
  123. package/dist/components/rel-table/rel-table-body.ts +0 -22
  124. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  125. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  126. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  127. package/dist/components/rel-table/rel-table-head.ts +0 -47
  128. package/dist/components/rel-table/rel-table-header.ts +0 -22
  129. package/dist/components/rel-table/rel-table-row.ts +0 -37
  130. package/dist/components/rel-table/rel-table.ts +0 -62
  131. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  132. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  133. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  134. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  135. package/dist/components/rel-toast/rel-toast.ts +0 -206
  136. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  137. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  138. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  139. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  140. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  141. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  142. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  144. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  145. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  146. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  147. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  148. package/dist/components/rel-upload/rel-upload.ts +0 -968
@@ -1,100 +1,88 @@
1
- # rel-divider
2
-
3
- ## Overview
4
- A simple divider component supporting horizontal and vertical orientations. Provides a visual separator line with configurable styling via CSS tokens.
5
-
6
- ## Usage
7
- ```html
8
- <!-- Horizontal divider (default) -->
9
- <p>Section 1</p>
10
- <rel-divider></rel-divider>
11
- <p>Section 2</p>
12
-
13
- <!-- Vertical divider -->
14
- <div style="display: flex; align-items: center; height: 50px;">
15
- <span>Item 1</span>
16
- <rel-divider orientation="vertical"></rel-divider>
17
- <span>Item 2</span>
18
- <rel-divider orientation="vertical"></rel-divider>
19
- <span>Item 3</span>
20
- </div>
21
-
22
- <!-- In a toolbar -->
23
- <div style="display: flex; gap: 16px; align-items: center;">
24
- <button>Action 1</button>
25
- <rel-divider orientation="vertical"></rel-divider>
26
- <button>Action 2</button>
27
- <rel-divider orientation="vertical"></rel-divider>
28
- <button>Action 3</button>
29
- </div>
30
-
31
- <!-- Between content sections -->
32
- <section>
33
- <h2>Section A</h2>
34
- <p>Content A</p>
35
- </section>
36
- <rel-divider></rel-divider>
37
- <section>
38
- <h2>Section B</h2>
39
- <p>Content B</p>
40
- </section>
41
- ```
42
-
43
- ## API
44
-
45
- ### Attributes/Properties
46
- | Name | Type | Default | Description |
47
- |------|------|---------|-------------|
48
- | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Divider orientation |
49
-
50
- ## Events
51
- None.
52
-
53
- ## Slots
54
- None.
55
-
56
- ## CSS Parts
57
- None exposed.
58
-
59
- ## Tokens / CSS Variables
60
-
61
- ### Semantic Tokens
62
- - `--rel-fonts-font-family` - Font family
63
- - `--rel-text-default` - Text color (not used visually, but set)
64
-
65
- ### Color Tokens
66
- - `--rel-border-default` - Divider line color
67
-
68
- ### Border Tokens
69
- - `--rel-stroke-sm` - Line thickness (width/height)
70
-
71
- ### Spacing Tokens
72
- - `--rel-spacing-md` - Margin around divider
73
-
74
- ## Accessibility
75
- - Uses `role="separator"` for proper ARIA semantics
76
- - Screen readers will announce the divider as a separator
77
-
78
- ### Keyboard Interactions
79
- - None (non-interactive element)
80
-
81
- ### Focus Behavior
82
- - Does not receive focus
83
-
84
- ## Notes / Edge Cases
85
- - **Horizontal orientation**:
86
- - `width: 100%`
87
- - `height: var(--rel-stroke-sm)`
88
- - `margin: var(--rel-spacing-md) 0` (vertical margin)
89
-
90
- - **Vertical orientation**:
91
- - `width: var(--rel-stroke-sm)`
92
- - `height: 100%`
93
- - `margin: 0 var(--rel-spacing-md)` (horizontal margin)
94
- - Uses `align-self: stretch` to fill parent height
95
-
96
- - The divider is purely visual and has `background: transparent` on the host element
97
- - The actual divider line is rendered by an internal `.rel-divider` div
98
- - For vertical dividers to work properly, the parent must have a defined height
99
- - Vertical dividers use `align-self: stretch` to match the parent's height
100
- - The divider is `display: block` on the host element
1
+ # rel-divider
2
+
3
+ A thin separator rule, horizontal or vertical, drawn with the neutral elevated background token at the small stroke width and padded by the medium spacing token. Use it to visually split sections, list groups or toolbar clusters. Do not use it purely as a spacer — use layout gaps for that.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Horizontal (default): full width, vertical margin -->
9
+ <section>
10
+ <h2>Section A</h2>
11
+ <p>Content A</p>
12
+ </section>
13
+ <rel-divider></rel-divider>
14
+ <section>
15
+ <h2>Section B</h2>
16
+ <p>Content B</p>
17
+ </section>
18
+
19
+ <!-- Vertical: give the parent a height or use a flex row -->
20
+ <div style="display: flex; align-items: center; height: 40px;">
21
+ <rel-button variant="ghost">Cut</rel-button>
22
+ <rel-divider orientation="vertical"></rel-divider>
23
+ <rel-button variant="ghost">Copy</rel-button>
24
+ <rel-divider orientation="vertical"></rel-divider>
25
+ <rel-button variant="ghost">Paste</rel-button>
26
+ </div>
27
+
28
+ <!-- Restyle through the part -->
29
+ <style>
30
+ .thick::part(base) {
31
+ height: 2px;
32
+ margin: 24px 0;
33
+ }
34
+ </style>
35
+ <rel-divider class="thick"></rel-divider>
36
+ ```
37
+
38
+ <!-- readme-gen:start -->
39
+
40
+ <!-- Generated from rel-divider.ts — do not edit; run readme-generate.mjs -->
41
+
42
+ ## API
43
+
44
+ ### Attributes / Properties
45
+
46
+ | Property | Attribute | Type | Default | Description |
47
+ | --- | --- | --- | --- | --- |
48
+ | `orientation` | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Axis of the rule: `horizontal` spans the full width with vertical margin; `vertical` is a full-height line with horizontal margin (the parent needs a defined height or a flex row). Mirrored to `aria-orientation` on the host. |
49
+
50
+ ## Events
51
+
52
+ | Event | Detail | Bubbles / composed | Description |
53
+ | --- | --- | --- | --- |
54
+ | — | — | — | This element emits no custom events. |
55
+
56
+ ## Slots
57
+
58
+ | Slot | Description |
59
+ | --- | --- |
60
+ | — | This element has no slots. |
61
+
62
+ ## CSS Parts
63
+
64
+ | Part | Description |
65
+ | --- | --- |
66
+ | `base` | The rendered rule — restyle thickness, colour or margin here. |
67
+
68
+ ## Tokens / CSS Variables
69
+
70
+ ### Component hooks
71
+
72
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
73
+
74
+ | Custom property | Default | Description |
75
+ | --- | --- | --- |
76
+ | `--rel-divider-spacing` | `var(--rel-spacing-md)` | Cross-axis margin around the rule; default 16px. Figma specifies none, so set it to `0` for strict parity — the default is kept for back-compat and is planned to become `0` in 3.0. |
77
+
78
+ <!-- readme-gen:end -->
79
+
80
+ ## Accessibility
81
+
82
+ - The host receives `role="separator"` when connected and `aria-orientation` (`horizontal` or `vertical`) on every update, so screen readers announce it as a separator in the right axis. The inner rule also carries `role="separator"`.
83
+ - Not focusable; no keyboard interaction.
84
+
85
+ ## Notes / Edge Cases
86
+
87
+ - **Vertical dividers need a height.** The vertical rule is `height: 100%` with `align-self: stretch`; inside a flex row it stretches to the row, otherwise the parent must have a definite height or the rule collapses to 0px.
88
+ - The host is `display: block` with a transparent background; the visible line is the inner `base` part. Override thickness, colour or margin via `::part(base)` rather than on the host.
@@ -1,200 +1,187 @@
1
- # RelDrawer Component
2
-
3
- A flexible, accessible drawer/sheet component for the Reliability Design System.
4
-
5
- ## Features
6
-
7
- - Slides from bottom (default), left, right, or top
8
- - Overlay/backdrop with configurable dismiss behavior
9
- - Drag-to-close for bottom drawers (touch & mouse)
10
- - Focus trapping for modal mode
11
- - Keyboard navigation (Escape to close, Tab trap)
12
- - Token-driven styling (no hardcoded colors)
13
- - Respects `prefers-reduced-motion`
14
- - Slot-based content API
15
-
16
- ## Basic Usage
17
-
18
- ```html
19
- <rel-drawer open>
20
- <h3 slot="title">Drawer Title</h3>
21
- <p slot="description">Optional description text</p>
22
-
23
- <p>Your drawer content goes here.</p>
24
-
25
- <div slot="footer">
26
- <button>Cancel</button>
27
- <button>Save</button>
28
- </div>
29
- </rel-drawer>
30
- ```
31
-
32
- ## Properties
33
-
34
- | Property | Type | Default | Description |
35
- |----------|------|---------|-------------|
36
- | `open` | `boolean` | `false` | Controls drawer visibility (reflects) |
37
- | `side` | `"bottom" \| "left" \| "right" \| "top"` | `"bottom"` | Edge from which drawer slides |
38
- | `dismissible` | `boolean` | `true` | Allows backdrop/Escape close |
39
- | `modal` | `boolean` | `true` | Enables focus trap and `aria-modal` |
40
- | `close-on-backdrop` | `boolean` | `true` | Close when clicking backdrop |
41
- | `close-on-escape` | `boolean` | `true` | Close when pressing Escape |
42
- | `show-handle` | `boolean` | `true` | Show handle bar (bottom drawer only) |
43
- | `draggable` | `boolean` | `true` | Enable drag-to-close (bottom only) |
44
- | `snap-threshold` | `number` | `0.25` | Drag distance % to trigger close |
45
- | `max-height` | `string` | `"80vh"` | Max height for bottom/top drawers |
46
- | `width` | `string` | `"420px"` | Width for left/right drawers |
47
- | `disabled` | `boolean` | `false` | Disables all interaction |
48
-
49
- ## Events
50
-
51
- | Event | Detail | Description |
52
- |-------|--------|-------------|
53
- | `rel-open-change` | `{ open: boolean }` | Fires when open state changes |
54
- | `rel-close` | `{ reason: "backdrop" \| "escape" \| "drag" \| "programmatic" }` | Fires when drawer closes |
55
-
56
- ## Slots
57
-
58
- | Slot | Description |
59
- |------|-------------|
60
- | (default) | Drawer content body |
61
- | `title` | Header title text |
62
- | `description` | Header description text |
63
- | `footer` | Footer content (buttons, actions) |
64
-
65
- ## CSS Parts
66
-
67
- | Part | Description |
68
- |------|-------------|
69
- | `overlay` | Backdrop element |
70
- | `panel` | Drawer panel container |
71
- | `handle` | Drag handle bar |
72
- | `header` | Header container |
73
- | `content` | Content container |
74
- | `footer` | Footer container |
75
- | `close-button` | Close button (X) |
76
-
77
- ## Examples
78
-
79
- ### Bottom Sheet (Mobile-style)
80
-
81
- ```html
82
- <rel-drawer open side="bottom" max-height="60vh">
83
- <h3 slot="title">Select an option</h3>
84
- <ul>
85
- <li>Option 1</li>
86
- <li>Option 2</li>
87
- <li>Option 3</li>
88
- </ul>
89
- </rel-drawer>
90
- ```
91
-
92
- ### Side Panel (Desktop Navigation)
93
-
94
- ```html
95
- <rel-drawer open side="right" width="300px">
96
- <h3 slot="title">Navigation</h3>
97
- <nav>
98
- <a href="/home">Home</a>
99
- <a href="/about">About</a>
100
- <a href="/contact">Contact</a>
101
- </nav>
102
- </rel-drawer>
103
- ```
104
-
105
- ### Programmatic Control
106
-
107
- ```javascript
108
- const drawer = document.querySelector('rel-drawer');
109
-
110
- // Open drawer
111
- drawer.open = true;
112
-
113
- // Close drawer
114
- drawer.open = false;
115
-
116
- // Listen for close event
117
- drawer.addEventListener('rel-close', (e) => {
118
- console.log('Closed via:', e.detail.reason);
119
- });
120
- ```
121
-
122
- ### Non-Modal Drawer
123
-
124
- ```html
125
- <rel-drawer open modal="false" dismissible="false">
126
- <!-- Doesn't trap focus, can't be dismissed -->
127
- <p>Persistent sidebar content</p>
128
- </rel-drawer>
129
- ```
130
-
131
- ## Accessibility
132
-
133
- - When `modal="true"`:
134
- - Sets `role="dialog"` and `aria-modal="true"`
135
- - Traps focus within drawer
136
- - Returns focus to trigger element on close
137
- - Locks body scroll to prevent background scrolling
138
- - Keyboard support:
139
- - `Escape`: Close drawer (if `close-on-escape`)
140
- - `Tab`: Cycle focus within drawer (if `modal`)
141
- - Screen reader: Announced as dialog when opened
142
-
143
- ## Styling
144
-
145
- The drawer uses design system tokens for all colors, spacing, shadows, and borders. You can customize appearance using CSS parts:
146
-
147
- ```css
148
- rel-drawer::part(overlay) {
149
- background: rgba(0, 0, 0, 0.7);
150
- }
151
-
152
- rel-drawer::part(panel) {
153
- box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);
154
- }
155
-
156
- rel-drawer::part(handle) {
157
- background: var(--rel-bg-info);
158
- }
159
- ```
160
-
161
- ## Framework Integration
162
-
163
- ### React
164
-
165
- ```jsx
166
- <RelDrawer
167
- open={isOpen}
168
- onRelClose={(e) => setIsOpen(false)}
169
- side="right"
170
- >
171
- <span slot="title">Settings</span>
172
- <SettingsForm />
173
- </RelDrawer>
174
- ```
175
-
176
- ### Angular
177
-
178
- ```html
179
- <rel-drawer
180
- [open]="isOpen"
181
- (rel-close)="isOpen = false"
182
- side="left"
183
- >
184
- <span slot="title">Menu</span>
185
- <app-menu></app-menu>
186
- </rel-drawer>
187
- ```
188
-
189
- ### Vue
190
-
191
- ```vue
192
- <rel-drawer
193
- :open="isOpen"
194
- @rel-close="isOpen = false"
195
- side="bottom"
196
- >
197
- <template #title>Options</template>
198
- <OptionsPanel />
199
- </rel-drawer>
200
- ```
1
+ # rel-drawer
2
+
3
+ `<rel-drawer>` implements the Figma **Drawer** component (5699:6844): a panel that slides in from the bottom, left or right edge over a scrim, with an optional drag-to-close handle on bottom drawers, a title/description header, a scrollable body and a footer. The folder also registers `<rel-drawer-footer>`, the right-aligned actions row the drawer uses for its `footer` slot, which can be reused standalone. Use a drawer for side navigation, filter panels and secondary editing flows that should stay attached to a viewport edge; use `<rel-modal>` for confirmations and short dialogs, and `<rel-popover>` for small contextual content anchored to a trigger.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Bottom drawer (default) with header, body and footer actions -->
9
+ <rel-button id="open-filters">Filters</rel-button>
10
+
11
+ <rel-drawer id="filters" title="Filters" description="Narrow down the results.">
12
+ <p>Filter controls go here.</p>
13
+ <rel-button slot="footer" variant="secondary" id="reset">Reset</rel-button>
14
+ <rel-button slot="footer" variant="primary" id="apply">Apply</rel-button>
15
+ </rel-drawer>
16
+
17
+ <script>
18
+ const drawer = document.getElementById('filters');
19
+ document.getElementById('open-filters').addEventListener('click', () => { drawer.open = true; });
20
+ document.getElementById('apply').addEventListener('click', () => { drawer.open = false; });
21
+ drawer.addEventListener('rel-open-change', (e) => {
22
+ console.log('open =', e.detail.open);
23
+ });
24
+ </script>
25
+
26
+ <!-- Right side panel with an explicit width -->
27
+ <rel-drawer side="right" width="360px" title="Settings">
28
+ <p>Account settings.</p>
29
+ </rel-drawer>
30
+
31
+ <!-- Left navigation drawer -->
32
+ <rel-drawer side="left" title="Menu">
33
+ <nav>
34
+ <a href="/home">Home</a>
35
+ <a href="/reports">Reports</a>
36
+ </nav>
37
+ </rel-drawer>
38
+
39
+ <!-- Bottom drawer that closes after a longer drag -->
40
+ <rel-drawer snap-threshold="0.5" title="Share">
41
+ <p>Drag the handle down past half the panel to close.</p>
42
+ </rel-drawer>
43
+
44
+ <!-- Non-modal, persistent side panel (no scrim, no focus trap, not dismissible) -->
45
+ <rel-drawer id="sidebar" side="left" open>
46
+ <p>Always-on sidebar content.</p>
47
+ </rel-drawer>
48
+ <script>
49
+ // Boolean props that default to true can only be switched off from JS —
50
+ // an absent attribute leaves the default in place.
51
+ const sidebar = document.getElementById('sidebar');
52
+ sidebar.modal = false;
53
+ sidebar.dismissible = false;
54
+ </script>
55
+
56
+ <!-- Standalone actions row using the same layout as the drawer footer -->
57
+ <rel-drawer-footer>
58
+ <rel-button variant="secondary">Cancel</rel-button>
59
+ <rel-button variant="primary">Save</rel-button>
60
+ </rel-drawer-footer>
61
+ ```
62
+
63
+ <!-- readme-gen:start -->
64
+
65
+ <!-- Generated from rel-drawer.ts, rel-drawer-footer.ts — do not edit; run readme-generate.mjs -->
66
+
67
+ ## Elements
68
+
69
+ | Element | Class | Source |
70
+ | --- | --- | --- |
71
+ | `<rel-drawer>` | `RelDrawer` | `rel-drawer.ts` |
72
+ | `<rel-drawer-footer>` | `RelDrawerFooter` | `rel-drawer-footer.ts` |
73
+
74
+ ## API
75
+
76
+ ### `<rel-drawer>`
77
+
78
+ #### Attributes / Properties
79
+
80
+ | Property | Attribute | Type | Default | Description |
81
+ | --- | --- | --- | --- | --- |
82
+ | `open` | `open` | `boolean` | `false` | Whether the drawer is shown. Toggle it to open/close; every change fires `rel-open-change`. Reflected. |
83
+ | `side` | `side` | `"bottom" \| "left" \| "right"` | `"bottom"` | Edge the panel slides in from. `bottom` is centred horizontally and supports the drag handle; `left`/`right` are full-height side panels. |
84
+ | `dismissible` | `dismissible` | `boolean` | `true` | When false the close button is hidden and backdrop clicks / Escape are ignored (drag-to-close still works). |
85
+ | `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. |
86
+ | `closeOnBackdrop` | `close-on-backdrop` | `boolean` | `true` | Close when the scrim is clicked. Only effective while `dismissible` is true. |
87
+ | `closeOnEscape` | `close-on-escape` | `boolean` | `true` | Close on the Escape key. Only effective while `dismissible` is true. |
88
+ | `showHandle` | `show-handle` | `boolean` | `true` | Show the grab bar above the header. Only rendered when `side="bottom"` and `draggable` is true. |
89
+ | `draggable` | `draggable` | `boolean` | `true` | Enable drag-to-close on the handle (pointer or touch). Bottom drawers only. |
90
+ | `snapThreshold` | `snap-threshold` | `number` | `0.25` | Fraction (0–1) of the panel height the user must drag down before release closes the drawer; shorter drags snap back. |
91
+ | `maxHeight` | `max-height` | `string` | `"80vh"` | Written to the panel as the `--drawer-max-height` custom property (any CSS length). No built-in rule reads it yet; use `--rel-drawer-height` to size a bottom drawer. |
92
+ | `width` | `width` | `string` | `""` | Explicit panel width (any CSS length). Empty by default, which uses the per-side `--rel-drawer-width` default. |
93
+ | `title` | `title` | `string` | `""` | Heading text (rendered as an `<h2>`, linked via `aria-labelledby`). |
94
+ | `description` | `description` | `string` | `""` | Supporting text under the title (linked via `aria-describedby`). |
95
+
96
+ ### Events
97
+
98
+ | Event | Detail | Bubbles / composed | Description |
99
+ | --- | --- | --- | --- |
100
+ | `rel-open-change` | `{ open: true } / { open: false }` | bubbles / composed | Fired whenever `open` changes, from any cause (prop set, close button, backdrop, Escape, drag). Detail: `{ open: boolean }`. |
101
+
102
+ ### Slots
103
+
104
+ | Slot | Description |
105
+ | --- | --- |
106
+ | (default) | Body content of the drawer |
107
+ | `footer` | Actions row; rendered inside a `<rel-drawer-footer>` (right-aligned, 8px gap) |
108
+
109
+ ### CSS Parts
110
+
111
+ | Part | Description |
112
+ | --- | --- |
113
+ | `overlay` | The full-viewport scrim behind the panel |
114
+ | `panel` | The sliding panel (role="dialog") |
115
+ | `handle` | The drag-to-close grab bar (bottom drawers only) |
116
+ | `header` | Header block holding title, description and close button |
117
+ | `close-button` | The "X" close button |
118
+ | `content` | Scrollable body wrapper around the default slot |
119
+ | `footer` | Footer wrapper around the `footer` slot |
120
+
121
+ ### Tokens / CSS Variables
122
+
123
+ #### Component hooks
124
+
125
+ Set these on the host (or an ancestor) to customise the element without touching design tokens.
126
+
127
+ | Custom property | Default | Description |
128
+ | --- | --- | --- |
129
+ | `--rel-drawer-height` | `var(--drawer-height, clamp(360px, 49vh, 600px))` | Panel height for `side="bottom"`; default `clamp(360px, 49vh, 600px)`. Left/right drawers are always full height |
130
+ | `--rel-drawer-scrim-opacity` | `1` | Opacity of the scrim while open; default `1` |
131
+ | `--rel-drawer-transition-duration` | `var(--drawer-transition-duration)` | Slide/scrim animation duration; default `0.3s` |
132
+ | `--rel-drawer-transition-timing` | `var(--drawer-transition-timing)` | Slide/scrim animation easing; default `cubic-bezier(0.32, 0.72, 0, 1)` |
133
+ | `--rel-drawer-width` | `var(--drawer-width, clamp(640px, 66vw, 952px))` | Panel width. Default `clamp(640px, 66vw, 952px)` for `side="bottom"`, `clamp(280px, 24vw, 420px)` for left/right. The `width` prop sets this on the panel and wins over a host value |
134
+
135
+ ### `<rel-drawer-footer>`
136
+
137
+ #### Attributes / Properties
138
+
139
+ | Property | Attribute | Type | Default | Description |
140
+ | --- | --- | --- | --- | --- |
141
+ | — | — | — | — | No public properties. |
142
+
143
+ ### Events
144
+
145
+ | Event | Detail | Bubbles / composed | Description |
146
+ | --- | --- | --- | --- |
147
+ | — | — | — | This element emits no custom events. |
148
+
149
+ ### Slots
150
+
151
+ | Slot | Description |
152
+ | --- | --- |
153
+ | (default) | Footer actions (typically `<rel-button>`s) |
154
+
155
+ ### CSS Parts
156
+
157
+ | Part | Description |
158
+ | --- | --- |
159
+ | — | None exposed. |
160
+
161
+ <!-- readme-gen:end -->
162
+
163
+ ## Accessibility
164
+
165
+ - 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.
166
+ - `aria-labelledby` points at the rendered `<h2>` when `title` is set, otherwise the panel carries `aria-label="Drawer"`; `aria-describedby` points at the description paragraph when `description` is set.
167
+ - The close button is a real `<button>` with `aria-label="Close"`. It is rendered whenever `dismissible` is on.
168
+ - Focus: on open in modal mode focus moves to the first focusable element inside the panel, or to the panel itself (`tabindex="-1"`). On close focus always returns to the element that was active before opening — resolved through shadow roots, so a `<rel-button>` opener gets focus back.
169
+ - Body scroll is locked while open; the scrollbar width is added as body padding so the page does not shift.
170
+ - The drag handle is pointer-only (`touch-action: none`); keyboard users close with `Escape` or the close button.
171
+ - `prefers-reduced-motion: reduce` removes the slide/fade transitions and hides the closed panel outright.
172
+
173
+ | Key | Action |
174
+ | --- | --- |
175
+ | `Escape` | Closes the drawer when `dismissible` and `close-on-escape` are on. |
176
+ | `Tab` / `Shift+Tab` | Cycles focus inside the panel while `modal` is on (focus trap); wraps at either end. |
177
+
178
+ ## Notes / Edge Cases
179
+
180
+ - Drag-to-close only exists for `side="bottom"` and only when `draggable` is on; the handle is additionally hidden when `show-handle` is off. Dragging is one-directional (down); release past `snap-threshold` × panel height closes, shorter drags snap back. The scrim fades in proportion to the drag. Drag still closes the drawer when `dismissible` is off.
181
+ - `rel-open-change` is the only event; it fires for every `open` change including programmatic ones. The exported `DrawerCloseReason` type is used internally only — the event detail does not carry a reason.
182
+ - Boolean props default to `true` (`dismissible`, `modal`, `close-on-backdrop`, `close-on-escape`, `show-handle`, `draggable`); an absent attribute keeps the default, so switch them off from JavaScript (`drawer.modal = false`).
183
+ - `width` is written to the panel as an inline `--rel-drawer-width`, so it wins over a `--rel-drawer-width` set on the host. Leave it empty to use the per-side defaults.
184
+ - `max-height` is written to the panel as `--drawer-max-height` but no rule reads it yet; size bottom drawers with `--rel-drawer-height` instead.
185
+ - After a left/right drawer finishes sliding in, its `transform` is dropped so `position: fixed` descendants (select menus, popovers, tooltips, date pickers) are no longer clipped to the panel. Bottom drawers keep their transform because it centres them.
186
+ - The footer wrapper (padding + top border) is always rendered, even when the `footer` slot is empty.
187
+ - Legacy hook aliases still honoured: `--drawer-width`, `--drawer-height`, `--drawer-transition-duration` and `--drawer-transition-timing` are read as fallbacks of the `--rel-drawer-*` hooks. `--rel-drawer-scrim-opacity` has no legacy alias.