@cssints/apg-specs 0.0.0-stage → 0.5.1

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 (260) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -2
  3. package/dist/apg/accordion.bridge.d.mts +35 -0
  4. package/dist/apg/accordion.bridge.mjs +326 -0
  5. package/dist/apg/accordion.model.json +8397 -0
  6. package/dist/apg/alert.bridge.d.mts +22 -0
  7. package/dist/apg/alert.bridge.mjs +86 -0
  8. package/dist/apg/alert.model.json +871 -0
  9. package/dist/apg/alertdialog.bridge.d.mts +21 -0
  10. package/dist/apg/alertdialog.bridge.mjs +221 -0
  11. package/dist/apg/alertdialog.model.json +5232 -0
  12. package/dist/apg/breadcrumb.bridge.d.mts +26 -0
  13. package/dist/apg/breadcrumb.bridge.mjs +120 -0
  14. package/dist/apg/breadcrumb.model.json +574 -0
  15. package/dist/apg/button.bridge.d.mts +35 -0
  16. package/dist/apg/button.bridge.mjs +208 -0
  17. package/dist/apg/button.model.json +5814 -0
  18. package/dist/apg/carousel.bridge.d.mts +44 -0
  19. package/dist/apg/carousel.bridge.mjs +262 -0
  20. package/dist/apg/carousel.model.json +8963 -0
  21. package/dist/apg/checkbox-group.bridge.d.mts +25 -0
  22. package/dist/apg/checkbox-group.bridge.mjs +276 -0
  23. package/dist/apg/checkbox-group.model.json +3863 -0
  24. package/dist/apg/checkbox.bridge.d.mts +34 -0
  25. package/dist/apg/checkbox.bridge.mjs +253 -0
  26. package/dist/apg/checkbox.model.json +3158 -0
  27. package/dist/apg/combobox-autocomplete.bridge.d.mts +14 -0
  28. package/dist/apg/combobox-autocomplete.bridge.mjs +326 -0
  29. package/dist/apg/combobox-autocomplete.model.json +11586 -0
  30. package/dist/apg/combobox-dialog.bridge.d.mts +17 -0
  31. package/dist/apg/combobox-dialog.bridge.mjs +250 -0
  32. package/dist/apg/combobox-dialog.model.json +8981 -0
  33. package/dist/apg/combobox-grid.bridge.d.mts +17 -0
  34. package/dist/apg/combobox-grid.bridge.mjs +227 -0
  35. package/dist/apg/combobox-grid.model.json +8554 -0
  36. package/dist/apg/combobox-select-only.bridge.d.mts +24 -0
  37. package/dist/apg/combobox-select-only.bridge.mjs +304 -0
  38. package/dist/apg/combobox-select-only.model.json +7846 -0
  39. package/dist/apg/combobox-tree.bridge.d.mts +17 -0
  40. package/dist/apg/combobox-tree.bridge.mjs +211 -0
  41. package/dist/apg/combobox-tree.model.json +9345 -0
  42. package/dist/apg/dialog-modal.bridge.d.mts +35 -0
  43. package/dist/apg/dialog-modal.bridge.mjs +186 -0
  44. package/dist/apg/dialog-modal.model.json +7580 -0
  45. package/dist/apg/disclosure.bridge.d.mts +25 -0
  46. package/dist/apg/disclosure.bridge.mjs +202 -0
  47. package/dist/apg/disclosure.model.json +4703 -0
  48. package/dist/apg/feed.bridge.d.mts +31 -0
  49. package/dist/apg/feed.bridge.mjs +246 -0
  50. package/dist/apg/feed.model.json +4523 -0
  51. package/dist/apg/grid-selection.bridge.d.mts +13 -0
  52. package/dist/apg/grid-selection.bridge.mjs +160 -0
  53. package/dist/apg/grid-selection.model.json +6974 -0
  54. package/dist/apg/grid-sort.bridge.d.mts +12 -0
  55. package/dist/apg/grid-sort.bridge.mjs +138 -0
  56. package/dist/apg/grid-sort.model.json +3799 -0
  57. package/dist/apg/grid.bridge.d.mts +54 -0
  58. package/dist/apg/grid.bridge.mjs +441 -0
  59. package/dist/apg/grid.model.json +3802 -0
  60. package/dist/apg/link.bridge.d.mts +24 -0
  61. package/dist/apg/link.bridge.mjs +126 -0
  62. package/dist/apg/link.model.json +694 -0
  63. package/dist/apg/listbox-multi.bridge.d.mts +10 -0
  64. package/dist/apg/listbox-multi.bridge.mjs +261 -0
  65. package/dist/apg/listbox-multi.model.json +10893 -0
  66. package/dist/apg/listbox-rearrangeable.bridge.d.mts +20 -0
  67. package/dist/apg/listbox-rearrangeable.bridge.mjs +237 -0
  68. package/dist/apg/listbox-rearrangeable.model.json +17592 -0
  69. package/dist/apg/listbox-shared.d.mts +58 -0
  70. package/dist/apg/listbox-shared.mjs +171 -0
  71. package/dist/apg/listbox-single.bridge.d.mts +10 -0
  72. package/dist/apg/listbox-single.bridge.mjs +196 -0
  73. package/dist/apg/listbox-single.model.json +8024 -0
  74. package/dist/apg/listbox-typeahead.bridge.d.mts +10 -0
  75. package/dist/apg/listbox-typeahead.bridge.mjs +153 -0
  76. package/dist/apg/listbox-typeahead.model.json +5615 -0
  77. package/dist/apg/menu-button.bridge.d.mts +29 -0
  78. package/dist/apg/menu-button.bridge.mjs +259 -0
  79. package/dist/apg/menu-button.model.json +5706 -0
  80. package/dist/apg/menu-checkable.bridge.d.mts +25 -0
  81. package/dist/apg/menu-checkable.bridge.mjs +226 -0
  82. package/dist/apg/menu-checkable.model.json +4277 -0
  83. package/dist/apg/menu-menubar.bridge.d.mts +27 -0
  84. package/dist/apg/menu-menubar.bridge.mjs +273 -0
  85. package/dist/apg/menu-menubar.model.json +9540 -0
  86. package/dist/apg/meter.bridge.d.mts +28 -0
  87. package/dist/apg/meter.bridge.mjs +159 -0
  88. package/dist/apg/meter.model.json +1185 -0
  89. package/dist/apg/player.bridge.d.mts +24 -0
  90. package/dist/apg/player.bridge.mjs +342 -0
  91. package/dist/apg/player.model.json +11013 -0
  92. package/dist/apg/radio.bridge.d.mts +35 -0
  93. package/dist/apg/radio.bridge.mjs +371 -0
  94. package/dist/apg/radio.model.json +5011 -0
  95. package/dist/apg/slider-multithumb.bridge.d.mts +34 -0
  96. package/dist/apg/slider-multithumb.bridge.mjs +365 -0
  97. package/dist/apg/slider-multithumb.model.json +5774 -0
  98. package/dist/apg/slider.bridge.d.mts +54 -0
  99. package/dist/apg/slider.bridge.mjs +359 -0
  100. package/dist/apg/slider.model.json +4881 -0
  101. package/dist/apg/spinbutton.bridge.d.mts +41 -0
  102. package/dist/apg/spinbutton.bridge.mjs +327 -0
  103. package/dist/apg/spinbutton.model.json +7571 -0
  104. package/dist/apg/switch.bridge.d.mts +30 -0
  105. package/dist/apg/switch.bridge.mjs +243 -0
  106. package/dist/apg/switch.model.json +3159 -0
  107. package/dist/apg/tabs.bridge.d.mts +41 -0
  108. package/dist/apg/tabs.bridge.mjs +294 -0
  109. package/dist/apg/tabs.model.json +7659 -0
  110. package/dist/apg/timeline.bridge.d.mts +36 -0
  111. package/dist/apg/timeline.bridge.mjs +265 -0
  112. package/dist/apg/timeline.model.json +6189 -0
  113. package/dist/apg/toolbar.bridge.d.mts +25 -0
  114. package/dist/apg/toolbar.bridge.mjs +307 -0
  115. package/dist/apg/toolbar.model.json +6616 -0
  116. package/dist/apg/tooltip.bridge.d.mts +36 -0
  117. package/dist/apg/tooltip.bridge.mjs +208 -0
  118. package/dist/apg/tooltip.model.json +8295 -0
  119. package/dist/apg/treegrid.bridge.d.mts +28 -0
  120. package/dist/apg/treegrid.bridge.mjs +311 -0
  121. package/dist/apg/treegrid.model.json +17358 -0
  122. package/dist/apg/treeview.bridge.d.mts +26 -0
  123. package/dist/apg/treeview.bridge.mjs +396 -0
  124. package/dist/apg/treeview.model.json +13745 -0
  125. package/dist/apg/windowsplitter.bridge.d.mts +36 -0
  126. package/dist/apg/windowsplitter.bridge.mjs +242 -0
  127. package/dist/apg/windowsplitter.model.json +6253 -0
  128. package/dist/canvas/camera.model.json +6568 -0
  129. package/dist/canvas/canvas.bridge.d.mts +190 -0
  130. package/dist/canvas/canvas.bridge.mjs +729 -0
  131. package/dist/canvas/pointer.model.json +17095 -0
  132. package/dist/scenario.d.mts +233 -0
  133. package/dist/scenario.mjs +313 -0
  134. package/package.json +57 -4
  135. package/scenarios/apg/README.md +221 -0
  136. package/scenarios/apg/accordion.base-ui.json +1005 -0
  137. package/scenarios/apg/accordion.react-aria.json +929 -0
  138. package/scenarios/apg/alert.base-ui.json +81 -0
  139. package/scenarios/apg/alert.react-aria.json +98 -0
  140. package/scenarios/apg/alertdialog.base-ui.json +331 -0
  141. package/scenarios/apg/alertdialog.react-aria.json +225 -0
  142. package/scenarios/apg/breadcrumb.react-aria.json +312 -0
  143. package/scenarios/apg/button.ariakit.json +136 -0
  144. package/scenarios/apg/button.base-ui.json +747 -0
  145. package/scenarios/apg/button.react-aria.json +443 -0
  146. package/scenarios/apg/carousel.apg.json +909 -0
  147. package/scenarios/apg/checkbox.ariakit.json +299 -0
  148. package/scenarios/apg/checkbox.base-ui.json +1126 -0
  149. package/scenarios/apg/checkbox.react-aria.json +518 -0
  150. package/scenarios/apg/combobox.ariakit.json +945 -0
  151. package/scenarios/apg/combobox.base-ui.json +2444 -0
  152. package/scenarios/apg/combobox.react-aria.json +845 -0
  153. package/scenarios/apg/dialog-modal.ariakit.json +1102 -0
  154. package/scenarios/apg/dialog-modal.base-ui.json +775 -0
  155. package/scenarios/apg/dialog-modal.react-aria.json +638 -0
  156. package/scenarios/apg/disclosure.apg.json +349 -0
  157. package/scenarios/apg/disclosure.ariakit.json +163 -0
  158. package/scenarios/apg/disclosure.base-ui.json +451 -0
  159. package/scenarios/apg/disclosure.react-aria.json +643 -0
  160. package/scenarios/apg/feed.apg.json +442 -0
  161. package/scenarios/apg/grid.ariakit.json +197 -0
  162. package/scenarios/apg/grid.base-ui.json +720 -0
  163. package/scenarios/apg/grid.react-aria.json +969 -0
  164. package/scenarios/apg/landmarks.ariakit.json +93 -0
  165. package/scenarios/apg/landmarks.react-aria.json +330 -0
  166. package/scenarios/apg/link.ariakit.json +83 -0
  167. package/scenarios/apg/link.base-ui.json +88 -0
  168. package/scenarios/apg/link.react-aria.json +186 -0
  169. package/scenarios/apg/listbox.ariakit.json +78 -0
  170. package/scenarios/apg/listbox.base-ui.json +163 -0
  171. package/scenarios/apg/listbox.react-aria.json +1118 -0
  172. package/scenarios/apg/menu-button.ariakit.json +924 -0
  173. package/scenarios/apg/menu-button.base-ui.json +1155 -0
  174. package/scenarios/apg/menu-button.react-aria.json +1080 -0
  175. package/scenarios/apg/menubar.ariakit.json +758 -0
  176. package/scenarios/apg/menubar.base-ui.json +673 -0
  177. package/scenarios/apg/meter.base-ui.json +243 -0
  178. package/scenarios/apg/meter.react-aria.json +201 -0
  179. package/scenarios/apg/radio.ariakit.json +459 -0
  180. package/scenarios/apg/radio.base-ui.json +581 -0
  181. package/scenarios/apg/radio.react-aria.json +576 -0
  182. package/scenarios/apg/slider-multithumb.base-ui.json +316 -0
  183. package/scenarios/apg/slider-multithumb.react-aria.json +363 -0
  184. package/scenarios/apg/slider.base-ui.json +544 -0
  185. package/scenarios/apg/slider.react-aria.json +456 -0
  186. package/scenarios/apg/spinbutton.base-ui.json +1688 -0
  187. package/scenarios/apg/spinbutton.react-aria.json +426 -0
  188. package/scenarios/apg/switch.base-ui.json +456 -0
  189. package/scenarios/apg/switch.react-aria.json +303 -0
  190. package/scenarios/apg/table.ariakit.json +65 -0
  191. package/scenarios/apg/table.react-aria.json +221 -0
  192. package/scenarios/apg/tabs.ariakit.json +329 -0
  193. package/scenarios/apg/tabs.base-ui.json +875 -0
  194. package/scenarios/apg/tabs.react-aria.json +644 -0
  195. package/scenarios/apg/toolbar.ariakit.json +595 -0
  196. package/scenarios/apg/toolbar.base-ui.json +1189 -0
  197. package/scenarios/apg/toolbar.react-aria.json +383 -0
  198. package/scenarios/apg/tooltip.ariakit.json +441 -0
  199. package/scenarios/apg/tooltip.base-ui.json +411 -0
  200. package/scenarios/apg/tooltip.react-aria.json +454 -0
  201. package/scenarios/apg/treegrid.apg.json +2558 -0
  202. package/scenarios/apg/treegrid.react-aria.json +5094 -0
  203. package/scenarios/apg/treeview.apg.json +928 -0
  204. package/scenarios/apg/windowsplitter.apg.json +557 -0
  205. package/scenarios/canvas/README.md +69 -0
  206. package/scenarios/canvas/camera.contract.json +237 -0
  207. package/scenarios/canvas/camera.excalidraw.json +57 -0
  208. package/scenarios/canvas/marquee.excalidraw.json +122 -0
  209. package/scenarios/canvas/pan.excalidraw.json +46 -0
  210. package/scenarios/canvas/pointer.contract.json +528 -0
  211. package/scenarios/parts.json +291 -0
  212. package/shared/aria.qnt +186 -0
  213. package/shared/details-group.qnt +50 -0
  214. package/shared/focusgroup.qnt +152 -0
  215. package/shared/invokers.qnt +81 -0
  216. package/shared/popover.qnt +71 -0
  217. package/specs/apg/STATIC.md +103 -0
  218. package/specs/apg/accordion.qnt +578 -0
  219. package/specs/apg/alert.qnt +131 -0
  220. package/specs/apg/alertdialog.qnt +455 -0
  221. package/specs/apg/breadcrumb.qnt +88 -0
  222. package/specs/apg/button.qnt +445 -0
  223. package/specs/apg/carousel.qnt +732 -0
  224. package/specs/apg/checkbox-group.qnt +388 -0
  225. package/specs/apg/checkbox.qnt +394 -0
  226. package/specs/apg/combobox-autocomplete.qnt +764 -0
  227. package/specs/apg/combobox-dialog.qnt +627 -0
  228. package/specs/apg/combobox-grid.qnt +632 -0
  229. package/specs/apg/combobox-select-only.qnt +626 -0
  230. package/specs/apg/combobox-tree.qnt +633 -0
  231. package/specs/apg/dialog-modal.qnt +499 -0
  232. package/specs/apg/disclosure.qnt +309 -0
  233. package/specs/apg/feed.qnt +485 -0
  234. package/specs/apg/grid-selection.qnt +512 -0
  235. package/specs/apg/grid-sort.qnt +330 -0
  236. package/specs/apg/grid.qnt +360 -0
  237. package/specs/apg/link.qnt +119 -0
  238. package/specs/apg/listbox-multi.qnt +799 -0
  239. package/specs/apg/listbox-rearrangeable.qnt +801 -0
  240. package/specs/apg/listbox-single.qnt +511 -0
  241. package/specs/apg/listbox-typeahead.qnt +396 -0
  242. package/specs/apg/menu-button.qnt +363 -0
  243. package/specs/apg/menu-checkable.qnt +304 -0
  244. package/specs/apg/menu-menubar.qnt +531 -0
  245. package/specs/apg/meter.qnt +129 -0
  246. package/specs/apg/player.qnt +1081 -0
  247. package/specs/apg/radio.qnt +394 -0
  248. package/specs/apg/slider-multithumb.qnt +441 -0
  249. package/specs/apg/slider.qnt +396 -0
  250. package/specs/apg/spinbutton.qnt +494 -0
  251. package/specs/apg/switch.qnt +389 -0
  252. package/specs/apg/tabs.qnt +412 -0
  253. package/specs/apg/timeline.qnt +612 -0
  254. package/specs/apg/toolbar.qnt +364 -0
  255. package/specs/apg/tooltip.qnt +553 -0
  256. package/specs/apg/treegrid.qnt +983 -0
  257. package/specs/apg/treeview.qnt +1004 -0
  258. package/specs/apg/windowsplitter.qnt +487 -0
  259. package/specs/canvas/camera.qnt +407 -0
  260. package/specs/canvas/pointer.qnt +841 -0
