@reliability-design/web 1.4.6 → 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 (146) 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 -138
  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 -111
  42. package/dist/components/rel-upload/README.md +220 -0
  43. package/dist/index.d.mts +1147 -340
  44. package/dist/index.d.ts +1147 -340
  45. package/dist/index.js +3451 -3163
  46. package/dist/index.js.map +1 -1
  47. package/dist/index.mjs +3416 -3118
  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 +3 -2
  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 -720
  55. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  56. package/dist/components/rel-badge/rel-badge.ts +0 -175
  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 -565
  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 -723
  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 -483
  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/date-parse.test.ts +0 -116
  74. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  75. package/dist/components/rel-date-picker/index.ts +0 -1
  76. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  77. package/dist/components/rel-divider/rel-divider.ts +0 -54
  78. package/dist/components/rel-drawer/index.ts +0 -1
  79. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  80. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  81. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  82. package/dist/components/rel-layout/rel-layout.ts +0 -49
  83. package/dist/components/rel-menu/rel-menu.ts +0 -541
  84. package/dist/components/rel-menubar/index.ts +0 -2
  85. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  86. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  87. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  88. package/dist/components/rel-nav-menu/README.md +0 -289
  89. package/dist/components/rel-nav-menu/index.ts +0 -3
  90. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  91. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  92. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  93. package/dist/components/rel-navbar/README.md +0 -126
  94. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  95. package/dist/components/rel-otp/index.ts +0 -1
  96. package/dist/components/rel-otp/rel-otp.ts +0 -527
  97. package/dist/components/rel-pagination/index.ts +0 -1
  98. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  99. package/dist/components/rel-popover/index.ts +0 -2
  100. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  101. package/dist/components/rel-popover/rel-popover.ts +0 -475
  102. package/dist/components/rel-progress/rel-progress.ts +0 -234
  103. package/dist/components/rel-radio/rel-radio.ts +0 -481
  104. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  105. package/dist/components/rel-resizable/index.ts +0 -3
  106. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  107. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  108. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  109. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  110. package/dist/components/rel-select/rel-select.ts +0 -1416
  111. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  112. package/dist/components/rel-sidebar/README.md +0 -209
  113. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  114. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  115. package/dist/components/rel-slider/rel-slider.ts +0 -673
  116. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  117. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  118. package/dist/components/rel-switch/rel-switch.ts +0 -199
  119. package/dist/components/rel-tab/rel-tab.ts +0 -264
  120. package/dist/components/rel-table/README.md +0 -178
  121. package/dist/components/rel-table/rel-table-body.ts +0 -22
  122. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  123. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  124. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  125. package/dist/components/rel-table/rel-table-head.ts +0 -47
  126. package/dist/components/rel-table/rel-table-header.ts +0 -22
  127. package/dist/components/rel-table/rel-table-row.ts +0 -37
  128. package/dist/components/rel-table/rel-table.ts +0 -62
  129. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  130. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  131. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  132. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  133. package/dist/components/rel-toast/rel-toast.ts +0 -206
  134. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  135. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  136. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  137. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  138. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  139. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  140. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  141. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  142. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  144. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  145. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  146. package/dist/components/rel-upload/rel-upload.ts +0 -968
