@ixfx/components 0.6.2 → 0.7.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 (181) hide show
  1. package/bundle/index.d.ts +1918 -835
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +22137 -16840
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +1 -1
  6. package/dist/ac-text.d.ts +1 -1
  7. package/dist/ac-text.js +3 -2
  8. package/dist/ac-text.js.map +1 -1
  9. package/dist/{ac-token-BAa6ke09.d.ts → ac-token--_vCHXWw.d.ts} +2 -2
  10. package/dist/{ac-token-BAa6ke09.d.ts.map → ac-token--_vCHXWw.d.ts.map} +1 -1
  11. package/dist/ac-token.d.ts +1 -1
  12. package/dist/ac-token.js +3 -2
  13. package/dist/ac-token.js.map +1 -1
  14. package/dist/{button-Bn0BuLpO.js → button-DsFbV4XD.js} +5 -4
  15. package/dist/button-DsFbV4XD.js.map +1 -0
  16. package/dist/button.d.ts.map +1 -1
  17. package/dist/button.js +1 -1
  18. package/dist/checkbox.js +1 -1
  19. package/dist/{colour-picker-0stHB90J.js → colour-picker-Ddsk-7E_.js} +4 -3
  20. package/dist/{colour-picker-0stHB90J.js.map → colour-picker-Ddsk-7E_.js.map} +1 -1
  21. package/dist/colour-picker.js +1 -1
  22. package/dist/crumbs.d.ts +1 -1
  23. package/dist/crumbs.js +4 -2
  24. package/dist/crumbs.js.map +1 -1
  25. package/dist/data-display.js +1 -1
  26. package/dist/{data-grid-C8qIo1-u.d.ts → data-grid-Bh4YrQGK.d.ts} +2 -2
  27. package/dist/{data-grid-C8qIo1-u.d.ts.map → data-grid-Bh4YrQGK.d.ts.map} +1 -1
  28. package/dist/data-grid.d.ts +1 -1
  29. package/dist/data-grid.js +4 -2
  30. package/dist/data-grid.js.map +1 -1
  31. package/dist/{defaults-BCiDhZbF.js → defaults-BJwDsMH4.js} +27 -20
  32. package/dist/defaults-BJwDsMH4.js.map +1 -0
  33. package/dist/editable-label-rzXkjf1H.d.ts +75 -0
  34. package/dist/editable-label-rzXkjf1H.d.ts.map +1 -0
  35. package/dist/editable-label.d.ts +2 -75
  36. package/dist/editable-label.js +2 -1
  37. package/dist/editable-label.js.map +1 -1
  38. package/dist/{fallbacks-DEE1nCTt.js → fallbacks-DNI9xt0F.js} +2 -2
  39. package/dist/{fallbacks-DEE1nCTt.js.map → fallbacks-DNI9xt0F.js.map} +1 -1
  40. package/dist/{grouped-item-lister-_pMDwIo1.d.ts → grouped-item-lister-DnWB-eFT.d.ts} +2 -2
  41. package/dist/{grouped-item-lister-_pMDwIo1.d.ts.map → grouped-item-lister-DnWB-eFT.d.ts.map} +1 -1
  42. package/dist/grouped-item-lister.d.ts +1 -1
  43. package/dist/{hex-editor-Bk6rxhfg.js → hex-editor-BiRfwTz1.js} +2 -2
  44. package/dist/{hex-editor-Bk6rxhfg.js.map → hex-editor-BiRfwTz1.js.map} +1 -1
  45. package/dist/hex.js +1 -1
  46. package/dist/{icon-DpA9x2Ve.d.ts → icon-CDGprSdE.d.ts} +1 -12
  47. package/dist/icon-CDGprSdE.d.ts.map +1 -0
  48. package/dist/{icons-Bm2ByQ3s.js → icon-DcEEGQa_.js} +38 -12
  49. package/dist/icon-DcEEGQa_.js.map +1 -0
  50. package/dist/icons.d.ts +3 -3
  51. package/dist/icons.js +9 -3
  52. package/dist/icons.js.map +1 -0
  53. package/dist/{index-CKtLhgYj.d.ts → index-9AhaHIT2.d.ts} +3 -3
  54. package/dist/{index-CKtLhgYj.d.ts.map → index-9AhaHIT2.d.ts.map} +1 -1
  55. package/dist/index-CG2vIgPv.d.ts +101 -0
  56. package/dist/index-CG2vIgPv.d.ts.map +1 -0
  57. package/dist/{index-BtGFYfaK.d.ts → index-CS9yM8L-.d.ts} +14 -4
  58. package/dist/index-CS9yM8L-.d.ts.map +1 -0
  59. package/dist/index.d.ts +861 -71
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +4257 -931
  62. package/dist/index.js.map +1 -1
  63. package/dist/interaction-D5XdKzbR.js +2 -0
  64. package/dist/labelled-radial-input.js +2 -1
  65. package/dist/labelled-radial-input.js.map +1 -1
  66. package/dist/labelled-slider-input-DzigjMwP.js +808 -0
  67. package/dist/labelled-slider-input-DzigjMwP.js.map +1 -0
  68. package/dist/labelled-slider-input.d.ts +2 -0
  69. package/dist/labelled-slider-input.js +2 -0
  70. package/dist/{types-DlVNJez_.d.ts → list-selection-types-DSuRNWpx.d.ts} +10 -2
  71. package/dist/list-selection-types-DSuRNWpx.d.ts.map +1 -0
  72. package/dist/menu-CXDFJxNm.js +825 -0
  73. package/dist/menu-CXDFJxNm.js.map +1 -0
  74. package/dist/{menu-item-Bs2MYyHq.d.ts → menu-item-CZi9vy5O.d.ts} +4 -2
  75. package/dist/menu-item-CZi9vy5O.d.ts.map +1 -0
  76. package/dist/menu-item-D2S4i8u1.js +809 -0
  77. package/dist/menu-item-D2S4i8u1.js.map +1 -0
  78. package/dist/menu.d.ts +2 -2
  79. package/dist/menu.js +2 -1
  80. package/dist/miller.d.ts +1 -1
  81. package/dist/miller.js +3 -2
  82. package/dist/miller.js.map +1 -1
  83. package/dist/narrowed-text.js +4 -2
  84. package/dist/narrowed-text.js.map +1 -1
  85. package/dist/notification-pill-DyZydXoZ.d.ts.map +1 -1
  86. package/dist/notifier.js +4 -3
  87. package/dist/notifier.js.map +1 -1
  88. package/dist/panel.d.ts +13 -13
  89. package/dist/panel.d.ts.map +1 -1
  90. package/dist/panel.js +37 -253
  91. package/dist/panel.js.map +1 -1
  92. package/dist/plots.js +1 -1
  93. package/dist/polar-pad.js +1 -1
  94. package/dist/{radial-input-Dk8Wydp5.js → radial-input-Dp5qz0ly.js} +2 -2
  95. package/dist/{radial-input-Dk8Wydp5.js.map → radial-input-Dp5qz0ly.js.map} +1 -1
  96. package/dist/radial-input.js +1 -1
  97. package/dist/range-input.js +1 -1
  98. package/dist/range.js +1 -1
  99. package/dist/registry-BEtb8_wB.js +46 -0
  100. package/dist/registry-BEtb8_wB.js.map +1 -0
  101. package/dist/select-horiz.js +3 -2
  102. package/dist/select-horiz.js.map +1 -1
  103. package/dist/{slider-input-XppH3vcy.d.ts → slider-input-BfRUW2ZB.d.ts} +16 -3
  104. package/dist/slider-input-BfRUW2ZB.d.ts.map +1 -0
  105. package/dist/{slider-input-CT4gcF-o.js → slider-input-De4eoT11.js} +382 -67
  106. package/dist/slider-input-De4eoT11.js.map +1 -0
  107. package/dist/slider-input.d.ts +1 -1
  108. package/dist/slider-input.js +1 -1
  109. package/dist/snackbar.js +1 -1
  110. package/dist/split-layout-BFSbUZQv.js +969 -0
  111. package/dist/split-layout-BFSbUZQv.js.map +1 -0
  112. package/dist/split-layout-JK3xWVX2.d.ts +179 -0
  113. package/dist/split-layout-JK3xWVX2.d.ts.map +1 -0
  114. package/dist/split-layout.d.ts +2 -60
  115. package/dist/split-layout.js +1 -617
  116. package/dist/style.css +1 -1
  117. package/dist/swipe.js +1 -1
  118. package/dist/{tab-list-D_1cYhB_.d.ts → tab-list-CGyPt07Z.d.ts} +10 -2
  119. package/dist/tab-list-CGyPt07Z.d.ts.map +1 -0
  120. package/dist/tabs.d.ts +1 -1
  121. package/dist/tabs.js +128 -27
  122. package/dist/tabs.js.map +1 -1
  123. package/dist/{tickled-controller-BtevrRLV.d.ts → tickled-controller-CRzdIEjJ.d.ts} +7 -1
  124. package/dist/tickled-controller-CRzdIEjJ.d.ts.map +1 -0
  125. package/dist/{tickled-controller-DkAU-0qL.js → tickled-controller-h9GmJ_bU.js} +8 -2
  126. package/dist/tickled-controller-h9GmJ_bU.js.map +1 -0
  127. package/dist/titlebar-Bj5pfdw_.d.ts +50 -0
  128. package/dist/titlebar-Bj5pfdw_.d.ts.map +1 -0
  129. package/dist/titlebar.d.ts +2 -0
  130. package/dist/titlebar.js +324 -0
  131. package/dist/titlebar.js.map +1 -0
  132. package/dist/tooltip-BlvBUQxx.d.ts.map +1 -1
  133. package/dist/{tree-BO6BXI2b.js → tree-Ch4W8qXQ.js} +4 -3
  134. package/dist/{tree-BO6BXI2b.js.map → tree-Ch4W8qXQ.js.map} +1 -1
  135. package/dist/tree.d.ts +1 -1
  136. package/dist/tree.js +1 -1
  137. package/dist/vertical-list-ClnqTkF3.js +814 -0
  138. package/dist/vertical-list-ClnqTkF3.js.map +1 -0
  139. package/dist/vertical-list.d.ts +8 -9
  140. package/dist/vertical-list.d.ts.map +1 -1
  141. package/dist/vertical-list.js +1 -736
  142. package/dist/{xy-axis-B6yMjckW.js → xy-axis-DWizs0bt.js} +109 -3
  143. package/dist/xy-axis-DWizs0bt.js.map +1 -0
  144. package/dist/xy-pad.js +1 -1
  145. package/docs-user/README.md +5 -0
  146. package/docs-user/detail-list.md +398 -0
  147. package/docs-user/dock.md +461 -0
  148. package/docs-user/icons.md +4 -0
  149. package/docs-user/index.json +28 -3
  150. package/docs-user/labelled-slider-input.md +198 -0
  151. package/docs-user/llms.txt +6 -1
  152. package/docs-user/panel.md +20 -1
  153. package/docs-user/slider-input.md +55 -15
  154. package/docs-user/split-layout.md +136 -170
  155. package/docs-user/tabs.md +54 -0
  156. package/docs-user/titlebar.md +102 -0
  157. package/docs-user/toolbar.md +95 -22
  158. package/docs-user/twosplit-layout.md +254 -0
  159. package/docs-user/user-catalog.md +8 -1
  160. package/docs-user/user-theming.md +109 -0
  161. package/llms.txt +6 -1
  162. package/package.json +1 -2
  163. package/dist/button-Bn0BuLpO.js.map +0 -1
  164. package/dist/defaults-BCiDhZbF.js.map +0 -1
  165. package/dist/editable-label.d.ts.map +0 -1
  166. package/dist/icon-DpA9x2Ve.d.ts.map +0 -1
  167. package/dist/icons-Bm2ByQ3s.js.map +0 -1
  168. package/dist/index-BtGFYfaK.d.ts.map +0 -1
  169. package/dist/menu-DIfU70AA.js +0 -1609
  170. package/dist/menu-DIfU70AA.js.map +0 -1
  171. package/dist/menu-item-Bs2MYyHq.d.ts.map +0 -1
  172. package/dist/slider-input-CT4gcF-o.js.map +0 -1
  173. package/dist/slider-input-XppH3vcy.d.ts.map +0 -1
  174. package/dist/split-layout.d.ts.map +0 -1
  175. package/dist/split-layout.js.map +0 -1
  176. package/dist/tab-list-D_1cYhB_.d.ts.map +0 -1
  177. package/dist/tickled-controller-BtevrRLV.d.ts.map +0 -1
  178. package/dist/tickled-controller-DkAU-0qL.js.map +0 -1
  179. package/dist/types-DlVNJez_.d.ts.map +0 -1
  180. package/dist/vertical-list.js.map +0 -1
  181. package/dist/xy-axis-B6yMjckW.js.map +0 -1
