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