foldkit 0.100.1 → 0.102.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 (217) hide show
  1. package/README.md +3 -2
  2. package/dist/canvas/view.d.ts +1 -1
  3. package/dist/canvas/view.d.ts.map +1 -1
  4. package/dist/canvas/view.js +5 -5
  5. package/dist/command/index.d.ts +71 -0
  6. package/dist/command/index.d.ts.map +1 -1
  7. package/dist/command/index.js +34 -1
  8. package/dist/command/public.d.ts +1 -1
  9. package/dist/command/public.d.ts.map +1 -1
  10. package/dist/command/public.js +1 -1
  11. package/dist/devTools/overlay.d.ts.map +1 -1
  12. package/dist/devTools/overlay.js +156 -149
  13. package/dist/dom/dom.d.ts +8 -11
  14. package/dist/dom/dom.d.ts.map +1 -1
  15. package/dist/dom/dom.js +8 -11
  16. package/dist/dom/elementMovement.d.ts +1 -3
  17. package/dist/dom/elementMovement.d.ts.map +1 -1
  18. package/dist/dom/elementMovement.js +1 -3
  19. package/dist/dom/inert.d.ts +2 -4
  20. package/dist/dom/inert.d.ts.map +1 -1
  21. package/dist/dom/inert.js +2 -4
  22. package/dist/dom/scrollLock.d.ts +2 -2
  23. package/dist/dom/scrollLock.js +2 -2
  24. package/dist/dom/waitForAnimation.d.ts +1 -1
  25. package/dist/dom/waitForAnimation.js +1 -1
  26. package/dist/html/boundary.d.ts +98 -0
  27. package/dist/html/boundary.d.ts.map +1 -0
  28. package/dist/html/boundary.js +176 -0
  29. package/dist/html/childAttribute.d.ts +44 -0
  30. package/dist/html/childAttribute.d.ts.map +1 -0
  31. package/dist/html/childAttribute.js +34 -0
  32. package/dist/html/index.d.ts +70 -23
  33. package/dist/html/index.d.ts.map +1 -1
  34. package/dist/html/index.js +639 -575
  35. package/dist/html/lazy.d.ts +12 -7
  36. package/dist/html/lazy.d.ts.map +1 -1
  37. package/dist/html/lazy.js +30 -11
  38. package/dist/html/public.d.ts +2 -2
  39. package/dist/html/public.d.ts.map +1 -1
  40. package/dist/html/public.js +1 -1
  41. package/dist/html/runtimeSingleton.d.ts +72 -0
  42. package/dist/html/runtimeSingleton.d.ts.map +1 -0
  43. package/dist/html/runtimeSingleton.js +112 -0
  44. package/dist/html/submodel.d.ts +98 -0
  45. package/dist/html/submodel.d.ts.map +1 -0
  46. package/dist/html/submodel.js +190 -0
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +1 -0
  50. package/dist/render/render.d.ts +1 -1
  51. package/dist/render/render.js +1 -1
  52. package/dist/runtime/messagePriority.d.ts +5 -1
  53. package/dist/runtime/messagePriority.d.ts.map +1 -1
  54. package/dist/runtime/messagePriority.js +25 -4
  55. package/dist/runtime/runtime.d.ts +11 -11
  56. package/dist/runtime/runtime.d.ts.map +1 -1
  57. package/dist/runtime/runtime.js +118 -63
  58. package/dist/runtime/subscription.d.ts +139 -19
  59. package/dist/runtime/subscription.d.ts.map +1 -1
  60. package/dist/runtime/subscription.js +90 -9
  61. package/dist/submodel/public.d.ts +4 -0
  62. package/dist/submodel/public.d.ts.map +1 -0
  63. package/dist/submodel/public.js +1 -0
  64. package/dist/submodel/submodel.d.ts +32 -0
  65. package/dist/submodel/submodel.d.ts.map +1 -0
  66. package/dist/submodel/submodel.js +1 -0
  67. package/dist/subscription/animationFrame.d.ts +23 -26
  68. package/dist/subscription/animationFrame.d.ts.map +1 -1
  69. package/dist/subscription/animationFrame.js +17 -18
  70. package/dist/subscription/public.d.ts +2 -2
  71. package/dist/subscription/public.d.ts.map +1 -1
  72. package/dist/subscription/public.js +1 -1
  73. package/dist/test/apps/disabledButton.d.ts +4 -5
  74. package/dist/test/apps/disabledButton.d.ts.map +1 -1
  75. package/dist/test/apps/disabledButton.js +16 -16
  76. package/dist/test/scene.d.ts +8 -8
  77. package/dist/test/scene.d.ts.map +1 -1
  78. package/dist/test/scene.js +25 -13
  79. package/dist/test/story.d.ts +15 -8
  80. package/dist/test/story.d.ts.map +1 -1
  81. package/dist/test/story.js +21 -9
  82. package/dist/ui/animation/index.d.ts +30 -14
  83. package/dist/ui/animation/index.d.ts.map +1 -1
  84. package/dist/ui/animation/index.js +9 -19
  85. package/dist/ui/animation/public.d.ts +2 -2
  86. package/dist/ui/animation/public.d.ts.map +1 -1
  87. package/dist/ui/animation/public.js +1 -1
  88. package/dist/ui/calendar/index.d.ts +199 -84
  89. package/dist/ui/calendar/index.d.ts.map +1 -1
  90. package/dist/ui/calendar/index.js +129 -140
  91. package/dist/ui/calendar/public.d.ts +2 -2
  92. package/dist/ui/calendar/public.d.ts.map +1 -1
  93. package/dist/ui/calendar/public.js +1 -1
  94. package/dist/ui/checkbox/index.d.ts +93 -21
  95. package/dist/ui/checkbox/index.d.ts.map +1 -1
  96. package/dist/ui/checkbox/index.js +62 -33
  97. package/dist/ui/checkbox/public.d.ts +2 -2
  98. package/dist/ui/checkbox/public.d.ts.map +1 -1
  99. package/dist/ui/checkbox/public.js +1 -1
  100. package/dist/ui/combobox/multi.d.ts +35 -91
  101. package/dist/ui/combobox/multi.d.ts.map +1 -1
  102. package/dist/ui/combobox/multi.js +34 -17
  103. package/dist/ui/combobox/multiPublic.d.ts +2 -2
  104. package/dist/ui/combobox/multiPublic.d.ts.map +1 -1
  105. package/dist/ui/combobox/multiPublic.js +1 -1
  106. package/dist/ui/combobox/public.d.ts +3 -3
  107. package/dist/ui/combobox/public.d.ts.map +1 -1
  108. package/dist/ui/combobox/public.js +2 -2
  109. package/dist/ui/combobox/shared.d.ts +56 -31
  110. package/dist/ui/combobox/shared.d.ts.map +1 -1
  111. package/dist/ui/combobox/shared.js +333 -322
  112. package/dist/ui/combobox/single.d.ts +46 -93
  113. package/dist/ui/combobox/single.d.ts.map +1 -1
  114. package/dist/ui/combobox/single.js +44 -17
  115. package/dist/ui/datePicker/index.d.ts +256 -48
  116. package/dist/ui/datePicker/index.d.ts.map +1 -1
  117. package/dist/ui/datePicker/index.js +149 -104
  118. package/dist/ui/datePicker/public.d.ts +2 -2
  119. package/dist/ui/datePicker/public.d.ts.map +1 -1
  120. package/dist/ui/datePicker/public.js +1 -1
  121. package/dist/ui/dialog/index.d.ts +95 -39
  122. package/dist/ui/dialog/index.d.ts.map +1 -1
  123. package/dist/ui/dialog/index.js +71 -62
  124. package/dist/ui/dialog/public.d.ts +2 -2
  125. package/dist/ui/dialog/public.d.ts.map +1 -1
  126. package/dist/ui/dialog/public.js +1 -1
  127. package/dist/ui/disclosure/index.d.ts +71 -31
  128. package/dist/ui/disclosure/index.d.ts.map +1 -1
  129. package/dist/ui/disclosure/index.js +57 -62
  130. package/dist/ui/disclosure/public.d.ts +2 -2
  131. package/dist/ui/disclosure/public.d.ts.map +1 -1
  132. package/dist/ui/disclosure/public.js +1 -1
  133. package/dist/ui/dragAndDrop/index.d.ts +385 -103
  134. package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
  135. package/dist/ui/dragAndDrop/index.js +26 -31
  136. package/dist/ui/dragAndDrop/public.d.ts +1 -1
  137. package/dist/ui/dragAndDrop/public.d.ts.map +1 -1
  138. package/dist/ui/dragAndDrop/public.js +1 -1
  139. package/dist/ui/fileDrop/index.d.ts +42 -46
  140. package/dist/ui/fileDrop/index.d.ts.map +1 -1
  141. package/dist/ui/fileDrop/index.js +30 -46
  142. package/dist/ui/fileDrop/public.d.ts +2 -2
  143. package/dist/ui/fileDrop/public.d.ts.map +1 -1
  144. package/dist/ui/fileDrop/public.js +1 -1
  145. package/dist/ui/listbox/multi.d.ts +39 -84
  146. package/dist/ui/listbox/multi.d.ts.map +1 -1
  147. package/dist/ui/listbox/multi.js +38 -20
  148. package/dist/ui/listbox/multiPublic.d.ts +2 -2
  149. package/dist/ui/listbox/multiPublic.d.ts.map +1 -1
  150. package/dist/ui/listbox/multiPublic.js +1 -1
  151. package/dist/ui/listbox/public.d.ts +3 -3
  152. package/dist/ui/listbox/public.d.ts.map +1 -1
  153. package/dist/ui/listbox/public.js +2 -2
  154. package/dist/ui/listbox/shared.d.ts +71 -30
  155. package/dist/ui/listbox/shared.d.ts.map +1 -1
  156. package/dist/ui/listbox/shared.js +319 -296
  157. package/dist/ui/listbox/single.d.ts +57 -85
  158. package/dist/ui/listbox/single.d.ts.map +1 -1
  159. package/dist/ui/listbox/single.js +48 -24
  160. package/dist/ui/menu/index.d.ts +80 -36
  161. package/dist/ui/menu/index.d.ts.map +1 -1
  162. package/dist/ui/menu/index.js +117 -86
  163. package/dist/ui/menu/public.d.ts +2 -2
  164. package/dist/ui/menu/public.d.ts.map +1 -1
  165. package/dist/ui/menu/public.js +1 -1
  166. package/dist/ui/popover/index.d.ts +117 -44
  167. package/dist/ui/popover/index.d.ts.map +1 -1
  168. package/dist/ui/popover/index.js +88 -101
  169. package/dist/ui/popover/public.d.ts +2 -2
  170. package/dist/ui/popover/public.d.ts.map +1 -1
  171. package/dist/ui/popover/public.js +1 -1
  172. package/dist/ui/radioGroup/index.d.ts +122 -45
  173. package/dist/ui/radioGroup/index.d.ts.map +1 -1
  174. package/dist/ui/radioGroup/index.js +111 -72
  175. package/dist/ui/radioGroup/public.d.ts +2 -2
  176. package/dist/ui/radioGroup/public.d.ts.map +1 -1
  177. package/dist/ui/radioGroup/public.js +1 -1
  178. package/dist/ui/slider/index.d.ts +247 -103
  179. package/dist/ui/slider/index.d.ts.map +1 -1
  180. package/dist/ui/slider/index.js +52 -68
  181. package/dist/ui/slider/public.d.ts +2 -2
  182. package/dist/ui/slider/public.d.ts.map +1 -1
  183. package/dist/ui/slider/public.js +1 -1
  184. package/dist/ui/switch/index.d.ts +74 -21
  185. package/dist/ui/switch/index.d.ts.map +1 -1
  186. package/dist/ui/switch/index.js +62 -33
  187. package/dist/ui/switch/public.d.ts +2 -2
  188. package/dist/ui/switch/public.d.ts.map +1 -1
  189. package/dist/ui/switch/public.js +1 -1
  190. package/dist/ui/tabs/index.d.ts +107 -45
  191. package/dist/ui/tabs/index.d.ts.map +1 -1
  192. package/dist/ui/tabs/index.js +99 -81
  193. package/dist/ui/tabs/public.d.ts +2 -2
  194. package/dist/ui/tabs/public.d.ts.map +1 -1
  195. package/dist/ui/tabs/public.js +1 -1
  196. package/dist/ui/toast/index.d.ts +93 -109
  197. package/dist/ui/toast/index.d.ts.map +1 -1
  198. package/dist/ui/toast/index.js +16 -29
  199. package/dist/ui/toast/schema.d.ts +15 -4
  200. package/dist/ui/toast/schema.d.ts.map +1 -1
  201. package/dist/ui/toast/schema.js +11 -4
  202. package/dist/ui/toast/update.d.ts +36 -18
  203. package/dist/ui/toast/update.d.ts.map +1 -1
  204. package/dist/ui/toast/update.js +33 -14
  205. package/dist/ui/tooltip/index.d.ts +94 -42
  206. package/dist/ui/tooltip/index.d.ts.map +1 -1
  207. package/dist/ui/tooltip/index.js +64 -73
  208. package/dist/ui/tooltip/public.d.ts +2 -2
  209. package/dist/ui/tooltip/public.d.ts.map +1 -1
  210. package/dist/ui/tooltip/public.js +1 -1
  211. package/dist/ui/virtualList/index.d.ts +63 -80
  212. package/dist/ui/virtualList/index.d.ts.map +1 -1
  213. package/dist/ui/virtualList/index.js +22 -49
  214. package/dist/ui/virtualList/public.d.ts +2 -2
  215. package/dist/ui/virtualList/public.d.ts.map +1 -1
  216. package/dist/ui/virtualList/public.js +1 -1
  217. package/package.json +1 -1
