@reliability-design/web 1.4.3 → 1.4.5

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 (48) hide show
  1. package/dist/components/rel-accordion/rel-accordion.ts +13 -1
  2. package/dist/components/rel-autocomplete/README.md +1 -0
  3. package/dist/components/rel-autocomplete/rel-autocomplete.ts +56 -1
  4. package/dist/components/rel-button/rel-button.ts +18 -2
  5. package/dist/components/rel-calendar/rel-calendar.ts +23 -1
  6. package/dist/components/rel-carousel/rel-carousel.ts +20 -0
  7. package/dist/components/rel-checkbox/README.md +69 -22
  8. package/dist/components/rel-checkbox/rel-checkbox.ts +119 -9
  9. package/dist/components/rel-chip/rel-chip.ts +29 -0
  10. package/dist/components/rel-date-picker/rel-date-picker.ts +156 -13
  11. package/dist/components/rel-drawer/rel-drawer.ts +22 -58
  12. package/dist/components/rel-menu/rel-menu.ts +124 -15
  13. package/dist/components/rel-menubar/rel-menubar.ts +221 -63
  14. package/dist/components/rel-nav-menu/rel-nav-menu.ts +39 -3
  15. package/dist/components/rel-otp/rel-otp.ts +3 -3
  16. package/dist/components/rel-pagination/README.md +14 -0
  17. package/dist/components/rel-pagination/rel-pagination.ts +30 -14
  18. package/dist/components/rel-popover/rel-popover.ts +31 -3
  19. package/dist/components/rel-range-picker/rel-range-picker.ts +251 -3
  20. package/dist/components/rel-resizable/rel-resizable-group.ts +20 -0
  21. package/dist/components/rel-segmented-button/rel-segmented-button.ts +50 -12
  22. package/dist/components/rel-select/README.md +1 -0
  23. package/dist/components/rel-select/rel-select.ts +1385 -1170
  24. package/dist/components/rel-sheet/rel-sheet.ts +22 -1
  25. package/dist/components/rel-sidebar/rel-sidebar.ts +43 -39
  26. package/dist/components/rel-stepper/rel-stepper.ts +44 -1
  27. package/dist/components/rel-tab/rel-tab.ts +32 -7
  28. package/dist/components/rel-time-picker/rel-time-picker.ts +338 -206
  29. package/dist/components/rel-tooltip/rel-tooltip.ts +30 -0
  30. package/dist/components/rel-topbar/rel-topbar-actions.ts +1 -1
  31. package/dist/components/rel-topbar/rel-topbar-brand.ts +1 -1
  32. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +1 -1
  33. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +1 -1
  34. package/dist/components/rel-topbar/rel-topbar-item.ts +318 -319
  35. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +1 -1
  36. package/dist/components/rel-topbar/rel-topbar-profile.ts +224 -224
  37. package/dist/components/rel-topbar/rel-topbar-utilities.ts +1 -1
  38. package/dist/components/rel-topbar/rel-topbar.ts +440 -440
  39. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +134 -0
  40. package/dist/components/rel-upload/rel-upload-actions.ts +163 -0
  41. package/dist/components/rel-upload/rel-upload.ts +943 -0
  42. package/dist/index.d.mts +491 -18
  43. package/dist/index.d.ts +491 -18
  44. package/dist/index.js +2748 -410
  45. package/dist/index.js.map +1 -1
  46. package/dist/index.mjs +2953 -627
  47. package/dist/index.mjs.map +1 -1
  48. package/package.json +1 -1
