@ankhorage/zora 25.6.2 → 25.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/dist/capabilities/index.js +13 -1
  4. package/dist/capabilities/index.js.map +5 -4
  5. package/dist/features/grid-interactions/adapters/inbound/GridInteractions.d.ts +5 -0
  6. package/dist/features/grid-interactions/adapters/inbound/GridInteractions.d.ts.map +1 -0
  7. package/dist/features/grid-interactions/adapters/inbound/GridInteractions.js +40 -0
  8. package/dist/features/grid-interactions/adapters/inbound/GridInteractions.js.map +1 -0
  9. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.d.ts +2 -0
  10. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.d.ts.map +1 -0
  11. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.js +2 -0
  12. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.js.map +1 -0
  13. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.native.d.ts +11 -0
  14. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.native.d.ts.map +1 -0
  15. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.native.js +5 -0
  16. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.native.js.map +1 -0
  17. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.d.ts +11 -0
  18. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.d.ts.map +1 -0
  19. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.js +20 -0
  20. package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.js.map +1 -0
  21. package/dist/features/grid-interactions/adapters/inbound/createGridInteractionsPointerQueue.d.ts +17 -0
  22. package/dist/features/grid-interactions/adapters/inbound/createGridInteractionsPointerQueue.d.ts.map +1 -0
  23. package/dist/features/grid-interactions/adapters/inbound/createGridInteractionsPointerQueue.js +76 -0
  24. package/dist/features/grid-interactions/adapters/inbound/createGridInteractionsPointerQueue.js.map +1 -0
  25. package/dist/features/grid-interactions/adapters/inbound/resolveGridInteractionPointer.d.ts +21 -0
  26. package/dist/features/grid-interactions/adapters/inbound/resolveGridInteractionPointer.d.ts.map +1 -0
  27. package/dist/features/grid-interactions/adapters/inbound/resolveGridInteractionPointer.js +20 -0
  28. package/dist/features/grid-interactions/adapters/inbound/resolveGridInteractionPointer.js.map +1 -0
  29. package/dist/features/grid-interactions/application/createGridInteractionsController.d.ts +4 -0
  30. package/dist/features/grid-interactions/application/createGridInteractionsController.d.ts.map +1 -0
  31. package/dist/features/grid-interactions/application/createGridInteractionsController.js +191 -0
  32. package/dist/features/grid-interactions/application/createGridInteractionsController.js.map +1 -0
  33. package/dist/features/grid-interactions/meta.d.ts +11 -0
  34. package/dist/features/grid-interactions/meta.d.ts.map +1 -0
  35. package/dist/features/grid-interactions/meta.js +11 -0
  36. package/dist/features/grid-interactions/meta.js.map +1 -0
  37. package/dist/features/grid-interactions/public.d.ts +4 -0
  38. package/dist/features/grid-interactions/public.d.ts.map +1 -0
  39. package/dist/features/grid-interactions/public.js +3 -0
  40. package/dist/features/grid-interactions/public.js.map +1 -0
  41. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.d.ts.map +1 -1
  42. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.js +73 -19
  43. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.js.map +1 -1
  44. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.d.ts +9 -0
  45. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.d.ts.map +1 -0
  46. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.js +5 -0
  47. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.js.map +1 -0
  48. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.d.ts +9 -0
  49. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.d.ts.map +1 -0
  50. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.js +5 -0
  51. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.js.map +1 -0
  52. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.d.ts +9 -0
  53. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.d.ts.map +1 -0
  54. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.js +28 -0
  55. package/dist/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.js.map +1 -0
  56. package/dist/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.d.ts +14 -0
  57. package/dist/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.d.ts.map +1 -0
  58. package/dist/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.js +50 -0
  59. package/dist/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.js.map +1 -0
  60. package/dist/features/matrix-grid/application/createMatrixGridSparseIndex.d.ts +18 -0
  61. package/dist/features/matrix-grid/application/createMatrixGridSparseIndex.d.ts.map +1 -0
  62. package/dist/features/matrix-grid/application/createMatrixGridSparseIndex.js +56 -0
  63. package/dist/features/matrix-grid/application/createMatrixGridSparseIndex.js.map +1 -0
  64. package/dist/features/matrix-grid/application/getMatrixGridNextFocusId.d.ts +4 -0
  65. package/dist/features/matrix-grid/application/getMatrixGridNextFocusId.d.ts.map +1 -0
  66. package/dist/features/matrix-grid/application/getMatrixGridNextFocusId.js +65 -0
  67. package/dist/features/matrix-grid/application/getMatrixGridNextFocusId.js.map +1 -0
  68. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.d.ts +8 -1
  69. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.d.ts.map +1 -1
  70. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.js +15 -4
  71. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.js.map +1 -1
  72. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.d.ts.map +1 -1
  73. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js +2 -0
  74. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js.map +1 -1
  75. package/dist/features/registry/componentMeta.d.ts.map +1 -1
  76. package/dist/features/registry/componentMeta.js +2 -0
  77. package/dist/features/registry/componentMeta.js.map +1 -1
  78. package/dist/index.d.ts +1 -0
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +1 -0
  81. package/dist/index.js.map +1 -1
  82. package/dist/types/grid-interactions.d.ts +58 -0
  83. package/dist/types/grid-interactions.d.ts.map +1 -0
  84. package/dist/types/grid-interactions.js +2 -0
  85. package/dist/types/grid-interactions.js.map +1 -0
  86. package/dist/types/matrix-grid.d.ts +2 -0
  87. package/dist/types/matrix-grid.d.ts.map +1 -1
  88. package/dist/types/matrix-grid.js.map +1 -1
  89. package/package.json +5 -5
  90. package/src/features/grid-interactions/adapters/inbound/GridInteractions.test.tsx +143 -0
  91. package/src/features/grid-interactions/adapters/inbound/GridInteractions.tsx +79 -0
  92. package/src/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.native.tsx +14 -0
  93. package/src/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.tsx +1 -0
  94. package/src/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.tsx +41 -0
  95. package/src/features/grid-interactions/adapters/inbound/createGridInteractionsPointerQueue.test.ts +98 -0
  96. package/src/features/grid-interactions/adapters/inbound/createGridInteractionsPointerQueue.ts +94 -0
  97. package/src/features/grid-interactions/adapters/inbound/resolveGridInteractionPointer.test.ts +33 -0
  98. package/src/features/grid-interactions/adapters/inbound/resolveGridInteractionPointer.ts +45 -0
  99. package/src/features/grid-interactions/application/createGridInteractionsController.test.ts +115 -0
  100. package/src/features/grid-interactions/application/createGridInteractionsController.ts +231 -0
  101. package/src/features/grid-interactions/meta.ts +12 -0
  102. package/src/features/grid-interactions/public.ts +11 -0
  103. package/src/features/matrix-grid/adapters/inbound/MatrixGrid.test.tsx +280 -2
  104. package/src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx +121 -31
  105. package/src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.tsx +11 -0
  106. package/src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.tsx +11 -0
  107. package/src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.tsx +43 -0
  108. package/src/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.ts +70 -0
  109. package/src/features/matrix-grid/application/createMatrixGridSparseIndex.test.ts +35 -0
  110. package/src/features/matrix-grid/application/createMatrixGridSparseIndex.ts +105 -0
  111. package/src/features/matrix-grid/application/getMatrixGridNextFocusId.test.ts +93 -0
  112. package/src/features/matrix-grid/application/getMatrixGridNextFocusId.ts +112 -0
  113. package/src/features/matrix-grid/application/resolveMatrixGridSelection.test.ts +63 -2
  114. package/src/features/matrix-grid/application/resolveMatrixGridSelection.ts +27 -4
  115. package/src/features/registry/ZORA_COMPONENT_REGISTRY.ts +2 -0
  116. package/src/features/registry/componentMeta.ts +2 -0
  117. package/src/index.ts +11 -0
  118. package/src/types/grid-interactions.ts +72 -0
  119. package/src/types/matrix-grid.ts +2 -0
  120. package/web-dist/chunks/{Accordion-5g05kfmx.js → Accordion-0q2wzjdd.js} +4 -4
  121. package/web-dist/chunks/{Accordion-b96evb46.js → Accordion-1fsrnq73.js} +1 -1
  122. package/web-dist/chunks/{Accordion-h3y8qev2.js → Accordion-38ts3gnn.js} +2 -2
  123. package/web-dist/chunks/{Accordion-jnc315h7.js → Accordion-8pkw32q9.js} +2 -2
  124. package/web-dist/chunks/{Accordion-h7zsx9eg.js → Accordion-9jrxktne.js} +3 -3
  125. package/web-dist/chunks/{Accordion-9w8wg9mf.js → Accordion-9rnsg9pk.js} +1 -1
  126. package/web-dist/chunks/{Accordion-4zqd7twp.js → Accordion-9ygakvwk.js} +5 -5
  127. package/web-dist/chunks/{Accordion-fhnazn3n.js → Accordion-b74j4hdt.js} +1 -1
  128. package/web-dist/chunks/{Accordion-nssr5gep.js → Accordion-c50pywj3.js} +2 -2
  129. package/web-dist/chunks/{Accordion-pvj5npzc.js → Accordion-ddrn94v3.js} +3 -3
  130. package/web-dist/chunks/{Accordion-090y18cv.js → Accordion-dk0dtyc0.js} +3 -3
  131. package/web-dist/chunks/{Accordion-59pa0677.js → Accordion-fcczvwgg.js} +0 -1
  132. package/web-dist/chunks/{Accordion-sp4k08kw.js → Accordion-geah5s4f.js} +4 -4
  133. package/web-dist/chunks/{Accordion-6rrqpb2h.js → Accordion-h4ekm5cp.js} +2 -2
  134. package/web-dist/chunks/{Accordion-3d4wkzg7.js → Accordion-hecpczme.js} +5 -5
  135. package/web-dist/chunks/{Accordion-a6551mh4.js → Accordion-hn43wt45.js} +1 -1
  136. package/web-dist/chunks/{Accordion-sw7ep29d.js → Accordion-hnx7hx55.js} +2 -2
  137. package/web-dist/chunks/{Accordion-rsvphbe4.js → Accordion-j1chy29e.js} +1 -1
  138. package/web-dist/chunks/{Accordion-ewf1zen9.js → Accordion-k9cxpg08.js} +5 -5
  139. package/web-dist/chunks/{Accordion-5df6cgyf.js → Accordion-md1g54wg.js} +1 -1
  140. package/web-dist/chunks/{Accordion-kjtcbe09.js → Accordion-p1ebrt17.js} +3 -3
  141. package/web-dist/chunks/{Accordion-qn398m1x.js → Accordion-r2g18vxa.js} +1 -1
  142. package/web-dist/chunks/{Accordion-zt9yghdz.js → Accordion-rctfgyfv.js} +4 -4
  143. package/web-dist/chunks/{Accordion-88t8fgxv.js → Accordion-rfc5mdbv.js} +1 -1
  144. package/web-dist/chunks/{Accordion-fmzxat3v.js → Accordion-sdnzqktc.js} +4 -4
  145. package/web-dist/chunks/{Accordion-v0grdh6q.js → Accordion-sq7ya2ye.js} +2 -2
  146. package/web-dist/chunks/{Accordion-ejx5gcf9.js → Accordion-t5scffdr.js} +9 -9
  147. package/web-dist/chunks/{Accordion-sy1cc5my.js → Accordion-ts788t7b.js} +3 -3
  148. package/web-dist/chunks/{Accordion-4s68t3h7.js → Accordion-v3rzy273.js} +6 -6
  149. package/web-dist/chunks/{Accordion-7tjz25jh.js → Accordion-vbzjq3z8.js} +1 -1
  150. package/web-dist/chunks/{Accordion-jh72azm2.js → Accordion-vg337250.js} +2 -2
  151. package/web-dist/chunks/{Accordion-42jfy1a1.js → Accordion-vj1m2wck.js} +1 -1
  152. package/web-dist/chunks/{Accordion-tqpsmdrk.js → Accordion-vxg5sw01.js} +4 -4
  153. package/web-dist/chunks/{Accordion-61ntvh14.js → Accordion-w59y0jdf.js} +4 -4
  154. package/web-dist/chunks/{Accordion-fjxcn6g9.js → Accordion-wcmrasqx.js} +8 -8
  155. package/web-dist/chunks/{Accordion-r1cj2w9e.js → Accordion-wpk8dxqp.js} +3 -3
  156. package/web-dist/chunks/{Accordion-w6qedeba.js → Accordion-x055n3b3.js} +1 -1
  157. package/web-dist/chunks/{Accordion-dbf93gxh.js → Accordion-xcm1qc39.js} +1 -1
  158. package/web-dist/chunks/{Accordion-7kq500r1.js → Accordion-xgxxg1hz.js} +1 -1
  159. package/web-dist/chunks/{Accordion-a4cma5b6.js → Accordion-y3083394.js} +3 -3
  160. package/web-dist/chunks/{Accordion-40tenzcg.js → Accordion-yexfbrzg.js} +4 -4
  161. package/web-dist/chunks/{Accordion-2r0gqk3x.js → Accordion-ztw7zp6v.js} +5 -5
  162. package/web-dist/chunks/{Accordion-bz04casa.js → Accordion-zypyr9xw.js} +211 -6
  163. package/web-dist/components/accordion/Accordion.js +5 -5
  164. package/web-dist/components/accordion-item/AccordionItem.js +5 -5
  165. package/web-dist/components/activity-indicator/ActivityIndicator.js +1 -1
  166. package/web-dist/components/app-bar/AppBar.js +7 -7
  167. package/web-dist/components/app-header/AppHeader.js +7 -7
  168. package/web-dist/components/app-shell/AppShell.js +2 -2
  169. package/web-dist/components/auth-screen/AuthScreen.js +10 -10
  170. package/web-dist/components/avatar/Avatar.js +5 -5
  171. package/web-dist/components/avatar-group/AvatarGroup.js +5 -5
  172. package/web-dist/components/badge/Badge.js +2 -2
  173. package/web-dist/components/barcode-scanner-view/BarcodeScannerView.js +10 -10
  174. package/web-dist/components/bottom-sheet/BottomSheet.js +3 -3
  175. package/web-dist/components/bottom-sheet-flat-list/BottomSheetFlatList.js +3 -3
  176. package/web-dist/components/bottom-sheet-scroll-view/BottomSheetScrollView.js +3 -3
  177. package/web-dist/components/bottom-sheet-section-list/BottomSheetSectionList.js +3 -3
  178. package/web-dist/components/bottom-sheet-view/BottomSheetView.js +3 -3
  179. package/web-dist/components/bottom-sheet-virtualized-list/BottomSheetVirtualizedList.js +3 -3
  180. package/web-dist/components/breadcrumbs/Breadcrumbs.js +5 -5
  181. package/web-dist/components/button/Button.js +3 -3
  182. package/web-dist/components/button-group/ButtonGroup.js +3 -3
  183. package/web-dist/components/camera-permission-view/CameraPermissionView.js +10 -10
  184. package/web-dist/components/card/Card.js +9 -9
  185. package/web-dist/components/card-back/CardBack.js +2 -2
  186. package/web-dist/components/card-hand/CardHand.js +2 -2
  187. package/web-dist/components/chat-list-item/ChatListItem.js +7 -7
  188. package/web-dist/components/checkbox/Checkbox.js +4 -4
  189. package/web-dist/components/checkbox-group/CheckboxGroup.js +4 -4
  190. package/web-dist/components/chess-board/ChessBoard.js +2 -2
  191. package/web-dist/components/chip/Chip.js +5 -5
  192. package/web-dist/components/chip-group/ChipGroup.js +5 -5
  193. package/web-dist/components/collection-editor/CollectionEditor.js +9 -9
  194. package/web-dist/components/content-rail/ContentRail.js +4 -4
  195. package/web-dist/components/data-table/DataTable.js +14 -14
  196. package/web-dist/components/date-picker/DatePicker.js +5 -5
  197. package/web-dist/components/dialog/Dialog.js +4 -4
  198. package/web-dist/components/divider/Divider.js +2 -2
  199. package/web-dist/components/empty-state/EmptyState.js +10 -10
  200. package/web-dist/components/explorer/Explorer.js +7 -7
  201. package/web-dist/components/field/Field.js +4 -4
  202. package/web-dist/components/file-explorer/FileExplorer.js +7 -7
  203. package/web-dist/components/flat-list/FlatList.js +5 -5
  204. package/web-dist/components/forgot-password-form/ForgotPasswordForm.js +10 -10
  205. package/web-dist/components/form/Form.js +6 -6
  206. package/web-dist/components/form-actions/FormActions.js +6 -6
  207. package/web-dist/components/form-error/FormError.js +6 -6
  208. package/web-dist/components/game/Game.js +3 -3
  209. package/web-dist/components/game-entity/GameEntity.js +3 -3
  210. package/web-dist/components/game-field/GameField.js +3 -3
  211. package/web-dist/components/game-input-zone/GameInputZone.js +3 -3
  212. package/web-dist/components/game-measurement-probe/GameMeasurementProbe.js +3 -3
  213. package/web-dist/components/game-overlay/GameOverlay.js +3 -3
  214. package/web-dist/components/gradient/Gradient.js +3 -3
  215. package/web-dist/components/gradient-renderer-provider/GradientRendererProvider.js +3 -3
  216. package/web-dist/components/graph-view/GraphView.js +2 -2
  217. package/web-dist/components/grid/Grid.js +2 -2
  218. package/web-dist/components/grid-interactions/GridInteractions.d.ts +3 -0
  219. package/web-dist/components/grid-interactions/GridInteractions.js +371 -0
  220. package/web-dist/components/grid-interactions/index.d.ts +1 -0
  221. package/web-dist/components/grid-interactions/index.js +2 -0
  222. package/web-dist/components/grid-line-overlay/GridLineOverlay.js +2 -2
  223. package/web-dist/components/grid-ruler/GridRuler.js +2 -2
  224. package/web-dist/components/grid-view/GridView.js +1 -1
  225. package/web-dist/components/heading/Heading.js +2 -2
  226. package/web-dist/components/hero/Hero.js +9 -9
  227. package/web-dist/components/icon/Icon.js +2 -2
  228. package/web-dist/components/icon-button/IconButton.js +3 -3
  229. package/web-dist/components/image/Image.js +4 -4
  230. package/web-dist/components/keyboard-avoiding-view/KeyboardAvoidingView.js +2 -2
  231. package/web-dist/components/list/List.js +5 -5
  232. package/web-dist/components/list-item/ListItem.js +5 -5
  233. package/web-dist/components/list-section/ListSection.js +5 -5
  234. package/web-dist/components/matrix-grid/MatrixGrid.js +296 -47
  235. package/web-dist/components/media-card/MediaCard.js +9 -9
  236. package/web-dist/components/media-explorer/MediaExplorer.js +7 -7
  237. package/web-dist/components/message-bubble/MessageBubble.js +7 -7
  238. package/web-dist/components/metric-card/MetricCard.js +9 -9
  239. package/web-dist/components/missing-element/MissingElement.js +4 -4
  240. package/web-dist/components/o-auth-provider-button/OAuthProviderButton.js +10 -10
  241. package/web-dist/components/o-auth-provider-list/OAuthProviderList.js +10 -10
  242. package/web-dist/components/opening-book/OpeningBook.js +2 -2
  243. package/web-dist/components/otp-form/OtpForm.js +10 -10
  244. package/web-dist/components/pagination/Pagination.js +4 -4
  245. package/web-dist/components/palette-item/PaletteItem.js +9 -9
  246. package/web-dist/components/playing-card/PlayingCard.js +2 -2
  247. package/web-dist/components/poker-training-table/PokerTrainingTable.js +2 -2
  248. package/web-dist/components/popover-menu/PopoverMenu.js +4 -4
  249. package/web-dist/components/post-card/PostCard.js +9 -9
  250. package/web-dist/components/product-card/ProductCard.js +9 -9
  251. package/web-dist/components/progress/Progress.js +4 -4
  252. package/web-dist/components/progress-ring/ProgressRing.js +4 -4
  253. package/web-dist/components/radio/Radio.js +5 -5
  254. package/web-dist/components/radio-group/RadioGroup.js +5 -5
  255. package/web-dist/components/rating/Rating.js +3 -3
  256. package/web-dist/components/reader/Reader.js +10 -10
  257. package/web-dist/components/scan-overlay/ScanOverlay.js +10 -10
  258. package/web-dist/components/screen/Screen.js +2 -2
  259. package/web-dist/components/screen-section/ScreenSection.js +4 -4
  260. package/web-dist/components/scroll-view/ScrollView.js +2 -2
  261. package/web-dist/components/search-input/SearchInput.js +4 -4
  262. package/web-dist/components/section-header/SectionHeader.js +4 -4
  263. package/web-dist/components/section-list/SectionList.js +5 -5
  264. package/web-dist/components/select/Select.js +4 -4
  265. package/web-dist/components/selectable-item/SelectableItem.js +2 -2
  266. package/web-dist/components/selection-provider/SelectionProvider.js +2 -2
  267. package/web-dist/components/sign-in-form/SignInForm.js +10 -10
  268. package/web-dist/components/sign-up-form/SignUpForm.js +10 -10
  269. package/web-dist/components/skeleton/Skeleton.js +12 -12
  270. package/web-dist/components/skeleton-card/SkeletonCard.js +12 -12
  271. package/web-dist/components/skeleton-list/SkeletonList.js +12 -12
  272. package/web-dist/components/skeleton-text/SkeletonText.js +12 -12
  273. package/web-dist/components/spatial-grid/SpatialGrid.js +1 -1
  274. package/web-dist/components/surface/Surface.js +2 -2
  275. package/web-dist/components/switch/Switch.js +1 -1
  276. package/web-dist/components/tab/Tab.js +2 -2
  277. package/web-dist/components/tab-list/TabList.js +2 -2
  278. package/web-dist/components/tab-panel/TabPanel.js +2 -2
  279. package/web-dist/components/tabletop-table/TabletopTable.js +2 -2
  280. package/web-dist/components/tabs/Tabs.js +2 -2
  281. package/web-dist/components/text/Text.js +2 -2
  282. package/web-dist/components/text-input/TextInput.js +4 -4
  283. package/web-dist/components/tile-grid/TileGrid.js +1 -1
  284. package/web-dist/components/time-grid/TimeGrid.js +2 -2
  285. package/web-dist/components/time-picker/TimePicker.js +5 -5
  286. package/web-dist/components/timeline/Timeline.js +4 -4
  287. package/web-dist/components/toast/Toast.js +2 -2
  288. package/web-dist/components/toast-provider/ToastProvider.js +2 -2
  289. package/web-dist/components/toolbar/Toolbar.js +9 -9
  290. package/web-dist/components/tree-item/TreeItem.js +9 -9
  291. package/web-dist/components/tree-view/TreeView.js +1 -1
  292. package/web-dist/components/uploader/Uploader.js +12 -12
  293. package/web-dist/components/view/View.js +2 -2
  294. package/web-dist/manifest.json +787 -772
  295. package/web-dist/runtime/ZoraProvider.js +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"MatrixGrid.d.ts","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAmIrE,gGAAgG;AAChG,eAAO,MAAM,UAAU,uDAAsC,CAAC"}