@@ -0,0 +1,825 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { t as tickledItemStyles } from "./tickled-styles-BrAHEj1q.js";
3
+ import { t as themeFallbacks } from "./fallbacks-DNI9xt0F.js";
4
+ import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
5
+ import "./icon-DcEEGQa_.js";
6
+ import "./interaction-D5XdKzbR.js";
7
+ import { n as MenuTrigger, r as MenuContainer, t as MenuItem } from "./menu-item-D2S4i8u1.js";
8
+ import { LitElement, css, html, nothing } from "lit";
9
+ import { property, query, state } from "lit/decorators.js";
10
+ //#region src/menu/menu-bar.ts
11
+ let MenuBar = class MenuBar extends LitElement {
12
+ constructor(..._args) {
13
+ super(..._args);
14
+ this._openTrigger = null;
15
+ this._inputMode = `mouse`;
16
+ this._handlePointerMove = () => {
17
+ this._setInputMode(`mouse`);
18
+ };
19
+ this._handleTriggerOpen = (e) => {
20
+ this._openTrigger = e.target;
21
+ };
22
+ this._handleTriggerClose = (e) => {
23
+ if (e.target === this._openTrigger) this._openTrigger = null;
24
+ };
25
+ this._handleFocusIn = (e) => {
26
+ const trigger = this._getTriggers().find((t) => t === e.target);
27
+ if (!trigger || !this._openTrigger || trigger === this._openTrigger) return;
28
+ this._openTrigger.closeMenu();
29
+ trigger.openMenu();
30
+ };
31
+ this._handleKeydown = (e) => {
32
+ if (e.key !== `ArrowLeft` && e.key !== `ArrowRight`) return;
33
+ const triggers = this._getTriggers();
34
+ if (triggers.length === 0) return;
35
+ const current = this._openTrigger ?? triggers.find((t) => t === e.target);
36
+ if (!current) return;
37
+ const idx = triggers.indexOf(current);
38
+ if (idx === -1) return;
39
+ e.preventDefault();
40
+ e.stopPropagation();
41
+ this._setInputMode(`keyboard`);
42
+ const next = triggers[(idx + (e.key === `ArrowRight` ? 1 : -1) + triggers.length) % triggers.length];
43
+ if (this._openTrigger) {
44
+ this._openTrigger.closeMenu();
45
+ next.openMenu();
46
+ } else next.focusTrigger();
47
+ };
48
+ }
49
+ connectedCallback() {
50
+ super.connectedCallback();
51
+ this.addEventListener(`menu-trigger-open`, this._handleTriggerOpen);
52
+ this.addEventListener(`menu-trigger-close`, this._handleTriggerClose);
53
+ this.addEventListener(`focusin`, this._handleFocusIn);
54
+ this.addEventListener(`keydown`, this._handleKeydown);
55
+ this.addEventListener(`pointermove`, this._handlePointerMove);
56
+ }
57
+ disconnectedCallback() {
58
+ super.disconnectedCallback();
59
+ this.removeEventListener(`menu-trigger-open`, this._handleTriggerOpen);
60
+ this.removeEventListener(`menu-trigger-close`, this._handleTriggerClose);
61
+ this.removeEventListener(`focusin`, this._handleFocusIn);
62
+ this.removeEventListener(`keydown`, this._handleKeydown);
63
+ this.removeEventListener(`pointermove`, this._handlePointerMove);
64
+ }
65
+ _setInputMode(mode) {
66
+ if (this._inputMode === mode) return;
67
+ this._inputMode = mode;
68
+ this.setAttribute(`data-input-mode`, mode);
69
+ }
70
+ _getTriggers() {
71
+ return [...this.children].filter((el) => el.tagName === `IXFX-MENU-TRIGGER`);
72
+ }
73
+ static {
74
+ this.styles = css`
75
+ :host {
76
+ display: flex;
77
+ align-items: center;
78
+ }
79
+
80
+ /* Keyboard mode: suppress hover highlight on trigger buttons */
81
+ :host([data-input-mode="keyboard"]) {
82
+ --_trigger-hover-bg: transparent;
83
+ --_trigger-hover-opacity: 0.6;
84
+ }
85
+ `;
86
+ }
87
+ render() {
88
+ return html`<slot role="menubar"></slot>`;
89
+ }
90
+ };
91
+ MenuBar = __decorate([safeCustomElement(`ixfx-menu-bar`)], MenuBar);
92
+ //#endregion
93
+ //#region src/menu/menu-check-item.ts
94
+ let MenuCheckItem = class MenuCheckItem extends LitElement {
95
+ constructor(..._args) {
96
+ super(..._args);
97
+ this.command = ``;
98
+ this.commandArgs = ``;
99
+ this.label = ``;
100
+ this.checked = false;
101
+ this.disabled = false;
102
+ this.iconName = ``;
103
+ }
104
+ handleClick() {
105
+ if (this.disabled) return;
106
+ this.checked = !this.checked;
107
+ this.dispatchEvent(new CustomEvent(`command`, {
108
+ detail: {
109
+ command: this.command,
110
+ checked: this.checked,
111
+ args: this.commandArgs
112
+ },
113
+ bubbles: true,
114
+ composed: true
115
+ }));
116
+ }
117
+ _resolvedLabel() {
118
+ if (this.label) return this.label;
119
+ if (this.registry && this.command) return this.registry.get(this.command)?.label ?? ``;
120
+ return ``;
121
+ }
122
+ _resolvedIcon() {
123
+ if (this.iconName) return this.iconName;
124
+ if (this.registry && this.command) return this.registry.get(this.command)?.icon ?? null;
125
+ return null;
126
+ }
127
+ willUpdate(changedProperties) {
128
+ super.willUpdate(changedProperties);
129
+ const resolvedIcon = this._resolvedIcon();
130
+ if (resolvedIcon && !this.iconName) this.setAttribute(`data-icon-section`, ``);
131
+ else if (!resolvedIcon && !this.iconName) this.removeAttribute(`data-icon-section`);
132
+ }
133
+ updated(changedProperties) {
134
+ super.updated(changedProperties);
135
+ }
136
+ _getShortcut() {
137
+ if (!this.keyboardManager || !this.command) return null;
138
+ const binding = (this.keyboardManager.getBindings?.() ?? []).find((b) => b.commandId === this.command);
139
+ if (!binding) return null;
140
+ const mods = Array.from(binding.modifiers ?? [], (m) => ({
141
+ ctrl: `⌃`,
142
+ shift: `⇧`,
143
+ alt: `⌥`,
144
+ meta: `⌘`
145
+ })[m] ?? m);
146
+ const key = binding.key?.length === 1 ? binding.key.toUpperCase() : binding.key;
147
+ return [...mods, key].join(``);
148
+ }
149
+ static {
150
+ this.styles = [
151
+ themeFallbacks,
152
+ tickledItemStyles,
153
+ css`
154
+ :host {
155
+ display: block;
156
+ }
157
+
158
+ .item {
159
+ display: flex;
160
+ padding: 6px var(--space-m);
161
+ font-size: var(--text-m);
162
+ }
163
+
164
+ :host(:focus) {
165
+ outline: none;
166
+ }
167
+
168
+ .item.disabled {
169
+ opacity: var(--disabled-opacity);
170
+ cursor: default;
171
+ }
172
+
173
+ .item.disabled:hover {
174
+ background: transparent;
175
+ }
176
+
177
+ .check {
178
+ width: 16px;
179
+ margin-right: var(--space-s);
180
+ font-size: var(--text-m);
181
+ color: var(--accent);
182
+ }
183
+
184
+ .icon-slot {
185
+ width: 0;
186
+ overflow: hidden;
187
+ flex-shrink: 0;
188
+ display: inline-flex;
189
+ align-items: center;
190
+ justify-content: center;
191
+ }
192
+
193
+ :host([icon-name]) .icon-slot,
194
+ :host([data-icon-section]) .icon-slot {
195
+ width: 1em;
196
+ height: 1em;
197
+ margin-right: var(--space-s);
198
+ }
199
+
200
+ .label {
201
+ flex: 1;
202
+ }
203
+
204
+ .shortcut {
205
+ margin-left: var(--space-l);
206
+ color: var(--surface-muted-text);
207
+ font-size: var(--text-s);
208
+ }
209
+ `
210
+ ];
211
+ }
212
+ render() {
213
+ const shortcut = this._getShortcut();
214
+ const resolvedIcon = this._resolvedIcon();
215
+ return html`
216
+ <div
217
+ class="item ${this.disabled ? `disabled` : ``}"
218
+ @click=${this.handleClick}
219
+ tabindex="${this.disabled ? -1 : 0}"
220
+ role="menuitemcheckbox"
221
+ aria-checked="${this.checked}"
222
+ >
223
+ <span class="check">${this.checked ? `✓` : ``}</span>
224
+ <span class="icon-slot">${resolvedIcon ? html`<ixfx-icon name="${resolvedIcon}"></ixfx-icon>` : null}</span>
225
+ <span class="label">${this._resolvedLabel()}</span>
226
+ ${shortcut ? html`<span class="shortcut">${shortcut}</span>` : null}
227
+ </div>
228
+ `;
229
+ }
230
+ };
231
+ __decorate([property({ type: String })], MenuCheckItem.prototype, "command", void 0);
232
+ __decorate([property({
233
+ type: String,
234
+ attribute: `command-args`
235
+ })], MenuCheckItem.prototype, "commandArgs", void 0);
236
+ __decorate([property({ type: String })], MenuCheckItem.prototype, "label", void 0);
237
+ __decorate([property({ type: Boolean })], MenuCheckItem.prototype, "checked", void 0);
238
+ __decorate([property({ type: Boolean })], MenuCheckItem.prototype, "disabled", void 0);
239
+ __decorate([property({
240
+ type: String,
241
+ attribute: `icon-name`
242
+ })], MenuCheckItem.prototype, "iconName", void 0);
243
+ __decorate([property({ attribute: false })], MenuCheckItem.prototype, "registry", void 0);
244
+ __decorate([property({ attribute: false })], MenuCheckItem.prototype, "keyboardManager", void 0);
245
+ MenuCheckItem = __decorate([safeCustomElement(`ixfx-menu-check-item`)], MenuCheckItem);
246
+ //#endregion
247
+ //#region src/menu/menu-command-controller.ts
248
+ var MenuCommandController = class {
249
+ constructor(options) {
250
+ this.registry = options.registry;
251
+ this.target = options.target ?? document;
252
+ this.boundHandler = this.handleCommand.bind(this);
253
+ }
254
+ start() {
255
+ this.target.addEventListener(`command`, this.boundHandler);
256
+ }
257
+ stop() {
258
+ this.target.removeEventListener(`command`, this.boundHandler);
259
+ }
260
+ handleCommand(e) {
261
+ const target = e.target;
262
+ const command = target?.command;
263
+ if (!command) return;
264
+ const args = target?.commandArgs ?? ``;
265
+ this.registry.invoke(command, { args });
266
+ }
267
+ };
268
+ //#endregion
269
+ //#region src/menu/menu-sub-trigger.ts
270
+ var _MenuSubTrigger;
271
+ let MenuSubTrigger = class MenuSubTrigger extends LitElement {
272
+ static {
273
+ _MenuSubTrigger = this;
274
+ }
275
+ constructor(..._args) {
276
+ super(..._args);
277
+ this.command = ``;
278
+ this.commandArgs = ``;
279
+ this.label = ``;
280
+ this.disabled = false;
281
+ this.iconName = ``;
282
+ this._hasSubmenu = false;
283
+ this._anchorName = `--mst-${_MenuSubTrigger._count++}`;
284
+ this._hoverTimeout = null;
285
+ this._hideTimeout = null;
286
+ }
287
+ static {
288
+ this._count = 0;
289
+ }
290
+ connectedCallback() {
291
+ super.connectedCallback();
292
+ this.addEventListener(`keydown`, this._handleKeydown);
293
+ }
294
+ firstUpdated() {
295
+ this.style.setProperty(`--anchor-name`, this._anchorName);
296
+ }
297
+ disconnectedCallback() {
298
+ super.disconnectedCallback();
299
+ this.removeEventListener(`keydown`, this._handleKeydown);
300
+ if (this._hoverTimeout) clearTimeout(this._hoverTimeout);
301
+ if (this._hideTimeout) clearTimeout(this._hideTimeout);
302
+ }
303
+ _propagateContext() {
304
+ const items = this._slot?.assignedElements({ flatten: true }) ?? [];
305
+ for (const el of items) {
306
+ if (`registry` in el) el.registry = this.registry;
307
+ if (`keyboardManager` in el) el.keyboardManager = this.keyboardManager;
308
+ }
309
+ }
310
+ updated(changedProperties) {
311
+ if (changedProperties.has(`registry`) || changedProperties.has(`keyboardManager`)) this._propagateContext();
312
+ }
313
+ willUpdate(changedProperties) {
314
+ super.willUpdate(changedProperties);
315
+ const resolvedIcon = this._resolvedIcon();
316
+ if (resolvedIcon && !this.iconName) this.setAttribute(`data-icon-section`, ``);
317
+ else if (!resolvedIcon && !this.iconName) this.removeAttribute(`data-icon-section`);
318
+ }
319
+ _resolvedIcon() {
320
+ if (this.iconName) return this.iconName;
321
+ if (this.registry && this.command) return this.registry.get(this.command)?.icon ?? null;
322
+ return null;
323
+ }
324
+ _handleSlotChange() {
325
+ this._hasSubmenu = this._slot?.assignedElements().length > 0;
326
+ this._propagateContext();
327
+ }
328
+ _showSubmenu() {
329
+ if (!this._submenuPopover?.popover) return;
330
+ try {
331
+ this._submenuPopover.showPopover();
332
+ } catch {}
333
+ }
334
+ _hideSubmenu() {
335
+ if (!this._submenuPopover?.popover) return;
336
+ try {
337
+ this._submenuPopover.hidePopover();
338
+ } catch {}
339
+ }
340
+ _cancelHide() {
341
+ if (this._hideTimeout) {
342
+ clearTimeout(this._hideTimeout);
343
+ this._hideTimeout = null;
344
+ }
345
+ }
346
+ _scheduleHide() {
347
+ this._cancelHide();
348
+ this._hideTimeout = window.setTimeout(() => {
349
+ this._hideSubmenu();
350
+ this._hideTimeout = null;
351
+ }, 100);
352
+ }
353
+ _handleMouseEnter() {
354
+ if (this.disabled || !this._hasSubmenu) return;
355
+ this._cancelHide();
356
+ if (this._hoverTimeout) clearTimeout(this._hoverTimeout);
357
+ this._hoverTimeout = window.setTimeout(() => {
358
+ this._showSubmenu();
359
+ }, 150);
360
+ }
361
+ _handleMouseLeave() {
362
+ if (this._hoverTimeout) {
363
+ clearTimeout(this._hoverTimeout);
364
+ this._hoverTimeout = null;
365
+ }
366
+ this._scheduleHide();
367
+ }
368
+ _handleSubmenuMouseEnter() {
369
+ this._cancelHide();
370
+ }
371
+ _handleSubmenuMouseLeave() {
372
+ this._scheduleHide();
373
+ }
374
+ _handleClick() {
375
+ if (this.disabled || !this.command) return;
376
+ this.dispatchEvent(new CustomEvent(`command`, {
377
+ detail: {
378
+ command: this.command,
379
+ args: this.commandArgs
380
+ },
381
+ bubbles: true,
382
+ composed: true
383
+ }));
384
+ }
385
+ _handleKeydown(e) {
386
+ if (this.disabled) return;
387
+ switch (e.key) {
388
+ case `ArrowRight`:
389
+ case `Enter`:
390
+ case ` `:
391
+ e.preventDefault();
392
+ e.stopPropagation();
393
+ if (this._hasSubmenu) {
394
+ this._showSubmenu();
395
+ requestAnimationFrame(() => {
396
+ (this._slot?.assignedElements({ flatten: true }).find((el) => el.tagName === `IXFX-MENU-CONTAINER`))?.focusFirst();
397
+ });
398
+ }
399
+ break;
400
+ case `ArrowLeft`:
401
+ e.preventDefault();
402
+ e.stopPropagation();
403
+ this._hideSubmenu();
404
+ this._itemEl?.focus();
405
+ break;
406
+ case `Escape`:
407
+ e.preventDefault();
408
+ e.stopPropagation();
409
+ this._hideSubmenu();
410
+ }
411
+ }
412
+ static {
413
+ this.styles = [
414
+ themeFallbacks,
415
+ tickledItemStyles,
416
+ css`
417
+ :host {
418
+ display: block;
419
+ }
420
+
421
+ .item {
422
+ anchor-name: var(--anchor-name);
423
+ display: flex;
424
+ padding: 6px var(--space-m);
425
+ font-size: var(--text-m);
426
+ }
427
+
428
+ .submenu-popover {
429
+ position: fixed;
430
+ position-anchor: var(--anchor-name);
431
+ inset: auto;
432
+ top: anchor(top);
433
+ left: anchor(right);
434
+ margin: 0;
435
+ padding: 0;
436
+ border: none;
437
+ background: transparent;
438
+ /* UA stylesheet sets overflow:auto on [popover], which clips the box-shadow
439
+ of the inner ixfx-menu-container child. Override to let the shadow render. */
440
+ overflow: visible;
441
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
442
+ }
443
+
444
+ :host(:focus) {
445
+ outline: none;
446
+ }
447
+
448
+ .item.disabled {
449
+ opacity: var(--disabled-opacity);
450
+ cursor: default;
451
+ }
452
+
453
+ .item.disabled:hover {
454
+ background: transparent;
455
+ }
456
+
457
+ .icon-slot {
458
+ width: 0;
459
+ overflow: hidden;
460
+ flex-shrink: 0;
461
+ display: inline-flex;
462
+ align-items: center;
463
+ justify-content: center;
464
+ }
465
+
466
+ :host([icon-name]) .icon-slot,
467
+ :host([data-icon-section]) .icon-slot {
468
+ width: 1em;
469
+ height: 1em;
470
+ margin-right: var(--space-s);
471
+ }
472
+
473
+ .label {
474
+ flex: 1;
475
+ }
476
+
477
+ .arrow {
478
+ color: var(--surface-muted-text);
479
+ margin-left: var(--space-m);
480
+ }
481
+ `
482
+ ];
483
+ }
484
+ render() {
485
+ const resolvedIcon = this._resolvedIcon();
486
+ return html`
487
+ <div
488
+ class="item ${this.disabled ? `disabled` : ``}"
489
+ @click=${this._handleClick}
490
+ @mouseenter=${this._handleMouseEnter}
491
+ @mouseleave=${this._handleMouseLeave}
492
+ tabindex="${this.disabled ? -1 : 0}"
493
+ role="menuitem"
494
+ aria-haspopup="true"
495
+ aria-expanded="false"
496
+ >
497
+ <span class="icon-slot">${resolvedIcon ? html`<ixfx-icon name="${resolvedIcon}"></ixfx-icon>` : null}</span>
498
+ <span class="label"><slot></slot>${this.label}</span>
499
+ <span class="arrow">${this._hasSubmenu ? html`<ixfx-icon name="chevron-right"></ixfx-icon>` : nothing}</span>
500
+ </div>
501
+ <div class="submenu-popover" popover="auto"
502
+ @mouseenter=${this._handleSubmenuMouseEnter}
503
+ @mouseleave=${this._handleSubmenuMouseLeave}
504
+ >
505
+ <slot name="submenu" @slotchange=${this._handleSlotChange}></slot>
506
+ </div>
507
+ `;
508
+ }
509
+ };
510
+ __decorate([property({ type: String })], MenuSubTrigger.prototype, "command", void 0);
511
+ __decorate([property({
512
+ type: String,
513
+ attribute: `command-args`
514
+ })], MenuSubTrigger.prototype, "commandArgs", void 0);
515
+ __decorate([property({ type: String })], MenuSubTrigger.prototype, "label", void 0);
516
+ __decorate([property({ type: Boolean })], MenuSubTrigger.prototype, "disabled", void 0);
517
+ __decorate([property({
518
+ type: String,
519
+ attribute: `icon-name`
520
+ })], MenuSubTrigger.prototype, "iconName", void 0);
521
+ __decorate([property({ attribute: false })], MenuSubTrigger.prototype, "registry", void 0);
522
+ __decorate([property({ attribute: false })], MenuSubTrigger.prototype, "keyboardManager", void 0);
523
+ __decorate([state()], MenuSubTrigger.prototype, "_hasSubmenu", void 0);
524
+ __decorate([query(`slot[name="submenu"]`)], MenuSubTrigger.prototype, "_slot", void 0);
525
+ __decorate([query(`.submenu-popover`)], MenuSubTrigger.prototype, "_submenuPopover", void 0);
526
+ __decorate([query(`.item`)], MenuSubTrigger.prototype, "_itemEl", void 0);
527
+ MenuSubTrigger = _MenuSubTrigger = __decorate([safeCustomElement(`ixfx-menu-sub-trigger`)], MenuSubTrigger);
528
+ //#endregion
529
+ //#region src/menu/menu-separator.ts
530
+ let MenuSeparator = class MenuSeparator extends LitElement {
531
+ static {
532
+ this.styles = [themeFallbacks, css`
533
+ :host {
534
+ display: block;
535
+ margin: var(--space-xs) 0;
536
+ }
537
+
538
+ .separator {
539
+ height: 1px;
540
+ background: var(--surface-4);
541
+ }
542
+ `];
543
+ }
544
+ render() {
545
+ return html`<div class="separator"></div>`;
546
+ }
547
+ };
548
+ MenuSeparator = __decorate([safeCustomElement(`ixfx-menu-separator`)], MenuSeparator);
549
+ //#endregion
550
+ //#region src/menu/menu-header.ts
551
+ let MenuHeader = class MenuHeader extends LitElement {
552
+ constructor(..._args) {
553
+ super(..._args);
554
+ this.label = ``;
555
+ }
556
+ static {
557
+ this.styles = [themeFallbacks, css`
558
+ :host {
559
+ display: block;
560
+ padding: 6px var(--space-m) var(--space-xs);
561
+ font-size: var(--text-s);
562
+ font-weight: var(--font-weight-bold);
563
+ text-transform: uppercase;
564
+ color: var(--surface-muted-text);
565
+ letter-spacing: 0.5px;
566
+ }
567
+ `];
568
+ }
569
+ render() {
570
+ return html`<div>${this.label}</div>`;
571
+ }
572
+ };
573
+ __decorate([property({ type: String })], MenuHeader.prototype, "label", void 0);
574
+ MenuHeader = __decorate([safeCustomElement(`ixfx-menu-header`)], MenuHeader);
575
+ //#endregion
576
+ //#region src/menu/menu-from-tree.ts
577
+ function isLeaf(node) {
578
+ return node.children === void 0 || node.children.length === 0;
579
+ }
580
+ function menuFromTree(nodes, options = {}) {
581
+ const { onCommand, registry, keyboardManager } = options;
582
+ return html`${nodes.map((node) => {
583
+ const label = node.item.label;
584
+ if (label === `-`) return html`<ixfx-menu-separator></ixfx-menu-separator>`;
585
+ if (label.startsWith(`# `)) return html`<ixfx-menu-header label="${label.slice(2)}"></ixfx-menu-header>`;
586
+ if (!isLeaf(node)) {
587
+ const submenu = menuFromTree(node.children, options);
588
+ return html`
589
+ <ixfx-menu-sub-trigger label="${label}">
590
+ <ixfx-menu-container
591
+ slot="submenu"
592
+ .registry=${registry ?? nothing}
593
+ .keyboardManager=${keyboardManager ?? nothing}
594
+ >${submenu}</ixfx-menu-container>
595
+ </ixfx-menu-sub-trigger>
596
+ `;
597
+ }
598
+ return html`
599
+ <ixfx-menu-item
600
+ command="${node.item.key}"
601
+ label="${label}"
602
+ icon-name="${node.item.icon ?? nothing}"
603
+ @command=${onCommand ? (e) => onCommand(e.detail) : nothing}
604
+ ></ixfx-menu-item>
605
+ `;
606
+ })}`;
607
+ }
608
+ function buildMenuItemEl(node, options) {
609
+ const { onCommand, registry } = options;
610
+ const label = node.item.label;
611
+ const el = document.createElement(`ixfx-menu-item`);
612
+ el.setAttribute(`command`, node.item.key);
613
+ el.setAttribute(`label`, label);
614
+ if (node.item.icon) el.setAttribute(`icon-name`, node.item.icon);
615
+ if (onCommand) el.addEventListener(`command`, (e) => onCommand(e.detail));
616
+ if (registry) el.registry = registry;
617
+ return el;
618
+ }
619
+ function buildMenuSeparatorEl() {
620
+ return document.createElement(`ixfx-menu-separator`);
621
+ }
622
+ function buildMenuHeaderEl(label) {
623
+ const el = document.createElement(`ixfx-menu-header`);
624
+ el.setAttribute(`label`, label);
625
+ return el;
626
+ }
627
+ function buildMenuSubTriggerEl(node, options) {
628
+ const { registry, keyboardManager } = options;
629
+ const el = document.createElement(`ixfx-menu-sub-trigger`);
630
+ el.setAttribute(`label`, node.item.label);
631
+ if (registry) el.registry = registry;
632
+ if (keyboardManager) el.keyboardManager = keyboardManager;
633
+ const container = document.createElement(`ixfx-menu-container`);
634
+ container.setAttribute(`slot`, `submenu`);
635
+ if (registry) container.registry = registry;
636
+ if (keyboardManager) container.keyboardManager = keyboardManager;
637
+ const childEls = menuFromTreeToElements(node.children, options);
638
+ for (const child of childEls) container.appendChild(child);
639
+ el.appendChild(container);
640
+ return el;
641
+ }
642
+ function menuFromTreeToElements(nodes, options = {}) {
643
+ return nodes.map((node) => {
644
+ const label = node.item.label;
645
+ if (label === `-`) return buildMenuSeparatorEl();
646
+ if (label.startsWith(`# `)) return buildMenuHeaderEl(label.slice(2));
647
+ if (!isLeaf(node)) return buildMenuSubTriggerEl(node, options);
648
+ return buildMenuItemEl(node, options);
649
+ });
650
+ }
651
+ //#endregion
652
+ //#region src/menu/menu-radio-item.ts
653
+ let MenuRadioItem = class MenuRadioItem extends LitElement {
654
+ constructor(..._args) {
655
+ super(..._args);
656
+ this.value = ``;
657
+ this.label = ``;
658
+ this.disabled = false;
659
+ this.groupValue = ``;
660
+ this.iconName = ``;
661
+ }
662
+ handleClick() {
663
+ if (this.disabled) return;
664
+ this.dispatchEvent(new CustomEvent(`radio-select`, {
665
+ detail: { value: this.value },
666
+ bubbles: true,
667
+ composed: true
668
+ }));
669
+ }
670
+ static {
671
+ this.styles = [
672
+ themeFallbacks,
673
+ tickledItemStyles,
674
+ css`
675
+ :host {
676
+ display: block;
677
+ }
678
+
679
+ .item {
680
+ display: flex;
681
+ padding: 6px var(--space-m);
682
+ font-size: var(--text-m);
683
+ }
684
+
685
+ :host(:focus) {
686
+ outline: none;
687
+ }
688
+
689
+ .item.disabled {
690
+ opacity: var(--disabled-opacity);
691
+ cursor: default;
692
+ }
693
+
694
+ .item.disabled:hover {
695
+ background: transparent;
696
+ }
697
+
698
+ .radio {
699
+ width: 16px;
700
+ margin-right: var(--space-s);
701
+ font-size: var(--text-m);
702
+ color: var(--accent);
703
+ }
704
+
705
+ .icon-slot {
706
+ width: 0;
707
+ overflow: hidden;
708
+ flex-shrink: 0;
709
+ display: inline-flex;
710
+ align-items: center;
711
+ justify-content: center;
712
+ }
713
+
714
+ :host([icon-name]) .icon-slot,
715
+ :host([data-icon-section]) .icon-slot {
716
+ width: 1em;
717
+ height: 1em;
718
+ margin-right: var(--space-s);
719
+ }
720
+
721
+ .label {
722
+ flex: 1;
723
+ }
724
+ `
725
+ ];
726
+ }
727
+ render() {
728
+ const isSelected = this.groupValue === this.value;
729
+ return html`
730
+ <div
731
+ class="item ${this.disabled ? `disabled` : ``}"
732
+ @click=${this.handleClick}
733
+ tabindex="${this.disabled ? -1 : 0}"
734
+ role="menuitemradio"
735
+ aria-checked="${isSelected}"
736
+ >
737
+ <span class="radio">${isSelected ? `●` : ``}</span>
738
+ <span class="icon-slot">${this.iconName ? html`<ixfx-icon name="${this.iconName}"></ixfx-icon>` : null}</span>
739
+ <span class="label">${this.label}</span>
740
+ </div>
741
+ `;
742
+ }
743
+ };
744
+ __decorate([property({ type: String })], MenuRadioItem.prototype, "value", void 0);
745
+ __decorate([property({ type: String })], MenuRadioItem.prototype, "label", void 0);
746
+ __decorate([property({ type: Boolean })], MenuRadioItem.prototype, "disabled", void 0);
747
+ __decorate([property({ type: String })], MenuRadioItem.prototype, "groupValue", void 0);
748
+ __decorate([property({
749
+ type: String,
750
+ attribute: `icon-name`
751
+ })], MenuRadioItem.prototype, "iconName", void 0);
752
+ MenuRadioItem = __decorate([safeCustomElement(`ixfx-menu-radio-item`)], MenuRadioItem);
753
+ //#endregion
754
+ //#region src/menu/menu-radio-group.ts
755
+ let MenuRadioGroup = class MenuRadioGroup extends LitElement {
756
+ constructor(..._args) {
757
+ super(..._args);
758
+ this.name = ``;
759
+ this.value = ``;
760
+ this.slottedElements = [];
761
+ }
762
+ handleSlotChange(e) {
763
+ const slot = e.target;
764
+ this.slottedElements = slot.assignedElements();
765
+ this.updateSlottedValues();
766
+ }
767
+ updateSlottedValues() {
768
+ for (const el of this.slottedElements) el.groupValue = this.value;
769
+ }
770
+ handleRadioSelect(e) {
771
+ this.value = e.detail.value;
772
+ this.dispatchEvent(new CustomEvent(`radio-change`, {
773
+ detail: {
774
+ name: this.name,
775
+ value: this.value
776
+ },
777
+ bubbles: true,
778
+ composed: true
779
+ }));
780
+ }
781
+ updated(changedProperties) {
782
+ if (changedProperties.has(`value`)) this.updateSlottedValues();
783
+ }
784
+ static {
785
+ this.styles = css`
786
+ :host {
787
+ display: block;
788
+ }
789
+
790
+ ::slotted(menu-radio-item) {
791
+ display: block;
792
+ }
793
+ `;
794
+ }
795
+ render() {
796
+ return html`
797
+ <slot @slotchange=${this.handleSlotChange} @radio-select=${this.handleRadioSelect}></slot>
798
+ `;
799
+ }
800
+ };
801
+ __decorate([property({ type: String })], MenuRadioGroup.prototype, "name", void 0);
802
+ __decorate([property({ type: String })], MenuRadioGroup.prototype, "value", void 0);
803
+ __decorate([state()], MenuRadioGroup.prototype, "slottedElements", void 0);
804
+ MenuRadioGroup = __decorate([safeCustomElement(`ixfx-menu-radio-group`)], MenuRadioGroup);
805
+ //#endregion
806
+ //#region src/menu/index.ts
807
+ var menu_exports = /* @__PURE__ */ __exportAll({
808
+ MenuBar: () => MenuBar,
809
+ MenuCheckItem: () => MenuCheckItem,
810
+ MenuCommandController: () => MenuCommandController,
811
+ MenuContainer: () => MenuContainer,
812
+ MenuHeader: () => MenuHeader,
813
+ MenuItem: () => MenuItem,
814
+ MenuRadioGroup: () => MenuRadioGroup,
815
+ MenuRadioItem: () => MenuRadioItem,
816
+ MenuSeparator: () => MenuSeparator,
817
+ MenuSubTrigger: () => MenuSubTrigger,
818
+ MenuTrigger: () => MenuTrigger,
819
+ menuFromTree: () => menuFromTree,
820
+ menuFromTreeToElements: () => menuFromTreeToElements
821
+ });
822
+ //#endregion
823
+ export { menuFromTreeToElements as a, MenuSubTrigger as c, MenuBar as d, menuFromTree as i, MenuCommandController as l, MenuRadioGroup as n, MenuHeader as o, MenuRadioItem as r, MenuSeparator as s, menu_exports as t, MenuCheckItem as u };
824
+
825
+ //# sourceMappingURL=menu-CXDFJxNm.js.map