@threadlabs/looma 0.1.27 → 0.2.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 (214) hide show
  1. package/dist/{chunk-RLELJVBL.js → chunk-JXSHRMYW.js} +32 -33
  2. package/dist/{chunk-YHXJC5M5.js → chunk-M7FPK6GN.js} +17 -12
  3. package/dist/cjs/loader.cjs.js +1 -1
  4. package/dist/cjs/looma.cjs.js +1 -1
  5. package/dist/cjs/{positioning-i0WrCAdF.js → positioning-D5q9DM-0.js} +19 -12
  6. package/dist/cjs/ui-affordance-scope.cjs.entry.js +1 -1
  7. package/dist/cjs/ui-chip_2.cjs.entry.js +190 -498
  8. package/dist/cjs/ui-combobox.cjs.entry.js +708 -0
  9. package/dist/cjs/ui-context-menu.cjs.entry.js +2 -2
  10. package/dist/cjs/ui-dialog.cjs.entry.js +2 -2
  11. package/dist/cjs/ui-disclosure.cjs.entry.js +1 -1
  12. package/dist/cjs/ui-editable.cjs.entry.js +3 -3
  13. package/dist/cjs/ui-floating-action-button.cjs.entry.js +1 -1
  14. package/dist/cjs/ui-form-field.cjs.entry.js +1 -1
  15. package/dist/cjs/ui-icon-button.cjs.entry.js +1 -1
  16. package/dist/cjs/ui-input.cjs.entry.js +1 -1
  17. package/dist/cjs/ui-menu-item.cjs.entry.js +1 -1
  18. package/dist/cjs/ui-menu.cjs.entry.js +3 -3
  19. package/dist/cjs/ui-popover.cjs.entry.js +3 -3
  20. package/dist/cjs/ui-radio-group.cjs.entry.js +1 -1
  21. package/dist/cjs/ui-radio.cjs.entry.js +1 -1
  22. package/dist/cjs/ui-search-result-row.cjs.entry.js +1 -1
  23. package/dist/cjs/ui-search-shell.cjs.entry.js +1 -1
  24. package/dist/cjs/ui-select.cjs.entry.js +1 -1
  25. package/dist/cjs/ui-switch.cjs.entry.js +2 -2
  26. package/dist/cjs/ui-tabs.cjs.entry.js +1 -1
  27. package/dist/cjs/ui-textarea.cjs.entry.js +1 -1
  28. package/dist/cjs/ui-toast-region.cjs.entry.js +2 -2
  29. package/dist/cjs/ui-top-bar.cjs.entry.js +1 -1
  30. package/dist/cjs/ui-tree-item.cjs.entry.js +2 -2
  31. package/dist/cjs/ui-tree.cjs.entry.js +1 -1
  32. package/dist/collection/collection-manifest.json +0 -1
  33. package/dist/collection/components/ui-combobox/ui-combobox.css +23 -0
  34. package/dist/collection/components/ui-combobox/ui-combobox.js +298 -21
  35. package/dist/collection/components/ui-context-menu/ui-context-menu.js +1 -1
  36. package/dist/collection/components/ui-dialog/ui-dialog.css +1 -0
  37. package/dist/collection/components/ui-dialog/ui-dialog.js +1 -1
  38. package/dist/collection/components/ui-disclosure/ui-disclosure.js +1 -1
  39. package/dist/collection/components/ui-editable/ui-editable.js +3 -3
  40. package/dist/collection/components/ui-floating-action-button/ui-floating-action-button.js +1 -1
  41. package/dist/collection/components/ui-form-field/ui-form-field.js +1 -1
  42. package/dist/collection/components/ui-icon-button/ui-icon-button.js +1 -1
  43. package/dist/collection/components/ui-input/ui-input.js +1 -1
  44. package/dist/collection/components/ui-menu/ui-menu.css +7 -2
  45. package/dist/collection/components/ui-menu/ui-menu.js +1 -1
  46. package/dist/collection/components/ui-menu-item/ui-menu-item.js +1 -1
  47. package/dist/collection/components/ui-popover/ui-popover.css +6 -2
  48. package/dist/collection/components/ui-popover/ui-popover.js +1 -1
  49. package/dist/collection/components/ui-radio/ui-radio.js +1 -1
  50. package/dist/collection/components/ui-radio-group/ui-radio-group.js +1 -1
  51. package/dist/collection/components/ui-search-result-row/ui-search-result-row.js +1 -1
  52. package/dist/collection/components/ui-search-shell/ui-search-shell.js +1 -1
  53. package/dist/collection/components/ui-select/ui-select.js +1 -1
  54. package/dist/collection/components/ui-switch/ui-switch.js +2 -2
  55. package/dist/collection/components/ui-tabs/ui-tabs.js +1 -1
  56. package/dist/collection/components/ui-textarea/ui-textarea.js +1 -1
  57. package/dist/collection/components/ui-toast-region/ui-toast-region.js +1 -1
  58. package/dist/collection/components/ui-tooltip/ui-tooltip.js +1 -1
  59. package/dist/collection/components/ui-top-bar/ui-top-bar.js +1 -1
  60. package/dist/collection/components/ui-tree/ui-tree.js +1 -1
  61. package/dist/collection/components/ui-tree-item/ui-tree-item.js +2 -2
  62. package/dist/collection/overlay/positioning.js +21 -14
  63. package/dist/components/index.d.ts +0 -2
  64. package/dist/components/index.js +1 -1
  65. package/dist/components/{p-DZRtXH6j.js → p-DWN2m6ta.js} +1 -1
  66. package/dist/components/p-DYiNETk6.js +1 -0
  67. package/dist/components/p-Drw41pSY.js +1 -0
  68. package/dist/components/ui-affordance-scope.js +1 -1
  69. package/dist/components/ui-combobox.js +1 -1
  70. package/dist/components/ui-context-menu.js +1 -1
  71. package/dist/components/ui-dialog.js +1 -1
  72. package/dist/components/ui-disclosure.js +1 -1
  73. package/dist/components/ui-editable.js +1 -1
  74. package/dist/components/ui-floating-action-button.js +1 -1
  75. package/dist/components/ui-form-field.js +1 -1
  76. package/dist/components/ui-icon-button.js +1 -1
  77. package/dist/components/ui-input.js +1 -1
  78. package/dist/components/ui-menu-item.js +1 -1
  79. package/dist/components/ui-menu.js +1 -1
  80. package/dist/components/ui-popover.js +1 -1
  81. package/dist/components/ui-radio-group.js +1 -1
  82. package/dist/components/ui-radio.js +1 -1
  83. package/dist/components/ui-search-result-row.js +1 -1
  84. package/dist/components/ui-search-shell.js +1 -1
  85. package/dist/components/ui-select.js +1 -1
  86. package/dist/components/ui-switch.js +1 -1
  87. package/dist/components/ui-tabs.js +1 -1
  88. package/dist/components/ui-textarea.js +1 -1
  89. package/dist/components/ui-toast-region.js +1 -1
  90. package/dist/components/ui-tooltip.js +1 -1
  91. package/dist/components/ui-top-bar.js +1 -1
  92. package/dist/components/ui-tree-item.js +1 -1
  93. package/dist/components/ui-tree.js +1 -1
  94. package/dist/esm/loader.js +1 -1
  95. package/dist/esm/looma.js +1 -1
  96. package/dist/esm/{positioning-Bu0dmLBE.js → positioning-Drmwg-C1.js} +19 -12
  97. package/dist/esm/ui-affordance-scope.entry.js +1 -1
  98. package/dist/esm/ui-chip_2.entry.js +193 -501
  99. package/dist/esm/ui-combobox.entry.js +706 -0
  100. package/dist/esm/ui-context-menu.entry.js +2 -2
  101. package/dist/esm/ui-dialog.entry.js +2 -2
  102. package/dist/esm/ui-disclosure.entry.js +1 -1
  103. package/dist/esm/ui-editable.entry.js +3 -3
  104. package/dist/esm/ui-floating-action-button.entry.js +1 -1
  105. package/dist/esm/ui-form-field.entry.js +1 -1
  106. package/dist/esm/ui-icon-button.entry.js +1 -1
  107. package/dist/esm/ui-input.entry.js +1 -1
  108. package/dist/esm/ui-menu-item.entry.js +1 -1
  109. package/dist/esm/ui-menu.entry.js +3 -3
  110. package/dist/esm/ui-popover.entry.js +3 -3
  111. package/dist/esm/ui-radio-group.entry.js +1 -1
  112. package/dist/esm/ui-radio.entry.js +1 -1
  113. package/dist/esm/ui-search-result-row.entry.js +1 -1
  114. package/dist/esm/ui-search-shell.entry.js +1 -1
  115. package/dist/esm/ui-select.entry.js +1 -1
  116. package/dist/esm/ui-switch.entry.js +2 -2
  117. package/dist/esm/ui-tabs.entry.js +1 -1
  118. package/dist/esm/ui-textarea.entry.js +1 -1
  119. package/dist/esm/ui-toast-region.entry.js +2 -2
  120. package/dist/esm/ui-top-bar.entry.js +1 -1
  121. package/dist/esm/ui-tree-item.entry.js +2 -2
  122. package/dist/esm/ui-tree.entry.js +1 -1
  123. package/dist/index.cjs +525 -550
  124. package/dist/index.js +27 -14
  125. package/dist/looma/looma.esm.js +1 -1
  126. package/dist/looma/{p-9a82c523.entry.js → p-1249a806.entry.js} +1 -1
  127. package/dist/looma/p-1c00670f.entry.js +1 -0
  128. package/dist/looma/p-22842f8c.entry.js +1 -0
  129. package/dist/looma/{p-1e1de77f.entry.js → p-2915d5c0.entry.js} +1 -1
  130. package/dist/looma/{p-72338f53.entry.js → p-32c85198.entry.js} +1 -1
  131. package/dist/looma/{p-b75aff63.entry.js → p-37ec2b4b.entry.js} +1 -1
  132. package/dist/looma/{p-2f3c1b57.entry.js → p-3b2961a6.entry.js} +1 -1
  133. package/dist/looma/{p-e07e6ac2.entry.js → p-3f60f4c8.entry.js} +1 -1
  134. package/dist/looma/{p-9551ebf6.entry.js → p-424d6719.entry.js} +1 -1
  135. package/dist/looma/{p-6cc3180b.entry.js → p-4caccfce.entry.js} +1 -1
  136. package/dist/looma/p-55e06e2e.entry.js +1 -0
  137. package/dist/looma/{p-a939c00f.entry.js → p-56dac38a.entry.js} +1 -1
  138. package/dist/looma/p-5cbbf7a0.entry.js +1 -0
  139. package/dist/looma/{p-f431dc13.entry.js → p-6f20d470.entry.js} +1 -1
  140. package/dist/looma/{p-b68762f2.entry.js → p-7c0b5364.entry.js} +1 -1
  141. package/dist/looma/{p-e82f104c.entry.js → p-8bdd9495.entry.js} +1 -1
  142. package/dist/looma/{p-df696cca.entry.js → p-9cfbf722.entry.js} +1 -1
  143. package/dist/looma/p-Drmwg-C1.js +1 -0
  144. package/dist/looma/{p-607c3056.entry.js → p-b6ede6bb.entry.js} +1 -1
  145. package/dist/looma/p-b6fb6ba3.entry.js +1 -0
  146. package/dist/looma/{p-da6e2d01.entry.js → p-b76e2111.entry.js} +1 -1
  147. package/dist/looma/{p-1a12eb5c.entry.js → p-d372b0db.entry.js} +1 -1
  148. package/dist/looma/p-d46317e0.entry.js +1 -0
  149. package/dist/looma/{p-20387ffa.entry.js → p-d4825822.entry.js} +1 -1
  150. package/dist/looma/{p-8a5e3fe1.entry.js → p-d5c3954f.entry.js} +1 -1
  151. package/dist/looma/p-e604e906.entry.js +1 -0
  152. package/dist/looma/{p-e406656e.entry.js → p-f1f7c5cb.entry.js} +1 -1
  153. package/dist/types/components/ui-combobox/ui-combobox.d.ts +35 -4
  154. package/dist/types/components.d.ts +56 -153
  155. package/dist/{ui-affordance-scope.entry-7H6GIQEK.js → ui-affordance-scope.entry-VR7FLAWG.js} +2 -2
  156. package/dist/{ui-avatar-group.entry-QB25IUWA.js → ui-avatar-group.entry-L3UKOY3U.js} +1 -1
  157. package/dist/{ui-avatar.entry-L377CWPR.js → ui-avatar.entry-VM5OHEFQ.js} +1 -1
  158. package/dist/{ui-badge.entry-QHC3KI5S.js → ui-badge.entry-ZTM4OPUD.js} +1 -1
  159. package/dist/{ui-button.entry-MZGTPU22.js → ui-button.entry-CIPUSV5B.js} +1 -1
  160. package/dist/{ui-callout.entry-2D4LO74K.js → ui-callout.entry-OBFCI2O7.js} +1 -1
  161. package/dist/{ui-checkbox.entry-B2O5DREC.js → ui-checkbox.entry-XT6ET56H.js} +1 -1
  162. package/dist/{ui-tooltip.entry-VG4AWEBD.js → ui-chip_2.entry-32SHCLV6.js} +19 -4
  163. package/dist/{ui-chip_2.entry-OOSON72O.js → ui-combobox.entry-ONBBPQ2C.js} +170 -31
  164. package/dist/{ui-context-menu.entry-UY76G7HM.js → ui-context-menu.entry-RXNUOK24.js} +3 -3
  165. package/dist/{ui-dialog.entry-345V7IJ3.js → ui-dialog.entry-IJXNUARC.js} +3 -3
  166. package/dist/{ui-disclosure.entry-RUU7VNDN.js → ui-disclosure.entry-5QS7UDRH.js} +2 -2
  167. package/dist/{ui-editable.entry-WWFFHOMP.js → ui-editable.entry-D7LOQN2H.js} +3 -3
  168. package/dist/{ui-floating-action-button.entry-Y2TLDJO4.js → ui-floating-action-button.entry-XQZCTZQT.js} +2 -2
  169. package/dist/{ui-form-field.entry-C63GZMQR.js → ui-form-field.entry-A654LJZE.js} +2 -2
  170. package/dist/{ui-icon-button.entry-35MJYYEI.js → ui-icon-button.entry-MJ7F7ZIH.js} +2 -2
  171. package/dist/{ui-input.entry-3FAXEH5M.js → ui-input.entry-B2XM7JQU.js} +2 -2
  172. package/dist/{ui-menu-item.entry-3J42XLCJ.js → ui-menu-item.entry-JULYSFVW.js} +2 -2
  173. package/dist/{ui-menu.entry-YDABO3OO.js → ui-menu.entry-ORRWW7HD.js} +4 -4
  174. package/dist/{ui-popover.entry-YP7R6FQO.js → ui-popover.entry-W67V4UPA.js} +4 -4
  175. package/dist/{ui-radio-group.entry-TYXAN7G5.js → ui-radio-group.entry-KCFOR27M.js} +2 -2
  176. package/dist/{ui-radio.entry-JW7HX3LW.js → ui-radio.entry-I2P4V5E3.js} +2 -2
  177. package/dist/{ui-search-result-row.entry-MKQYGNFO.js → ui-search-result-row.entry-GHODLSLR.js} +2 -2
  178. package/dist/{ui-search-shell.entry-KHIQTT4J.js → ui-search-shell.entry-PDB5UN4B.js} +2 -2
  179. package/dist/{ui-select.entry-R235Y3IL.js → ui-select.entry-D3CZHCKB.js} +2 -2
  180. package/dist/{ui-switch.entry-BJ6FIEPB.js → ui-switch.entry-WUDRL4H5.js} +3 -3
  181. package/dist/{ui-tabs.entry-ZBP3FLR2.js → ui-tabs.entry-MW64GKIJ.js} +2 -2
  182. package/dist/{ui-textarea.entry-2YW7TCEU.js → ui-textarea.entry-VHRBYY6G.js} +2 -2
  183. package/dist/{ui-toast-region.entry-ZSCMMIKQ.js → ui-toast-region.entry-ET75RWYP.js} +3 -3
  184. package/dist/{ui-top-bar.entry-CZW3MLC6.js → ui-top-bar.entry-QIYA3LD3.js} +2 -2
  185. package/dist/{ui-tree-item.entry-CU2SWAOK.js → ui-tree-item.entry-BDB7VEUS.js} +3 -3
  186. package/dist/{ui-tree.entry-M6KXK7GJ.js → ui-tree.entry-GSC7BPRN.js} +2 -2
  187. package/package.json +1 -1
  188. package/styles.css +6 -4
  189. package/vue/{chunk-2DDIBSFD.js → chunk-ROMBQS2L.js} +32 -89
  190. package/vue/editor/index.js +1 -1
  191. package/vue/index.d.ts +30 -107
  192. package/vue/index.js +1 -3
  193. package/dist/cjs/ui-multi-combobox.cjs.entry.js +0 -190
  194. package/dist/cjs/ui-tooltip.cjs.entry.js +0 -241
  195. package/dist/collection/components/ui-multi-combobox/ui-multi-combobox.css +0 -33
  196. package/dist/collection/components/ui-multi-combobox/ui-multi-combobox.js +0 -553
  197. package/dist/components/p-BKzrrab4.js +0 -1
  198. package/dist/components/p-D0wBI-9r.js +0 -1
  199. package/dist/components/p-DOulVJT7.js +0 -1
  200. package/dist/components/ui-multi-combobox.d.ts +0 -11
  201. package/dist/components/ui-multi-combobox.js +0 -1
  202. package/dist/esm/ui-multi-combobox.entry.js +0 -188
  203. package/dist/esm/ui-tooltip.entry.js +0 -239
  204. package/dist/looma/p-071c139c.entry.js +0 -1
  205. package/dist/looma/p-0fd60103.entry.js +0 -1
  206. package/dist/looma/p-4fc9917f.entry.js +0 -1
  207. package/dist/looma/p-66c6b6dd.entry.js +0 -1
  208. package/dist/looma/p-77dcfa6f.entry.js +0 -1
  209. package/dist/looma/p-85a6716e.entry.js +0 -1
  210. package/dist/looma/p-8f102407.entry.js +0 -1
  211. package/dist/looma/p-Bu0dmLBE.js +0 -1
  212. package/dist/looma/p-caa37be2.entry.js +0 -1
  213. package/dist/types/components/ui-multi-combobox/ui-multi-combobox.d.ts +0 -51
  214. package/dist/ui-multi-combobox.entry-XXLS4V3I.js +0 -196
