@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
package/vue/UiMenu.vue CHANGED
@@ -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 { computed, ref } from 'vue'
4
4
  import * as controllerModule from '../components/ui-menu/ui-menu.js'
5
+ import { createDispatch, useComponentHost } from './host'
5
6
 
6
7
  defineOptions({ inheritAttrs: false })
7
8
 
@@ -51,133 +52,47 @@ const hostState = computed(() =>
51
52
  ].filter(Boolean).join(' ')
52
53
  )
53
54
 
54
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
55
- function dispatch(name: string, detail?: unknown): boolean {
56
- const declared: Record<string, EventInit | undefined> = {
57
- select: { bubbles: true, composed: true, cancelable: false },
58
- open: { bubbles: true, composed: true, cancelable: false },
59
- close: { bubbles: true, composed: true, cancelable: false },
60
- }
61
- const checks: Record<string, (detail: unknown) => boolean> = {
62
- select: (detail) =>
63
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
64
- && typeof (detail as Record<string, unknown>)['value'] === 'string'
65
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
66
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
67
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
68
- && Object.keys(detail as object).every((key) => ['value', 'trigger'].includes(key)),
69
- open: (detail) =>
70
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
71
- && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
72
- && ((detail as Record<string, unknown>)['reason'] === 'action'
73
- || (detail as Record<string, unknown>)['reason'] === 'programmatic')
74
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
75
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
76
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
77
- && Object.keys(detail as object).every((key) => ['open', 'reason', 'trigger'].includes(key)),
78
- close: (detail) =>
79
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
80
- && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
81
- && ((detail as Record<string, unknown>)['reason'] === 'action'
82
- || (detail as Record<string, unknown>)['reason'] === 'programmatic'
83
- || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
84
- || (detail as Record<string, unknown>)['reason'] === 'escape')
85
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
86
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
87
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
88
- && Object.keys(detail as object).every((key) => ['open', 'reason', 'trigger'].includes(key)),
89
- }
90
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
91
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
92
- }
93
- const emitEvent = emit as (name: string, detail: unknown) => void
94
- emitEvent(name, detail)
95
- if (detail !== null && typeof detail === 'object' && 'open' in detail) {
96
- emitEvent('update:open', (detail as Record<string, unknown>)['open'])
97
- }
98
- return root.value?.dispatchEvent(
99
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
100
- ) ?? true
101
- }
102
-
103
- function read(name: string): unknown {
104
- if (name === 'internalOpen') return internalOpen.value
105
- return (props as Record<string, unknown>)[name]
106
- }
107
-
108
- function write(name: string, value: unknown): boolean {
109
- if (name === 'internalOpen') {
110
- internalOpen.value = value as never
111
- return true
112
- }
113
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
114
- }
115
-
116
- const stops: Array<() => void> = []
117
- const host = {
118
- get element(): Element {
119
- return root.value as Element
55
+ const isSelectDetail = (detail: unknown): boolean =>
56
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
57
+ && typeof (detail as Record<string, unknown>)['value'] === 'string'
58
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
59
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
60
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
61
+ && Object.keys(detail as object).every((key) => ['value', 'trigger'].includes(key))
62
+ const isOpenDetail = (detail: unknown): boolean =>
63
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
64
+ && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
65
+ && ((detail as Record<string, unknown>)['reason'] === 'action'
66
+ || (detail as Record<string, unknown>)['reason'] === 'programmatic')
67
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
68
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
69
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
70
+ && Object.keys(detail as object).every((key) => ['open', 'reason', 'trigger'].includes(key))
71
+ const isCloseDetail = (detail: unknown): boolean =>
72
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
73
+ && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
74
+ && ((detail as Record<string, unknown>)['reason'] === 'action'
75
+ || (detail as Record<string, unknown>)['reason'] === 'programmatic'
76
+ || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
77
+ || (detail as Record<string, unknown>)['reason'] === 'escape')
78
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
79
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
80
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
81
+ && Object.keys(detail as object).every((key) => ['open', 'reason', 'trigger'].includes(key))
82
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
83
+ checks: {
84
+ select: isSelectDetail,
85
+ open: isOpenDetail,
86
+ close: isCloseDetail,
120
87
  },
121
- state: new Proxy({} as Record<string, unknown>, {
122
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
123
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
124
- }),
125
- refs: {} as Readonly<Record<string, Element>>,
126
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
127
- get: (_target, name) => {
128
- if (typeof name !== 'string' || root.value === null) return undefined
129
- const form = root.value instanceof HTMLFormElement
130
- ? root.value
131
- : root.value.querySelector('form')
132
- return form?.elements.namedItem(name)
133
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
134
- },
135
- }),
136
- signal<T>(initialValue: T) {
137
- const value = shallowRef(initialValue)
138
- return {
139
- get: (): T => value.value,
140
- set: (next: T): void => {
141
- if (!Object.is(value.value, next)) value.value = next
142
- },
143
- update: (next: (current: T) => T): void => {
144
- const updated = next(value.value)
145
- if (!Object.is(value.value, updated)) value.value = updated
146
- },
147
- }
148
- },
149
- computed<T>(compute: () => T) {
150
- const value = computed(compute)
151
- return { get: (): T => value.value }
152
- },
153
- effect(run: () => void | (() => void)): () => void {
154
- const stop = watchEffect((onCleanup) => {
155
- const cleanup = run()
156
- if (typeof cleanup === 'function') onCleanup(cleanup)
157
- }, { flush: 'post' })
158
- stops.push(stop)
159
- return stop
160
- },
161
- on(event: string, listener: EventListener): () => void {
162
- const element = root.value
163
- element?.addEventListener(event, listener)
164
- const off = (): void => element?.removeEventListener(event, listener)
165
- stops.push(off)
166
- return off
167
- },
168
- dispatch,
169
- }
170
-
171
- let cleanup: void | (() => void)
172
- let ready: Promise<void> | undefined
173
- onMounted(() => {
174
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
175
- cleanup = result
176
- })
88
+ modeled: ['open'],
177
89
  })