1
+ {"version":3,"file":"MatrixGrid.d.ts","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AA4NrE,gGAAgG;AAChG,eAAO,MAAM,UAAU,uDAAsC,CAAC"}
@@ -1,55 +1,109 @@
1
- import { getVisibleMatrixCells, } from '@ankhorage/grid-view';
2
- import { Pressable } from '@ankhorage/surface';
1
+ import { getMatrixCellPlacement, getVisibleMatrixCells, } from '@ankhorage/grid-view';
2
+ import { isRecord } from '@ankhorage/utility/object';
3
3
  import React from 'react';
4
- import { StyleSheet, View } from 'react-native';
4
+ import { Platform, Pressable as NativePressable, StyleSheet, View } from 'react-native';
5
5
  import { GridView } from '../../../grid-view/public';
6
6
  import { resolveSelectionEventIntent } from '../../../selection/public';
7
7
  import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
8
8
  import { useZoraTheme } from '../../../theme/composition/useZoraTheme';
9
+ import { createMatrixGridSparseIndex } from '../../application/createMatrixGridSparseIndex';
9
10
  import { resolveMatrixGridContentSize } from '../../application/resolveMatrixGridContentSize';
10
11
  import { resolveMatrixGridSelection } from '../../application/resolveMatrixGridSelection';
