@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-editable/ui-editable.js'
5
+ import { createDispatch, useComponentHost } from './host'
13
6
 
14
7
  defineOptions({ inheritAttrs: false })
15
8
 
@@ -74,156 +67,51 @@ const hostState = computed(() =>
74
67
  ].filter(Boolean).join(' ')
75
68
  )
76
69
 
77
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
78
- function dispatch(name: string, detail?: unknown): boolean {
79
- const declared: Record<string, EventInit | undefined> = {
80
- input: { bubbles: true, composed: true, cancelable: false },
81
- change: { bubbles: true, composed: true, cancelable: false },
82
- 'edit-change': { bubbles: true, composed: true, cancelable: false },
83
- }
84
- const checks: Record<string, (detail: unknown) => boolean> = {
85
- input: (detail) =>
86
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
87
- && typeof (detail as Record<string, unknown>)['value'] === 'string'
88
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
89
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
90
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
91
- && Object.keys(detail as object).every((key) => ['value', 'trigger'].includes(key)),
92
- change: (detail) =>
93
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
94
- && typeof (detail as Record<string, unknown>)['value'] === 'string'
95
- && typeof (detail as Record<string, unknown>)['previousValue'] === 'string'
96
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
97
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
98
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
99
- && Object.keys(detail as object).every((key) =>
100
- ['value', 'previousValue', 'trigger'].includes(key)
101
- ),
102
- 'edit-change': (detail) =>
103
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
104
- && typeof (detail as Record<string, unknown>)['edit'] === 'boolean'
105
- && ((detail as Record<string, unknown>)['reason'] === 'activate'
106
- || (detail as Record<string, unknown>)['reason'] === 'commit'
107
- || (detail as Record<string, unknown>)['reason'] === 'cancel'
108
- || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
109
- || (detail as Record<string, unknown>)['reason'] === 'escape'
110
- || (detail as Record<string, unknown>)['reason'] === 'programmatic')
111
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
112
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
113
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
114
- && Object.keys(detail as object).every((key) => ['edit', 'reason', 'trigger'].includes(key)),
115
- }
116
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
117
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
118
- }
119
- const emitEvent = emit as (name: string, detail: unknown) => void
120
- emitEvent(name, detail)
121
- if (detail !== null && typeof detail === 'object' && 'edit' in detail) {
122
- emitEvent('update:edit', (detail as Record<string, unknown>)['edit'])
123
- }
124
- if (detail !== null && typeof detail === 'object' && 'value' in detail) {
125
- emitEvent('update:value', (detail as Record<string, unknown>)['value'])
126
- }
127
- return root.value?.dispatchEvent(
128
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
129
- ) ?? true
130
- }
131
-
132
- function read(name: string): unknown {
133
- if (name === 'internalEdit') return internalEdit.value
134
- if (name === 'internalValue') return internalValue.value
135
- if (name === 'draft') return draft.value
136
- return (props as Record<string, unknown>)[name]
137
- }
138
-
139
- function write(name: string, value: unknown): boolean {
140
- if (name === 'internalEdit') {
141
- internalEdit.value = value as never
142
- return true
143
- }
144
- if (name === 'internalValue') {
145
- internalValue.value = value as never
146
- return true
147
- }
148
- if (name === 'draft') {
149
- draft.value = value as never
150
- return true
151
- }
152
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
153
- }
154
-
155
- const stops: Array<() => void> = []
156
- const host = {
157
- get element(): Element {
158
- return root.value as Element
159
- },
160
- state: new Proxy({} as Record<string, unknown>, {
161
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
162
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
163
- }),
164
- refs: {
165
- get preview(): Element {
166
- return previewElement.value as Element
167
- },
168
- get input(): Element {
169
- return inputElement.value as Element
170
- },
171
- } as Readonly<Record<string, Element>>,
172
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
173
- get: (_target, name) => {
174
- if (typeof name !== 'string' || root.value === null) return undefined
175
- const form = root.value instanceof HTMLFormElement
176
- ? root.value
177
- : root.value.querySelector('form')
178
- return form?.elements.namedItem(name)
179
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
180
- },
181
- }),
182
- signal<T>(initialValue: T) {
183
- const value = shallowRef(initialValue)
184
- return {
185
- get: (): T => value.value,
186
- set: (next: T): void => {
187
- if (!Object.is(value.value, next)) value.value = next
188
- },
189
- update: (next: (current: T) => T): void => {
190
- const updated = next(value.value)
191
- if (!Object.is(value.value, updated)) value.value = updated
192
- },
193
- }
194
- },
195
- computed<T>(compute: () => T) {
196
- const value = computed(compute)
197
- return { get: (): T => value.value }
198
- },
199
- effect(run: () => void | (() => void)): () => void {
200
- const stop = watchEffect((onCleanup) => {
201
- const cleanup = run()
202
- if (typeof cleanup === 'function') onCleanup(cleanup)
203
- }, { flush: 'post' })
204
- stops.push(stop)
205
- return stop
70
+ const isInputDetail = (detail: unknown): boolean =>
71
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
72
+ && typeof (detail as Record<string, unknown>)['value'] === 'string'
73
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
74
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
75
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
76
+ && Object.keys(detail as object).every((key) => ['value', 'trigger'].includes(key))
77
+ const isChangeDetail = (detail: unknown): boolean =>
78
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
79
+ && typeof (detail as Record<string, unknown>)['value'] === 'string'
80
+ && typeof (detail as Record<string, unknown>)['previousValue'] === 'string'
81
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
82
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
83
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
84
+ && Object.keys(detail as object).every((key) =>
85
+ ['value', 'previousValue', 'trigger'].includes(key)
86
+ )
87
+ const isEditChangeDetail = (detail: unknown): boolean =>
88
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
89
+ && typeof (detail as Record<string, unknown>)['edit'] === 'boolean'
90
+ && ((detail as Record<string, unknown>)['reason'] === 'activate'
91
+ || (detail as Record<string, unknown>)['reason'] === 'commit'
92
+ || (detail as Record<string, unknown>)['reason'] === 'cancel'
93
+ || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
94
+ || (detail as Record<string, unknown>)['reason'] === 'escape'
95
+ || (detail as Record<string, unknown>)['reason'] === 'programmatic')
96
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
97
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
98
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
99
+ && Object.keys(detail as object).every((key) => ['edit', 'reason', 'trigger'].includes(key))
100
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
101
+ checks: {
102
+ input: isInputDetail,
103
+ change: isChangeDetail,
104
+ 'edit-change': isEditChangeDetail,
206
105
  },
207
- on(event: string, listener: EventListener): () => void {
208
- const element = root.value
209
- element?.addEventListener(event, listener)
210
- const off = (): void => element?.removeEventListener(event, listener)
211
- stops.push(off)
212
- return off
213
- },
214
- dispatch,
215
- }
216
-
217
- let cleanup: void | (() => void)
218
- let ready: Promise<void> | undefined
219
- onMounted(() => {
220
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
221
- cleanup = result
222
- })
106
+ modeled: ['edit', 'value'],
223
107
  })