178
- onBeforeUnmount(() => {
179
- for (const stop of stops.splice(0)) stop()
180
- if (typeof cleanup === 'function') cleanup()
90
+
91
+ useComponentHost(controllerModule.default, {
92
+ root,
93
+ dispatch,
94
+ props,
95
+ state: { internalOpen },
181
96
  })
182
97
  </script>
183
98
 
@@ -1,4 +1,4 @@
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
3
  defineOptions({ inheritAttrs: false })
4
4
 
package/vue/UiPopover.vue CHANGED
@@ -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 { computed, ref } from 'vue'
4
4
  import * as controllerModule from '../components/ui-popover/ui-popover.js'
5
+ import { createDispatch, useComponentHost } from './host'
5
6
 
6
7
  defineOptions({ inheritAttrs: false })
7
8
 
@@ -45,127 +46,30 @@ const hostState = computed(() =>
45
46
  ].filter(Boolean).join(' ')
46
47
  )
47
48
 
48
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
49
- function dispatch(name: string, detail?: unknown): boolean {
50
- const declared: Record<string, EventInit | undefined> = {
51
- open: { bubbles: true, composed: true, cancelable: false },
52
- close: { bubbles: true, composed: true, cancelable: false },
53
- }
54
- const checks: Record<string, (detail: unknown) => boolean> = {
55
- open: (detail) =>
56
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
57
- && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
58
- && ((detail as Record<string, unknown>)['reason'] === 'action'
59
- || (detail as Record<string, unknown>)['reason'] === 'programmatic'
60
- || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
61
- || (detail as Record<string, unknown>)['reason'] === 'escape')
62
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
63
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
64
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
65
- && Object.keys(detail as object).every((key) => ['open', 'reason', 'trigger'].includes(key)),
66
- close: (detail) =>
67
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
68
- && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
69
- && ((detail as Record<string, unknown>)['reason'] === 'action'
70
- || (detail as Record<string, unknown>)['reason'] === 'programmatic'
71
- || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
72
- || (detail as Record<string, unknown>)['reason'] === 'escape')
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) => ['open', 'reason', 'trigger'].includes(key)),
77
- }
78
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
79
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
80
- }
81
- const emitEvent = emit as (name: string, detail: unknown) => void
82
- emitEvent(name, detail)
83
- if (detail !== null && typeof detail === 'object' && 'open' in detail) {
84
- emitEvent('update:open', (detail as Record<string, unknown>)['open'])
85
- }
86
- return root.value?.dispatchEvent(
87
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
88
- ) ?? true
89
- }
90
-
91
- function read(name: string): unknown {
92
- if (name === 'internalOpen') return internalOpen.value
93
- return (props as Record<string, unknown>)[name]
94
- }
95
-
96
- function write(name: string, value: unknown): boolean {
97
- if (name === 'internalOpen') {
98
- internalOpen.value = value as never
99
- return true
100
- }
101
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
102
- }
103
-
104
- const stops: Array<() => void> = []
105
- const host = {
106
- get element(): Element {
107
- return root.value as Element
49
+ const isOpenDetail = (detail: unknown): boolean =>
50
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
51
+ && typeof (detail as Record<string, unknown>)['open'] === 'boolean'
52
+ && ((detail as Record<string, unknown>)['reason'] === 'action'
53
+ || (detail as Record<string, unknown>)['reason'] === 'programmatic'
54
+ || (detail as Record<string, unknown>)['reason'] === 'light-dismiss'
55
+ || (detail as Record<string, unknown>)['reason'] === 'escape')
56
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
57
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
58
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
59
+ && Object.keys(detail as object).every((key) => ['open', 'reason', 'trigger'].includes(key))
60
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
61
+ checks: {
62
+ open: isOpenDetail,
63
+ close: isOpenDetail,
108
64
  },
109
- state: new Proxy({} as Record<string, unknown>, {
110
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
111
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
112
- }),
113
- refs: {} as Readonly<Record<string, Element>>,
114
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
115
- get: (_target, name) => {
116
- if (typeof name !== 'string' || root.value === null) return undefined
117
- const form = root.value instanceof HTMLFormElement
118
- ? root.value
119
- : root.value.querySelector('form')
120
- return form?.elements.namedItem(name)
121
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
122
- },
123
- }),
124
- signal<T>(initialValue: T) {
125
- const value = shallowRef(initialValue)
126
- return {
127
- get: (): T => value.value,
128
- set: (next: T): void => {
129
- if (!Object.is(value.value, next)) value.value = next
130
- },
131
- update: (next: (current: T) => T): void => {
132
- const updated = next(value.value)
133
- if (!Object.is(value.value, updated)) value.value = updated
134
- },
135
- }
136
- },
137
- computed<T>(compute: () => T) {
138
- const value = computed(compute)
139
- return { get: (): T => value.value }
140
- },
141
- effect(run: () => void | (() => void)): () => void {
142
- const stop = watchEffect((onCleanup) => {
143
- const cleanup = run()
144
- if (typeof cleanup === 'function') onCleanup(cleanup)
145
- }, { flush: 'post' })
146
- stops.push(stop)
147
- return stop
148
- },
149
- on(event: string, listener: EventListener): () => void {
150
- const element = root.value
151
- element?.addEventListener(event, listener)
152
- const off = (): void => element?.removeEventListener(event, listener)
153
- stops.push(off)
154
- return off
155
- },
156
- dispatch,
157
- }
158
-
159
- let cleanup: void | (() => void)
160
- let ready: Promise<void> | undefined
161
- onMounted(() => {
162
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
163
- cleanup = result
164
- })
65
+ modeled: ['open'],
165
66
  })
