@ixfx/components 0.6.2 → 0.7.0

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 (152) hide show
  1. package/bundle/index.d.ts +1490 -615
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +20477 -15855
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +1 -1
  6. package/dist/ac-text.js +3 -2
  7. package/dist/ac-text.js.map +1 -1
  8. package/dist/ac-token.js +3 -2
  9. package/dist/ac-token.js.map +1 -1
  10. package/dist/{button-Bn0BuLpO.js → button-Dat2yHAU.js} +4 -3
  11. package/dist/button-Dat2yHAU.js.map +1 -0
  12. package/dist/button.js +1 -1
  13. package/dist/checkbox.js +1 -1
  14. package/dist/{colour-picker-0stHB90J.js → colour-picker-BSDBL-QL.js} +4 -3
  15. package/dist/{colour-picker-0stHB90J.js.map → colour-picker-BSDBL-QL.js.map} +1 -1
  16. package/dist/colour-picker.js +1 -1
  17. package/dist/crumbs.js +4 -2
  18. package/dist/crumbs.js.map +1 -1
  19. package/dist/data-display.js +1 -1
  20. package/dist/data-grid.js +4 -2
  21. package/dist/data-grid.js.map +1 -1
  22. package/dist/{defaults-BCiDhZbF.js → defaults-BkWCPJFL.js} +3 -20
  23. package/dist/defaults-BkWCPJFL.js.map +1 -0
  24. package/dist/editable-label-rzXkjf1H.d.ts +75 -0
  25. package/dist/editable-label-rzXkjf1H.d.ts.map +1 -0
  26. package/dist/editable-label.d.ts +2 -75
  27. package/dist/editable-label.js +2 -1
  28. package/dist/editable-label.js.map +1 -1
  29. package/dist/{fallbacks-DEE1nCTt.js → fallbacks-DNI9xt0F.js} +2 -2
  30. package/dist/{fallbacks-DEE1nCTt.js.map → fallbacks-DNI9xt0F.js.map} +1 -1
  31. package/dist/{grouped-item-lister-_pMDwIo1.d.ts → grouped-item-lister-DnWB-eFT.d.ts} +2 -2
  32. package/dist/{grouped-item-lister-_pMDwIo1.d.ts.map → grouped-item-lister-DnWB-eFT.d.ts.map} +1 -1
  33. package/dist/grouped-item-lister.d.ts +1 -1
  34. package/dist/{icons-Bm2ByQ3s.js → icon-CvnPanhA.js} +3 -6
  35. package/dist/icon-CvnPanhA.js.map +1 -0
  36. package/dist/icons.js +8 -2
  37. package/dist/icons.js.map +1 -0
  38. package/dist/index-CG2vIgPv.d.ts +101 -0
  39. package/dist/index-CG2vIgPv.d.ts.map +1 -0
  40. package/dist/index.d.ts +655 -65
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +3682 -924
  43. package/dist/index.js.map +1 -1
  44. package/dist/interaction-D5XdKzbR.js +2 -0
  45. package/dist/labelled-radial-input.js +2 -1
  46. package/dist/labelled-radial-input.js.map +1 -1
  47. package/dist/labelled-slider-input-DzigjMwP.js +808 -0
  48. package/dist/labelled-slider-input-DzigjMwP.js.map +1 -0
  49. package/dist/labelled-slider-input.d.ts +2 -0
  50. package/dist/labelled-slider-input.js +2 -0
  51. package/dist/{types-DlVNJez_.d.ts → list-selection-types-DSuRNWpx.d.ts} +10 -2
  52. package/dist/list-selection-types-DSuRNWpx.d.ts.map +1 -0
  53. package/dist/menu-BjRvlgPy.js +825 -0
  54. package/dist/menu-BjRvlgPy.js.map +1 -0
  55. package/dist/menu-item-B-zYrTTi.js +797 -0
  56. package/dist/menu-item-B-zYrTTi.js.map +1 -0
  57. package/dist/menu.js +2 -1
  58. package/dist/miller.d.ts +1 -1
  59. package/dist/miller.js +3 -2
  60. package/dist/miller.js.map +1 -1
  61. package/dist/narrowed-text.js +4 -2
  62. package/dist/narrowed-text.js.map +1 -1
  63. package/dist/notifier.js +3 -2
  64. package/dist/notifier.js.map +1 -1
  65. package/dist/panel.d.ts +13 -13
  66. package/dist/panel.d.ts.map +1 -1
  67. package/dist/panel.js +37 -253
  68. package/dist/panel.js.map +1 -1
  69. package/dist/plots.js +1 -1
  70. package/dist/polar-pad.js +1 -1
  71. package/dist/{radial-input-Dk8Wydp5.js → radial-input-Dp5qz0ly.js} +2 -2
  72. package/dist/{radial-input-Dk8Wydp5.js.map → radial-input-Dp5qz0ly.js.map} +1 -1
  73. package/dist/radial-input.js +1 -1
  74. package/dist/range-input.js +1 -1
  75. package/dist/range.js +1 -1
  76. package/dist/registry-CkW7q09Q.js +21 -0
  77. package/dist/registry-CkW7q09Q.js.map +1 -0
  78. package/dist/select-horiz.js +3 -2
  79. package/dist/select-horiz.js.map +1 -1
  80. package/dist/{slider-input-XppH3vcy.d.ts → slider-input-BfRUW2ZB.d.ts} +16 -3
  81. package/dist/slider-input-BfRUW2ZB.d.ts.map +1 -0
  82. package/dist/{slider-input-CT4gcF-o.js → slider-input-De4eoT11.js} +382 -67
  83. package/dist/slider-input-De4eoT11.js.map +1 -0
  84. package/dist/slider-input.d.ts +1 -1
  85. package/dist/slider-input.js +1 -1
  86. package/dist/snackbar.js +1 -1
  87. package/dist/split-layout-BFSbUZQv.js +969 -0
  88. package/dist/split-layout-BFSbUZQv.js.map +1 -0
  89. package/dist/split-layout-JK3xWVX2.d.ts +179 -0
  90. package/dist/split-layout-JK3xWVX2.d.ts.map +1 -0
  91. package/dist/split-layout.d.ts +2 -60
  92. package/dist/split-layout.js +1 -617
  93. package/dist/style.css +1 -1
  94. package/dist/swipe.js +1 -1
  95. package/dist/{tab-list-D_1cYhB_.d.ts → tab-list-MPwq_1Jj.d.ts} +2 -1
  96. package/dist/tab-list-MPwq_1Jj.d.ts.map +1 -0
  97. package/dist/tabs.d.ts +1 -1
  98. package/dist/tabs.js +96 -14
  99. package/dist/tabs.js.map +1 -1
  100. package/dist/{tickled-controller-BtevrRLV.d.ts → tickled-controller-CRzdIEjJ.d.ts} +7 -1
  101. package/dist/tickled-controller-CRzdIEjJ.d.ts.map +1 -0
  102. package/dist/{tickled-controller-DkAU-0qL.js → tickled-controller-h9GmJ_bU.js} +8 -2
  103. package/dist/tickled-controller-h9GmJ_bU.js.map +1 -0
  104. package/dist/titlebar-DaCfpliv.d.ts +50 -0
  105. package/dist/titlebar-DaCfpliv.d.ts.map +1 -0
  106. package/dist/titlebar.d.ts +2 -0
  107. package/dist/titlebar.js +324 -0
  108. package/dist/titlebar.js.map +1 -0
  109. package/dist/{tree-BO6BXI2b.js → tree-Ch4W8qXQ.js} +4 -3
  110. package/dist/{tree-BO6BXI2b.js.map → tree-Ch4W8qXQ.js.map} +1 -1
  111. package/dist/tree.d.ts +1 -1
  112. package/dist/tree.js +1 -1
  113. package/dist/vertical-list-ClnqTkF3.js +814 -0
  114. package/dist/vertical-list-ClnqTkF3.js.map +1 -0
  115. package/dist/vertical-list.d.ts +8 -9
  116. package/dist/vertical-list.d.ts.map +1 -1
  117. package/dist/vertical-list.js +1 -736
  118. package/dist/{xy-axis-B6yMjckW.js → xy-axis-CxHC8z5E.js} +109 -3
  119. package/dist/xy-axis-CxHC8z5E.js.map +1 -0
  120. package/dist/xy-pad.js +1 -1
  121. package/docs-user/README.md +5 -0
  122. package/docs-user/detail-list.md +398 -0
  123. package/docs-user/dock.md +310 -0
  124. package/docs-user/index.json +27 -2
  125. package/docs-user/labelled-slider-input.md +198 -0
  126. package/docs-user/llms.txt +6 -1
  127. package/docs-user/panel.md +20 -1
  128. package/docs-user/slider-input.md +55 -15
  129. package/docs-user/split-layout.md +136 -170
  130. package/docs-user/tabs.md +34 -0
  131. package/docs-user/titlebar.md +102 -0
  132. package/docs-user/toolbar.md +95 -22
  133. package/docs-user/twosplit-layout.md +254 -0
  134. package/docs-user/user-catalog.md +8 -1
  135. package/llms.txt +6 -1
  136. package/package.json +1 -2
  137. package/dist/button-Bn0BuLpO.js.map +0 -1
  138. package/dist/defaults-BCiDhZbF.js.map +0 -1
  139. package/dist/editable-label.d.ts.map +0 -1
  140. package/dist/icons-Bm2ByQ3s.js.map +0 -1
  141. package/dist/menu-DIfU70AA.js +0 -1609
  142. package/dist/menu-DIfU70AA.js.map +0 -1
  143. package/dist/slider-input-CT4gcF-o.js.map +0 -1
  144. package/dist/slider-input-XppH3vcy.d.ts.map +0 -1
  145. package/dist/split-layout.d.ts.map +0 -1
  146. package/dist/split-layout.js.map +0 -1
  147. package/dist/tab-list-D_1cYhB_.d.ts.map +0 -1
  148. package/dist/tickled-controller-BtevrRLV.d.ts.map +0 -1
  149. package/dist/tickled-controller-DkAU-0qL.js.map +0 -1
  150. package/dist/types-DlVNJez_.d.ts.map +0 -1
  151. package/dist/vertical-list.js.map +0 -1
  152. package/dist/xy-axis-B6yMjckW.js.map +0 -1
