@exponential_app/eui 0.0.0-stage → 0.2.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 (272) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +54 -0
  3. package/README.md +377 -2
  4. package/catalog/a11y.json +705 -0
  5. package/catalog/basic-map.json +104 -0
  6. package/catalog/code.json +58 -0
  7. package/catalog/core.catalog.json +5190 -0
  8. package/catalog/core.schema.json +24542 -0
  9. package/catalog/host.json +95 -0
  10. package/catalog/layout.json +20 -0
  11. package/catalog/limits.json +9 -0
  12. package/catalog/locale.json +48 -0
  13. package/catalog/macros.json +4152 -0
  14. package/catalog/recipes.json +64 -0
  15. package/catalog/strings.json +84 -0
  16. package/catalog/style.json +180 -0
  17. package/catalog/theme.schema.json +47754 -0
  18. package/catalog/tokens.json +47 -0
  19. package/conformance/README.md +218 -0
  20. package/conformance/baseline.ts +101 -0
  21. package/conformance/browser-page.ts +146 -0
  22. package/conformance/browser-suites.ts +699 -0
  23. package/conformance/compare.ts +201 -0
  24. package/conformance/dom.ts +97 -0
  25. package/conformance/dump.ts +163 -0
  26. package/conformance/fonts.json +157 -0
  27. package/conformance/manifest.json +233 -0
  28. package/conformance/parity-compare.ts +191 -0
  29. package/conformance/parity-report.schema.json +73 -0
  30. package/conformance/parity.ts +412 -0
  31. package/conformance/pixel.ts +177 -0
  32. package/conformance/primitives-page.ts +49 -0
  33. package/conformance/report.schema.json +66 -0
  34. package/conformance/run.ts +118 -0
  35. package/conformance/voice-wave-child.ts +102 -0
  36. package/dist/chunks/index-5fmaa0xq.js +8384 -0
  37. package/dist/chunks/index-5fmaa0xq.js.map +10 -0
  38. package/dist/chunks/index-62yzr94z.js +2784 -0
  39. package/dist/chunks/index-62yzr94z.js.map +10 -0
  40. package/dist/chunks/index-bg2jsgjq.js +8541 -0
  41. package/dist/chunks/index-bg2jsgjq.js.map +15 -0
  42. package/dist/chunks/index-fy7y2nz8.js +186 -0
  43. package/dist/chunks/index-fy7y2nz8.js.map +9 -0
  44. package/dist/chunks/index-gtk2gwsb.js +4555 -0
  45. package/dist/chunks/index-gtk2gwsb.js.map +31 -0
  46. package/dist/chunks/index-t6qz1770.js +95 -0
  47. package/dist/chunks/index-t6qz1770.js.map +11 -0
  48. package/dist/conformance.js +230462 -0
  49. package/dist/conformance.js.map +10 -0
  50. package/dist/entries/prompt.js +251 -0
  51. package/dist/entries/prompt.js.map +11 -0
  52. package/dist/entries/schema.js +1725 -0
  53. package/dist/entries/schema.js.map +11 -0
  54. package/dist/host/index.js +194 -0
  55. package/dist/host/index.js.map +9 -0
  56. package/dist/index.js +3840 -0
  57. package/dist/index.js.map +29 -0
  58. package/dist/types/src/a11y.d.ts +21 -0
  59. package/dist/types/src/animation.d.ts +76 -0
  60. package/dist/types/src/basic-map.d.ts +38 -0
  61. package/dist/types/src/builder.d.ts +50 -0
  62. package/dist/types/src/catalog.d.ts +54 -0
  63. package/dist/types/src/catalog.described.d.ts +33 -0
  64. package/dist/types/src/catalog.generated.d.ts +904 -0
  65. package/dist/types/src/chart.d.ts +46 -0
  66. package/dist/types/src/code.d.ts +44 -0
  67. package/dist/types/src/color.d.ts +20 -0
  68. package/dist/types/src/conformance.d.ts +39 -0
  69. package/dist/types/src/connector/app.d.ts +14 -0
  70. package/dist/types/src/connector/connector.d.ts +77 -0
  71. package/dist/types/src/connector/index.d.ts +4 -0
  72. package/dist/types/src/css.d.ts +27 -0
  73. package/dist/types/src/define.d.ts +66 -0
  74. package/dist/types/src/direction.d.ts +16 -0
  75. package/dist/types/src/dynamic.d.ts +161 -0
  76. package/dist/types/src/entries/prompt.d.ts +11 -0
  77. package/dist/types/src/entries/schema.d.ts +8 -0
  78. package/dist/types/src/expr.d.ts +71 -0
  79. package/dist/types/src/extension.d.ts +4 -0
  80. package/dist/types/src/format.d.ts +112 -0
  81. package/dist/types/src/geometry.d.ts +40 -0
  82. package/dist/types/src/host/contract.d.ts +225 -0
  83. package/dist/types/src/host/decoders.d.ts +61 -0
  84. package/dist/types/src/host/index.d.ts +15 -0
  85. package/dist/types/src/host/package.d.ts +102 -0
  86. package/dist/types/src/host/policy.d.ts +107 -0
  87. package/dist/types/src/host/record-store.d.ts +103 -0
  88. package/dist/types/src/host/records.d.ts +45 -0
  89. package/dist/types/src/host/router.d.ts +38 -0
  90. package/dist/types/src/host/runtime.d.ts +213 -0
  91. package/dist/types/src/host/signature.d.ts +52 -0
  92. package/dist/types/src/host/sources.d.ts +22 -0
  93. package/dist/types/src/host/tools.d.ts +42 -0
  94. package/dist/types/src/host/transports.d.ts +109 -0
  95. package/dist/types/src/index.d.ts +69 -0
  96. package/dist/types/src/layout.d.ts +20 -0
  97. package/dist/types/src/limits.d.ts +21 -0
  98. package/dist/types/src/list.d.ts +133 -0
  99. package/dist/types/src/locale.d.ts +22 -0
  100. package/dist/types/src/macros.d.ts +29 -0
  101. package/dist/types/src/overlay.d.ts +27 -0
  102. package/dist/types/src/prompt.d.ts +44 -0
  103. package/dist/types/src/qr-code.d.ts +30 -0
  104. package/dist/types/src/recipes.d.ts +17 -0
  105. package/dist/types/src/reducer.d.ts +41 -0
  106. package/dist/types/src/resizable.d.ts +38 -0
  107. package/dist/types/src/schema.d.ts +7 -0
  108. package/dist/types/src/strings.d.ts +13 -0
  109. package/dist/types/src/style.d.ts +201 -0
  110. package/dist/types/src/test-preload.d.ts +1 -0
  111. package/dist/types/src/text-shimmer.d.ts +24 -0
  112. package/dist/types/src/theme-types.d.ts +162 -0
  113. package/dist/types/src/theme.d.ts +75 -0
  114. package/dist/types/src/themes.d.ts +22 -0
  115. package/dist/types/src/tree-guides.d.ts +17 -0
  116. package/dist/types/src/types.d.ts +320 -0
  117. package/dist/types/src/validate.d.ts +31 -0
  118. package/dist/types/src/voice-wave.d.ts +181 -0
  119. package/dist/types/src/web/base-css.d.ts +1 -0
  120. package/dist/types/src/web/box-css.d.ts +63 -0
  121. package/dist/types/src/web/coerce.d.ts +32 -0
  122. package/dist/types/src/web/custom-icons.generated.d.ts +4 -0
  123. package/dist/types/src/web/data.d.ts +107 -0
  124. package/dist/types/src/web/dates.d.ts +12 -0
  125. package/dist/types/src/web/form.d.ts +44 -0
  126. package/dist/types/src/web/host-types.d.ts +126 -0
  127. package/dist/types/src/web/index.d.ts +35 -0
  128. package/dist/types/src/web/inputs.d.ts +55 -0
  129. package/dist/types/src/web/list.d.ts +16 -0
  130. package/dist/types/src/web/listbox.d.ts +14 -0
  131. package/dist/types/src/web/markdown.d.ts +96 -0
  132. package/dist/types/src/web/media.d.ts +63 -0
  133. package/dist/types/src/web/parts.d.ts +4 -0
  134. package/dist/types/src/web/primitives/alert-dialog.d.ts +10 -0
  135. package/dist/types/src/web/primitives/alert.d.ts +9 -0
  136. package/dist/types/src/web/primitives/avatar-color.d.ts +2 -0
  137. package/dist/types/src/web/primitives/avatar.d.ts +13 -0
  138. package/dist/types/src/web/primitives/badge.d.ts +10 -0
  139. package/dist/types/src/web/primitives/breadcrumb.d.ts +10 -0
  140. package/dist/types/src/web/primitives/button.d.ts +6 -0
  141. package/dist/types/src/web/primitives/calendar.d.ts +43 -0
  142. package/dist/types/src/web/primitives/card.d.ts +9 -0
  143. package/dist/types/src/web/primitives/checkbox.d.ts +5 -0
  144. package/dist/types/src/web/primitives/choice-tiles.d.ts +32 -0
  145. package/dist/types/src/web/primitives/cn.d.ts +3 -0
  146. package/dist/types/src/web/primitives/code-block.d.ts +24 -0
  147. package/dist/types/src/web/primitives/command.d.ts +134 -0
  148. package/dist/types/src/web/primitives/context-ring.d.ts +24 -0
  149. package/dist/types/src/web/primitives/dialog-arms.d.ts +6 -0
  150. package/dist/types/src/web/primitives/dialog.d.ts +24 -0
  151. package/dist/types/src/web/primitives/disclosure-header.d.ts +5 -0
  152. package/dist/types/src/web/primitives/dock.d.ts +42 -0
  153. package/dist/types/src/web/primitives/dropdown-menu.d.ts +14 -0
  154. package/dist/types/src/web/primitives/empty-state.d.ts +15 -0
  155. package/dist/types/src/web/primitives/glass-card.d.ts +4 -0
  156. package/dist/types/src/web/primitives/hover-card.d.ts +7 -0
  157. package/dist/types/src/web/primitives/icon-disc.d.ts +12 -0
  158. package/dist/types/src/web/primitives/index.d.ts +50 -0
  159. package/dist/types/src/web/primitives/input.d.ts +5 -0
  160. package/dist/types/src/web/primitives/kbd.d.ts +4 -0
  161. package/dist/types/src/web/primitives/label.d.ts +3 -0
  162. package/dist/types/src/web/primitives/measure.d.ts +16 -0
  163. package/dist/types/src/web/primitives/menu-surface.d.ts +17 -0
  164. package/dist/types/src/web/primitives/meter.d.ts +21 -0
  165. package/dist/types/src/web/primitives/popover.d.ts +3 -0
  166. package/dist/types/src/web/primitives/progress-ring.d.ts +5 -0
  167. package/dist/types/src/web/primitives/progress.d.ts +8 -0
  168. package/dist/types/src/web/primitives/scroll-area.d.ts +49 -0
  169. package/dist/types/src/web/primitives/segmented-control.d.ts +5 -0
  170. package/dist/types/src/web/primitives/select.d.ts +47 -0
  171. package/dist/types/src/web/primitives/separator.d.ts +3 -0
  172. package/dist/types/src/web/primitives/sheet-chrome.d.ts +4 -0
  173. package/dist/types/src/web/primitives/sheet.d.ts +20 -0
  174. package/dist/types/src/web/primitives/skeleton.d.ts +3 -0
  175. package/dist/types/src/web/primitives/spinner.d.ts +3 -0
  176. package/dist/types/src/web/primitives/switch.d.ts +4 -0
  177. package/dist/types/src/web/primitives/table.d.ts +11 -0
  178. package/dist/types/src/web/primitives/tabs.d.ts +13 -0
  179. package/dist/types/src/web/primitives/textarea.d.ts +3 -0
  180. package/dist/types/src/web/primitives/toast.d.ts +163 -0
  181. package/dist/types/src/web/primitives/tooltip.d.ts +3 -0
  182. package/dist/types/src/web/primitives/truncate.d.ts +7 -0
  183. package/dist/types/src/web/primitives/typeahead-portal.d.ts +12 -0
  184. package/dist/types/src/web/primitives/voice-wave.d.ts +50 -0
  185. package/dist/types/src/web/round5.d.ts +107 -0
  186. package/dist/types/src/web/share.d.ts +6 -0
  187. package/dist/types/src/web/table.d.ts +20 -0
  188. package/dist/types/src/web/theme-css.d.ts +69 -0
  189. package/dist/types/src/web/urls.d.ts +21 -0
  190. package/dist/web/index.js +2565 -0
  191. package/dist/web/index.js.map +28 -0
  192. package/dist/web/primitives/index.js +1476 -0
  193. package/dist/web/primitives/index.js.map +57 -0
  194. package/docs/components.generated.json +6783 -0
  195. package/docs/package-format.md +182 -0
  196. package/docs/round-1-contract.md +679 -0
  197. package/docs/round-2-contract.md +476 -0
  198. package/docs/round-3-contract.md +174 -0
  199. package/docs/round-5-contract.md +268 -0
  200. package/docs/themes.generated.json +3647 -0
  201. package/fixtures/animations.json +2890 -0
  202. package/fixtures/bench-list.json +58 -0
  203. package/fixtures/bind-time.json +54734 -0
  204. package/fixtures/catalog-basic-map.json +1692 -0
  205. package/fixtures/catalog-components.json +10293 -0
  206. package/fixtures/catalog-extension.json +620 -0
  207. package/fixtures/catalog-macros.json +51805 -0
  208. package/fixtures/code-tokens.json +1993 -0
  209. package/fixtures/conformance-baseline.json +59016 -0
  210. package/fixtures/conformance-cases.json +49 -0
  211. package/fixtures/conformance-known.json +2111 -0
  212. package/fixtures/control-geometry.json +5129 -0
  213. package/fixtures/dashboard.data.json +74 -0
  214. package/fixtures/dashboard.json +781 -0
  215. package/fixtures/demo-surface.json +47 -0
  216. package/fixtures/format.json +870 -0
  217. package/fixtures/host-package.json +1262 -0
  218. package/fixtures/host-policy.json +1209 -0
  219. package/fixtures/host-router.json +2034 -0
  220. package/fixtures/host-transport.json +590 -0
  221. package/fixtures/interactions-round1.json +1058 -0
  222. package/fixtures/kitchen-sink.expanded.json +11972 -0
  223. package/fixtures/kitchen-sink.json +3140 -0
  224. package/fixtures/layout-geometry-round1.json +7278 -0
  225. package/fixtures/layout-geometry.json +2072 -0
  226. package/fixtures/overlay-geometry.json +272 -0
  227. package/fixtures/pointer.json +89 -0
  228. package/fixtures/primitive-specimens.json +59 -0
  229. package/fixtures/prompt-budget.json +33 -0
  230. package/fixtures/qr-code.json +480 -0
  231. package/fixtures/resizable.json +714 -0
  232. package/fixtures/round4-contract.json +2985 -0
  233. package/fixtures/specimens.json +11168 -0
  234. package/fixtures/style-conditions.json +336 -0
  235. package/fixtures/template-items.json +2215 -0
  236. package/fixtures/text-direction.json +309 -0
  237. package/fixtures/text-shimmer.json +96 -0
  238. package/fixtures/theme-extends.json +573 -0
  239. package/fixtures/theme-invalid.json +1300 -0
  240. package/fixtures/theme-recipes.json +61762 -0
  241. package/fixtures/theme-resolved.json +25969 -0
  242. package/fixtures/toast-stack.json +215 -0
  243. package/fixtures/tree-guides.json +224 -0
  244. package/fixtures/virtual-list.json +733 -0
  245. package/fixtures/voice-wave.json +19236 -0
  246. package/generated/ExponentialUICatalog.generated.kt +67 -0
  247. package/generated/ExponentialUICatalog.generated.swift +67 -0
  248. package/generated/ExponentialUIThemes.generated.kt +23 -0
  249. package/generated/ExponentialUIThemes.generated.swift +23 -0
  250. package/generated/catalog.descriptions.generated.rs +6 -0
  251. package/generated/catalog.generated.rs +80 -0
  252. package/generated/catalog.themes.generated.rs +34 -0
  253. package/generated/core.descriptions.json +2726 -0
  254. package/generated/core.runtime.json +3944 -0
  255. package/package.json +87 -4
  256. package/themes/exponential.recipes.json +49 -0
  257. package/themes/exponential.theme.json +768 -0
  258. package/themes/neutral.theme.json +6178 -0
  259. package/themes/orange.theme.json +43 -0
  260. package/themes/playful.theme.json +219 -0
  261. package/vendor/a2ui/LICENSE.txt +203 -0
  262. package/vendor/a2ui/README.md +27 -0
  263. package/vendor/a2ui/v0_9/basic_catalog.json +1387 -0
  264. package/vendor/a2ui/v0_9/basic_catalog_rules.txt +5 -0
  265. package/vendor/a2ui/v0_9/client_capabilities.json +97 -0
  266. package/vendor/a2ui/v0_9/client_to_server.json +104 -0
  267. package/vendor/a2ui/v0_9/common_types.json +315 -0
  268. package/vendor/a2ui/v0_9/server_to_client.json +132 -0
  269. package/vendor/json-render/LICENSE.txt +201 -0
  270. package/vendor/json-render/README.md +13 -0
  271. package/vendor/nayuki-qr/LICENSE.txt +20 -0
  272. package/vendor/nayuki-qr/README.md +10 -0