166
- onBeforeUnmount(() => {
167
- for (const stop of stops.splice(0)) stop()
168
- if (typeof cleanup === 'function') cleanup()
67
+
68
+ useComponentHost(controllerModule.default, {
69
+ root,
70
+ dispatch,
71
+ props,
72
+ state: { internalOpen },
169
73
  })
170
74
  </script>
171
75
 
package/vue/UiRadio.vue CHANGED
@@ -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-radio/ui-radio.js'
5
+ import { createDispatch, useComponentHost } from './host'
13
6
 
14
7
  defineOptions({ inheritAttrs: false })
15
8
 
@@ -52,121 +45,27 @@ const hostState = computed(() =>
52
45
  ].filter(Boolean).join(' ')
53
46
  )
54
47
 
55
- /** Dispatches a component event to Vue listeners and, for controllers and page code, on the root. */
56
- function dispatch(name: string, detail?: unknown): boolean {
57
- const declared: Record<string, EventInit | undefined> = {
58
- change: { bubbles: true, composed: true, cancelable: false },
59
- }
60
- const checks: Record<string, (detail: unknown) => boolean> = {
61
- change: (detail) =>
62
- detail !== null && typeof detail === 'object' && !Array.isArray(detail)
63
- && typeof (detail as Record<string, unknown>)['checked'] === 'boolean'
64
- && typeof (detail as Record<string, unknown>)['value'] === 'string'
65
- && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
66
- || (detail as Record<string, unknown>)['trigger'] === 'pointer'
67
- || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
68
- && Object.keys(detail as object).every((key) =>
69
- ['checked', 'value', 'trigger'].includes(key)
70
- ),
71
- }
72
- if (detail !== undefined && checks[name] !== undefined && !checks[name]!(detail)) {
73
- throw new TypeError(`HR002: Event \`${name}\` detail does not satisfy its declared type.`)
74
- }
75
- const emitEvent = emit as (name: string, detail: unknown) => void
76
- emitEvent(name, detail)
77
- if (detail !== null && typeof detail === 'object' && 'checked' in detail) {
78
- emitEvent('update:checked', (detail as Record<string, unknown>)['checked'])
79
- }
80
- if (detail !== null && typeof detail === 'object' && 'value' in detail) {
81
- emitEvent('update:value', (detail as Record<string, unknown>)['value'])
82
- }
83
- return root.value?.dispatchEvent(
84
- new CustomEvent(name, { bubbles: true, composed: true, ...declared[name], detail }),
85
- ) ?? true
86
- }
87
-
88
- function read(name: string): unknown {
89
- if (name === 'internalChecked') return internalChecked.value
90
- return (props as Record<string, unknown>)[name]
91
- }
92
-
93
- function write(name: string, value: unknown): boolean {
94
- if (name === 'internalChecked') {
95
- internalChecked.value = value as never
96
- return true
97
- }
98
- throw new TypeError(`Only declared state is writable; \`${name}\` is not.`)
99
- }
100
-
101
- const stops: Array<() => void> = []
102
- const host = {
103
- get element(): Element {
104
- return root.value as Element
105
- },
106
- state: new Proxy({} as Record<string, unknown>, {
107
- get: (_target, name) => typeof name === 'string' ? read(name) : undefined,
108
- set: (_target, name, value) => typeof name === 'string' && write(name, value),
109
- }),
110
- refs: {
111
- get input(): Element {
112
- return inputElement.value as Element
113
- },
114
- } as Readonly<Record<string, Element>>,
115
- elements: new Proxy({} as Record<string, Element | RadioNodeList | undefined>, {
116
- get: (_target, name) => {
117
- if (typeof name !== 'string' || root.value === null) return undefined
118
- const form = root.value instanceof HTMLFormElement
119
- ? root.value
120
- : root.value.querySelector('form')
121
- return form?.elements.namedItem(name)
122
- ?? root.value.querySelector(`[name="${CSS.escape(name)}"]`) ?? undefined
123
- },
124
- }),
125
- signal<T>(initialValue: T) {
126
- const value = shallowRef(initialValue)
127
- return {
128
- get: (): T => value.value,
129
- set: (next: T): void => {
130
- if (!Object.is(value.value, next)) value.value = next
131
- },
132
- update: (next: (current: T) => T): void => {
133
- const updated = next(value.value)
134
- if (!Object.is(value.value, updated)) value.value = updated
135
- },
136
- }
48
+ const isChangeDetail = (detail: unknown): boolean =>
49
+ detail !== null && typeof detail === 'object' && !Array.isArray(detail)
50
+ && typeof (detail as Record<string, unknown>)['checked'] === 'boolean'
51
+ && typeof (detail as Record<string, unknown>)['value'] === 'string'
52
+ && ((detail as Record<string, unknown>)['trigger'] === 'keyboard'
53
+ || (detail as Record<string, unknown>)['trigger'] === 'pointer'
54
+ || (detail as Record<string, unknown>)['trigger'] === 'programmatic')
55
+ && Object.keys(detail as object).every((key) => ['checked', 'value', 'trigger'].includes(key))
56
+ const dispatch = createDispatch(root, emit as (name: string, detail: unknown) => void, {
57
+ checks: {
58
+ change: isChangeDetail,
137
59
  },
138
- computed<T>(compute: () => T) {
139
- const value = computed(compute)
140
- return { get: (): T => value.value }
141
- },
142
- effect(run: () => void | (() => void)): () => void {
143
- const stop = watchEffect((onCleanup) => {
144
- const cleanup = run()
145
- if (typeof cleanup === 'function') onCleanup(cleanup)
146
- }, { flush: 'post' })
147
- stops.push(stop)
148
- return stop
149
- },
150
- on(event: string, listener: EventListener): () => void {
151
- const element = root.value
152
- element?.addEventListener(event, listener)
153
- const off = (): void => element?.removeEventListener(event, listener)
154
- stops.push(off)
155
- return off
156
- },
157
- dispatch,
158
- }
159
-
160
- let cleanup: void | (() => void)
161
- let ready: Promise<void> | undefined
162
- onMounted(() => {
163
- ready = Promise.resolve(controllerModule.default(host as never)).then((result) => {
164
- cleanup = result
165
- })
60
+ modeled: ['checked', 'value'],
166
61
  })
167
- onBeforeUnmount(() => {
168
- for (const stop of stops.splice(0)) stop()
169
- if (typeof cleanup === 'function') cleanup()
62
+
63
+ useComponentHost(controllerModule.default, {
64
+ root,
65
+ dispatch,
66
+ props,
67
+ refs: { input: inputElement },
68
+ state: { internalChecked },
170
69
  })
171
70
  </script>
172
71
 
@@ -35,8 +35,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
35
35
  }) => any) | undefined;
36
36
  "onUpdate:value"?: ((value: string) => any) | undefined;
37
37
  }>, {
38
- label: string;
39
38
  name: string;
39
+ label: string;
40
40
  value: string;
41
41
  disabled: boolean;
42
42
  required: boolean;