@@ -1,289 +0,0 @@
1
- # rel-nav-menu
2
-
3
- A horizontal navigation menu component with dropdown panels, perfect for top-level site navigation. Features keyboard navigation, accessible ARIA attributes, and token-driven styling.
4
-
5
- ## What It Is
6
-
7
- The navigation menu consists of three custom elements:
8
- - `<rel-nav-menu>` - Root container that manages navigation state and interactions
9
- - `<rel-nav-menu-item>` - Individual navigation items (can be links or dropdown triggers)
10
- - `<rel-nav-menu-panel>` - Styled container for dropdown content
11
-
12
- ## Basic Usage
13
-
14
- ```html
15
- <rel-nav-menu>
16
- <rel-nav-menu-item label="Features" href="#features"></rel-nav-menu-item>
17
- <rel-nav-menu-item label="Pricing" href="#pricing"></rel-nav-menu-item>
18
- <rel-nav-menu-item label="About" href="#about"></rel-nav-menu-item>
19
- <rel-nav-menu-item label="Contact" href="#contact"></rel-nav-menu-item>
20
- </rel-nav-menu>
21
- ```
22
-
23
- ## Dropdown with Content
24
-
25
- ```html
26
- <rel-nav-menu>
27
- <rel-nav-menu-item label="Getting started">
28
- <rel-nav-menu-panel>
29
- <a href="#intro" data-nav-item>
30
- <div data-title>Introduction</div>
31
- <div data-desc>Re-usable components built with Tailwind CSS.</div>
32
- </a>
33
- <a href="#install" data-nav-item>
34
- <div data-title>Installation</div>
35
- <div data-desc>How to install dependencies and structure your app.</div>
36
- </a>
37
- <a href="#typography" data-nav-item>
38
- <div data-title>Typography</div>
39
- <div data-desc>Styles for headings, paragraphs, lists...</div>
40
- </a>
41
- </rel-nav-menu-panel>
42
- </rel-nav-menu-item>
43
-
44
- <rel-nav-menu-item label="Components">
45
- <rel-nav-menu-panel>
46
- <a href="#accordion" data-nav-item>
47
- <div data-title>Accordion</div>
48
- <div data-desc>Vertically stacked interactive headings.</div>
49
- </a>
50
- <a href="#alert" data-nav-item>
51
- <div data-title>Alert Dialog</div>
52
- <div data-desc>Modal dialog that interrupts the user.</div>
53
- </a>
54
- </rel-nav-menu-panel>
55
- </rel-nav-menu-item>
56
-
57
- <rel-nav-menu-item label="Docs" href="#docs"></rel-nav-menu-item>
58
- </rel-nav-menu>
59
- ```
60
-
61
- ## Simple Dropdown List
62
-
63
- For simpler dropdowns without titles and descriptions:
64
-
65
- ```html
66
- <rel-nav-menu>
67
- <rel-nav-menu-item label="Status">
68
- <rel-nav-menu-panel>
69
- <a href="#backlog" data-nav-item>Backlog</a>
70
- <a href="#todo" data-nav-item>To Do</a>
71
- <a href="#in-progress" data-nav-item>In Progress</a>
72
- <a href="#done" data-nav-item>Done</a>
73
- </rel-nav-menu-panel>
74
- </rel-nav-menu-item>
75
- </rel-nav-menu>
76
- ```
77
-
78
- ## API Reference
79
-
80
- ### rel-nav-menu
81
-
82
- Root navigation container.
83
-
84
- **Attributes:**
85
- - `open` (string) - ID of currently open item (reflects to attribute)
86
- - `disabled` (boolean) - Disables all interactions
87
- - `density` ("comfortable" | "compact") - Spacing density, default: "comfortable"
88
-
89
- **Events:**
90
- - `rel-nav-open-change` - Emitted when open state changes
91
- ```typescript
92
- detail: { openId: string }
93
- ```
94
-
95
- **Example:**
96
- ```javascript
97
- const navMenu = document.querySelector('rel-nav-menu');
98
- navMenu.addEventListener('rel-nav-open-change', (e) => {
99
- console.log('Open item:', e.detail.openId);
100
- });
101
- ```
102
-
103
- ### rel-nav-menu-item
104
-
105
- Individual navigation item (link or dropdown trigger).
106
-
107
- **Attributes:**
108
- - `label` (string, required) - Text displayed on the trigger
109
- - `href` (string, optional) - If provided, renders as link (no dropdown)
110
- - `item-id` (string, optional) - Stable identifier; auto-generated from label if not provided
111
- - `disabled` (boolean) - Disables this item
112
- - `icon` (string, optional) - Reserved for future icon support
113
-
114
- **Behavior:**
115
- - If `href` is set and no dropdown content → renders as anchor link
116
- - If dropdown content exists → renders as button with dropdown
117
- - Auto-generates `item-id` from label if not specified
118
-
119
- **Slots:**
120
- - Default slot: dropdown panel content (if any)
121
-
122
- ### rel-nav-menu-panel
123
-
124
- Styled container for dropdown content.
125
-
126
- **Usage:**
127
- Place inside `<rel-nav-menu-item>` to create dropdown content.
128
-
129
- **Content Structure:**
130
- Use data attributes for styling:
131
- - `data-nav-item` - On anchor/link elements for hover styling
132
- - `data-title` - For the main title text
133
- - `data-desc` - For the description text
134
-
135
- ## Keyboard Navigation
136
-
137
- Full keyboard accessibility support:
138
-
139
- | Key | Action |
140
- |-----|--------|
141
- | `Tab` / `Shift+Tab` | Navigate through triggers |
142
- | `ArrowLeft` | Move focus to previous trigger |
143
- | `ArrowRight` | Move focus to next trigger |
144
- | `Enter` / `Space` | Open/close focused dropdown (if it has content) |
145
- | `ArrowDown` | Move focus into open dropdown panel (first focusable element) |
146
- | `Escape` | Close open dropdown and return focus to trigger |
147
-
148
- ## Interaction Behavior
149
-
150
- ### Mouse Interactions
151
- - **Click** a trigger to toggle its dropdown
152
- - **Click** another trigger to switch dropdowns
153
- - **Click outside** to close dropdown
154
- - **Hover switching**: When a dropdown is open, hovering another trigger switches to it
155
-
156
- ### Accessibility
157
- - Root has `role="navigation"`
158
- - Dropdown triggers have `aria-haspopup="menu"`, `aria-expanded`, and `aria-controls`
159
- - Panels have matching `id` attributes
160
- - Disabled items are marked with `aria-disabled`
161
- - Focus management with visible focus indicators
162
-
163
- ## Styling Tokens
164
-
165
- The component uses design tokens from the Reliability Design System:
166
-
167
- ### Colors
168
- - `--rel-bg-surface-elevated` - Nav container background
169
- - `--rel-bg-neutral-elevated-1` - Trigger hover/active state, panel item hover
170
- - `--rel-border-default` - Borders
171
- - `--rel-text-label` - Text color
172
- - `--rel-text-placeholder` - Description text
173
- - `--rel-bg-surface` - Panel background
174
- - `--rel-bg-info` - Focus outline
175
-
176
- ### Typography
177
- - `--rel-fonts-font-family` - Font family (Poppins)
178
- - `--rel-fonts-weight-body-medium` - Trigger text weight
179
- - `--rel-fonts-weight-body-semibold` - Panel item title weight
180
- - `--rel-body-sm-regular-font-size` - Trigger and title text size
181
- - `--rel-body-xs-regular-font-size` - Description text size
182
- - `--rel-body-xs-regular-line-height` - Description line height
183
-
184
- ### Spacing
185
- - `--rel-spacing-3xs` (2px) - Compact spacing
186
- - `--rel-spacing-2xs` (4px) - Container padding, panel gaps
187
- - `--rel-spacing-xs` (8px) - Trigger padding, panel padding
188
- - `--rel-spacing-sm` (12px) - Panel item padding
189
- - `--rel-spacing-md` (16px) - Trigger horizontal padding
190
-
191
- ### Borders & Effects
192
- - `--rel-stroke-sm` (1px) - Border width
193
- - `--rel-border-radius-xs` (2px) - Panel item radius
194
- - `--rel-border-radius-sm` (8px) - Container and panel radius
195
- - `--rel-shadows-shadow-300` - Panel drop shadow
196
-
197
- ### Z-Index
198
- - Dropdown panels: `z-index: 1000`
199
-
200
- ## Positioning
201
-
202
- Dropdown panels use fixed positioning with smart collision detection:
203
- - **Default**: Opens below trigger, start-aligned
204
- - **Right overflow**: Shifts left to fit viewport
205
- - **Bottom overflow**: Flips above trigger if more space available
206
-
207
- ## Complete Example
208
-
209
- ```html
210
- <rel-nav-menu id="main-nav">
211
- <rel-nav-menu-item label="Getting started">
212
- <rel-nav-menu-panel>
213
- <a href="#intro" data-nav-item>
214
- <div data-title>Introduction</div>
215
- <div data-desc>Re-usable components built using Radix UI and Tailwind CSS.</div>
216
- </a>
217
- <a href="#installation" data-nav-item>
218
- <div data-title>Installation</div>
219
- <div data-desc>How to install dependencies and structure your app.</div>
220
- </a>
221
- <a href="#typography" data-nav-item>
222
- <div data-title>Typography</div>
223
- <div data-desc>Styles for headings, paragraphs, lists, and more.</div>
224
- </a>
225
- </rel-nav-menu-panel>
226
- </rel-nav-menu-item>
227
-
228
- <rel-nav-menu-item label="Components">
229
- <rel-nav-menu-panel>
230
- <a href="#accordion" data-nav-item>
231
- <div data-title>Accordion</div>
232
- <div data-desc>A vertically stacked set of interactive headings.</div>
233
- </a>
234
- <a href="#alert-dialog" data-nav-item>
235
- <div data-title>Alert Dialog</div>
236
- <div data-desc>A modal dialog that interrupts the user.</div>
237
- </a>
238
- <a href="#avatar" data-nav-item>
239
- <div data-title>Avatar</div>
240
- <div data-desc>An image element with a fallback.</div>
241
- </a>
242
- </rel-nav-menu-panel>
243
- </rel-nav-menu-item>
244
-
245
- <rel-nav-menu-item label="Status">
246
- <rel-nav-menu-panel>
247
- <a href="#backlog" data-nav-item>Backlog</a>
248
- <a href="#todo" data-nav-item>To Do</a>
249
- <a href="#in-progress" data-nav-item>In Progress</a>
250
- <a href="#done" data-nav-item>Done</a>
251
- </rel-nav-menu-panel>
252
- </rel-nav-menu-item>
253
-
254
- <rel-nav-menu-item label="Documentation" href="#docs"></rel-nav-menu-item>
255
- </rel-nav-menu>
256
-
257
- <script>
258
- const navMenu = document.getElementById('main-nav');
259
- navMenu.addEventListener('rel-nav-open-change', (e) => {
260
- console.log('Navigation state:', e.detail.openId);
261
- });
262
- </script>
263
- ```
264
-
265
- ## Browser Support
266
-
267
- Compatible with all modern browsers supporting:
268
- - Web Components (Custom Elements v1)
269
- - Shadow DOM
270
- - ES2020+ features
271
-
272
- ## Framework Integration
273
-
274
- Works seamlessly with:
275
- - Vanilla JavaScript
276
- - Angular
277
- - React (via wrapper)
278
- - Vue
279
- - Any framework supporting Web Components
280
-
281
- ## Comparison with Menubar
282
-
283
- While `rel-menubar` is designed for application menus (File/Edit/View), `rel-nav-menu` is optimized for:
284
- - **Website navigation** - Top-level site sections
285
- - **Content-rich dropdowns** - With titles, descriptions, and icons
286
- - **Flexible layouts** - Horizontal navigation bars
287
- - **Marketing sites** - Product features, documentation, etc.
288
-
289
- Use `rel-menubar` for desktop application UIs, use `rel-nav-menu` for website navigation.
@@ -1,3 +0,0 @@
1
- export * from "./rel-nav-menu";
2
- export * from "./rel-nav-menu-item";
3
- export * from "./rel-nav-menu-panel";
@@ -1,243 +0,0 @@
1
- import { LitElement, html, css } from "lit";
2
- import { customElement, property } from "lit/decorators.js";
3
-
4
- @customElement("rel-nav-menu-item")
5
- export class RelNavMenuItem extends LitElement {
6
- @property({ type: String }) label = "";
7
- @property({ type: String }) href = "";
8
- @property({ type: String, attribute: "item-id" }) itemId = "";
9
- @property({ type: Boolean, reflect: true }) disabled = false;
10
- @property({ type: String }) icon = "";
11
-
12
- /** Promoted from @state so rel-nav-menu can read it as a property. */
13
- @property({ type: Boolean, reflect: true }) hasContent = false;
14
-
15
- /** Set by rel-nav-menu to open/close this item's panel. */
16
- @property({ type: Boolean, reflect: true }) open = false;
17
-
18
- static styles = css`
19
- :host {
20
- color: var(--rel-text-default);
21
- display: inline-block;
22
- }
23
-
24
- .trigger {
25
- display: inline-flex;
26
- align-items: center;
27
- gap: var(--rel-spacing-2xs);
28
- padding: var(--rel-spacing-xs) var(--rel-spacing-md);
29
- color: var(--rel-text-label);
30
- background: transparent;
31
- border: none;
32
- border-radius: var(--rel-border-radius-sm);
33
- cursor: pointer;
34
- transition: all 0.15s ease;
35
- text-decoration: none;
36
- outline: none;
37
- user-select: none;
38
- font-family: var(--rel-body-sm-medium-font-family);
39
- font-weight: var(--rel-body-sm-medium-font-weight);
40
- font-size: var(--rel-body-sm-medium-font-size);
41
- line-height: var(--rel-body-sm-medium-line-height);
42
- letter-spacing: var(--rel-body-sm-medium-letter-spacing);
43
- }
44
-
45
- .trigger:hover:not(:disabled) {
46
- background: var(--rel-bg-surface-elevated);
47
- }
48
-
49
- .trigger:focus-visible {
50
- outline: 2px solid var(--rel-border-focus);
51
- outline-offset: 2px;
52
- }
53
-
54
- /* Active state driven by :host([open]) — no external class manipulation needed */
55
- :host([open]) .trigger,
56
- .trigger.active {
57
- background: var(--rel-bg-surface-elevated);
58
- }
59
-
60
- .trigger:disabled {
61
- opacity: 0.5;
62
- cursor: not-allowed;
63
- }
64
-
65
- :host([disabled]) .trigger {
66
- opacity: 0.5;
67
- cursor: not-allowed;
68
- }
69
-
70
- /* Panel lives inside the item's own shadow DOM */
71
- .panel {
72
- position: fixed;
73
- min-width: 320px;
74
- max-width: 600px;
75
- background: var(--rel-bg-surface);
76
- border: var(--rel-stroke-sm) solid var(--rel-border-default);
77
- border-radius: var(--rel-border-radius-sm);
78
- box-shadow: var(--rel-shadows-shadow-300);
79
- padding: var(--rel-spacing-xs);
80
- z-index: 1000;
81
- display: none;
82
- }
83
-
84
- .panel.open {
85
- display: block;
86
- }
87
- `;
88
-
89
- connectedCallback() {
90
- super.connectedCallback();
91
- if (!this.itemId && this.label) {
92
- this.itemId = this.label.toLowerCase().replace(/\s+/g, "-");
93
- }
94
- }
95
-
96
- firstUpdated() {
97
- this.updateHasContent();
98
- }
99
-
100
- updated(changed: Map<string, any>) {
101
- if (changed.has("open") && this.open) {
102
- // Wait for paint so the panel has layout dimensions before positioning.
103
- this.updateComplete.then(() => this.positionPanel());
104
- }
105
- }
106
-
107
- // ── Content detection ──────────────────────────────────────────────────────
108
-
109
- private updateHasContent() {
110
- const slot = this.shadowRoot?.querySelector("slot");
111
- if (slot) {
112
- const nodes = slot.assignedNodes({ flatten: true });
113
- this.hasContent = nodes.some(
114
- (node) => node.nodeType === Node.ELEMENT_NODE || node.textContent?.trim()
115
- );
116
- }
117
- }
118
-
119
- private handleSlotChange() {
120
- this.updateHasContent();
121
- }
122
-
123
- // ── Panel positioning (moved from rel-nav-menu) ────────────────────────────
124
-
125
- private positionPanel() {
126
- const trigger = this.shadowRoot?.querySelector(".trigger") as HTMLElement;
127
- const panel = this.shadowRoot?.querySelector(".panel") as HTMLElement;
128
- if (!trigger || !panel) return;
129
-
130
- const triggerRect = trigger.getBoundingClientRect();
131
- const panelRect = panel.getBoundingClientRect();
132
- const viewportWidth = window.innerWidth;
133
- const viewportHeight = window.innerHeight;
134
-
135
- let top = triggerRect.bottom + 8;
136
- let left = triggerRect.left;
137
-
138
- // Handle right overflow
139
- if (left + panelRect.width > viewportWidth) {
140
- left = viewportWidth - panelRect.width - 16;
141
- }
142
-
143
- // Handle left overflow
144
- if (left < 0) left = 16;
145
-
146
- // Handle bottom overflow — flip above if more space
147
- if (top + panelRect.height > viewportHeight) {
148
- const spaceAbove = triggerRect.top;
149
- const spaceBelow = viewportHeight - triggerRect.bottom;
150
- if (spaceAbove > spaceBelow && spaceAbove > panelRect.height) {
151
- top = triggerRect.top - panelRect.height - 8;
152
- }
153
- }
154
-
155
- panel.style.top = `${top}px`;
156
- panel.style.left = `${left}px`;
157
- }
158
-
159
- // ── Events dispatched upward — rel-nav-menu listens via connectedCallback ──
160
-
161
- private handleTriggerClick() {
162
- if (this.disabled) return;
163
- this.dispatchEvent(
164
- new CustomEvent("rel-nav-item-click", {
165
- detail: { itemId: this.itemId, hasContent: this.hasContent },
166
- bubbles: true,
167
- composed: true,
168
- })
169
- );
170
- }
171
-
172
- private handleTriggerMouseEnter() {
173
- if (this.disabled) return;
174
- this.dispatchEvent(
175
- new CustomEvent("rel-nav-item-hover", {
176
- detail: { itemId: this.itemId },
177
- bubbles: true,
178
- composed: true,
179
- })
180
- );
181
- }
182
-
183
- // ── ID helpers ─────────────────────────────────────────────────────────────
184
-
185
- get triggerId() {
186
- return `nav-trigger-${this.itemId}`;
187
- }
188
-
189
- get panelId() {
190
- return `nav-panel-${this.itemId}`;
191
- }
192
-
193
- // ── Render ─────────────────────────────────────────────────────────────────
194
-
195
- render() {
196
- const isLink = !!this.href && !this.hasContent;
197
-
198
- return html`
199
- ${isLink
200
- ? html`
201
- <a
202
- class="trigger"
203
- href="${this.href}"
204
- id="${this.triggerId}"
205
- ?disabled="${this.disabled}"
206
- @click="${this.handleTriggerClick}"
207
- @mouseenter="${this.handleTriggerMouseEnter}"
208
- >
209
- ${this.label}
210
- </a>
211
- `
212
- : html`
213
- <button
214
- class="trigger"
215
- id="${this.triggerId}"
216
- type="button"
217
- ?disabled="${this.disabled}"
218
- aria-haspopup="${this.hasContent ? "menu" : "false"}"
219
- aria-controls="${this.hasContent ? this.panelId : ""}"
220
- aria-expanded="${this.open ? "true" : "false"}"
221
- @click="${this.handleTriggerClick}"
222
- @mouseenter="${this.handleTriggerMouseEnter}"
223
- >
224
- ${this.label}
225
- </button>
226
- `}
227
-
228
- <!--
229
- Panel rendered inside this shadow root.
230
- Slot projects the consumer's light-DOM children directly — no cloning.
231
- rel-nav-menu sets item.open = true/false to show/hide.
232
- -->
233
- <div
234
- class="panel ${this.open ? "open" : ""}"
235
- id="${this.panelId}"
236
- role="menu"
237
- @click="${(e: Event) => e.stopPropagation()}"
238
- >
239
- <slot @slotchange="${this.handleSlotChange}"></slot>
240
- </div>
241
- `;
242
- }
243
- }
@@ -1,72 +0,0 @@
1
- import { LitElement, html, css } from "lit";
2
- import { customElement } from "lit/decorators.js";
3
-
4
- @customElement("rel-nav-menu-panel")
5
- export class RelNavMenuPanel extends LitElement {
6
- static styles = css`
7
- :host {
8
- color: var(--rel-text-default);
9
- display: block;
10
- width: 100%;
11
- }
12
-
13
- .panel-content {
14
- display: flex;
15
- flex-direction: column;
16
- gap: var(--rel-spacing-2xs);
17
- padding: var(--rel-spacing-xs);
18
- }
19
-
20
- ::slotted(a[data-nav-item]) {
21
- display: block;
22
- padding: var(--rel-spacing-sm);
23
- border-radius: var(--rel-border-radius-xs);
24
- transition: background 0.15s ease;
25
- text-decoration: none;
26
- color: inherit;
27
- }
28
-
29
- ::slotted(a[data-nav-item]:hover) {
30
- background: var(--rel-bg-surface-elevated);
31
- }
32
-
33
- ::slotted([data-title]) {
34
- color: var(--rel-text-label);
35
- margin-bottom: var(--rel-spacing-3xs);
36
-
37
- font-family: var(--rel-body-sm-semibold-font-family);
38
-
39
- font-weight: var(--rel-body-sm-semibold-font-weight);
40
-
41
- font-size: var(--rel-body-sm-semibold-font-size);
42
-
43
- line-height: var(--rel-body-sm-semibold-line-height);
44
-
45
- letter-spacing: var(--rel-body-sm-semibold-letter-spacing);
46
-
47
- }
48
-
49
- ::slotted([data-desc]) {
50
- color: var(--rel-text-placeholder);
51
-
52
- font-family: var(--rel-body-xs-regular-font-family);
53
-
54
- font-weight: var(--rel-body-xs-regular-font-weight);
55
-
56
- font-size: var(--rel-body-xs-regular-font-size);
57
-
58
- line-height: var(--rel-body-xs-regular-line-height);
59
-
60
- letter-spacing: var(--rel-body-xs-regular-letter-spacing);
61
-
62
- }
63
- `;
64
-
65
- render() {
66
- return html`
67
- <div class="panel-content">
68
- <slot></slot>
69
- </div>
70
- `;
71
- }
72
- }