@@ -1,9 +1,30 @@
1
- import { Array, Context, Data, Effect, Fiber, Function, Match, Option, Predicate, Ref, Stream, String, pipe, } from 'effect';
1
+ import { Array, Context, Data, Effect, Fiber, Function, Match, Option, Predicate, Stream, String, pipe, } from 'effect';
2
2
  import { h } from 'snabbdom';
3
3
  import { MountTracker } from '../mount/index.js';
4
- import { Dispatch } from '../runtime/index.js';
4
+ import { isChildAttribute } from './childAttribute.js';
5
5
  import { checkScheduledLeave, clearDragZoneAfterDrop, getDragZoneState, processDragEnter, processDragLeave, } from './dragZoneTracking.js';
6
+ import { clearRuntime, requireDispatch, requireRuntimeContext, setRuntime, } from './runtimeSingleton.js';
7
+ import { submodel } from './submodel.js';
6
8
  export { createKeyedLazy, createLazy } from './lazy.js';
9
+ export { beginRender as __beginRender, createBoundaryRegistry as __createBoundaryRegistry, } from './boundary.js';
10
+ export { childAttributes } from './childAttribute.js';
11
+ export { defineView, submodel } from './submodel.js';
12
+ /** Pushes a dispatch and runtime context frame for the duration of a render.
13
+ * The runtime calls this immediately before invoking a user `view` and
14
+ * matches it with {@link __clearRuntime} in a `finally` so an exception
15
+ * inside view code does not leak the frame to the next render. Test
16
+ * scaffolding that builds VNodes outside of a real program (Scene, Canvas
17
+ * view-only tests, Mount tests) uses the same pair. Nested frames are
18
+ * supported via an internal stack. */
19
+ export const __setRuntime = setRuntime;
20
+ /** Pops the current dispatch and runtime context frame. Must be paired with a
21
+ * prior {@link __setRuntime} on the same call stack. */
22
+ export const __clearRuntime = clearRuntime;
23
+ /** Returns the current dispatch function. Foldkit's `Canvas.view` reads this
24
+ * to build its synchronous pointer handlers, since it builds VNodes directly
25
+ * rather than going through the html factory. Most application code never
26
+ * needs to call this. */
27
+ export const __requireDispatch = requireDispatch;
7
28
  /**
8
29
  * The `id` of the DOM element that hosts the Foldkit DevTools shadow root.
9
30
  * Lives here (not in `devTools/`) because the `OnBlur` handler below uses it
@@ -16,7 +37,7 @@ export const DEVTOOLS_HOST_ID = 'foldkit-devtools';
16
37
  * Tag symbol attached to file-aware event handler functions so Scene test
17
38
  * helpers can distinguish `OnFileChange` from `OnChange` (both register on
18
39
  * the DOM `change` event) and `OnDropFiles` from `OnDrop` (both register on
19
- * the DOM `drop` event). Internal implementation detail consumer code
40
+ * the DOM `drop` event). Internal implementation detail. Consumer code
20
41
  * should never need to reference this directly.
21
42
  */
22
43
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
@@ -41,580 +62,614 @@ const onMountStates = new WeakMap();
41
62
  export const FOLDKIT_MOUNT_KEY = 'foldkitMount';
42
63
  const { Key, Class, Id, Title, Lang, Dir, Tabindex, Hidden, Contenteditable, Draggable, Accesskey, Translate, Inert, Popover, Popovertarget, Popovertargetaction, OnClick, OnDoubleClick, OnMouseDown, OnMouseUp, OnMouseEnter, OnMouseLeave, OnMouseOver, OnMouseOut, OnMouseMove, OnPointerMove, OnPointerLeave, OnPointerDown, OnPointerUp, OnKeyDown, OnKeyDownPreventDefault, OnKeyUp, OnKeyUpPreventDefault, OnKeyPress, OnFocus, OnBlur, OnInput, OnChange, OnFileChange, OnSubmit, OnReset, OnScroll, OnWheel, OnCopy, OnCut, OnPaste, OnCancel, OnToggle, OnContextMenu, OnDragStart, OnDrag, OnDragEnd, OnDragEnter, OnDragLeave, OnDragOver, AllowDrop, OnDrop, OnDropFiles, OnTouchStart, OnTouchEnd, OnTouchMove, OnTouchCancel, OnAnimationStart, OnAnimationEnd, OnAnimationIteration, OnTransitionEnd, OnLoad, OnError, OnPlay, OnPause, OnEnded, OnTimeUpdate, OnVolumeChange, OnSelect, Value, Checked, Selected, Open, Placeholder, Name, Disabled, Readonly, Required, Autofocus, Spellcheck, Autocorrect, Autocapitalize, InputMode, EnterKeyHint, Multiple, Type, Accept, Autocomplete, Pattern, Maxlength, Minlength, Size, Cols, Rows, Max, Min, Step, For, Href, Src, Alt, Target, Rel, Download, Action, Method, Enctype, Novalidate, Formaction, Formmethod, Formnovalidate, Formtarget, Formenctype, Colspan, Rowspan, Scope, Headers, Span, Start, Reversed, CiteAttr, Datetime, Wrap, List, FormAttr, LabelAttr, ContentAttr, Charset, HttpEquiv, Srcset, Sizes, Loading, Decoding, Fetchpriority, Crossorigin, Referrerpolicy, Integrity, Hreflang, Ping, Sandbox, Allow, Srcdoc, Autoplay, Controls, Loop, Muted, Poster, Preload, Playsinline, High, Low, Optimum, Usemap, Ismap, Role, AriaLabel, AriaLabelledBy, AriaDescribedBy, AriaHidden, AriaExpanded, AriaSelected, AriaChecked, AriaDisabled, AriaRequired, AriaInvalid, AriaLive, AriaControls, AriaCurrent, AriaOrientation, AriaPressed, AriaHasPopup, AriaActiveDescendant, AriaSort, AriaMultiSelectable, AriaModal, AriaBusy, AriaErrorMessage, AriaRoleDescription, AriaAtomic, AriaAutocomplete, AriaColcount, AriaColindex, AriaColspan, AriaDescription, AriaDetails, AriaFlowto, AriaKeyshortcuts, AriaLevel, AriaOwns, AriaPlaceholder, AriaPosinset, AriaReadonly, AriaRelevant, AriaRowcount, AriaRowindex, AriaRowspan, AriaSetsize, AriaValuemax, AriaValuemin, AriaValuenow, AriaValuetext, Attribute, DataAttribute, Style, InnerHTML, ViewBox, Xmlns, Fill, FillRule, ClipRule, Stroke, StrokeWidth, StrokeLinecap, StrokeLinejoin, D, Cx, Cy, R, X, Y, Width, Height, X1, Y1, X2, Y2, Points, Transform, Opacity, StrokeDasharray, StrokeDashoffset, Prop, OnCustomEvent, OnMount, } = Data.taggedEnum();
43
64
  export { Prop, OnCustomEvent };