12
+ import { MatrixGridKeyboardProxy } from './MatrixGridKeyboardProxy';
13
+ import { useMatrixGridKeyboardFocus } from './useMatrixGridKeyboardFocus';
11
14
  /*** Compose the canonical GridView around released sparse matrix placement and culling geometry. */
12
- function MatrixGridInner({ accessibilityLabel = 'Matrix grid', cells, height, interactionPolicy, layout, onSelectionChange, onViewportChange, overscanPixels = 160, renderCell, selectedCellIds = [], selectionMode = 'single', testID, viewport: controlledViewport, width, zoomX = 1, zoomY = 1, }) {
15
+ function MatrixGridInner({ accessibilityLabel = 'Matrix grid', cells, height, interactionPolicy, layout, onSelectionChange, onViewportChange, overscanPixels = 160, readOnly = false, renderCell, selectedCellIds = [], selectionMode = 'single', testID, viewport: controlledViewport, width, zoomX = 1, zoomY = 1, }) {
13
16
  const { theme } = useZoraTheme();
14
17
  const contentSize = React.useMemo(() => resolveMatrixGridContentSize(layout), [layout]);
15
18
  const initialViewport = React.useMemo(() => ({ height, offsetX: 0, offsetY: 0, pixelsPerUnitX: zoomX, pixelsPerUnitY: zoomY, width }), [height, width, zoomX, zoomY]);
16
19
  const [uncontrolledViewport, setUncontrolledViewport] = React.useState(initialViewport);
17
20
  const viewport = controlledViewport ?? uncontrolledViewport;
18
- const visibleCells = React.useMemo(() => getVisibleMatrixCells(layout, cells, viewport, overscanPixels), [cells, layout, overscanPixels, viewport]);
19
- const visibleCellById = React.useMemo(() => new Map(visibleCells.map((cell) => [cell.id, cell])), [visibleCells]);
21
+ const sparseIndex = React.useMemo(() => createMatrixGridSparseIndex(layout, cells), [cells, layout]);
22
+ const cellPlacements = React.useMemo(() => getVisibleMatrixCells(layout, cells, viewport, overscanPixels), [cells, layout, overscanPixels, viewport]);
23
+ const [visibleIds, setVisibleIds] = React.useState([]);
24
+ const anchorId = React.useRef(null);
20
25
  const handleViewportChange = React.useCallback((proposal) => {
21
26
  if (controlledViewport === undefined)
22
27
  setUncontrolledViewport(proposal);
23
28
  onViewportChange?.(proposal);
24
29
  }, [controlledViewport, onViewportChange]);
25
30
  const activateCell = React.useCallback((cell, event) => {
26
- if (interactionPolicy === 'passive')
31
+ if (interactionPolicy === 'passive' || readOnly)
27
32
  return;
28
- const intent = resolveSelectionEventIntent(event, 'pointer');
29
- onSelectionChange?.(resolveMatrixGridSelection(selectedCellIds, cell.id, intent, selectionMode));
30
- }, [interactionPolicy, onSelectionChange, selectedCellIds, selectionMode]);
33
+ const intent = isRangeSelectionEvent(event)
34
+ ? 'range'
35
+ : resolveSelectionEventIntent(event, 'pointer');
36
+ onSelectionChange?.(resolveMatrixGridSelection(sparseIndex.entries, selectedCellIds, cell.id, anchorId.current, intent, selectionMode));
37
+ if (intent !== 'range')
38
+ anchorId.current = cell.id;
39
+ }, [
40
+ interactionPolicy,
41
+ onSelectionChange,
42
+ readOnly,
43
+ selectedCellIds,
44
+ selectionMode,
45
+ sparseIndex.entries,
46
+ ]);
47
+ const handleKeyboardNavigation = React.useCallback((targetId, originId, shiftKey) => {
48
+ anchorId.current ??= originId;
49
+ if (!shiftKey)
50
+ return;
51
+ const cell = sparseIndex.cellById.get(targetId);
52
+ if (cell)
53
+ activateCell(getMatrixCellPlacement(layout, cell), { shiftKey: true });
54
+ }, [activateCell, layout, sparseIndex]);
55
+ const keyboard = useMatrixGridKeyboardFocus(sparseIndex, interactionPolicy === 'passive', visibleIds, handleKeyboardNavigation);
56
+ const focusedPlacement = React.useMemo(() => {
57
+ const focusedCell = keyboard.focusedId === null ? undefined : sparseIndex.cellById.get(keyboard.focusedId);
58
+ return focusedCell ? getMatrixCellPlacement(layout, focusedCell) : undefined;
59
+ }, [keyboard.focusedId, layout, sparseIndex.cellById]);
60
+ const gridItems = React.useMemo(() => focusedPlacement && !cellPlacements.some((cell) => cell.id === focusedPlacement.id)
61
+ ? [...cellPlacements, focusedPlacement]
62
+ : cellPlacements, [cellPlacements, focusedPlacement]);
63
+ const cellById = React.useMemo(() => new Map(gridItems.map((cell) => [cell.id, cell])), [gridItems]);
31
64
  return (<View accessibilityLabel={accessibilityLabel}>
32
- <GridView contentHeight={contentSize.height} contentWidth={contentSize.width} height={height} interactionPolicy={interactionPolicy} items={visibleCells} overscanPixels={0} renderItem={(item) => {
33
- const cell = visibleCellById.get(item.id);
65
+ <GridView contentHeight={contentSize.height} contentWidth={contentSize.width} height={height} interactionPolicy={interactionPolicy} items={gridItems} focusedItemId={keyboard.focusedId ?? undefined} overscanPixels={0} onVisibleItemIdsChange={setVisibleIds} renderItem={(item) => {
66
+ const cell = cellById.get(item.id);
34
67
  if (!cell)
35
68
  return null;
36
- return renderMatrixCell(cell, selectedCellIds, theme.semantics.neutral.divider, theme.colors.primary, renderCell, activateCell, testID);
69
+ return renderMatrixCell(cell, selectedCellIds, theme.semantics.neutral.divider, theme.colors.primary, renderCell, activateCell, keyboard, interactionPolicy === 'passive', readOnly, testID);
37
70
  }} testID={testID} viewport={viewport} width={width} onViewportChange={handleViewportChange}/>
38
71
  </View>);
39
72
  }
40
73
  /*** Render one positioned sparse cell with native/web accessible selection semantics. */
41
- function renderMatrixCell(cell, selectedCellIds, dividerColor, selectedColor, renderCell, activateCell, testID) {
74
+ function renderMatrixCell(cell, selectedCellIds, dividerColor, selectedColor, renderCell, activateCell, keyboard, passive, readOnly, testID) {
42
75
  const selected = selectedCellIds.includes(cell.id);
43
- return (<Pressable key={cell.id} accessibilityLabel={`Cell ${cell.id}`} accessibilityRole="button" accessibilityState={{ selected }} style={[
76
+ const canInteract = keyboard.tabStopId === cell.id;
77
+ return (<MatrixGridKeyboardProxy onKeyDown={(event) => {
78
+ if (keyboard.onKeyDown(cell.id, event.key, event.shiftKey))
79
+ return true;
80
+ if (!['Enter', ' '].includes(event.key))
81
+ return false;
82
+ if (passive || readOnly)
83
+ return false;
84
+ activateCell(cell, event);
85
+ return true;
86
+ }}>
87
+ <NativePressable key={cell.id} accessibilityActions={[{ name: 'activate' }]} accessibilityLabel={`Cell ${cell.id}`} accessibilityRole="button" accessibilityState={{ disabled: passive, selected }} disabled={passive} focusable={Platform.OS !== 'web' || canInteract} style={[
44
88
  styles.cell,
45
89
  {
46
- borderColor: selected ? selectedColor : dividerColor,
90
+ borderColor: selected || keyboard.focusedId === cell.id ? selectedColor : dividerColor,
47
91
  height: '100%',
48
92
  width: '100%',
49
93
  },
50
- ]} testID={testID === undefined ? undefined : `${testID}-cell-${cell.id}`} onPress={(event) => activateCell(cell, event)}>
51
- {renderCell(cell)}
52
- </Pressable>);
94
+ ]} testID={testID === undefined ? undefined : `${testID}-cell-${cell.id}`} onAccessibilityAction={() => activateCell(cell, {})} onFocus={() => keyboard.onFocus(cell.id)} onPress={(event) => activateCell(cell, event)} ref={(node) => keyboard.registerCell(cell.id, node)}>
95
+ {renderCell(cell)}
96
+ </NativePressable>
97
+ </MatrixGridKeyboardProxy>);
98
+ }
99
+ /*** Recognize range intent without changing the shared replace-or-toggle selection contract. */
100
+ function isRangeSelectionEvent(event) {
101
+ if (!isRecord(event))
102
+ return false;
103
+ if (event.shiftKey === true)
104
+ return true;
105
+ return ((isRecord(event.nativeEvent) && event.nativeEvent.shiftKey === true) ||
106
+ (isRecord(event.originalEvent) && event.originalEvent.shiftKey === true));
53
107
  }
54
108
  const styles = StyleSheet.create({
55
109
  cell: { borderWidth: 1, height: '100%', overflow: 'hidden', width: '100%' },
@@ -1 +1 @@
1
- {"version":3,"file":"MatrixGrid.js","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getVisibleMatrixCells,\n type GridMatrixCellPlacement,\n type GridViewport,\n} from '@ankhorage/grid-view';\nimport { Pressable } from '@ankhorage/surface';\nimport React from 'react';\nimport { StyleSheet, View } from 'react-native';\n\nimport type { MatrixGridProps } from '../../../../types/matrix-grid';\nimport { GridView } from '../../../grid-view/public';\nimport { resolveSelectionEventIntent } from '../../../selection/public';\nimport { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';\nimport { useZoraTheme } from '../../../theme/composition/useZoraTheme';\nimport { resolveMatrixGridContentSize } from '../../application/resolveMatrixGridContentSize';\nimport { resolveMatrixGridSelection } from '../../application/resolveMatrixGridSelection';\n\n/*** Compose the canonical GridView around released sparse matrix placement and culling geometry. */\nfunction MatrixGridInner({\n accessibilityLabel = 'Matrix grid',\n cells,\n height,\n interactionPolicy,\n layout,\n onSelectionChange,\n onViewportChange,\n overscanPixels = 160,\n renderCell,\n selectedCellIds = [],\n selectionMode = 'single',\n testID,\n viewport: controlledViewport,\n width,\n zoomX = 1,\n zoomY = 1,\n}: MatrixGridProps) {\n const { theme } = useZoraTheme();\n const contentSize = React.useMemo(() => resolveMatrixGridContentSize(layout), [layout]);\n const initialViewport = React.useMemo<GridViewport>(\n () => ({ height, offsetX: 0, offsetY: 0, pixelsPerUnitX: zoomX, pixelsPerUnitY: zoomY, width }),\n [height, width, zoomX, zoomY],\n );\n const [uncontrolledViewport, setUncontrolledViewport] = React.useState(initialViewport);\n const viewport = controlledViewport ?? uncontrolledViewport;\n const visibleCells = React.useMemo(\n () => getVisibleMatrixCells(layout, cells, viewport, overscanPixels),\n [cells, layout, overscanPixels, viewport],\n );\n\n const visibleCellById = React.useMemo(\n () => new Map(visibleCells.map((cell) => [cell.id, cell])),\n [visibleCells],\n );\n\n const handleViewportChange = React.useCallback(\n (proposal: GridViewport) => {\n if (controlledViewport === undefined) setUncontrolledViewport(proposal);\n onViewportChange?.(proposal);\n },\n [controlledViewport, onViewportChange],\n );\n\n const activateCell = React.useCallback(\n (cell: GridMatrixCellPlacement, event: unknown) => {\n if (interactionPolicy === 'passive') return;\n const intent = resolveSelectionEventIntent(event, 'pointer');\n onSelectionChange?.(\n resolveMatrixGridSelection(selectedCellIds, cell.id, intent, selectionMode),\n );\n },\n [interactionPolicy, onSelectionChange, selectedCellIds, selectionMode],\n );\n return (\n <View accessibilityLabel={accessibilityLabel}>\n <GridView\n contentHeight={contentSize.height}\n contentWidth={contentSize.width}\n height={height}\n interactionPolicy={interactionPolicy}\n items={visibleCells}\n overscanPixels={0}\n renderItem={(item) => {\n const cell = visibleCellById.get(item.id);\n if (!cell) return null;\n return renderMatrixCell(\n cell,\n selectedCellIds,\n theme.semantics.neutral.divider,\n theme.colors.primary,\n renderCell,\n activateCell,\n testID,\n );\n }}\n testID={testID}\n viewport={viewport}\n width={width}\n onViewportChange={handleViewportChange}\n />\n </View>\n );\n}\n\n/*** Render one positioned sparse cell with native/web accessible selection semantics. */\nfunction renderMatrixCell(\n cell: GridMatrixCellPlacement,\n selectedCellIds: readonly string[],\n dividerColor: string,\n selectedColor: string,\n renderCell: MatrixGridProps['renderCell'],\n activateCell: (cell: GridMatrixCellPlacement, event: unknown) => void,\n testID: string | undefined,\n) {\n const selected = selectedCellIds.includes(cell.id);\n return (\n <Pressable\n key={cell.id}\n accessibilityLabel={`Cell ${cell.id}`}\n accessibilityRole=\"button\"\n accessibilityState={{ selected }}\n style={[\n styles.cell,\n {\n borderColor: selected ? selectedColor : dividerColor,\n height: '100%',\n width: '100%',\n },\n ]}\n testID={testID === undefined ? undefined : `${testID}-cell-${cell.id}`}\n onPress={(event) => activateCell(cell, event)}\n >\n {renderCell(cell)}\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n cell: { borderWidth: 1, height: '100%', overflow: 'hidden', width: '100%' },\n});\n\n/*** A code-first generic sparse matrix grid; formulas and domain vocabulary remain external. */\nexport const MatrixGrid = withZoraThemeScope(MatrixGridInner);\n"]}
1
+ {"version":3,"file":"MatrixGrid.js","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n getMatrixCellPlacement,\n getVisibleMatrixCells,\n type GridMatrixCellPlacement,\n type GridViewport,\n} from '@ankhorage/grid-view';\nimport { isRecord } from '@ankhorage/utility/object';\nimport React from 'react';\nimport { Platform, Pressable as NativePressable, StyleSheet, View } from 'react-native';\n\nimport type { MatrixGridProps } from '../../../../types/matrix-grid';\nimport { GridView } from '../../../grid-view/public';\nimport { resolveSelectionEventIntent } from '../../../selection/public';\nimport { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';\nimport { useZoraTheme } from '../../../theme/composition/useZoraTheme';\nimport { createMatrixGridSparseIndex } from '../../application/createMatrixGridSparseIndex';\nimport { resolveMatrixGridContentSize } from '../../application/resolveMatrixGridContentSize';\nimport { resolveMatrixGridSelection } from '../../application/resolveMatrixGridSelection';\nimport { MatrixGridKeyboardProxy } from './MatrixGridKeyboardProxy';\nimport { useMatrixGridKeyboardFocus } from './useMatrixGridKeyboardFocus';\n\n/*** Compose the canonical GridView around released sparse matrix placement and culling geometry. */\nfunction MatrixGridInner({\n accessibilityLabel = 'Matrix grid',\n cells,\n height,\n interactionPolicy,\n layout,\n onSelectionChange,\n onViewportChange,\n overscanPixels = 160,\n readOnly = false,\n renderCell,\n selectedCellIds = [],\n selectionMode = 'single',\n testID,\n viewport: controlledViewport,\n width,\n zoomX = 1,\n zoomY = 1,\n}: MatrixGridProps) {\n const { theme } = useZoraTheme();\n const contentSize = React.useMemo(() => resolveMatrixGridContentSize(layout), [layout]);\n const initialViewport = React.useMemo<GridViewport>(\n () => ({ height, offsetX: 0, offsetY: 0, pixelsPerUnitX: zoomX, pixelsPerUnitY: zoomY, width }),\n [height, width, zoomX, zoomY],\n );\n const [uncontrolledViewport, setUncontrolledViewport] = React.useState(initialViewport);\n const viewport = controlledViewport ?? uncontrolledViewport;\n const sparseIndex = React.useMemo(\n () => createMatrixGridSparseIndex(layout, cells),\n [cells, layout],\n );\n const cellPlacements = React.useMemo(\n () => getVisibleMatrixCells(layout, cells, viewport, overscanPixels),\n [cells, layout, overscanPixels, viewport],\n );\n const [visibleIds, setVisibleIds] = React.useState<readonly string[]>([]);\n const anchorId = React.useRef<string | null>(null);\n\n const handleViewportChange = React.useCallback(\n (proposal: GridViewport) => {\n if (controlledViewport === undefined) setUncontrolledViewport(proposal);\n onViewportChange?.(proposal);\n },\n [controlledViewport, onViewportChange],\n );\n\n const activateCell = React.useCallback(\n (cell: GridMatrixCellPlacement, event: unknown) => {\n if (interactionPolicy === 'passive' || readOnly) return;\n const intent = isRangeSelectionEvent(event)\n ? 'range'\n : resolveSelectionEventIntent(event, 'pointer');\n onSelectionChange?.(\n resolveMatrixGridSelection(\n sparseIndex.entries,\n selectedCellIds,\n cell.id,\n anchorId.current,\n intent,\n selectionMode,\n ),\n );\n if (intent !== 'range') anchorId.current = cell.id;\n },\n [\n interactionPolicy,\n onSelectionChange,\n readOnly,\n selectedCellIds,\n selectionMode,\n sparseIndex.entries,\n ],\n );\n const handleKeyboardNavigation = React.useCallback(\n (targetId: string, originId: string, shiftKey: boolean) => {\n anchorId.current ??= originId;\n if (!shiftKey) return;\n const cell = sparseIndex.cellById.get(targetId);\n if (cell) activateCell(getMatrixCellPlacement(layout, cell), { shiftKey: true });\n },\n [activateCell, layout, sparseIndex],\n );\n const keyboard = useMatrixGridKeyboardFocus(\n sparseIndex,\n interactionPolicy === 'passive',\n visibleIds,\n handleKeyboardNavigation,\n );\n const focusedPlacement = React.useMemo(() => {\n const focusedCell =\n keyboard.focusedId === null ? undefined : sparseIndex.cellById.get(keyboard.focusedId);\n return focusedCell ? getMatrixCellPlacement(layout, focusedCell) : undefined;\n }, [keyboard.focusedId, layout, sparseIndex.cellById]);\n const gridItems = React.useMemo(\n () =>\n focusedPlacement && !cellPlacements.some((cell) => cell.id === focusedPlacement.id)\n ? [...cellPlacements, focusedPlacement]\n : cellPlacements,\n [cellPlacements, focusedPlacement],\n );\n const cellById = React.useMemo(\n () => new Map(gridItems.map((cell) => [cell.id, cell])),\n [gridItems],\n );\n\n return (\n <View accessibilityLabel={accessibilityLabel}>\n <GridView\n contentHeight={contentSize.height}\n contentWidth={contentSize.width}\n height={height}\n interactionPolicy={interactionPolicy}\n items={gridItems}\n focusedItemId={keyboard.focusedId ?? undefined}\n overscanPixels={0}\n onVisibleItemIdsChange={setVisibleIds}\n renderItem={(item) => {\n const cell = cellById.get(item.id);\n if (!cell) return null;\n return renderMatrixCell(\n cell,\n selectedCellIds,\n theme.semantics.neutral.divider,\n theme.colors.primary,\n renderCell,\n activateCell,\n keyboard,\n interactionPolicy === 'passive',\n readOnly,\n testID,\n );\n }}\n testID={testID}\n viewport={viewport}\n width={width}\n onViewportChange={handleViewportChange}\n />\n </View>\n );\n}\n\n/*** Render one positioned sparse cell with native/web accessible selection semantics. */\nfunction renderMatrixCell(\n cell: GridMatrixCellPlacement,\n selectedCellIds: readonly string[],\n dividerColor: string,\n selectedColor: string,\n renderCell: MatrixGridProps['renderCell'],\n activateCell: (cell: GridMatrixCellPlacement, event: unknown) => void,\n keyboard: ReturnType<typeof useMatrixGridKeyboardFocus>,\n passive: boolean,\n readOnly: boolean,\n testID: string | undefined,\n) {\n const selected = selectedCellIds.includes(cell.id);\n const canInteract = keyboard.tabStopId === cell.id;\n return (\n <MatrixGridKeyboardProxy\n onKeyDown={(event) => {\n if (keyboard.onKeyDown(cell.id, event.key, event.shiftKey)) return true;\n if (!['Enter', ' '].includes(event.key)) return false;\n if (passive || readOnly) return false;\n activateCell(cell, event);\n return true;\n }}\n >\n <NativePressable\n key={cell.id}\n accessibilityActions={[{ name: 'activate' }]}\n accessibilityLabel={`Cell ${cell.id}`}\n accessibilityRole=\"button\"\n accessibilityState={{ disabled: passive, selected }}\n disabled={passive}\n focusable={Platform.OS !== 'web' || canInteract}\n style={[\n styles.cell,\n {\n borderColor: selected || keyboard.focusedId === cell.id ? selectedColor : dividerColor,\n height: '100%',\n width: '100%',\n },\n ]}\n testID={testID === undefined ? undefined : `${testID}-cell-${cell.id}`}\n onAccessibilityAction={() => activateCell(cell, {})}\n onFocus={() => keyboard.onFocus(cell.id)}\n onPress={(event) => activateCell(cell, event)}\n ref={(node) => keyboard.registerCell(cell.id, node)}\n >\n {renderCell(cell)}\n </NativePressable>\n </MatrixGridKeyboardProxy>\n );\n}\n\n/*** Recognize range intent without changing the shared replace-or-toggle selection contract. */\nfunction isRangeSelectionEvent(event: unknown): boolean {\n if (!isRecord(event)) return false;\n if (event.shiftKey === true) return true;\n return (\n (isRecord(event.nativeEvent) && event.nativeEvent.shiftKey === true) ||\n (isRecord(event.originalEvent) && event.originalEvent.shiftKey === true)\n );\n}\n\nconst styles = StyleSheet.create({\n cell: { borderWidth: 1, height: '100%', overflow: 'hidden', width: '100%' },\n});\n\n/*** A code-first generic sparse matrix grid; formulas and domain vocabulary remain external. */\nexport const MatrixGrid = withZoraThemeScope(MatrixGridInner);\n"]}
@@ -0,0 +1,9 @@
1
+ import type React from 'react';
2
+ /*** Provides the native fallback type surface; RNW resolves the web adapter at runtime. */
3
+ export declare function MatrixGridKeyboardProxy({ children }: MatrixGridKeyboardProxyProps): React.JSX.Element;
4
+ interface MatrixGridKeyboardProxyProps {
5
+ readonly children: React.ReactNode;
6
+ readonly onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => boolean;
7
+ }
8
+ export {};
9
+ //# sourceMappingURL=MatrixGridKeyboardProxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixGridKeyboardProxy.d.ts","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,2FAA2F;AAC3F,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,EAAE,4BAA4B,qBAEjF;AAED,UAAU,4BAA4B;IACpC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,KAAK,OAAO,CAAC;CAC7E"}
@@ -0,0 +1,5 @@
1
+ /*** Provides the native fallback type surface; RNW resolves the web adapter at runtime. */
2
+ export function MatrixGridKeyboardProxy({ children }) {
3
+ return <>{children}</>;
4
+ }
5
+ //# sourceMappingURL=MatrixGridKeyboardProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixGridKeyboardProxy.js","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.tsx"],"names":[],"mappings":"AAEA,2FAA2F;AAC3F,MAAM,UAAU,uBAAuB,CAAC,EAAE,QAAQ,EAAgC;IAChF,OAAO,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC;AACzB,CAAC","sourcesContent":["import type React from 'react';\n\n/*** Provides the native fallback type surface; RNW resolves the web adapter at runtime. */\nexport function MatrixGridKeyboardProxy({ children }: MatrixGridKeyboardProxyProps) {\n return <>{children}</>;\n}\n\ninterface MatrixGridKeyboardProxyProps {\n readonly children: React.ReactNode;\n readonly onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => boolean;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type React from 'react';
2
+ /*** Retain native accessibility focus while physical-key dispatch remains a web host concern. */
3
+ export declare function MatrixGridKeyboardProxy({ children }: MatrixGridKeyboardProxyProps): React.JSX.Element;
4
+ interface MatrixGridKeyboardProxyProps {
5
+ readonly children: React.ReactNode;
6
+ readonly onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => boolean;
7
+ }
8
+ export {};
9
+ //# sourceMappingURL=MatrixGridKeyboardProxy.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixGridKeyboardProxy.native.d.ts","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,iGAAiG;AACjG,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,EAAE,4BAA4B,qBAEjF;AAED,UAAU,4BAA4B;IACpC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,KAAK,OAAO,CAAC;CAC7E"}
@@ -0,0 +1,5 @@
1
+ /*** Retain native accessibility focus while physical-key dispatch remains a web host concern. */
2
+ export function MatrixGridKeyboardProxy({ children }) {
3
+ return <>{children}</>;
4
+ }
5
+ //# sourceMappingURL=MatrixGridKeyboardProxy.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixGridKeyboardProxy.native.js","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.native.tsx"],"names":[],"mappings":"AAEA,iGAAiG;AACjG,MAAM,UAAU,uBAAuB,CAAC,EAAE,QAAQ,EAAgC;IAChF,OAAO,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC;AACzB,CAAC","sourcesContent":["import type React from 'react';\n\n/*** Retain native accessibility focus while physical-key dispatch remains a web host concern. */\nexport function MatrixGridKeyboardProxy({ children }: MatrixGridKeyboardProxyProps) {\n return <>{children}</>;\n}\n\ninterface MatrixGridKeyboardProxyProps {\n readonly children: React.ReactNode;\n readonly onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => boolean;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type React from 'react';
2
+ /*** Bridge browser keyboard events into the matrix's platform-neutral focus policy. */
3
+ export declare function MatrixGridKeyboardProxy({ children, onKeyDown }: MatrixGridKeyboardProxyProps): React.JSX.Element;
4
+ interface MatrixGridKeyboardProxyProps {
5
+ readonly children: React.ReactNode;
6
+ readonly onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => boolean;
7
+ }
8
+ export {};
9
+ //# sourceMappingURL=MatrixGridKeyboardProxy.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixGridKeyboardProxy.web.d.ts","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,uFAAuF;AACvF,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,4BAA4B,qBAY5F;AAwBD,UAAU,4BAA4B;IACpC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,cAAc,CAAC,KAAK,OAAO,CAAC;CAC7E"}
@@ -0,0 +1,28 @@
1
+ /*** Bridge browser keyboard events into the matrix's platform-neutral focus policy. */
2
+ export function MatrixGridKeyboardProxy({ children, onKeyDown }) {
3
+ return (<div onKeyDownCapture={(event) => {
4
+ if (isNestedInteractiveElement(event.target, event.currentTarget))
5
+ return;
6
+ if (onKeyDown(event))
7
+ event.preventDefault();
8
+ }} style={{ display: 'flex', flex: 1 }}>
9
+ {children}
10
+ </div>);
11
+ }
12
+ /*** Leave editable and independently interactive cell content in control of its own keyboard events. */
13
+ function isNestedInteractiveElement(target, boundary) {
14
+ if (target === boundary || !hasClosest(target))
15
+ return false;
16
+ const interactiveElement = target.closest(interactiveSelector);
17
+ return interactiveElement !== null && interactiveElement !== getFirstElementChild(boundary);
18
+ }
19
+ /*** Recognize the browser-only closest capability without leaking DOM globals into shared code. */
20
+ function hasClosest(target) {
21
+ return 'closest' in target && typeof target.closest === 'function';
22
+ }
23
+ /*** Exempt the cell's own Pressable while preserving keyboard ownership for nested controls. */
24
+ function getFirstElementChild(boundary) {
25
+ return 'firstElementChild' in boundary ? boundary.firstElementChild : undefined;
26
+ }
27
+ const interactiveSelector = 'a, button, input, select, textarea, [contenteditable="true"], [role="button"], [role="checkbox"], [role="combobox"], [role="link"], [role="menuitem"], [role="option"], [role="slider"], [role="spinbutton"], [role="switch"], [role="tab"]';
28
+ //# sourceMappingURL=MatrixGridKeyboardProxy.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MatrixGridKeyboardProxy.web.js","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/MatrixGridKeyboardProxy.web.tsx"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,MAAM,UAAU,uBAAuB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAgC;IAC3F,OAAO,CACL,CAAC,GAAG,CACF,gBAAgB,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,0BAA0B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC;gBAAE,OAAO;YAC1E,IAAI,SAAS,CAAC,KAAK,CAAC;gBAAE,KAAK,CAAC,cAAc,EAAE,CAAC;QAC/C,CAAC,CAAC,CACF,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAEpC;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC;AAED,wGAAwG;AACxG,SAAS,0BAA0B,CAAC,MAAmB,EAAE,QAAqB;IAC5E,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7D,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC/D,OAAO,kBAAkB,KAAK,IAAI,IAAI,kBAAkB,KAAK,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AAC9F,CAAC;AAED,mGAAmG;AACnG,SAAS,UAAU,CACjB,MAAmB;IAEnB,OAAO,SAAS,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,UAAU,CAAC;AACrE,CAAC;AAED,gGAAgG;AAChG,SAAS,oBAAoB,CAAC,QAAqB;IACjD,OAAO,mBAAmB,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC;AAClF,CAAC;AAED,MAAM,mBAAmB,GACvB,6OAA6O,CAAC","sourcesContent":["import type React from 'react';\n\n/*** Bridge browser keyboard events into the matrix's platform-neutral focus policy. */\nexport function MatrixGridKeyboardProxy({ children, onKeyDown }: MatrixGridKeyboardProxyProps) {\n return (\n <div\n onKeyDownCapture={(event) => {\n if (isNestedInteractiveElement(event.target, event.currentTarget)) return;\n if (onKeyDown(event)) event.preventDefault();\n }}\n style={{ display: 'flex', flex: 1 }}\n >\n {children}\n </div>\n );\n}\n\n/*** Leave editable and independently interactive cell content in control of its own keyboard events. */\nfunction isNestedInteractiveElement(target: EventTarget, boundary: EventTarget): boolean {\n if (target === boundary || !hasClosest(target)) return false;\n const interactiveElement = target.closest(interactiveSelector);\n return interactiveElement !== null && interactiveElement !== getFirstElementChild(boundary);\n}\n\n/*** Recognize the browser-only closest capability without leaking DOM globals into shared code. */\nfunction hasClosest(\n target: EventTarget,\n): target is EventTarget & { closest: (selector: string) => unknown } {\n return 'closest' in target && typeof target.closest === 'function';\n}\n\n/*** Exempt the cell's own Pressable while preserving keyboard ownership for nested controls. */\nfunction getFirstElementChild(boundary: EventTarget): unknown {\n return 'firstElementChild' in boundary ? boundary.firstElementChild : undefined;\n}\n\nconst interactiveSelector =\n 'a, button, input, select, textarea, [contenteditable=\"true\"], [role=\"button\"], [role=\"checkbox\"], [role=\"combobox\"], [role=\"link\"], [role=\"menuitem\"], [role=\"option\"], [role=\"slider\"], [role=\"spinbutton\"], [role=\"switch\"], [role=\"tab\"]';\n\ninterface MatrixGridKeyboardProxyProps {\n readonly children: React.ReactNode;\n readonly onKeyDown: (event: React.KeyboardEvent<HTMLDivElement>) => boolean;\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { MatrixGridSparseIndex } from '../../application/createMatrixGridSparseIndex';
2
+ /*** Keep one roving focus target and restore it after GridView virtualizes a sparse cell. */
3
+ export declare function useMatrixGridKeyboardFocus(index: MatrixGridSparseIndex, disabled: boolean, visibleIds: readonly string[], onNavigate: (targetId: string, originId: string, shiftKey: boolean) => void): {
4
+ focusedId: string | null;
5
+ onFocus: (id: string) => void;
6
+ onKeyDown: (id: string, key: string, shiftKey: boolean) => boolean;
7
+ registerCell: (id: string, node: FocusableCell | null) => void;
8
+ tabStopId: string | undefined;
9
+ };
10
+ interface FocusableCell {
11
+ focus: () => void;
12
+ }
13
+ export {};
14
+ //# sourceMappingURL=useMatrixGridKeyboardFocus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMatrixGridKeyboardFocus.d.ts","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAG3F,6FAA6F;AAC7F,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,qBAAqB,EAC5B,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI;;kBAYpC,MAAM;oBAmBtC,MAAM,OAAO,MAAM,YAAY,OAAO,KAAG,OAAO;uBAbX,MAAM,QAAQ,aAAa,GAAG,IAAI;;EAqC/E;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB"}
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import { getMatrixGridNextFocusId } from '../../application/getMatrixGridNextFocusId';
3
+ /*** Keep one roving focus target and restore it after GridView virtualizes a sparse cell. */
4
+ export function useMatrixGridKeyboardFocus(index, disabled, visibleIds, onNavigate) {
5
+ const [focusedId, setFocusedId] = React.useState(null);
6
+ const focusedRef = React.useRef(null);
7
+ const pendingFocusRef = React.useRef(null);
8
+ const cellRefs = React.useRef(new Map());
9
+ const visibleIdSet = React.useMemo(() => new Set(visibleIds), [visibleIds]);
10
+ const tabStopId = focusedId !== null && visibleIdSet.has(focusedId)
11
+ ? focusedId
12
+ : visibleIds.find((id) => index.positionById.has(id));
13
+ const onFocus = React.useCallback((id) => {
14
+ pendingFocusRef.current = null;
15
+ focusedRef.current = id;
16
+ setFocusedId(id);
17
+ }, []);
18
+ const registerCell = React.useCallback((id, node) => {
19
+ if (node === null) {
20
+ cellRefs.current.delete(id);
21
+ return;
22
+ }
23
+ cellRefs.current.set(id, node);
24
+ if (pendingFocusRef.current === id) {
25
+ pendingFocusRef.current = null;
26
+ node.focus();
27
+ }
28
+ }, []);
29
+ const onKeyDown = React.useCallback((id, key, shiftKey) => {
30
+ if (disabled || !['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(key)) {
31
+ return false;
32
+ }
33
+ const originId = focusedRef.current ?? id;
34
+ const nextId = getMatrixGridNextFocusId(index, originId, key);
35
+ if (nextId === null || nextId === originId)
36
+ return true;
37
+ focusedRef.current = nextId;
38
+ pendingFocusRef.current = nextId;
39
+ setFocusedId(nextId);
40
+ onNavigate(nextId, originId, shiftKey);
41
+ const mounted = cellRefs.current.get(nextId);
42
+ if (mounted) {
43
+ pendingFocusRef.current = null;
44
+ mounted.focus();
45
+ }
46
+ return true;
47
+ }, [disabled, index, onNavigate]);
48
+ return { focusedId, onFocus, onKeyDown, registerCell, tabStopId };
49
+ }
50
+ //# sourceMappingURL=useMatrixGridKeyboardFocus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMatrixGridKeyboardFocus.js","sourceRoot":"","sources":["../../../../../src/features/matrix-grid/adapters/inbound/useMatrixGridKeyboardFocus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAEtF,6FAA6F;AAC7F,MAAM,UAAU,0BAA0B,CACxC,KAA4B,EAC5B,QAAiB,EACjB,UAA6B,EAC7B,UAA2E;IAE3E,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAgB,IAAI,CAAC,CAAC;IACrD,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,GAAG,EAAyB,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5E,MAAM,SAAS,GACb,SAAS,KAAK,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC;QAC/C,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QAC/C,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC;QAC/B,UAAU,CAAC,OAAO,GAAG,EAAE,CAAC;QACxB,YAAY,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,EAAU,EAAE,IAA0B,EAAE,EAAE;QAChF,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,eAAe,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;YACnC,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC;YAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CACjC,CAAC,EAAU,EAAE,GAAW,EAAE,QAAiB,EAAW,EAAE;QACtD,IAAI,QAAQ,IAAI,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACnF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,wBAAwB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC9D,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAExD,UAAU,CAAC,OAAO,GAAG,MAAM,CAAC;QAC5B,eAAe,CAAC,OAAO,GAAG,MAAM,CAAC;QACjC,YAAY,CAAC,MAAM,CAAC,CAAC;QACrB,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,OAAO,EAAE,CAAC;YACZ,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC;YAC/B,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,EACD,CAAC,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,CAC9B,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACpE,CAAC","sourcesContent":["import React from 'react';\n\nimport type { MatrixGridSparseIndex } from '../../application/createMatrixGridSparseIndex';\nimport { getMatrixGridNextFocusId } from '../../application/getMatrixGridNextFocusId';\n\n/*** Keep one roving focus target and restore it after GridView virtualizes a sparse cell. */\nexport function useMatrixGridKeyboardFocus(\n index: MatrixGridSparseIndex,\n disabled: boolean,\n visibleIds: readonly string[],\n onNavigate: (targetId: string, originId: string, shiftKey: boolean) => void,\n) {\n const [focusedId, setFocusedId] = React.useState<string | null>(null);\n const focusedRef = React.useRef<string | null>(null);\n const pendingFocusRef = React.useRef<string | null>(null);\n const cellRefs = React.useRef(new Map<string, FocusableCell>());\n const visibleIdSet = React.useMemo(() => new Set(visibleIds), [visibleIds]);\n const tabStopId =\n focusedId !== null && visibleIdSet.has(focusedId)\n ? focusedId\n : visibleIds.find((id) => index.positionById.has(id));\n\n const onFocus = React.useCallback((id: string) => {\n pendingFocusRef.current = null;\n focusedRef.current = id;\n setFocusedId(id);\n }, []);\n\n const registerCell = React.useCallback((id: string, node: FocusableCell | null) => {\n if (node === null) {\n cellRefs.current.delete(id);\n return;\n }\n cellRefs.current.set(id, node);\n if (pendingFocusRef.current === id) {\n pendingFocusRef.current = null;\n node.focus();\n }\n }, []);\n\n const onKeyDown = React.useCallback(\n (id: string, key: string, shiftKey: boolean): boolean => {\n if (disabled || !['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(key)) {\n return false;\n }\n const originId = focusedRef.current ?? id;\n const nextId = getMatrixGridNextFocusId(index, originId, key);\n if (nextId === null || nextId === originId) return true;\n\n focusedRef.current = nextId;\n pendingFocusRef.current = nextId;\n setFocusedId(nextId);\n onNavigate(nextId, originId, shiftKey);\n\n const mounted = cellRefs.current.get(nextId);\n if (mounted) {\n pendingFocusRef.current = null;\n mounted.focus();\n }\n return true;\n },\n [disabled, index, onNavigate],\n );\n\n return { focusedId, onFocus, onKeyDown, registerCell, tabStopId };\n}\n\ninterface FocusableCell {\n focus: () => void;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { GridMatrixCell, GridMatrixLayout } from '@ankhorage/grid-view';
2
+ /*** Build a geometry-independent lookup for sparse matrix navigation, selection, and focus recovery. */
3
+ export declare function createMatrixGridSparseIndex(layout: GridMatrixLayout, cells: readonly GridMatrixCell[]): MatrixGridSparseIndex;
4
+ export type MatrixGridSparseIndex = Readonly<{
5
+ cellById: ReadonlyMap<string, GridMatrixCell>;
6
+ entries: readonly MatrixGridSparseIndexEntry[];
7
+ entriesByColumn: ReadonlyMap<number, readonly MatrixGridSparseIndexEntry[]>;
8
+ entriesByRow: ReadonlyMap<number, readonly MatrixGridSparseIndexEntry[]>;
9
+ firstId: string | null;
10
+ positionById: ReadonlyMap<string, MatrixGridSparseIndexEntry>;
11
+ }>;
12
+ export type MatrixGridSparseIndexEntry = Readonly<{
13
+ cell: GridMatrixCell;
14
+ columnIndex: number;
15
+ id: string;
16
+ rowIndex: number;
17
+ }>;
18
+ //# sourceMappingURL=createMatrixGridSparseIndex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createMatrixGridSparseIndex.d.ts","sourceRoot":"","sources":["../../../../src/features/matrix-grid/application/createMatrixGridSparseIndex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,wGAAwG;AACxG,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,SAAS,cAAc,EAAE,GAC/B,qBAAqB,CAgBvB;AAoED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC9C,OAAO,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC/C,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,0BAA0B,EAAE,CAAC,CAAC;IAC5E,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,0BAA0B,EAAE,CAAC,CAAC;IACzE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC;CAC/D,CAAC,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC"}
@@ -0,0 +1,56 @@
1
+ /*** Build a geometry-independent lookup for sparse matrix navigation, selection, and focus recovery. */
2
+ export function createMatrixGridSparseIndex(layout, cells) {
3
+ const rowIndexes = new Map(layout.rows.map((row, index) => [row.id, index]));
4
+ const columnIndexes = new Map(layout.columns.map((column, index) => [column.id, index]));
5
+ const entries = cells.map((cell) => createSparseEntry(cell, rowIndexes, columnIndexes));
6
+ const entriesByRow = groupEntries(entries, 'columnIndex');
7
+ const entriesByColumn = groupEntries(entries, 'rowIndex');
8
+ const orderedEntries = [...entries].sort(compareRowThenColumn);
9
+ return {
10
+ cellById: new Map(entries.map((entry) => [entry.id, entry.cell])),
11
+ entries,
12
+ entriesByColumn,
13
+ entriesByRow,
14
+ firstId: orderedEntries.at(0)?.id ?? null,
15
+ positionById: new Map(entries.map((entry) => [entry.id, entry])),
16
+ };
17
+ }
18
+ /*** Resolve validated matrix coordinates once without materializing every cell rectangle. */
19
+ function createSparseEntry(cell, rowIndexes, columnIndexes) {
20
+ const rowIndex = rowIndexes.get(cell.rowId);
21
+ const columnIndex = columnIndexes.get(cell.columnId);
22
+ if (rowIndex === undefined || columnIndex === undefined) {
23
+ throw new Error(`Matrix cell ${cell.id} references an unknown row or column.`);
24
+ }
25
+ return { cell, columnIndex, id: cell.id, rowIndex };
26
+ }
27
+ /*** Group and sort directional neighbours so arrow navigation is logarithmic within one axis. */
28
+ function groupEntries(entries, axis) {
29
+ const groups = new Map();
30
+ for (const entry of entries) {
31
+ const groupKey = axis === 'columnIndex' ? entry.rowIndex : entry.columnIndex;
32
+ const group = groups.get(groupKey) ?? [];
33
+ group.push(entry);
34
+ groups.set(groupKey, group);
35
+ }
36
+ return new Map([...groups].map(([key, group]) => [
37
+ key,
38
+ group.sort((left, right) => compareAxisThenId(left, right, axis)),
39
+ ]));
40
+ }
41
+ /*** Keep the initial roving target deterministic even when sparse input arrives in arbitrary order. */
42
+ function compareRowThenColumn(left, right) {
43
+ return (left.rowIndex - right.rowIndex ||
44
+ left.columnIndex - right.columnIndex ||
45
+ left.id.localeCompare(right.id));
46
+ }
47
+ /*** Sort a row or column by its navigated coordinate and stable identity. */
48
+ function compareAxisThenId(left, right, axis) {
49
+ return (getAxisCoordinate(left, axis) - getAxisCoordinate(right, axis) ||
50
+ left.id.localeCompare(right.id));
51
+ }
52
+ /*** Read a selected coordinate without dynamically indexing an object. */
53
+ function getAxisCoordinate(entry, axis) {
54
+ return axis === 'columnIndex' ? entry.columnIndex : entry.rowIndex;
55
+ }
56
+ //# sourceMappingURL=createMatrixGridSparseIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createMatrixGridSparseIndex.js","sourceRoot":"","sources":["../../../../src/features/matrix-grid/application/createMatrixGridSparseIndex.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GridMatrixCell, GridMatrixLayout } from '@ankhorage/grid-view';\n\n/*** Build a geometry-independent lookup for sparse matrix navigation, selection, and focus recovery. */\nexport function createMatrixGridSparseIndex(\n layout: GridMatrixLayout,\n cells: readonly GridMatrixCell[],\n): MatrixGridSparseIndex {\n const rowIndexes = new Map(layout.rows.map((row, index) => [row.id, index]));\n const columnIndexes = new Map(layout.columns.map((column, index) => [column.id, index]));\n const entries = cells.map((cell) => createSparseEntry(cell, rowIndexes, columnIndexes));\n const entriesByRow = groupEntries(entries, 'columnIndex');\n const entriesByColumn = groupEntries(entries, 'rowIndex');\n const orderedEntries = [...entries].sort(compareRowThenColumn);\n\n return {\n cellById: new Map(entries.map((entry) => [entry.id, entry.cell])),\n entries,\n entriesByColumn,\n entriesByRow,\n firstId: orderedEntries.at(0)?.id ?? null,\n positionById: new Map(entries.map((entry) => [entry.id, entry])),\n };\n}\n\n/*** Resolve validated matrix coordinates once without materializing every cell rectangle. */\nfunction createSparseEntry(\n cell: GridMatrixCell,\n rowIndexes: ReadonlyMap<string, number>,\n columnIndexes: ReadonlyMap<string, number>,\n): MatrixGridSparseIndexEntry {\n const rowIndex = rowIndexes.get(cell.rowId);\n const columnIndex = columnIndexes.get(cell.columnId);\n if (rowIndex === undefined || columnIndex === undefined) {\n throw new Error(`Matrix cell ${cell.id} references an unknown row or column.`);\n }\n return { cell, columnIndex, id: cell.id, rowIndex };\n}\n\n/*** Group and sort directional neighbours so arrow navigation is logarithmic within one axis. */\nfunction groupEntries(\n entries: readonly MatrixGridSparseIndexEntry[],\n axis: 'columnIndex' | 'rowIndex',\n): ReadonlyMap<number, readonly MatrixGridSparseIndexEntry[]> {\n const groups = new Map<number, MatrixGridSparseIndexEntry[]>();\n for (const entry of entries) {\n const groupKey = axis === 'columnIndex' ? entry.rowIndex : entry.columnIndex;\n const group = groups.get(groupKey) ?? [];\n group.push(entry);\n groups.set(groupKey, group);\n }\n return new Map(\n [...groups].map(([key, group]) => [\n key,\n group.sort((left, right) => compareAxisThenId(left, right, axis)),\n ]),\n );\n}\n\n/*** Keep the initial roving target deterministic even when sparse input arrives in arbitrary order. */\nfunction compareRowThenColumn(\n left: MatrixGridSparseIndexEntry,\n right: MatrixGridSparseIndexEntry,\n): number {\n return (\n left.rowIndex - right.rowIndex ||\n left.columnIndex - right.columnIndex ||\n left.id.localeCompare(right.id)\n );\n}\n\n/*** Sort a row or column by its navigated coordinate and stable identity. */\nfunction compareAxisThenId(\n left: MatrixGridSparseIndexEntry,\n right: MatrixGridSparseIndexEntry,\n axis: 'columnIndex' | 'rowIndex',\n): number {\n return (\n getAxisCoordinate(left, axis) - getAxisCoordinate(right, axis) ||\n left.id.localeCompare(right.id)\n );\n}\n\n/*** Read a selected coordinate without dynamically indexing an object. */\nfunction getAxisCoordinate(\n entry: MatrixGridSparseIndexEntry,\n axis: 'columnIndex' | 'rowIndex',\n): number {\n return axis === 'columnIndex' ? entry.columnIndex : entry.rowIndex;\n}\n\nexport type MatrixGridSparseIndex = Readonly<{\n cellById: ReadonlyMap<string, GridMatrixCell>;\n entries: readonly MatrixGridSparseIndexEntry[];\n entriesByColumn: ReadonlyMap<number, readonly MatrixGridSparseIndexEntry[]>;\n entriesByRow: ReadonlyMap<number, readonly MatrixGridSparseIndexEntry[]>;\n firstId: string | null;\n positionById: ReadonlyMap<string, MatrixGridSparseIndexEntry>;\n}>;\n\nexport type MatrixGridSparseIndexEntry = Readonly<{\n cell: GridMatrixCell;\n columnIndex: number;\n id: string;\n rowIndex: number;\n}>;\n"]}
@@ -0,0 +1,4 @@
1
+ import type { MatrixGridSparseIndex } from './createMatrixGridSparseIndex';
2
+ /*** Resolve arrow-key focus among existing sparse cells without inventing placeholder geometry. */
3
+ export declare function getMatrixGridNextFocusId(index: MatrixGridSparseIndex, currentId: string | null, key: string): string | null;
4
+ //# sourceMappingURL=getMatrixGridNextFocusId.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMatrixGridNextFocusId.d.ts","sourceRoot":"","sources":["../../../../src/features/matrix-grid/application/getMatrixGridNextFocusId.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,+BAA+B,CAAC;AAEvC,mGAAmG;AACnG,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,qBAAqB,EAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,IAAI,CAKf"}
@@ -0,0 +1,65 @@
1
+ /*** Resolve arrow-key focus among existing sparse cells without inventing placeholder geometry. */
2
+ export function getMatrixGridNextFocusId(index, currentId, key) {
3
+ const current = currentId === null ? undefined : index.positionById.get(currentId);
4
+ if (!current)
5
+ return index.firstId;
6
+ return resolveDirectionalCandidate(index, current, key)?.id ?? current.id;
7
+ }
8
+ /*** Find the closest existing sparse cell along the requested matrix axis. */
9
+ function resolveDirectionalCandidate(index, current, key) {
10
+ switch (key) {
11
+ case 'ArrowLeft':
12
+ return findDirectionalNeighbour(index.entriesByRow.get(current.rowIndex), current, 'columnIndex', -1);
13
+ case 'ArrowRight':
14
+ return findDirectionalNeighbour(index.entriesByRow.get(current.rowIndex), current, 'columnIndex', 1);
15
+ case 'ArrowUp':
16
+ return findDirectionalNeighbour(index.entriesByColumn.get(current.columnIndex), current, 'rowIndex', -1);
17
+ case 'ArrowDown':
18
+ return findDirectionalNeighbour(index.entriesByColumn.get(current.columnIndex), current, 'rowIndex', 1);
19
+ default:
20
+ return undefined;
21
+ }
22
+ }
23
+ /*** Read the nearest strictly directional neighbour from a pre-sorted sparse axis. */
24
+ function findDirectionalNeighbour(entries, current, axis, direction) {
25
+ if (!entries)
26
+ return undefined;
27
+ const coordinate = getAxisCoordinate(current, axis);
28
+ const insertionIndex = findFirstGreaterOrEqual(entries, coordinate, axis);
29
+ if (direction === -1)
30
+ return insertionIndex === 0 ? undefined : entries[insertionIndex - 1];
31
+ return entries[findFirstGreater(entries, coordinate, axis)];
32
+ }
33
+ /*** Locate the first entry strictly after a matrix coordinate in a sorted sparse axis. */
34
+ function findFirstGreater(entries, coordinate, axis) {
35
+ let lower = 0;
36
+ let upper = entries.length;
37
+ while (lower < upper) {
38
+ const middle = Math.floor((lower + upper) / 2);
39
+ const entry = entries.at(middle);
40
+ if (entry && getAxisCoordinate(entry, axis) <= coordinate)
41
+ lower = middle + 1;
42
+ else
43
+ upper = middle;
44
+ }
45
+ return lower;
46
+ }
47
+ /*** Locate the first index at or after a matrix coordinate in a sorted sparse axis. */
48
+ function findFirstGreaterOrEqual(entries, coordinate, axis) {
49
+ let lower = 0;
50
+ let upper = entries.length;
51
+ while (lower < upper) {
52
+ const middle = Math.floor((lower + upper) / 2);
53
+ const entry = entries.at(middle);
54
+ if (entry && getAxisCoordinate(entry, axis) < coordinate)
55
+ lower = middle + 1;
56
+ else
57
+ upper = middle;
58
+ }
59
+ return lower;
60
+ }
61
+ /*** Read a selected coordinate without dynamically indexing sparse entries. */
62
+ function getAxisCoordinate(entry, axis) {
63
+ return axis === 'columnIndex' ? entry.columnIndex : entry.rowIndex;
64
+ }
65
+ //# sourceMappingURL=getMatrixGridNextFocusId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getMatrixGridNextFocusId.js","sourceRoot":"","sources":["../../../../src/features/matrix-grid/application/getMatrixGridNextFocusId.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n MatrixGridSparseIndex,\n MatrixGridSparseIndexEntry,\n} from './createMatrixGridSparseIndex';\n\n/*** Resolve arrow-key focus among existing sparse cells without inventing placeholder geometry. */\nexport function getMatrixGridNextFocusId(\n index: MatrixGridSparseIndex,\n currentId: string | null,\n key: string,\n): string | null {\n const current = currentId === null ? undefined : index.positionById.get(currentId);\n if (!current) return index.firstId;\n\n return resolveDirectionalCandidate(index, current, key)?.id ?? current.id;\n}\n\n/*** Find the closest existing sparse cell along the requested matrix axis. */\nfunction resolveDirectionalCandidate(\n index: MatrixGridSparseIndex,\n current: MatrixGridSparseIndexEntry,\n key: string,\n): MatrixGridSparseIndexEntry | undefined {\n switch (key) {\n case 'ArrowLeft':\n return findDirectionalNeighbour(\n index.entriesByRow.get(current.rowIndex),\n current,\n 'columnIndex',\n -1,\n );\n case 'ArrowRight':\n return findDirectionalNeighbour(\n index.entriesByRow.get(current.rowIndex),\n current,\n 'columnIndex',\n 1,\n );\n case 'ArrowUp':\n return findDirectionalNeighbour(\n index.entriesByColumn.get(current.columnIndex),\n current,\n 'rowIndex',\n -1,\n );\n case 'ArrowDown':\n return findDirectionalNeighbour(\n index.entriesByColumn.get(current.columnIndex),\n current,\n 'rowIndex',\n 1,\n );\n default:\n return undefined;\n }\n}\n\n/*** Read the nearest strictly directional neighbour from a pre-sorted sparse axis. */\nfunction findDirectionalNeighbour(\n entries: readonly MatrixGridSparseIndexEntry[] | undefined,\n current: MatrixGridSparseIndexEntry,\n axis: 'columnIndex' | 'rowIndex',\n direction: -1 | 1,\n): MatrixGridSparseIndexEntry | undefined {\n if (!entries) return undefined;\n const coordinate = getAxisCoordinate(current, axis);\n const insertionIndex = findFirstGreaterOrEqual(entries, coordinate, axis);\n if (direction === -1) return insertionIndex === 0 ? undefined : entries[insertionIndex - 1];\n return entries[findFirstGreater(entries, coordinate, axis)];\n}\n\n/*** Locate the first entry strictly after a matrix coordinate in a sorted sparse axis. */\nfunction findFirstGreater(\n entries: readonly MatrixGridSparseIndexEntry[],\n coordinate: number,\n axis: 'columnIndex' | 'rowIndex',\n): number {\n let lower = 0;\n let upper = entries.length;\n while (lower < upper) {\n const middle = Math.floor((lower + upper) / 2);\n const entry = entries.at(middle);\n if (entry && getAxisCoordinate(entry, axis) <= coordinate) lower = middle + 1;\n else upper = middle;\n }\n return lower;\n}\n\n/*** Locate the first index at or after a matrix coordinate in a sorted sparse axis. */\nfunction findFirstGreaterOrEqual(\n entries: readonly MatrixGridSparseIndexEntry[],\n coordinate: number,\n axis: 'columnIndex' | 'rowIndex',\n): number {\n let lower = 0;\n let upper = entries.length;\n while (lower < upper) {\n const middle = Math.floor((lower + upper) / 2);\n const entry = entries.at(middle);\n if (entry && getAxisCoordinate(entry, axis) < coordinate) lower = middle + 1;\n else upper = middle;\n }\n return lower;\n}\n\n/*** Read a selected coordinate without dynamically indexing sparse entries. */\nfunction getAxisCoordinate(\n entry: MatrixGridSparseIndexEntry,\n axis: 'columnIndex' | 'rowIndex',\n): number {\n return axis === 'columnIndex' ? entry.columnIndex : entry.rowIndex;\n}\n"]}
@@ -1,5 +1,12 @@
1
1
  import { type SelectionIntent } from '@ankhorage/utility/selection';
2
2
  import type { SelectionMode } from '../../../types/selection';
3
+ type MatrixGridSelectionIntent = SelectionIntent | 'range';
3
4
  /*** Apply ZORA's canonical selection intent while retaining the configured selection mode. */
4
- export declare function resolveMatrixGridSelection(selectedIds: readonly string[], cellId: string, intent: SelectionIntent, mode: SelectionMode): readonly string[];
5
+ export declare function resolveMatrixGridSelection(cells: readonly MatrixGridSelectionCell[], selectedIds: readonly string[], cellId: string, anchorId: string | null, intent: MatrixGridSelectionIntent, mode: SelectionMode): readonly string[];
6
+ type MatrixGridSelectionCell = Readonly<{
7
+ columnIndex: number;
8
+ id: string;
9
+ rowIndex: number;
10
+ }>;
11
+ export {};
5
12
  //# sourceMappingURL=resolveMatrixGridSelection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveMatrixGridSelection.d.ts","sourceRoot":"","sources":["../../../../src/features/matrix-grid/application/resolveMatrixGridSelection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,8FAA8F;AAC9F,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,GAClB,SAAS,MAAM,EAAE,CAInB"}
1
+ {"version":3,"file":"resolveMatrixGridSelection.d.ts","sourceRoot":"","sources":["../../../../src/features/matrix-grid/application/resolveMatrixGridSelection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE1F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,KAAK,yBAAyB,GAAG,eAAe,GAAG,OAAO,CAAC;AAE3D,8FAA8F;AAC9F,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,uBAAuB,EAAE,EACzC,WAAW,EAAE,SAAS,MAAM,EAAE,EAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,yBAAyB,EACjC,IAAI,EAAE,aAAa,GAClB,SAAS,MAAM,EAAE,CAiBnB;AAED,KAAK,uBAAuB,GAAG,QAAQ,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC"}