@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.
Files changed (60) hide show
  1. package/dist/components/rel-accordion/rel-accordion.ts +4 -0
  2. package/dist/components/rel-alert/rel-alert.ts +83 -13
  3. package/dist/components/rel-avatar/rel-avatar.ts +3 -2
  4. package/dist/components/rel-badge/rel-badge.ts +6 -2
  5. package/dist/components/rel-button/rel-button.ts +64 -8
  6. package/dist/components/rel-calendar/rel-calendar.ts +3 -3
  7. package/dist/components/rel-carousel/rel-carousel.ts +10 -11
  8. package/dist/components/rel-checkbox/rel-checkbox.ts +33 -2
  9. package/dist/components/rel-chip/rel-chip.ts +63 -5
  10. package/dist/components/rel-divider/rel-divider.ts +9 -0
  11. package/dist/components/rel-drawer/rel-drawer-footer.ts +29 -0
  12. package/dist/components/rel-drawer/rel-drawer.ts +17 -26
  13. package/dist/components/rel-menu/rel-menu.ts +53 -21
  14. package/dist/components/rel-menubar/rel-menubar.ts +52 -23
  15. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +240 -143
  16. package/dist/components/rel-nav-menu/rel-nav-menu.ts +227 -331
  17. package/dist/components/rel-navbar/rel-navbar.ts +13 -0
  18. package/dist/components/rel-pagination/rel-pagination.ts +11 -6
  19. package/dist/components/rel-popover/rel-popover.ts +16 -13
  20. package/dist/components/rel-radio/rel-radio.ts +18 -1
  21. package/dist/components/rel-resizable/rel-resizable-handle.ts +4 -8
  22. package/dist/components/rel-select/rel-select.ts +14 -0
  23. package/dist/components/rel-sheet/rel-sheet.ts +7 -6
  24. package/dist/components/rel-sidebar/rel-sidebar.ts +13 -5
  25. package/dist/components/rel-slider/rel-slider.ts +25 -2
  26. package/dist/components/rel-snackbar/rel-snackbar.ts +46 -16
  27. package/dist/components/rel-stepper/rel-stepper.ts +32 -21
  28. package/dist/components/rel-switch/rel-switch.ts +19 -6
  29. package/dist/components/rel-tab/rel-tab.ts +49 -15
  30. package/dist/components/rel-table/rel-table-body.ts +5 -0
  31. package/dist/components/rel-table/rel-table-caption.ts +6 -1
  32. package/dist/components/rel-table/rel-table-cell.ts +42 -49
  33. package/dist/components/rel-table/rel-table-footer.ts +5 -0
  34. package/dist/components/rel-table/rel-table-head.ts +13 -1
  35. package/dist/components/rel-table/rel-table-header.ts +5 -0
  36. package/dist/components/rel-table/rel-table-row.ts +7 -3
  37. package/dist/components/rel-table/rel-table.ts +8 -2
  38. package/dist/components/rel-textfield/rel-textfield.ts +20 -20
  39. package/dist/components/rel-toast/rel-toast.ts +31 -10
  40. package/dist/components/rel-tooltip/rel-tooltip.ts +123 -80
  41. package/dist/components/rel-topbar/rel-topbar-actions.ts +23 -0
  42. package/dist/components/rel-topbar/rel-topbar-brand.ts +46 -0
  43. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +33 -0
  44. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +28 -0
  45. package/dist/components/rel-topbar/rel-topbar-item.ts +315 -0
  46. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +23 -0
  47. package/dist/components/rel-topbar/rel-topbar-profile.ts +248 -0
  48. package/dist/components/rel-topbar/rel-topbar-utilities.ts +23 -0
  49. package/dist/components/rel-topbar/rel-topbar.ts +329 -0
  50. package/dist/index.d.mts +278 -289
  51. package/dist/index.d.ts +278 -289
  52. package/dist/index.js +4498 -5727
  53. package/dist/index.js.map +1 -1
  54. package/dist/index.mjs +4535 -5756
  55. package/dist/index.mjs.map +1 -1
  56. package/dist/styles/vars.css +346 -294
  57. package/dist/{vars-ITL2K3KO.css → vars-TBB4BMSD.css} +346 -294
  58. package/package.json +2 -1
  59. package/dist/components/rel-quote-page/README.md +0 -166
  60. 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
- setTimeout(() => {
299
- this.focusPanel();
300
- }, 50);
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
- setTimeout(() => {
323
+ this.updateComplete.then(() => {
320
324
  this.previousFocus?.focus();
321
325
  this.previousFocus = null;
322
- }, 50);
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(reason: DrawerCloseReason) {
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.hasSlotContent("title");
531
- const hasDescription = this.hasSlotContent("description");
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="--drawer-width: ${this.width}; --drawer-max-height: ${this
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-colors-white, #fff);
32
- color: var(--rel-text-primary, #333);
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-surface-secondary, #fafafa);
74
+ background: var(--rel-color-bg-hover);
61
75
  }
62
76
 
63
77
  .rel-menu-item:active {
64
- background: var(--rel-colors-gray-divider, #bdbdbd);
78
+ background: var(--rel-color-bg-hover);
65
79
  }
66
80
 
67
81
  .rel-menu-item.active {
68
- background: var(--rel-surface-secondary, #fafafa);
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-colors-white, #fff);
116
- color: var(--rel-text-primary, #333);
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.items.forEach((i) => (i.open = false));
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.items.forEach((i) => {
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("item-checked", {
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.items.forEach((i) => (i.open = false));
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.items.forEach((i) => (i.active = false));
225
+ this._effectiveItems.forEach((i) => (i.active = false));
195
226
  item.active = true;
196
227
  this.dispatchEvent(
197
- new CustomEvent("item-selected", {
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.items.forEach((i) => {
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-selected", {
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("item-checked", {
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.items.length - 1;
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.items[this.focusedIndex];
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.items.forEach((i) => (i.open = false));
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.items[this.focusedIndex];
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.items.map((item, index) => this.renderMenuItem(item, index))}
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-surface-secondary, #fafafa);
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-surface-secondary, #fafafa);
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-colors-white);
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-surface-secondary, #fafafa);
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-surface-secondary, #fafafa);
132
+ background: var(--rel-color-bg-hover);
131
133
  }
132
134
 
133
- .menu-checkbox input[type="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::after {
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-colors-white);
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
- // Focus first item
296
- setTimeout(() => this.focusMenuItem(0), 50);
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
- const checkbox = item.querySelector('input[type="checkbox"]') as HTMLInputElement;
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
- const rect = submenuTrigger.getBoundingClientRect();
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: { type, [type === "checkbox" ? "label" : "name"]: labelOrName, [type === "checkbox" ? "checked" : "value"]: value },
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
- <input type="checkbox" .checked="${checkbox?.checked || false}" @click="${(e: Event) => e.stopPropagation()}" />
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
  `;