44
- const buildVNodeData = (attributes) => Effect.gen(function* () {
45
- const { dispatchSync } = yield* Dispatch;
46
- const capturedContext = yield* Effect.context();
47
- const dataRef = yield* Ref.make({});
48
- const setData = (key, value) => Ref.update(dataRef, data => ({ ...data, [key]: value }));
49
- const updateData = (key, value) => Ref.update(dataRef, data => ({
50
- ...data,
51
- [key]: { ...data[key], ...value },
52
- }));
53
- const updateDataProps = (props) => updateData('props', props);
54
- const updateDataOn = (on) => updateData('on', on);
55
- const updateDataAttrs = (attrs) => updateData('attrs', attrs);
56
- const postpatchPropsRef = yield* Ref.make([]);
57
- const updatePropsWithPostpatch = (propName, value) => Effect.all([
58
- Ref.update(dataRef, data => ({
59
- ...data,
60
- props: {
61
- ...data.props,
62
- [propName]: value,
63
- },
64
- })),
65
- Ref.update(postpatchPropsRef, entries => [
66
- ...entries,
67
- { propName, value },
68
- ]),
69
- ]);
70
- yield* Effect.forEach(attributes, attr => Match.value(attr).pipe(Match.tagsExhaustive({
71
- Key: ({ value }) => setData('key', value),
72
- Class: ({ value }) => Effect.gen(function* () {
73
- const classObject = pipe(value, String.split(/\s+/), Array.filter(String.isNonEmpty), Array.reduce({}, (acc, className) => ({
74
- ...acc,
75
- [className]: true,
76
- })));
77
- yield* setData('class', classObject);
78
- }),
79
- Id: ({ value }) => updateDataProps({ id: value }),
80
- Title: ({ value }) => updateDataProps({ title: value }),
81
- Lang: ({ value }) => updateDataProps({ lang: value }),
82
- Dir: ({ value }) => updateDataProps({ dir: value }),
83
- Tabindex: ({ value }) => updateDataProps({ tabIndex: value }),
84
- Hidden: ({ value }) => updateDataProps({ hidden: value }),
85
- Contenteditable: ({ value }) => updateDataAttrs({ contenteditable: value }),
86
- Draggable: ({ value }) => updateDataProps({ draggable: value }),
87
- Accesskey: ({ value }) => updateDataAttrs({ accesskey: value }),
88
- Translate: ({ value }) => updateDataAttrs({ translate: value }),
89
- Inert: ({ value }) => updateDataProps({ inert: value }),
90
- Popover: ({ value }) => updateDataAttrs({ popover: value }),
91
- Popovertarget: ({ value }) => updateDataAttrs({ popovertarget: value }),
92
- Popovertargetaction: ({ value }) => updateDataAttrs({ popovertargetaction: value }),
93
- OnClick: ({ message }) => updateDataOn({
94
- click: () => dispatchSync(message),
95
- }),
96
- OnDoubleClick: ({ message }) => updateDataOn({
97
- dblclick: () => dispatchSync(message),
98
- }),
99
- OnMouseDown: ({ message }) => updateDataOn({
100
- mousedown: () => dispatchSync(message),
101
- }),
102
- OnMouseUp: ({ message }) => updateDataOn({
103
- mouseup: () => dispatchSync(message),
104
- }),
105
- OnMouseEnter: ({ message }) => updateDataOn({
106
- mouseenter: () => dispatchSync(message),
107
- }),
108
- OnMouseLeave: ({ message }) => updateDataOn({
109
- mouseleave: () => dispatchSync(message),
110
- }),
111
- OnMouseOver: ({ message }) => updateDataOn({
112
- mouseover: () => dispatchSync(message),
113
- }),
114
- OnMouseOut: ({ message }) => updateDataOn({
115
- mouseout: () => dispatchSync(message),
116
- }),
117
- OnMouseMove: ({ message }) => updateDataOn({
118
- mousemove: () => dispatchSync(message),
119
- }),
120
- OnPointerMove: ({ f }) => updateDataOn({
121
- pointermove: (event) => {
122
- const maybeMessage = f(event.screenX, event.screenY, event.pointerType);
123
- if (Option.isSome(maybeMessage)) {
124
- dispatchSync(maybeMessage.value);
125
- }
126
- },
127
- }),
128
- OnPointerLeave: ({ f }) => updateDataOn({
129
- pointerleave: (event) => {
130
- const maybeMessage = f(event.pointerType);
131
- if (Option.isSome(maybeMessage)) {
132
- dispatchSync(maybeMessage.value);
133
- }
134
- },
135
- }),
136
- OnPointerDown: ({ f }) => updateDataOn({
137
- pointerdown: (event) => {
138
- const maybeMessage = f(event.pointerType, event.button, event.screenX, event.screenY, event.timeStamp, event.clientX, event.clientY);
139
- if (Option.isSome(maybeMessage)) {
140
- dispatchSync(maybeMessage.value);
141
- }
142
- },
143
- }),
144
- OnPointerUp: ({ f }) => updateDataOn({
145
- pointerup: (event) => {
146
- const maybeMessage = f(event.screenX, event.screenY, event.pointerType, event.timeStamp);
147
- if (Option.isSome(maybeMessage)) {
148
- dispatchSync(maybeMessage.value);
149
- }
150
- },
151
- }),
152
- OnKeyDown: ({ f }) => updateDataOn({
153
- keydown: (event) => dispatchSync(f(event.key, keyboardModifiers(event))),
154
- }),
155
- OnKeyDownPreventDefault: ({ f }) => updateDataOn({
156
- keydown: (event) => {
157
- const maybeMessage = f(event.key, keyboardModifiers(event));
158
- if (Option.isSome(maybeMessage)) {
159
- event.preventDefault();
160
- dispatchSync(maybeMessage.value);
161
- }
162
- },
163
- }),
164
- OnKeyUp: ({ f }) => updateDataOn({
165
- keyup: (event) => dispatchSync(f(event.key, keyboardModifiers(event))),
166
- }),
167
- OnKeyUpPreventDefault: ({ f }) => updateDataOn({
168
- keyup: (event) => {
169
- const maybeMessage = f(event.key, keyboardModifiers(event));
170
- if (Option.isSome(maybeMessage)) {
171
- event.preventDefault();
172
- dispatchSync(maybeMessage.value);
173
- }
174
- },
175
- }),
176
- OnKeyPress: ({ f }) => updateDataOn({
177
- keypress: (event) => dispatchSync(f(event.key, keyboardModifiers(event))),
178
- }),
179
- OnFocus: ({ message }) => updateDataOn({
180
- focus: () => dispatchSync(message),
181
- }),
182
- OnBlur: ({ message }) => updateDataOn({
183
- blur: (event) => {
184
- if (event.relatedTarget instanceof Element &&
185
- event.relatedTarget.id === DEVTOOLS_HOST_ID) {
186
- return;
187
- }
188
- dispatchSync(message);
189
- },
190
- }),
191
- OnInput: ({ f }) => updateDataOn({
192
- input: (event) =>
65
+ const setData = (ctx, key, value) => {
66
+ ctx.data[key] = value;
67
+ };
68
+ const updateData = (ctx, key, value) => {
69
+ const existing = ctx.data[key];
70
+ if (existing === undefined) {
71
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
72
+ ctx.data[key] = value;
73
+ }
74
+ else {
75
+ Object.assign(existing, value);
76
+ }
77
+ };
78
+ const updateDataProps = (ctx, props) => updateData(ctx, 'props', props);
79
+ const updateDataAttrs = (ctx, attrs) => updateData(ctx, 'attrs', attrs);
80
+ // Event handlers chain per DOM event in spread order. Without this,
81
+ // `Object.assign` would silently drop earlier handlers for the same
82
+ // event when a consumer spreads published ChildAttributes alongside
83
+ // their own (e.g. `[...attributes.checkbox, h.OnClick(MyMsg())]` would
84
+ // drop one of the two click handlers depending on order). Each chained
85
+ // handler is invoked synchronously in registration order; if an
86
+ // earlier handler throws, later handlers do not run (mirroring native
87
+ // exception propagation, not silently swallowing bugs).
88
+ const updateDataOn = (ctx, on) => {
89
+ if (ctx.data.on === undefined) {
90
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
91
+ ctx.data.on = on;
92
+ return;
93
+ }
94
+ const existing = ctx.data.on;
95
+ for (const key of Object.keys(on)) {
96
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
97
+ const existingHandler = existing[key];
98
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
99
+ const newHandler = on[key];
100
+ if (existingHandler === undefined) {
193
101
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
194
- dispatchSync(f(event.target.value)),
195
- }),
196
- OnChange: ({ f }) => updateDataOn({
197
- change: (event) =>
102
+ ;
103
+ existing[key] = newHandler;
104
+ }
105
+ else {
198
106
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
199
- dispatchSync(f(event.target.value)),
200
- }),
201
- OnFileChange: ({ f }) => updateDataOn({
202
- change: tagAsFileHandler((event) => {
203
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
204
- const target = event.target;
205
- const files = target.files
206
- ? Array.fromIterable(target.files)
207
- : Array.empty();
208
- target.value = '';
209
- dispatchSync(f(files));
210
- }, 'OnFileChange'),
211
- }),
212
- OnSubmit: ({ message }) => updateDataOn({
213
- submit: (event) => {
107
+ ;
108
+ existing[key] = (...args) => {
109
+ existingHandler(...args);
110
+ newHandler(...args);
111
+ };
112
+ }
113
+ }
114
+ };
115
+ const updatePropsWithPostpatch = (ctx, propName, value) => {
116
+ updateDataProps(ctx, { [propName]: value });
117
+ ctx.postpatchProps.push({ propName, value });
118
+ };
119
+ // NOTE: Built once at module load. The matcher dispatches on `_tag` and
120
+ // returns a thunk that applies the resulting mutation to a per-VNode
121
+ // BuildContext. Per-attribute cost drops from O(matcher arms) closure
122
+ // allocations to one thunk. `Attribute<unknown>` is the runtime-erased
123
+ // shape. Message is purely a TypeScript parameter at this level and
124
+ // DispatchSync already accepts unknown.
125
+ const attributeMatcher = Match.type().pipe(Match.tagsExhaustive({
126
+ Key: ({ value }) => (ctx) => setData(ctx, 'key', value),
127
+ Class: ({ value }) => {
128
+ const classObject = pipe(value, String.split(/\s+/), Array.filter(String.isNonEmpty), Array.reduce({}, (acc, className) => ({
129
+ ...acc,
130
+ [className]: true,
131
+ })));
132
+ return (ctx) => setData(ctx, 'class', classObject);
133
+ },
134
+ Id: ({ value }) => (ctx) => updateDataProps(ctx, { id: value }),
135
+ Title: ({ value }) => (ctx) => updateDataProps(ctx, { title: value }),
136
+ Lang: ({ value }) => (ctx) => updateDataProps(ctx, { lang: value }),
137
+ Dir: ({ value }) => (ctx) => updateDataProps(ctx, { dir: value }),
138
+ Tabindex: ({ value }) => (ctx) => updateDataProps(ctx, { tabIndex: value }),
139
+ Hidden: ({ value }) => (ctx) => updateDataProps(ctx, { hidden: value }),
140
+ Contenteditable: ({ value }) => (ctx) => updateDataAttrs(ctx, { contenteditable: value }),
141
+ Draggable: ({ value }) => (ctx) => updateDataProps(ctx, { draggable: value }),
142
+ Accesskey: ({ value }) => (ctx) => updateDataAttrs(ctx, { accesskey: value }),
143
+ Translate: ({ value }) => (ctx) => updateDataAttrs(ctx, { translate: value }),
144
+ Inert: ({ value }) => (ctx) => updateDataProps(ctx, { inert: value }),
145
+ Popover: ({ value }) => (ctx) => updateDataAttrs(ctx, { popover: value }),
146
+ Popovertarget: ({ value }) => (ctx) => updateDataAttrs(ctx, { popovertarget: value }),
147
+ Popovertargetaction: ({ value }) => (ctx) => updateDataAttrs(ctx, { popovertargetaction: value }),
148
+ OnClick: ({ message }) => (ctx) => updateDataOn(ctx, { click: () => ctx.dispatch(message) }),
149
+ OnDoubleClick: ({ message }) => (ctx) => updateDataOn(ctx, { dblclick: () => ctx.dispatch(message) }),
150
+ OnMouseDown: ({ message }) => (ctx) => updateDataOn(ctx, { mousedown: () => ctx.dispatch(message) }),
151
+ OnMouseUp: ({ message }) => (ctx) => updateDataOn(ctx, { mouseup: () => ctx.dispatch(message) }),
152
+ OnMouseEnter: ({ message }) => (ctx) => updateDataOn(ctx, { mouseenter: () => ctx.dispatch(message) }),
153
+ OnMouseLeave: ({ message }) => (ctx) => updateDataOn(ctx, { mouseleave: () => ctx.dispatch(message) }),
154
+ OnMouseOver: ({ message }) => (ctx) => updateDataOn(ctx, { mouseover: () => ctx.dispatch(message) }),
155
+ OnMouseOut: ({ message }) => (ctx) => updateDataOn(ctx, { mouseout: () => ctx.dispatch(message) }),
156
+ OnMouseMove: ({ message }) => (ctx) => updateDataOn(ctx, { mousemove: () => ctx.dispatch(message) }),
157
+ OnPointerMove: ({ f }) => (ctx) => updateDataOn(ctx, {
158
+ pointermove: (event) => {
159
+ const maybeMessage = f(event.screenX, event.screenY, event.pointerType);
160
+ if (Option.isSome(maybeMessage)) {
161
+ ctx.dispatch(maybeMessage.value);
162
+ }
163
+ },
164
+ }),
165
+ OnPointerLeave: ({ f }) => (ctx) => updateDataOn(ctx, {
166
+ pointerleave: (event) => {
167
+ const maybeMessage = f(event.pointerType);
168
+ if (Option.isSome(maybeMessage)) {
169
+ ctx.dispatch(maybeMessage.value);
170
+ }
171
+ },
172
+ }),
173
+ OnPointerDown: ({ f }) => (ctx) => updateDataOn(ctx, {
174
+ pointerdown: (event) => {
175
+ const maybeMessage = f(event.pointerType, event.button, event.screenX, event.screenY, event.timeStamp, event.clientX, event.clientY);
176
+ if (Option.isSome(maybeMessage)) {
177
+ ctx.dispatch(maybeMessage.value);
178
+ }
179
+ },
180
+ }),
181
+ OnPointerUp: ({ f }) => (ctx) => updateDataOn(ctx, {
182
+ pointerup: (event) => {
183
+ const maybeMessage = f(event.screenX, event.screenY, event.pointerType, event.timeStamp);
184
+ if (Option.isSome(maybeMessage)) {
185
+ ctx.dispatch(maybeMessage.value);
186
+ }
187
+ },
188
+ }),
189
+ OnKeyDown: ({ f }) => (ctx) => updateDataOn(ctx, {
190
+ keydown: (event) => ctx.dispatch(f(event.key, keyboardModifiers(event))),
191
+ }),
192
+ OnKeyDownPreventDefault: ({ f }) => (ctx) => updateDataOn(ctx, {
193
+ keydown: (event) => {
194
+ const maybeMessage = f(event.key, keyboardModifiers(event));
195
+ if (Option.isSome(maybeMessage)) {
214
196
  event.preventDefault();
215
- dispatchSync(message);
216
- },
217
- }),
218
- OnReset: ({ message }) => updateDataOn({
219
- reset: () => dispatchSync(message),
220
- }),
221
- OnScroll: ({ f }) => updateDataOn({
222
- scroll: (event) =>
223
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
224
- dispatchSync(f(event.target.scrollTop)),
225
- }),
226
- OnWheel: ({ message }) => updateDataOn({
227
- wheel: () => dispatchSync(message),
228
- }),
229
- OnCopy: ({ message }) => updateDataOn({
230
- copy: () => dispatchSync(message),
231
- }),
232
- OnCut: ({ message }) => updateDataOn({
233
- cut: () => dispatchSync(message),
234
- }),
235
- OnPaste: ({ message }) => updateDataOn({
236
- paste: () => dispatchSync(message),
237
- }),
238
- OnCancel: ({ message }) => updateDataOn({
239
- cancel: (event) => {
197
+ ctx.dispatch(maybeMessage.value);
198
+ }
199
+ },
200
+ }),
201
+ OnKeyUp: ({ f }) => (ctx) => updateDataOn(ctx, {
202
+ keyup: (event) => ctx.dispatch(f(event.key, keyboardModifiers(event))),
203
+ }),
204
+ OnKeyUpPreventDefault: ({ f }) => (ctx) => updateDataOn(ctx, {
205
+ keyup: (event) => {
206
+ const maybeMessage = f(event.key, keyboardModifiers(event));
207
+ if (Option.isSome(maybeMessage)) {
240
208
  event.preventDefault();
241
- dispatchSync(message);
242
- },
243
- }),
244
- OnToggle: ({ f }) => updateDataOn({
245
- toggle: event =>
209
+ ctx.dispatch(maybeMessage.value);
210
+ }
211
+ },
212
+ }),
213
+ OnKeyPress: ({ f }) => (ctx) => updateDataOn(ctx, {
214
+ keypress: (event) => ctx.dispatch(f(event.key, keyboardModifiers(event))),
215
+ }),
216
+ OnFocus: ({ message }) => (ctx) => updateDataOn(ctx, { focus: () => ctx.dispatch(message) }),
217
+ OnBlur: ({ message }) => (ctx) => updateDataOn(ctx, {
218
+ blur: (event) => {
219
+ if (event.relatedTarget instanceof Element &&
220
+ event.relatedTarget.id === DEVTOOLS_HOST_ID) {
221
+ return;
222
+ }
223
+ ctx.dispatch(message);
224
+ },
225
+ }),
226
+ OnInput: ({ f }) => (ctx) => updateDataOn(ctx, {
227
+ input: (event) =>
228
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
229
+ ctx.dispatch(f(event.target.value)),
230
+ }),
231
+ OnChange: ({ f }) => (ctx) => updateDataOn(ctx, {
232
+ change: (event) =>
233
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
234
+ ctx.dispatch(f(event.target.value)),
235
+ }),
236
+ OnFileChange: ({ f }) => (ctx) => updateDataOn(ctx, {
237
+ change: tagAsFileHandler((event) => {
246
238
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
247
- dispatchSync(f(event.target.open)),
248
- }),
249
- OnContextMenu: ({ message }) => updateDataOn({
250
- contextmenu: (event) => {
251
- event.preventDefault();
252
- dispatchSync(message);
253
- },
254
- }),
255
- OnDragStart: ({ message }) => updateDataOn({
256
- dragstart: () => dispatchSync(message),
257
- }),
258
- OnDrag: ({ message }) => updateDataOn({
259
- drag: () => dispatchSync(message),
260
- }),
261
- OnDragEnd: ({ message }) => updateDataOn({
262
- dragend: () => dispatchSync(message),
263
- }),
264
- OnDragEnter: ({ message }) => updateDataOn({
265
- dragenter: (event) => {
266
- event.preventDefault();
267
- const zone = event.currentTarget;
268
- if (!(zone instanceof Element)) {
269
- dispatchSync(message);
270
- return;
271
- }
272
- const state = getDragZoneState(zone);
273
- if (processDragEnter(state, zone, event.target)) {
274
- dispatchSync(message);
275
- }
276
- },
277
- }),
278
- OnDragLeave: ({ message }) => updateDataOn({
279
- dragleave: (event) => {
280
- const zone = event.currentTarget;
281
- if (!(zone instanceof Element)) {
282
- dispatchSync(message);
283
- return;
284
- }
285
- const state = getDragZoneState(zone);
286
- if (processDragLeave(state, zone, event.target) === 'schedule') {
287
- queueMicrotask(() => {
288
- if (checkScheduledLeave(state)) {
289
- dispatchSync(message);
290
- }
291
- });
292
- }
293
- },
294
- }),
295
- OnDragOver: ({ message }) => updateDataOn({
296
- dragover: (event) => {
297
- event.preventDefault();
298
- dispatchSync(message);
299
- },
300
- }),
301
- AllowDrop: () => updateDataOn({
302
- dragover: (event) => {
303
- event.preventDefault();
304
- },
305
- }),
306
- OnDrop: ({ message }) => updateDataOn({
307
- drop: (event) => {
308
- event.preventDefault();
309
- const zone = event.currentTarget;
310
- if (zone instanceof Element) {
311
- clearDragZoneAfterDrop(zone);
239
+ const target = event.target;
240
+ const files = target.files
241
+ ? Array.fromIterable(target.files)
242
+ : Array.empty();
243
+ target.value = '';
244
+ ctx.dispatch(f(files));
245
+ }, 'OnFileChange'),
246
+ }),
247
+ OnSubmit: ({ message }) => (ctx) => updateDataOn(ctx, {
248
+ submit: (event) => {
249
+ event.preventDefault();
250
+ ctx.dispatch(message);
251
+ },
252
+ }),
253
+ OnReset: ({ message }) => (ctx) => updateDataOn(ctx, { reset: () => ctx.dispatch(message) }),
254
+ OnScroll: ({ f }) => (ctx) => updateDataOn(ctx, {
255
+ scroll: (event) =>
256
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
257
+ ctx.dispatch(f(event.target.scrollTop)),
258
+ }),
259
+ OnWheel: ({ message }) => (ctx) => updateDataOn(ctx, { wheel: () => ctx.dispatch(message) }),
260
+ OnCopy: ({ message }) => (ctx) => updateDataOn(ctx, { copy: () => ctx.dispatch(message) }),
261
+ OnCut: ({ message }) => (ctx) => updateDataOn(ctx, { cut: () => ctx.dispatch(message) }),
262
+ OnPaste: ({ message }) => (ctx) => updateDataOn(ctx, { paste: () => ctx.dispatch(message) }),
263
+ OnCancel: ({ message }) => (ctx) => updateDataOn(ctx, {
264
+ cancel: (event) => {
265
+ event.preventDefault();
266
+ ctx.dispatch(message);
267
+ },
268
+ }),
269
+ OnToggle: ({ f }) => (ctx) => updateDataOn(ctx, {
270
+ toggle: event =>
271
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
272
+ ctx.dispatch(f(event.target.open)),
273
+ }),
274
+ OnContextMenu: ({ message }) => (ctx) => updateDataOn(ctx, {
275
+ contextmenu: (event) => {
276
+ event.preventDefault();
277
+ ctx.dispatch(message);
278
+ },
279
+ }),
280
+ OnDragStart: ({ message }) => (ctx) => updateDataOn(ctx, { dragstart: () => ctx.dispatch(message) }),
281
+ OnDrag: ({ message }) => (ctx) => updateDataOn(ctx, { drag: () => ctx.dispatch(message) }),
282
+ OnDragEnd: ({ message }) => (ctx) => updateDataOn(ctx, { dragend: () => ctx.dispatch(message) }),
283
+ OnDragEnter: ({ message }) => (ctx) => updateDataOn(ctx, {
284
+ dragenter: (event) => {
285
+ event.preventDefault();
286
+ const zone = event.currentTarget;
287
+ if (!(zone instanceof Element)) {
288
+ ctx.dispatch(message);
289
+ return;
290
+ }
291
+ const state = getDragZoneState(zone);
292
+ if (processDragEnter(state, zone, event.target)) {
293
+ ctx.dispatch(message);
294
+ }
295
+ },
296
+ }),
297
+ OnDragLeave: ({ message }) => (ctx) => updateDataOn(ctx, {
298
+ dragleave: (event) => {
299
+ const zone = event.currentTarget;
300
+ if (!(zone instanceof Element)) {
301
+ ctx.dispatch(message);
302
+ return;
303
+ }
304
+ const state = getDragZoneState(zone);
305
+ if (processDragLeave(state, zone, event.target) === 'schedule') {
306
+ queueMicrotask(() => {
307
+ if (checkScheduledLeave(state)) {
308
+ ctx.dispatch(message);
309
+ }
310
+ });
311
+ }
312
+ },
313
+ }),
314
+ OnDragOver: ({ message }) => (ctx) => updateDataOn(ctx, {
315
+ dragover: (event) => {
316
+ event.preventDefault();
317
+ ctx.dispatch(message);
318
+ },
319
+ }),
320
+ AllowDrop: () => (ctx) => updateDataOn(ctx, {
321
+ dragover: (event) => {
322
+ event.preventDefault();
323
+ },
324
+ }),
325
+ OnDrop: ({ message }) => (ctx) => updateDataOn(ctx, {
326
+ drop: (event) => {
327
+ event.preventDefault();
328
+ const zone = event.currentTarget;
329
+ if (zone instanceof Element) {
330
+ clearDragZoneAfterDrop(zone);
331
+ }
332
+ ctx.dispatch(message);
333
+ },
334
+ }),
335
+ OnDropFiles: ({ f }) => (ctx) => updateDataOn(ctx, {
336
+ drop: tagAsFileHandler((event) => {
337
+ event.preventDefault();
338
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
339
+ const dragEvent = event;
340
+ const zone = dragEvent.currentTarget;
341
+ if (zone instanceof Element) {
342
+ clearDragZoneAfterDrop(zone);
343
+ }
344
+ const files = dragEvent.dataTransfer?.files
345
+ ? Array.fromIterable(dragEvent.dataTransfer.files)
346
+ : Array.empty();
347
+ ctx.dispatch(f(files));
348
+ }, 'OnDropFiles'),
349
+ }),
350
+ OnTouchStart: ({ message }) => (ctx) => updateDataOn(ctx, { touchstart: () => ctx.dispatch(message) }),
351
+ OnTouchEnd: ({ message }) => (ctx) => updateDataOn(ctx, { touchend: () => ctx.dispatch(message) }),
352
+ OnTouchMove: ({ message }) => (ctx) => updateDataOn(ctx, { touchmove: () => ctx.dispatch(message) }),
353
+ OnTouchCancel: ({ message }) => (ctx) => updateDataOn(ctx, { touchcancel: () => ctx.dispatch(message) }),
354
+ OnAnimationStart: ({ message }) => (ctx) => updateDataOn(ctx, { animationstart: () => ctx.dispatch(message) }),
355
+ OnAnimationEnd: ({ message }) => (ctx) => updateDataOn(ctx, { animationend: () => ctx.dispatch(message) }),
356
+ OnAnimationIteration: ({ message }) => (ctx) => updateDataOn(ctx, { animationiteration: () => ctx.dispatch(message) }),
357
+ OnTransitionEnd: ({ message }) => (ctx) => updateDataOn(ctx, { transitionend: () => ctx.dispatch(message) }),
358
+ OnLoad: ({ message }) => (ctx) => updateDataOn(ctx, { load: () => ctx.dispatch(message) }),
359
+ OnError: ({ message }) => (ctx) => updateDataOn(ctx, { error: () => ctx.dispatch(message) }),
360
+ OnPlay: ({ message }) => (ctx) => updateDataOn(ctx, { play: () => ctx.dispatch(message) }),
361
+ OnPause: ({ message }) => (ctx) => updateDataOn(ctx, { pause: () => ctx.dispatch(message) }),
362
+ OnEnded: ({ message }) => (ctx) => updateDataOn(ctx, { ended: () => ctx.dispatch(message) }),
363
+ OnTimeUpdate: ({ message }) => (ctx) => updateDataOn(ctx, { timeupdate: () => ctx.dispatch(message) }),
364
+ OnVolumeChange: ({ message }) => (ctx) => updateDataOn(ctx, { volumechange: () => ctx.dispatch(message) }),
365
+ OnSelect: ({ message }) => (ctx) => updateDataOn(ctx, { select: () => ctx.dispatch(message) }),
366
+ Value: ({ value }) => (ctx) => updatePropsWithPostpatch(ctx, 'value', value),
367
+ Checked: ({ value }) => (ctx) => updatePropsWithPostpatch(ctx, 'checked', value),
368
+ Selected: ({ value }) => (ctx) => updatePropsWithPostpatch(ctx, 'selected', value),
369
+ Open: ({ value }) => (ctx) => updatePropsWithPostpatch(ctx, 'open', value),
370
+ Placeholder: ({ value }) => (ctx) => updateDataProps(ctx, { placeholder: value }),
371
+ Name: ({ value }) => (ctx) => updateDataProps(ctx, { name: value }),
372
+ Disabled: ({ value }) => (ctx) => updateDataProps(ctx, { disabled: value }),
373
+ Readonly: ({ value }) => (ctx) => updateDataProps(ctx, { readOnly: value }),
374
+ Required: ({ value }) => (ctx) => updateDataProps(ctx, { required: value }),
375
+ Autofocus: ({ value }) => (ctx) => updateDataProps(ctx, { autofocus: value }),
376
+ Spellcheck: ({ value }) => (ctx) => updateDataAttrs(ctx, { spellcheck: value.toString() }),
377
+ Autocorrect: ({ value }) => (ctx) => updateDataAttrs(ctx, { autocorrect: value }),
378
+ Autocapitalize: ({ value }) => (ctx) => updateDataAttrs(ctx, { autocapitalize: value }),
379
+ InputMode: ({ value }) => (ctx) => updateDataAttrs(ctx, { inputmode: value }),
380
+ EnterKeyHint: ({ value }) => (ctx) => updateDataAttrs(ctx, { enterkeyhint: value }),
381
+ Multiple: ({ value }) => (ctx) => updateDataProps(ctx, { multiple: value }),
382
+ Type: ({ value }) => (ctx) => updateDataProps(ctx, { type: value }),
383
+ Accept: ({ value }) => (ctx) => updateDataProps(ctx, { accept: value }),
384
+ Autocomplete: ({ value }) => (ctx) => updateDataProps(ctx, { autocomplete: value }),
385
+ Pattern: ({ value }) => (ctx) => updateDataProps(ctx, { pattern: value }),
386
+ Maxlength: ({ value }) => (ctx) => updateDataProps(ctx, { maxLength: value }),
387
+ Minlength: ({ value }) => (ctx) => updateDataProps(ctx, { minLength: value }),
388
+ Size: ({ value }) => (ctx) => updateDataProps(ctx, { size: value }),
389
+ Cols: ({ value }) => (ctx) => updateDataProps(ctx, { cols: value }),
390
+ Rows: ({ value }) => (ctx) => updateDataProps(ctx, { rows: value }),
391
+ Max: ({ value }) => (ctx) => updateDataProps(ctx, { max: value }),
392
+ Min: ({ value }) => (ctx) => updateDataProps(ctx, { min: value }),
393
+ Step: ({ value }) => (ctx) => updateDataProps(ctx, { step: value }),
394
+ For: ({ value }) => (ctx) => updateDataProps(ctx, { htmlFor: value }),
395
+ Href: ({ value }) => (ctx) => updateDataProps(ctx, { href: value }),
396
+ Src: ({ value }) => (ctx) => updateDataProps(ctx, { src: value }),
397
+ Alt: ({ value }) => (ctx) => updateDataProps(ctx, { alt: value }),
398
+ Target: ({ value }) => (ctx) => updateDataProps(ctx, { target: value }),
399
+ Rel: ({ value }) => (ctx) => updateDataProps(ctx, { rel: value }),
400
+ Download: ({ value }) => (ctx) => updateDataProps(ctx, { download: value }),
401
+ Action: ({ value }) => (ctx) => updateDataProps(ctx, { action: value }),
402
+ Method: ({ value }) => (ctx) => updateDataProps(ctx, { method: value }),
403
+ Enctype: ({ value }) => (ctx) => updateDataProps(ctx, { enctype: value }),
404
+ Novalidate: ({ value }) => (ctx) => updateDataProps(ctx, { noValidate: value }),
405
+ Formaction: ({ value }) => (ctx) => updateDataProps(ctx, { formAction: value }),
406
+ Formmethod: ({ value }) => (ctx) => updateDataProps(ctx, { formMethod: value }),
407
+ Formnovalidate: ({ value }) => (ctx) => updateDataProps(ctx, { formNoValidate: value }),
408
+ Formtarget: ({ value }) => (ctx) => updateDataProps(ctx, { formTarget: value }),
409
+ Formenctype: ({ value }) => (ctx) => updateDataProps(ctx, { formEnctype: value }),
410
+ Colspan: ({ value }) => (ctx) => updateDataProps(ctx, { colSpan: value }),
411
+ Rowspan: ({ value }) => (ctx) => updateDataProps(ctx, { rowSpan: value }),
412
+ Scope: ({ value }) => (ctx) => updateDataAttrs(ctx, { scope: value }),
413
+ Headers: ({ value }) => (ctx) => updateDataAttrs(ctx, { headers: value }),
414
+ Span: ({ value }) => (ctx) => updateDataProps(ctx, { span: value }),
415
+ Start: ({ value }) => (ctx) => updateDataProps(ctx, { start: value }),
416
+ Reversed: ({ value }) => (ctx) => updateDataProps(ctx, { reversed: value }),
417
+ CiteAttr: ({ value }) => (ctx) => updateDataProps(ctx, { cite: value }),
418
+ Datetime: ({ value }) => (ctx) => updateDataProps(ctx, { dateTime: value }),
419
+ Wrap: ({ value }) => (ctx) => updateDataProps(ctx, { wrap: value }),
420
+ List: ({ value }) => (ctx) => updateDataAttrs(ctx, { list: value }),
421
+ FormAttr: ({ value }) => (ctx) => updateDataAttrs(ctx, { form: value }),
422
+ LabelAttr: ({ value }) => (ctx) => updateDataProps(ctx, { label: value }),
423
+ ContentAttr: ({ value }) => (ctx) => updateDataAttrs(ctx, { content: value }),
424
+ Charset: ({ value }) => (ctx) => updateDataAttrs(ctx, { charset: value }),
425
+ HttpEquiv: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'http-equiv': value }),
426
+ Srcset: ({ value }) => (ctx) => updateDataAttrs(ctx, { srcset: value }),
427
+ Sizes: ({ value }) => (ctx) => updateDataAttrs(ctx, { sizes: value }),
428
+ Loading: ({ value }) => (ctx) => updateDataAttrs(ctx, { loading: value }),
429
+ Decoding: ({ value }) => (ctx) => updateDataAttrs(ctx, { decoding: value }),
430
+ Fetchpriority: ({ value }) => (ctx) => updateDataAttrs(ctx, { fetchpriority: value }),
431
+ Crossorigin: ({ value }) => (ctx) => updateDataAttrs(ctx, { crossorigin: value }),
432
+ Referrerpolicy: ({ value }) => (ctx) => updateDataAttrs(ctx, { referrerpolicy: value }),
433
+ Integrity: ({ value }) => (ctx) => updateDataAttrs(ctx, { integrity: value }),
434
+ Hreflang: ({ value }) => (ctx) => updateDataAttrs(ctx, { hreflang: value }),
435
+ Ping: ({ value }) => (ctx) => updateDataAttrs(ctx, { ping: value }),
436
+ Sandbox: ({ value }) => (ctx) => updateDataAttrs(ctx, { sandbox: value }),
437
+ Allow: ({ value }) => (ctx) => updateDataAttrs(ctx, { allow: value }),
438
+ Srcdoc: ({ value }) => (ctx) => updateDataAttrs(ctx, { srcdoc: value }),
439
+ Autoplay: ({ value }) => (ctx) => updateDataProps(ctx, { autoplay: value }),
440
+ Controls: ({ value }) => (ctx) => updateDataProps(ctx, { controls: value }),
441
+ Loop: ({ value }) => (ctx) => updateDataProps(ctx, { loop: value }),
442
+ Muted: ({ value }) => (ctx) => updatePropsWithPostpatch(ctx, 'muted', value),
443
+ Poster: ({ value }) => (ctx) => updateDataProps(ctx, { poster: value }),
444
+ Preload: ({ value }) => (ctx) => updateDataProps(ctx, { preload: value }),
445
+ Playsinline: ({ value }) => (ctx) => updateDataProps(ctx, { playsInline: value }),
446
+ High: ({ value }) => (ctx) => updateDataProps(ctx, { high: value }),
447
+ Low: ({ value }) => (ctx) => updateDataProps(ctx, { low: value }),
448
+ Optimum: ({ value }) => (ctx) => updateDataProps(ctx, { optimum: value }),
449
+ Usemap: ({ value }) => (ctx) => updateDataAttrs(ctx, { usemap: value }),
450
+ Ismap: ({ value }) => (ctx) => updateDataProps(ctx, { isMap: value }),
451
+ Role: ({ value }) => (ctx) => updateDataAttrs(ctx, { role: value }),
452
+ AriaLabel: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-label': value }),
453
+ AriaLabelledBy: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-labelledby': value }),
454
+ AriaDescribedBy: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-describedby': value }),
455
+ AriaHidden: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-hidden': value.toString() }),
456
+ AriaExpanded: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-expanded': value.toString() }),
457
+ AriaSelected: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-selected': value.toString() }),
458
+ AriaChecked: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-checked': value.toString() }),
459
+ AriaDisabled: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-disabled': value.toString() }),
460
+ AriaRequired: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-required': value.toString() }),
461
+ AriaInvalid: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-invalid': value.toString() }),
462
+ AriaLive: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-live': value }),
463
+ AriaControls: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-controls': value }),
464
+ AriaCurrent: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-current': value }),
465
+ AriaOrientation: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-orientation': value }),
466
+ AriaPressed: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-pressed': value }),
467
+ AriaHasPopup: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-haspopup': value }),
468
+ AriaActiveDescendant: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-activedescendant': value }),
469
+ AriaSort: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-sort': value }),
470
+ AriaMultiSelectable: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-multiselectable': value.toString() }),
471
+ AriaModal: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-modal': value.toString() }),
472
+ AriaBusy: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-busy': value.toString() }),
473
+ AriaErrorMessage: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-errormessage': value }),
474
+ AriaRoleDescription: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-roledescription': value }),
475
+ AriaAtomic: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-atomic': value.toString() }),
476
+ AriaAutocomplete: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-autocomplete': value }),
477
+ AriaColcount: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-colcount': value.toString() }),
478
+ AriaColindex: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-colindex': value.toString() }),
479
+ AriaColspan: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-colspan': value.toString() }),
480
+ AriaDescription: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-description': value }),
481
+ AriaDetails: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-details': value }),
482
+ AriaFlowto: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-flowto': value }),
483
+ AriaKeyshortcuts: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-keyshortcuts': value }),
484
+ AriaLevel: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-level': value.toString() }),
485
+ AriaOwns: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-owns': value }),
486
+ AriaPlaceholder: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-placeholder': value }),
487
+ AriaPosinset: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-posinset': value.toString() }),
488
+ AriaReadonly: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-readonly': value.toString() }),
489
+ AriaRelevant: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-relevant': value }),
490
+ AriaRowcount: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-rowcount': value.toString() }),
491
+ AriaRowindex: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-rowindex': value.toString() }),
492
+ AriaRowspan: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-rowspan': value.toString() }),
493
+ AriaSetsize: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-setsize': value.toString() }),
494
+ AriaValuemax: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-valuemax': value.toString() }),
495
+ AriaValuemin: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-valuemin': value.toString() }),
496
+ AriaValuenow: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-valuenow': value.toString() }),
497
+ AriaValuetext: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'aria-valuetext': value }),
498
+ Attribute: ({ key, value }) => (ctx) => updateDataAttrs(ctx, { [key]: value }),
499
+ DataAttribute: ({ key, value }) => (ctx) => updateDataAttrs(ctx, { [`data-${key}`]: value }),
500
+ Style: ({ value }) => (ctx) => setData(ctx, 'style', value),
501
+ InnerHTML: ({ value }) => (ctx) => updateDataProps(ctx, { innerHTML: value }),
502
+ ViewBox: ({ value }) => (ctx) => updateDataAttrs(ctx, { viewBox: value }),
503
+ Xmlns: ({ value }) => (ctx) => updateDataAttrs(ctx, { xmlns: value }),
504
+ Fill: ({ value }) => (ctx) => updateDataAttrs(ctx, { fill: value }),
505
+ FillRule: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'fill-rule': value }),
506
+ ClipRule: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'clip-rule': value }),
507
+ Stroke: ({ value }) => (ctx) => updateDataAttrs(ctx, { stroke: value }),
508
+ StrokeWidth: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'stroke-width': value }),
509
+ StrokeLinecap: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'stroke-linecap': value }),
510
+ StrokeLinejoin: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'stroke-linejoin': value }),
511
+ D: ({ value }) => (ctx) => updateDataAttrs(ctx, { d: value }),
512
+ Cx: ({ value }) => (ctx) => updateDataAttrs(ctx, { cx: value }),
513
+ Cy: ({ value }) => (ctx) => updateDataAttrs(ctx, { cy: value }),
514
+ R: ({ value }) => (ctx) => updateDataAttrs(ctx, { r: value }),
515
+ X: ({ value }) => (ctx) => updateDataAttrs(ctx, { x: value }),
516
+ Y: ({ value }) => (ctx) => updateDataAttrs(ctx, { y: value }),
517
+ Width: ({ value }) => (ctx) => updateDataAttrs(ctx, { width: value }),
518
+ Height: ({ value }) => (ctx) => updateDataAttrs(ctx, { height: value }),
519
+ X1: ({ value }) => (ctx) => updateDataAttrs(ctx, { x1: value }),
520
+ Y1: ({ value }) => (ctx) => updateDataAttrs(ctx, { y1: value }),
521
+ X2: ({ value }) => (ctx) => updateDataAttrs(ctx, { x2: value }),
522
+ Y2: ({ value }) => (ctx) => updateDataAttrs(ctx, { y2: value }),
523
+ Points: ({ value }) => (ctx) => updateDataAttrs(ctx, { points: value }),
524
+ Transform: ({ value }) => (ctx) => updateDataAttrs(ctx, { transform: value }),
525
+ Opacity: ({ value }) => (ctx) => updateDataAttrs(ctx, { opacity: value }),
526
+ StrokeDasharray: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'stroke-dasharray': value }),
527
+ StrokeDashoffset: ({ value }) => (ctx) => updateDataAttrs(ctx, { 'stroke-dashoffset': value }),
528
+ Prop: ({ key, value }) => (ctx) => updateDataProps(ctx, { [key]: value }),
529
+ OnCustomEvent: ({ name, f }) => (ctx) => updateDataOn(ctx, {
530
+ [name]: (event) => {
531
+ if (event instanceof CustomEvent) {
532
+ ctx.dispatch(f(event));
533
+ }
534
+ },
535
+ }),
536
+ OnMount: ({ action }) => (ctx) => {
537
+ const capturedContext = ctx.getCapturedContext();
538
+ const maybeTracker = Context.getOption(capturedContext, MountTracker);
539
+ const notifyStarted = Option.isSome(maybeTracker)
540
+ ? () => maybeTracker.value.started(action.name, action.args)
541
+ : Function.constVoid;
542
+ const notifyEnded = Option.isSome(maybeTracker)
543
+ ? () => maybeTracker.value.ended(action.name, action.args)
544
+ : Function.constVoid;
545
+ const marker = action.args === undefined
546
+ ? { name: action.name }
547
+ : { name: action.name, args: action.args };
548
+ ctx.data[FOLDKIT_MOUNT_KEY] = marker;
549
+ ctx.data.hook = {
550
+ ...ctx.data.hook,
551
+ insert: vnode => {
552
+ if (vnode.elm instanceof Element) {
553
+ const element = vnode.elm;
554
+ notifyStarted();
555
+ const fiber = Effect.runForkWith(capturedContext)(Stream.runForEach(action.f(element), message => Effect.sync(() => ctx.dispatch(message))).pipe(Effect.catchCause(cause => Effect.sync(() => {
556
+ console.error(`[OnMount ${action.name}] unhandled failure`, cause);
557
+ }))));
558
+ onMountStates.set(element, { fiber });
312
559
  }
313
- dispatchSync(message);
314
560
  },
315
- }),
316
- OnDropFiles: ({ f }) => updateDataOn({
317
- drop: tagAsFileHandler((event) => {
318
- event.preventDefault();
319
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
320
- const dragEvent = event;
321
- const zone = dragEvent.currentTarget;
322
- if (zone instanceof Element) {
323
- clearDragZoneAfterDrop(zone);
324
- }
325
- const files = dragEvent.dataTransfer?.files
326
- ? Array.fromIterable(dragEvent.dataTransfer.files)
327
- : Array.empty();
328
- dispatchSync(f(files));
329
- }, 'OnDropFiles'),
330
- }),
331
- OnTouchStart: ({ message }) => updateDataOn({
332
- touchstart: () => dispatchSync(message),
333
- }),
334
- OnTouchEnd: ({ message }) => updateDataOn({
335
- touchend: () => dispatchSync(message),
336
- }),
337
- OnTouchMove: ({ message }) => updateDataOn({
338
- touchmove: () => dispatchSync(message),
339
- }),
340
- OnTouchCancel: ({ message }) => updateDataOn({
341
- touchcancel: () => dispatchSync(message),
342
- }),
343
- OnAnimationStart: ({ message }) => updateDataOn({
344
- animationstart: () => dispatchSync(message),
345
- }),
346
- OnAnimationEnd: ({ message }) => updateDataOn({
347
- animationend: () => dispatchSync(message),
348
- }),
349
- OnAnimationIteration: ({ message }) => updateDataOn({
350
- animationiteration: () => dispatchSync(message),
351
- }),
352
- OnTransitionEnd: ({ message }) => updateDataOn({
353
- transitionend: () => dispatchSync(message),
354
- }),
355
- OnLoad: ({ message }) => updateDataOn({
356
- load: () => dispatchSync(message),
357
- }),
358
- OnError: ({ message }) => updateDataOn({
359
- error: () => dispatchSync(message),
360
- }),
361
- OnPlay: ({ message }) => updateDataOn({
362
- play: () => dispatchSync(message),
363
- }),
364
- OnPause: ({ message }) => updateDataOn({
365
- pause: () => dispatchSync(message),
366
- }),
367
- OnEnded: ({ message }) => updateDataOn({
368
- ended: () => dispatchSync(message),
369
- }),
370
- OnTimeUpdate: ({ message }) => updateDataOn({
371
- timeupdate: () => dispatchSync(message),
372
- }),
373
- OnVolumeChange: ({ message }) => updateDataOn({
374
- volumechange: () => dispatchSync(message),
375
- }),
376
- OnSelect: ({ message }) => updateDataOn({
377
- select: () => dispatchSync(message),
378
- }),
379
- Value: ({ value }) => updatePropsWithPostpatch('value', value),
380
- Checked: ({ value }) => updatePropsWithPostpatch('checked', value),
381
- Selected: ({ value }) => updatePropsWithPostpatch('selected', value),
382
- Open: ({ value }) => updatePropsWithPostpatch('open', value),
383
- Placeholder: ({ value }) => updateDataProps({ placeholder: value }),
384
- Name: ({ value }) => updateDataProps({ name: value }),
385
- Disabled: ({ value }) => updateDataProps({ disabled: value }),
386
- Readonly: ({ value }) => updateDataProps({ readOnly: value }),
387
- Required: ({ value }) => updateDataProps({ required: value }),
388
- Autofocus: ({ value }) => updateDataProps({ autofocus: value }),
389
- Spellcheck: ({ value }) => updateDataAttrs({ spellcheck: value.toString() }),
390
- Autocorrect: ({ value }) => updateDataAttrs({ autocorrect: value }),
391
- Autocapitalize: ({ value }) => updateDataAttrs({ autocapitalize: value }),
392
- InputMode: ({ value }) => updateDataAttrs({ inputmode: value }),
393
- EnterKeyHint: ({ value }) => updateDataAttrs({ enterkeyhint: value }),
394
- Multiple: ({ value }) => updateDataProps({ multiple: value }),
395
- Type: ({ value }) => updateDataProps({ type: value }),
396
- Accept: ({ value }) => updateDataProps({ accept: value }),
397
- Autocomplete: ({ value }) => updateDataProps({ autocomplete: value }),
398
- Pattern: ({ value }) => updateDataProps({ pattern: value }),
399
- Maxlength: ({ value }) => updateDataProps({ maxLength: value }),
400
- Minlength: ({ value }) => updateDataProps({ minLength: value }),
401
- Size: ({ value }) => updateDataProps({ size: value }),
402
- Cols: ({ value }) => updateDataProps({ cols: value }),
403
- Rows: ({ value }) => updateDataProps({ rows: value }),
404
- Max: ({ value }) => updateDataProps({ max: value }),
405
- Min: ({ value }) => updateDataProps({ min: value }),
406
- Step: ({ value }) => updateDataProps({ step: value }),
407
- For: ({ value }) => updateDataProps({ htmlFor: value }),
408
- Href: ({ value }) => updateDataProps({ href: value }),
409
- Src: ({ value }) => updateDataProps({ src: value }),
410
- Alt: ({ value }) => updateDataProps({ alt: value }),
411
- Target: ({ value }) => updateDataProps({ target: value }),
412
- Rel: ({ value }) => updateDataProps({ rel: value }),
413
- Download: ({ value }) => updateDataProps({ download: value }),
414
- Action: ({ value }) => updateDataProps({ action: value }),
415
- Method: ({ value }) => updateDataProps({ method: value }),
416
- Enctype: ({ value }) => updateDataProps({ enctype: value }),
417
- Novalidate: ({ value }) => updateDataProps({ noValidate: value }),
418
- Formaction: ({ value }) => updateDataProps({ formAction: value }),
419
- Formmethod: ({ value }) => updateDataProps({ formMethod: value }),
420
- Formnovalidate: ({ value }) => updateDataProps({ formNoValidate: value }),
421
- Formtarget: ({ value }) => updateDataProps({ formTarget: value }),
422
- Formenctype: ({ value }) => updateDataProps({ formEnctype: value }),
423
- Colspan: ({ value }) => updateDataProps({ colSpan: value }),
424
- Rowspan: ({ value }) => updateDataProps({ rowSpan: value }),
425
- Scope: ({ value }) => updateDataAttrs({ scope: value }),
426
- Headers: ({ value }) => updateDataAttrs({ headers: value }),
427
- Span: ({ value }) => updateDataProps({ span: value }),
428
- Start: ({ value }) => updateDataProps({ start: value }),
429
- Reversed: ({ value }) => updateDataProps({ reversed: value }),
430
- CiteAttr: ({ value }) => updateDataProps({ cite: value }),
431
- Datetime: ({ value }) => updateDataProps({ dateTime: value }),
432
- Wrap: ({ value }) => updateDataProps({ wrap: value }),
433
- List: ({ value }) => updateDataAttrs({ list: value }),
434
- FormAttr: ({ value }) => updateDataAttrs({ form: value }),
435
- LabelAttr: ({ value }) => updateDataProps({ label: value }),
436
- ContentAttr: ({ value }) => updateDataAttrs({ content: value }),
437
- Charset: ({ value }) => updateDataAttrs({ charset: value }),
438
- HttpEquiv: ({ value }) => updateDataAttrs({ 'http-equiv': value }),
439
- Srcset: ({ value }) => updateDataAttrs({ srcset: value }),
440
- Sizes: ({ value }) => updateDataAttrs({ sizes: value }),
441
- Loading: ({ value }) => updateDataAttrs({ loading: value }),
442
- Decoding: ({ value }) => updateDataAttrs({ decoding: value }),
443
- Fetchpriority: ({ value }) => updateDataAttrs({ fetchpriority: value }),
444
- Crossorigin: ({ value }) => updateDataAttrs({ crossorigin: value }),
445
- Referrerpolicy: ({ value }) => updateDataAttrs({ referrerpolicy: value }),
446
- Integrity: ({ value }) => updateDataAttrs({ integrity: value }),
447
- Hreflang: ({ value }) => updateDataAttrs({ hreflang: value }),
448
- Ping: ({ value }) => updateDataAttrs({ ping: value }),
449
- Sandbox: ({ value }) => updateDataAttrs({ sandbox: value }),
450
- Allow: ({ value }) => updateDataAttrs({ allow: value }),
451
- Srcdoc: ({ value }) => updateDataAttrs({ srcdoc: value }),
452
- Autoplay: ({ value }) => updateDataProps({ autoplay: value }),
453
- Controls: ({ value }) => updateDataProps({ controls: value }),
454
- Loop: ({ value }) => updateDataProps({ loop: value }),
455
- Muted: ({ value }) => updatePropsWithPostpatch('muted', value),
456
- Poster: ({ value }) => updateDataProps({ poster: value }),
457
- Preload: ({ value }) => updateDataProps({ preload: value }),
458
- Playsinline: ({ value }) => updateDataProps({ playsInline: value }),
459
- High: ({ value }) => updateDataProps({ high: value }),
460
- Low: ({ value }) => updateDataProps({ low: value }),
461
- Optimum: ({ value }) => updateDataProps({ optimum: value }),
462
- Usemap: ({ value }) => updateDataAttrs({ usemap: value }),
463
- Ismap: ({ value }) => updateDataProps({ isMap: value }),
464
- Role: ({ value }) => updateDataAttrs({ role: value }),
465
- AriaLabel: ({ value }) => updateDataAttrs({ 'aria-label': value }),
466
- AriaLabelledBy: ({ value }) => updateDataAttrs({ 'aria-labelledby': value }),
467
- AriaDescribedBy: ({ value }) => updateDataAttrs({ 'aria-describedby': value }),
468
- AriaHidden: ({ value }) => updateDataAttrs({ 'aria-hidden': value.toString() }),
469
- AriaExpanded: ({ value }) => updateDataAttrs({ 'aria-expanded': value.toString() }),
470
- AriaSelected: ({ value }) => updateDataAttrs({ 'aria-selected': value.toString() }),
471
- AriaChecked: ({ value }) => updateDataAttrs({ 'aria-checked': value.toString() }),
472
- AriaDisabled: ({ value }) => updateDataAttrs({ 'aria-disabled': value.toString() }),
473
- AriaRequired: ({ value }) => updateDataAttrs({ 'aria-required': value.toString() }),
474
- AriaInvalid: ({ value }) => updateDataAttrs({ 'aria-invalid': value.toString() }),
475
- AriaLive: ({ value }) => updateDataAttrs({ 'aria-live': value }),
476
- AriaControls: ({ value }) => updateDataAttrs({ 'aria-controls': value }),
477
- AriaCurrent: ({ value }) => updateDataAttrs({ 'aria-current': value }),
478
- AriaOrientation: ({ value }) => updateDataAttrs({ 'aria-orientation': value }),
479
- AriaPressed: ({ value }) => updateDataAttrs({ 'aria-pressed': value }),
480
- AriaHasPopup: ({ value }) => updateDataAttrs({ 'aria-haspopup': value }),
481
- AriaActiveDescendant: ({ value }) => updateDataAttrs({ 'aria-activedescendant': value }),
482
- AriaSort: ({ value }) => updateDataAttrs({ 'aria-sort': value }),
483
- AriaMultiSelectable: ({ value }) => updateDataAttrs({ 'aria-multiselectable': value.toString() }),
484
- AriaModal: ({ value }) => updateDataAttrs({ 'aria-modal': value.toString() }),
485
- AriaBusy: ({ value }) => updateDataAttrs({ 'aria-busy': value.toString() }),
486
- AriaErrorMessage: ({ value }) => updateDataAttrs({ 'aria-errormessage': value }),
487
- AriaRoleDescription: ({ value }) => updateDataAttrs({ 'aria-roledescription': value }),
488
- AriaAtomic: ({ value }) => updateDataAttrs({ 'aria-atomic': value.toString() }),
489
- AriaAutocomplete: ({ value }) => updateDataAttrs({ 'aria-autocomplete': value }),
490
- AriaColcount: ({ value }) => updateDataAttrs({ 'aria-colcount': value.toString() }),
491
- AriaColindex: ({ value }) => updateDataAttrs({ 'aria-colindex': value.toString() }),
492
- AriaColspan: ({ value }) => updateDataAttrs({ 'aria-colspan': value.toString() }),
493
- AriaDescription: ({ value }) => updateDataAttrs({ 'aria-description': value }),
494
- AriaDetails: ({ value }) => updateDataAttrs({ 'aria-details': value }),
495
- AriaFlowto: ({ value }) => updateDataAttrs({ 'aria-flowto': value }),
496
- AriaKeyshortcuts: ({ value }) => updateDataAttrs({ 'aria-keyshortcuts': value }),
497
- AriaLevel: ({ value }) => updateDataAttrs({ 'aria-level': value.toString() }),
498
- AriaOwns: ({ value }) => updateDataAttrs({ 'aria-owns': value }),
499
- AriaPlaceholder: ({ value }) => updateDataAttrs({ 'aria-placeholder': value }),
500
- AriaPosinset: ({ value }) => updateDataAttrs({ 'aria-posinset': value.toString() }),
501
- AriaReadonly: ({ value }) => updateDataAttrs({ 'aria-readonly': value.toString() }),
502
- AriaRelevant: ({ value }) => updateDataAttrs({ 'aria-relevant': value }),
503
- AriaRowcount: ({ value }) => updateDataAttrs({ 'aria-rowcount': value.toString() }),
504
- AriaRowindex: ({ value }) => updateDataAttrs({ 'aria-rowindex': value.toString() }),
505
- AriaRowspan: ({ value }) => updateDataAttrs({ 'aria-rowspan': value.toString() }),
506
- AriaSetsize: ({ value }) => updateDataAttrs({ 'aria-setsize': value.toString() }),
507
- AriaValuemax: ({ value }) => updateDataAttrs({ 'aria-valuemax': value.toString() }),
508
- AriaValuemin: ({ value }) => updateDataAttrs({ 'aria-valuemin': value.toString() }),
509
- AriaValuenow: ({ value }) => updateDataAttrs({ 'aria-valuenow': value.toString() }),
510
- AriaValuetext: ({ value }) => updateDataAttrs({ 'aria-valuetext': value }),
511
- Attribute: ({ key, value }) => updateDataAttrs({ [key]: value }),
512
- DataAttribute: ({ key, value }) => updateDataAttrs({ [`data-${key}`]: value }),
513
- Style: ({ value }) => setData('style', value),
514
- InnerHTML: ({ value }) => updateDataProps({ innerHTML: value }),
515
- ViewBox: ({ value }) => updateDataAttrs({ viewBox: value }),
516
- Xmlns: ({ value }) => updateDataAttrs({ xmlns: value }),
517
- Fill: ({ value }) => updateDataAttrs({ fill: value }),
518
- FillRule: ({ value }) => updateDataAttrs({ 'fill-rule': value }),
519
- ClipRule: ({ value }) => updateDataAttrs({ 'clip-rule': value }),
520
- Stroke: ({ value }) => updateDataAttrs({ stroke: value }),
521
- StrokeWidth: ({ value }) => updateDataAttrs({ 'stroke-width': value }),
522
- StrokeLinecap: ({ value }) => updateDataAttrs({ 'stroke-linecap': value }),
523
- StrokeLinejoin: ({ value }) => updateDataAttrs({ 'stroke-linejoin': value }),
524
- D: ({ value }) => updateDataAttrs({ d: value }),
525
- Cx: ({ value }) => updateDataAttrs({ cx: value }),
526
- Cy: ({ value }) => updateDataAttrs({ cy: value }),
527
- R: ({ value }) => updateDataAttrs({ r: value }),
528
- X: ({ value }) => updateDataAttrs({ x: value }),
529
- Y: ({ value }) => updateDataAttrs({ y: value }),
530
- Width: ({ value }) => updateDataAttrs({ width: value }),
531
- Height: ({ value }) => updateDataAttrs({ height: value }),
532
- X1: ({ value }) => updateDataAttrs({ x1: value }),
533
- Y1: ({ value }) => updateDataAttrs({ y1: value }),
534
- X2: ({ value }) => updateDataAttrs({ x2: value }),
535
- Y2: ({ value }) => updateDataAttrs({ y2: value }),
536
- Points: ({ value }) => updateDataAttrs({ points: value }),
537
- Transform: ({ value }) => updateDataAttrs({ transform: value }),
538
- Opacity: ({ value }) => updateDataAttrs({ opacity: value }),
539
- StrokeDasharray: ({ value }) => updateDataAttrs({ 'stroke-dasharray': value }),
540
- StrokeDashoffset: ({ value }) => updateDataAttrs({ 'stroke-dashoffset': value }),
541
- Prop: ({ key, value }) => updateDataProps({ [key]: value }),
542
- OnCustomEvent: ({ name, f }) => updateDataOn({
543
- [name]: (event) => {
544
- if (event instanceof CustomEvent) {
545
- dispatchSync(f(event));
561
+ destroy: vnode => {
562
+ if (vnode.elm instanceof Element) {
563
+ const state = onMountStates.get(vnode.elm);
564
+ if (state) {
565
+ Effect.runFork(Fiber.interrupt(state.fiber));
566
+ onMountStates.delete(vnode.elm);
567
+ notifyEnded();
568
+ }
546
569
  }
547
570
  },
548
- }),
549
- OnMount: ({ action }) => {
550
- const maybeTracker = Context.getOption(capturedContext, MountTracker);
551
- const notifyStarted = Option.isSome(maybeTracker)
552
- ? () => maybeTracker.value.started(action.name, action.args)
553
- : Function.constVoid;
554
- const notifyEnded = Option.isSome(maybeTracker)
555
- ? () => maybeTracker.value.ended(action.name, action.args)
556
- : Function.constVoid;
557
- const marker = action.args === undefined
558
- ? { name: action.name }
559
- : { name: action.name, args: action.args };
560
- return Ref.update(dataRef, data => ({
561
- ...data,
562
- [FOLDKIT_MOUNT_KEY]: marker,
563
- hook: {
564
- ...data.hook,
565
- insert: vnode => {
566
- if (vnode.elm instanceof Element) {
567
- const element = vnode.elm;
568
- notifyStarted();
569
- const fiber = Effect.runForkWith(capturedContext)(Stream.runForEach(action.f(element), message => Effect.sync(() => dispatchSync(message))).pipe(Effect.catchCause(cause => Effect.sync(() => {
570
- console.error(`[OnMount ${action.name}] unhandled failure`, cause);
571
- }))));
572
- onMountStates.set(element, { fiber });
573
- }
574
- },
575
- destroy: vnode => {
576
- if (vnode.elm instanceof Element) {
577
- const state = onMountStates.get(vnode.elm);
578
- if (state) {
579
- Effect.runFork(Fiber.interrupt(state.fiber));
580
- onMountStates.delete(vnode.elm);
581
- notifyEnded();
582
- }
583
- }
584
- },
585
- },
586
- }));
587
- },
588
- })));
589
- const postpatchProps = yield* Ref.get(postpatchPropsRef);
571
+ };
572
+ },
573
+ }));
574
+ const buildVNodeData = (attributes) => {
575
+ // Capture lazily, and tolerate the absence of a runtime frame. Static
576
+ // elements (`h.code([h.Class('x')], ['text'])`) and prose fragments built
577
+ // at module top level (`const fragment = inlineCode('foo')` at import
578
+ // time) must construct without an active render frame. They never invoke
579
+ // the fallback dispatcher because they have no event handlers; event-
580
+ // bearing Html constructed outside a render reaches the fallback only at
581
+ // event-fire time, which surfaces a clear error rather than failing at
582
+ // import time.
583
+ let cachedCurrentDispatch;
584
+ const getCurrentDispatch = () => {
585
+ if (cachedCurrentDispatch === undefined) {
586
+ try {
587
+ cachedCurrentDispatch = requireDispatch();
588
+ }
589
+ catch {
590
+ cachedCurrentDispatch = () => {
591
+ throw new Error('Foldkit: an event-bearing Html attribute fired without an ' +
592
+ 'active runtime frame. This typically means an Html element ' +
593
+ 'with event handlers (OnClick, OnInput, etc.) was constructed ' +
594
+ 'at module top level outside of a view function.');
595
+ };
596
+ }
597
+ }
598
+ return cachedCurrentDispatch;
599
+ };
600
+ let cachedCapturedContext;
601
+ const getCapturedContext = () => {
602
+ if (cachedCapturedContext === undefined) {
603
+ try {
604
+ cachedCapturedContext = requireRuntimeContext();
605
+ }
606
+ catch {
607
+ cachedCapturedContext = Context.empty();
608
+ }
609
+ }
610
+ return cachedCapturedContext;
611
+ };
612
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
613
+ const data = {};
614
+ const postpatchProps = [];
615
+ // Most attributes route through the current frame's dispatch. ChildAttribute
616
+ // items carry a different dispatcher (captured by `childAttributes`
617
+ // in a Submodel's own boundary), so they need their own BuildContext closed
618
+ // over that dispatch. The matcher itself is module-level and shared.
619
+ // The main ctx is built lazily. Static-only attribute arrays (Class, Id,
620
+ // etc. with no event handlers) skip `requireDispatch` entirely so Html can
621
+ // be constructed at module top level.
622
+ let mainCtx;
623
+ const boundaryCtxByDispatch = new Map();
624
+ for (const item of attributes) {
625
+ if (isChildAttribute(item)) {
626
+ let ctx = boundaryCtxByDispatch.get(item.dispatch);
627
+ if (ctx === undefined) {
628
+ ctx = {
629
+ data,
630
+ postpatchProps,
631
+ dispatch: item.dispatch,
632
+ getCapturedContext,
633
+ };
634
+ boundaryCtxByDispatch.set(item.dispatch, ctx);
635
+ }
636
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
637
+ attributeMatcher(item.attribute)(ctx);
638
+ }
639
+ else {
640
+ if (mainCtx === undefined) {
641
+ mainCtx = {
642
+ data,
643
+ postpatchProps,
644
+ dispatch: getCurrentDispatch(),
645
+ getCapturedContext,
646
+ };
647
+ }
648
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
649
+ attributeMatcher(item)(mainCtx);
650
+ }
651
+ }
590
652
  if (Array.isReadonlyArrayNonEmpty(postpatchProps)) {
591
- yield* Ref.update(dataRef, data => ({
592
- ...data,
593
- hook: {
594
- ...data.hook,
595
- postpatch: (_oldVnode, vnode) => {
596
- if (vnode.elm) {
597
- Array.forEach(postpatchProps, ({ propName, value }) => {
653
+ data.hook = {
654
+ ...data.hook,
655
+ postpatch: (_oldVnode, vnode) => {
656
+ if (vnode.elm) {
657
+ Array.forEach(postpatchProps, ({ propName, value }) => {
658
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
659
+ if (vnode.elm[propName] !== value) {
598
660
  /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
599
- if (vnode.elm[propName] !== value) {
600
- /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
601
- ;
602
- vnode.elm[propName] = value;
603
- }
604
- });
605
- }
606
- },
661
+ ;
662
+ vnode.elm[propName] = value;
663
+ }
664
+ });
665
+ }
607
666
  },
608
- }));
667
+ };
609
668
  }
610
- return yield* Ref.get(dataRef);
611
- });
612
- const processVNodeChildren = (children) => Effect.forEach(children, (child) => Predicate.isString(child) ? Effect.succeed(child) : child).pipe(Effect.map(Array.filter(Predicate.isNotNull)));
613
- const createElement = (tagName, attributes = [], children = []) => Effect.gen(function* () {
614
- const vnodeData = yield* buildVNodeData(attributes);
615
- const vnodeChildren = yield* processVNodeChildren(children);
616
- return h(tagName, vnodeData, Array.fromIterable(vnodeChildren));
617
- });
669
+ return data;
670
+ };
671
+ const processVNodeChildren = (children) => Array.filter(children, Predicate.isNotNull);
672
+ const createElement = (tagName, attributes = [], children = []) => h(tagName, buildVNodeData(attributes), Array.fromIterable(processVNodeChildren(children)));
618
673
  const element = () => (tagName) => (attributes = [], children = []) => createElement(tagName, attributes, children);
