@threadlabs/looma 0.6.4 → 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 (259) hide show
  1. package/components/ui-button/ui-button.html +103 -81
  2. package/components/ui-checkbox/ui-checkbox.html +4 -1
  3. package/components/ui-combobox/ui-combobox.html +40 -3
  4. package/components/ui-combobox/ui-combobox.js +27 -5
  5. package/components/ui-select/ui-select.html +3 -5
  6. package/dist/index.js +1 -1
  7. package/package.json +2 -2
  8. package/styles/ui-affordance-scope.css +1 -1
  9. package/styles/ui-avatar-group.css +1 -1
  10. package/styles/ui-avatar.css +1 -1
  11. package/styles/ui-badge.css +1 -1
  12. package/styles/ui-button.css +112 -80
  13. package/styles/ui-callout.css +1 -1
  14. package/styles/ui-checkbox.css +5 -2
  15. package/styles/ui-cluster.css +1 -1
  16. package/styles/ui-combobox.css +38 -1
  17. package/styles/ui-container.css +1 -1
  18. package/styles/ui-context-menu.css +1 -1
  19. package/styles/ui-dialog.css +1 -1
  20. package/styles/ui-disclosure.css +1 -1
  21. package/styles/ui-editable.css +1 -1
  22. package/styles/ui-editor-insert-table-grid.css +1 -1
  23. package/styles/ui-editor-mention-menu.css +1 -1
  24. package/styles/ui-editor-slash-menu.css +1 -1
  25. package/styles/ui-editor-table-context-menu.css +1 -1
  26. package/styles/ui-editor-table-overlay.css +1 -1
  27. package/styles/ui-editor-table-toolbar.css +1 -1
  28. package/styles/ui-editor-toolbar.css +1 -1
  29. package/styles/ui-floating-action-button.css +1 -1
  30. package/styles/ui-form-field.css +1 -1
  31. package/styles/ui-grid.css +1 -1
  32. package/styles/ui-icon-button.css +1 -1
  33. package/styles/ui-icon.css +1 -1
  34. package/styles/ui-input.css +1 -1
  35. package/styles/ui-menu-item.css +1 -1
  36. package/styles/ui-menu.css +1 -1
  37. package/styles/ui-popover.css +1 -1
  38. package/styles/ui-radio-group.css +1 -1
  39. package/styles/ui-radio.css +1 -1
  40. package/styles/ui-reel.css +1 -1
  41. package/styles/ui-search-result-row.css +1 -1
  42. package/styles/ui-search-shell.css +1 -1
  43. package/styles/ui-select.css +4 -5
  44. package/styles/ui-separator.css +1 -1
  45. package/styles/ui-sidebar.css +1 -1
  46. package/styles/ui-stack.css +1 -1
  47. package/styles/ui-switch.css +1 -1
  48. package/styles/ui-switcher.css +1 -1
  49. package/styles/ui-tabs.css +1 -1
  50. package/styles/ui-textarea.css +1 -1
  51. package/styles/ui-toast-region.css +1 -1
  52. package/styles/ui-tooltip.css +1 -1
  53. package/styles/ui-top-bar.css +1 -1
  54. package/styles/ui-tree-item.css +1 -1
  55. package/styles/ui-tree.css +1 -1
  56. package/theme-dark.css +6 -30
  57. package/theme-high-contrast.css +30 -20
  58. package/theme-light.css +2 -16
  59. package/tokens.css +33 -24
  60. package/vanilla/UiAffordanceScope.d.ts +1 -1
  61. package/vanilla/UiAffordanceScope.js +1 -1
  62. package/vanilla/UiAvatar.d.ts +1 -1
  63. package/vanilla/UiAvatar.js +1 -1
  64. package/vanilla/UiAvatarGroup.d.ts +1 -1
  65. package/vanilla/UiAvatarGroup.js +1 -1
  66. package/vanilla/UiBadge.d.ts +1 -1
  67. package/vanilla/UiBadge.js +1 -1
  68. package/vanilla/UiButton.d.ts +2 -2
  69. package/vanilla/UiButton.js +2 -2
  70. package/vanilla/UiCallout.d.ts +1 -1
  71. package/vanilla/UiCallout.js +1 -1
  72. package/vanilla/UiCheckbox.d.ts +1 -1
  73. package/vanilla/UiCheckbox.js +1 -1
  74. package/vanilla/UiCluster.d.ts +1 -1
  75. package/vanilla/UiCluster.js +1 -1
  76. package/vanilla/UiCombobox.d.ts +1 -1
  77. package/vanilla/UiCombobox.js +2 -2
  78. package/vanilla/UiContainer.d.ts +1 -1
  79. package/vanilla/UiContainer.js +1 -1
  80. package/vanilla/UiContextMenu.d.ts +1 -1
  81. package/vanilla/UiContextMenu.js +1 -1
  82. package/vanilla/UiDialog.d.ts +1 -1
  83. package/vanilla/UiDialog.js +1 -1
  84. package/vanilla/UiDisclosure.d.ts +1 -1
  85. package/vanilla/UiDisclosure.js +1 -1
  86. package/vanilla/UiEditable.d.ts +1 -1
  87. package/vanilla/UiEditable.js +1 -1
  88. package/vanilla/UiEditorInsertTableGrid.d.ts +1 -1
  89. package/vanilla/UiEditorInsertTableGrid.js +1 -1
  90. package/vanilla/UiEditorMentionMenu.d.ts +1 -1
  91. package/vanilla/UiEditorMentionMenu.js +1 -1
  92. package/vanilla/UiEditorSlashMenu.d.ts +1 -1
  93. package/vanilla/UiEditorSlashMenu.js +1 -1
  94. package/vanilla/UiEditorTableContextMenu.d.ts +1 -1
  95. package/vanilla/UiEditorTableContextMenu.js +1 -1
  96. package/vanilla/UiEditorTableOverlay.d.ts +1 -1
  97. package/vanilla/UiEditorTableOverlay.js +1 -1
  98. package/vanilla/UiEditorTableToolbar.d.ts +1 -1
  99. package/vanilla/UiEditorTableToolbar.js +1 -1
  100. package/vanilla/UiEditorToolbar.d.ts +1 -1
  101. package/vanilla/UiEditorToolbar.js +1 -1
  102. package/vanilla/UiFloatingActionButton.d.ts +1 -1
  103. package/vanilla/UiFloatingActionButton.js +1 -1
  104. package/vanilla/UiFormField.d.ts +1 -1
  105. package/vanilla/UiFormField.js +1 -1
  106. package/vanilla/UiGrid.d.ts +1 -1
  107. package/vanilla/UiGrid.js +1 -1
  108. package/vanilla/UiIcon.d.ts +1 -1
  109. package/vanilla/UiIcon.js +1 -1
  110. package/vanilla/UiIconButton.d.ts +1 -1
  111. package/vanilla/UiIconButton.js +1 -1
  112. package/vanilla/UiInput.d.ts +1 -1
  113. package/vanilla/UiInput.js +1 -1
  114. package/vanilla/UiMenu.d.ts +1 -1
  115. package/vanilla/UiMenu.js +1 -1
  116. package/vanilla/UiMenuItem.d.ts +1 -1
  117. package/vanilla/UiMenuItem.js +1 -1
  118. package/vanilla/UiPopover.d.ts +1 -1
  119. package/vanilla/UiPopover.js +1 -1
  120. package/vanilla/UiRadio.d.ts +1 -1
  121. package/vanilla/UiRadio.js +1 -1
  122. package/vanilla/UiRadioGroup.d.ts +1 -1
  123. package/vanilla/UiRadioGroup.js +1 -1
  124. package/vanilla/UiReel.d.ts +1 -1
  125. package/vanilla/UiReel.js +1 -1
  126. package/vanilla/UiSearchResultRow.d.ts +1 -1
  127. package/vanilla/UiSearchResultRow.js +1 -1
  128. package/vanilla/UiSearchShell.d.ts +1 -1
  129. package/vanilla/UiSearchShell.js +1 -1
  130. package/vanilla/UiSelect.d.ts +1 -2
  131. package/vanilla/UiSelect.js +4 -7
  132. package/vanilla/UiSeparator.d.ts +1 -1
  133. package/vanilla/UiSeparator.js +1 -1
  134. package/vanilla/UiSidebar.d.ts +1 -1
  135. package/vanilla/UiSidebar.js +1 -1
  136. package/vanilla/UiStack.d.ts +1 -1
  137. package/vanilla/UiStack.js +1 -1
  138. package/vanilla/UiSwitch.d.ts +1 -1
  139. package/vanilla/UiSwitch.js +1 -1
  140. package/vanilla/UiSwitcher.d.ts +1 -1
  141. package/vanilla/UiSwitcher.js +1 -1
  142. package/vanilla/UiTabs.d.ts +1 -1
  143. package/vanilla/UiTabs.js +1 -1
  144. package/vanilla/UiTextarea.d.ts +1 -1
  145. package/vanilla/UiTextarea.js +1 -1
  146. package/vanilla/UiToastRegion.d.ts +1 -1
  147. package/vanilla/UiToastRegion.js +1 -1
  148. package/vanilla/UiTooltip.d.ts +1 -1
  149. package/vanilla/UiTooltip.js +1 -1
  150. package/vanilla/UiTopBar.d.ts +1 -1
  151. package/vanilla/UiTopBar.js +1 -1
  152. package/vanilla/UiTree.d.ts +1 -1
  153. package/vanilla/UiTree.js +1 -1
  154. package/vanilla/UiTreeItem.d.ts +1 -1
  155. package/vanilla/UiTreeItem.js +1 -1
  156. package/vue/UiAffordanceScope.vue +8 -84
  157. package/vue/UiAvatar.d.ts +1 -1
  158. package/vue/UiAvatar.vue +9 -106
  159. package/vue/UiAvatarGroup.vue +9 -96
  160. package/vue/UiBadge.vue +1 -1
  161. package/vue/UiButton.d.ts +2 -2
  162. package/vue/UiButton.vue +104 -97
  163. package/vue/UiCallout.vue +1 -1
  164. package/vue/UiCheckbox.vue +26 -124
  165. package/vue/UiCluster.vue +1 -1
  166. package/vue/UiCombobox.d.ts +1 -1
  167. package/vue/UiCombobox.vue +270 -479
  168. package/vue/UiContainer.vue +1 -1
  169. package/vue/UiContextMenu.vue +34 -141
  170. package/vue/UiDialog.vue +25 -126
  171. package/vue/UiDisclosure.vue +26 -138
  172. package/vue/UiEditable.vue +46 -158
  173. package/vue/UiEditorInsertTableGrid.vue +19 -138
  174. package/vue/UiEditorMentionMenu.vue +17 -124
  175. package/vue/UiEditorSlashMenu.vue +17 -109
  176. package/vue/UiEditorTableContextMenu.vue +34 -122
  177. package/vue/UiEditorTableOverlay.vue +61 -167
  178. package/vue/UiEditorTableToolbar.vue +34 -142
  179. package/vue/UiEditorToolbar.vue +1 -1
  180. package/vue/UiFloatingActionButton.vue +1 -1
  181. package/vue/UiFormField.vue +7 -79
  182. package/vue/UiGrid.vue +1 -1
  183. package/vue/UiIcon.vue +8 -84
  184. package/vue/UiIconButton.vue +7 -79
  185. package/vue/UiInput.vue +7 -79
  186. package/vue/UiMenu.vue +42 -127
  187. package/vue/UiMenuItem.vue +1 -1
  188. package/vue/UiPopover.vue +25 -121
  189. package/vue/UiRadio.vue +22 -123
  190. package/vue/UiRadioGroup.d.ts +1 -1
  191. package/vue/UiRadioGroup.vue +32 -119
  192. package/vue/UiReel.vue +1 -1
  193. package/vue/UiSearchResultRow.vue +1 -1
  194. package/vue/UiSearchShell.vue +25 -121
  195. package/vue/UiSelect.d.ts +0 -2
  196. package/vue/UiSelect.vue +9 -85
  197. package/vue/UiSeparator.vue +1 -1
  198. package/vue/UiSidebar.vue +32 -133
  199. package/vue/UiStack.vue +1 -1
  200. package/vue/UiSwitch.vue +22 -123
  201. package/vue/UiSwitcher.vue +1 -1
  202. package/vue/UiTabs.vue +24 -128
  203. package/vue/UiTextarea.vue +7 -79
  204. package/vue/UiToastRegion.vue +37 -126
  205. package/vue/UiTooltip.vue +25 -124
  206. package/vue/UiTopBar.vue +1 -1
  207. package/vue/UiTree.vue +56 -137
  208. package/vue/UiTreeItem.vue +28 -144
  209. package/vue/chunks/UiAffordanceScope.js +9 -78
  210. package/vue/chunks/UiAvatar.js +13 -89
  211. package/vue/chunks/UiAvatarGroup.js +10 -80
  212. package/vue/chunks/UiBadge.js +1 -1
  213. package/vue/chunks/UiButton.js +3 -3
  214. package/vue/chunks/UiCallout.js +1 -1
  215. package/vue/chunks/UiCheckbox.js +17 -95
  216. package/vue/chunks/UiCluster.js +1 -1
  217. package/vue/chunks/UiCombobox.js +115 -326
  218. package/vue/chunks/UiContainer.js +1 -1
  219. package/vue/chunks/UiContextMenu.js +21 -113
  220. package/vue/chunks/UiDialog.js +20 -99
  221. package/vue/chunks/UiDisclosure.js +22 -112
  222. package/vue/chunks/UiEditable.js +32 -128
  223. package/vue/chunks/UiEditorInsertTableGrid.js +22 -116
  224. package/vue/chunks/UiEditorMentionMenu.js +18 -116
  225. package/vue/chunks/UiEditorSlashMenu.js +15 -101
  226. package/vue/chunks/UiEditorTableContextMenu.js +12 -91
  227. package/vue/chunks/UiEditorTableOverlay.js +29 -120
  228. package/vue/chunks/UiEditorTableToolbar.js +16 -111
  229. package/vue/chunks/UiEditorToolbar.js +1 -1
  230. package/vue/chunks/UiFloatingActionButton.js +1 -1
  231. package/vue/chunks/UiFormField.js +8 -73
  232. package/vue/chunks/UiGrid.js +1 -1
  233. package/vue/chunks/UiIcon.js +9 -78
  234. package/vue/chunks/UiIconButton.js +8 -73
  235. package/vue/chunks/UiInput.js +8 -73
  236. package/vue/chunks/UiMenu.js +25 -111
  237. package/vue/chunks/UiMenuItem.js +1 -1
  238. package/vue/chunks/UiPopover.js +18 -105
  239. package/vue/chunks/UiRadio.js +17 -95
  240. package/vue/chunks/UiRadioGroup.js +23 -105
  241. package/vue/chunks/UiReel.js +1 -1
  242. package/vue/chunks/UiSearchResultRow.js +1 -1
  243. package/vue/chunks/UiSearchShell.js +17 -94
  244. package/vue/chunks/UiSelect.js +8 -79
  245. package/vue/chunks/UiSeparator.js +1 -1
  246. package/vue/chunks/UiSidebar.js +23 -108
  247. package/vue/chunks/UiStack.js +1 -1
  248. package/vue/chunks/UiSwitch.js +17 -95
  249. package/vue/chunks/UiSwitcher.js +1 -1
  250. package/vue/chunks/UiTabs.js +22 -103
  251. package/vue/chunks/UiTextarea.js +8 -73
  252. package/vue/chunks/UiToastRegion.js +27 -112
  253. package/vue/chunks/UiTooltip.js +18 -106
  254. package/vue/chunks/UiTopBar.js +1 -1
  255. package/vue/chunks/UiTree.js +31 -109
  256. package/vue/chunks/UiTreeItem.js +29 -119
  257. package/vue/chunks/host.js +101 -0
  258. package/vue/components.css +844 -797
  259. package/vue/host.ts +154 -0