@@ -1,325 +1,324 @@
1
- import { LitElement, html, css } from "lit";
2
- import { customElement, property, state } from "lit/decorators.js";
3
- import "./rel-topbar-dropdown";
4
- import "./rel-topbar-dropdown-item";
5
- import "@reliability-design/icons/rel-icon";
6
-
7
- /**
8
- * `rel-topbar-item` — A navigation item within rel-topbar.
9
- *
10
- * @deprecated Part of the deprecated rel-topbar family. Use the "App
11
- * Topbar" recipe at /docs/recipes/app-topbar, which composes nav links and
12
- * `rel-menu`/`rel-popover` dropdowns directly instead of a dedicated item component.
13
- *
14
- * Renders as an `<a>` when `href` is supplied, otherwise a `<button>`.
15
- *
16
- * Slots:
17
- * (default) — Label text / icon (overrides `label` property)
18
- * prefix — Icon/content before the label
19
- * suffix — Icon/content after the label (e.g. badge)
20
- * dropdown — Expandable panel content shown below the item
21
- *
22
- * Events:
23
- * rel-select — fired when a non-disabled, non-expandable item is activated
24
- * rel-toggle — fired when an expandable item is opened/closed { open: boolean }
25
- */
26
- @customElement("rel-topbar-item")
27
- export class RelTopbarItem extends LitElement {
28
- /** Accessible label — also shown as text when no default slot content */
29
- @property({ type: String }) label?: string;
30
-
31
- /** Navigation href — renders an anchor element when set */
32
- @property({ type: String }) href?: string;
33
-
34
- /** Marks this item as the current/active page */
35
- @property({ type: Boolean, reflect: true }) active = false;
36
-
37
- /** Prevents interaction */
38
- @property({ type: Boolean, reflect: true }) disabled = false;
39
-
40
- /** Shows a chevron and enables dropdown panel */
41
- @property({ type: Boolean, reflect: true }) expandable = false;
42
-
43
- /** Controlled open state of the dropdown panel */
44
- @property({ type: Boolean, reflect: true }) open = false;
45
-
46
- /** Optional string value forwarded in rel-select / rel-toggle events */
47
- @property({ type: String }) value?: string;
48
-
49
- /** @internal tracks whether dropdown slot has content */
50
- @state() private _hasDropdown = false;
51
-
52
- static styles = css`
53
- /* ─── Component tokens ──────────────────────────────────────────── */
54
- :host {
55
- color: var(--rel-text-default);
56
- --_item-color: var(--rel-topbar-item-color, var(--rel-text-default));
57
- --_item-active-color: var(--rel-topbar-item-active-color, var(--rel-text-success));
58
- --_item-active-indicator: var(--rel-topbar-item-active-indicator, var(--rel-bg-brand));
59
- --_item-hover-bg: var(--rel-topbar-item-hover-bg, var(--rel-bg-surface-elevated));
60
-
61
- display: inline-block;
62
- position: relative;
63
- font-family: var(--rel-fonts-font-family, Poppins, sans-serif);
64
- }
65
-
66
- :host([hidden]) {
67
- display: none !important;
68
- }
69
-
70
- /* ─── Trigger (shared for <a> and <button>) ─────────────────────── */
71
- .trigger {
72
- display: inline-flex;
73
- align-items: center;
74
- gap: var(--rel-spacing-2xs, 4px);
75
- padding: var(--rel-spacing-xs, 8px) var(--rel-spacing-sm, 12px);
76
- border: none;
77
- background: transparent;
78
- border-radius: var(--rel-border-radius-sm, 8px);
79
- cursor: pointer;
80
- color: var(--_item-color);
81
- text-decoration: none;
82
- white-space: nowrap;
83
- position: relative;
84
- transition: background 0.15s ease, color 0.15s ease;
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+ import "./rel-topbar-dropdown";
4
+ import "./rel-topbar-dropdown-item";
5
+ import "@reliability-design/icons/rel-icon";
6
+
7
+ /**
8
+ * `rel-topbar-item` — A navigation item within rel-topbar.
9
+ *
10
+ * @deprecated Part of the deprecated rel-topbar family. Use the "Navbar" recipe at /docs/recipes/navbar, which composes nav links and
11
+ * `rel-menu`/`rel-popover` dropdowns directly instead of a dedicated item component.
12
+ *
13
+ * Renders as an `<a>` when `href` is supplied, otherwise a `<button>`.
14
+ *
15
+ * Slots:
16
+ * (default) — Label text / icon (overrides `label` property)
17
+ * prefix — Icon/content before the label
18
+ * suffix — Icon/content after the label (e.g. badge)
19
+ * dropdown — Expandable panel content shown below the item
20
+ *
21
+ * Events:
22
+ * rel-select — fired when a non-disabled, non-expandable item is activated
23
+ * rel-toggle — fired when an expandable item is opened/closed { open: boolean }
24
+ */
25
+ @customElement("rel-topbar-item")
26
+ export class RelTopbarItem extends LitElement {
27
+ /** Accessible label — also shown as text when no default slot content */
28
+ @property({ type: String }) label?: string;
29
+
30
+ /** Navigation href — renders an anchor element when set */
31
+ @property({ type: String }) href?: string;
32
+
33
+ /** Marks this item as the current/active page */
34
+ @property({ type: Boolean, reflect: true }) active = false;
35
+
36
+ /** Prevents interaction */
37
+ @property({ type: Boolean, reflect: true }) disabled = false;
38
+
39
+ /** Shows a chevron and enables dropdown panel */
40
+ @property({ type: Boolean, reflect: true }) expandable = false;
41
+
42
+ /** Controlled open state of the dropdown panel */
43
+ @property({ type: Boolean, reflect: true }) open = false;
44
+
45
+ /** Optional string value forwarded in rel-select / rel-toggle events */
46
+ @property({ type: String }) value?: string;
47
+
48
+ /** @internal tracks whether dropdown slot has content */
49
+ @state() private _hasDropdown = false;
50
+
51
+ static styles = css`
52
+ /* ─── Component tokens ──────────────────────────────────────────── */
53
+ :host {
54
+ color: var(--rel-text-default);
55
+ --_item-color: var(--rel-topbar-item-color, var(--rel-text-default));
56
+ --_item-active-color: var(--rel-topbar-item-active-color, var(--rel-text-success));
57
+ --_item-active-indicator: var(--rel-topbar-item-active-indicator, var(--rel-bg-brand));
58
+ --_item-hover-bg: var(--rel-topbar-item-hover-bg, var(--rel-bg-surface-elevated));
59
+
60
+ display: inline-block;
61
+ position: relative;
62
+ font-family: var(--rel-fonts-font-family, Poppins, sans-serif);
63
+ }
64
+
65
+ :host([hidden]) {
66
+ display: none !important;
67
+ }
68
+
69
+ /* ─── Trigger (shared for <a> and <button>) ─────────────────────── */
70
+ .trigger {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ gap: var(--rel-spacing-2xs, 4px);
74
+ padding: var(--rel-spacing-xs, 8px) var(--rel-spacing-sm, 12px);
75
+ border: none;
76
+ background: transparent;
77
+ border-radius: var(--rel-border-radius-sm, 8px);
78
+ cursor: pointer;
79
+ color: var(--_item-color);
80
+ text-decoration: none;
81
+ white-space: nowrap;
82
+ position: relative;
83
+ transition: background 0.15s ease, color 0.15s ease;
85
84
  box-sizing: border-box;
86
85
  font-family: var(--rel-body-md-medium-font-family);
87
86
  font-weight: var(--rel-body-md-medium-font-weight);
88
87
  font-size: var(--rel-body-md-medium-font-size);
89
88
  line-height: var(--rel-body-md-medium-line-height);
90
89
  letter-spacing: var(--rel-body-md-medium-letter-spacing);
91
- }
92
-
93
- .trigger::after {
94
- content: "";
95
- position: absolute;
96
- bottom: -2px;
97
- left: var(--rel-spacing-sm, 12px);
98
- right: var(--rel-spacing-sm, 12px);
99
- height: 2px;
100
- border-radius: 1px;
101
- background: transparent;
102
- transition: background 0.15s ease;
103
- }
104
-
105
- /* Active state */
106
- :host([active]) .trigger {
107
- color: var(--_item-active-color);
108
- font-weight: var(--rel-fonts-weight-body-semibold, 600);
109
- }
110
-
111
- :host([active]) .trigger::after {
112
- background: var(--_item-active-indicator);
113
- }
114
-
115
- /* Hover */
116
- .trigger:hover:not(:disabled) {
117
- background: var(--_item-hover-bg);
118
- }
119
-
120
- /* Focus */
121
- .trigger:focus-visible {
122
- outline: 2px solid var(--_item-active-indicator);
123
- outline-offset: 2px;
124
- }
125
-
126
- /* Disabled */
127
- :host([disabled]) {
128
- cursor: not-allowed;
129
- }
130
-
131
- :host([disabled]) .trigger {
132
- opacity: 0.45;
133
- cursor: not-allowed;
134
- pointer-events: none;
135
- }
136
-
137
- /* Open state (expandable) */
138
- :host([open]) .trigger {
139
- background: var(--_item-hover-bg);
140
- }
141
-
142
- /* ─── Prefix / suffix slots ─────────────────────────────────────── */
143
- .prefix,
144
- .suffix {
145
- display: contents;
146
- }
147
-
148
- /* ─── Chevron icon ──────────────────────────────────────────────── */
149
- .chevron {
150
- display: inline-flex;
151
- align-items: center;
152
- flex-shrink: 0;
153
- transition: transform 0.2s ease;
154
- color: inherit;
155
- }
156
-
157
- :host([open]) .chevron {
158
- transform: rotate(180deg);
159
- }
160
-
161
- /* ─── Dropdown panel ────────────────────────────────────────────── */
162
- .dropdown {
163
- position: absolute;
164
- top: calc(100% + 6px);
165
- left: 0;
166
- min-width: 200px;
167
- background: var(--rel-bg-surface);
168
- border: var(--rel-stroke-sm, 1px) solid var(--rel-border-default);
169
- border-radius: var(--rel-border-radius-sm, 8px);
170
- box-shadow: var(--rel-shadows-shadow-300);
171
- padding: var(--rel-spacing-2xs, 4px);
172
- z-index: 200;
173
- display: none;
174
- }
175
-
176
- :host([open]) .dropdown {
177
- display: block;
178
- }
179
- `;
180
-
181
- connectedCallback() {
182
- super.connectedCallback();
183
- document.addEventListener("click", this._handleOutsideClick);
184
- document.addEventListener("keydown", this._handleDocKeydown);
185
- }
186
-
187
- disconnectedCallback() {
188
- super.disconnectedCallback();
189
- document.removeEventListener("click", this._handleOutsideClick);
190
- document.removeEventListener("keydown", this._handleDocKeydown);
191
- }
192
-
193
- private _handleOutsideClick = (e: MouseEvent) => {
194
- if (!this.open) return;
195
- const path = e.composedPath() as Node[];
196
- if (!path.includes(this)) {
197
- this._setOpen(false);
198
- }
199
- };
200
-
201
- private _handleDocKeydown = (e: KeyboardEvent) => {
202
- if (e.key === "Escape" && this.open) {
203
- this._setOpen(false);
204
- (this.shadowRoot?.querySelector(".trigger") as HTMLElement)?.focus();
205
- }
206
- };
207
-
208
- private _setOpen(value: boolean) {
209
- this.open = value;
210
- this.dispatchEvent(
211
- new CustomEvent("rel-toggle", {
212
- detail: { open: this.open, value: this.value },
213
- bubbles: true,
214
- composed: true,
215
- })
216
- );
217
- }
218
-
219
- private _handleTriggerClick(e: MouseEvent) {
220
- if (this.disabled) {
221
- e.preventDefault();
222
- return;
223
- }
224
-
225
- if (this.expandable || this._hasDropdown) {
226
- e.preventDefault();
227
- this._setOpen(!this.open);
228
- return;
229
- }
230
-
231
- if (!this.href) {
232
- e.preventDefault();
233
- }
234
-
235
- this.dispatchEvent(
236
- new CustomEvent("rel-select", {
237
- detail: { value: this.value, label: this.label },
238
- bubbles: true,
239
- composed: true,
240
- })
241
- );
242
-
243
- // Bubble up to topbar
244
- this.dispatchEvent(
245
- new CustomEvent("rel-nav-select", {
246
- detail: { value: this.value, label: this.label },
247
- bubbles: true,
248
- composed: true,
249
- })
250
- );
251
- }
252
-
253
- private _routeSlots(e: Event) {
254
- const slot = e.target as HTMLSlotElement;
255
- for (const el of slot.assignedElements({ flatten: true })) {
256
- const targetSlot = (el as HTMLElement).tagName.toLowerCase() === "rel-topbar-dropdown" ? "dropdown" : "";
257
- if ((el as HTMLElement).slot !== targetSlot) {
258
- (el as HTMLElement).slot = targetSlot;
259
- }
260
- }
261
- }
262
-
263
- private _handleDropdownSlotChange(e: Event) {
264
- const slot = e.target as HTMLSlotElement;
265
- const nodes = slot.assignedElements();
266
- this._hasDropdown = nodes.length > 0;
267
- }
268
-
269
- render() {
270
- const isLink = !!this.href && !this.disabled;
271
- const showChevron = this.expandable || this._hasDropdown;
272
- const ariaCurrent = this.active ? "page" : undefined;
273
- const ariaExpanded = showChevron ? (this.open ? "true" : "false") : undefined;
274
- const ariaHasPopup = showChevron ? "true" : undefined;
275
-
276
- const triggerContent = html`
277
- <span class="prefix"><slot name="prefix"></slot></span>
278
- <slot>${this.label ?? ""}</slot>
279
- <span class="suffix"><slot name="suffix"></slot></span>
280
- ${showChevron
281
- ? html`<span class="chevron" aria-hidden="true">
282
- <rel-icon name="chevron-down" size="sm"></rel-icon>
283
- </span>`
284
- : null}
285
- `;
286
-
287
- const trigger = isLink
288
- ? html`
289
- <a
290
- class="trigger"
291
- href=${this.href!}
292
- aria-current=${ariaCurrent as string}
293
- aria-expanded=${ariaExpanded as string}
294
- aria-haspopup=${ariaHasPopup as string}
295
- @click=${this._handleTriggerClick}
296
- >
297
- ${triggerContent}
298
- </a>
299
- `
300
- : html`
301
- <button
302
- class="trigger"
303
- type="button"
304
- ?disabled=${this.disabled}
305
- aria-current=${ariaCurrent as string}
306
- aria-expanded=${ariaExpanded as string}
307
- aria-haspopup=${ariaHasPopup as string}
308
- @click=${this._handleTriggerClick}
309
- >
310
- ${triggerContent}
311
- </button>
312
- `;
313
-
314
- return html`
315
- <!-- router: auto-assigns slot="dropdown" for rel-topbar-dropdown children -->
316
- <slot style="display:none" @slotchange=${this._routeSlots}></slot>
317
-
318
- ${trigger}
319
- <div class="dropdown" role="region">
320
- <slot name="dropdown" @slotchange=${this._handleDropdownSlotChange}></slot>
321
- </div>
322
- `;
323
- }
324
- }
325
-
90
+ }
91
+
92
+ .trigger::after {
93
+ content: "";
94
+ position: absolute;
95
+ bottom: -2px;
96
+ left: var(--rel-spacing-sm, 12px);
97
+ right: var(--rel-spacing-sm, 12px);
98
+ height: 2px;
99
+ border-radius: 1px;
100
+ background: transparent;
101
+ transition: background 0.15s ease;
102
+ }
103
+
104
+ /* Active state */
105
+ :host([active]) .trigger {
106
+ color: var(--_item-active-color);
107
+ font-weight: var(--rel-fonts-weight-body-semibold, 600);
108
+ }
109
+
110
+ :host([active]) .trigger::after {
111
+ background: var(--_item-active-indicator);
112
+ }
113
+
114
+ /* Hover */
115
+ .trigger:hover:not(:disabled) {
116
+ background: var(--_item-hover-bg);
117
+ }
118
+
119
+ /* Focus */
120
+ .trigger:focus-visible {
121
+ outline: 2px solid var(--_item-active-indicator);
122
+ outline-offset: 2px;
123
+ }
124
+
125
+ /* Disabled */
126
+ :host([disabled]) {
127
+ cursor: not-allowed;
128
+ }
129
+
130
+ :host([disabled]) .trigger {
131
+ opacity: 0.45;
132
+ cursor: not-allowed;
133
+ pointer-events: none;
134
+ }
135
+
136
+ /* Open state (expandable) */
137
+ :host([open]) .trigger {
138
+ background: var(--_item-hover-bg);
139
+ }
140
+
141
+ /* ─── Prefix / suffix slots ─────────────────────────────────────── */
142
+ .prefix,
143
+ .suffix {
144
+ display: contents;
145
+ }
146
+
147
+ /* ─── Chevron icon ──────────────────────────────────────────────── */
148
+ .chevron {
149
+ display: inline-flex;
150
+ align-items: center;
151
+ flex-shrink: 0;
152
+ transition: transform 0.2s ease;
153
+ color: inherit;
154
+ }
155
+
156
+ :host([open]) .chevron {
157
+ transform: rotate(180deg);
158
+ }
159
+
160
+ /* ─── Dropdown panel ────────────────────────────────────────────── */
161
+ .dropdown {
162
+ position: absolute;
163
+ top: calc(100% + 6px);
164
+ left: 0;
165
+ min-width: 200px;
166
+ background: var(--rel-bg-surface);
167
+ border: var(--rel-stroke-sm, 1px) solid var(--rel-border-default);
168
+ border-radius: var(--rel-border-radius-sm, 8px);
169
+ box-shadow: var(--rel-shadows-shadow-300);
170
+ padding: var(--rel-spacing-2xs, 4px);
171
+ z-index: 200;
172
+ display: none;
173
+ }
174
+
175
+ :host([open]) .dropdown {
176
+ display: block;
177
+ }
178
+ `;
179
+
180
+ connectedCallback() {
181
+ super.connectedCallback();
182
+ document.addEventListener("click", this._handleOutsideClick);
183
+ document.addEventListener("keydown", this._handleDocKeydown);
184
+ }
185
+
186
+ disconnectedCallback() {
187
+ super.disconnectedCallback();
188
+ document.removeEventListener("click", this._handleOutsideClick);
189
+ document.removeEventListener("keydown", this._handleDocKeydown);
190
+ }
191
+
192
+ private _handleOutsideClick = (e: MouseEvent) => {
193
+ if (!this.open) return;
194
+ const path = e.composedPath() as Node[];
195
+ if (!path.includes(this)) {
196
+ this._setOpen(false);
197
+ }
198
+ };
199
+
200
+ private _handleDocKeydown = (e: KeyboardEvent) => {
201
+ if (e.key === "Escape" && this.open) {
202
+ this._setOpen(false);
203
+ (this.shadowRoot?.querySelector(".trigger") as HTMLElement)?.focus();
204
+ }
205
+ };
206
+
207
+ private _setOpen(value: boolean) {
208
+ this.open = value;
209
+ this.dispatchEvent(
210
+ new CustomEvent("rel-toggle", {
211
+ detail: { open: this.open, value: this.value },
212
+ bubbles: true,
213
+ composed: true,
214
+ })
215
+ );
216
+ }
217
+
218
+ private _handleTriggerClick(e: MouseEvent) {
219
+ if (this.disabled) {
220
+ e.preventDefault();
221
+ return;
222
+ }
223
+
224
+ if (this.expandable || this._hasDropdown) {
225
+ e.preventDefault();
226
+ this._setOpen(!this.open);
227
+ return;
228
+ }
229
+
230
+ if (!this.href) {
231
+ e.preventDefault();
232
+ }
233
+
234
+ this.dispatchEvent(
235
+ new CustomEvent("rel-select", {
236
+ detail: { value: this.value, label: this.label },
237
+ bubbles: true,
238
+ composed: true,
239
+ })
240
+ );
241
+
242
+ // Bubble up to topbar
243
+ this.dispatchEvent(
244
+ new CustomEvent("rel-nav-select", {
245
+ detail: { value: this.value, label: this.label },
246
+ bubbles: true,
247
+ composed: true,
248
+ })
249
+ );
250
+ }
251
+
252
+ private _routeSlots(e: Event) {
253
+ const slot = e.target as HTMLSlotElement;
254
+ for (const el of slot.assignedElements({ flatten: true })) {
255
+ const targetSlot = (el as HTMLElement).tagName.toLowerCase() === "rel-topbar-dropdown" ? "dropdown" : "";
256
+ if ((el as HTMLElement).slot !== targetSlot) {
257
+ (el as HTMLElement).slot = targetSlot;
258
+ }
259
+ }
260
+ }
261
+
262
+ private _handleDropdownSlotChange(e: Event) {
263
+ const slot = e.target as HTMLSlotElement;
264
+ const nodes = slot.assignedElements();
265
+ this._hasDropdown = nodes.length > 0;
266
+ }
267
+
268
+ render() {
269
+ const isLink = !!this.href && !this.disabled;
270
+ const showChevron = this.expandable || this._hasDropdown;
271
+ const ariaCurrent = this.active ? "page" : undefined;
272
+ const ariaExpanded = showChevron ? (this.open ? "true" : "false") : undefined;
273
+ const ariaHasPopup = showChevron ? "true" : undefined;
274
+
275
+ const triggerContent = html`
276
+ <span class="prefix"><slot name="prefix"></slot></span>
277
+ <slot>${this.label ?? ""}</slot>
278
+ <span class="suffix"><slot name="suffix"></slot></span>
279
+ ${showChevron
280
+ ? html`<span class="chevron" aria-hidden="true">
281
+ <rel-icon name="chevron-down" size="sm"></rel-icon>
282
+ </span>`
283
+ : null}
284
+ `;
285
+
286
+ const trigger = isLink
287
+ ? html`
288
+ <a
289
+ class="trigger"
290
+ href=${this.href!}
291
+ aria-current=${ariaCurrent as string}
292
+ aria-expanded=${ariaExpanded as string}
293
+ aria-haspopup=${ariaHasPopup as string}
294
+ @click=${this._handleTriggerClick}
295
+ >
296
+ ${triggerContent}
297
+ </a>
298
+ `
299
+ : html`
300
+ <button
301
+ class="trigger"
302
+ type="button"
303
+ ?disabled=${this.disabled}
304
+ aria-current=${ariaCurrent as string}
305
+ aria-expanded=${ariaExpanded as string}
306
+ aria-haspopup=${ariaHasPopup as string}
307
+ @click=${this._handleTriggerClick}
308
+ >
309
+ ${triggerContent}
310
+ </button>
311
+ `;
312
+
313
+ return html`
314
+ <!-- router: auto-assigns slot="dropdown" for rel-topbar-dropdown children -->
315
+ <slot style="display:none" @slotchange=${this._routeSlots}></slot>
316
+
317
+ ${trigger}
318
+ <div class="dropdown" role="region">
319
+ <slot name="dropdown" @slotchange=${this._handleDropdownSlotChange}></slot>
320
+ </div>
321
+ `;
322
+ }
323
+ }
324
+
@@ -3,7 +3,7 @@ import { customElement } from "lit/decorators.js";
3
3
 
4
4
  /**
5
5
  * @deprecated Part of the deprecated rel-topbar family. Use `rel-drawer`
6
- * for the mobile nav panel in the "App Topbar" recipe at /docs/recipes/app-topbar.
6
+ * for the mobile nav panel in the "Navbar" recipe at /docs/recipes/navbar.
7
7
  */
8
8
  @customElement("rel-topbar-mobile-panel")
9
9
  export class RelTopbarMobilePanel extends LitElement {