@reliability-design/web 1.0.6 → 1.1.1
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.
- package/dist/components/rel-accordion/rel-accordion.ts +4 -0
- package/dist/components/rel-alert/rel-alert.ts +83 -13
- package/dist/components/rel-avatar/rel-avatar.ts +3 -2
- package/dist/components/rel-badge/rel-badge.ts +6 -2
- package/dist/components/rel-button/rel-button.ts +64 -8
- package/dist/components/rel-calendar/rel-calendar.ts +3 -3
- package/dist/components/rel-carousel/rel-carousel.ts +10 -11
- package/dist/components/rel-checkbox/rel-checkbox.ts +33 -2
- package/dist/components/rel-chip/rel-chip.ts +63 -5
- package/dist/components/rel-divider/rel-divider.ts +9 -0
- package/dist/components/rel-drawer/rel-drawer-footer.ts +29 -0
- package/dist/components/rel-drawer/rel-drawer.ts +17 -26
- package/dist/components/rel-menu/rel-menu.ts +53 -21
- package/dist/components/rel-menubar/rel-menubar.ts +52 -23
- package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +240 -143
- package/dist/components/rel-nav-menu/rel-nav-menu.ts +227 -331
- package/dist/components/rel-navbar/rel-navbar.ts +13 -0
- package/dist/components/rel-pagination/rel-pagination.ts +11 -6
- package/dist/components/rel-popover/rel-popover.ts +16 -13
- package/dist/components/rel-radio/rel-radio.ts +18 -1
- package/dist/components/rel-resizable/rel-resizable-handle.ts +4 -8
- package/dist/components/rel-select/rel-select.ts +14 -0
- package/dist/components/rel-sheet/rel-sheet.ts +7 -6
- package/dist/components/rel-sidebar/rel-sidebar.ts +13 -5
- package/dist/components/rel-slider/rel-slider.ts +25 -2
- package/dist/components/rel-snackbar/rel-snackbar.ts +46 -16
- package/dist/components/rel-stepper/rel-stepper.ts +32 -21
- package/dist/components/rel-switch/rel-switch.ts +19 -6
- package/dist/components/rel-tab/rel-tab.ts +49 -15
- package/dist/components/rel-table/rel-table-body.ts +5 -0
- package/dist/components/rel-table/rel-table-caption.ts +6 -1
- package/dist/components/rel-table/rel-table-cell.ts +42 -49
- package/dist/components/rel-table/rel-table-footer.ts +5 -0
- package/dist/components/rel-table/rel-table-head.ts +13 -1
- package/dist/components/rel-table/rel-table-header.ts +5 -0
- package/dist/components/rel-table/rel-table-row.ts +7 -3
- package/dist/components/rel-table/rel-table.ts +8 -2
- package/dist/components/rel-textfield/rel-textfield.ts +20 -20
- package/dist/components/rel-toast/rel-toast.ts +31 -10
- package/dist/components/rel-tooltip/rel-tooltip.ts +123 -80
- package/dist/components/rel-topbar/rel-topbar-actions.ts +23 -0
- package/dist/components/rel-topbar/rel-topbar-brand.ts +46 -0
- package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +33 -0
- package/dist/components/rel-topbar/rel-topbar-dropdown.ts +28 -0
- package/dist/components/rel-topbar/rel-topbar-item.ts +315 -0
- package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +23 -0
- package/dist/components/rel-topbar/rel-topbar-profile.ts +248 -0
- package/dist/components/rel-topbar/rel-topbar-utilities.ts +23 -0
- package/dist/components/rel-topbar/rel-topbar.ts +329 -0
- package/dist/index.d.mts +278 -289
- package/dist/index.d.ts +278 -289
- package/dist/index.js +4498 -5727
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4535 -5756
- package/dist/index.mjs.map +1 -1
- package/dist/styles/vars.css +346 -294
- package/dist/{vars-ITL2K3KO.css → vars-TBB4BMSD.css} +346 -294
- package/package.json +2 -1
- package/dist/components/rel-quote-page/README.md +0 -166
- package/dist/components/rel-quote-page/rel-quote-page.ts +0 -816
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LitElement, html, css } from "lit";
|
|
2
2
|
import { customElement, property, state, query } from "lit/decorators.js";
|
|
3
|
+
import "./rel-drawer-footer";
|
|
3
4
|
|
|
4
5
|
export type DrawerSide = "bottom" | "left" | "right" | "top";
|
|
5
6
|
export type DrawerCloseReason = "backdrop" | "escape" | "drag" | "programmatic";
|
|
@@ -18,6 +19,8 @@ export class RelDrawer extends LitElement {
|
|
|
18
19
|
@property({ type: String, attribute: "max-height" }) maxHeight = "80vh";
|
|
19
20
|
@property({ type: String }) width = "420px";
|
|
20
21
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
|
22
|
+
@property({ type: String }) title: string = "";
|
|
23
|
+
@property({ type: String }) description: string = "";
|
|
21
24
|
|
|
22
25
|
@state() private isDragging = false;
|
|
23
26
|
@state() private dragOffset = 0;
|
|
@@ -69,7 +72,7 @@ export class RelDrawer extends LitElement {
|
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
.drawer-container.open .overlay {
|
|
72
|
-
opacity: 1;
|
|
75
|
+
opacity: var(--rel-drawer-scrim-opacity, 1);
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
/* Panel base */
|
|
@@ -295,9 +298,10 @@ export class RelDrawer extends LitElement {
|
|
|
295
298
|
this.lockScroll();
|
|
296
299
|
|
|
297
300
|
if (this.modal) {
|
|
298
|
-
|
|
299
|
-
this.
|
|
300
|
-
|
|
301
|
+
this.updateComplete.then(() => {
|
|
302
|
+
const focusTarget = this.shadowRoot?.querySelector<HTMLElement>("[autofocus], .close-button, .panel");
|
|
303
|
+
focusTarget?.focus();
|
|
304
|
+
});
|
|
301
305
|
}
|
|
302
306
|
|
|
303
307
|
document.addEventListener("keydown", this.handleKeydown);
|
|
@@ -316,10 +320,10 @@ export class RelDrawer extends LitElement {
|
|
|
316
320
|
document.removeEventListener("keydown", this.handleKeydown);
|
|
317
321
|
|
|
318
322
|
if (this.previousFocus && this.previousFocus.focus) {
|
|
319
|
-
|
|
323
|
+
this.updateComplete.then(() => {
|
|
320
324
|
this.previousFocus?.focus();
|
|
321
325
|
this.previousFocus = null;
|
|
322
|
-
}
|
|
326
|
+
});
|
|
323
327
|
}
|
|
324
328
|
|
|
325
329
|
this.dispatchEvent(
|
|
@@ -439,16 +443,8 @@ export class RelDrawer extends LitElement {
|
|
|
439
443
|
this.close("programmatic");
|
|
440
444
|
}
|
|
441
445
|
|
|
442
|
-
private close(
|
|
446
|
+
private close(_reason: DrawerCloseReason) {
|
|
443
447
|
this.open = false;
|
|
444
|
-
|
|
445
|
-
this.dispatchEvent(
|
|
446
|
-
new CustomEvent("rel-close", {
|
|
447
|
-
detail: { reason },
|
|
448
|
-
bubbles: true,
|
|
449
|
-
composed: true,
|
|
450
|
-
})
|
|
451
|
-
);
|
|
452
448
|
}
|
|
453
449
|
|
|
454
450
|
// Drag-to-close handlers
|
|
@@ -527,8 +523,8 @@ export class RelDrawer extends LitElement {
|
|
|
527
523
|
}
|
|
528
524
|
|
|
529
525
|
render() {
|
|
530
|
-
const hasTitle = this.
|
|
531
|
-
const hasDescription = this.
|
|
526
|
+
const hasTitle = !!this.title;
|
|
527
|
+
const hasDescription = !!this.description;
|
|
532
528
|
const hasFooter = this.hasSlotContent("footer");
|
|
533
529
|
const showCloseButton = this.dismissible;
|
|
534
530
|
const hasHeader = hasTitle || hasDescription || showCloseButton;
|
|
@@ -548,8 +544,7 @@ export class RelDrawer extends LitElement {
|
|
|
548
544
|
part="panel"
|
|
549
545
|
class="panel ${this.isDragging ? "dragging" : ""}"
|
|
550
546
|
data-side="${this.side}"
|
|
551
|
-
style="
|
|
552
|
-
.maxHeight}; ${this.getPanelStyle()}"
|
|
547
|
+
style="${this.width ? `--drawer-width: ${this.width};` : ''}${this.maxHeight ? `--drawer-max-height: ${this.maxHeight};` : ''}${this.getPanelStyle()}"
|
|
553
548
|
role="${this.modal ? "dialog" : "region"}"
|
|
554
549
|
aria-modal="${this.modal}"
|
|
555
550
|
tabindex="-1">
|
|
@@ -566,14 +561,10 @@ export class RelDrawer extends LitElement {
|
|
|
566
561
|
<div class="header-top">
|
|
567
562
|
<div>
|
|
568
563
|
${hasTitle
|
|
569
|
-
? html`<h2 class="title"
|
|
570
|
-
<slot name="title"></slot>
|
|
571
|
-
</h2>`
|
|
564
|
+
? html`<h2 class="title">${this.title}</h2>`
|
|
572
565
|
: ""}
|
|
573
566
|
${hasDescription
|
|
574
|
-
? html`<p class="description"
|
|
575
|
-
<slot name="description"></slot>
|
|
576
|
-
</p>`
|
|
567
|
+
? html`<p class="description">${this.description}</p>`
|
|
577
568
|
: ""}
|
|
578
569
|
</div>
|
|
579
570
|
${showCloseButton
|
|
@@ -605,7 +596,7 @@ export class RelDrawer extends LitElement {
|
|
|
605
596
|
|
|
606
597
|
${hasFooter
|
|
607
598
|
? html`<div part="footer" class="footer">
|
|
608
|
-
<slot name="footer"></slot>
|
|
599
|
+
<rel-drawer-footer><slot name="footer"></slot></rel-drawer-footer>
|
|
609
600
|
</div>`
|
|
610
601
|
: ""}
|
|
611
602
|
</div>
|
|
@@ -12,6 +12,18 @@ export interface MenuItem {
|
|
|
12
12
|
open?: boolean;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
@customElement("rel-menu-item")
|
|
16
|
+
export class RelMenuItem extends LitElement {
|
|
17
|
+
@property({ type: String }) label: string = "";
|
|
18
|
+
@property({ type: String }) value: string = "";
|
|
19
|
+
@property({ type: Boolean }) disabled: boolean = false;
|
|
20
|
+
@property({ type: String }) icon: string = "";
|
|
21
|
+
|
|
22
|
+
render() {
|
|
23
|
+
return html``;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
@customElement("rel-menu")
|
|
16
28
|
export class RelMenu extends LitElement {
|
|
17
29
|
@property({ type: String }) type: MenuType = "default";
|
|
@@ -19,6 +31,7 @@ export class RelMenu extends LitElement {
|
|
|
19
31
|
@property({ type: Array }) items: MenuItem[] = [];
|
|
20
32
|
|
|
21
33
|
@state() private focusedIndex: number = 0;
|
|
34
|
+
@state() private _menuItems: RelMenuItem[] = [];
|
|
22
35
|
|
|
23
36
|
static styles = css`
|
|
24
37
|
:host {
|
|
@@ -28,8 +41,8 @@ export class RelMenu extends LitElement {
|
|
|
28
41
|
.rel-menu {
|
|
29
42
|
position: relative;
|
|
30
43
|
display: inline-block;
|
|
31
|
-
background: var(--rel-
|
|
32
|
-
color: var(--rel-text-primary
|
|
44
|
+
background: var(--rel-color-bg-primary);
|
|
45
|
+
color: var(--rel-color-text-primary);
|
|
33
46
|
border-radius: var(--rel-borders-radius-border-radius-300);
|
|
34
47
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
35
48
|
min-width: 220px;
|
|
@@ -37,6 +50,7 @@ export class RelMenu extends LitElement {
|
|
|
37
50
|
font-size: var(--rel-fontSizes-sm);
|
|
38
51
|
padding: var(--rel-spacing-space-3xs) 0;
|
|
39
52
|
outline: none;
|
|
53
|
+
overflow: hidden;
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
.rel-menu:focus-visible {
|
|
@@ -57,15 +71,15 @@ export class RelMenu extends LitElement {
|
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
.rel-menu-item:hover {
|
|
60
|
-
background: var(--rel-
|
|
74
|
+
background: var(--rel-color-bg-hover);
|
|
61
75
|
}
|
|
62
76
|
|
|
63
77
|
.rel-menu-item:active {
|
|
64
|
-
background: var(--rel-
|
|
78
|
+
background: var(--rel-color-bg-hover);
|
|
65
79
|
}
|
|
66
80
|
|
|
67
81
|
.rel-menu-item.active {
|
|
68
|
-
background: var(--rel-
|
|
82
|
+
background: var(--rel-color-bg-hover);
|
|
69
83
|
font-weight: var(--rel-fontWeights-medium);
|
|
70
84
|
}
|
|
71
85
|
|
|
@@ -112,8 +126,8 @@ export class RelMenu extends LitElement {
|
|
|
112
126
|
top: calc(-1 * var(--rel-spacing-space-3xs));
|
|
113
127
|
left: calc(100% + var(--rel-spacing-space-2xs));
|
|
114
128
|
min-width: 200px;
|
|
115
|
-
background: var(--rel-
|
|
116
|
-
color: var(--rel-text-primary
|
|
129
|
+
background: var(--rel-color-bg-primary);
|
|
130
|
+
color: var(--rel-color-text-primary);
|
|
117
131
|
border-radius: var(--rel-borders-radius-border-radius-300);
|
|
118
132
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
119
133
|
padding: var(--rel-spacing-space-3xs) 0;
|
|
@@ -130,6 +144,23 @@ export class RelMenu extends LitElement {
|
|
|
130
144
|
}
|
|
131
145
|
`;
|
|
132
146
|
|
|
147
|
+
private _onSlotChange(e: Event) {
|
|
148
|
+
const slot = e.target as HTMLSlotElement;
|
|
149
|
+
this._menuItems = slot
|
|
150
|
+
.assignedElements()
|
|
151
|
+
.filter((el): el is RelMenuItem => el instanceof RelMenuItem);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private get _effectiveItems(): MenuItem[] {
|
|
155
|
+
if (this._menuItems.length > 0) {
|
|
156
|
+
return this._menuItems.map((el) => ({
|
|
157
|
+
label: el.label,
|
|
158
|
+
disabled: el.disabled,
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
return this.items;
|
|
162
|
+
}
|
|
163
|
+
|
|
133
164
|
connectedCallback() {
|
|
134
165
|
super.connectedCallback();
|
|
135
166
|
document.addEventListener("click", this.handleDocumentClick);
|
|
@@ -144,14 +175,14 @@ export class RelMenu extends LitElement {
|
|
|
144
175
|
const path = e.composedPath() as HTMLElement[];
|
|
145
176
|
const hit = path.some((n) => n?.classList?.contains("rel-menu"));
|
|
146
177
|
if (!hit) {
|
|
147
|
-
this.
|
|
178
|
+
this._effectiveItems.forEach((i) => (i.open = false));
|
|
148
179
|
this.requestUpdate();
|
|
149
180
|
}
|
|
150
181
|
};
|
|
151
182
|
|
|
152
183
|
private onItemEnter(item: MenuItem) {
|
|
153
184
|
if (this.type === "arrow" && item.submenu?.length) {
|
|
154
|
-
this.
|
|
185
|
+
this._effectiveItems.forEach((i) => {
|
|
155
186
|
if (i !== item) i.open = false;
|
|
156
187
|
});
|
|
157
188
|
item.open = true;
|
|
@@ -172,7 +203,7 @@ export class RelMenu extends LitElement {
|
|
|
172
203
|
if (this.type === "checkbox") {
|
|
173
204
|
item.checked = !item.checked;
|
|
174
205
|
this.dispatchEvent(
|
|
175
|
-
new CustomEvent("
|
|
206
|
+
new CustomEvent("rel-check", {
|
|
176
207
|
detail: { item, checked: item.checked },
|
|
177
208
|
bubbles: true,
|
|
178
209
|
composed: true,
|
|
@@ -184,17 +215,17 @@ export class RelMenu extends LitElement {
|
|
|
184
215
|
|
|
185
216
|
if (this.type === "arrow" && item.submenu?.length) {
|
|
186
217
|
const next = !item.open;
|
|
187
|
-
this.
|
|
218
|
+
this._effectiveItems.forEach((i) => (i.open = false));
|
|
188
219
|
item.open = next;
|
|
189
220
|
this.requestUpdate();
|
|
190
221
|
return;
|
|
191
222
|
}
|
|
192
223
|
|
|
193
224
|
// Default: set active
|
|
194
|
-
this.
|
|
225
|
+
this._effectiveItems.forEach((i) => (i.active = false));
|
|
195
226
|
item.active = true;
|
|
196
227
|
this.dispatchEvent(
|
|
197
|
-
new CustomEvent("
|
|
228
|
+
new CustomEvent("rel-select", {
|
|
198
229
|
detail: { item },
|
|
199
230
|
bubbles: true,
|
|
200
231
|
composed: true,
|
|
@@ -205,14 +236,14 @@ export class RelMenu extends LitElement {
|
|
|
205
236
|
|
|
206
237
|
private onSubClick(parent: MenuItem, sub: MenuItem, ev?: Event) {
|
|
207
238
|
ev?.stopPropagation();
|
|
208
|
-
this.
|
|
239
|
+
this._effectiveItems.forEach((i) => {
|
|
209
240
|
i.active = false;
|
|
210
241
|
i.submenu?.forEach((s) => (s.active = false));
|
|
211
242
|
});
|
|
212
243
|
sub.active = true;
|
|
213
244
|
parent.open = false;
|
|
214
245
|
this.dispatchEvent(
|
|
215
|
-
new CustomEvent("submenu-
|
|
246
|
+
new CustomEvent("rel-submenu-select", {
|
|
216
247
|
detail: { parent, sub },
|
|
217
248
|
bubbles: true,
|
|
218
249
|
composed: true,
|
|
@@ -226,7 +257,7 @@ export class RelMenu extends LitElement {
|
|
|
226
257
|
if (!item.disabled) {
|
|
227
258
|
item.checked = !item.checked;
|
|
228
259
|
this.dispatchEvent(
|
|
229
|
-
new CustomEvent("
|
|
260
|
+
new CustomEvent("rel-check", {
|
|
230
261
|
detail: { item, checked: item.checked },
|
|
231
262
|
bubbles: true,
|
|
232
263
|
composed: true,
|
|
@@ -237,7 +268,7 @@ export class RelMenu extends LitElement {
|
|
|
237
268
|
}
|
|
238
269
|
|
|
239
270
|
private onKeydown(ev: KeyboardEvent) {
|
|
240
|
-
const last = this.
|
|
271
|
+
const last = this._effectiveItems.length - 1;
|
|
241
272
|
|
|
242
273
|
if (ev.key === "ArrowDown") {
|
|
243
274
|
this.focusedIndex = Math.min(last, this.focusedIndex + 1);
|
|
@@ -246,16 +277,16 @@ export class RelMenu extends LitElement {
|
|
|
246
277
|
this.focusedIndex = Math.max(0, this.focusedIndex - 1);
|
|
247
278
|
ev.preventDefault();
|
|
248
279
|
} else if (ev.key === "ArrowRight") {
|
|
249
|
-
const item = this.
|
|
280
|
+
const item = this._effectiveItems[this.focusedIndex];
|
|
250
281
|
if (this.type === "arrow" && item?.submenu?.length) {
|
|
251
282
|
item.open = true;
|
|
252
283
|
this.requestUpdate();
|
|
253
284
|
}
|
|
254
285
|
} else if (ev.key === "ArrowLeft" || ev.key === "Escape") {
|
|
255
|
-
this.
|
|
286
|
+
this._effectiveItems.forEach((i) => (i.open = false));
|
|
256
287
|
this.requestUpdate();
|
|
257
288
|
} else if (ev.key === "Enter" || ev.key === " ") {
|
|
258
|
-
const item = this.
|
|
289
|
+
const item = this._effectiveItems[this.focusedIndex];
|
|
259
290
|
this.onItemClick(item, this.focusedIndex);
|
|
260
291
|
ev.preventDefault();
|
|
261
292
|
}
|
|
@@ -314,13 +345,14 @@ export class RelMenu extends LitElement {
|
|
|
314
345
|
|
|
315
346
|
render() {
|
|
316
347
|
return html`
|
|
348
|
+
<slot name="items" style="display:none;" @slotchange="${this._onSlotChange}"></slot>
|
|
317
349
|
<div
|
|
318
350
|
class="rel-menu"
|
|
319
351
|
role="menu"
|
|
320
352
|
tabindex="0"
|
|
321
353
|
@keydown="${this.onKeydown}"
|
|
322
354
|
@click="${(e: Event) => e.stopPropagation()}">
|
|
323
|
-
${this.
|
|
355
|
+
${this._effectiveItems.map((item, index) => this.renderMenuItem(item, index))}
|
|
324
356
|
</div>
|
|
325
357
|
`;
|
|
326
358
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { LitElement, html, css } from "lit";
|
|
2
2
|
import { customElement, state, query } from "lit/decorators.js";
|
|
3
3
|
import { RelMenubarMenu } from "./rel-menubar-menu";
|
|
4
|
+
import "@reliability-design/icons/rel-icon";
|
|
5
|
+
import "../rel-checkbox/rel-checkbox";
|
|
4
6
|
|
|
5
7
|
interface MenuState {
|
|
6
8
|
menu: RelMenubarMenu;
|
|
@@ -52,7 +54,7 @@ export class RelMenubar extends LitElement {
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
.menubar-trigger:hover {
|
|
55
|
-
background: var(--rel-
|
|
57
|
+
background: var(--rel-color-bg-hover);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
.menubar-trigger:focus-visible {
|
|
@@ -61,13 +63,13 @@ export class RelMenubar extends LitElement {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
.menubar-trigger.active {
|
|
64
|
-
background: var(--rel-
|
|
66
|
+
background: var(--rel-color-bg-hover);
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
.menubar-panel {
|
|
68
70
|
position: fixed;
|
|
69
71
|
min-width: 220px;
|
|
70
|
-
background: var(--rel-
|
|
72
|
+
background: var(--rel-color-bg-primary);
|
|
71
73
|
border: var(--rel-borders-width-stroke-100) solid var(--rel-colors-gray-border);
|
|
72
74
|
border-radius: var(--rel-borders-radius-border-radius-200);
|
|
73
75
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
@@ -96,7 +98,7 @@ export class RelMenubar extends LitElement {
|
|
|
96
98
|
|
|
97
99
|
.menu-item:hover,
|
|
98
100
|
.menu-item.focused {
|
|
99
|
-
background: var(--rel-
|
|
101
|
+
background: var(--rel-color-bg-hover);
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
.menu-item[data-disabled="true"] {
|
|
@@ -127,14 +129,24 @@ export class RelMenubar extends LitElement {
|
|
|
127
129
|
.menu-checkbox.focused,
|
|
128
130
|
.menu-radio-item:hover,
|
|
129
131
|
.menu-radio-item.focused {
|
|
130
|
-
background: var(--rel-
|
|
132
|
+
background: var(--rel-color-bg-hover);
|
|
131
133
|
}
|
|
132
134
|
|
|
133
|
-
.menu-checkbox
|
|
135
|
+
.menu-checkbox rel-checkbox,
|
|
134
136
|
.menu-radio-item::before {
|
|
135
137
|
margin: 0;
|
|
136
138
|
}
|
|
137
139
|
|
|
140
|
+
:host-context([data-theme="dark"]) rel-checkbox,
|
|
141
|
+
:host-context(.dark) rel-checkbox {
|
|
142
|
+
color: var(--rel-color-text-primary);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
rel-icon {
|
|
146
|
+
display: inline-flex;
|
|
147
|
+
pointer-events: none;
|
|
148
|
+
}
|
|
149
|
+
|
|
138
150
|
.menu-radio-item {
|
|
139
151
|
position: relative;
|
|
140
152
|
padding-left: calc(var(--rel-spacing-space-md) + var(--rel-spacing-space-md));
|
|
@@ -165,16 +177,14 @@ export class RelMenubar extends LitElement {
|
|
|
165
177
|
position: relative;
|
|
166
178
|
}
|
|
167
179
|
|
|
168
|
-
.menu-submenu-trigger
|
|
169
|
-
content: "▸";
|
|
180
|
+
.menu-submenu-trigger rel-icon {
|
|
170
181
|
opacity: 0.6;
|
|
171
|
-
font-size: var(--rel-fontSizes-sm);
|
|
172
182
|
}
|
|
173
183
|
|
|
174
184
|
.submenu-panel {
|
|
175
185
|
position: fixed;
|
|
176
186
|
min-width: 200px;
|
|
177
|
-
background: var(--rel-
|
|
187
|
+
background: var(--rel-color-bg-primary);
|
|
178
188
|
border: var(--rel-borders-width-stroke-100) solid var(--rel-colors-gray-border);
|
|
179
189
|
border-radius: var(--rel-borders-radius-border-radius-200);
|
|
180
190
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
@@ -292,8 +302,16 @@ export class RelMenubar extends LitElement {
|
|
|
292
302
|
) as HTMLElement;
|
|
293
303
|
if (trigger) {
|
|
294
304
|
this.openMenu(this.focusedTriggerIndex, trigger);
|
|
295
|
-
|
|
296
|
-
|
|
305
|
+
this.updateComplete.then(() => {
|
|
306
|
+
const focusTarget = this.shadowRoot?.querySelector<HTMLElement>(
|
|
307
|
+
"[autofocus], [role='menuitem']"
|
|
308
|
+
);
|
|
309
|
+
if (focusTarget) {
|
|
310
|
+
focusTarget.focus();
|
|
311
|
+
} else {
|
|
312
|
+
this.focusMenuItem(0);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
297
315
|
}
|
|
298
316
|
} else if (key === "ArrowDown" && this.openMenuIndex !== -1) {
|
|
299
317
|
event.preventDefault();
|
|
@@ -368,11 +386,7 @@ export class RelMenubar extends LitElement {
|
|
|
368
386
|
|
|
369
387
|
private handleItemClick(item: HTMLElement) {
|
|
370
388
|
if (item.hasAttribute("data-checkbox")) {
|
|
371
|
-
|
|
372
|
-
if (checkbox) {
|
|
373
|
-
checkbox.checked = !checkbox.checked;
|
|
374
|
-
this.dispatchChangeEvent("checkbox", item.textContent?.trim() || "", checkbox.checked);
|
|
375
|
-
}
|
|
389
|
+
// Toggle is handled by rel-checkbox @rel-change; nothing to do here
|
|
376
390
|
} else if (item.hasAttribute("data-radio")) {
|
|
377
391
|
const radioGroup = item.closest("[data-radio-group]") as HTMLElement;
|
|
378
392
|
const value = item.getAttribute("data-radio") || item.getAttribute("value") || "";
|
|
@@ -398,7 +412,7 @@ export class RelMenubar extends LitElement {
|
|
|
398
412
|
}
|
|
399
413
|
}
|
|
400
414
|
|
|
401
|
-
private openSubmenu(submenuTrigger: HTMLElement) {
|
|
415
|
+
private openSubmenu(submenuTrigger: HTMLElement, renderedTrigger?: HTMLElement) {
|
|
402
416
|
this.openSubmenuElement = submenuTrigger;
|
|
403
417
|
this.requestUpdate();
|
|
404
418
|
|
|
@@ -407,7 +421,10 @@ export class RelMenubar extends LitElement {
|
|
|
407
421
|
`.submenu-panel[data-submenu-id="${submenuTrigger.getAttribute("data-submenu") || ""}"]`
|
|
408
422
|
) as HTMLElement;
|
|
409
423
|
if (submenuPanel) {
|
|
410
|
-
|
|
424
|
+
// Use the rendered shadow-DOM element for getBoundingClientRect() —
|
|
425
|
+
// the light-DOM submenuTrigger is in a display:none slot and returns {0,0,0,0}.
|
|
426
|
+
const positionTarget = renderedTrigger ?? submenuTrigger;
|
|
427
|
+
const rect = positionTarget.getBoundingClientRect();
|
|
411
428
|
submenuPanel.style.top = `${rect.top}px`;
|
|
412
429
|
submenuPanel.style.left = `${rect.right + 4}px`;
|
|
413
430
|
}
|
|
@@ -420,9 +437,13 @@ export class RelMenubar extends LitElement {
|
|
|
420
437
|
}
|
|
421
438
|
|
|
422
439
|
private dispatchChangeEvent(type: "checkbox" | "radio", labelOrName: string, value: string | boolean) {
|
|
440
|
+
const detail =
|
|
441
|
+
type === "checkbox"
|
|
442
|
+
? { type, label: labelOrName, name: "", checked: value as boolean }
|
|
443
|
+
: { type, label: "", name: labelOrName, value: value as string };
|
|
423
444
|
this.dispatchEvent(
|
|
424
445
|
new CustomEvent("rel-menubar-change", {
|
|
425
|
-
detail
|
|
446
|
+
detail,
|
|
426
447
|
bubbles: true,
|
|
427
448
|
composed: true,
|
|
428
449
|
})
|
|
@@ -465,7 +486,14 @@ export class RelMenubar extends LitElement {
|
|
|
465
486
|
this.handleItemClick(item as HTMLElement);
|
|
466
487
|
}}"
|
|
467
488
|
>
|
|
468
|
-
<
|
|
489
|
+
<rel-checkbox
|
|
490
|
+
.checked="${checkbox?.checked || false}"
|
|
491
|
+
@click="${(e: Event) => e.stopPropagation()}"
|
|
492
|
+
@rel-change="${(e: CustomEvent) => {
|
|
493
|
+
if (checkbox) checkbox.checked = e.detail.checked;
|
|
494
|
+
this.dispatchChangeEvent("checkbox", label.textContent?.replace(/\s+/g, " ").trim() || "", e.detail.checked);
|
|
495
|
+
}}"
|
|
496
|
+
></rel-checkbox>
|
|
469
497
|
<span>${label.textContent?.replace(/\s+/g, " ").trim()}</span>
|
|
470
498
|
</label>
|
|
471
499
|
`;
|
|
@@ -478,10 +506,11 @@ export class RelMenubar extends LitElement {
|
|
|
478
506
|
return html`
|
|
479
507
|
<div
|
|
480
508
|
class="menu-item menu-submenu-trigger ${isFocused ? "focused" : ""}"
|
|
481
|
-
@click="${() => this.openSubmenu(item as HTMLElement)}"
|
|
482
|
-
@mouseenter="${() => this.openSubmenu(item as HTMLElement)}"
|
|
509
|
+
@click="${(e: Event) => this.openSubmenu(item as HTMLElement, e.currentTarget as HTMLElement)}"
|
|
510
|
+
@mouseenter="${(e: Event) => this.openSubmenu(item as HTMLElement, e.currentTarget as HTMLElement)}"
|
|
483
511
|
>
|
|
484
512
|
<span>${label}</span>
|
|
513
|
+
<rel-icon name="chevron-right"></rel-icon>
|
|
485
514
|
</div>
|
|
486
515
|
${this.renderSubmenu(item as HTMLElement, submenuId)}
|
|
487
516
|
`;
|