@@ -1,15 +1,8 @@
1
- <!-- Generated by HTML Next 1.0.0-alpha.2 for Vue 3.5. Do not edit. -->
1
+ <!-- Generated by HTML Next 1.0.0-alpha.3 for Vue 3.5. Do not edit. -->
2
2
  <script setup lang="ts">
3
- import {
4
- computed,
5
- onBeforeUnmount,
6
- onMounted,
7
- ref,
8
- shallowRef,
9
- useTemplateRef,
10
- watchEffect,
11
- } from 'vue'
3
+ import { computed, ref, useTemplateRef } from 'vue'
12
4
  import * as controllerModule from '../components/ui-combobox/ui-combobox.js'
5
+ import { createDispatch, useComponentHost } from './host'
13
6
  import UiBadge from './UiBadge.vue'
14
7
  import UiTooltip from './UiTooltip.vue'
15
8
 
@@ -191,9 +184,16 @@ const raw = ref('')
191
184
  const display = ref('')
192
185
  const selected = ref<string | null>(null)
193
186
  const expanded = ref(false)
194
- const rows = ref<{ id: string; value: string; label: string; group?: string; disabled: boolean }[]>(
195
- [],
196
- )
187
+ const rows = ref<
188
+ {
189
+ id: string
190
+ value: string
191
+ label: string
192
+ group?: string
193
+ disabled: boolean
194
+ selected: boolean
195
+ }[]
196
+ >([])
197
197
  const active = ref<number | null>(-1)