224
- onBeforeUnmount(() => {
225
- for (const stop of stops.splice(0)) stop()
226
- if (typeof cleanup === 'function') cleanup()
108
+
109
+ useComponentHost(controllerModule.default, {
110
+ root,
111
+ dispatch,
112
+ props,
113
+ refs: { preview: previewElement, input: inputElement },
114
+ state: { internalEdit, internalValue, draft },
227
115
  })
228
116
  </script>
229
117
 
@@ -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 { ref, useTemplateRef } from 'vue'
12
4
  import * as controllerModule from '../components/ui-editor-insert-table-grid/ui-editor-insert-table-grid.js'
5
+ import { createDispatch, useComponentHost } from './host'
13
6
 
14
7
  defineOptions({ inheritAttrs: false })
15
8
 
@@ -42,136 +35,24 @@ const cols = ref(8)
42
35
  const hint = ref('')
43
36
  const withHeaderRow = ref(false)
44
37
 
45
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
46
- function dispatch(name: string, detail?: unknown): boolean {
47
- const declared: Record<string, EventInit | undefined> = {
48
- insert: { bubbles: true, composed: true, cancelable: false },
49
- }
50
- const checks: Record<string, (detail: unknown) => boolean> = {
51
- insert: (detail) =>
52
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
53
- && Number.isInteger((detail as Record<string, unknown>)['rows'])
54
- && Number.isInteger((detail as Record<string, unknown>)['cols'])
55
- && typeof (detail as Record<string, unknown>)['withHeaderRow'] === 'boolean'
56
- && Object.keys(detail as object).every((key) =>
57
- ['rows', 'cols', 'withHeaderRow'].includes(key)
58
- ),
59
- }
60
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
61
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
62
- }
63
- const emitEvent = emit as (name: string, detail: unknown) => void
64
- emitEvent(name, detail)
65
- return root.value?.dispatchEvent(
66
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
67
- ) ?? true
68
- }
69
-
70
- function read(name: string): unknown {
71
- if (name === 'cells') return cells.value
72
- if (name === 'rows') return rows.value
73
- if (name === 'cols') return cols.value
74
- if (name === 'hint') return hint.value
75
- if (name === 'withHeaderRow') return withHeaderRow.value
76
- return (props as Record<string, unknown>)[name]
77
- }
78
-
79
- function write(name: string, value: unknown): boolean {
80
- if (name === 'cells') {
81
- cells.value = value as never
82
- return true
83
- }
84
- if (name === 'rows') {
85
- rows.value = value as never
86
- return true
87
- }
88
- if (name === 'cols') {
89
- cols.value = value as never
90
- return true
91
- }
92
- if (name === 'hint') {
93
- hint.value = value as never
94
- return true
95
- }
96
- if (name === 'withHeaderRow') {
97
- withHeaderRow.value = value as never
98
- return true
99
- }
100
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
101
- }
102
-
103
- const stops: Array<() => void> = []
104
- const host = {
105
- get element(): Element {
106
- return root.value as Element
107
- },
108
- state: new Proxy({} as Record<string, unknown>, {
109
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
110
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
111
- }),
112
- refs: {
113
- get header(): Element {
114
- return headerElement.value as Element
115
- },
116
- get insert(): Element {
117
- return insertElement.value as Element
118
- },
119
- } as Readonly<Record<string, Element>>,
120
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
121
- get: (_target, name) => {
122
- if (typeof name !== 'string' || root.value === null) return undefined
123
- const form = root.value instanceof HTMLFormElement
124
- ? root.value
125
- : root.value.querySelector('form')
126
- return form?.elements.namedItem(name)
127
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
128
- },
129
- }),
130
- signal<T>(initialValue: T) {
131
- const value = shallowRef(initialValue)
132
- return {
133
- get: (): T => value.value,
134
- set: (next: T): void => {
135
- if (!Object.is(value.value, next)) value.value = next
136
- },
137
- update: (next: (current: T) => T): void => {
138
- const updated = next(value.value)
139
- if (!Object.is(value.value, updated)) value.value = updated
140
- },
141
- }
142
- },
143
- computed<T>(compute: () => T) {
144
- const value = computed(compute)
145
- return { get: (): T => value.value }
38
+ const isInsertDetail = (detail: unknown): boolean =>
39
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
40
+ && Number.isInteger((detail as Record<string, unknown>)['rows'])
41
+ && Number.isInteger((detail as Record<string, unknown>)['cols'])
42
+ && typeof (detail as Record<string, unknown>)['withHeaderRow'] === 'boolean'
43
+ && Object.keys(detail as object).every((key) => ['rows', 'cols', 'withHeaderRow'].includes(key))
44
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
45
+ checks: {
46
+ insert: isInsertDetail,
146
47
  },
147
- effect(run: () => void | (() => void)): () => void {
148
- const stop = watchEffect((onCleanup) => {
149
- const cleanup = run()
150
- if (typeof cleanup === 'function') onCleanup(cleanup)
151
- }, { flush: 'post' })
152
- stops.push(stop)
153
- return stop
154
- },
155
- on(event: string, listener: EventListener): () => void {
156
- const element = root.value
157
- element?.addEventListener(event, listener)
158
- const off = (): void => element?.removeEventListener(event, listener)
159
- stops.push(off)
160
- return off
161
- },
162
- dispatch,
163
- }
164
-
165
- let cleanup: void | (() => void)
166
- let ready: Promise<void> | undefined
167
- onMounted(() => {
168
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
169
- cleanup = result
170
- })
171
48
  })