@@ -1,737 +1,2 @@
1
- import { t as TickledController } from "./tickled-controller-DkAU-0qL.js";
2
- import { t as themeFallbacks } from "./fallbacks-DEE1nCTt.js";
3
- import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
4
- import { t as createElementIncrSearch } from "./element-search-Y8SRfPGM.js";
5
- import { LitElement, css, html, render } from "lit";
6
- import { property, query, state } from "lit/decorators.js";
7
- //#region src/vertical-list/vertical-list.ts
8
- const ITEM_SELECTOR = `li, [data-list-item]`;
9
- function isMultiMode(mode) {
10
- return mode === `checked` || mode === `sticky` || mode === `vscode` || mode === `standard`;
11
- }
12
- let VerticalListElement = class VerticalListElement extends LitElement {
13
- constructor(..._args2) {
14
- super(..._args2);
15
- this.selectionMode = `single`;
16
- this.interactionMode = `standard`;
17
- this._selectedItems = /* @__PURE__ */ new Set();
18
- this._searchVisible = false;
19
- this._searchQuery = ``;
20
- this.#customWrappers = /* @__PURE__ */ new Map();
21
- this.#wrappedElements = /* @__PURE__ */ new Set();
22
- this.tickled = new TickledController(this, {
23
- getItems: () => this._getVisibleItems().map((el) => ({
24
- id: el,
25
- enabled: true
26
- })),
27
- onTickle: (id) => {
28
- if (id !== void 0) this._dispatch(`list-tickle`, { item: id });
29
- },
30
- onStateChange: () => this._syncItemStates()
31
- });
32
- this._onPointerOver = (e) => {
33
- const item = this._findListItem(e.composedPath());
34
- if (item) this.tickled.handlePointerEnter(item);
35
- };
36
- this._onPointerLeave = (e) => {
37
- this.tickled.handlePointerLeave(e);
38
- };
39
- this._onKeyDown = (e) => {
40
- if ((e.ctrlKey || e.metaKey) && e.key === `f`) {
41
- e.preventDefault();
42
- this._openSearch();
43
- return;
44
- }
45
- if ((e.ctrlKey || e.metaKey) && e.key === `a`) {
46
- if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) {
47
- e.preventDefault();
48
- this._selectAll();
49
- }
50
- return;
51
- }
52
- if (this._searchVisible) return;
53
- switch (e.key) {
54
- case `ArrowDown`:
55
- e.preventDefault();
56
- this.tickled.handleKeyboardNavigation(`next`);
57
- if (e.shiftKey && this.interactionMode === `vscode`) {
58
- const cur = this.tickled.tickledId;
59
- if (cur) this._rangeSelectTo(cur);
60
- }
61
- break;
62
- case `ArrowUp`:
63
- e.preventDefault();
64
- this.tickled.handleKeyboardNavigation(`previous`);
65
- if (e.shiftKey && this.interactionMode === `vscode`) {
66
- const cur = this.tickled.tickledId;
67
- if (cur) this._rangeSelectTo(cur);
68
- }
69
- break;
70
- case `Enter`: {
71
- const id = this.tickled.tickledId;
72
- if (id) {
73
- e.preventDefault();
74
- this._dispatch(`list-item-click`, { item: id });
75
- this._activateItem(id);
76
- }
77
- break;
78
- }
79
- case ` `: {
80
- const id = this.tickled.tickledId;
81
- if (id) {
82
- e.preventDefault();
83
- this._handleSpaceKey(id);
84
- }
85
- break;
86
- }
87
- case `Escape`: this._clearSelection();
88
- }
89
- };
90
- this._onClick = (e) => {
91
- const item = this._findListItem(e.composedPath());
92
- if (!item) return;
93
- this._dispatch(`list-item-click`, { item });
94
- this._handleClickSelection(item, e);
95
- };
96
- this._onDblClick = (e) => {
97
- const item = this._findListItem(e.composedPath());
98
- if (item) this._activateItem(item);
99
- };
100
- this._onSearchInput = (e) => {
101
- const input = e.target;
102
- this._searchQuery = input.value;
103
- this.#search?.setQuery(this._searchQuery);
104
- };
105
- this._onSearchKeydown = (e) => {
106
- if (e.key === `Escape`) {
107
- e.stopPropagation();
108
- this._closeSearch();
109
- } else if (e.key === `ArrowDown`) {
110
- e.preventDefault();
111
- this.tickled.handleKeyboardNavigation(`next`);
112
- } else if (e.key === `ArrowUp`) {
113
- e.preventDefault();
114
- this.tickled.handleKeyboardNavigation(`previous`);
115
- } else if (e.key === `Enter`) {
116
- e.preventDefault();
117
- e.stopPropagation();
118
- const id = this.tickled.tickledId ?? this._getVisibleItems()[0];
119
- if (id) {
120
- this._dispatch(`list-item-click`, { item: id });
121
- this._activateItem(id);
122
- this._closeSearch();
123
- }
124
- }
125
- };
126
- }
127
- #search;
128
- #selectionAnchor;
129
- #customWrappers;
130
- #wrappedElements;
131
- connectedCallback() {
132
- super.connectedCallback();
133
- if (!this.hasAttribute(`tabindex`)) this.tabIndex = 0;
134
- this.addEventListener(`pointerover`, this._onPointerOver);
135
- this.addEventListener(`pointerleave`, this._onPointerLeave);
136
- this.addEventListener(`keydown`, this._onKeyDown);
137
- this.addEventListener(`click`, this._onClick);
138
- this.addEventListener(`dblclick`, this._onDblClick);
139
- }
140
- disconnectedCallback() {
141
- super.disconnectedCallback();
142
- this.removeEventListener(`pointerover`, this._onPointerOver);
143
- this.removeEventListener(`pointerleave`, this._onPointerLeave);
144
- this.removeEventListener(`keydown`, this._onKeyDown);
145
- this.removeEventListener(`click`, this._onClick);
146
- this.removeEventListener(`dblclick`, this._onDblClick);
147
- this.#search?.dispose();
148
- this.#search = void 0;
149
- }
150
- firstUpdated() {
151
- this.#search = createElementIncrSearch({
152
- container: this,
153
- itemSelector: ITEM_SELECTOR,
154
- getLabel: (el) => el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
155
- getKey: (el) => el.getAttribute(`data-key`) ?? el.getAttribute(`data-search-label`) ?? el.textContent?.trim() ?? ``,
156
- highlightKey: `vertical-list-search`
157
- });
158
- }
159
- updated(changed) {
160
- super.updated(changed);
161
- if (changed.has(`interactionMode`)) {
162
- this.#selectionAnchor = void 0;
163
- const previousSelected = this._selectedItems;
164
- const savedWrappers = changed.get(`interactionMode`) === `checked` ? new Map(this.#customWrappers) : null;
165
- this._syncCheckboxes();
166
- if (previousSelected.size > 0) {
167
- let remapped;
168
- if (savedWrappers && savedWrappers.size > 0) remapped = new Set([...previousSelected].map((el) => savedWrappers.get(el) ?? el));
169
- else if (this.#customWrappers.size > 0) {
170
- const innerToWrapper = new Map([...this.#customWrappers].map(([w, i]) => [i, w]));
171
- remapped = new Set([...previousSelected].map((el) => innerToWrapper.get(el) ?? el));
172
- } else remapped = new Set(previousSelected);
173
- this._selectedItems = remapped;
174
- }
175
- this._syncItemStates();
176
- } else if (changed.has(`checkboxRenderer`) && this.interactionMode === `checked`) this._syncCheckboxes();
177
- }
178
- /** The most recently selected item, or `undefined` if nothing is selected. */
179
- get selectedItem() {
180
- return [...this._selectedItems].at(-1);
181
- }
182
- /** The full current selection set (read-only). */
183
- get selectedItems() {
184
- return this._selectedItems;
185
- }
186
- addItem(item, options) {
187
- let el;
188
- if (typeof item === `string`) {
189
- const li = document.createElement(`li`);
190
- li.textContent = item;
191
- el = li;
192
- } else el = item;
193
- if (options?.notChecked) el.setAttribute(`not-checked`, ``);
194
- this.appendChild(el);
195
- if (this.interactionMode === `checked`) this._syncCheckboxes();
196
- }
197
- removeItem(item) {
198
- item.remove();
199
- }
200
- clearItems() {
201
- this.#customWrappers.clear();
202
- this.replaceChildren();
203
- this.#selectionAnchor = void 0;
204
- this._selectedItems = /* @__PURE__ */ new Set();
205
- this._syncItemStates();
206
- }
207
- /**
208
- * Replace the entire item list in one call.
209
- * Equivalent to `clearItems()` followed by `addItem()` for each element.
210
- * Preserves `interactionMode` checkbox wrapping.
211
- */
212
- setItems(items) {
213
- this.clearItems();
214
- for (const item of items) this.appendChild(item);
215
- if (this.interactionMode === `checked`) this._syncCheckboxes();
216
- }
217
- /**
218
- * Dispatch a command to this list. No-op by default.
219
- * Intended for use with `ixfx-grouped-item-lister`'s `dispatch()` method,
220
- * which forwards commands to all sub-components.
221
- */
222
- dispatch(_commandId, _args) {}
223
- select(item) {
224
- this._replaceSelection(item);
225
- }
226
- selectMany(items) {
227
- if (this.selectionMode !== `multiple`) throw new Error(`selectMany requires selectionMode="multiple" (current: "${this.selectionMode}")`);
228
- const previous = this._selectedItems;
229
- const next = new Set([...items].filter((el) => this._isCheckable(el)));
230
- if (next.size === 0) return;
231
- this._selectedItems = next;
232
- this.#selectionAnchor = [...next].at(-1);
233
- this._syncItemStates();
234
- this._dispatch(`list-select`, {
235
- selected: next,
236
- previous
237
- });
238
- }
239
- deselect(item) {
240
- if (!this._selectedItems.has(item)) return;
241
- const previous = this._selectedItems;
242
- const next = new Set(this._selectedItems);
243
- next.delete(item);
244
- this._selectedItems = next;
245
- this._syncItemStates();
246
- this._dispatch(`list-select`, {
247
- selected: next,
248
- previous
249
- });
250
- }
251
- clearSelection() {
252
- this._clearSelection();
253
- }
254
- selectAll() {
255
- if ((this.selectionMode === `multiple` || isMultiMode(this.interactionMode)) && this.selectionMode !== `none`) this._selectAll();
256
- }
257
- *selectedFilter(kind) {
258
- const wanted = (el) => {
259
- switch (kind) {
260
- case `selected`: return el.hasAttribute(`data-selected`);
261
- case `checked`: return el.hasAttribute(`data-checked`);
262
- case `either`: return el.hasAttribute(`data-selected`) || el.hasAttribute(`data-checked`);
263
- }
264
- };
265
- for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
266
- if (this.#wrappedElements.has(el)) continue;
267
- if (el.hidden) continue;
268
- if (wanted(el)) yield el;
269
- }
270
- }
271
- _replaceSelection(item) {
272
- if (this.selectionMode === `none`) return;
273
- if (!this._isCheckable(item)) return;
274
- const previous = this._selectedItems;
275
- const next = /* @__PURE__ */ new Set([item]);
276
- this._selectedItems = next;
277
- this.#selectionAnchor = item;
278
- this._syncItemStates();
279
- this._dispatch(`list-select`, {
280
- selected: next,
281
- previous
282
- });
283
- }
284
- _toggleItem(item) {
285
- if (!this._isCheckable(item)) return;
286
- const effectiveMultiple = this.selectionMode === `multiple` || isMultiMode(this.interactionMode);
287
- if (this.selectionMode === `none` && this.interactionMode !== `checked` && this.interactionMode !== `sticky`) return;
288
- const previous = this._selectedItems;
289
- const next = new Set(this._selectedItems);
290
- if (next.has(item)) next.delete(item);
291
- else {
292
- if (!effectiveMultiple) next.clear();
293
- next.add(item);
294
- }
295
- this._selectedItems = next;
296
- this._syncItemStates();
297
- this._dispatch(`list-select`, {
298
- selected: next,
299
- previous
300
- });
301
- }
302
- _rangeSelectTo(item) {
303
- if (this.selectionMode === `none`) return;
304
- if (!this.#selectionAnchor) {
305
- this._replaceSelection(item);
306
- return;
307
- }
308
- const visible = this._getVisibleItems();
309
- const anchorIdx = visible.indexOf(this.#selectionAnchor);
310
- const targetIdx = visible.indexOf(item);
311
- if (anchorIdx === -1 || targetIdx === -1) {
312
- this._replaceSelection(item);
313
- return;
314
- }
315
- const start = Math.min(anchorIdx, targetIdx);
316
- const end = Math.max(anchorIdx, targetIdx);
317
- const previous = this._selectedItems;
318
- const next = new Set(visible.slice(start, end + 1).filter((el) => this._isCheckable(el)));
319
- this._selectedItems = next;
320
- this._syncItemStates();
321
- this._dispatch(`list-select`, {
322
- selected: next,
323
- previous
324
- });
325
- }
326
- _clearSelection() {
327
- if (this._selectedItems.size === 0) return;
328
- const previous = this._selectedItems;
329
- this._selectedItems = /* @__PURE__ */ new Set();
330
- this._syncItemStates();
331
- this._dispatch(`list-select`, {
332
- selected: /* @__PURE__ */ new Set(),
333
- previous
334
- });
335
- }
336
- _selectAll() {
337
- const visible = this._getVisibleItems();
338
- if (visible.length === 0) return;
339
- const previous = this._selectedItems;
340
- const next = new Set(visible.filter((el) => this._isCheckable(el)));
341
- if (next.size === 0) return;
342
- this._selectedItems = next;
343
- this._syncItemStates();
344
- this._dispatch(`list-select`, {
345
- selected: next,
346
- previous
347
- });
348
- }
349
- _handleClickSelection(item, e) {
350
- const mode = this.interactionMode;
351
- if (mode === `manual`) return;
352
- if (this.selectionMode === `none` && mode !== `checked` && mode !== `sticky`) return;
353
- switch (mode) {
354
- case `implicit`:
355
- this._replaceSelection(item);
356
- break;
357
- case `standard`:
358
- case `vscode`:
359
- if (e.ctrlKey || e.metaKey) {
360
- if (this.selectionMode === `multiple` || mode === `vscode`) this._toggleItem(item);
361
- } else if (e.shiftKey && (this.selectionMode === `multiple` || mode === `vscode`)) this._rangeSelectTo(item);
362
- else this._replaceSelection(item);
363
- break;
364
- case `checked`: break;
365
- case `sticky`: this._toggleItem(item);
366
- }
367
- }
368
- _handleSpaceKey(item) {
369
- const mode = this.interactionMode;
370
- if (mode === `manual`) return;
371
- if (mode === `implicit`) this._replaceSelection(item);
372
- else this._toggleItem(item);
373
- }
374
- _getVisibleItems() {
375
- return Array.from(this.querySelectorAll(ITEM_SELECTOR)).filter((el) => {
376
- if (this.#wrappedElements.has(el)) return false;
377
- if (el.hidden) return false;
378
- if (this.filterPredicate && !this.filterPredicate(el)) return false;
379
- return true;
380
- });
381
- }
382
- _isCheckable(item) {
383
- if (this.interactionMode !== `checked`) return true;
384
- return !(this.#customWrappers.get(item) ?? item).hasAttribute(`not-checked`);
385
- }
386
- _syncItemStates() {
387
- for (const el of this.querySelectorAll(ITEM_SELECTOR)) {
388
- if (this.#wrappedElements.has(el)) continue;
389
- const item = this.#customWrappers.get(el) ?? el;
390
- el.toggleAttribute(`data-tickled`, this.tickled.isTickled(el));
391
- el.toggleAttribute(`data-selected`, this._selectedItems.has(el));
392
- if (this.interactionMode === `checked`) el.toggleAttribute(`data-checked`, !item.hasAttribute(`not-checked`) && this._selectedItems.has(el));
393
- else el.removeAttribute(`data-checked`);
394
- }
395
- this.dataset.inputMode = this.tickled.inputMode;
396
- this._syncCheckboxes();
397
- }
398
- _syncCheckboxes() {
399
- const inCheckedMode = this.interactionMode === `checked`;
400
- const wantsCustom = typeof this.checkboxRenderer === `function`;
401
- if (inCheckedMode) for (const inner of Array.from(this.children)) {
402
- if (!inner.hasAttribute(`data-list-item`)) continue;
403
- if (inner.parentElement !== this) continue;
404
- const wrapper = document.createElement(`li`);
405
- wrapper.className = `ixfx-custom-row`;
406
- const key = inner.getAttribute(`data-key`);
407
- const label = inner.getAttribute(`data-search-label`);
408
- if (key !== null) wrapper.setAttribute(`data-key`, key);
409
- if (label !== null) wrapper.setAttribute(`data-search-label`, label);
410
- inner.removeAttribute(`data-list-item`);
411
- this.insertBefore(wrapper, inner);
412
- wrapper.appendChild(inner);
413
- this.#customWrappers.set(wrapper, inner);
414
- this.#wrappedElements.add(inner);
415
- }
416
- else {
417
- for (const [wrapper, inner] of this.#customWrappers) {
418
- if (wrapper.parentElement !== this) continue;
419
- inner.setAttribute(`data-list-item`, ``);
420
- this.insertBefore(inner, wrapper);
421
- wrapper.remove();
422
- }
423
- this.#customWrappers.clear();
424
- this.#wrappedElements.clear();
425
- }
426
- for (const el of this.querySelectorAll(`li`)) {
427
- const existing = el.querySelector(`.ixfx-list-checkbox`);
428
- if (!inCheckedMode) {
429
- if (existing) existing.remove();
430
- continue;
431
- }
432
- if ((this.#customWrappers.get(el) ?? el).hasAttribute(`not-checked`)) {
433
- if (existing) existing.remove();
434
- continue;
435
- }
436
- const existingIsCustom = existing?.classList.contains(`ixfx-list-checkbox-custom`) ?? false;
437
- if (existing && existingIsCustom !== wantsCustom) existing.remove();
438
- let cb = el.querySelector(`.ixfx-list-checkbox`);
439
- if (!cb) {
440
- if (wantsCustom) {
441
- const opts = this.checkboxRenderer;
442
- const margin = opts.margin ?? `0`;
443
- const width = opts.width ?? `24px`;
444
- cb = this._createCustomCheckbox(el, margin, width);
445
- } else cb = this._createNativeCheckboxCell(el);
446
- el.prepend(cb);
447
- }
448
- const checked = this._selectedItems.has(el);
449
- if (wantsCustom) {
450
- cb.setAttribute(`aria-checked`, String(checked));
451
- cb.toggleAttribute(`data-checked`, checked);
452
- if (this.checkboxRenderer) {
453
- const renderer = typeof this.checkboxRenderer === `function` ? this.checkboxRenderer : this.checkboxRenderer.renderer;
454
- render(renderer(checked), cb);
455
- }
456
- } else {
457
- const input = cb.querySelector(`input.ixfx-list-checkbox`);
458
- if (input) input.checked = checked;
459
- }
460
- }
461
- }
462
- /**
463
- * Native checkbox cell: a span that stretches to the row's full cross-axis
464
- * (so the entire column height is a click target) with a real `<input>`
465
- * centred inside. The span owns the click; the input is purely visual and
466
- * has `pointer-events:none` so a single click produces one toggle.
467
- */
468
- _createNativeCheckboxCell(el) {
469
- const cell = document.createElement(`span`);
470
- cell.className = `ixfx-list-checkbox ixfx-list-checkbox-native`;
471
- cell.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;align-self:stretch;width:18px;margin:0 6px 0 0;cursor:pointer;pointer-events:auto`;
472
- cell.tabIndex = -1;
473
- cell.setAttribute(`role`, `checkbox`);
474
- cell.setAttribute(`part`, `checkbox`);
475
- cell.addEventListener(`click`, (e) => {
476
- e.stopPropagation();
477
- this._toggleItem(el);
478
- });
479
- const input = document.createElement(`input`);
480
- input.type = `checkbox`;
481
- input.className = `ixfx-list-checkbox`;
482
- input.style.cssText = `pointer-events:none;cursor:pointer;margin:0`;
483
- cell.appendChild(input);
484
- return cell;
485
- }
486
- /**
487
- * Custom checkbox cell: same shape as the native cell (a stretching span)
488
- * so behaviour is identical. The renderer's content goes inside.
489
- */
490
- _createCustomCheckbox(el, margin, width) {
491
- const span = document.createElement(`span`);
492
- span.className = `ixfx-list-checkbox ixfx-list-checkbox-custom`;
493
- span.style.cssText = `display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;align-self:stretch;width:${width};margin:${margin};cursor:pointer;pointer-events:auto`;
494
- span.tabIndex = -1;
495
- span.setAttribute(`role`, `checkbox`);
496
- span.setAttribute(`part`, `checkbox`);
497
- span.addEventListener(`click`, (e) => {
498
- e.stopPropagation();
499
- this._toggleItem(el);
500
- });
501
- return span;
502
- }
503
- _findListItem(path) {
504
- for (const target of path) {
505
- if (!(target instanceof Element)) continue;
506
- if (target === this) break;
507
- if (target.parentElement === this && target.matches(ITEM_SELECTOR)) return target;
508
- }
509
- }
510
- _dispatch(name, detail) {
511
- this.dispatchEvent(new CustomEvent(name, {
512
- detail,
513
- bubbles: true,
514
- composed: true
515
- }));
516
- }
517
- _openSearch() {
518
- this._searchVisible = true;
519
- this.updateComplete.then(() => this._searchInputEl?.focus());
520
- }
521
- _closeSearch() {
522
- this._searchVisible = false;
523
- this._searchQuery = ``;
524
- this.#search?.clearQuery();
525
- this.focus();
526
- }
527
- _activateItem(item) {
528
- if (this.interactionMode !== `manual`) this._replaceSelection(item);
529
- this._dispatch(`list-activate`, { item });
530
- }
531
- static {
532
- this.styles = [themeFallbacks, css`
533
- :host {
534
- display: block;
535
- position: relative;
536
- background: var(--list-bg, var(--surface-3));
537
- color: var(--list-text, var(--surface-3-text));
538
- border-radius: var(--list-radius, var(--radius-s));
539
- border: 1px solid var(--list-border, var(--border));
540
- width: 100%;
541
- height: 100%;
542
- overflow: hidden;
543
- box-sizing: border-box;
544
- outline: none;
545
- --ixfx-list-item-padding: var(--ixfx-list-item-padding, var(--list-item-padding, 4px var(--space-m, 8px)));
546
- }
547
-
548
- :host(:focus-visible) {
549
- outline: 2px solid var(--accent);
550
- outline-offset: 2px;
551
- }
552
-
553
- .container {
554
- position: relative;
555
- width: 100%;
556
- height: 100%;
557
- }
558
-
559
- ul {
560
- list-style: none;
561
- margin: 0;
562
- padding: 0;
563
- width: 100%;
564
- height: 100%;
565
- overflow-x: hidden;
566
- overflow-y: auto;
567
- box-sizing: border-box;
568
- /* Scrollbar theming: end users override these CSS variables to control
569
- the native scrollbar (scrollbar-width, scrollbar-gutter, scrollbar-color). */
570
- scrollbar-width: var(--list-scrollbar-width, auto);
571
- scrollbar-gutter: var(--list-scrollbar-gutter, auto);
572
- scrollbar-color: var(--list-scrollbar-color, auto);
573
- }
574
-
575
- ::slotted([hidden]) {
576
- display: none !important;
577
- }
578
-
579
- ::slotted(li) {
580
- display: flex;
581
- align-items: center;
582
- padding: var(--ixfx-list-item-padding);
583
- min-height: var(--list-item-height, 28px);
584
- cursor: pointer;
585
- user-select: none;
586
- transition: background var(--transition, 0.1s ease-out),
587
- outline-color var(--transition, 0.1s ease-out);
588
- box-sizing: border-box;
589
- outline: 1px solid transparent;
590
- }
591
-
592
- /* Custom shadow-DOM components handle their own internal layout/padding */
593
- ::slotted([data-list-item]) {
594
- display: block;
595
- cursor: pointer;
596
- user-select: none;
597
- transition: background var(--transition, 0.1s ease-out),
598
- outline-color var(--transition, 0.1s ease-out);
599
- outline: 1px solid transparent;
600
- }
601
-
602
- /* In checked mode, only the checkbox column is clickable; the row body
603
- gets a default cursor so it doesn't suggest otherwise. */
604
- :host([interaction-mode="checked"]) ::slotted(li),
605
- :host([interaction-mode="checked"]) ::slotted([data-list-item]) {
606
- cursor: default;
607
- }
608
-
609
- /* Wrapper inserted around custom [data-list-item] elements in checked mode.
610
- Provides the flex layout so the injected checkbox can stretch to the
611
- row's full height via align-self:stretch. */
612
- .ixfx-custom-row {
613
- display: flex;
614
- align-items: center;
615
- min-height: var(--list-item-height, 28px);
616
- box-sizing: border-box;
617
- cursor: default;
618
- user-select: none;
619
- }
620
-
621
- ::slotted([data-tickled]) {
622
- background: var(--item-bg-tickled);
623
- outline: var(--item-border-tickled);
624
- }
625
-
626
- ::slotted([data-selected]) {
627
- background: var(--item-bg-selected);
628
- color: var(--item-text-selected);
629
- outline: 1px solid transparent;
630
- }
631
-
632
- ::slotted([data-selected][data-tickled]) {
633
- background: var(--item-bg-selected-tickled);
634
- outline: 2px dashed var(--surface-3);
635
- outline-offset: -2px;
636
- }
637
-
638
- /* checked mode: checkbox (injected into li) communicates selection — suppress bg highlight */
639
- :host([interaction-mode="checked"]) ::slotted([data-selected]) {
640
- background: transparent;
641
- color: inherit;
642
- outline: 1px solid transparent;
643
- }
644
-
645
- :host([interaction-mode="checked"]) ::slotted([data-selected][data-tickled]) {
646
- background: var(--item-bg-tickled);
647
- color: inherit;
648
- outline: var(--item-border-tickled);
649
- }
650
-
651
- .search-overlay {
652
- position: absolute;
653
- top: 8px;
654
- right: 8px;
655
- z-index: 10;
656
- display: flex;
657
- align-items: center;
658
- gap: 4px;
659
- background: var(--surface-4, #2a2a2a);
660
- border: 1px solid var(--border, #444);
661
- border-radius: var(--radius-m, 4px);
662
- padding: 4px 6px;
663
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
664
- }
665
-
666
- .search-overlay[hidden] {
667
- display: none;
668
- }
669
-
670
- .search-input {
671
- background: transparent;
672
- border: none;
673
- outline: none;
674
- color: inherit;
675
- font-size: var(--text-m, 0.875em);
676
- min-width: 140px;
677
- }
678
-
679
- .search-close {
680
- background: transparent;
681
- border: none;
682
- color: var(--surface-muted-text, #888);
683
- cursor: pointer;
684
- font-size: 1.1em;
685
- line-height: 1;
686
- padding: 0 2px;
687
- }
688
-
689
- .search-close:hover {
690
- color: inherit;
691
- }
692
- `];
693
- }
694
- render() {
695
- return html`
696
- <div class="container">
697
- <ul part="list">
698
- <slot></slot>
699
- </ul>
700
- <div
701
- class="search-overlay"
702
- part="search-overlay"
703
- ?hidden=${!this._searchVisible}
704
- >
705
- <input
706
- type="text"
707
- class="search-input"
708
- placeholder="Search…"
709
- .value=${this._searchQuery}
710
- @input=${this._onSearchInput}
711
- @keydown=${this._onSearchKeydown}
712
- />
713
- <button class="search-close" @click=${this._closeSearch} title="Close search (Esc)">×</button>
714
- </div>
715
- </div>
716
- `;
717
- }
718
- };
719
- __decorate([property({
720
- type: String,
721
- attribute: `selection-mode`
722
- })], VerticalListElement.prototype, "selectionMode", void 0);
723
- __decorate([property({
724
- type: String,
725
- attribute: `interaction-mode`
726
- })], VerticalListElement.prototype, "interactionMode", void 0);
727
- __decorate([property({ attribute: false })], VerticalListElement.prototype, "filterPredicate", void 0);
728
- __decorate([property({ attribute: false })], VerticalListElement.prototype, "checkboxRenderer", void 0);
729
- __decorate([state()], VerticalListElement.prototype, "_selectedItems", void 0);
730
- __decorate([state()], VerticalListElement.prototype, "_searchVisible", void 0);
731
- __decorate([state()], VerticalListElement.prototype, "_searchQuery", void 0);
732
- __decorate([query(`.search-input`)], VerticalListElement.prototype, "_searchInputEl", void 0);
733
- VerticalListElement = __decorate([safeCustomElement(`ixfx-vertical-list`)], VerticalListElement);
734
- //#endregion
1
+ import { t as VerticalListElement } from "./vertical-list-ClnqTkF3.js";
735
2
  export { VerticalListElement };
736
-
737
- //# sourceMappingURL=vertical-list.js.map