198
198
  const loading = ref(false)
199
199
  const helpOpen = ref(false)
@@ -219,6 +219,7 @@ const groups = ref<
219
219
  label: string
220
220
  group?: string
221
221
  disabled: boolean
222
+ selected: boolean
222
223
  index: number
223
224
  }[]
224
225
  }[]
@@ -239,484 +240,240 @@ const hostState = computed(() =>
239
240
  ].filter(Boolean).join(' ')
240
241
  )
241
242
 
242
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
243
- function dispatch(name: string, detail?: unknown): boolean {
244
- const declared: Record<string, EventInit | undefined> = {
245
- 'query-change': { bubbles: true, composed: true, cancelable: false },
246
- 'value-change': { bubbles: true, composed: true, cancelable: false },
247
- 'free-entry': { bubbles: true, composed: true, cancelable: false },
248
- 'create-entry': { bubbles: true, composed: true, cancelable: false },
249
- 'validation-change': { bubbles: true, composed: true, cancelable: false },
250
- 'options-change': { bubbles: true, composed: true, cancelable: false },
251
- 'add-item': { bubbles: true, composed: true, cancelable: false },
252
- 'remove-item': { bubbles: true, composed: true, cancelable: false },
253
- 'create-item': { bubbles: true, composed: true, cancelable: false },
254
- }
255
- const checks: Record<string, (detail: unknown) => boolean> = {
256
- 'query-change': (detail) =>
257
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
258
- && typeof (detail as Record<string, unknown>)['query'] === 'string'
259
- && typeof (detail as Record<string, unknown>)['display'] === 'string'
260
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
261
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
262
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
263
- && Object.keys(detail as object).every((key) =>
264
- ['query', 'display', 'trigger'].includes(key)
265
- ),
266
- 'value-change': (detail) =>
267
- (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
268
- && (typeof (detail as Record<string, unknown>)['value'] === 'string'
269
- || (detail as Record<string, unknown>)['value'] === null)
270
- && typeof (detail as Record<string, unknown>)['query'] === 'string'
271
- && (((detail as Record<string, unknown>)['option'] !== null
272
- && typeof (detail as Record<string, unknown>)['option'] === 'object'
273
- && !Array.isArray((detail as Record<string, unknown>)['option'])
274
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['id']
275
- === 'string'
276
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
277
- 'value'
278
- ] === 'string'
279
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
280
- 'label'
281
- ] === 'string'
282
- && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['group']
283
- === undefined
284
- || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
285
- 'group'
286
- ] === 'string')
287
- && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['disabled']
288
- === undefined
289
- || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
290
- 'disabled'
291
- ] === 'boolean')
292
- && Object.keys((detail as Record<string, unknown>)['option'] as object).every((key) =>
293
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
294
- )) || (detail as Record<string, unknown>)['option'] === null)
295
- && ((detail as Record<string, unknown>)['kind'] === 'selection'
296
- || (detail as Record<string, unknown>)['kind'] === 'clear'
297
- || (detail as Record<string, unknown>)['kind'] === 'free-entry'
298
- || (detail as Record<string, unknown>)['kind'] === 'create')
299
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
300
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
301
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
302
- && Object.keys(detail as object).every((key) =>
303
- ['value', 'query', 'option', 'kind', 'trigger'].includes(key)
304
- ))
305
- || (Array.isArray(detail)
306
- && (detail as unknown[]).every((
307
- item: unknown,
308
- ) => (item !== null && typeof item === 'object' && !Array.isArray(item)
309
- && typeof (item as Record<string, unknown>)['id'] === 'string'
310
- && typeof (item as Record<string, unknown>)['value'] === 'string'
311
- && typeof (item as Record<string, unknown>)['label'] === 'string'
312
- && ((item as Record<string, unknown>)['group'] === undefined
313
- || typeof (item as Record<string, unknown>)['group'] === 'string')
314
- && ((item as Record<string, unknown>)['disabled'] === undefined
315
- || typeof (item as Record<string, unknown>)['disabled'] === 'boolean')
316
- && Object.keys(item as object).every((key) =>
317
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
318
- ))
319
- )),
320
- 'free-entry': (detail) =>
321
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
322
- && (typeof (detail as Record<string, unknown>)['value'] === 'string'
323
- || (detail as Record<string, unknown>)['value'] === null)
324
- && typeof (detail as Record<string, unknown>)['query'] === 'string'
325
- && (((detail as Record<string, unknown>)['option'] !== null
326
- && typeof (detail as Record<string, unknown>)['option'] === 'object'
327
- && !Array.isArray((detail as Record<string, unknown>)['option'])
328
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['id']
329
- === 'string'
330
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
331
- 'value'
332
- ] === 'string'
333
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
334
- 'label'
335
- ] === 'string'
336
- && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['group']
337
- === undefined
338
- || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
339
- 'group'
340
- ] === 'string')
341
- && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['disabled']
342
- === undefined
343
- || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
344
- 'disabled'
345
- ] === 'boolean')
346
- && Object.keys((detail as Record<string, unknown>)['option'] as object).every((key) =>
347
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
348
- )) || (detail as Record<string, unknown>)['option'] === null)
349
- && ((detail as Record<string, unknown>)['kind'] === 'selection'
350
- || (detail as Record<string, unknown>)['kind'] === 'clear'
351
- || (detail as Record<string, unknown>)['kind'] === 'free-entry'
352
- || (detail as Record<string, unknown>)['kind'] === 'create')
353
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
354
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
355
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
356
- && Object.keys(detail as object).every((key) =>
357
- ['value', 'query', 'option', 'kind', 'trigger'].includes(key)
358
- ),
359
- 'create-entry': (detail) =>
360
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
361
- && (typeof (detail as Record<string, unknown>)['value'] === 'string'
362
- || (detail as Record<string, unknown>)['value'] === null)
363
- && typeof (detail as Record<string, unknown>)['query'] === 'string'
364
- && (((detail as Record<string, unknown>)['option'] !== null
365
- && typeof (detail as Record<string, unknown>)['option'] === 'object'
366
- && !Array.isArray((detail as Record<string, unknown>)['option'])
367
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['id']
368
- === 'string'
369
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
370
- 'value'
371
- ] === 'string'
372
- && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
373
- 'label'
374
- ] === 'string'
375
- && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['group']
376
- === undefined
377
- || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
378
- 'group'
379
- ] === 'string')
380
- && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['disabled']
381
- === undefined
382
- || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
383
- 'disabled'
384
- ] === 'boolean')
385
- && Object.keys((detail as Record<string, unknown>)['option'] as object).every((key) =>
386
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
387
- )) || (detail as Record<string, unknown>)['option'] === null)
388
- && ((detail as Record<string, unknown>)['kind'] === 'selection'
389
- || (detail as Record<string, unknown>)['kind'] === 'clear'
390
- || (detail as Record<string, unknown>)['kind'] === 'free-entry'
391
- || (detail as Record<string, unknown>)['kind'] === 'create')
392
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
393
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
394
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
395
- && Object.keys(detail as object).every((key) =>
396
- ['value', 'query', 'option', 'kind', 'trigger'].includes(key)
397
- ),
398
- 'validation-change': (detail) =>
399
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
400
- && ((detail as Record<string, unknown>)['status'] === 'pristine'
401
- || (detail as Record<string, unknown>)['status'] === 'pending'
402
- || (detail as Record<string, unknown>)['status'] === 'valid'
403
- || (detail as Record<string, unknown>)['status'] === 'warning'
404
- || (detail as Record<string, unknown>)['status'] === 'error')
405
- && typeof (detail as Record<string, unknown>)['touched'] === 'boolean'
406
- && typeof (detail as Record<string, unknown>)['dirty'] === 'boolean'
407
- && (Array.isArray((detail as Record<string, unknown>)['issues'])
408
- && ((detail as Record<string, unknown>)['issues'] as unknown[]).every((
409
- item: unknown,
410
- ) => (item !== null && typeof item === 'object' && !Array.isArray(item)
411
- && typeof (item as Record<string, unknown>)['message'] === 'string'
412
- && ((item as Record<string, unknown>)['path'] === undefined
413
- || (Array.isArray((item as Record<string, unknown>)['path'])
414
- && ((item as Record<string, unknown>)['path'] as unknown[]).every((item: unknown) =>
415
- true
416
- )))
417
- && ((item as Record<string, unknown>)['severity'] === undefined
418
- || ((item as Record<string, unknown>)['severity'] === 'error'
419
- || (item as Record<string, unknown>)['severity'] === 'warning'))
420
- && Object.keys(item as object).every((key) =>
421
- ['message', 'path', 'severity'].includes(key)
422
- ))
423
- ))
424
- && ((detail as Record<string, unknown>)['output'] === undefined || true)
425
- && Object.keys(detail as object).every((key) =>
426
- ['status', 'touched', 'dirty', 'issues', 'output'].includes(key)
427
- ),
428
- 'options-change': (detail) =>
429
- Array.isArray(detail)
430
- && (detail as unknown[]).every((
431
- item: unknown,
432
- ) => (item !== null && typeof item === 'object' && !Array.isArray(item)
433
- && typeof (item as Record<string, unknown>)['id'] === 'string'
434
- && typeof (item as Record<string, unknown>)['value'] === 'string'
435
- && typeof (item as Record<string, unknown>)['label'] === 'string'
436
- && ((item as Record<string, unknown>)['group'] === undefined
437
- || typeof (item as Record<string, unknown>)['group'] === 'string')
438
- && ((item as Record<string, unknown>)['disabled'] === undefined
439
- || typeof (item as Record<string, unknown>)['disabled'] === 'boolean')
440
- && Object.keys(item as object).every((key) =>
441
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
442
- ))
443
- ),
444
- 'add-item': (detail) =>
445
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
446
- && ((detail as Record<string, unknown>)['item'] !== null
447
- && typeof (detail as Record<string, unknown>)['item'] === 'object'
448
- && !Array.isArray((detail as Record<string, unknown>)['item'])
449
- && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['id']
450
- === 'string'
451
- && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['value']
452
- === 'string'
453
- && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['label']
454
- === 'string'
455
- && (((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['group']
456
- === undefined
457
- || typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)[
458
- 'group'
459
- ] === 'string')
460
- && (((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['disabled']
461
- === undefined
462
- || typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)[
463
- 'disabled'
464
- ] === 'boolean')
465
- && Object.keys((detail as Record<string, unknown>)['item'] as object).every((key) =>
466
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
467
- ))
468
- && Number.isInteger((detail as Record<string, unknown>)['index'])
469
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
470
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
471
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
472
- && Object.keys(detail as object).every((key) =>
473
- ['item', 'index', 'trigger'].includes(key)
474
- ),
475
- 'remove-item': (detail) =>
476
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
477
- && ((detail as Record<string, unknown>)['item'] !== null
478
- && typeof (detail as Record<string, unknown>)['item'] === 'object'
479
- && !Array.isArray((detail as Record<string, unknown>)['item'])
480
- && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['id']
481
- === 'string'
482
- && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['value']
483
- === 'string'
484
- && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['label']
485
- === 'string'
486
- && (((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['group']
487
- === undefined
488
- || typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)[
489
- 'group'
490
- ] === 'string')
491
- && (((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['disabled']
492
- === undefined
493
- || typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)[
494
- 'disabled'
495
- ] === 'boolean')
496
- && Object.keys((detail as Record<string, unknown>)['item'] as object).every((key) =>
497
- ['id', 'value', 'label', 'group', 'disabled'].includes(key)
498
- ))
499
- && Number.isInteger((detail as Record<string, unknown>)['index'])
500
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
501
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
502
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
503
- && Object.keys(detail as object).every((key) =>
504
- ['item', 'index', 'trigger'].includes(key)
505
- ),
506
- 'create-item': (detail) =>
507
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
508
- && typeof (detail as Record<string, unknown>)['query'] === 'string'
509
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
510
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
511
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
512
- && Object.keys(detail as object).every((key) => ['query', 'trigger'].includes(key)),
513
- }
514
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
515
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
516
- }
517
- const emitEvent = emit as (name: string, detail: unknown) => void
518
- emitEvent(name, detail)
519
- if (detail !== null && typeof detail === 'object' && 'query' in detail) {
520
- emitEvent('update:query', (detail as Record<string, unknown>)['query'])
521
- }
522
- if (detail !== null && typeof detail === 'object' && 'value' in detail) {
523
- emitEvent('update:value', (detail as Record<string, unknown>)['value'])
524
- }
525
- return root.value?.dispatchEvent(
526
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
527
- ) ?? true
528
- }
529
-
530
- function read(name: string): unknown {
531
- if (name === 'internalItems') return internalItems.value
532
- if (name === 'raw') return raw.value
533
- if (name === 'display') return display.value
534
- if (name === 'selected') return selected.value
535
- if (name === 'expanded') return expanded.value
536
- if (name === 'rows') return rows.value
537
- if (name === 'active') return active.value
538
- if (name === 'loading') return loading.value
539
- if (name === 'helpOpen') return helpOpen.value
540
- if (name === 'lookupError') return lookupError.value
541
- if (name === 'validation') return validation.value
542
- if (name === 'uid') return uid.value
543
- if (name === 'groups') return groups.value
544
- if (name === 'creatable') return creatable.value
545
- if (name === 'createIndex') return createIndex.value
546
- if (name === 'message') return message.value
547
- if (name === 'statusText') return statusText.value
548
- if (name === 'validationStatus') return validationStatus.value
549
- return (props as Record<string, unknown>)[name]
550
- }
551
-
552
- function write(name: string, value: unknown): boolean {
553
- if (name === 'internalItems') {
554
- internalItems.value = value as never
555
- return true
556
- }
557
- if (name === 'raw') {
558
- raw.value = value as never
559
- return true
560
- }
561
- if (name === 'display') {
562
- display.value = value as never
563
- return true
564
- }
565
- if (name === 'selected') {
566
- selected.value = value as never
567
- return true
568
- }
569
- if (name === 'expanded') {
570
- expanded.value = value as never
571
- return true
572
- }
573
- if (name === 'rows') {
574
- rows.value = value as never
575
- return true
576
- }
577
- if (name === 'active') {
578
- active.value = value as never
579
- return true
580
- }
581
- if (name === 'loading') {
582
- loading.value = value as never
583
- return true
584
- }
585
- if (name === 'helpOpen') {
586
- helpOpen.value = value as never
587
- return true
588
- }
589
- if (name === 'lookupError') {
590
- lookupError.value = value as never
591
- return true
592
- }
593
- if (name === 'validation') {
594
- validation.value = value as never
595
- return true
596
- }
597
- if (name === 'uid') {
598
- uid.value = value as never
599
- return true
600
- }
601
- if (name === 'groups') {
602
- groups.value = value as never
603
- return true
604
- }
605
- if (name === 'creatable') {
606
- creatable.value = value as never
607
- return true
608
- }
609
- if (name === 'createIndex') {
610
- createIndex.value = value as never
611
- return true
612
- }
613
- if (name === 'message') {
614
- message.value = value as never
615
- return true
616
- }
617
- if (name === 'statusText') {
618
- statusText.value = value as never
619
- return true
620
- }
621
- if (name === 'validationStatus') {
622
- validationStatus.value = value as never
623
- return true
624
- }
625
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
626
- }
627
-
628
- const stops: Array<() => void> = []
629
- const host = {
630
- get element(): Element {
631
- return root.value as Element
243
+ const isQueryChangeDetail = (detail: unknown): boolean =>
244
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
245
+ && typeof (detail as Record<string, unknown>)['query'] === 'string'
246
+ && typeof (detail as Record<string, unknown>)['display'] === 'string'
247
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
248
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
249
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
250
+ && Object.keys(detail as object).every((key) => ['query', 'display', 'trigger'].includes(key))
251
+ const isValueChangeDetail = (detail: unknown): boolean =>
252
+ (detail !== null && typeof detail === 'object' && !Array.isArray(detail)
253
+ && (typeof (detail as Record<string, unknown>)['value'] === 'string'
254
+ || (detail as Record<string, unknown>)['value'] === null)
255
+ && typeof (detail as Record<string, unknown>)['query'] === 'string'
256
+ && (((detail as Record<string, unknown>)['option'] !== null
257
+ && typeof (detail as Record<string, unknown>)['option'] === 'object'
258
+ && !Array.isArray((detail as Record<string, unknown>)['option'])
259
+ && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['id']
260
+ === 'string'
261
+ && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['value']
262
+ === 'string'
263
+ && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['label']
264
+ === 'string'
265
+ && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['group']
266
+ === undefined
267
+ || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
268
+ 'group'
269
+ ] === 'string')
270
+ && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['disabled']
271
+ === undefined
272
+ || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
273
+ 'disabled'
274
+ ] === 'boolean')
275
+ && Object.keys((detail as Record<string, unknown>)['option'] as object).every((key) =>
276
+ ['id', 'value', 'label', 'group', 'disabled'].includes(key)
277
+ )) || (detail as Record<string, unknown>)['option'] === null)
278
+ && ((detail as Record<string, unknown>)['kind'] === 'selection'
279
+ || (detail as Record<string, unknown>)['kind'] === 'clear'
280
+ || (detail as Record<string, unknown>)['kind'] === 'free-entry'
281
+ || (detail as Record<string, unknown>)['kind'] === 'create')
282
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
283
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
284
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
285
+ && Object.keys(detail as object).every((key) =>
286
+ ['value', 'query', 'option', 'kind', 'trigger'].includes(key)
287
+ ))
288
+ || (Array.isArray(detail)
289
+ && (detail as unknown[]).every((
290
+ item: unknown,
291
+ ) => (item !== null && typeof item === 'object' && !Array.isArray(item)
292
+ && typeof (item as Record<string, unknown>)['id'] === 'string'
293
+ && typeof (item as Record<string, unknown>)['value'] === 'string'
294
+ && typeof (item as Record<string, unknown>)['label'] === 'string'
295
+ && ((item as Record<string, unknown>)['group'] === undefined
296
+ || typeof (item as Record<string, unknown>)['group'] === 'string')
297
+ && ((item as Record<string, unknown>)['disabled'] === undefined
298
+ || typeof (item as Record<string, unknown>)['disabled'] === 'boolean')
299
+ && Object.keys(item as object).every((key) =>
300
+ ['id', 'value', 'label', 'group', 'disabled'].includes(key)
301
+ ))
302
+ ))
303
+ const isFreeEntryDetail = (detail: unknown): boolean =>
304
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
305
+ && (typeof (detail as Record<string, unknown>)['value'] === 'string'
306
+ || (detail as Record<string, unknown>)['value'] === null)
307
+ && typeof (detail as Record<string, unknown>)['query'] === 'string'
308
+ && (((detail as Record<string, unknown>)['option'] !== null
309
+ && typeof (detail as Record<string, unknown>)['option'] === 'object'
310
+ && !Array.isArray((detail as Record<string, unknown>)['option'])
311
+ && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['id']
312
+ === 'string'
313
+ && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['value']
314
+ === 'string'
315
+ && typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['label']
316
+ === 'string'
317
+ && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['group']
318
+ === undefined
319
+ || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['group']
320
+ === 'string')
321
+ && (((detail as Record<string, unknown>)['option'] as Record<string, unknown>)['disabled']
322
+ === undefined
323
+ || typeof ((detail as Record<string, unknown>)['option'] as Record<string, unknown>)[
324
+ 'disabled'
325
+ ] === 'boolean')
326
+ && Object.keys((detail as Record<string, unknown>)['option'] as object).every((key) =>
327
+ ['id', 'value', 'label', 'group', 'disabled'].includes(key)
328
+ )) || (detail as Record<string, unknown>)['option'] === null)
329
+ && ((detail as Record<string, unknown>)['kind'] === 'selection'
330
+ || (detail as Record<string, unknown>)['kind'] === 'clear'
331
+ || (detail as Record<string, unknown>)['kind'] === 'free-entry'
332
+ || (detail as Record<string, unknown>)['kind'] === 'create')
333
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
334
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
335
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
336
+ && Object.keys(detail as object).every((key) =>
337
+ ['value', 'query', 'option', 'kind', 'trigger'].includes(key)
338
+ )
339
+ const isValidationChangeDetail = (detail: unknown): boolean =>
340
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
341
+ && ((detail as Record<string, unknown>)['status'] === 'pristine'
342
+ || (detail as Record<string, unknown>)['status'] === 'pending'
343
+ || (detail as Record<string, unknown>)['status'] === 'valid'
344
+ || (detail as Record<string, unknown>)['status'] === 'warning'
345
+ || (detail as Record<string, unknown>)['status'] === 'error')
346
+ && typeof (detail as Record<string, unknown>)['touched'] === 'boolean'
347
+ && typeof (detail as Record<string, unknown>)['dirty'] === 'boolean'
348
+ && (Array.isArray((detail as Record<string, unknown>)['issues'])
349
+ && ((detail as Record<string, unknown>)['issues'] as unknown[]).every((
350
+ item: unknown,
351
+ ) => (item !== null && typeof item === 'object' && !Array.isArray(item)
352
+ && typeof (item as Record<string, unknown>)['message'] === 'string'
353
+ && ((item as Record<string, unknown>)['path'] === undefined
354
+ || (Array.isArray((item as Record<string, unknown>)['path'])
355
+ && ((item as Record<string, unknown>)['path'] as unknown[]).every((item: unknown) =>
356
+ true
357
+ )))
358
+ && ((item as Record<string, unknown>)['severity'] === undefined
359
+ || ((item as Record<string, unknown>)['severity'] === 'error'
360
+ || (item as Record<string, unknown>)['severity'] === 'warning'))
361
+ && Object.keys(item as object).every((key) =>
362
+ ['message', 'path', 'severity'].includes(key)
363
+ ))
364
+ ))
365
+ && ((detail as Record<string, unknown>)['output'] === undefined || true)
366
+ && Object.keys(detail as object).every((key) =>
367
+ ['status', 'touched', 'dirty', 'issues', 'output'].includes(key)
368
+ )
369
+ const isOptionsChangeDetail = (detail: unknown): boolean =>
370
+ Array.isArray(detail)
371
+ && (detail as unknown[]).every((
372
+ item: unknown,
373
+ ) => (item !== null && typeof item === 'object' && !Array.isArray(item)
374
+ && typeof (item as Record<string, unknown>)['id'] === 'string'
375
+ && typeof (item as Record<string, unknown>)['value'] === 'string'
376
+ && typeof (item as Record<string, unknown>)['label'] === 'string'
377
+ && ((item as Record<string, unknown>)['group'] === undefined
378
+ || typeof (item as Record<string, unknown>)['group'] === 'string')
379
+ && ((item as Record<string, unknown>)['disabled'] === undefined
380
+ || typeof (item as Record<string, unknown>)['disabled'] === 'boolean')
381
+ && Object.keys(item as object).every((key) =>
382
+ ['id', 'value', 'label', 'group', 'disabled'].includes(key)
383
+ ))
384
+ )
385
+ const isAddItemDetail = (detail: unknown): boolean =>
386
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
387
+ && ((detail as Record<string, unknown>)['item'] !== null
388
+ && typeof (detail as Record<string, unknown>)['item'] === 'object'
389
+ && !Array.isArray((detail as Record<string, unknown>)['item'])
390
+ && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['id']
391
+ === 'string'
392
+ && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['value']
393
+ === 'string'
394
+ && typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['label']
395
+ === 'string'
396
+ && (((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['group']
397
+ === undefined
398
+ || typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['group']
399
+ === 'string')
400
+ && (((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['disabled']
401
+ === undefined
402
+ || typeof ((detail as Record<string, unknown>)['item'] as Record<string, unknown>)['disabled']
403
+ === 'boolean')
404
+ && Object.keys((detail as Record<string, unknown>)['item'] as object).every((key) =>
405
+ ['id', 'value', 'label', 'group', 'disabled'].includes(key)
406
+ ))
407
+ && Number.isInteger((detail as Record<string, unknown>)['index'])
408
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
409
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
410
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
411
+ && Object.keys(detail as object).every((key) => ['item', 'index', 'trigger'].includes(key))
412
+ const isCreateItemDetail = (detail: unknown): boolean =>
413
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
414
+ && typeof (detail as Record<string, unknown>)['query'] === 'string'
415
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
416
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
417
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
418
+ && Object.keys(detail as object).every((key) => ['query', 'trigger'].includes(key))
419
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
420
+ checks: {
421
+ 'query-change': isQueryChangeDetail,
422
+ 'value-change': isValueChangeDetail,
423
+ 'free-entry': isFreeEntryDetail,
424
+ 'create-entry': isFreeEntryDetail,
425
+ 'validation-change': isValidationChangeDetail,
426
+ 'options-change': isOptionsChangeDetail,
427
+ 'add-item': isAddItemDetail,
428
+ 'remove-item': isAddItemDetail,
429
+ 'create-item': isCreateItemDetail,
632
430
  },
633
- state: new Proxy({} as Record<string, unknown>, {
634
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
635
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
636
- }),
431
+ modeled: ['query', 'value'],
432
+ })
433
+
434
+ const { host, ready } = useComponentHost(controllerModule.default, {
435
+ root,
436
+ dispatch,
437
+ props,
637
438
  refs: {
638
- get field(): Element {
639
- return fieldElement.value as Element
640
- },
641
- get input(): Element {
642
- return inputElement.value as Element
643
- },
644
- get popup(): Element {
645
- return popupElement.value as Element
646
- },
647
- get listbox(): Element {
648
- return listboxElement.value as Element
649
- },
650
- get options(): Element {
651
- return optionsElement.value as Element
652
- },
653
- } as Readonly<Record<string, Element>>,
654
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
655
- get: (_target, name) => {
656
- if (typeof name !== 'string' || root.value === null) return undefined
657
- const form = root.value instanceof HTMLFormElement
658
- ? root.value
659
- : root.value.querySelector('form')
660
- return form?.elements.namedItem(name)
661
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
662
- },
663
- }),
664
- signal<T>(initialValue: T) {
665
- const value = shallowRef(initialValue)
666
- return {
667
- get: (): T => value.value,
668
- set: (next: T): void => {
669
- if (!Object.is(value.value, next)) value.value = next
670
- },
671
- update: (next: (current: T) => T): void => {
672
- const updated = next(value.value)
673
- if (!Object.is(value.value, updated)) value.value = updated
674
- },
675
- }
439
+ field: fieldElement,
440
+ input: inputElement,
441
+ popup: popupElement,
442
+ listbox: listboxElement,
443
+ options: optionsElement,
676
444
  },
677
- computed<T>(compute: () => T) {
678
- const value = computed(compute)
679
- return { get: (): T => value.value }
445
+ state: {
446
+ internalItems,
447
+ raw,
448
+ display,
449
+ selected,
450
+ expanded,
451
+ rows,
452
+ active,
453
+ loading,
454
+ helpOpen,
455
+ lookupError,
456
+ validation,
457
+ uid,
458
+ groups,
459
+ creatable,
460
+ createIndex,
461
+ message,
462
+ statusText,
463
+ validationStatus,
680
464
  },
681
- effect(run: () => void | (() => void)): () => void {
682
- const stop = watchEffect((onCleanup) => {
683
- const cleanup = run()
684
- if (typeof cleanup === 'function') onCleanup(cleanup)
685
- }, { flush: 'post' })
686
- stops.push(stop)
687
- return stop
688
- },
689
- on(event: string, listener: EventListener): () => void {
690
- const element = root.value
691
- element?.addEventListener(event, listener)
692
- const off = (): void => element?.removeEventListener(event, listener)
693
- stops.push(off)
694
- return off
695
- },
696
- dispatch,
697
- }
698
-
699
- let cleanup: void | (() => void)
700
- let ready: Promise<void> | undefined
701
- onMounted(() => {
702
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
703
- cleanup = result
704
- })
705
- })
706
- onBeforeUnmount(() => {
707
- for (const stop of stops.splice(0)) stop()
708
- if (typeof cleanup === 'function') cleanup()
709
465
  })
