@reliability-design/web 1.0.3 → 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 (126) hide show
  1. package/dist/components/rel-accordion/README.md +132 -0
  2. package/dist/components/rel-accordion/rel-accordion.ts +47 -16
  3. package/dist/components/rel-alert/README.md +141 -0
  4. package/dist/components/rel-alert/rel-alert.ts +101 -20
  5. package/dist/components/rel-avatar/README.md +119 -0
  6. package/dist/components/rel-avatar/rel-avatar.ts +3 -2
  7. package/dist/components/rel-badge/README.md +86 -0
  8. package/dist/components/rel-badge/rel-badge.ts +11 -7
  9. package/dist/components/rel-breadcrumb/README.md +102 -0
  10. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +12 -6
  11. package/dist/components/rel-button/README.md +130 -0
  12. package/dist/components/rel-button/rel-button.ts +64 -8
  13. package/dist/components/rel-calendar/README.md +109 -0
  14. package/dist/components/rel-calendar/index.ts +1 -0
  15. package/dist/components/rel-calendar/rel-calendar.ts +467 -0
  16. package/dist/components/rel-card/README.md +94 -0
  17. package/dist/components/rel-card/rel-card.ts +12 -3
  18. package/dist/components/rel-cardmedia/README.md +127 -0
  19. package/dist/components/rel-cardmedia/rel-cardmedia.ts +14 -4
  20. package/dist/components/rel-carousel/README.md +166 -0
  21. package/dist/components/rel-carousel/index.ts +1 -0
  22. package/dist/components/rel-carousel/rel-carousel.ts +468 -0
  23. package/dist/components/rel-chart/README.md +286 -0
  24. package/dist/components/rel-chart/index.ts +1 -0
  25. package/dist/components/rel-chart/rel-chart.ts +736 -0
  26. package/dist/components/rel-checkbox/README.md +77 -0
  27. package/dist/components/rel-checkbox/rel-checkbox.ts +51 -12
  28. package/dist/components/rel-chip/README.md +114 -0
  29. package/dist/components/rel-chip/rel-chip.ts +83 -9
  30. package/dist/components/rel-container/README.md +99 -0
  31. package/dist/components/rel-date-picker/README.md +253 -0
  32. package/dist/components/rel-date-picker/index.ts +1 -0
  33. package/dist/components/rel-date-picker/rel-date-picker.ts +916 -0
  34. package/dist/components/rel-divider/README.md +100 -0
  35. package/dist/components/rel-divider/rel-divider.ts +9 -0
  36. package/dist/components/rel-drawer/README.md +200 -0
  37. package/dist/components/rel-drawer/index.ts +1 -0
  38. package/dist/components/rel-drawer/rel-drawer-footer.ts +29 -0
  39. package/dist/components/rel-drawer/rel-drawer.ts +612 -0
  40. package/dist/components/rel-kbd/README.md +151 -0
  41. package/dist/components/rel-kbd/rel-kbd.ts +118 -0
  42. package/dist/components/rel-layout/README.md +88 -0
  43. package/dist/components/rel-menu/README.md +151 -0
  44. package/dist/components/rel-menu/rel-menu.ts +64 -24
  45. package/dist/components/rel-menubar/README.md +329 -0
  46. package/dist/components/rel-menubar/index.ts +2 -0
  47. package/dist/components/rel-menubar/rel-menubar-menu.ts +16 -0
  48. package/dist/components/rel-menubar/rel-menubar.ts +605 -0
  49. package/dist/components/rel-nav-menu/README.md +289 -0
  50. package/dist/components/rel-nav-menu/index.ts +3 -0
  51. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +240 -0
  52. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +53 -0
  53. package/dist/components/rel-nav-menu/rel-nav-menu.ts +227 -0
  54. package/dist/components/rel-navbar/README.md +126 -0
  55. package/dist/components/rel-navbar/rel-navbar.ts +104 -0
  56. package/dist/components/rel-otp/README.md +440 -0
  57. package/dist/components/rel-otp/index.ts +1 -0
  58. package/dist/components/rel-otp/rel-otp.ts +504 -0
  59. package/dist/components/rel-pagination/README.md +410 -0
  60. package/dist/components/rel-pagination/index.ts +1 -0
  61. package/dist/components/rel-pagination/rel-pagination.ts +381 -0
  62. package/dist/components/rel-popover/README.md +568 -0
  63. package/dist/components/rel-popover/index.ts +2 -0
  64. package/dist/components/rel-popover/rel-popover-content.ts +55 -0
  65. package/dist/components/rel-popover/rel-popover.ts +330 -0
  66. package/dist/components/rel-progress/README.md +110 -0
  67. package/dist/components/rel-progress/rel-progress.ts +32 -5
  68. package/dist/components/rel-radio/README.md +120 -0
  69. package/dist/components/rel-radio/rel-radio.ts +31 -6
  70. package/dist/components/rel-resizable/README.md +140 -0
  71. package/dist/components/rel-resizable/index.ts +3 -0
  72. package/dist/components/rel-resizable/rel-resizable-group.ts +374 -0
  73. package/dist/components/rel-resizable/rel-resizable-handle.ts +145 -0
  74. package/dist/components/rel-resizable/rel-resizable-panel.ts +47 -0
  75. package/dist/components/rel-segmented-button/README.md +141 -0
  76. package/dist/components/rel-segmented-button/rel-segmented-button.ts +18 -13
  77. package/dist/components/rel-select/README.md +107 -0
  78. package/dist/components/rel-select/rel-select.ts +28 -14
  79. package/dist/components/rel-sheet/README.md +224 -0
  80. package/dist/components/rel-sheet/rel-sheet.ts +684 -0
  81. package/dist/components/rel-sidebar/README.md +209 -0
  82. package/dist/components/rel-sidebar/rel-sidebar.ts +1166 -0
  83. package/dist/components/rel-slider/README.md +135 -0
  84. package/dist/components/rel-slider/rel-slider.ts +44 -9
  85. package/dist/components/rel-snackbar/README.md +134 -0
  86. package/dist/components/rel-snackbar/rel-snackbar.ts +109 -14
  87. package/dist/components/rel-stepper/README.md +160 -0
  88. package/dist/components/rel-stepper/rel-stepper.ts +38 -27
  89. package/dist/components/rel-switch/README.md +102 -0
  90. package/dist/components/rel-switch/rel-switch.ts +34 -12
  91. package/dist/components/rel-tab/README.md +163 -0
  92. package/dist/components/rel-tab/rel-tab.ts +79 -23
  93. package/dist/components/rel-table/README.md +178 -0
  94. package/dist/components/rel-table/rel-table-body.ts +21 -0
  95. package/dist/components/rel-table/rel-table-caption.ts +27 -0
  96. package/dist/components/rel-table/rel-table-cell.ts +42 -0
  97. package/dist/components/rel-table/rel-table-footer.ts +23 -0
  98. package/dist/components/rel-table/rel-table-head.ts +45 -0
  99. package/dist/components/rel-table/rel-table-header.ts +21 -0
  100. package/dist/components/rel-table/rel-table-row.ts +36 -0
  101. package/dist/components/rel-table/rel-table.ts +53 -0
  102. package/dist/components/rel-textfield/README.md +90 -0
  103. package/dist/components/rel-textfield/rel-textfield.ts +55 -39
  104. package/dist/components/rel-toast/README.md +148 -0
  105. package/dist/components/rel-toast/rel-toast.ts +63 -24
  106. package/dist/components/rel-tooltip/README.md +103 -0
  107. package/dist/components/rel-tooltip/rel-tooltip.ts +123 -80
  108. package/dist/components/rel-topbar/rel-topbar-actions.ts +23 -0
  109. package/dist/components/rel-topbar/rel-topbar-brand.ts +46 -0
  110. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +33 -0
  111. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +28 -0
  112. package/dist/components/rel-topbar/rel-topbar-item.ts +315 -0
  113. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +23 -0
  114. package/dist/components/rel-topbar/rel-topbar-profile.ts +248 -0
  115. package/dist/components/rel-topbar/rel-topbar-utilities.ts +23 -0
  116. package/dist/components/rel-topbar/rel-topbar.ts +329 -0
  117. package/dist/index.d.mts +831 -7
  118. package/dist/index.d.ts +831 -7
  119. package/dist/index.js +9500 -1564
  120. package/dist/index.js.map +1 -1
  121. package/dist/index.mjs +9240 -1344
  122. package/dist/index.mjs.map +1 -1
  123. package/dist/styles/vars.css +187 -25
  124. package/dist/vars-TBB4BMSD.css +346 -0
  125. package/package.json +2 -1
  126. package/dist/vars-6ZIUPIU4.css +0 -184
