@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,557 @@
1
+ {
2
+ "pattern": "windowsplitter",
3
+ "source": "apg",
4
+ "commit": null,
5
+ "license": "W3C Software and Document License",
6
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/",
7
+ "notes": "No upstream implementation of the window splitter pattern exists in ariakit, base-ui or react-aria. Searched all *test* files under ariakit/app/src, base-ui/packages and react-spectrum/packages for separator/splitter/resiz: ariakit and base-ui ship only a static role=separator element (base-ui Separator.test.tsx, ariakit examples/separator and toolbar separators) that has no size control; react-aria's useSeparator is likewise static. react-aria's ColumnResizer (react-aria-components Table) is a table-column resizer, not a splitter: it renders an <input type=range> with role=slider (so not role=separator), Enter starts keyboard resizing rather than collapsing, arrows move the slider, and there is no F6 pane cycle - it does not follow the window splitter keyboard model, so it is not ported. Scenarios are therefore derived from the APG Window Splitter Pattern page: About This Pattern, Keyboard Interaction, and WAI-ARIA Roles, States, and Properties, licensed W3C Software and Document License. There is no functional APG example for this pattern (tracked upstream as issue 130), so no example-derived scenarios exist.",
8
+ "skipped": [
9
+ {
10
+ "reason": "ariakit static separators (app/src/sandbox/separator-semantics, app/src/examples/separator/_component/test.ts, app/src/sandbox/toolbar-separator-6302, app/src/sandbox/role-7455): role=separator elements that are not focusable and do not resize a pane"
11
+ },
12
+ {
13
+ "reason": "base-ui static separators (packages/react/src/separator/Separator.test.tsx, packages/react/src/toolbar/separator/ToolbarSeparator.test.tsx): role=separator + aria-orientation conformance only, no size control"
14
+ },
15
+ {
16
+ "reason": "react-aria static separators (packages/react-aria-components/test/Separator.test.js, packages/@adobe/react-spectrum/test/divider/Divider.test.js): render/class/DOM-prop assertions on a static separator; useSeparator is not focusable and does not resize"
17
+ },
18
+ {
19
+ "reason": "react-aria table column resizing (packages/react-aria-components/test/Table.test.js resizeCol, packages/@adobe/react-spectrum/test/table/TableSizing.test.tsx, packages/react-aria/test/table/ariaTableResizing.test.tsx, packages/react-aria/test/table/tableResizingTests.tsx): ColumnResizer/Resizer render an <input type=range> with role=slider and resize table columns; this is the Slider pattern, not the window splitter keyboard model (Enter starts keyboard resize, no collapse/restore, no F6 cycle)"
20
+ },
21
+ {
22
+ "reason": "@adobe/spectrum-css-temp/components/splitview/*.css: CSS custom-property styles with no React component or test"
23
+ }
24
+ ],
25
+ "scenarios": [
26
+ {
27
+ "id": "windowsplitter.apg.about.vertical-splitter-between-left-and-right-panes",
28
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#aboutthispattern",
29
+ "upstreamTest": "About This Pattern: a vertical splitter divides left and right panes",
30
+ "apg": "about",
31
+ "config": {
32
+ "orientation": "vertical",
33
+ "value": 4,
34
+ "min": 0,
35
+ "max": 6,
36
+ "step": 2
37
+ },
38
+ "steps": [
39
+ {
40
+ "expect": {
41
+ "attrs": {
42
+ "separator": {
43
+ "role": "separator",
44
+ "aria-orientation": "vertical",
45
+ "aria-valuenow": "4"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ]
51
+ },
52
+ {
53
+ "id": "windowsplitter.apg.about.horizontal-splitter-between-top-and-bottom-panes",
54
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#aboutthispattern",
55
+ "upstreamTest": "About This Pattern: a horizontal splitter divides top and bottom panes",
56
+ "apg": "about",
57
+ "config": {
58
+ "orientation": "horizontal",
59
+ "value": 4,
60
+ "min": 0,
61
+ "max": 6,
62
+ "step": 2
63
+ },
64
+ "steps": [
65
+ {
66
+ "expect": {
67
+ "attrs": {
68
+ "separator": {
69
+ "role": "separator",
70
+ "aria-orientation": "horizontal",
71
+ "aria-valuenow": "4"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ]
77
+ },
78
+
79
+ {
80
+ "id": "windowsplitter.apg.keyboard.left-arrow-moves-vertical-splitter-left",
81
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
82
+ "upstreamTest": "Keyboard Interaction: Left Arrow moves a vertical splitter to the left",
83
+ "apg": "keyboard",
84
+ "config": {
85
+ "orientation": "vertical",
86
+ "value": 4,
87
+ "min": 0,
88
+ "max": 6,
89
+ "step": 2
90
+ },
91
+ "steps": [
92
+ { "event": "focus", "target": "separator" },
93
+ { "event": "key", "key": "ArrowLeft", "target": "separator" },
94
+ {
95
+ "expect": {
96
+ "focus": "separator",
97
+ "attrs": { "separator": { "aria-valuenow": "2" } }
98
+ }
99
+ }
100
+ ]
101
+ },
102
+ {
103
+ "id": "windowsplitter.apg.keyboard.right-arrow-moves-vertical-splitter-right",
104
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
105
+ "upstreamTest": "Keyboard Interaction: Right Arrow moves a vertical splitter to the right",
106
+ "apg": "keyboard",
107
+ "config": {
108
+ "orientation": "vertical",
109
+ "value": 4,
110
+ "min": 0,
111
+ "max": 6,
112
+ "step": 2
113
+ },
114
+ "steps": [
115
+ { "event": "focus", "target": "separator" },
116
+ { "event": "key", "key": "ArrowRight", "target": "separator" },
117
+ {
118
+ "expect": {
119
+ "focus": "separator",
120
+ "attrs": { "separator": { "aria-valuenow": "6" } }
121
+ }
122
+ }
123
+ ]
124
+ },
125
+ {
126
+ "id": "windowsplitter.apg.keyboard.vertical-splitter-ignores-up-and-down-arrows",
127
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
128
+ "upstreamTest": "Keyboard Interaction: only the arrow pair matching the splitter axis moves it",
129
+ "apg": "keyboard",
130
+ "config": {
131
+ "orientation": "vertical",
132
+ "value": 4,
133
+ "min": 0,
134
+ "max": 6,
135
+ "step": 2
136
+ },
137
+ "steps": [
138
+ { "event": "focus", "target": "separator" },
139
+ { "event": "key", "key": "ArrowUp", "target": "separator" },
140
+ { "event": "key", "key": "ArrowDown", "target": "separator" },
141
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "4" } } } }
142
+ ]
143
+ },
144
+ {
145
+ "id": "windowsplitter.apg.keyboard.up-arrow-moves-horizontal-splitter-up",
146
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
147
+ "upstreamTest": "Keyboard Interaction: Up Arrow moves a horizontal splitter up",
148
+ "apg": "keyboard",
149
+ "config": {
150
+ "orientation": "horizontal",
151
+ "value": 4,
152
+ "min": 0,
153
+ "max": 6,
154
+ "step": 2
155
+ },
156
+ "steps": [
157
+ { "event": "focus", "target": "separator" },
158
+ { "event": "key", "key": "ArrowUp", "target": "separator" },
159
+ {
160
+ "expect": {
161
+ "focus": "separator",
162
+ "attrs": { "separator": { "aria-valuenow": "2" } }
163
+ }
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ "id": "windowsplitter.apg.keyboard.down-arrow-moves-horizontal-splitter-down",
169
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
170
+ "upstreamTest": "Keyboard Interaction: Down Arrow moves a horizontal splitter down",
171
+ "apg": "keyboard",
172
+ "config": {
173
+ "orientation": "horizontal",
174
+ "value": 4,
175
+ "min": 0,
176
+ "max": 6,
177
+ "step": 2
178
+ },
179
+ "steps": [
180
+ { "event": "focus", "target": "separator" },
181
+ { "event": "key", "key": "ArrowDown", "target": "separator" },
182
+ {
183
+ "expect": {
184
+ "focus": "separator",
185
+ "attrs": { "separator": { "aria-valuenow": "6" } }
186
+ }
187
+ }
188
+ ]
189
+ },
190
+ {
191
+ "id": "windowsplitter.apg.keyboard.horizontal-splitter-ignores-left-and-right-arrows",
192
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
193
+ "upstreamTest": "Keyboard Interaction: only the arrow pair matching the splitter axis moves it",
194
+ "apg": "keyboard",
195
+ "config": {
196
+ "orientation": "horizontal",
197
+ "value": 4,
198
+ "min": 0,
199
+ "max": 6,
200
+ "step": 2
201
+ },
202
+ "steps": [
203
+ { "event": "focus", "target": "separator" },
204
+ { "event": "key", "key": "ArrowLeft", "target": "separator" },
205
+ { "event": "key", "key": "ArrowRight", "target": "separator" },
206
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "4" } } } }
207
+ ]
208
+ },
209
+ {
210
+ "id": "windowsplitter.apg.keyboard.left-arrow-clamps-at-minimum",
211
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
212
+ "upstreamTest": "Keyboard Interaction: the splitter cannot move below the minimum position",
213
+ "apg": "keyboard",
214
+ "config": {
215
+ "orientation": "vertical",
216
+ "value": 0,
217
+ "min": 0,
218
+ "max": 6,
219
+ "step": 2
220
+ },
221
+ "steps": [
222
+ { "event": "focus", "target": "separator" },
223
+ { "event": "key", "key": "ArrowLeft", "target": "separator" },
224
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "0" } } } }
225
+ ]
226
+ },
227
+ {
228
+ "id": "windowsplitter.apg.keyboard.right-arrow-clamps-at-maximum",
229
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
230
+ "upstreamTest": "Keyboard Interaction: the splitter cannot move above the maximum position",
231
+ "apg": "keyboard",
232
+ "config": {
233
+ "orientation": "vertical",
234
+ "value": 6,
235
+ "min": 0,
236
+ "max": 6,
237
+ "step": 2
238
+ },
239
+ "steps": [
240
+ { "event": "focus", "target": "separator" },
241
+ { "event": "key", "key": "ArrowRight", "target": "separator" },
242
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "6" } } } }
243
+ ]
244
+ },
245
+ {
246
+ "id": "windowsplitter.apg.keyboard.enter-collapses-primary-pane",
247
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
248
+ "upstreamTest": "Keyboard Interaction: Enter collapses the primary pane when it is not collapsed",
249
+ "apg": "keyboard",
250
+ "config": {
251
+ "orientation": "vertical",
252
+ "value": 4,
253
+ "min": 0,
254
+ "max": 6,
255
+ "step": 2,
256
+ "collapsed": false
257
+ },
258
+ "steps": [
259
+ { "event": "focus", "target": "separator" },
260
+ { "event": "key", "key": "Enter", "target": "separator" },
261
+ {
262
+ "expect": {
263
+ "attrs": {
264
+ "separator": { "aria-valuenow": "0", "aria-valuemin": "0" }
265
+ }
266
+ }
267
+ }
268
+ ]
269
+ },
270
+ {
271
+ "id": "windowsplitter.apg.keyboard.enter-restores-previous-position",
272
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
273
+ "upstreamTest": "Keyboard Interaction: Enter restores the splitter to its previous position when the pane is collapsed",
274
+ "apg": "keyboard",
275
+ "config": {
276
+ "orientation": "vertical",
277
+ "value": 2,
278
+ "min": 0,
279
+ "max": 6,
280
+ "step": 2,
281
+ "prev": 2
282
+ },
283
+ "steps": [
284
+ { "event": "focus", "target": "separator" },
285
+ { "event": "key", "key": "Enter", "target": "separator" },
286
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "0" } } } },
287
+ { "event": "key", "key": "Enter", "target": "separator" },
288
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "2" } } } }
289
+ ],
290
+ "notes": "The remembered position is the value at the moment of collapse; moving to value 2 first makes the restore distinguishable from the initial 4."
291
+ },
292
+ {
293
+ "id": "windowsplitter.apg.keyboard.home-moves-splitter-to-minimum",
294
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
295
+ "upstreamTest": "Keyboard Interaction (optional): Home moves splitter to the smallest allowed primary-pane size",
296
+ "apg": "keyboard",
297
+ "config": {
298
+ "orientation": "vertical",
299
+ "value": 4,
300
+ "min": 0,
301
+ "max": 6,
302
+ "step": 2
303
+ },
304
+ "steps": [
305
+ { "event": "focus", "target": "separator" },
306
+ { "event": "key", "key": "Home", "target": "separator" },
307
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "0" } } } }
308
+ ]
309
+ },
310
+ {
311
+ "id": "windowsplitter.apg.keyboard.end-moves-splitter-to-maximum",
312
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
313
+ "upstreamTest": "Keyboard Interaction (optional): End moves splitter to the largest allowed primary-pane size",
314
+ "apg": "keyboard",
315
+ "config": {
316
+ "orientation": "vertical",
317
+ "value": 4,
318
+ "min": 0,
319
+ "max": 6,
320
+ "step": 2
321
+ },
322
+ "steps": [
323
+ { "event": "focus", "target": "separator" },
324
+ { "event": "key", "key": "End", "target": "separator" },
325
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "6" } } } }
326
+ ]
327
+ },
328
+ {
329
+ "id": "windowsplitter.apg.keyboard.f6-cycles-focus-through-panes",
330
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
331
+ "upstreamTest": "Keyboard Interaction (optional): F6 cycles through window panes",
332
+ "apg": "keyboard",
333
+ "config": {
334
+ "orientation": "vertical",
335
+ "value": 4,
336
+ "min": 0,
337
+ "max": 6,
338
+ "step": 2
339
+ },
340
+ "steps": [
341
+ { "event": "focus", "target": "separator" },
342
+ { "event": "key", "key": "F6", "target": "separator" },
343
+ { "expect": { "focus": "secondary" } },
344
+ { "event": "key", "key": "F6", "target": "secondary" },
345
+ { "expect": { "focus": "primary" } },
346
+ { "event": "key", "key": "F6", "target": "primary" },
347
+ { "expect": { "focus": "separator" } }
348
+ ],
349
+ "notes": "APG does not fix the cycle order; the order asserted here is the one modelled by specs/apg/windowsplitter.qnt (splitter -> secondary -> primary -> splitter)."
350
+ },
351
+ {
352
+ "id": "windowsplitter.apg.keyboard.keys-ignored-when-a-pane-has-focus",
353
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
354
+ "upstreamTest": "Keyboard Interaction: splitter keys operate only while the splitter has focus",
355
+ "apg": "keyboard",
356
+ "config": {
357
+ "orientation": "vertical",
358
+ "value": 4,
359
+ "min": 0,
360
+ "max": 6,
361
+ "step": 2
362
+ },
363
+ "steps": [
364
+ { "event": "focus", "target": "separator" },
365
+ { "event": "key", "key": "F6", "target": "separator" },
366
+ { "event": "key", "key": "ArrowLeft", "target": "secondary" },
367
+ { "event": "key", "key": "Enter", "target": "secondary" },
368
+ {
369
+ "expect": {
370
+ "focus": "secondary",
371
+ "attrs": { "separator": { "aria-valuenow": "4" } }
372
+ }
373
+ }
374
+ ]
375
+ },
376
+ {
377
+ "id": "windowsplitter.apg.keyboard.fixed-splitter-ignores-arrows",
378
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#keyboardinteraction",
379
+ "upstreamTest": "Keyboard Interaction note: a fixed size splitter omits implementation of the arrow keys",
380
+ "apg": "keyboard",
381
+ "config": {
382
+ "orientation": "vertical",
383
+ "fixed": true,
384
+ "value": 4,
385
+ "min": 0,
386
+ "max": 6,
387
+ "step": 2
388
+ },
389
+ "steps": [
390
+ { "event": "focus", "target": "separator" },
391
+ { "event": "key", "key": "ArrowLeft", "target": "separator" },
392
+ { "event": "key", "key": "ArrowRight", "target": "separator" },
393
+ { "event": "key", "key": "Home", "target": "separator" },
394
+ { "event": "key", "key": "End", "target": "separator" },
395
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "4" } } } }
396
+ ]
397
+ },
398
+ {
399
+ "id": "windowsplitter.apg.keyboard.fixed-splitter-enter-toggles-two-positions",
400
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#aboutthispattern",
401
+ "upstreamTest": "About This Pattern: a fixed splitter toggles between two positions",
402
+ "apg": "keyboard",
403
+ "config": {
404
+ "orientation": "vertical",
405
+ "fixed": true,
406
+ "value": 4,
407
+ "min": 0,
408
+ "max": 6,
409
+ "step": 2,
410
+ "prev": 4
411
+ },
412
+ "steps": [
413
+ { "event": "focus", "target": "separator" },
414
+ { "event": "key", "key": "Enter", "target": "separator" },
415
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "0" } } } },
416
+ { "event": "key", "key": "Enter", "target": "separator" },
417
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "4" } } } }
418
+ ],
419
+ "notes": "A fixed splitter still collapses/restores with Enter; only the arrow keys are omitted (previous scenario)."
420
+ },
421
+
422
+ {
423
+ "id": "windowsplitter.apg.roles.focusable-splitter-has-role-separator",
424
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
425
+ "upstreamTest": "Roles/States: the focusable splitter element has role separator",
426
+ "apg": "roles",
427
+ "config": {
428
+ "orientation": "vertical",
429
+ "value": 4,
430
+ "min": 0,
431
+ "max": 6,
432
+ "step": 2
433
+ },
434
+ "steps": [
435
+ {
436
+ "expect": {
437
+ "attrs": { "separator": { "role": "separator", "tabindex": "0" } }
438
+ }
439
+ }
440
+ ]
441
+ },
442
+ {
443
+ "id": "windowsplitter.apg.roles.aria-valuenow-represents-current-position",
444
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
445
+ "upstreamTest": "Roles/States: aria-valuenow is a decimal for the current separator position",
446
+ "apg": "roles",
447
+ "config": {
448
+ "orientation": "vertical",
449
+ "value": 4,
450
+ "min": 0,
451
+ "max": 6,
452
+ "step": 2
453
+ },
454
+ "steps": [
455
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "4" } } } },
456
+ { "event": "focus", "target": "separator" },
457
+ { "event": "key", "key": "ArrowRight", "target": "separator" },
458
+ { "expect": { "attrs": { "separator": { "aria-valuenow": "6" } } } }
459
+ ]
460
+ },
461
+ {
462
+ "id": "windowsplitter.apg.roles.aria-valuemin-is-minimum-position",
463
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
464
+ "upstreamTest": "Roles/States: aria-valuemin represents the position of the smallest primary pane, typically 0",
465
+ "apg": "roles",
466
+ "config": {
467
+ "orientation": "vertical",
468
+ "value": 4,
469
+ "min": 0,
470
+ "max": 6,
471
+ "step": 2
472
+ },
473
+ "steps": [
474
+ { "expect": { "attrs": { "separator": { "aria-valuemin": "0" } } } }
475
+ ]
476
+ },
477
+ {
478
+ "id": "windowsplitter.apg.roles.aria-valuemax-is-maximum-position",
479
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
480
+ "upstreamTest": "Roles/States: aria-valuemax represents the position of the largest primary pane, typically 100",
481
+ "apg": "roles",
482
+ "config": {
483
+ "orientation": "vertical",
484
+ "value": 4,
485
+ "min": 0,
486
+ "max": 6,
487
+ "step": 2
488
+ },
489
+ "steps": [
490
+ { "expect": { "attrs": { "separator": { "aria-valuemax": "6" } } } }
491
+ ],
492
+ "notes": "APG says aria-valuemax is typically 100; this scenario pins the range end of the modelled widget (maximum 6)."
493
+ },
494
+ {
495
+ "id": "windowsplitter.apg.roles.aria-label-names-primary-pane",
496
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
497
+ "upstreamTest": "Roles/States: without a visible primary-pane label, the splitter gets its name from aria-label",
498
+ "apg": "roles",
499
+ "config": {
500
+ "orientation": "vertical",
501
+ "value": 4,
502
+ "min": 0,
503
+ "max": 6,
504
+ "labelledby": null
505
+ },
506
+ "steps": [
507
+ {
508
+ "expect": {
509
+ "attrs": {
510
+ "separator": { "aria-label": "*", "aria-labelledby": null }
511
+ }
512
+ }
513
+ }
514
+ ],
515
+ "notes": "Attribute value \"*\" means any non-empty implementation-chosen accessible name matching the primary pane name."
516
+ },
517
+ {
518
+ "id": "windowsplitter.apg.roles.aria-labelledby-references-primary-pane-label",
519
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
520
+ "upstreamTest": "Roles/States: a visible primary-pane label is referenced by aria-labelledby on the splitter",
521
+ "apg": "roles",
522
+ "config": {
523
+ "orientation": "vertical",
524
+ "value": 4,
525
+ "min": 0,
526
+ "max": 6,
527
+ "labelledby": "primary-label"
528
+ },
529
+ "steps": [
530
+ {
531
+ "expect": {
532
+ "attrs": { "separator": { "aria-labelledby": "primary-label" } }
533
+ }
534
+ }
535
+ ]
536
+ },
537
+ {
538
+ "id": "windowsplitter.apg.roles.aria-controls-references-primary-pane",
539
+ "upstream": "https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/#wai-ariaroles,states,andproperties",
540
+ "upstreamTest": "Roles/States: the splitter has aria-controls referring to the primary pane",
541
+ "apg": "roles",
542
+ "config": {
543
+ "orientation": "vertical",
544
+ "value": 4,
545
+ "min": 0,
546
+ "max": 6,
547
+ "step": 2
548
+ },
549
+ "steps": [
550
+ {
551
+ "expect": { "attrs": { "separator": { "aria-controls": "*" } } }
552
+ }
553
+ ],
554
+ "notes": "Attribute value \"*\" means any non-empty IDREF (or IDREF list) identifying the primary pane."
555
+ }
556
+ ]
557
+ }
@@ -0,0 +1,69 @@
1
+ # Canvas scenarios — upstream tests ported as library-neutral data
2
+
3
+ Same envelope (and `skipped` shape) as `../apg/README.md`, which is the one
4
+ format spec; the step/expectation vocabulary below is canvas-specific and is not
5
+ decoded by `src/scenario.ts`. For the canvas machines
6
+ (`specs/canvas/camera.qnt`, `specs/canvas/pointer.qnt`). One file per area and
7
+ source: `<area>.<source>.json`. Each scenario is a port of one upstream test (no
8
+ code copied; behaviour and numbers restated).
9
+
10
+ Only MIT-licensed sources are ported. **tldraw is deliberately absent**: its
11
+ licence is not open-source (see `docs/research/canvas-prior-art.md` §9), so none of
12
+ its code, tests or scenario data may be copied or paraphrased.
13
+
14
+ | source | repo | commit | licence | copyright |
15
+ | ---------- | --------------------- | ------------------------------------------ | ------- | ----------------------------- |
16
+ | excalidraw | excalidraw/excalidraw | `ed10ac7dca7e40f3f4a31269b4bfba980d0db41e` | MIT | Copyright (c) 2020 Excalidraw |
17
+
18
+ ## NOTICE
19
+
20
+ The scenario files named `*.excalidraw.json` restate tests from
21
+ https://github.com/excalidraw/excalidraw (MIT). The upstream notice travels with
22
+ them:
23
+
24
+ > MIT License
25
+ >
26
+ > Copyright (c) 2020 Excalidraw
27
+ >
28
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ > of this software and associated documentation files (the "Software"), to deal
30
+ > in the Software without restriction, including without limitation the rights
31
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ > copies of the Software, and to permit persons to whom the Software is
33
+ > furnished to do so, subject to the following conditions:
34
+ >
35
+ > The above copyright notice and this permission notice shall be included in all
36
+ > copies or substantial portions of the Software.
37
+ >
38
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44
+ > SOFTWARE.
45
+
46
+ ## Shape
47
+
48
+ The envelope adds `copyright`; `apg` becomes `area` (`"selection"` | `"extension"`,
49
+ i.e. not derived from a spec section). `config` always states its own limits
50
+ (box-selection mode, drag threshold, camera, nodes) — upstream defaults differ per
51
+ library and are never assumed.
52
+
53
+ - Units: world units for `nodes` and `camera.x / y` (world-offset: screen =
54
+ (world + camera) \* zoom, which is the `camera.qnt` convention), screen px for
55
+ `at`, `viewport` and `dragThresholdPx`.
56
+ - `event`: `pointerdown` | `pointermove` | `pointerup` | `pointercancel` |
57
+ `modifier` (`{ "shift": true }`) | `tween` (`goal`, `animation`) | `tick`
58
+ (`count` or `until: "settled"`).
59
+ - `expect` checks only what the upstream test checks: `selection` (node ids;
60
+ `selectionOrder: "unordered"`), `selectionChanged` (did THIS step change the
61
+ selection set), `camera`, `tweenActive`, `cameraMoved`,
62
+ `cameraUnchangedSinceSettled`, `panEngaged`.
63
+ - The artificial `move(-1000, -1000)` upstream uses to get past a drag threshold is
64
+ dropped: scenarios move straight to the final point.
65
+
66
+ `test/canvas/scenarios.test.ts` validates the envelope and replays the marquee
67
+ scenarios and the centre-on arithmetic against the same definitions the specs use
68
+ (contain = box encloses node, overlap = positive-area intersection; fixed-point
69
+ centre-on).