466
+
710
467
  defineExpose({
711
468
  validate: async (...args: unknown[]) => {
712
- await ready
469
+ await ready()
713
470
  return (controllerModule as Record<string, (...values: unknown[]) => unknown>)['validate']!(
714
471
  host,
715
472
  ...args,
716
473
  )
717
474
  },
718
475
  focusInput: async (...args: unknown[]) => {
719
- await ready
476
+ await ready()
720
477
  return (controllerModule as Record<string, (...values: unknown[]) => unknown>)['focusInput']!(
721
478
  host,
722
479
  ...args,
@@ -850,7 +607,7 @@ defineExpose({
850
607
  class="option"
851
608
  role="option"
852
609
  :id="`${uid}-option-${row.index}`"
853
- :aria-selected="row.value === selected"
610
+ :aria-selected="row.selected"
854
611
  :aria-disabled="row.disabled"
855
612
  :data-index="row.index"
856
613
  :class="{ active: row.index === active }"
@@ -1094,6 +851,40 @@ input:disabled, button:disabled {
1094
851
  }
1095
852
  }
1096
853
 
854
+ /* Multiple mode: every option carries a checkbox, so a list that takes several answers says so
855
+ before anything is picked. aria-selected is the state; this draws it.
856
+ Longhands, not shorthands: lowering drops a shorthand that omits a component. */
857
+ [data-component~="ui-combobox"][data-ui-combobox-state~="multiple"] .option {
858
+ display: flex;
859
+ gap: var(--ui-space-2);
860
+ align-items: center;
861
+ }
862
+
863
+ [data-component~="ui-combobox"][data-ui-combobox-state~="multiple"] .option::before {
864
+ content: "";
865
+ flex: none;
866
+ inline-size: 1.125rem;
867
+ block-size: 1.125rem;
868
+ border-style: solid;
869
+ border-width: 1px;
870
+ border-color: var(--ui-control-border-hover, var(--ui-border-strong));
871
+ border-radius: var(--ui-radius-sm);
872
+ background-color: var(--ui-control-surface, var(--ui-surface-default));
873
+ background-repeat: no-repeat;
874
+ background-position: center;
875
+ background-size: 0.7rem;
876
+ }
877
+
878
+ [data-component~="ui-combobox"][data-ui-combobox-state~="multiple"]
879
+ .option[aria-selected="true"]::before {
880
+ border-color: var(--ui-accent-solid);
881
+ background-color: var(--ui-accent-solid);
882
+ background-image: var(
883
+ --ui-combobox-option-check,
884
+ url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-9'/%3E%3C/svg%3E")
885
+ );
886
+ }
887
+
1097
888
  /* Multiple mode: chips wrap before the cursor on one flexible field line. */
1098
889
  [data-component~="ui-combobox"][data-ui-combobox-state~="multiple"] .field {
1099
890
  flex-wrap: wrap;