@@ -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,14 +41,21 @@ export class RelMenu extends LitElement {
28
41
  .rel-menu {
29
42
  position: relative;
30
43
  display: inline-block;
31
- background: var(--rel-colors-white);
44
+ background: var(--rel-color-bg-primary);
45
+ color: var(--rel-color-text-primary);
32
46
  border-radius: var(--rel-borders-radius-border-radius-300);
33
47
  box-shadow: var(--rel-shadows-shadow-300);
34
48
  min-width: 220px;
35
- font-family: var(--rel-fontFamilies-primary);
49
+ font-family: var(--rel-fontFamilies-primary, sans-serif);
36
50
  font-size: var(--rel-fontSizes-sm);
37
51
  padding: var(--rel-spacing-space-3xs) 0;
38
52
  outline: none;
53
+ overflow: hidden;
54
+ }
55
+
56
+ .rel-menu:focus-visible {
57
+ outline: 2px solid var(--rel-colors-blue-primary, #0091ea);
58
+ outline-offset: 2px;
39
59
  }
40
60
 
41
61
  .rel-menu-item {
@@ -51,26 +71,27 @@ export class RelMenu extends LitElement {
51
71
  }
52
72
 
53
73
  .rel-menu-item:hover {
54
- background: var(--rel-colors-gray-border);
74
+ background: var(--rel-color-bg-hover);
55
75
  }
56
76
 
57
77
  .rel-menu-item:active {
58
- background: var(--rel-colors-gray-tertiary);
78
+ background: var(--rel-color-bg-hover);
59
79
  }
60
80
 
61
81
  .rel-menu-item.active {
62
- background: var(--rel-colors-gray-tertiary);
82
+ background: var(--rel-color-bg-hover);
83
+ font-weight: var(--rel-fontWeights-medium);
63
84
  }
64
85
 
65
86
  .rel-menu-item.disabled {
66
- background-color: var(--rel-colors-gray-light);
67
- color: var(--rel-colors-gray-placeholder);
87
+ background-color: transparent;
88
+ color: var(--rel-text-disabled, #9e9e9e);
68
89
  cursor: not-allowed;
69
90
  }
70
91
 
71
92
  .rel-menu-item[data-focused="true"] {
72
- border-top: var(--rel-borders-width-stroke-200) solid var(--rel-colors-gray-primary);
73
- border-bottom: var(--rel-borders-width-stroke-200) solid var(--rel-colors-gray-primary);
93
+ outline: 2px solid var(--rel-colors-blue-primary, #0091ea);
94
+ outline-offset: -2px;
74
95
  }
75
96
 
76
97
  .menu-check-row {
@@ -105,7 +126,8 @@ export class RelMenu extends LitElement {
105
126
  top: calc(-1 * var(--rel-spacing-space-3xs));
106
127
  left: calc(100% + var(--rel-spacing-space-2xs));
107
128
  min-width: 200px;
108
- background: var(--rel-colors-white);
129
+ background: var(--rel-color-bg-primary);
130
+ color: var(--rel-color-text-primary);
109
131
  border-radius: var(--rel-borders-radius-border-radius-300);
110
132
  box-shadow: var(--rel-shadows-shadow-300);
111
133
  padding: var(--rel-spacing-space-3xs) 0;
@@ -122,6 +144,23 @@ export class RelMenu extends LitElement {
122
144
  }
123
145
  `;
124
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
+
125
164
  connectedCallback() {
126
165
  super.connectedCallback();
127
166
  document.addEventListener("click", this.handleDocumentClick);
@@ -136,14 +175,14 @@ export class RelMenu extends LitElement {
136
175
  const path = e.composedPath() as HTMLElement[];
137
176
  const hit = path.some((n) => n?.classList?.contains("rel-menu"));
138
177
  if (!hit) {
139
- this.items.forEach((i) => (i.open = false));
178
+ this._effectiveItems.forEach((i) => (i.open = false));
140
179
  this.requestUpdate();
141
180
  }
142
181
  };
143
182
 
144
183
  private onItemEnter(item: MenuItem) {
145
184
  if (this.type === "arrow" && item.submenu?.length) {
146
- this.items.forEach((i) => {
185
+ this._effectiveItems.forEach((i) => {
147
186
  if (i !== item) i.open = false;
148
187
  });
149
188
  item.open = true;
@@ -164,7 +203,7 @@ export class RelMenu extends LitElement {
164
203
  if (this.type === "checkbox") {
165
204
  item.checked = !item.checked;
166
205
  this.dispatchEvent(
167
- new CustomEvent("item-checked", {
206
+ new CustomEvent("rel-check", {
168
207
  detail: { item, checked: item.checked },
169
208
  bubbles: true,
170
209
  composed: true,
@@ -176,17 +215,17 @@ export class RelMenu extends LitElement {
176
215
 
177
216
  if (this.type === "arrow" && item.submenu?.length) {
178
217
  const next = !item.open;
179
- this.items.forEach((i) => (i.open = false));
218
+ this._effectiveItems.forEach((i) => (i.open = false));
180
219
  item.open = next;
181
220
  this.requestUpdate();
182
221
  return;
183
222
  }
184
223
 
185
224
  // Default: set active
186
- this.items.forEach((i) => (i.active = false));
225
+ this._effectiveItems.forEach((i) => (i.active = false));
187
226
  item.active = true;
188
227
  this.dispatchEvent(
189
- new CustomEvent("item-selected", {
228
+ new CustomEvent("rel-select", {
190
229
  detail: { item },
191
230
  bubbles: true,
192
231
  composed: true,
@@ -197,14 +236,14 @@ export class RelMenu extends LitElement {
197
236
 
198
237
  private onSubClick(parent: MenuItem, sub: MenuItem, ev?: Event) {
199
238
  ev?.stopPropagation();
200
- this.items.forEach((i) => {
239
+ this._effectiveItems.forEach((i) => {
201
240
  i.active = false;
202
241
  i.submenu?.forEach((s) => (s.active = false));
203
242
  });
204
243
  sub.active = true;
205
244
  parent.open = false;
206
245
  this.dispatchEvent(
207
- new CustomEvent("submenu-selected", {
246
+ new CustomEvent("rel-submenu-select", {
208
247
  detail: { parent, sub },
209
248
  bubbles: true,
210
249
  composed: true,
@@ -218,7 +257,7 @@ export class RelMenu extends LitElement {
218
257
  if (!item.disabled) {
219
258
  item.checked = !item.checked;
220
259
  this.dispatchEvent(
221
- new CustomEvent("item-checked", {
260
+ new CustomEvent("rel-check", {
222
261
  detail: { item, checked: item.checked },
223
262
  bubbles: true,
224
263
  composed: true,
@@ -229,7 +268,7 @@ export class RelMenu extends LitElement {
229
268
  }
230
269
 
231
270
  private onKeydown(ev: KeyboardEvent) {
232
- const last = this.items.length - 1;
271
+ const last = this._effectiveItems.length - 1;
233
272
 
234
273
  if (ev.key === "ArrowDown") {
235
274
  this.focusedIndex = Math.min(last, this.focusedIndex + 1);
@@ -238,16 +277,16 @@ export class RelMenu extends LitElement {
238
277
  this.focusedIndex = Math.max(0, this.focusedIndex - 1);
239
278
  ev.preventDefault();
240
279
  } else if (ev.key === "ArrowRight") {
241
- const item = this.items[this.focusedIndex];
280
+ const item = this._effectiveItems[this.focusedIndex];
242
281
  if (this.type === "arrow" && item?.submenu?.length) {
243
282
  item.open = true;
244
283
  this.requestUpdate();
245
284
  }
246
285
  } else if (ev.key === "ArrowLeft" || ev.key === "Escape") {
247
- this.items.forEach((i) => (i.open = false));
286
+ this._effectiveItems.forEach((i) => (i.open = false));
248
287
  this.requestUpdate();
249
288
  } else if (ev.key === "Enter" || ev.key === " ") {
250
- const item = this.items[this.focusedIndex];
289
+ const item = this._effectiveItems[this.focusedIndex];
251
290
  this.onItemClick(item, this.focusedIndex);
252
291
  ev.preventDefault();
253
292
  }
@@ -306,13 +345,14 @@ export class RelMenu extends LitElement {
306
345
 
307
346
  render() {
308
347
  return html`
348
+ <slot name="items" style="display:none;" @slotchange="${this._onSlotChange}"></slot>
309
349
  <div
310
350
  class="rel-menu"
311
351
  role="menu"
312
352
  tabindex="0"
313
353
  @keydown="${this.onKeydown}"
314
354
  @click="${(e: Event) => e.stopPropagation()}">
315
- ${this.items.map((item, index) => this.renderMenuItem(item, index))}
355
+ ${this._effectiveItems.map((item, index) => this.renderMenuItem(item, index))}
316
356
  </div>
317
357
  `;
318
358
  }
@@ -0,0 +1,329 @@
1
+ # rel-menubar
2
+
3
+ A horizontal menubar component with dropdown menus, submenus, checkbox items, and radio groups. Provides full keyboard navigation and accessibility features.
4
+
5
+ ## What It Is
6
+
7
+ The menubar component consists of two custom elements:
8
+ - `<rel-menubar>` - The root container that manages state and interactions
9
+ - `<rel-menubar-menu>` - Individual menu definitions with their content
10
+
11
+ Content is authored using semantic HTML with data attributes, allowing the component to enhance it with proper menubar behavior.
12
+
13
+ ## Basic Usage
14
+
15
+ ```html
16
+ <rel-menubar>
17
+ <rel-menubar-menu label="File">
18
+ <button data-item>New Tab</button>
19
+ <button data-item>New Window</button>
20
+ <button data-item>Close</button>
21
+ </rel-menubar-menu>
22
+
23
+ <rel-menubar-menu label="Edit">
24
+ <button data-item>Undo</button>
25
+ <button data-item>Redo</button>
26
+ <div data-separator></div>
27
+ <button data-item>Cut</button>
28
+ <button data-item>Copy</button>
29
+ <button data-item>Paste</button>
30
+ </rel-menubar-menu>
31
+
32
+ <rel-menubar-menu label="View">
33
+ <button data-item>Zoom In</button>
34
+ <button data-item>Zoom Out</button>
35
+ </rel-menubar-menu>
36
+ </rel-menubar>
37
+ ```
38
+
39
+ ## Submenu Example
40
+
41
+ Use `data-submenu` attribute with a `label` attribute to create nested menus:
42
+
43
+ ```html
44
+ <rel-menubar>
45
+ <rel-menubar-menu label="File">
46
+ <button data-item>New Tab</button>
47
+ <div data-separator></div>
48
+ <div data-submenu label="Share">
49
+ <button data-item>Email link</button>
50
+ <button data-item>Messages</button>
51
+ <button data-item>Notes</button>
52
+ </div>
53
+ <div data-separator></div>
54
+ <button data-item>Close</button>
55
+ </rel-menubar-menu>
56
+ </rel-menubar>
57
+ ```
58
+
59
+ ## Checkbox Example
60
+
61
+ Wrap a checkbox input in a label with `data-checkbox` attribute:
62
+
63
+ ```html
64
+ <rel-menubar>
65
+ <rel-menubar-menu label="View">
66
+ <label data-checkbox>
67
+ <input type="checkbox" />
68
+ Always Show Bookmarks Bar
69
+ </label>
70
+ <label data-checkbox>
71
+ <input type="checkbox" checked />
72
+ Always Show Full URLs
73
+ </label>
74
+ </rel-menubar-menu>
75
+ </rel-menubar>
76
+ ```
77
+
78
+ ## Radio Group Example
79
+
80
+ Use `data-radio-group` container with `data-radio` items:
81
+
82
+ ```html
83
+ <rel-menubar>
84
+ <rel-menubar-menu label="Profile">
85
+ <div data-radio-group name="user-profile" value="andy">
86
+ <button data-radio value="andy">Andy</button>
87
+ <button data-radio value="benoit">Benoit</button>
88
+ <button data-radio value="luis">Luis</button>
89
+ </div>
90
+ </rel-menubar-menu>
91
+ </rel-menubar>
92
+ ```
93
+
94
+ ## Shortcuts
95
+
96
+ Add keyboard shortcuts as text using the `data-shortcut` attribute:
97
+
98
+ ```html
99
+ <rel-menubar>
100
+ <rel-menubar-menu label="Edit">
101
+ <button data-item data-shortcut="Ctrl+Z">Undo</button>
102
+ <button data-item data-shortcut="Ctrl+Y">Redo</button>
103
+ </rel-menubar-menu>
104
+ </rel-menubar>
105
+ ```
106
+
107
+ Or use `<rel-kbd>` components in the button content for better styling:
108
+
109
+ ```html
110
+ <rel-menubar>
111
+ <rel-menubar-menu label="Edit">
112
+ <button data-item>
113
+ Undo
114
+ <span style="margin-left: auto; display: flex; gap: 4px;">
115
+ <rel-kbd size="sm">Ctrl</rel-kbd>
116
+ <rel-kbd size="sm">Z</rel-kbd>
117
+ </span>
118
+ </button>
119
+ </rel-menubar-menu>
120
+ </rel-menubar>
121
+ ```
122
+
123
+ ## Data Attributes
124
+
125
+ ### Menu Items
126
+
127
+ | Attribute | Element | Description |
128
+ |-----------|---------|-------------|
129
+ | `data-item` | `<button>` | Standard clickable menu item |
130
+ | `data-separator` | `<div>` | Visual separator line |
131
+ | `data-submenu` | `<div>` | Container for submenu items (requires `label` attribute) |
132
+ | `data-checkbox` | `<label>` | Checkbox item (must contain `<input type="checkbox">`) |
133
+ | `data-radio-group` | `<div>` | Radio group container (requires `name` and `value` attributes) |
134
+ | `data-radio` | `<button>` | Radio button item (requires `value` attribute) |
135
+ | `data-shortcut` | `<button>` | Optional keyboard shortcut text |
136
+
137
+ ### Properties
138
+
139
+ **rel-menubar-menu**
140
+ - `label` (string) - The text displayed on the menubar trigger button
141
+
142
+ ## Events
143
+
144
+ ### rel-menubar-change
145
+
146
+ Emitted when a checkbox is toggled or a radio button is selected.
147
+
148
+ **Checkbox Event Detail:**
149
+ ```typescript
150
+ {
151
+ type: "checkbox",
152
+ label: string, // Label text of the checkbox
153
+ checked: boolean // New checked state
154
+ }
155
+ ```
156
+
157
+ **Radio Event Detail:**
158
+ ```typescript
159
+ {
160
+ type: "radio",
161
+ name: string, // Name of the radio group
162
+ value: string // Selected value
163
+ }
164
+ ```
165
+
166
+ **Usage Example:**
167
+ ```javascript
168
+ const menubar = document.querySelector('rel-menubar');
169
+ menubar.addEventListener('rel-menubar-change', (event) => {
170
+ const { type, label, checked, name, value } = event.detail;
171
+
172
+ if (type === 'checkbox') {
173
+ console.log(`Checkbox "${label}" is now ${checked ? 'checked' : 'unchecked'}`);
174
+ } else if (type === 'radio') {
175
+ console.log(`Radio group "${name}" selected: ${value}`);
176
+ }
177
+ });
178
+ ```
179
+
180
+ ## Keyboard Navigation
181
+
182
+ The menubar provides comprehensive keyboard support:
183
+
184
+ | Key | Context | Action |
185
+ |-----|---------|--------|
186
+ | `Tab` / `Shift+Tab` | Menubar | Focus menubar triggers |
187
+ | `ArrowLeft` / `ArrowRight` | Menubar triggers | Navigate between menu triggers |
188
+ | `Enter` / `Space` | Focused trigger | Open the menu |
189
+ | `ArrowDown` | Open menu | Move to first item or next item |
190
+ | `ArrowUp` | Open menu | Move to previous item |
191
+ | `ArrowRight` | Submenu item | Open submenu |
192
+ | `ArrowLeft` | Open submenu | Close submenu and return to parent |
193
+ | `Escape` | Open menu | Close menu and return focus to trigger |
194
+ | `Enter` / `Space` | Menu item | Activate item (click, toggle checkbox, select radio) |
195
+
196
+ ## Interaction Behavior
197
+
198
+ ### Opening/Closing
199
+ - Click a trigger to open its menu
200
+ - Click outside to close all menus
201
+ - When a menu is open, clicking another trigger switches to it
202
+ - When a menu is open, hovering another trigger switches to it
203
+
204
+ ### Submenus
205
+ - Click or hover a submenu item to open its submenu
206
+ - Submenu appears to the right of the parent menu
207
+ - ArrowRight/ArrowLeft navigate in/out of submenus
208
+
209
+ ### State Management
210
+ - Checkbox state is maintained in the DOM
211
+ - Radio group value is stored on the `data-radio-group` element
212
+ - Selected radio items receive `data-checked` attribute
213
+
214
+ ## Accessibility
215
+
216
+ - Proper ARIA roles and keyboard navigation
217
+ - Focus management with visual focus indicators
218
+ - Screen reader friendly with semantic HTML
219
+ - Disabled items are properly marked and non-interactive
220
+ - All interactive elements are keyboard accessible
221
+
222
+ ## Styling Tokens
223
+
224
+ The component uses design tokens from the Reliability Design System:
225
+
226
+ ### Colors
227
+ - `--rel-colors-gray-light` - Menubar background
228
+ - `--rel-colors-gray-background` - Trigger and item hover state
229
+ - `--rel-colors-gray-border` - Borders
230
+ - `--rel-colors-gray-divider` - Separators
231
+ - `--rel-colors-gray-heading` - Text color
232
+ - `--rel-colors-white` - Panel background
233
+ - `--rel-colors-blue-primary` - Focus outline and radio selected state
234
+
235
+ ### Typography
236
+ - `--rel-fontFamilies-primary` - Font family (Poppins)
237
+ - `--rel-fontSizes-sm` - Default text size
238
+ - `--rel-fontSizes-xs` - Shortcut text size
239
+ - `--rel-lineHeights-sm` - Line height
240
+
241
+ ### Spacing
242
+ - `--rel-spacing-space-3xs` (2px) - Menubar gap and panel padding
243
+ - `--rel-spacing-space-2xs` (4px) - Trigger padding vertical
244
+ - `--rel-spacing-space-xs` (8px) - Item padding vertical
245
+ - `--rel-spacing-space-sm` (12px) - Trigger and item horizontal padding
246
+ - `--rel-spacing-space-md` (16px) - Item padding and radio offset
247
+
248
+ ### Borders
249
+ - `--rel-borders-width-stroke-100` (1px) - Border width
250
+ - `--rel-borders-width-stroke-150` (1.5px) - Radio border
251
+ - `--rel-borders-radius-border-radius-100` (2px) - Trigger border radius
252
+ - `--rel-borders-radius-border-radius-200` (8px) - Panel border radius
253
+
254
+ ### Shadows
255
+ - `--rel-shadows-shadow-300` - Panel drop shadow
256
+
257
+ ### Z-Index
258
+ - Menu panels: `z-index: 1000`
259
+ - Submenu panels: `z-index: 1001`
260
+
261
+ ## Browser Support
262
+
263
+ Compatible with all modern browsers that support:
264
+ - Web Components (Custom Elements v1)
265
+ - Shadow DOM
266
+ - ES2020+ features
267
+
268
+ ## Framework Integration
269
+
270
+ Works seamlessly with:
271
+ - Vanilla JavaScript
272
+ - Angular
273
+ - React (via wrapper)
274
+ - Vue
275
+ - Any framework that supports Web Components
276
+
277
+ ## Complete Example
278
+
279
+ ```html
280
+ <rel-menubar id="app-menubar">
281
+ <rel-menubar-menu label="File">
282
+ <button data-item data-shortcut="Ctrl+N">New Tab</button>
283
+ <button data-item data-shortcut="Ctrl+Shift+N">New Window</button>
284
+ <div data-separator></div>
285
+ <div data-submenu label="Share">
286
+ <button data-item>Email link</button>
287
+ <button data-item>Messages</button>
288
+ <button data-item>Notes</button>
289
+ </div>
290
+ <div data-separator></div>
291
+ <button data-item>Close</button>
292
+ </rel-menubar-menu>
293
+
294
+ <rel-menubar-menu label="Edit">
295
+ <button data-item data-shortcut="Ctrl+Z">Undo</button>
296
+ <button data-item data-shortcut="Ctrl+Y">Redo</button>
297
+ <div data-separator></div>
298
+ <button data-item data-shortcut="Ctrl+X">Cut</button>
299
+ <button data-item data-shortcut="Ctrl+C">Copy</button>
300
+ <button data-item data-shortcut="Ctrl+V">Paste</button>
301
+ </rel-menubar-menu>
302
+
303
+ <rel-menubar-menu label="View">
304
+ <button data-item>Zoom In</button>
305
+ <button data-item>Zoom Out</button>
306
+ <div data-separator></div>
307
+ <label data-checkbox>
308
+ <input type="checkbox" />
309
+ Always Show Bookmarks Bar
310
+ </label>
311
+ <label data-checkbox>
312
+ <input type="checkbox" checked />
313
+ Always Show Full URLs
314
+ </label>
315
+ <div data-separator></div>
316
+ <div data-radio-group name="profile" value="andy">
317
+ <button data-radio value="andy">Andy</button>
318
+ <button data-radio value="benoit">Benoit</button>
319
+ <button data-radio value="luis">Luis</button>
320
+ </div>
321
+ </rel-menubar-menu>
322
+ </rel-menubar>
323
+
324
+ <script>
325
+ document.getElementById('app-menubar').addEventListener('rel-menubar-change', (e) => {
326
+ console.log('Menubar change:', e.detail);
327
+ });
328
+ </script>
329
+ ```
@@ -0,0 +1,2 @@
1
+ export * from "./rel-menubar";
2
+ export * from "./rel-menubar-menu";
@@ -0,0 +1,16 @@
1
+ import { LitElement, html } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+
4
+ @customElement("rel-menubar-menu")
5
+ export class RelMenubarMenu extends LitElement {
6
+ @property({ type: String }) label = "";
7
+
8
+ // Disable shadow DOM to allow parent to access children
9
+ createRenderRoot() {
10
+ return this;
11
+ }
12
+
13
+ render() {
14
+ return html`<slot></slot>`;
15
+ }
16
+ }