619
674
  export const customElement = () => (tagName) => (attributes = [], children = []) => createElement(tagName, attributes, children);
620
675
  const voidElement = () => (tagName) => (attributes = []) => createElement(tagName, attributes, []);
@@ -1080,16 +1135,25 @@ const htmlAttributes = () => ({
1080
1135
  StrokeDashoffset: (value) => StrokeDashoffset({ value }),
1081
1136
  OnMount: (action) => OnMount({ action }),
1082
1137
  });
1138
+ const buildHtmlFactory = () => ({
1139
+ ...htmlElements(),
1140
+ ...htmlAttributes(),
1141
+ empty: null,
1142
+ keyed: keyed(),
1143
+ submodel,
1144
+ });
1145
+ const cachedHtmlFactory = buildHtmlFactory();
1083
1146
  /**
1084
- * Factory that returns all HTML, SVG, and MathML element constructors,
1085
- * attribute constructors, a `keyed` helper for keyed elements, and `empty`
1086
- * for rendering nothing.
1147
+ * Returns all HTML, SVG, and MathML element constructors, attribute
1148
+ * constructors, a `keyed` helper for keyed elements, and `empty` for
1149
+ * rendering nothing.
1150
+ *
1151
+ * The returned object is a process-wide singleton. The `Message` type
1152
+ * parameter is erased at runtime, and the element and attribute constructors
1153
+ * carry no per-program state (dispatch is read from the runtime singleton at
1154
+ * call time), so calling `html()` repeatedly from inside view functions does
1155
+ * not allocate a fresh object.
1087
1156
  */
1088
- export const html = () => {
1089
- return {
1090
- ...htmlElements(),
1091
- ...htmlAttributes(),
1092
- empty: Effect.succeed(null),
1093
- keyed: keyed(),
1094
- };
1095
- };
1157
+ export const html = () =>
1158
+ /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
1159
+ cachedHtmlFactory;