@@ -0,0 +1,1688 @@
1
+ {
2
+ "pattern": "spinbutton",
3
+ "source": "base-ui",
4
+ "commit": "19511bb171f3b360b006c94cf6d07e53cb446505",
5
+ "license": "MIT",
6
+ "skipped": [
7
+ {
8
+ "reason": "describeConformance suites (ref forwarding, prop merging, native button/input conformance) - React-API-only"
9
+ },
10
+ {
11
+ "reason": "styling and state callbacks: className as function (disabled), data-focused/data-touched/data-dirty/data-filled/data-invalid/data-valid/data-readonly attribute presentation, -webkit-textfield customisation"
12
+ },
13
+ {
14
+ "reason": "exhaustive Intl number-format locale matrices: roundingMode per en-US/fr-FR/ar-EG, percent permille variants, currency/unit/scientific formatting, group/decimal separators, default-formatting precision edge cases"
15
+ },
16
+ {
17
+ "reason": "React-API-only integration: Field.Label/Field.Description wiring, Field validationMode, Form external errors, hidden number-input autofill, React re-render/controlled rerender plumbing"
18
+ },
19
+ {
20
+ "reason": "console warning assertions (paste clipboard read failure and its owner-stack variant)"
21
+ },
22
+ {
23
+ "reason": "NumberField.ScrubArea pointer-drag scrubbing and NumberField.ScrubAreaCursor tracking (not APG spinbutton behaviour)"
24
+ },
25
+ {
26
+ "reason": "largeStep/smallStep on pointer button press with Shift/Alt - browser-only (skipIf(isJSDOM)), timing-sensitive hold accounting, touch settle/scroll heuristics and global pointerup listener teardown"
27
+ },
28
+ {
29
+ "reason": "NumberFieldGroup describeConformance and role-only assertion beyond the group role check"
30
+ }
31
+ ],
32
+ "scenarios": [
33
+ {
34
+ "id": "spinbutton.base-ui.input-has-textbox-role",
35
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L47",
36
+ "upstreamTest": "<NumberField.Input /> > has textbox role",
37
+ "apg": "aria",
38
+ "config": {},
39
+ "steps": [{ "expect": { "attrs": { "input": { "role": "textbox" } } } }],
40
+ "notes": "Divergence from APG: base-ui exposes the editable field as role=textbox backed by a hidden input[type=number], whereas the APG spinbutton pattern uses role=spinbutton with aria-valuenow/min/max."
41
+ },
42
+ {
43
+ "id": "spinbutton.base-ui.group-has-role-group",
44
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/group/NumberFieldGroup.test.tsx#L16",
45
+ "upstreamTest": "<NumberField.Group /> > has role prop",
46
+ "apg": "aria",
47
+ "config": {},
48
+ "steps": [{ "expect": { "attrs": { "group": { "role": "group" } } } }]
49
+ },
50
+ {
51
+ "id": "spinbutton.base-ui.increment-has-increase-label",
52
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L23",
53
+ "upstreamTest": "<NumberField.Increment /> > has increase label",
54
+ "apg": "aria",
55
+ "config": { "buttons": true },
56
+ "steps": [
57
+ { "expect": { "attrs": { "increment": { "aria-label": "Increase" } } } }
58
+ ]
59
+ },
60
+ {
61
+ "id": "spinbutton.base-ui.decrement-has-decrease-label",
62
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L20",
63
+ "upstreamTest": "<NumberField.Decrement /> > has decrease label",
64
+ "apg": "aria",
65
+ "config": { "buttons": true },
66
+ "steps": [
67
+ { "expect": { "attrs": { "decrement": { "aria-label": "Decrease" } } } }
68
+ ]
69
+ },
70
+ {
71
+ "id": "spinbutton.base-ui.stepper-aria-controls-input",
72
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L1024",
73
+ "upstreamTest": "<NumberField.Increment /> > disabled state > exposes aria-controls on the stepper",
74
+ "apg": "aria",
75
+ "config": { "readOnly": true, "buttons": true },
76
+ "steps": [
77
+ {
78
+ "expect": {
79
+ "attrs": {
80
+ "increment": {
81
+ "aria-controls": "input:0",
82
+ "aria-disabled": "true"
83
+ },
84
+ "input": { "readonly": "true" }
85
+ }
86
+ }
87
+ }
88
+ ],
89
+ "notes": "The stepper button points at the input id; readOnly is expressed as aria-disabled on the buttons and readonly on the input."
90
+ },
91
+ {
92
+ "id": "spinbutton.base-ui.readonly-input-no-aria-readonly-on-steppers",
93
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L960",
94
+ "upstreamTest": "<NumberField /> > prop: readOnly > does not render aria-readonly on stepper buttons",
95
+ "apg": "aria",
96
+ "config": { "readOnly": true, "buttons": true },
97
+ "steps": [
98
+ {
99
+ "expect": {
100
+ "attrs": {
101
+ "input": { "readonly": "true" },
102
+ "increment": { "aria-readonly": null, "aria-disabled": "true" },
103
+ "decrement": { "aria-readonly": null, "aria-disabled": "true" }
104
+ }
105
+ }
106
+ }
107
+ ],
108
+ "notes": "aria-readonly is invalid on role=button; readonly lives on the input and the steppers use disabled semantics."
109
+ },
110
+ {
111
+ "id": "spinbutton.base-ui.disabled-input-attribute",
112
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L929",
113
+ "upstreamTest": "<NumberField /> > prop: disabled > should disable the input",
114
+ "apg": "extension",
115
+ "config": { "disabled": true },
116
+ "steps": [{ "expect": { "attrs": { "input": { "disabled": "true" } } } }]
117
+ },
118
+ {
119
+ "id": "spinbutton.base-ui.required-input-attribute",
120
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L977",
121
+ "upstreamTest": "<NumberField /> > prop: required > should mark the input as required",
122
+ "apg": "extension",
123
+ "config": { "required": true },
124
+ "steps": [{ "expect": { "attrs": { "input": { "required": "true" } } } }]
125
+ },
126
+ {
127
+ "id": "spinbutton.base-ui.arrow-up-increments",
128
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L92",
129
+ "upstreamTest": "<NumberField.Input /> > should increment on keydown ArrowUp",
130
+ "apg": "keyboard",
131
+ "config": { "defaultValue": 0 },
132
+ "steps": [
133
+ { "event": "focus", "target": "input" },
134
+ { "event": "key", "key": "ArrowUp", "target": "input" },
135
+ { "expect": { "value": { "input": "1" } } }
136
+ ],
137
+ "notes": "APG: Up Arrow increases the value by one step."
138
+ },
139
+ {
140
+ "id": "spinbutton.base-ui.arrow-down-decrements",
141
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L104",
142
+ "upstreamTest": "<NumberField.Input /> > should decrement on keydown ArrowDown",
143
+ "apg": "keyboard",
144
+ "config": { "defaultValue": 0 },
145
+ "steps": [
146
+ { "event": "focus", "target": "input" },
147
+ { "event": "key", "key": "ArrowDown", "target": "input" },
148
+ { "expect": { "value": { "input": "-1" } } }
149
+ ]
150
+ },
151
+ {
152
+ "id": "spinbutton.base-ui.home-sets-min",
153
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L116",
154
+ "upstreamTest": "<NumberField.Input /> > should set the value to min on keydown Home",
155
+ "apg": "keyboard",
156
+ "config": { "min": -10, "max": 10 },
157
+ "steps": [
158
+ { "event": "focus", "target": "input" },
159
+ { "event": "key", "key": "Home", "target": "input" },
160
+ { "expect": { "value": { "input": "-10" } } }
161
+ ]
162
+ },
163
+ {
164
+ "id": "spinbutton.base-ui.end-sets-max",
165
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L128",
166
+ "upstreamTest": "<NumberField.Input /> > should set the value to max on keydown End",
167
+ "apg": "keyboard",
168
+ "config": { "min": -10, "max": 10 },
169
+ "steps": [
170
+ { "event": "focus", "target": "input" },
171
+ { "event": "key", "key": "End", "target": "input" },
172
+ { "expect": { "value": { "input": "10" } } }
173
+ ],
174
+ "notes": "APG: Home sets the minimum and End the maximum when bounds exist."
175
+ },
176
+ {
177
+ "id": "spinbutton.base-ui.pageup-pagedown-not-swallowed",
178
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L2900",
179
+ "upstreamTest": "<NumberField /> > does not swallow non-printing keys it does not handle",
180
+ "apg": "extension",
181
+ "config": { "defaultValue": 5 },
182
+ "steps": [
183
+ { "event": "focus", "target": "input" },
184
+ { "event": "key", "key": "PageUp", "target": "input" },
185
+ { "event": "key", "key": "PageDown", "target": "input" },
186
+ { "expect": { "value": { "input": "5" } } }
187
+ ],
188
+ "notes": "Divergence from APG: PageUp/PageDown larger-step variation is not implemented by base-ui; the events pass through untouched."
189
+ },
190
+ {
191
+ "id": "spinbutton.base-ui.navigation-keys-not-prevented",
192
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L2874",
193
+ "upstreamTest": "<NumberField /> > should allow navigation keys and not prevent their default behavior",
194
+ "apg": "keyboard",
195
+ "config": { "value": "123" },
196
+ "steps": [
197
+ { "event": "focus", "target": "input" },
198
+ {
199
+ "event": "key",
200
+ "key": "Backspace",
201
+ "target": "input",
202
+ "defaultPrevented": false
203
+ },
204
+ {
205
+ "event": "key",
206
+ "key": "Delete",
207
+ "target": "input",
208
+ "defaultPrevented": false
209
+ },
210
+ {
211
+ "event": "key",
212
+ "key": "ArrowLeft",
213
+ "target": "input",
214
+ "defaultPrevented": false
215
+ },
216
+ {
217
+ "event": "key",
218
+ "key": "ArrowRight",
219
+ "target": "input",
220
+ "defaultPrevented": false
221
+ },
222
+ {
223
+ "event": "key",
224
+ "key": "Tab",
225
+ "target": "input",
226
+ "defaultPrevented": false
227
+ },
228
+ {
229
+ "event": "key",
230
+ "key": "Enter",
231
+ "target": "input",
232
+ "defaultPrevented": false
233
+ }
234
+ ],
235
+ "notes": "Caret movement, deletion and Tab/Enter keep browser default behaviour."
236
+ },
237
+ {
238
+ "id": "spinbutton.base-ui.home-end-not-prevented-when-unbounded",
239
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L2888",
240
+ "upstreamTest": "<NumberField /> > does not prevent native caret movement for Home/End without min/max",
241
+ "apg": "keyboard",
242
+ "config": { "defaultValue": 5 },
243
+ "steps": [
244
+ { "event": "focus", "target": "input" },
245
+ {
246
+ "event": "key",
247
+ "key": "Home",
248
+ "target": "input",
249
+ "defaultPrevented": false
250
+ },
251
+ {
252
+ "event": "key",
253
+ "key": "End",
254
+ "target": "input",
255
+ "defaultPrevented": false
256
+ },
257
+ { "expect": { "value": { "input": "5" } } }
258
+ ],
259
+ "notes": "With no bounds Home/End keep native caret behaviour instead of jumping to min/max."
260
+ },
261
+ {
262
+ "id": "spinbutton.base-ui.step-not-taken-when-keydown-default-prevented",
263
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L1595",
264
+ "upstreamTest": "<NumberField.Input /> > consumer-prevented defaults > does not step when the keydown default is prevented",
265
+ "apg": "extension",
266
+ "config": { "defaultValue": 5, "preventKeyDown": true },
267
+ "steps": [
268
+ { "event": "focus", "target": "input" },
269
+ { "event": "key", "key": "ArrowUp", "target": "input" },
270
+ {
271
+ "expect": {
272
+ "value": { "input": "5" },
273
+ "events": { "onValueChange": [] }
274
+ }
275
+ }
276
+ ]
277
+ },
278
+ {
279
+ "id": "spinbutton.base-ui.rejects-non-numeric-change",
280
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L56",
281
+ "upstreamTest": "<NumberField.Input /> > should not allow non-numeric characters on change",
282
+ "apg": "keyboard",
283
+ "config": {},
284
+ "steps": [
285
+ { "event": "focus", "target": "input" },
286
+ { "event": "type", "target": "input", "value": "abc" },
287
+ { "expect": { "value": { "input": "" } } }
288
+ ]
289
+ },
290
+ {
291
+ "id": "spinbutton.base-ui.rejects-non-numeric-keydown",
292
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L68",
293
+ "upstreamTest": "<NumberField.Input /> > should not allow non-numeric characters on keydown",
294
+ "apg": "keyboard",
295
+ "config": {},
296
+ "steps": [
297
+ { "event": "focus", "target": "input" },
298
+ { "event": "key", "key": "a", "target": "input" },
299
+ { "expect": { "value": { "input": "" } } }
300
+ ]
301
+ },
302
+ {
303
+ "id": "spinbutton.base-ui.accepts-numeric-change",
304
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L80",
305
+ "upstreamTest": "<NumberField.Input /> > should allow numeric characters on change",
306
+ "apg": "keyboard",
307
+ "config": {},
308
+ "steps": [
309
+ { "event": "focus", "target": "input" },
310
+ { "event": "type", "target": "input", "value": "123" },
311
+ { "expect": { "value": { "input": "123" } } }
312
+ ]
313
+ },
314
+ {
315
+ "id": "spinbutton.base-ui.commits-formatted-value-on-blur",
316
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L486",
317
+ "upstreamTest": "<NumberField.Input /> > commits formatted value only on blur",
318
+ "apg": "keyboard",
319
+ "config": {},
320
+ "steps": [
321
+ { "event": "focus", "target": "input" },
322
+ { "event": "type", "target": "input", "value": "1234" },
323
+ { "expect": { "value": { "input": "1234" } } },
324
+ { "event": "blur", "target": "input" },
325
+ { "expect": { "value": { "input": "1,234" } } }
326
+ ],
327
+ "notes": "Raw text while editing, canonical locale-formatted number on commit."
328
+ },
329
+ {
330
+ "id": "spinbutton.base-ui.commit-clamps-min-on-blur",
331
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L500",
332
+ "upstreamTest": "<NumberField.Input /> > should commit validated number on blur (min)",
333
+ "apg": "keyboard",
334
+ "config": { "min": 0 },
335
+ "steps": [
336
+ { "event": "focus", "target": "input" },
337
+ { "event": "type", "target": "input", "value": "-1" },
338
+ { "expect": { "value": { "input": "-1" } } },
339
+ { "event": "blur", "target": "input" },
340
+ { "expect": { "value": { "input": "0" } } }
341
+ ]
342
+ },
343
+ {
344
+ "id": "spinbutton.base-ui.commit-clamps-max-on-blur",
345
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L514",
346
+ "upstreamTest": "<NumberField.Input /> > should commit validated number on blur (max)",
347
+ "apg": "keyboard",
348
+ "config": { "max": 0 },
349
+ "steps": [
350
+ { "event": "focus", "target": "input" },
351
+ { "event": "type", "target": "input", "value": "1" },
352
+ { "expect": { "value": { "input": "1" } } },
353
+ { "event": "blur", "target": "input" },
354
+ { "expect": { "value": { "input": "0" } } }
355
+ ]
356
+ },
357
+ {
358
+ "id": "spinbutton.base-ui.no-step-snap-on-blur",
359
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L528",
360
+ "upstreamTest": "<NumberField.Input /> > should not snap number to step on blur",
361
+ "apg": "extension",
362
+ "config": { "step": 0.5, "snapOnStep": true },
363
+ "steps": [
364
+ { "event": "focus", "target": "input" },
365
+ { "event": "type", "target": "input", "value": "1.5" },
366
+ { "event": "blur", "target": "input" },
367
+ { "expect": { "value": { "input": "1.5" } } }
368
+ ],
369
+ "notes": "snapOnStep applies to stepper/keyboard stepping, not to blur commit."
370
+ },
371
+ {
372
+ "id": "spinbutton.base-ui.commit-keeps-invalid-off-step-value",
373
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L542",
374
+ "upstreamTest": "<NumberField.Input /> > should commit validated number on blur (step and min)",
375
+ "apg": "keyboard",
376
+ "config": { "min": 2, "step": 2 },
377
+ "steps": [
378
+ { "event": "focus", "target": "input" },
379
+ { "event": "type", "target": "input", "value": "3" },
380
+ { "event": "blur", "target": "input" },
381
+ { "expect": { "value": { "input": "3" } } }
382
+ ],
383
+ "notes": "A step mismatch is a validation concern, not a clamp; the value is kept."
384
+ },
385
+
386
+ {
387
+ "id": "spinbutton.base-ui.typing-fires-parseable-changes",
388
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L332",
389
+ "upstreamTest": "<NumberField /> > typing behavior (parseable changes) > fires onValueChange for each parseable change while typing",
390
+ "apg": "keyboard",
391
+ "config": {},
392
+ "steps": [
393
+ { "event": "type", "target": "input", "value": "1" },
394
+ { "event": "type", "target": "input", "value": "12" },
395
+ { "event": "type", "target": "input", "value": "12." },
396
+ { "event": "type", "target": "input", "value": "12.a" },
397
+ {
398
+ "expect": {
399
+ "events": { "onValueChange": [1, 12, 12], "onValueCommitted": [] }
400
+ }
401
+ }
402
+ ],
403
+ "notes": "Only parseable text reports a change; '12.a' is ignored; nothing commits while typing."
404
+ },
405
+ {
406
+ "id": "spinbutton.base-ui.ime-non-numeric-no-change",
407
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L357",
408
+ "upstreamTest": "<NumberField /> > typing behavior (parseable changes) > does not fire onValueChange for non-numeric composition/partial input",
409
+ "apg": "extension",
410
+ "config": {},
411
+ "steps": [
412
+ { "event": "compositionstart", "target": "input" },
413
+ { "event": "type", "target": "input", "value": "n" },
414
+ { "event": "type", "target": "input", "value": "ni" },
415
+ { "event": "compositionend", "target": "input" },
416
+ { "expect": { "events": { "onValueChange": [] } } },
417
+ { "event": "type", "target": "input", "value": "一" },
418
+ { "expect": { "events": { "onValueChange": [1] } } },
419
+ { "event": "blur", "target": "input" },
420
+ { "expect": { "events": { "onValueCommitted": [1] } } }
421
+ ],
422
+ "notes": "Han numeral 一 parses to 1; commit happens once on blur. IME partial Latin text reports nothing."
423
+ },
424
+ {
425
+ "id": "spinbutton.base-ui.sign-and-decimal-partials",
426
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L384",
427
+ "upstreamTest": "<NumberField /> > typing behavior (parseable changes) > handles sign and decimal partials vs. parseable numbers",
428
+ "apg": "keyboard",
429
+ "config": { "min": -10 },
430
+ "steps": [
431
+ { "event": "type", "target": "input", "value": "-" },
432
+ { "event": "type", "target": "input", "value": "." },
433
+ { "event": "type", "target": "input", "value": "0." },
434
+ { "event": "type", "target": "input", "value": "-1" },
435
+ { "event": "type", "target": "input", "value": "-1.5" },
436
+ {
437
+ "expect": {
438
+ "events": { "onValueChange": [0, -1, -1.5], "onValueCommitted": [] }
439
+ }
440
+ },
441
+ { "event": "blur", "target": "input" },
442
+ { "expect": { "events": { "onValueCommitted": [-1.5] } } }
443
+ ],
444
+ "notes": "'-' and '.' alone are not parseable; '0.' parses to 0."
445
+ },
446
+ {
447
+ "id": "spinbutton.base-ui.invalid-input-not-committed-on-blur",
448
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L720",
449
+ "upstreamTest": "<NumberField /> > typing behavior (parseable changes) > does not commit on blur for invalid input",
450
+ "apg": "extension",
451
+ "config": {},
452
+ "steps": [
453
+ { "event": "type", "target": "input", "value": "." },
454
+ { "expect": { "value": { "input": "." } } },
455
+ { "event": "blur", "target": "input" },
456
+ { "expect": { "events": { "onValueCommitted": [] } } }
457
+ ]
458
+ },
459
+ {
460
+ "id": "spinbutton.base-ui.onvaluechange-when-value-changes",
461
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L171",
462
+ "upstreamTest": "<NumberField /> > prop: onValueChange > should be called when the value changes",
463
+ "apg": "extension",
464
+ "config": { "controlled": true, "defaultValue": 1 },
465
+ "steps": [
466
+ { "event": "type", "target": "input", "value": "2" },
467
+ { "expect": { "events": { "onValueChange": [2] } } }
468
+ ]
469
+ },
470
+ {
471
+ "id": "spinbutton.base-ui.onvaluechange-null-when-empty",
472
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L213",
473
+ "upstreamTest": "<NumberField /> > prop: onValueChange > should be called with `null` when empty and transitioning from a number",
474
+ "apg": "extension",
475
+ "config": { "controlled": true, "defaultValue": 5 },
476
+ "steps": [
477
+ { "event": "type", "target": "input", "value": "" },
478
+ { "expect": { "events": { "onValueChange": [null] } } }
479
+ ]
480
+ },
481
+ {
482
+ "id": "spinbutton.base-ui.onvaluechange-from-null",
483
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L192",
484
+ "upstreamTest": "<NumberField /> > prop: onValueChange > should be called with a number when transitioning from `null`",
485
+ "apg": "extension",
486
+ "config": { "controlled": true, "defaultValue": null },
487
+ "steps": [
488
+ { "event": "type", "target": "input", "value": "5" },
489
+ { "expect": { "events": { "onValueChange": [5] } } }
490
+ ]
491
+ },
492
+ {
493
+ "id": "spinbutton.base-ui.onvaluechange-reason-keyboard",
494
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L264",
495
+ "upstreamTest": "<NumberField /> > prop: onValueChange > includes the reason for keyboard increments",
496
+ "apg": "extension",
497
+ "config": { "defaultValue": 1 },
498
+ "steps": [
499
+ { "event": "focus", "target": "input" },
500
+ { "event": "key", "key": "ArrowUp", "target": "input" },
501
+ {
502
+ "expect": {
503
+ "events": {
504
+ "onValueChange": [1],
505
+ "onValueChangeReason": ["keyboard"]
506
+ }
507
+ }
508
+ }
509
+ ],
510
+ "notes": "Only the change reason is restated; the rich ChangeEventDetails object is a React-API detail."
511
+ },
512
+ {
513
+ "id": "spinbutton.base-ui.onvaluechange-reason-increment-press",
514
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L282",
515
+ "upstreamTest": "<NumberField /> > prop: onValueChange > includes the reason for increment button presses",
516
+ "apg": "extension",
517
+ "config": { "defaultValue": 1, "buttons": true },
518
+ "steps": [
519
+ { "event": "click", "target": "increment" },
520
+ {
521
+ "expect": {
522
+ "events": {
523
+ "onValueChange": [2],
524
+ "onValueChangeReason": ["increment-press"]
525
+ }
526
+ }
527
+ }
528
+ ]
529
+ },
530
+ {
531
+ "id": "spinbutton.base-ui.onvaluechange-reason-decrement-press",
532
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L297",
533
+ "upstreamTest": "<NumberField /> > prop: onValueChange > includes the reason for decrement button presses",
534
+ "apg": "extension",
535
+ "config": { "defaultValue": 1, "buttons": true },
536
+ "steps": [
537
+ { "event": "click", "target": "decrement" },
538
+ {
539
+ "expect": {
540
+ "events": {
541
+ "onValueChange": [0],
542
+ "onValueChangeReason": ["decrement-press"]
543
+ }
544
+ }
545
+ }
546
+ ]
547
+ },
548
+ {
549
+ "id": "spinbutton.base-ui.canceled-keyboard-change-reverts",
550
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L889",
551
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > does not commit a canceled keyboard change",
552
+ "apg": "extension",
553
+ "config": { "defaultValue": 0, "onValueChangeCancel": true },
554
+ "steps": [
555
+ { "event": "focus", "target": "input" },
556
+ { "event": "key", "key": "ArrowUp", "target": "input" },
557
+ {
558
+ "expect": {
559
+ "value": { "input": "0" },
560
+ "events": { "onValueCommitted": [] }
561
+ }
562
+ }
563
+ ],
564
+ "notes": "A canceled change leaves the controlled value untouched."
565
+ },
566
+ {
567
+ "id": "spinbutton.base-ui.canceled-clear-on-blur-no-commit",
568
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L908",
569
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > does not commit a canceled clear on blur",
570
+ "apg": "extension",
571
+ "config": { "defaultValue": 5, "onValueChangeCancel": true },
572
+ "steps": [
573
+ { "event": "focus", "target": "input" },
574
+ { "event": "type", "target": "input", "value": "" },
575
+ { "event": "blur", "target": "input" },
576
+ { "expect": { "events": { "onValueCommitted": [] } } }
577
+ ]
578
+ },
579
+ {
580
+ "id": "spinbutton.base-ui.paste-unicode-numerals",
581
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L2545",
582
+ "upstreamTest": "<NumberField /> > integration: exotic inputs and IME > pastes Persian numerals through the input contract",
583
+ "apg": "extension",
584
+ "config": { "defaultValue": 0 },
585
+ "steps": [
586
+ { "event": "focus", "target": "input" },
587
+ { "event": "paste", "target": "input", "value": "۱۲۳" },
588
+ {
589
+ "expect": {
590
+ "value": { "input": "۱۲۳" },
591
+ "events": {
592
+ "onValueChange": [123],
593
+ "onValueChangeReason": ["input-paste"]
594
+ }
595
+ }
596
+ }
597
+ ],
598
+ "notes": "Persian ۱۲۳ (and Arabic-Indic, fullwidth, Han numerals) parse to 123."
599
+ },
600
+ {
601
+ "id": "spinbutton.base-ui.paste-invalid-rejected",
602
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L2564",
603
+ "upstreamTest": "<NumberField /> > integration: exotic inputs and IME > rejects invalid pasted characters without changing the value contract",
604
+ "apg": "extension",
605
+ "config": { "defaultValue": 12 },
606
+ "steps": [
607
+ { "event": "focus", "target": "input" },
608
+ { "event": "paste", "target": "input", "value": "abc" },
609
+ {
610
+ "expect": {
611
+ "value": { "input": "12" },
612
+ "events": { "onValueChange": [] }
613
+ }
614
+ }
615
+ ]
616
+ },
617
+ {
618
+ "id": "spinbutton.base-ui.change-default-prevented-ignored",
619
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L1578",
620
+ "upstreamTest": "<NumberField.Input /> > consumer-prevented defaults > ignores a change whose native default was already prevented",
621
+ "apg": "extension",
622
+ "config": { "defaultValue": 5, "preventChange": true },
623
+ "steps": [
624
+ { "event": "focus", "target": "input" },
625
+ { "event": "type", "target": "input", "value": "9" },
626
+ {
627
+ "expect": {
628
+ "value": { "input": "5" },
629
+ "events": { "onValueChange": [] }
630
+ }
631
+ }
632
+ ]
633
+ },
634
+ {
635
+ "id": "spinbutton.base-ui.blur-default-prevented-no-commit",
636
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L1557",
637
+ "upstreamTest": "<NumberField.Input /> > consumer-prevented defaults > does not reformat, touch, or commit on blur when the blur default is prevented",
638
+ "apg": "extension",
639
+ "config": { "preventBlur": true },
640
+ "steps": [
641
+ { "event": "focus", "target": "input" },
642
+ { "event": "type", "target": "input", "value": "5.10" },
643
+ { "event": "blur", "target": "input" },
644
+ {
645
+ "expect": {
646
+ "value": { "input": "5.10" },
647
+ "events": { "onValueCommitted": [] }
648
+ }
649
+ }
650
+ ]
651
+ },
652
+
653
+ {
654
+ "id": "spinbutton.base-ui.oncommit-fires-on-blur",
655
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L734",
656
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > fires on blur with committed numeric value",
657
+ "apg": "keyboard",
658
+ "config": {},
659
+ "steps": [
660
+ { "event": "focus", "target": "input" },
661
+ { "event": "type", "target": "input", "value": "123." },
662
+ { "event": "blur", "target": "input" },
663
+ { "expect": { "events": { "onValueCommitted": [123] } } }
664
+ ]
665
+ },
666
+ {
667
+ "id": "spinbutton.base-ui.oncommit-null-when-cleared",
668
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L748",
669
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > fires null on blur when input is cleared",
670
+ "apg": "keyboard",
671
+ "config": { "defaultValue": 5 },
672
+ "steps": [
673
+ { "event": "focus", "target": "input" },
674
+ { "event": "type", "target": "input", "value": "" },
675
+ { "event": "blur", "target": "input" },
676
+ { "expect": { "events": { "onValueCommitted": [null] } } }
677
+ ]
678
+ },
679
+ {
680
+ "id": "spinbutton.base-ui.oncommit-reports-clamped-max",
681
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L761",
682
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > reports and displays the clamped value on blur, not the raw input",
683
+ "apg": "keyboard",
684
+ "config": { "max": 10 },
685
+ "steps": [
686
+ { "event": "focus", "target": "input" },
687
+ { "event": "type", "target": "input", "value": "1000" },
688
+ { "event": "blur", "target": "input" },
689
+ {
690
+ "expect": {
691
+ "value": { "input": "10" },
692
+ "events": { "onValueCommitted": [10] }
693
+ }
694
+ }
695
+ ]
696
+ },
697
+ {
698
+ "id": "spinbutton.base-ui.oncommit-reports-clamped-min",
699
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L775",
700
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > reports and displays the min-clamped value on blur, not the raw input",
701
+ "apg": "keyboard",
702
+ "config": { "min": 0 },
703
+ "steps": [
704
+ { "event": "focus", "target": "input" },
705
+ { "event": "type", "target": "input", "value": "-50" },
706
+ { "event": "blur", "target": "input" },
707
+ {
708
+ "expect": {
709
+ "value": { "input": "0" },
710
+ "events": { "onValueCommitted": [0] }
711
+ }
712
+ }
713
+ ]
714
+ },
715
+ {
716
+ "id": "spinbutton.base-ui.oncommit-keyboard-steps",
717
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L789",
718
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > fires on keyboard interactions (ArrowUp/Down/Home/End)",
719
+ "apg": "keyboard",
720
+ "config": { "defaultValue": 0, "min": -10, "max": 10 },
721
+ "steps": [
722
+ { "event": "focus", "target": "input" },
723
+ { "event": "key", "key": "ArrowUp", "target": "input" },
724
+ { "expect": { "events": { "onValueCommitted": [1] } } },
725
+ { "event": "key", "key": "ArrowDown", "target": "input" },
726
+ { "expect": { "events": { "onValueCommitted": [1, 0] } } },
727
+ { "event": "key", "key": "Home", "target": "input" },
728
+ { "expect": { "events": { "onValueCommitted": [1, 0, -10] } } },
729
+ { "event": "key", "key": "End", "target": "input" },
730
+ { "expect": { "events": { "onValueCommitted": [1, 0, -10, 10] } } }
731
+ ],
732
+ "notes": "Keyboard steps commit immediately in base-ui, unlike typed text which commits on blur."
733
+ },
734
+ {
735
+ "id": "spinbutton.base-ui.oncommit-buttons",
736
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L815",
737
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > fires when using increment/decrement buttons",
738
+ "apg": "keyboard",
739
+ "config": { "defaultValue": 0, "buttons": true },
740
+ "steps": [
741
+ { "event": "click", "target": "increment" },
742
+ {
743
+ "expect": {
744
+ "value": { "input": "1" },
745
+ "events": { "onValueCommitted": [1] }
746
+ }
747
+ },
748
+ { "event": "click", "target": "decrement" },
749
+ {
750
+ "expect": {
751
+ "value": { "input": "0" },
752
+ "events": { "onValueCommitted": [1, 0] }
753
+ }
754
+ }
755
+ ]
756
+ },
757
+ {
758
+ "id": "spinbutton.base-ui.oncommit-reason-buttons",
759
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L834",
760
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > includes the correct reason for increment and decrement button presses",
761
+ "apg": "extension",
762
+ "config": { "defaultValue": 0, "buttons": true },
763
+ "steps": [
764
+ { "event": "click", "target": "increment" },
765
+ { "event": "click", "target": "decrement" },
766
+ {
767
+ "expect": {
768
+ "events": {
769
+ "onValueCommittedReason": ["increment-press", "decrement-press"]
770
+ }
771
+ }
772
+ }
773
+ ]
774
+ },
775
+ {
776
+ "id": "spinbutton.base-ui.oncommit-skipped-when-untouched-empty",
777
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L848",
778
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > does not fire when blurring an untouched empty field",
779
+ "apg": "extension",
780
+ "config": {},
781
+ "steps": [
782
+ { "event": "focus", "target": "input" },
783
+ { "event": "blur", "target": "input" },
784
+ { "expect": { "events": { "onValueCommitted": [] } } }
785
+ ]
786
+ },
787
+ {
788
+ "id": "spinbutton.base-ui.oncommit-skips-no-op-steps",
789
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L859",
790
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > does not fire on keyboard steps that do not change the value",
791
+ "apg": "extension",
792
+ "config": { "defaultValue": 5, "min": 0, "max": 5 },
793
+ "steps": [
794
+ { "event": "focus", "target": "input" },
795
+ { "event": "key", "key": "ArrowUp", "target": "input" },
796
+ { "event": "key", "key": "End", "target": "input" },
797
+ { "expect": { "events": { "onValueCommitted": [] } } },
798
+ { "event": "key", "key": "ArrowDown", "target": "input" },
799
+ { "expect": { "events": { "onValueCommitted": [4] } } }
800
+ ]
801
+ },
802
+ {
803
+ "id": "spinbutton.base-ui.oncommit-once-per-press-release",
804
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L876",
805
+ "upstreamTest": "<NumberField /> > prop: onValueCommitted > fires once per press-release even after mouseleave/mouseenter during a hold",
806
+ "apg": "extension",
807
+ "config": { "defaultValue": 0, "buttons": true },
808
+ "steps": [
809
+ {
810
+ "event": "pointerdown",
811
+ "target": "increment",
812
+ "button": 0,
813
+ "pointerType": "mouse"
814
+ },
815
+ { "event": "mouseleave", "target": "increment" },
816
+ { "event": "mouseenter", "target": "increment", "buttons": 1 },
817
+ {
818
+ "event": "pointerup",
819
+ "target": "increment",
820
+ "button": 0,
821
+ "pointerType": "mouse"
822
+ },
823
+ { "expect": { "events": { "onValueCommitted": [1] } } }
824
+ ]
825
+ },
826
+
827
+ {
828
+ "id": "spinbutton.base-ui.min-prevents-below-on-type",
829
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1004",
830
+ "upstreamTest": "<NumberField /> > prop: min > prevents the raw value from going below the `min` prop",
831
+ "apg": "extension",
832
+ "config": { "defaultValue": 5, "min": 5 },
833
+ "steps": [
834
+ { "event": "type", "target": "input", "value": "4" },
835
+ {
836
+ "expect": {
837
+ "value": { "input": "4" },
838
+ "events": { "onValueChange": [5] }
839
+ }
840
+ }
841
+ ],
842
+ "notes": "Typed text can undershoot; the reported value is clamped to min while the raw text stays until blur."
843
+ },
844
+ {
845
+ "id": "spinbutton.base-ui.allows-above-min",
846
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1030",
847
+ "upstreamTest": "<NumberField /> > prop: min > allows the value to go above the `min` prop",
848
+ "apg": "extension",
849
+ "config": { "defaultValue": 5, "min": 5 },
850
+ "steps": [
851
+ { "event": "type", "target": "input", "value": "6" },
852
+ { "expect": { "value": { "input": "6" } } }
853
+ ]
854
+ },
855
+ {
856
+ "id": "spinbutton.base-ui.max-prevents-above-on-type",
857
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1057",
858
+ "upstreamTest": "<NumberField /> > prop: max > prevents the value from going above the `max` prop",
859
+ "apg": "extension",
860
+ "config": { "defaultValue": 5, "max": 5 },
861
+ "steps": [
862
+ { "event": "type", "target": "input", "value": "6" },
863
+ {
864
+ "expect": {
865
+ "value": { "input": "6" },
866
+ "events": { "onValueChange": [5] }
867
+ }
868
+ }
869
+ ]
870
+ },
871
+ {
872
+ "id": "spinbutton.base-ui.allows-below-max",
873
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1083",
874
+ "upstreamTest": "<NumberField /> > prop: max > allows the value to go below the `max` prop",
875
+ "apg": "extension",
876
+ "config": { "defaultValue": 5, "max": 5 },
877
+ "steps": [
878
+ { "event": "type", "target": "input", "value": "4" },
879
+ {
880
+ "expect": {
881
+ "value": { "input": "4" },
882
+ "events": { "onValueChange": [4] }
883
+ }
884
+ }
885
+ ]
886
+ },
887
+ {
888
+ "id": "spinbutton.base-ui.allow-out-of-range-typing",
889
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1111",
890
+ "upstreamTest": "<NumberField /> > prop: allowOutOfRange > allows typing a negative value via keyboard when min is 0",
891
+ "apg": "extension",
892
+ "config": { "min": 0, "allowOutOfRange": true },
893
+ "steps": [
894
+ { "event": "focus", "target": "input" },
895
+ {
896
+ "event": "key",
897
+ "key": "-",
898
+ "target": "input",
899
+ "defaultPrevented": false
900
+ },
901
+ { "event": "type", "target": "input", "value": "-1" },
902
+ { "expect": { "value": { "input": "-1" } } }
903
+ ]
904
+ },
905
+ {
906
+ "id": "spinbutton.base-ui.allow-out-of-range-still-clamps-step",
907
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1152",
908
+ "upstreamTest": "<NumberField /> > prop: allowOutOfRange > still clamps step interactions when true",
909
+ "apg": "extension",
910
+ "config": {
911
+ "defaultValue": 5,
912
+ "max": 5,
913
+ "allowOutOfRange": true,
914
+ "buttons": true
915
+ },
916
+ "steps": [
917
+ { "event": "click", "target": "increment" },
918
+ { "expect": { "value": { "input": "5" } } }
919
+ ],
920
+ "notes": "allowOutOfRange opens typed input; stepper interactions still clamp to the range."
921
+ },
922
+
923
+ {
924
+ "id": "spinbutton.base-ui.step-defaults-to-one",
925
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1205",
926
+ "upstreamTest": "<NumberField /> > prop: step > defaults to 1",
927
+ "apg": "keyboard",
928
+ "config": { "defaultValue": 5, "buttons": true },
929
+ "steps": [
930
+ { "event": "click", "target": "increment" },
931
+ { "expect": { "value": { "input": "6" } } }
932
+ ]
933
+ },
934
+ {
935
+ "id": "spinbutton.base-ui.step-increments-by-step",
936
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1212",
937
+ "upstreamTest": "<NumberField /> > prop: step > should increment the value by the `step` prop",
938
+ "apg": "keyboard",
939
+ "config": { "defaultValue": 4, "step": 2, "buttons": true },
940
+ "steps": [
941
+ { "event": "click", "target": "increment" },
942
+ { "expect": { "value": { "input": "6" } } }
943
+ ]
944
+ },
945
+ {
946
+ "id": "spinbutton.base-ui.step-snaps-increment",
947
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1219",
948
+ "upstreamTest": "<NumberField /> > prop: step > should snap when incrementing to the nearest multiple of the `step` prop",
949
+ "apg": "keyboard",
950
+ "config": {
951
+ "defaultValue": 5,
952
+ "step": 2,
953
+ "snapOnStep": true,
954
+ "buttons": true
955
+ },
956
+ "steps": [
957
+ { "event": "click", "target": "increment" },
958
+ { "expect": { "value": { "input": "6" } } }
959
+ ]
960
+ },
961
+ {
962
+ "id": "spinbutton.base-ui.step-decrements-by-step",
963
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1226",
964
+ "upstreamTest": "<NumberField /> > prop: step > should decrement the value by the `step` prop",
965
+ "apg": "keyboard",
966
+ "config": { "defaultValue": 6, "step": 2, "buttons": true },
967
+ "steps": [
968
+ { "event": "click", "target": "decrement" },
969
+ { "expect": { "value": { "input": "4" } } }
970
+ ]
971
+ },
972
+ {
973
+ "id": "spinbutton.base-ui.step-snaps-decrement",
974
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/root/NumberFieldRoot.test.tsx#L1233",
975
+ "upstreamTest": "<NumberField /> > prop: step > should snap when decrementing to the nearest multiple of the `step` prop",
976
+ "apg": "keyboard",
977
+ "config": {
978
+ "defaultValue": 5,
979
+ "step": 2,
980
+ "snapOnStep": true,
981
+ "buttons": true
982
+ },
983
+ "steps": [
984
+ { "event": "click", "target": "decrement" },
985
+ { "expect": { "value": { "input": "4" } } }
986
+ ]
987
+ },
988
+ {
989
+ "id": "spinbutton.base-ui.alt-arrow-small-step",
990
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L140",
991
+ "upstreamTest": "<NumberField.Input /> > uses smallStep and snapOnStep when holding Alt with ArrowUp/ArrowDown",
992
+ "apg": "extension",
993
+ "config": { "defaultValue": 0.15, "smallStep": 0.1, "snapOnStep": true },
994
+ "steps": [
995
+ { "event": "focus", "target": "input" },
996
+ {
997
+ "event": "key",
998
+ "key": "ArrowUp",
999
+ "target": "input",
1000
+ "modifiers": ["Alt"]
1001
+ },
1002
+ { "expect": { "value": { "input": "0.3" } } },
1003
+ {
1004
+ "event": "key",
1005
+ "key": "ArrowDown",
1006
+ "target": "input",
1007
+ "modifiers": ["Alt"]
1008
+ },
1009
+ { "expect": { "value": { "input": "0.2" } } }
1010
+ ],
1011
+ "notes": "Not in APG; Alt applies the finer smallStep (default 0.1) instead of step."
1012
+ },
1013
+ {
1014
+ "id": "spinbutton.base-ui.small-step-finer-than-three-digits",
1015
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L154",
1016
+ "upstreamTest": "<NumberField.Input /> > advances by a smallStep finer than 3 fraction digits",
1017
+ "apg": "extension",
1018
+ "config": { "controlled": true, "defaultValue": 0, "smallStep": 0.0001 },
1019
+ "steps": [
1020
+ { "event": "focus", "target": "input" },
1021
+ {
1022
+ "event": "key",
1023
+ "key": "ArrowUp",
1024
+ "target": "input",
1025
+ "modifiers": ["Alt"]
1026
+ },
1027
+ { "expect": { "events": { "onValueChange": [0.0001] } } }
1028
+ ]
1029
+ },
1030
+ {
1031
+ "id": "spinbutton.base-ui.keyboard-step-from-full-precision",
1032
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L184",
1033
+ "upstreamTest": "<NumberField.Input /> > increments with keyboard from numeric state, not rounded display text",
1034
+ "apg": "extension",
1035
+ "config": { "defaultValue": 1.23456 },
1036
+ "steps": [
1037
+ { "event": "focus", "target": "input" },
1038
+ { "event": "key", "key": "ArrowUp", "target": "input" },
1039
+ { "expect": { "events": { "onValueChange": [2.23456] } } }
1040
+ ],
1041
+ "notes": "Stepping uses full numeric precision, not the rounded display text."
1042
+ },
1043
+ {
1044
+ "id": "spinbutton.base-ui.keyboard-step-from-dirty-text",
1045
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L258",
1046
+ "upstreamTest": "<NumberField.Input /> > steps keyboard from dirty input text when the controlled value lags onValueChange",
1047
+ "apg": "extension",
1048
+ "config": { "controlled": true, "value": 0 },
1049
+ "steps": [
1050
+ { "event": "focus", "target": "input" },
1051
+ { "event": "type", "target": "input", "value": "1.5" },
1052
+ { "expect": { "events": { "onValueChange": [1.5] } } },
1053
+ { "event": "key", "key": "ArrowUp", "target": "input" },
1054
+ { "expect": { "events": { "onValueChange": [1.5, 2.5] } } }
1055
+ ],
1056
+ "notes": "When the parent does not mirror the change, the next step uses the dirty text rather than the stale stored value."
1057
+ },
1058
+ {
1059
+ "id": "spinbutton.base-ui.dirty-authority-survives-navigation-key",
1060
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L324",
1061
+ "upstreamTest": "<NumberField.Input /> > keeps dirty-input authority after a non-mutating key so the next keyboard step uses dirty text",
1062
+ "apg": "extension",
1063
+ "config": { "controlled": true, "value": 0 },
1064
+ "steps": [
1065
+ { "event": "focus", "target": "input" },
1066
+ { "event": "type", "target": "input", "value": "1.5" },
1067
+ { "event": "key", "key": "ArrowLeft", "target": "input" },
1068
+ { "event": "key", "key": "ArrowUp", "target": "input" },
1069
+ { "expect": { "events": { "onValueChange": [1.5, 2.5] } } }
1070
+ ],
1071
+ "notes": "A cursor key does not mark the field synced."
1072
+ },
1073
+ {
1074
+ "id": "spinbutton.base-ui.blur-commits-dirty-text-after-cursor-key",
1075
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L368",
1076
+ "upstreamTest": "<NumberField.Input /> > commits dirty text on blur after a cursor key when the controlled value does not mirror it",
1077
+ "apg": "extension",
1078
+ "config": { "controlled": true, "value": 0 },
1079
+ "steps": [
1080
+ { "event": "focus", "target": "input" },
1081
+ { "event": "type", "target": "input", "value": "5" },
1082
+ { "event": "key", "key": "ArrowLeft", "target": "input" },
1083
+ { "event": "blur", "target": "input" },
1084
+ { "expect": { "events": { "onValueChange": [5, 5] } } }
1085
+ ],
1086
+ "notes": "Blur commits the typed text rather than reverting to the stale stored value."
1087
+ },
1088
+ {
1089
+ "id": "spinbutton.base-ui.keyboard-step-not-stale-after-cancel",
1090
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L280",
1091
+ "upstreamTest": "<NumberField.Input /> > does not commit a stale value when a synced keyboard step is canceled after an external change",
1092
+ "apg": "extension",
1093
+ "config": {
1094
+ "controlled": true,
1095
+ "value": 0,
1096
+ "externalValue": 10,
1097
+ "cancelNextAfterExternal": true
1098
+ },
1099
+ "steps": [
1100
+ { "event": "focus", "target": "input" },
1101
+ { "event": "key", "key": "ArrowUp", "target": "input" },
1102
+ { "expect": { "events": { "onValueCommitted": [1] } } },
1103
+ { "event": "prop", "target": "input", "set": { "value": 10 } },
1104
+ { "event": "key", "key": "ArrowUp", "target": "input" },
1105
+ { "expect": { "events": { "onValueCommitted": [1] } } }
1106
+ ],
1107
+ "notes": "A canceled step after an external change must not re-commit the pre-external value."
1108
+ },
1109
+
1110
+ {
1111
+ "id": "spinbutton.base-ui.percent-formatted-unicode-keys-allowed",
1112
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L392",
1113
+ "upstreamTest": "<NumberField.Input /> > allows unicode plus/minus, permille and fullwidth digits on keydown when formatted as percent",
1114
+ "apg": "extension",
1115
+ "config": { "format": "percent" },
1116
+ "steps": [
1117
+ { "event": "focus", "target": "input" },
1118
+ {
1119
+ "event": "key",
1120
+ "key": "−",
1121
+ "target": "input",
1122
+ "defaultPrevented": false
1123
+ },
1124
+ {
1125
+ "event": "key",
1126
+ "key": "+",
1127
+ "target": "input",
1128
+ "defaultPrevented": false
1129
+ },
1130
+ {
1131
+ "event": "key",
1132
+ "key": "‰",
1133
+ "target": "input",
1134
+ "defaultPrevented": false
1135
+ },
1136
+ {
1137
+ "event": "key",
1138
+ "key": "1",
1139
+ "target": "input",
1140
+ "defaultPrevented": false
1141
+ }
1142
+ ]
1143
+ },
1144
+ {
1145
+ "id": "spinbutton.base-ui.percent-symbols-blocked-when-not-percent",
1146
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L413",
1147
+ "upstreamTest": "<NumberField.Input /> > blocks percent and permille symbols on keydown when not formatted as percent",
1148
+ "apg": "extension",
1149
+ "config": {},
1150
+ "steps": [
1151
+ { "event": "focus", "target": "input" },
1152
+ {
1153
+ "event": "key",
1154
+ "key": "%",
1155
+ "target": "input",
1156
+ "defaultPrevented": true
1157
+ },
1158
+ {
1159
+ "event": "key",
1160
+ "key": "‰",
1161
+ "target": "input",
1162
+ "defaultPrevented": true
1163
+ }
1164
+ ]
1165
+ },
1166
+ {
1167
+ "id": "spinbutton.base-ui.locale-decimal-group-gating",
1168
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L432",
1169
+ "upstreamTest": "<NumberField.Input /> > applies locale-aware decimal/group gating (de-DE)",
1170
+ "apg": "extension",
1171
+ "config": { "locale": "de-DE" },
1172
+ "steps": [
1173
+ { "event": "focus", "target": "input" },
1174
+ {
1175
+ "event": "key",
1176
+ "key": ",",
1177
+ "target": "input",
1178
+ "defaultPrevented": false
1179
+ },
1180
+ { "event": "type", "target": "input", "value": "1," },
1181
+ {
1182
+ "event": "key",
1183
+ "key": ",",
1184
+ "target": "input",
1185
+ "defaultPrevented": true
1186
+ },
1187
+ {
1188
+ "event": "key",
1189
+ "key": ".",
1190
+ "target": "input",
1191
+ "defaultPrevented": false
1192
+ }
1193
+ ],
1194
+ "notes": "de-DE uses ',' as decimal (one only) and '.' as group (repeatable)."
1195
+ },
1196
+ {
1197
+ "id": "spinbutton.base-ui.space-grouping-allowed",
1198
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/input/NumberFieldInput.test.tsx#L463",
1199
+ "upstreamTest": "<NumberField.Input /> > allows space key when locale uses space-like grouping (pl-PL)",
1200
+ "apg": "extension",
1201
+ "config": { "locale": "pl-PL" },
1202
+ "steps": [
1203
+ { "event": "focus", "target": "input" },
1204
+ {
1205
+ "event": "key",
1206
+ "key": " ",
1207
+ "target": "input",
1208
+ "defaultPrevented": false
1209
+ },
1210
+ { "event": "type", "target": "input", "value": "1 234" },
1211
+ { "expect": { "value": { "input": "1 234" } } }
1212
+ ]
1213
+ },
1214
+
1215
+ {
1216
+ "id": "spinbutton.base-ui.increment-starts-empty-at-zero",
1217
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L32",
1218
+ "upstreamTest": "<NumberField.Increment /> > increments starting from 0 click",
1219
+ "apg": "keyboard",
1220
+ "config": { "buttons": true },
1221
+ "steps": [
1222
+ { "event": "click", "target": "increment" },
1223
+ { "expect": { "value": { "input": "0" } } }
1224
+ ],
1225
+ "notes": "An empty field seeds to the nearest in-range value (0 when unbounded)."
1226
+ },
1227
+ {
1228
+ "id": "spinbutton.base-ui.increment-zero-to-one",
1229
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L45",
1230
+ "upstreamTest": "<NumberField.Increment /> > increments to 1 starting from defaultValue=0 click",
1231
+ "apg": "keyboard",
1232
+ "config": { "defaultValue": 0, "buttons": true },
1233
+ "steps": [
1234
+ { "event": "click", "target": "increment" },
1235
+ { "expect": { "value": { "input": "1" } } }
1236
+ ]
1237
+ },
1238
+ {
1239
+ "id": "spinbutton.base-ui.increment-seeds-negative-range",
1240
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L58",
1241
+ "upstreamTest": "<NumberField.Increment /> > seeds an empty fully-negative range in range on first increment",
1242
+ "apg": "extension",
1243
+ "config": { "min": -10, "max": -5, "buttons": true },
1244
+ "steps": [
1245
+ { "event": "click", "target": "increment" },
1246
+ { "expect": { "value": { "input": "-5" } } }
1247
+ ],
1248
+ "notes": "An empty field seeds the in-range value nearest zero (the max here), not 0."
1249
+ },
1250
+ {
1251
+ "id": "spinbutton.base-ui.increment-once-per-click",
1252
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L261",
1253
+ "upstreamTest": "<NumberField.Increment /> > only calls onValueChange once per increment",
1254
+ "apg": "keyboard",
1255
+ "config": { "buttons": true },
1256
+ "steps": [
1257
+ { "event": "click", "target": "increment" },
1258
+ { "event": "click", "target": "increment" },
1259
+ { "expect": { "events": { "onValueChange": [0, 1] } } }
1260
+ ]
1261
+ },
1262
+ {
1263
+ "id": "spinbutton.base-ui.increment-dirty-input-click",
1264
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L742",
1265
+ "upstreamTest": "<NumberField.Increment /> > should increment when input is dirty but not blurred (click)",
1266
+ "apg": "extension",
1267
+ "config": { "defaultValue": 0, "buttons": true },
1268
+ "steps": [
1269
+ { "event": "focus", "target": "input" },
1270
+ { "event": "type", "target": "input", "value": "100" },
1271
+ { "event": "click", "target": "increment" },
1272
+ { "expect": { "value": { "input": "101" } } }
1273
+ ]
1274
+ },
1275
+ {
1276
+ "id": "spinbutton.base-ui.increment-dirty-input-pointerdown",
1277
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L760",
1278
+ "upstreamTest": "<NumberField.Increment /> > should increment when input is dirty but not blurred (pointerdown)",
1279
+ "apg": "extension",
1280
+ "config": { "defaultValue": 0, "buttons": true },
1281
+ "steps": [
1282
+ { "event": "focus", "target": "input" },
1283
+ { "event": "type", "target": "input", "value": "100" },
1284
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1285
+ { "expect": { "value": { "input": "101" } } }
1286
+ ]
1287
+ },
1288
+ {
1289
+ "id": "spinbutton.base-ui.increment-ignores-non-primary-button",
1290
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L778",
1291
+ "upstreamTest": "<NumberField.Increment /> > ignores non-primary pointer buttons",
1292
+ "apg": "extension",
1293
+ "config": { "controlled": true, "value": 0, "buttons": true },
1294
+ "steps": [
1295
+ { "event": "focus", "target": "input" },
1296
+ { "event": "type", "target": "input", "value": "100" },
1297
+ { "event": "pointerdown", "target": "increment", "button": 1 },
1298
+ {
1299
+ "expect": {
1300
+ "value": { "input": "100" },
1301
+ "events": { "onValueChange": [100] }
1302
+ }
1303
+ }
1304
+ ],
1305
+ "notes": "Only the change from typing is reported; a non-primary press does not sync dirty text or step."
1306
+ },
1307
+ {
1308
+ "id": "spinbutton.base-ui.increment-caret-on-mouse-press",
1309
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L835",
1310
+ "upstreamTest": "<NumberField.Increment /> > places the caret at the end of the input when a mouse press focuses it",
1311
+ "apg": "extension",
1312
+ "config": { "defaultValue": 100, "buttons": true },
1313
+ "steps": [
1314
+ {
1315
+ "event": "pointerdown",
1316
+ "target": "increment",
1317
+ "button": 0,
1318
+ "pointerType": "mouse"
1319
+ },
1320
+ {
1321
+ "expect": {
1322
+ "focus": "input",
1323
+ "attrs": {
1324
+ "input": { "selectionStart": "end", "selectionEnd": "end" }
1325
+ }
1326
+ }
1327
+ }
1328
+ ]
1329
+ },
1330
+ {
1331
+ "id": "spinbutton.base-ui.increment-hold-continuous",
1332
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L291",
1333
+ "upstreamTest": "<NumberField.Increment /> > press and hold > increments continuously when holding pointerdown",
1334
+ "apg": "extension",
1335
+ "config": { "defaultValue": 0, "buttons": true },
1336
+ "steps": [
1337
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1338
+ { "expect": { "value": { "input": "1" } } },
1339
+ { "event": "wait", "ms": 400 },
1340
+ { "event": "wait", "ms": 60 },
1341
+ { "event": "wait", "ms": 60 },
1342
+ { "event": "wait", "ms": 60 },
1343
+ { "expect": { "value": { "input": "4" } } },
1344
+ { "event": "pointerup", "target": "increment", "button": 0 },
1345
+ { "event": "wait", "ms": 60 },
1346
+ { "expect": { "value": { "input": "4" } } }
1347
+ ],
1348
+ "notes": "After a 400ms start delay the value ticks every 60ms until release."
1349
+ },
1350
+ {
1351
+ "id": "spinbutton.base-ui.increment-hold-stops-at-max",
1352
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L500",
1353
+ "upstreamTest": "<NumberField.Increment /> > press and hold > stops calling onValueChange once max is reached",
1354
+ "apg": "extension",
1355
+ "config": { "defaultValue": 9, "max": 10, "buttons": true },
1356
+ "steps": [
1357
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1358
+ {
1359
+ "expect": {
1360
+ "value": { "input": "10" },
1361
+ "events": { "onValueChange": [10] }
1362
+ }
1363
+ },
1364
+ { "event": "wait", "ms": 400 },
1365
+ { "event": "wait", "ms": 60 },
1366
+ { "event": "wait", "ms": 60 },
1367
+ {
1368
+ "expect": {
1369
+ "value": { "input": "10" },
1370
+ "events": { "onValueChange": [10] }
1371
+ }
1372
+ },
1373
+ { "event": "pointerup", "target": "increment", "button": 0 }
1374
+ ]
1375
+ },
1376
+ {
1377
+ "id": "spinbutton.base-ui.increment-hold-stops-on-mouseleave",
1378
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L620",
1379
+ "upstreamTest": "<NumberField.Increment /> > press and hold > should stop incrementing after mouseleave",
1380
+ "apg": "extension",
1381
+ "config": { "defaultValue": 0, "buttons": true },
1382
+ "steps": [
1383
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1384
+ { "event": "wait", "ms": 400 },
1385
+ { "event": "wait", "ms": 60 },
1386
+ { "event": "wait", "ms": 60 },
1387
+ { "event": "wait", "ms": 60 },
1388
+ { "expect": { "value": { "input": "4" } } },
1389
+ { "event": "mouseleave", "target": "increment" },
1390
+ { "event": "wait", "ms": 60 },
1391
+ { "expect": { "value": { "input": "4" } } }
1392
+ ]
1393
+ },
1394
+ {
1395
+ "id": "spinbutton.base-ui.increment-no-double-pointerdown-click",
1396
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L602",
1397
+ "upstreamTest": "<NumberField.Increment /> > press and hold > does not increment twice with pointerdown and click",
1398
+ "apg": "extension",
1399
+ "config": { "defaultValue": 0, "buttons": true },
1400
+ "steps": [
1401
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1402
+ { "event": "pointerup", "target": "increment", "button": 0 },
1403
+ { "event": "click", "target": "increment", "detail": 1 },
1404
+ { "expect": { "value": { "input": "1" } } }
1405
+ ]
1406
+ },
1407
+ {
1408
+ "id": "spinbutton.base-ui.increment-commits-on-release-after-boundary",
1409
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L528",
1410
+ "upstreamTest": "<NumberField.Increment /> > press and hold > commits on release after a hold reaches the boundary",
1411
+ "apg": "extension",
1412
+ "config": { "defaultValue": 9, "max": 10, "buttons": true },
1413
+ "steps": [
1414
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1415
+ { "event": "wait", "ms": 400 },
1416
+ { "event": "wait", "ms": 60 },
1417
+ { "event": "wait", "ms": 60 },
1418
+ {
1419
+ "expect": {
1420
+ "value": { "input": "10" },
1421
+ "events": { "onValueCommitted": [] }
1422
+ }
1423
+ },
1424
+ { "event": "pointerup", "target": "increment", "button": 0 },
1425
+ { "expect": { "events": { "onValueCommitted": [10] } } }
1426
+ ]
1427
+ },
1428
+ {
1429
+ "id": "spinbutton.base-ui.increment-snap-exact-step-when-false",
1430
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L944",
1431
+ "upstreamTest": "<NumberField.Increment /> > prop: snapOnStep > should increment by exact step without rounding when snapOnStep is false",
1432
+ "apg": "extension",
1433
+ "config": {
1434
+ "defaultValue": 2.7,
1435
+ "step": 2,
1436
+ "snapOnStep": false,
1437
+ "buttons": true
1438
+ },
1439
+ "steps": [
1440
+ { "event": "click", "target": "increment" },
1441
+ { "expect": { "value": { "input": "4.7" } } }
1442
+ ]
1443
+ },
1444
+ {
1445
+ "id": "spinbutton.base-ui.increment-snaps-when-true",
1446
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L958",
1447
+ "upstreamTest": "<NumberField.Increment /> > prop: snapOnStep > should snap on increment when snapOnStep is true",
1448
+ "apg": "extension",
1449
+ "config": { "defaultValue": 1.3, "snapOnStep": true, "buttons": true },
1450
+ "steps": [
1451
+ { "event": "click", "target": "increment" },
1452
+ { "expect": { "value": { "input": "2" } } },
1453
+ { "event": "type", "target": "input", "value": "1.9" },
1454
+ { "event": "click", "target": "increment" },
1455
+ { "expect": { "value": { "input": "2" } } },
1456
+ { "event": "type", "target": "input", "value": "-0.2" },
1457
+ { "event": "click", "target": "increment" },
1458
+ { "expect": { "value": { "input": "0" } } }
1459
+ ]
1460
+ },
1461
+ {
1462
+ "id": "spinbutton.base-ui.increment-snaps-relative-to-min",
1463
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L996",
1464
+ "upstreamTest": "<NumberField.Increment /> > prop: snapOnStep > should increment with respect to the min value",
1465
+ "apg": "extension",
1466
+ "config": {
1467
+ "defaultValue": 1,
1468
+ "min": 1,
1469
+ "step": 2,
1470
+ "snapOnStep": true,
1471
+ "buttons": true
1472
+ },
1473
+ "steps": [
1474
+ { "event": "click", "target": "increment" },
1475
+ { "expect": { "value": { "input": "3" } } },
1476
+ { "event": "click", "target": "increment" },
1477
+ { "expect": { "value": { "input": "5" } } },
1478
+ { "event": "type", "target": "input", "value": "1.112" },
1479
+ { "event": "click", "target": "increment" },
1480
+ { "expect": { "value": { "input": "3" } } },
1481
+ { "event": "type", "target": "input", "value": "0.999" },
1482
+ { "event": "click", "target": "increment" },
1483
+ { "expect": { "value": { "input": "1" } } }
1484
+ ],
1485
+ "notes": "With snapOnStep the step grid is anchored at min, so 0.999 snaps up to 1 rather than 3."
1486
+ },
1487
+ {
1488
+ "id": "spinbutton.base-ui.increment-disabled-root",
1489
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L1036",
1490
+ "upstreamTest": "<NumberField.Increment /> > disabled state > should not increment when root is disabled",
1491
+ "apg": "extension",
1492
+ "config": { "disabled": true, "buttons": true },
1493
+ "steps": [
1494
+ { "event": "click", "target": "increment" },
1495
+ {
1496
+ "expect": {
1497
+ "value": { "input": "" },
1498
+ "events": { "onValueChange": [] }
1499
+ }
1500
+ }
1501
+ ]
1502
+ },
1503
+ {
1504
+ "id": "spinbutton.base-ui.increment-disabled-button",
1505
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L1051",
1506
+ "upstreamTest": "<NumberField.Increment /> > disabled state > should not increment when button is disabled",
1507
+ "apg": "extension",
1508
+ "config": {
1509
+ "defaultValue": 0,
1510
+ "incrementDisabled": true,
1511
+ "buttons": true
1512
+ },
1513
+ "steps": [
1514
+ {
1515
+ "expect": {
1516
+ "attrs": { "increment": { "disabled": "true" } },
1517
+ "value": { "input": "0" }
1518
+ }
1519
+ },
1520
+ { "event": "pointerdown", "target": "increment", "button": 0 },
1521
+ {
1522
+ "expect": {
1523
+ "value": { "input": "0" },
1524
+ "events": { "onValueChange": [] }
1525
+ }
1526
+ }
1527
+ ]
1528
+ },
1529
+ {
1530
+ "id": "spinbutton.base-ui.decrement-starts-empty-at-zero",
1531
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L29",
1532
+ "upstreamTest": "<NumberField.Decrement /> > decrements starting from 0 click",
1533
+ "apg": "keyboard",
1534
+ "config": { "buttons": true },
1535
+ "steps": [
1536
+ { "event": "click", "target": "decrement" },
1537
+ { "expect": { "value": { "input": "0" } } }
1538
+ ]
1539
+ },
1540
+ {
1541
+ "id": "spinbutton.base-ui.decrement-zero-to-minus-one",
1542
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L42",
1543
+ "upstreamTest": "<NumberField.Decrement /> > decrements to -1 starting from defaultValue=0 click",
1544
+ "apg": "keyboard",
1545
+ "config": { "defaultValue": 0, "buttons": true },
1546
+ "steps": [
1547
+ { "event": "click", "target": "decrement" },
1548
+ { "expect": { "value": { "input": "-1" } } }
1549
+ ]
1550
+ },
1551
+ {
1552
+ "id": "spinbutton.base-ui.decrement-once-per-click",
1553
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L142",
1554
+ "upstreamTest": "<NumberField.Decrement /> > only calls onValueChange once per decrement",
1555
+ "apg": "keyboard",
1556
+ "config": { "buttons": true },
1557
+ "steps": [
1558
+ { "event": "click", "target": "decrement" },
1559
+ { "event": "click", "target": "decrement" },
1560
+ { "expect": { "events": { "onValueChange": [0, -1] } } }
1561
+ ]
1562
+ },
1563
+ {
1564
+ "id": "spinbutton.base-ui.decrement-dirty-input-click",
1565
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L361",
1566
+ "upstreamTest": "<NumberField.Decrement /> > should decrement when input is dirty but not blurred (click)",
1567
+ "apg": "extension",
1568
+ "config": { "defaultValue": 0, "buttons": true },
1569
+ "steps": [
1570
+ { "event": "focus", "target": "input" },
1571
+ { "event": "type", "target": "input", "value": "100" },
1572
+ { "event": "click", "target": "decrement" },
1573
+ { "expect": { "value": { "input": "99" } } }
1574
+ ]
1575
+ },
1576
+ {
1577
+ "id": "spinbutton.base-ui.decrement-snap-exact-step-when-false",
1578
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L447",
1579
+ "upstreamTest": "<NumberField.Decrement /> > prop: snapOnStep > should decrement by exact step without rounding when snapOnStep is false",
1580
+ "apg": "extension",
1581
+ "config": {
1582
+ "defaultValue": 2.7,
1583
+ "step": 2,
1584
+ "snapOnStep": false,
1585
+ "buttons": true
1586
+ },
1587
+ "steps": [
1588
+ { "event": "click", "target": "decrement" },
1589
+ { "expect": { "value": { "input": "0.7" } } }
1590
+ ]
1591
+ },
1592
+ {
1593
+ "id": "spinbutton.base-ui.decrement-snaps-when-true",
1594
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L461",
1595
+ "upstreamTest": "<NumberField.Decrement /> > prop: snapOnStep > should snap on decrement when snapOnStep is true",
1596
+ "apg": "extension",
1597
+ "config": { "defaultValue": 1.3, "snapOnStep": true, "buttons": true },
1598
+ "steps": [
1599
+ { "event": "click", "target": "decrement" },
1600
+ { "expect": { "value": { "input": "1" } } },
1601
+ { "event": "type", "target": "input", "value": "1.9" },
1602
+ { "event": "click", "target": "decrement" },
1603
+ { "expect": { "value": { "input": "1" } } },
1604
+ { "event": "type", "target": "input", "value": "-0.2" },
1605
+ { "event": "click", "target": "decrement" },
1606
+ { "expect": { "value": { "input": "-1" } } }
1607
+ ]
1608
+ },
1609
+ {
1610
+ "id": "spinbutton.base-ui.decrement-snaps-relative-to-min",
1611
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L485",
1612
+ "upstreamTest": "<NumberField.Decrement /> > prop: snapOnStep > should decrement with respect to the min value",
1613
+ "apg": "extension",
1614
+ "config": {
1615
+ "defaultValue": 8,
1616
+ "min": 1,
1617
+ "step": 2,
1618
+ "snapOnStep": true,
1619
+ "buttons": true
1620
+ },
1621
+ "steps": [
1622
+ { "event": "click", "target": "decrement" },
1623
+ { "expect": { "value": { "input": "7" } } },
1624
+ { "event": "click", "target": "decrement" },
1625
+ { "expect": { "value": { "input": "5" } } },
1626
+ { "event": "type", "target": "input", "value": "9.112" },
1627
+ { "event": "click", "target": "decrement" },
1628
+ { "expect": { "value": { "input": "9" } } },
1629
+ { "event": "type", "target": "input", "value": "1.112" },
1630
+ { "event": "click", "target": "decrement" },
1631
+ { "expect": { "value": { "input": "1" } } }
1632
+ ]
1633
+ },
1634
+ {
1635
+ "id": "spinbutton.base-ui.decrement-disabled-root",
1636
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L513",
1637
+ "upstreamTest": "<NumberField.Decrement /> > disabled state > should not decrement when root is disabled",
1638
+ "apg": "extension",
1639
+ "config": { "disabled": true, "buttons": true },
1640
+ "steps": [
1641
+ { "event": "click", "target": "decrement" },
1642
+ {
1643
+ "expect": {
1644
+ "value": { "input": "" },
1645
+ "events": { "onValueChange": [] }
1646
+ }
1647
+ }
1648
+ ]
1649
+ },
1650
+ {
1651
+ "id": "spinbutton.base-ui.decrement-disabled-button",
1652
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/decrement/NumberFieldDecrement.test.tsx#L528",
1653
+ "upstreamTest": "<NumberField.Decrement /> > disabled state > should not decrement when button is disabled",
1654
+ "apg": "extension",
1655
+ "config": {
1656
+ "defaultValue": 0,
1657
+ "decrementDisabled": true,
1658
+ "buttons": true
1659
+ },
1660
+ "steps": [
1661
+ {
1662
+ "expect": {
1663
+ "attrs": { "decrement": { "disabled": "true" } },
1664
+ "value": { "input": "0" }
1665
+ }
1666
+ },
1667
+ { "event": "pointerdown", "target": "decrement", "button": 0 },
1668
+ {
1669
+ "expect": {
1670
+ "value": { "input": "0" },
1671
+ "events": { "onValueChange": [] }
1672
+ }
1673
+ }
1674
+ ]
1675
+ },
1676
+ {
1677
+ "id": "spinbutton.base-ui.readonly-steppers-do-not-change",
1678
+ "upstream": "https://github.com/mui/base-ui/blob/19511bb171f3b360b006c94cf6d07e53cb446505/packages/react/src/number-field/increment/NumberFieldIncrement.test.tsx#L729",
1679
+ "upstreamTest": "<NumberField.Increment /> > should not increment when readOnly",
1680
+ "apg": "extension",
1681
+ "config": { "readOnly": true, "buttons": true },
1682
+ "steps": [
1683
+ { "event": "click", "target": "increment" },
1684
+ { "expect": { "value": { "input": "" } } }
1685
+ ]
1686
+ }
1687
+ ]
1688
+ }