@@ -0,0 +1,1058 @@
1
+ {
2
+ "$comment": "Round 1 review (renderer hardening): interaction semantics every renderer must share, HAND-AUTHORED and replayed by packages/exponential-ui-react/src/interactions-fixture.test.tsx (the reference, jsdom) and apps/desktop/crates/eui-core/tests/interactions_fixture.rs (the core, so gpui and the natives through the FFI). numberField: a NumberField bound to /v (value null = /v unseeded), one op (increment / decrement press, commit = type `input` then leave the field, none), then the value at /v and the text the field shows (en-US; `precision` absent = the step's decimals; values round like toFixed, the text like Intl.NumberFormat with that many fraction digits; a stepper on an unset value starts from min when min > 0, else 0; a stepper at its limit is disabled). checks: a Form `f` holding Checkbox `agree` (checked bound to /agreed) with `checks` and a submit Button; submitting gives the failing messages in order (a check WITH a condition fails when it resolves to nothing, null, false or an empty string; 0 passes; a non-string message reads `Invalid value`) and whether `submit` fired. tableSort: an UNBOUND sort of literal rows by one column (`sortRows`: missing values last both ways, two numbers numerically, a number column coerces, a date column by time, booleans as 0/1, the rest by Intl.Collator(locale, {numeric: true, sensitivity: base}); ties keep row order) → the row indexes in display order. choiceTiles (EXP-1280): a ChoiceTiles `c` over options a, b, c (`disabled` = the index of a disabled option) with `value` bound to /v (null = unseeded), the tiles pressed in order (a press on any part of tile i), then /v and every `change` value fired: single picks the pressed value; multiple toggles it in the comma-joined list kept in OPTION order (nothing picked = an empty string); a disabled option does nothing. select (VAPP-146): a plain single Select `s` over the options Any (value \"\"), Open (open) and Done (done) with `value` bound to /v (null = unseeded), the options picked in order (open the trigger, press option i), then /v, the text the trigger shows and every `change` value fired: an empty string is an ordinary option value (never refused, never the error placeholder); an unseeded value reads as \"\", so the trigger shows the option holding \"\"; picking an option writes its value; picking the option that holds the current value fires nothing (the empty one included, an unseeded /v stays unseeded). buttonHold (VAPP-162, docs/round-5-contract.md §9): a Button `b` (label `Hold to talk`, `holdingLabel` `Holding…` unless the case says otherwise) laid out at 120 × 40 px, coordinates relative to its top-left; `props` override the button's (null = unset; the base props are `hold: true`); `steps` = pointerdown/pointermove/pointerup at {x, y}, pointercancel, keydown/keyup {key}, blur; after each step `events` = the events that step fired (in order) and `pressed` / `label` = what the button paints. THE RULE: with `hold: true` a press never fires `press`; pointer down (or Space/Enter key down; key repeat ignored) fires `holdStart` and paints the pressed state + `holdingLabel`; while the hold is active the pointer may wander up to 24 px (the slop) outside the box; release (pointer up anywhere within the slop, or key up of the key that started it) fires `holdEnd`; the pointer leaving the box by more than the slop (the slide away), pointercancel, Escape or losing focus fire `holdCancel`; after a cancel nothing fires until the next down. `disabled` fires nothing; `hold: false` keeps the plain `press` on release over the box.",
3
+ "numberField": [
4
+ {
5
+ "name": "step 0.1 increments without float noise",
6
+ "props": {
7
+ "step": 0.1
8
+ },
9
+ "value": 0.2,
10
+ "op": "increment",
11
+ "expect": {
12
+ "value": 0.3,
13
+ "text": "0.3"
14
+ }
15
+ },
16
+ {
17
+ "name": "step 0.1 decrements without float noise",
18
+ "props": {
19
+ "step": 0.1
20
+ },
21
+ "value": 0.3,
22
+ "op": "decrement",
23
+ "expect": {
24
+ "value": 0.2,
25
+ "text": "0.2"
26
+ }
27
+ },
28
+ {
29
+ "name": "step 0.25 shows two decimals",
30
+ "props": {
31
+ "step": 0.25
32
+ },
33
+ "value": 1,
34
+ "op": "increment",
35
+ "expect": {
36
+ "value": 1.25,
37
+ "text": "1.25"
38
+ }
39
+ },
40
+ {
41
+ "name": "precision 0 shows 2.5 as 3 (half away from zero)",
42
+ "props": {
43
+ "precision": 0
44
+ },
45
+ "value": 2.5,
46
+ "op": "none",
47
+ "expect": {
48
+ "value": 2.5,
49
+ "text": "3"
50
+ }
51
+ },
52
+ {
53
+ "name": "precision 0 steps 1.5 to 3 (toFixed rounds 2.5 up)",
54
+ "props": {
55
+ "precision": 0
56
+ },
57
+ "value": 1.5,
58
+ "op": "increment",
59
+ "expect": {
60
+ "value": 3,
61
+ "text": "3"
62
+ }
63
+ },
64
+ {
65
+ "name": "precision 2 shows 0.125 as 0.13",
66
+ "props": {
67
+ "precision": 2
68
+ },
69
+ "value": 0.125,
70
+ "op": "none",
71
+ "expect": {
72
+ "value": 0.125,
73
+ "text": "0.13"
74
+ }
75
+ },
76
+ {
77
+ "name": "the text rounds the shortest decimal: 1.005 shows 1.01",
78
+ "props": {
79
+ "precision": 2
80
+ },
81
+ "value": 1.005,
82
+ "op": "none",
83
+ "expect": {
84
+ "value": 1.005,
85
+ "text": "1.01"
86
+ }
87
+ },
88
+ {
89
+ "name": "the text groups thousands",
90
+ "props": {
91
+ "precision": 1
92
+ },
93
+ "value": 1234.55,
94
+ "op": "none",
95
+ "expect": {
96
+ "value": 1234.55,
97
+ "text": "1,234.6"
98
+ }
99
+ },
100
+ {
101
+ "name": "an unset value with a negative min steps from 0",
102
+ "props": {
103
+ "min": -10
104
+ },
105
+ "value": null,
106
+ "op": "increment",
107
+ "expect": {
108
+ "value": 1,
109
+ "text": "1"
110
+ }
111
+ },
112
+ {
113
+ "name": "an unset value with a positive min steps from min",
114
+ "props": {
115
+ "min": 5
116
+ },
117
+ "value": null,
118
+ "op": "increment",
119
+ "expect": {
120
+ "value": 6,
121
+ "text": "6"
122
+ }
123
+ },
124
+ {
125
+ "name": "the stepper at max is disabled",
126
+ "props": {
127
+ "max": 3
128
+ },
129
+ "value": 3,
130
+ "op": "increment",
131
+ "expect": {
132
+ "value": 3,
133
+ "text": "3"
134
+ }
135
+ },
136
+ {
137
+ "name": "a commit rounds to the step's decimals",
138
+ "props": {
139
+ "step": 0.1
140
+ },
141
+ "value": 1,
142
+ "op": "commit",
143
+ "input": "0.123",
144
+ "expect": {
145
+ "value": 0.1,
146
+ "text": "0.1"
147
+ }
148
+ },
149
+ {
150
+ "name": "a commit clamps to max",
151
+ "props": {
152
+ "min": 0,
153
+ "max": 10
154
+ },
155
+ "value": 5,
156
+ "op": "commit",
157
+ "input": "42",
158
+ "expect": {
159
+ "value": 10,
160
+ "text": "10"
161
+ }
162
+ }
163
+ ],
164
+ "checks": [
165
+ {
166
+ "name": "an unseeded path fails",
167
+ "data": {},
168
+ "checks": [
169
+ {
170
+ "condition": {
171
+ "path": "/agreed"
172
+ },
173
+ "message": "Required"
174
+ }
175
+ ],
176
+ "failing": [
177
+ "Required"
178
+ ],
179
+ "submitted": false
180
+ },
181
+ {
182
+ "name": "false fails",
183
+ "data": {
184
+ "agreed": false
185
+ },
186
+ "checks": [
187
+ {
188
+ "condition": {
189
+ "path": "/agreed"
190
+ },
191
+ "message": "Required"
192
+ }
193
+ ],
194
+ "failing": [
195
+ "Required"
196
+ ],
197
+ "submitted": false
198
+ },
199
+ {
200
+ "name": "true passes",
201
+ "data": {
202
+ "agreed": true
203
+ },
204
+ "checks": [
205
+ {
206
+ "condition": {
207
+ "path": "/agreed"
208
+ },
209
+ "message": "Required"
210
+ }
211
+ ],
212
+ "failing": [],
213
+ "submitted": true
214
+ },
215
+ {
216
+ "name": "null fails",
217
+ "data": {
218
+ "agreed": true,
219
+ "n": null
220
+ },
221
+ "checks": [
222
+ {
223
+ "condition": {
224
+ "path": "/n"
225
+ },
226
+ "message": "Pick one"
227
+ }
228
+ ],
229
+ "failing": [
230
+ "Pick one"
231
+ ],
232
+ "submitted": false
233
+ },
234
+ {
235
+ "name": "zero passes",
236
+ "data": {
237
+ "agreed": true,
238
+ "n": 0
239
+ },
240
+ "checks": [
241
+ {
242
+ "condition": {
243
+ "path": "/n"
244
+ },
245
+ "message": "Pick one"
246
+ }
247
+ ],
248
+ "failing": [],
249
+ "submitted": true
250
+ },
251
+ {
252
+ "name": "an empty string fails",
253
+ "data": {
254
+ "agreed": true,
255
+ "s": ""
256
+ },
257
+ "checks": [
258
+ {
259
+ "condition": {
260
+ "path": "/s"
261
+ },
262
+ "message": "Empty"
263
+ }
264
+ ],
265
+ "failing": [
266
+ "Empty"
267
+ ],
268
+ "submitted": false
269
+ },
270
+ {
271
+ "name": "every failing message in order, a missing message reads Invalid value",
272
+ "data": {},
273
+ "checks": [
274
+ {
275
+ "condition": {
276
+ "path": "/agreed"
277
+ },
278
+ "message": "Required"
279
+ },
280
+ {
281
+ "condition": false
282
+ },
283
+ {
284
+ "condition": true,
285
+ "message": "Never"
286
+ }
287
+ ],
288
+ "failing": [
289
+ "Required",
290
+ "Invalid value"
291
+ ],
292
+ "submitted": false
293
+ },
294
+ {
295
+ "name": "a check without a condition passes",
296
+ "data": {
297
+ "agreed": true
298
+ },
299
+ "checks": [
300
+ {
301
+ "message": "No condition"
302
+ }
303
+ ],
304
+ "failing": [],
305
+ "submitted": true
306
+ }
307
+ ],
308
+ "tableSort": [
309
+ {
310
+ "name": "numbers inside text sort naturally",
311
+ "column": {
312
+ "key": "v",
313
+ "type": "text"
314
+ },
315
+ "rows": [
316
+ {
317
+ "v": "File 10",
318
+ "id": "r0"
319
+ },
320
+ {
321
+ "v": "File 2",
322
+ "id": "r1"
323
+ },
324
+ {
325
+ "v": "file 1",
326
+ "id": "r2"
327
+ }
328
+ ],
329
+ "direction": "asc",
330
+ "order": [
331
+ 2,
332
+ 1,
333
+ 0
334
+ ]
335
+ },
336
+ {
337
+ "name": "natural order descending",
338
+ "column": {
339
+ "key": "v",
340
+ "type": "text"
341
+ },
342
+ "rows": [
343
+ {
344
+ "v": "File 10",
345
+ "id": "r0"
346
+ },
347
+ {
348
+ "v": "File 2",
349
+ "id": "r1"
350
+ },
351
+ {
352
+ "v": "file 1",
353
+ "id": "r2"
354
+ }
355
+ ],
356
+ "direction": "desc",
357
+ "order": [
358
+ 0,
359
+ 1,
360
+ 2
361
+ ]
362
+ },
363
+ {
364
+ "name": "case and accents are ignored",
365
+ "column": {
366
+ "key": "v"
367
+ },
368
+ "rows": [
369
+ {
370
+ "v": "Ezra",
371
+ "id": "r0"
372
+ },
373
+ {
374
+ "v": "émile",
375
+ "id": "r1"
376
+ },
377
+ {
378
+ "v": "Eve",
379
+ "id": "r2"
380
+ }
381
+ ],
382
+ "direction": "asc",
383
+ "order": [
384
+ 1,
385
+ 2,
386
+ 0
387
+ ]
388
+ },
389
+ {
390
+ "name": "a number column coerces numeric strings",
391
+ "column": {
392
+ "key": "v",
393
+ "type": "number"
394
+ },
395
+ "rows": [
396
+ {
397
+ "v": "9",
398
+ "id": "r0"
399
+ },
400
+ {
401
+ "v": "10",
402
+ "id": "r1"
403
+ },
404
+ {
405
+ "v": "2.5",
406
+ "id": "r2"
407
+ }
408
+ ],
409
+ "direction": "asc",
410
+ "order": [
411
+ 2,
412
+ 0,
413
+ 1
414
+ ]
415
+ },
416
+ {
417
+ "name": "two numbers compare numerically in a text column",
418
+ "column": {
419
+ "key": "v"
420
+ },
421
+ "rows": [
422
+ {
423
+ "v": 10,
424
+ "id": "r0"
425
+ },
426
+ {
427
+ "v": 9,
428
+ "id": "r1"
429
+ },
430
+ {
431
+ "v": 100,
432
+ "id": "r2"
433
+ }
434
+ ],
435
+ "direction": "asc",
436
+ "order": [
437
+ 1,
438
+ 0,
439
+ 2
440
+ ]
441
+ },
442
+ {
443
+ "name": "a date column compares by time",
444
+ "column": {
445
+ "key": "v",
446
+ "type": "date"
447
+ },
448
+ "rows": [
449
+ {
450
+ "v": "2026-10-07",
451
+ "id": "r0"
452
+ },
453
+ {
454
+ "v": "2025-01-31",
455
+ "id": "r1"
456
+ },
457
+ {
458
+ "v": "2026-02-01",
459
+ "id": "r2"
460
+ }
461
+ ],
462
+ "direction": "asc",
463
+ "order": [
464
+ 1,
465
+ 2,
466
+ 0
467
+ ]
468
+ },
469
+ {
470
+ "name": "missing values go last ascending",
471
+ "column": {
472
+ "key": "v"
473
+ },
474
+ "rows": [
475
+ {
476
+ "v": "b",
477
+ "id": "r0"
478
+ },
479
+ {
480
+ "v": null,
481
+ "id": "r1"
482
+ },
483
+ {
484
+ "v": "a",
485
+ "id": "r2"
486
+ },
487
+ {
488
+ "id": "r3"
489
+ },
490
+ {
491
+ "v": "",
492
+ "id": "r4"
493
+ }
494
+ ],
495
+ "direction": "asc",
496
+ "order": [
497
+ 2,
498
+ 0,
499
+ 1,
500
+ 3,
501
+ 4
502
+ ]
503
+ },
504
+ {
505
+ "name": "missing values go last descending too",
506
+ "column": {
507
+ "key": "v"
508
+ },
509
+ "rows": [
510
+ {
511
+ "v": "b",
512
+ "id": "r0"
513
+ },
514
+ {
515
+ "v": null,
516
+ "id": "r1"
517
+ },
518
+ {
519
+ "v": "a",
520
+ "id": "r2"
521
+ },
522
+ {
523
+ "id": "r3"
524
+ },
525
+ {
526
+ "v": "",
527
+ "id": "r4"
528
+ }
529
+ ],
530
+ "direction": "desc",
531
+ "order": [
532
+ 0,
533
+ 2,
534
+ 1,
535
+ 3,
536
+ 4
537
+ ]
538
+ },
539
+ {
540
+ "name": "ties keep the row order in both directions",
541
+ "column": {
542
+ "key": "v",
543
+ "type": "number"
544
+ },
545
+ "rows": [
546
+ {
547
+ "v": 1,
548
+ "id": "r0"
549
+ },
550
+ {
551
+ "v": 1,
552
+ "id": "r1"
553
+ },
554
+ {
555
+ "v": 0,
556
+ "id": "r2"
557
+ }
558
+ ],
559
+ "direction": "desc",
560
+ "order": [
561
+ 0,
562
+ 1,
563
+ 2
564
+ ]
565
+ },
566
+ {
567
+ "name": "booleans sort false first",
568
+ "column": {
569
+ "key": "v",
570
+ "type": "boolean"
571
+ },
572
+ "rows": [
573
+ {
574
+ "v": true,
575
+ "id": "r0"
576
+ },
577
+ {
578
+ "v": false,
579
+ "id": "r1"
580
+ },
581
+ {
582
+ "v": true,
583
+ "id": "r2"
584
+ }
585
+ ],
586
+ "direction": "asc",
587
+ "order": [
588
+ 1,
589
+ 0,
590
+ 2
591
+ ]
592
+ }
593
+ ],
594
+ "choiceTiles": [
595
+ {
596
+ "name": "single picks",
597
+ "type": "single",
598
+ "value": null,
599
+ "presses": [
600
+ 1
601
+ ],
602
+ "expect": {
603
+ "value": "b",
604
+ "changes": [
605
+ "b"
606
+ ]
607
+ }
608
+ },
609
+ {
610
+ "name": "single re-picks",
611
+ "type": "single",
612
+ "value": "a",
613
+ "presses": [
614
+ 2,
615
+ 0
616
+ ],
617
+ "expect": {
618
+ "value": "a",
619
+ "changes": [
620
+ "c",
621
+ "a"
622
+ ]
623
+ }
624
+ },
625
+ {
626
+ "name": "multiple keeps option order",
627
+ "type": "multiple",
628
+ "value": null,
629
+ "presses": [
630
+ 2,
631
+ 0
632
+ ],
633
+ "expect": {
634
+ "value": "a,c",
635
+ "changes": [
636
+ "c",
637
+ "a,c"
638
+ ]
639
+ }
640
+ },
641
+ {
642
+ "name": "multiple toggles off",
643
+ "type": "multiple",
644
+ "value": "a,b",
645
+ "presses": [
646
+ 0
647
+ ],
648
+ "expect": {
649
+ "value": "b",
650
+ "changes": [
651
+ "b"
652
+ ]
653
+ }
654
+ },
655
+ {
656
+ "name": "multiple empties",
657
+ "type": "multiple",
658
+ "value": "b",
659
+ "presses": [
660
+ 1
661
+ ],
662
+ "expect": {
663
+ "value": "",
664
+ "changes": [
665
+ ""
666
+ ]
667
+ }
668
+ },
669
+ {
670
+ "name": "a disabled option does nothing",
671
+ "type": "single",
672
+ "value": "a",
673
+ "disabled": 1,
674
+ "presses": [
675
+ 1
676
+ ],
677
+ "expect": {
678
+ "value": "a",
679
+ "changes": []
680
+ }
681
+ }
682
+ ],
683
+ "select": [
684
+ {
685
+ "name": "an unseeded value shows the empty option",
686
+ "value": null,
687
+ "presses": [],
688
+ "expect": {
689
+ "value": null,
690
+ "shows": "Any",
691
+ "changes": []
692
+ }
693
+ },
694
+ {
695
+ "name": "a seeded empty string shows the empty option",
696
+ "value": "",
697
+ "presses": [],
698
+ "expect": {
699
+ "value": "",
700
+ "shows": "Any",
701
+ "changes": []
702
+ }
703
+ },
704
+ {
705
+ "name": "picking the empty option writes an empty string",
706
+ "value": "open",
707
+ "presses": [
708
+ 0
709
+ ],
710
+ "expect": {
711
+ "value": "",
712
+ "shows": "Any",
713
+ "changes": [
714
+ ""
715
+ ]
716
+ }
717
+ },
718
+ {
719
+ "name": "picking a value after the empty option",
720
+ "value": "",
721
+ "presses": [
722
+ 1
723
+ ],
724
+ "expect": {
725
+ "value": "open",
726
+ "shows": "Open",
727
+ "changes": [
728
+ "open"
729
+ ]
730
+ }
731
+ },
732
+ {
733
+ "name": "picking the empty option again fires nothing",
734
+ "value": "",
735
+ "presses": [
736
+ 0
737
+ ],
738
+ "expect": {
739
+ "value": "",
740
+ "shows": "Any",
741
+ "changes": []
742
+ }
743
+ },
744
+ {
745
+ "name": "picking the empty option on an unseeded value fires nothing",
746
+ "value": null,
747
+ "presses": [
748
+ 0
749
+ ],
750
+ "expect": {
751
+ "value": null,
752
+ "shows": "Any",
753
+ "changes": []
754
+ }
755
+ },
756
+ {
757
+ "name": "picking through the empty option and back",
758
+ "value": "done",
759
+ "presses": [
760
+ 0,
761
+ 2
762
+ ],
763
+ "expect": {
764
+ "value": "done",
765
+ "shows": "Done",
766
+ "changes": [
767
+ "",
768
+ "done"
769
+ ]
770
+ }
771
+ }
772
+ ],
773
+ "buttonHold": [
774
+ {
775
+ "name": "press and release over the button",
776
+ "steps": [
777
+ {
778
+ "do": "pointerdown",
779
+ "x": 60,
780
+ "y": 20,
781
+ "events": [
782
+ "holdStart"
783
+ ],
784
+ "pressed": true,
785
+ "label": "Holding…"
786
+ },
787
+ {
788
+ "do": "pointerup",
789
+ "x": 60,
790
+ "y": 20,
791
+ "events": [
792
+ "holdEnd"
793
+ ],
794
+ "pressed": false,
795
+ "label": "Hold to talk"
796
+ }
797
+ ]
798
+ },
799
+ {
800
+ "name": "a wander inside the slop keeps the hold; release there ends it",
801
+ "steps": [
802
+ {
803
+ "do": "pointerdown",
804
+ "x": 60,
805
+ "y": 20,
806
+ "events": [
807
+ "holdStart"
808
+ ],
809
+ "pressed": true,
810
+ "label": "Holding…"
811
+ },
812
+ {
813
+ "do": "pointermove",
814
+ "x": -20,
815
+ "y": 50,
816
+ "events": [],
817
+ "pressed": true,
818
+ "label": "Holding…"
819
+ },
820
+ {
821
+ "do": "pointerup",
822
+ "x": -20,
823
+ "y": 50,
824
+ "events": [
825
+ "holdEnd"
826
+ ],
827
+ "pressed": false,
828
+ "label": "Hold to talk"
829
+ }
830
+ ]
831
+ },
832
+ {
833
+ "name": "sliding away past the slop cancels; the later release fires nothing",
834
+ "steps": [
835
+ {
836
+ "do": "pointerdown",
837
+ "x": 60,
838
+ "y": 20,
839
+ "events": [
840
+ "holdStart"
841
+ ],
842
+ "pressed": true,
843
+ "label": "Holding…"
844
+ },
845
+ {
846
+ "do": "pointermove",
847
+ "x": -30,
848
+ "y": 20,
849
+ "events": [
850
+ "holdCancel"
851
+ ],
852
+ "pressed": false,
853
+ "label": "Hold to talk"
854
+ },
855
+ {
856
+ "do": "pointermove",
857
+ "x": 60,
858
+ "y": 20,
859
+ "events": [],
860
+ "pressed": false,
861
+ "label": "Hold to talk"
862
+ },
863
+ {
864
+ "do": "pointerup",
865
+ "x": 60,
866
+ "y": 20,
867
+ "events": [],
868
+ "pressed": false,
869
+ "label": "Hold to talk"
870
+ }
871
+ ]
872
+ },
873
+ {
874
+ "name": "pointercancel cancels",
875
+ "steps": [
876
+ {
877
+ "do": "pointerdown",
878
+ "x": 10,
879
+ "y": 10,
880
+ "events": [
881
+ "holdStart"
882
+ ],
883
+ "pressed": true,
884
+ "label": "Holding…"
885
+ },
886
+ {
887
+ "do": "pointercancel",
888
+ "events": [
889
+ "holdCancel"
890
+ ],
891
+ "pressed": false,
892
+ "label": "Hold to talk"
893
+ }
894
+ ]
895
+ },
896
+ {
897
+ "name": "Space holds from key down to key up, key repeat ignored",
898
+ "steps": [
899
+ {
900
+ "do": "keydown",
901
+ "key": " ",
902
+ "events": [
903
+ "holdStart"
904
+ ],
905
+ "pressed": true,
906
+ "label": "Holding…"
907
+ },
908
+ {
909
+ "do": "keydown",
910
+ "key": " ",
911
+ "repeat": true,
912
+ "events": [],
913
+ "pressed": true,
914
+ "label": "Holding…"
915
+ },
916
+ {
917
+ "do": "keyup",
918
+ "key": " ",
919
+ "events": [
920
+ "holdEnd"
921
+ ],
922
+ "pressed": false,
923
+ "label": "Hold to talk"
924
+ }
925
+ ]
926
+ },
927
+ {
928
+ "name": "Escape cancels an Enter hold; the key up fires nothing",
929
+ "steps": [
930
+ {
931
+ "do": "keydown",
932
+ "key": "Enter",
933
+ "events": [
934
+ "holdStart"
935
+ ],
936
+ "pressed": true,
937
+ "label": "Holding…"
938
+ },
939
+ {
940
+ "do": "keydown",
941
+ "key": "Escape",
942
+ "events": [
943
+ "holdCancel"
944
+ ],
945
+ "pressed": false,
946
+ "label": "Hold to talk"
947
+ },
948
+ {
949
+ "do": "keyup",
950
+ "key": "Enter",
951
+ "events": [],
952
+ "pressed": false,
953
+ "label": "Hold to talk"
954
+ }
955
+ ]
956
+ },
957
+ {
958
+ "name": "losing focus cancels",
959
+ "steps": [
960
+ {
961
+ "do": "keydown",
962
+ "key": " ",
963
+ "events": [
964
+ "holdStart"
965
+ ],
966
+ "pressed": true,
967
+ "label": "Holding…"
968
+ },
969
+ {
970
+ "do": "blur",
971
+ "events": [
972
+ "holdCancel"
973
+ ],
974
+ "pressed": false,
975
+ "label": "Hold to talk"
976
+ }
977
+ ]
978
+ },
979
+ {
980
+ "name": "without holdingLabel the label stays",
981
+ "props": {
982
+ "holdingLabel": null
983
+ },
984
+ "steps": [
985
+ {
986
+ "do": "pointerdown",
987
+ "x": 60,
988
+ "y": 20,
989
+ "events": [
990
+ "holdStart"
991
+ ],
992
+ "pressed": true,
993
+ "label": "Hold to talk"
994
+ },
995
+ {
996
+ "do": "pointerup",
997
+ "x": 60,
998
+ "y": 20,
999
+ "events": [
1000
+ "holdEnd"
1001
+ ],
1002
+ "pressed": false,
1003
+ "label": "Hold to talk"
1004
+ }
1005
+ ]
1006
+ },
1007
+ {
1008
+ "name": "disabled fires nothing",
1009
+ "props": {
1010
+ "disabled": true
1011
+ },
1012
+ "steps": [
1013
+ {
1014
+ "do": "pointerdown",
1015
+ "x": 60,
1016
+ "y": 20,
1017
+ "events": [],
1018
+ "pressed": false,
1019
+ "label": "Hold to talk"
1020
+ },
1021
+ {
1022
+ "do": "pointerup",
1023
+ "x": 60,
1024
+ "y": 20,
1025
+ "events": [],
1026
+ "pressed": false,
1027
+ "label": "Hold to talk"
1028
+ }
1029
+ ]
1030
+ },
1031
+ {
1032
+ "name": "hold false keeps the plain press",
1033
+ "props": {
1034
+ "hold": false
1035
+ },
1036
+ "steps": [
1037
+ {
1038
+ "do": "pointerdown",
1039
+ "x": 60,
1040
+ "y": 20,
1041
+ "events": [],
1042
+ "pressed": true,
1043
+ "label": "Hold to talk"
1044
+ },
1045
+ {
1046
+ "do": "pointerup",
1047
+ "x": 60,
1048
+ "y": 20,
1049
+ "events": [
1050
+ "press"
1051
+ ],
1052
+ "pressed": false,
1053
+ "label": "Hold to talk"
1054
+ }
1055
+ ]
1056
+ }
1057
+ ]
1058
+ }