@@ -2,16 +2,27 @@ import { Host, h } from "@stencil/core";
2
2
  import { createAnchoredSurface } from "../../overlay/positioning";
3
3
  import { openOverlay, closeOverlay } from "../../overlay/manager";
4
4
  import { formatEditingValue, validateField } from "../../field/validation";
5
- /** A single editable field with contextual suggestions, optional help and field validation. */
5
+ /**
6
+ * A single editable field with contextual suggestions, optional help and field validation.
7
+ * With `multiple`, it becomes a multi-value tag field: `value` holds the selected
8
+ * items, chips render before the cursor, and add/remove/create item events fire.
9
+ */
6
10
  export class UICombobox {
7
11
  host;
8
12
  /** Accessible visible label, associated with the native text input. */
9
13
  label = '';
10
14
  placeholder = '';
11
15
  name = '';
12
- /** Controlled canonical value. Undefined selects uncontrolled mode; null means no selection. */
16
+ /**
17
+ * Controlled canonical value. Undefined selects uncontrolled mode; null means no selection.
18
+ * With `multiple`, this is the controlled list of selected items instead.
19
+ */
13
20
  value;
14
21
  defaultValue;
22
+ /** Render selected values as removable chips before the cursor. `value` becomes the item list. */
23
+ multiple = false;
24
+ /** Characters that commit the current query and leave the input ready for the next item (multiple only). */
25
+ tokenSeparators = [];
15
26
  /** Controlled raw editing text; independent of canonical selection. */
16
27
  query;
17
28
  defaultQuery = '';
@@ -28,6 +39,7 @@ export class UICombobox {
28
39
  /** Optional description shown by the connected question-mark button. */
29
40
  help = '';
30
41
  queryChange;
42
+ /** Single mode: the ComboboxChange. Multiple mode: the full current item list on any change. */
31
43
  valueChange;
32
44
  freeEntry;
33
45
  createEntry;
@@ -35,6 +47,12 @@ export class UICombobox {
35
47
  validationChange;
36
48
  /** Supplies the current result rows for framework-owned rich slots. */
37
49
  optionsChange;
50
+ /** Multiple mode: a suggestion or exact-match token was committed as a new item. */
51
+ addItem;
52
+ /** Multiple mode: a selected item was removed via chip keyboard controls. */
53
+ removeItem;
54
+ /** Multiple mode: an unmatched query was submitted for creation. */
55
+ createItem;
38
56
  raw = '';
39
57
  display = '';
40
58
  selected = null;
@@ -62,8 +80,21 @@ export class UICombobox {
62
80
  proposedChange;
63
81
  formattedRaw;
64
82
  formattedWith;
83
+ /** Multiple mode: the controlled selected items (from `value`). Empty otherwise. */
84
+ get items() {
85
+ return this.multiple && Array.isArray(this.value) ? this.value : [];
86
+ }
87
+ get selectedValues() { return new Set(this.items.map(item => item.value)); }
65
88
  componentWillLoad() {
66
- this.selected = this.value !== undefined ? this.value : this.defaultValue ?? null;
89
+ if (this.multiple) {
90
+ this.selected = null;
91
+ this.raw = this.query ?? this.defaultQuery;
92
+ this.display = this.raw;
93
+ this.initialRaw = this.raw;
94
+ this.applyServerIssues();
95
+ return;
96
+ }
97
+ this.selected = (this.value !== undefined ? this.value : this.defaultValue ?? null);
67
98
  this.raw = this.query ?? this.defaultQuery;
68
99
  if (this.query === undefined && !this.raw && this.selected !== null) {
69
100
  this.raw = this.config.options?.find(row => row.value === this.selected)?.label ?? this.selected;
@@ -94,7 +125,8 @@ export class UICombobox {
94
125
  this.surface = createAnchoredSurface(this.popup, { anchor: this.field, placement: 'bottom-start' });
95
126
  }
96
127
  syncValue() {
97
- if (this.value === undefined)
128
+ // Multiple mode: `value` is the item list; Stencil re-renders chips on reference change.
129
+ if (this.multiple || this.value === undefined)
98
130
  return;
99
131
  this.selected = this.value;
100
132
  if (this.query === undefined) {
@@ -139,9 +171,15 @@ export class UICombobox {
139
171
  if (next.context !== previous?.context) {
140
172
  this.close();
141
173
  const policy = next.invalidation ?? 'retain-query';
142
- const value = policy === 'retain' ? this.selected : null;
143
- const query = policy === 'clear' ? '' : this.raw;
144
- this.commit(value, query, null, 'invalidation', 'programmatic');
174
+ if (this.multiple) {
175
+ if (policy === 'clear')
176
+ this.setMultiQuery('', 'programmatic');
177
+ }
178
+ else {
179
+ const value = policy === 'retain' ? this.selected : null;
180
+ const query = policy === 'clear' ? '' : this.raw;
181
+ this.commit(value, query, null, 'invalidation', 'programmatic');
182
+ }
145
183
  this.validation = { status: 'pristine', touched: false, dirty: this.raw !== this.initialRaw, issues: [] };
146
184
  }
147
185
  this.applyServerIssues();
@@ -207,12 +245,21 @@ export class UICombobox {
207
245
  this.resetValidation();
208
246
  }
209
247
  const ids = new Set();
248
+ const selected = this.multiple ? this.selectedValues : undefined;
210
249
  this.rows = options.filter(option => {
211
250
  if (ids.has(option.id))
212
251
  return false;
213
252
  ids.add(option.id);
214
- return this.fullSet || (config.filter ? config.filter(option, query, config.context)
215
- : config.provider ? true : option.label.toLocaleLowerCase().includes(query.toLocaleLowerCase()));
253
+ if (this.fullSet)
254
+ return true;
255
+ // Multiple mode always hides already-selected items and, absent an owner
256
+ // filter, falls back to a client label match (there is no unfiltered pass-through).
257
+ if (selected)
258
+ return !selected.has(option.value)
259
+ && (config.filter ? config.filter(option, query, config.context)
260
+ : option.label.toLocaleLowerCase().includes(query.toLocaleLowerCase()));
261
+ return config.filter ? config.filter(option, query, config.context)
262
+ : config.provider ? true : option.label.toLocaleLowerCase().includes(query.toLocaleLowerCase());
216
263
  });
217
264
  const groups = new Map();
218
265
  for (const row of this.rows) {
@@ -332,6 +379,18 @@ export class UICombobox {
332
379
  const option = this.rows[index];
333
380
  if (option?.disabled)
334
381
  return;
382
+ if (this.multiple) {
383
+ if (option)
384
+ this.addSelectedItem(option, trigger);
385
+ else if (this.canCreate && index === this.rows.length)
386
+ this.createSelectedItem(this.raw.trim(), trigger);
387
+ else
388
+ return;
389
+ this.setMultiQuery('', trigger);
390
+ this.close();
391
+ this.input?.focus();
392
+ return;
393
+ }
335
394
  if (option)
336
395
  this.commit(option.value, option.label, option, 'selection', trigger);
337
396
  else if (this.canCreate && index === this.rows.length)
@@ -343,6 +402,105 @@ export class UICombobox {
343
402
  if (this.config.validateOn !== 'submit')
344
403
  queueMicrotask(() => void this.validate());
345
404
  }
405
+ // --- Multiple-mode helpers ---------------------------------------------
406
+ emitItems(items) { this.valueChange.emit(items); }
407
+ setMultiQuery(query, trigger) {
408
+ if (this.query === undefined) {
409
+ this.raw = query;
410
+ this.display = query;
411
+ this.formattedRaw = undefined;
412
+ }
413
+ if (this.input)
414
+ this.input.value = query;
415
+ this.queryChange.emit({ query, display: query, trigger });
416
+ }
417
+ addSelectedItem(option, trigger) {
418
+ this.addItem.emit({ item: option, index: this.items.length, trigger });
419
+ this.emitItems([...this.items, option]);
420
+ }
421
+ createSelectedItem(query, trigger) {
422
+ if (!query)
423
+ return;
424
+ this.createItem.emit({ query, trigger });
425
+ }
426
+ commitQuery(trigger) {
427
+ const query = this.raw.trim();
428
+ if (!query)
429
+ return;
430
+ const normalized = query.toLocaleLowerCase();
431
+ const option = this.rows.find(row => row.label.trim().toLocaleLowerCase() === normalized);
432
+ if (option) {
433
+ this.setMultiQuery('', trigger);
434
+ this.addSelectedItem(option, trigger);
435
+ }
436
+ else if (this.config.allowCreate) {
437
+ this.setMultiQuery('', trigger);
438
+ this.createSelectedItem(query, trigger);
439
+ }
440
+ }
441
+ removeItemAt(index, trigger) {
442
+ const item = this.items[index];
443
+ if (!item || item.disabled || this.disabled || this.readOnly)
444
+ return;
445
+ this.removeItem.emit({ item, index, trigger });
446
+ this.emitItems(this.items.filter((_, position) => position !== index));
447
+ requestAnimationFrame(() => {
448
+ const buttons = this.host.shadowRoot?.querySelectorAll('[part="item"]') ?? [];
449
+ const next = buttons[Math.min(index, buttons.length - 1)] ?? buttons[index - 1];
450
+ if (next && next.dataset.value !== item.value)
451
+ next.focus();
452
+ else
453
+ void this.focusInput();
454
+ });
455
+ }
456
+ focusItem(index) {
457
+ this.host.shadowRoot?.querySelectorAll('[part="item"]')[index]?.focus();
458
+ }
459
+ onItemKeyDown = (event, index) => {
460
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
461
+ return;
462
+ if (event.key === 'ArrowLeft') {
463
+ event.preventDefault();
464
+ event.stopPropagation();
465
+ this.focusItem(Math.max(0, index - 1));
466
+ }
467
+ else if (event.key === 'ArrowRight') {
468
+ event.preventDefault();
469
+ event.stopPropagation();
470
+ if (index === this.items.length - 1)
471
+ void this.focusInput();
472
+ else
473
+ this.focusItem(index + 1);
474
+ }
475
+ else if (event.key === 'Backspace' || event.key === 'Delete') {
476
+ event.preventDefault();
477
+ event.stopPropagation();
478
+ this.removeItemAt(index, 'keyboard');
479
+ }
480
+ };
481
+ handleMultipleKeydown(event) {
482
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
483
+ return false;
484
+ if (this.tokenSeparators.includes(event.key)) {
485
+ event.preventDefault();
486
+ event.stopPropagation();
487
+ this.commitQuery('keyboard');
488
+ return true;
489
+ }
490
+ if (this.raw || (this.input?.selectionStart ?? 0) > 0)
491
+ return false;
492
+ if (event.key === 'ArrowLeft' && this.items.length) {
493
+ event.preventDefault();
494
+ this.focusItem(this.items.length - 1);
495
+ return true;
496
+ }
497
+ if (event.key === 'Backspace' && this.items.length) {
498
+ event.preventDefault();
499
+ this.removeItemAt(this.items.length - 1, 'keyboard');
500
+ return true;
501
+ }
502
+ return false;
503
+ }
346
504
  move(key) {
347
505
  const indices = this.rows.flatMap((row, index) => row.disabled ? [] : [index]);
348
506
  if (this.canCreate)
@@ -359,6 +517,8 @@ export class UICombobox {
359
517
  onKeydown = (event) => {
360
518
  if (this.composing || event.isComposing || this.disabled || this.readOnly)
361
519
  return;
520
+ if (this.multiple && this.handleMultipleKeydown(event))
521
+ return;
362
522
  if (event.key === 'Escape' && this.expanded) {
363
523
  event.preventDefault();
364
524
  event.stopPropagation();
@@ -399,7 +559,7 @@ export class UICombobox {
399
559
  this.close();
400
560
  this.format('blur');
401
561
  this.validation = { ...this.validation, touched: true };
402
- if (this.config.allowFreeText && this.selected === null)
562
+ if (!this.multiple && this.config.allowFreeText && this.selected === null)
403
563
  this.commit(null, this.raw, null, 'free-entry', 'keyboard');
404
564
  if ((this.config.validateOn ?? 'blur') === 'blur')
405
565
  void this.validate();
@@ -437,18 +597,18 @@ export class UICombobox {
437
597
  const description = [this.helpOpen ? 'help-text' : '', this.validation.issues.length ? 'validation' : ''].filter(Boolean).join(' ') || undefined;
438
598
  const status = this.loading ? 'Loading suggestions…' : this.lookupError || (this.expanded ? `${this.rows.length} suggestions available.` : '');
439
599
  const groups = [...new Set(this.rows.map(row => row.group ?? ''))];
440
- return h(Host, { key: '1f00d9a83729d9c2147ced7e5006b928d1b5e51d', "data-size": this.size, "data-validation": this.validation.status, onFocusout: this.onFocusOut }, h("label", { key: '10353b147cc68ef1d67be0988849af1527fcf9ba', htmlFor: "input", part: "label", class: this.labelVisibility === 'sr-only' ? 'sr-only' : undefined }, this.label, this.required ? ' *' : ''), h("div", { key: '74bb53137d9343add37c22f3ac503eccf41807a9', class: "field", part: "field", ref: element => this.field = element, onClick: event => {
600
+ return h(Host, { key: 'fc4c0192d3be88d8c0199ae1bcca44232bd22351', "data-size": this.size, "data-validation": this.validation.status, onFocusout: this.onFocusOut }, h("label", { key: 'bdd0d244c6ef448978fa77aac3a2d3b71d713553', htmlFor: "input", part: "label", class: this.labelVisibility === 'sr-only' ? 'sr-only' : undefined }, this.label, this.required ? ' *' : ''), h("div", { key: 'afb3972aab52171a3b25ede863c31059e56f5d91', class: "field", part: "field", ref: element => this.field = element, onClick: event => {
441
601
  if (!event.composedPath().some(node => node instanceof HTMLButtonElement))
442
602
  this.input?.focus();
443
- } }, h("slot", { key: '24c26916365013faa4a78bd4fe0d01f6c129c703', name: "start" }), h("input", { key: '835d19e66ec4a24c1a83f43bbc256fa2a9e3332f', id: "input", ref: element => this.input = element, role: "combobox", "aria-autocomplete": "list", "aria-expanded": String(this.expanded), "aria-controls": "listbox", "aria-activedescendant": this.expanded && this.active >= 0 ? `option-${this.active}` : undefined, "aria-describedby": description, "aria-invalid": String(this.validation.status === 'error'), "aria-busy": String(this.validation.status === 'pending'), value: this.display, placeholder: this.placeholder, name: this.name || undefined, disabled: this.disabled, readOnly: this.readOnly, required: this.required, autoComplete: "off", part: "input", onInput: this.onInput, onKeyDown: this.onKeydown, onCompositionstart: () => this.composing = true, onCompositionend: () => { this.composing = false; this.onInput(new InputEvent('input')); } }), this.clearable && h("button", { key: '326c1e24d3c417c3a72acd8234a53937b388ba79', type: "button", part: "affordance", "aria-label": `Clear ${this.label}`, disabled: this.disabled || this.readOnly, onClick: () => { this.commit(null, '', null, 'clear', 'pointer'); this.close(); this.input?.focus(); } }, "\u00D7"), this.help && h("button", { key: '6aeb62dc2935eb95670caa1d2028c0931dc362b2', id: "help", type: "button", part: "affordance", "aria-label": `Help for ${this.label}`, disabled: this.disabled }, h("span", { key: '9317be0fbb0c1bbb91061be69f38037a97a4c36b', "aria-hidden": "true" }, "?")), this.disclosure && h("button", { key: '1cd2a0ea92df1144ff2297fcf64df7b3d0f4713a', type: "button", part: "affordance", "aria-label": `Suggestions for ${this.label}`, "aria-controls": "listbox", "aria-expanded": String(this.expanded), disabled: this.disabled || this.readOnly, onClick: () => {
603
+ } }, h("slot", { key: '65e4e201d6c11cd2638e392e1298662de7ba4d57', name: "start" }), this.multiple && h("div", { key: 'b80b5b85fa0540139b9756fcc494aef9df245c15', class: "items", role: "group", "aria-label": `Selected ${this.label}` }, this.items.map((item, index) => h("button", { type: "button", part: "item", class: "item", "data-value": item.value, tabIndex: -1, disabled: this.disabled || this.readOnly || item.disabled, "aria-label": `${item.label}, press Delete or Backspace to remove`, onKeyDown: event => this.onItemKeyDown(event, index) }, h("slot", { name: `item-${item.id}` }, h("ui-chip", { appearance: "pill" }, item.label))))), h("input", { key: '64f76055ae412cc87119270eec10c69000a72563', id: "input", ref: element => this.input = element, role: "combobox", "aria-autocomplete": "list", "aria-expanded": String(this.expanded), "aria-controls": "listbox", "aria-activedescendant": this.expanded && this.active >= 0 ? `option-${this.active}` : undefined, "aria-describedby": description, "aria-invalid": String(this.validation.status === 'error'), "aria-busy": String(this.validation.status === 'pending'), value: this.display, placeholder: this.placeholder, name: this.name || undefined, disabled: this.disabled, readOnly: this.readOnly, required: this.required, autoComplete: "off", part: "input", onInput: this.onInput, onKeyDown: this.onKeydown, onCompositionstart: () => this.composing = true, onCompositionend: () => { this.composing = false; this.onInput(new InputEvent('input')); } }), this.clearable && h("button", { key: 'eac4c18dadcea92065af4ecd871d925ef1248d47', type: "button", part: "affordance", "aria-label": `Clear ${this.label}`, disabled: this.disabled || this.readOnly, onClick: () => { this.commit(null, '', null, 'clear', 'pointer'); this.close(); this.input?.focus(); } }, "\u00D7"), this.help && h("button", { key: '9a559d49a495ead3dbf159f170c594e0aaa0d0d0', id: "help", type: "button", part: "affordance", "aria-label": `Help for ${this.label}`, disabled: this.disabled }, h("span", { key: '73940e568b976f85399d5baa5e247a4a606d0039', "aria-hidden": "true" }, "?")), this.disclosure && h("button", { key: '30dd6746ffb121888a4c4fb6df54720906badf78', type: "button", part: "affordance", "aria-label": `Suggestions for ${this.label}`, "aria-controls": "listbox", "aria-expanded": String(this.expanded), disabled: this.disabled || this.readOnly, onClick: () => {
444
604
  if (this.expanded)
445
605
  this.close();
446
606
  else
447
607
  this.open('disclosure');
448
608
  this.input?.focus();
449
- } }, h("span", { key: '0188b2d0e8cc7b7ff4d1a2175a0ff0b47d9c7d98', "aria-hidden": "true" }, "\u2304"))), this.help && h("ui-tooltip", { key: 'e09fd35274c3e1fa6e408850d72f7a07c2bb4baf', id: "help-text", for: "help", toggleOnClick: true, onOpen: () => this.helpOpen = true, onClose: () => this.helpOpen = false }, this.help), h("div", { key: 'ddf83a5944dd03fc7eb580b81fcf291e06c03601', class: "popup", part: "popup", hidden: !this.expanded, ref: element => this.popup = element }, h("div", { key: '1d73de1dabb6eaa95af12f2af88dac74e3f163ea', id: "listbox", role: "listbox", "aria-label": `${this.label} suggestions`, "aria-busy": String(this.loading) }, groups.map(group => h("div", { role: group ? 'group' : 'presentation', "aria-label": group || undefined }, group && h("div", { class: "group", part: "group" }, group), this.rows.map((row, index) => (row.group ?? '') !== group ? null : h("div", { id: `option-${index}`, role: "option", "aria-selected": String(this.selected === row.value), "aria-disabled": String(Boolean(row.disabled)), "data-active": this.active === index ? '' : undefined, part: "option", class: "option", onPointerDown: event => event.preventDefault(), onClick: () => this.choose(index, 'pointer') }, h("slot", { name: `option-${row.id}` }, h("span", { class: "primary", part: "option-primary" }, row.label), row.description && h("span", { class: "secondary", part: "option-secondary" }, row.description)))))), this.canCreate && h("div", { key: 'a0aaafa2f4ff79efa954ed780f3a7bd81d4b2ecd', id: `option-${this.rows.length}`, role: "option", "aria-selected": "false", class: "option", part: "option", "data-active": this.active === this.rows.length ? '' : undefined, onPointerDown: event => event.preventDefault(), onClick: () => this.choose(this.rows.length, 'pointer') }, h("slot", { key: '53a6706fc2c26097948b08cf0a7ee6040e37fe57', name: "create" }, "Create \u201C", this.raw, "\u201D"))), this.loading ? h("div", { class: "message" }, h("slot", { name: "loading" }, "Loading suggestions\u2026"))
609
+ } }, h("span", { key: '7d3b10a765ee0a6c40d7b0b49e98c676a5837944', "aria-hidden": "true" }, "\u2304"))), this.help && h("ui-tooltip", { key: 'efff00f45dc281b727789eb2aa84ff772bb5c925', id: "help-text", for: "help", toggleOnClick: true, onOpen: () => this.helpOpen = true, onClose: () => this.helpOpen = false }, this.help), h("div", { key: '770bc12b873026b571bd3ae2a80416e8af52b8d4', class: "popup", part: "popup", hidden: !this.expanded, ref: element => this.popup = element }, h("div", { key: 'ed48c8dd8b672a577d567ca5e795b8a53fde2761', id: "listbox", role: "listbox", "aria-label": `${this.label} suggestions`, "aria-busy": String(this.loading) }, groups.map(group => h("div", { role: group ? 'group' : 'presentation', "aria-label": group || undefined }, group && h("div", { class: "group", part: "group" }, group), this.rows.map((row, index) => (row.group ?? '') !== group ? null : h("div", { id: `option-${index}`, role: "option", "aria-selected": String(this.selected === row.value), "aria-disabled": String(Boolean(row.disabled)), "data-active": this.active === index ? '' : undefined, part: "option", class: "option", onPointerDown: event => event.preventDefault(), onClick: () => this.choose(index, 'pointer') }, h("slot", { name: `option-${row.id}` }, h("span", { class: "primary", part: "option-primary" }, row.label), row.description && h("span", { class: "secondary", part: "option-secondary" }, row.description)))))), this.canCreate && h("div", { key: '43215f449bbccde407ef818cee473f69870f6f8c', id: `option-${this.rows.length}`, role: "option", "aria-selected": "false", class: "option", part: "option", "data-active": this.active === this.rows.length ? '' : undefined, onPointerDown: event => event.preventDefault(), onClick: () => this.choose(this.rows.length, 'pointer') }, h("slot", { key: '3ff70ff3ab8e24afc369a26e8474e7d1220ed6eb', name: "create" }, "Create \u201C", this.raw, "\u201D"))), this.loading ? h("div", { class: "message" }, h("slot", { name: "loading" }, "Loading suggestions\u2026"))
450
610
  : this.lookupError ? h("div", { class: "message" }, h("slot", { name: "error" }, this.lookupError))
451
- : !this.rows.length && !this.canCreate ? h("div", { class: "message" }, h("slot", { name: "empty" }, "No suggestions.")) : null, h("slot", { key: '7997a0233a3c1a560b820c846645405ec4ceec1d', name: "footer" })), h("div", { key: '9143eb79141f5f3660a63f7a2471d1eecd8e9332', id: "validation", class: "message", part: "validation", hidden: !this.validation.issues.length }, this.validation.issues.map(issue => h("div", null, issue.message))), h("div", { key: '21f310613b058f528f8c4df329864fd8a2a94b55', class: "sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true" }, status, " ", this.validation.status === 'pending' ? 'Checking value…' : this.validation.issues.map(issue => issue.message).join(' ')));
611
+ : !this.rows.length && !this.canCreate ? h("div", { class: "message" }, h("slot", { name: "empty" }, "No suggestions.")) : null, h("slot", { key: '8b1fbd4f5c372393d294d8c218ae1785e6b0334f', name: "footer" })), h("div", { key: '18e68687f04e35535edee363683523ce6bbb0291', id: "validation", class: "message", part: "validation", hidden: !this.validation.issues.length }, this.validation.issues.map(issue => h("div", null, issue.message))), h("div", { key: 'e4a7db06abcfaf08b8ac592107531a13ef3a5897', class: "sr-only", role: "status", "aria-live": "polite", "aria-atomic": "true" }, status, " ", this.validation.status === 'pending' ? 'Checking value…' : this.validation.issues.map(issue => issue.message).join(' ')));
452
612
  }
453
613
  static get is() { return "ui-combobox"; }
454
614
  static get encapsulation() { return "shadow"; }
@@ -528,15 +688,22 @@ export class UICombobox {
528
688
  "type": "string",
529
689
  "mutable": false,
530
690
  "complexType": {
531
- "original": "string | null",
532
- "resolved": "string",
533
- "references": {}
691
+ "original": "string | null | readonly MultiComboboxItem[]",
692
+ "resolved": "readonly MultiComboboxItem[] | string",
693
+ "references": {
694
+ "MultiComboboxItem": {
695
+ "location": "import",
696
+ "path": "../../field/multi-combobox",
697
+ "id": "src/field/multi-combobox.ts::MultiComboboxItem",
698
+ "referenceLocation": "MultiComboboxItem"
699
+ }
700
+ }
534
701
  },
535
702
  "required": false,
536
703
  "optional": true,
537
704
  "docs": {
538
705
  "tags": [],
539
- "text": "Controlled canonical value. Undefined selects uncontrolled mode; null means no selection."
706
+ "text": "Controlled canonical value. Undefined selects uncontrolled mode; null means no selection.\nWith `multiple`, this is the controlled list of selected items instead."
540
707
  },
541
708
  "getter": false,
542
709
  "setter": false,
@@ -562,6 +729,44 @@ export class UICombobox {
562
729
  "reflect": false,
563
730
  "attribute": "default-value"
564
731
  },
732
+ "multiple": {
733
+ "type": "boolean",
734
+ "mutable": false,
735
+ "complexType": {
736
+ "original": "boolean",
737
+ "resolved": "boolean",
738
+ "references": {}
739
+ },
740
+ "required": false,
741
+ "optional": false,
742
+ "docs": {
743
+ "tags": [],
744
+ "text": "Render selected values as removable chips before the cursor. `value` becomes the item list."
745
+ },
746
+ "getter": false,
747
+ "setter": false,
748
+ "reflect": true,
749
+ "attribute": "multiple",
750
+ "defaultValue": "false"
751
+ },
752
+ "tokenSeparators": {
753
+ "type": "unknown",
754
+ "mutable": false,
755
+ "complexType": {
756
+ "original": "readonly string[]",
757
+ "resolved": "readonly string[]",
758
+ "references": {}
759
+ },
760
+ "required": false,
761
+ "optional": false,
762
+ "docs": {
763
+ "tags": [],
764
+ "text": "Characters that commit the current query and leave the input ready for the next item (multiple only)."
765
+ },
766
+ "getter": false,
767
+ "setter": false,
768
+ "defaultValue": "[]"
769
+ },
565
770
  "query": {
566
771
  "type": "string",
567
772
  "mutable": false,
@@ -826,17 +1031,23 @@ export class UICombobox {
826
1031
  "composed": true,
827
1032
  "docs": {
828
1033
  "tags": [],
829
- "text": ""
1034
+ "text": "Single mode: the ComboboxChange. Multiple mode: the full current item list on any change."
830
1035
  },
831
1036
  "complexType": {
832
- "original": "ComboboxChange",
833
- "resolved": "ComboboxChange",
1037
+ "original": "ComboboxChange | readonly MultiComboboxItem[]",
1038
+ "resolved": "ComboboxChange | readonly MultiComboboxItem[]",
834
1039
  "references": {
835
1040
  "ComboboxChange": {
836
1041
  "location": "import",
837
1042
  "path": "../../field/combobox",
838
1043
  "id": "src/field/combobox.ts::ComboboxChange",
839
1044
  "referenceLocation": "ComboboxChange"
1045
+ },
1046
+ "MultiComboboxItem": {
1047
+ "location": "import",
1048
+ "path": "../../field/multi-combobox",
1049
+ "id": "src/field/multi-combobox.ts::MultiComboboxItem",
1050
+ "referenceLocation": "MultiComboboxItem"
840
1051
  }
841
1052
  }
842
1053
  }
@@ -950,6 +1161,72 @@ export class UICombobox {
950
1161
  }
951
1162
  }
952
1163
  }
1164
+ }, {
1165
+ "method": "addItem",
1166
+ "name": "add-item",
1167
+ "bubbles": true,
1168
+ "cancelable": true,
1169
+ "composed": true,
1170
+ "docs": {
1171
+ "tags": [],
1172
+ "text": "Multiple mode: a suggestion or exact-match token was committed as a new item."
1173
+ },
1174
+ "complexType": {
1175
+ "original": "MultiComboboxItemChange",
1176
+ "resolved": "MultiComboboxItemChange",
1177
+ "references": {
1178
+ "MultiComboboxItemChange": {
1179
+ "location": "import",
1180
+ "path": "../../field/multi-combobox",
1181
+ "id": "src/field/multi-combobox.ts::MultiComboboxItemChange",
1182
+ "referenceLocation": "MultiComboboxItemChange"
1183
+ }
1184
+ }
1185
+ }
1186
+ }, {
1187
+ "method": "removeItem",
1188
+ "name": "remove-item",
1189
+ "bubbles": true,
1190
+ "cancelable": true,
1191
+ "composed": true,
1192
+ "docs": {
1193
+ "tags": [],
1194
+ "text": "Multiple mode: a selected item was removed via chip keyboard controls."
1195
+ },
1196
+ "complexType": {
1197
+ "original": "MultiComboboxItemChange",
1198
+ "resolved": "MultiComboboxItemChange",
1199
+ "references": {
1200
+ "MultiComboboxItemChange": {
1201
+ "location": "import",
1202
+ "path": "../../field/multi-combobox",
1203
+ "id": "src/field/multi-combobox.ts::MultiComboboxItemChange",
1204
+ "referenceLocation": "MultiComboboxItemChange"
1205
+ }
1206
+ }
1207
+ }
1208
+ }, {
1209
+ "method": "createItem",
1210
+ "name": "create-item",
1211
+ "bubbles": true,
1212
+ "cancelable": true,
1213
+ "composed": true,
1214
+ "docs": {
1215
+ "tags": [],
1216
+ "text": "Multiple mode: an unmatched query was submitted for creation."
1217
+ },
1218
+ "complexType": {
1219
+ "original": "MultiComboboxCreate",
1220
+ "resolved": "MultiComboboxCreate",
1221
+ "references": {
1222
+ "MultiComboboxCreate": {
1223
+ "location": "import",
1224
+ "path": "../../field/multi-combobox",
1225
+ "id": "src/field/multi-combobox.ts::MultiComboboxCreate",
1226
+ "referenceLocation": "MultiComboboxCreate"
1227
+ }
1228
+ }
1229
+ }
953
1230
  }];
954
1231
  }
955
1232
  static get methods() {
@@ -212,7 +212,7 @@ export class UIContextMenu {
212
212
  this.closeMenu('action', 'pointer');
213
213
  };
214
214
  render() {
215
- return (h(Host, { key: '292937da8010dc741e3e845b6f7fd0fef6b8bda3', "data-open": this.internalOpen ? '' : undefined, "data-focus-trigger": this.internalOpen ? this.focusTrigger : undefined, onKeyDown: this.onKeydown, onClick: this.onItemClick }, h("slot", { key: '4f08876237d1919803200226d956e67de35fffab', name: "trigger" }), h("div", { key: 'c2cc0218165d02cc4c7fd11bdc52a51d39897546', class: "menu", "data-open": this.internalOpen ? '' : undefined }, h("ui-menu", { key: '1c2c6e62c86f3a38f014976843f3354d312d0744', open: this.internalOpen }, h("slot", { key: 'baeca960ac6d2277a60dc567f6e4110904d67b5e' })))));
215
+ return (h(Host, { key: 'aaf9f27402b0c88cede3847ee9c8f61ac844f889', "data-open": this.internalOpen ? '' : undefined, "data-focus-trigger": this.internalOpen ? this.focusTrigger : undefined, onKeyDown: this.onKeydown, onClick: this.onItemClick }, h("slot", { key: 'd801d564ec2ee073e517cb991c26efc61d3e499d', name: "trigger" }), h("div", { key: '4febcc5d76c79c2e5361db7b203e971582197fd2', class: "menu", "data-open": this.internalOpen ? '' : undefined }, h("ui-menu", { key: '7aace2479a8014a20da35f69bd3ed57b402f9ef2', open: this.internalOpen }, h("slot", { key: 'a31d703c437cf5d9ab82e5f7793caa093a312dfd' })))));
216
216
  }
217
217
  static get is() { return "ui-context-menu"; }
218
218
  static get encapsulation() { return "shadow"; }
@@ -11,6 +11,7 @@
11
11
  --ui-dialog-viewport-gap: var(--ui-space-4, 1rem);
12
12
  position: fixed;
13
13
  inset: 0;
14
+ box-sizing: border-box;
14
15
  inline-size: min(
15
16
  calc(100% - (var(--ui-dialog-viewport-gap) * 2)),
16
17
  var(--ui-dialog-max-width, 440px)
@@ -104,7 +104,7 @@ export class UIDialog {
104
104
  this.accessibleLabel = nextLabel;
105
105
  };
106
106
  render() {
107
- return (h(Host, { key: 'f5b4441f54505e40851dd239d12cf8ed09daabfe', "data-open": this.internalOpen ? '' : undefined, onKeyDown: this.onKeydown }, h("dialog", { key: '6896de6166cc085d9bd581dc053705fbce6328d8', ref: (el) => (this.dialogRef = el), open: this.internalOpen, "aria-label": this.accessibleLabel }, h("slot", { key: '07515a7b8da25ccbd18bcde226129a569c999af7' }))));
107
+ return (h(Host, { key: 'b606ef8c95728b5538047a7134030455fedf69e4', "data-open": this.internalOpen ? '' : undefined, onKeyDown: this.onKeydown }, h("dialog", { key: '85531d82c36e79230cbb22c105ff3821f1f35f58', ref: (el) => (this.dialogRef = el), open: this.internalOpen, "aria-label": this.accessibleLabel }, h("slot", { key: '8216096bc94e8261680664398691b8ea877daa0f' }))));
108
108
  }
109
109
  static get is() { return "ui-dialog"; }
110
110
  static get encapsulation() { return "shadow"; }
@@ -88,7 +88,7 @@ export class UIDisclosure {
88
88
  this.setOpen(!this.internalOpen, { reason: 'action', trigger: 'keyboard' });
89
89
  };
90
90
  render() {
91
- return (h(Host, { key: '5c49c41703850437e8b3a1476f3333da83a4f133' }, h("slot", { key: '9a4856ad2ab237331b8485f6c3a423a43ddceb8d' })));
91
+ return (h(Host, { key: '91d1df53268f18c8c15192fb66b67baa7053fe93' }, h("slot", { key: '578c99f8fd09415c5e63e9f6a860fe204471da2f' })));
92
92
  }
93
93
  static get is() { return "ui-disclosure"; }
94
94
  static get encapsulation() { return "shadow"; }
@@ -36,9 +36,9 @@ export class UIEditable {
36
36
  }
37
37
  focusEditor() {
38
38
  const editRoot = this.host.querySelector('[slot="edit"]');
39
- const candidate = editRoot?.matches('input, textarea, select, button, [tabindex], ui-combobox, ui-multi-combobox')
39
+ const candidate = editRoot?.matches('input, textarea, select, button, [tabindex], ui-combobox')
40
40
  ? editRoot
41
- : editRoot?.querySelector('input, textarea, select, button, [tabindex], ui-combobox, ui-multi-combobox');
41
+ : editRoot?.querySelector('input, textarea, select, button, [tabindex], ui-combobox');
42
42
  const focusInput = candidate?.focusInput;
43
43
  if (typeof focusInput === 'function')
44
44
  void focusInput.call(candidate);
@@ -79,7 +79,7 @@ export class UIEditable {
79
79
  this.requestEdit(false, 'light-dismiss', 'pointer');
80
80
  };
81
81
  render() {
82
- return h(Host, { key: '7f0c77aa06281c94407af1f060f5f2b2c34af394', "data-edit": this.internalEdit ? '' : undefined, "data-disabled": this.disabled ? '' : undefined, onClick: this.onClick, onKeyDown: this.onKeyDown }, h("div", { key: '4dc13c26dc4080ed0ad972aa677d9e844a0e7597', part: "preview", hidden: this.internalEdit }, h("slot", { key: '8332efed99f05173030d379088e8e97746f32ce6', name: "preview" })), h("div", { key: 'ec3e11ec9218077da5f17a0c724cfab17d56fb17', part: "edit", hidden: !this.internalEdit }, h("slot", { key: '46a4618614c6e55c0015d97e687a0f28e05eef38', name: "edit" })));
82
+ return h(Host, { key: 'c11babe81053ecc0fb6390507f74d5094c551f48', "data-edit": this.internalEdit ? '' : undefined, "data-disabled": this.disabled ? '' : undefined, onClick: this.onClick, onKeyDown: this.onKeyDown }, h("div", { key: 'fbb13fda25a177ff62f4bbb16b8fa7a8d1bfefb6', part: "preview", hidden: this.internalEdit }, h("slot", { key: '29537eed3c19da07a61b0236a563912eec332572', name: "preview" })), h("div", { key: 'a8cdb53c61041361ff97762bdf1e8e6992706751', part: "edit", hidden: !this.internalEdit }, h("slot", { key: '466c6bf07d44ab07ccab1fd138412e43a291dcca', name: "edit" })));
83
83
  }
84
84
  static get is() { return "ui-editable"; }
85
85
  static get encapsulation() { return "shadow"; }
@@ -4,7 +4,7 @@ export class UIFloatingActionButton {
4
4
  mobileOnly = false;
5
5
  label = '';
6
6
  render() {
7
- return (h(Host, { key: '86f7c100efe7fdf900de7abbcc1a01c475b0da1d', "data-disabled": this.disabled ? '' : undefined }, h("button", { key: '91398faeb693dcbe11d58e59a183391ce6e4876c', type: "button", "aria-label": this.label || undefined, disabled: this.disabled }, h("slot", { key: 'd11b6f638b045d6835279f3381442983b40472d9' }))));
7
+ return (h(Host, { key: '54f6284109397d15e2b3ef92f68e9bd4cf91fbae', "data-disabled": this.disabled ? '' : undefined }, h("button", { key: '9ebad7e3bbc2bf18d4d5a04f37a9f2d77011ad34', type: "button", "aria-label": this.label || undefined, disabled: this.disabled }, h("slot", { key: '222c6807ae4639eb20dc25be08fe5f4e91c638de' }))));
8
8
  }
9
9
  static get is() { return "ui-floating-action-button"; }
10
10
  static get encapsulation() { return "shadow"; }
@@ -98,7 +98,7 @@ export class UIFormField {
98
98
  input.setAttribute('aria-invalid', this.invalid ? 'true' : 'false');
99
99
  }
100
100
  render() {
101
- return (h(Host, { key: '3d331f3506c3853d751395569e87614c52ce0076', "data-invalid": this.invalid ? '' : undefined, "data-disabled": this.disabled ? '' : undefined, "data-required": this.required ? '' : undefined }, h("slot", { key: '1b582b4961a767230b19efa314943f8a5426270e', onSlotchange: this.scheduleWire })));
101
+ return (h(Host, { key: 'f052dbf0ba289bf187ea78c458260110fbfa059a', "data-invalid": this.invalid ? '' : undefined, "data-disabled": this.disabled ? '' : undefined, "data-required": this.required ? '' : undefined }, h("slot", { key: 'f26f48581b5781e8c3d7830ddd3707ea4fb04420', onSlotchange: this.scheduleWire })));
102
102
  }
103
103
  static get is() { return "ui-form-field"; }
104
104
  static get encapsulation() { return "shadow"; }
@@ -7,7 +7,7 @@ export class UIIconButton {
7
7
  /** Reveals this control through a surrounding ui-affordance-scope. */
8
8
  anticipatory = false;
9
9
  render() {
10
- return (h(Host, { key: '9e8ee3ff8c9f9ab5113a7635e49755e0eb998898', "data-disabled": this.disabled ? '' : undefined, "data-ui-affordance": this.anticipatory ? 'button' : undefined }, h("button", { key: '7f6dd5ae40b595634ba91834c2bb113687ee5cb8', type: "button", "aria-label": this.label || undefined, disabled: this.disabled }, h("slot", { key: 'c7a94d7fb54fbff44e372bf4f67bb29a40bfc45b' }))));
10
+ return (h(Host, { key: '8d0f84c9d3aaa69f47430369b511bb4160de5cc8', "data-disabled": this.disabled ? '' : undefined, "data-ui-affordance": this.anticipatory ? 'button' : undefined }, h("button", { key: 'b896cdb091e9733b2b8625463f1324819c23965c', type: "button", "aria-label": this.label || undefined, disabled: this.disabled }, h("slot", { key: '76ab5e5f4d34e3f0850287b4552dde060b3798e7' }))));
11
11
  }
12
12
  static get is() { return "ui-icon-button"; }
13
13
  static get encapsulation() { return "shadow"; }
@@ -70,7 +70,7 @@ export class UIInput {
70
70
  });
71
71
  };
72
72
  render() {
73
- return (h(Host, { key: '90597a900e0504f0e729990dd8cbc84c35d8162f', "data-invalid": this.invalid ? '' : undefined }, h("slot", { key: '1c8ac0ad7e4d3a5a9b913c2687021ef7037ccfa7', ref: (el) => (this.slotRef = el) })));
73
+ return (h(Host, { key: '92505de6b1245569a6d4746418a70f8d7bc4eed9', "data-invalid": this.invalid ? '' : undefined }, h("slot", { key: 'd5743dc62037b5d7722cfbb64a582592327c75e5', ref: (el) => (this.slotRef = el) })));
74
74
  }
75
75
  static get is() { return "ui-input"; }
76
76
  static get encapsulation() { return "shadow"; }
@@ -10,17 +10,22 @@
10
10
  border: 0;
11
11
  border-radius: 0;
12
12
  background: transparent;
13
- box-shadow: var(--ui-shadow-lg);
13
+ box-shadow: none;
14
+ overflow: visible;
14
15
  }
15
16
 
16
17
  .menu__surface {
17
18
  display: flex;
18
19
  flex-direction: column;
19
20
  box-sizing: border-box;
21
+ max-inline-size: inherit;
20
22
  padding: var(--ui-space-1);
21
23
  background: var(--ui-surface-elevated);
22
24
  border: 1px solid var(--ui-border-default);
23
25
  border-radius: var(--ui-radius-3);
26
+ box-shadow: var(--ui-shadow-lg);
27
+ max-block-size: inherit;
28
+ overflow: auto;
24
29
  }
25
30
 
26
31
  :host(:not([data-open])) {
@@ -31,7 +36,7 @@
31
36
  position: fixed;
32
37
  inset: auto;
33
38
  margin: 0;
34
- overflow: auto;
39
+ overflow: visible;
35
40
  max-block-size: calc(100dvh - (var(--ui-menu-viewport-gap) * 2));
36
41
  opacity: 0;
37
42
  transform: translateY(-4px) scale(0.99);
@@ -153,7 +153,7 @@ export class UIMenu {
153
153
  }
154
154
  };
155
155
  render() {
156
- return (h(Host, { key: '22689ca1b0514bb27a76bfb9a702c0d4ce49d136', role: "menu", "aria-orientation": "vertical", "data-open": this.internalOpen ? '' : undefined }, h("div", { key: 'cff891a33348f077631f1b92f1167285aafd25f1', class: "menu__surface" }, h("slot", { key: '3a0e9ff4f36b1afbe5f879e0e51ff4943279b5b5' }))));
156
+ return (h(Host, { key: '5b64cc53ca56ea04a63013c8cb61231c9b1045cc', role: "menu", "aria-orientation": "vertical", "data-open": this.internalOpen ? '' : undefined }, h("div", { key: '6410a56cc5efcffd0673c9abdf8f8aa45295c516', class: "menu__surface" }, h("slot", { key: '7e7f9d3b19bbf3024d61ecf44cd8b103748ef966' }))));
157
157
  }
158
158
  static get is() { return "ui-menu"; }
159
159
  static get encapsulation() { return "shadow"; }