172
- onBeforeUnmount(() => {
173
- for (const stop of stops.splice(0)) stop()
174
- if (typeof cleanup === 'function') cleanup()
49
+
50
+ useComponentHost(controllerModule.default, {
51
+ root,
52
+ dispatch,
53
+ props,
54
+ refs: { header: headerElement, insert: insertElement },
55
+ state: { cells, rows, cols, hint, withHeaderRow },
175
56
  })
176
57
  </script>
177
58
 
@@ -1,7 +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 { computed, onBeforeUnmount, onMounted, ref, shallowRef, watchEffect } from 'vue'
3
+ import { ref } from 'vue'
4
4
  import * as controllerModule from '../components/ui-editor-mention-menu/ui-editor-mention-menu.js'
5
+ import { createDispatch, useComponentHost } from './host'
5
6
 
6
7
  defineOptions({ inheritAttrs: false })
7
8
 
@@ -48,130 +49,22 @@ const searching = ref(false)
48
49
  const active = ref(0)
49
50
  const prefix = ref('ui-editor-mention-menu')
50
51
 
51
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
52
- function dispatch(name: string, detail?: unknown): boolean {
53
- const declared: Record<string, EventInit | undefined> = {
54
- highlight: { bubbles: true, composed: true, cancelable: false },
55
- select: { bubbles: true, composed: true, cancelable: false },
56
- }
57
- const checks: Record<string, (detail: unknown) => boolean> = {
58
- highlight: (detail) =>
59
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
60
- && Number.isInteger((detail as Record<string, unknown>)['index'])
61
- && Object.keys(detail as object).every((key) => ['index'].includes(key)),
62
- select: (detail) =>
63
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
64
- && Number.isInteger((detail as Record<string, unknown>)['index'])
65
- && Object.keys(detail as object).every((key) => ['index'].includes(key)),
66
- }
67
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
68
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
69
- }
70
- const emitEvent = emit as (name: string, detail: unknown) => void
71
- emitEvent(name, detail)
72
- return root.value?.dispatchEvent(
73
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
74
- ) ?? true
75
- }
76
-
77
- function read(name: string): unknown {
78
- if (name === 'visible') return visible.value
79
- if (name === 'rows') return rows.value
80
- if (name === 'searching') return searching.value
81
- if (name === 'active') return active.value
82
- if (name === 'prefix') return prefix.value
83
- return (props as Record<string, unknown>)[name]
84
- }
85
-
86
- function write(name: string, value: unknown): boolean {
87
- if (name === 'visible') {
88
- visible.value = value as never
89
- return true
90
- }
91
- if (name === 'rows') {
92
- rows.value = value as never
93
- return true
94
- }
95
- if (name === 'searching') {
96
- searching.value = value as never
97
- return true
98
- }
99
- if (name === 'active') {
100
- active.value = value as never
101
- return true
102
- }
103
- if (name === 'prefix') {
104
- prefix.value = value as never
105
- return true
106
- }
107
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
108
- }
109
-
110
- const stops: Array<() => void> = []
111
- const host = {
112
- get element(): Element {
113
- return root.value as Element
114
- },
115
- state: new Proxy({} as Record<string, unknown>, {
116
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
117
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
118
- }),
119
- refs: {} as Readonly<Record<string, Element>>,
120
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
121
- get: (_target, name) => {
122
- if (typeof name !== 'string' || root.value === null) return undefined
123
- const form = root.value instanceof HTMLFormElement
124
- ? root.value
125
- : root.value.querySelector('form')
126
- return form?.elements.namedItem(name)
127
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
128
- },
129
- }),
130
- signal<T>(initialValue: T) {
131
- const value = shallowRef(initialValue)
132
- return {
133
- get: (): T => value.value,
134
- set: (next: T): void => {
135
- if (!Object.is(value.value, next)) value.value = next
136
- },
137
- update: (next: (current: T) => T): void => {
138
- const updated = next(value.value)
139
- if (!Object.is(value.value, updated)) value.value = updated
140
- },
141
- }
142
- },
143
- computed<T>(compute: () => T) {
144
- const value = computed(compute)
145
- return { get: (): T => value.value }
146
- },
147
- effect(run: () => void | (() => void)): () => void {
148
- const stop = watchEffect((onCleanup) => {
149
- const cleanup = run()
150
- if (typeof cleanup === 'function') onCleanup(cleanup)
151
- }, { flush: 'post' })
152
- stops.push(stop)
153
- return stop
154
- },
155
- on(event: string, listener: EventListener): () => void {
156
- const element = root.value
157
- element?.addEventListener(event, listener)
158
- const off = (): void => element?.removeEventListener(event, listener)
159
- stops.push(off)
160
- return off
52
+ const isHighlightDetail = (detail: unknown): boolean =>
53
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
54
+ && Number.isInteger((detail as Record<string, unknown>)['index'])
55
+ && Object.keys(detail as object).every((key) => ['index'].includes(key))
56
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
57
+ checks: {
58
+ highlight: isHighlightDetail,
59
+ select: isHighlightDetail,
161
60
  },
162
- dispatch,
163
- }
164
-
165
- let cleanup: void | (() => void)
166
- let ready: Promise<void> | undefined
167
- onMounted(() => {
168
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
169
- cleanup = result
170
- })
171
61
  })
172
- onBeforeUnmount(() => {
173
- for (const stop of stops.splice(0)) stop()
174
- if (typeof cleanup === 'function') cleanup()
62
+
63
+ useComponentHost(controllerModule.default, {
64
+ root,
65
+ dispatch,
66
+ props,
67
+ state: { visible, rows, searching, active, prefix },
175
68
  })
176
69
  </script>
177
70