@ankhorage/zora 24.0.3 → 24.1.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 (321) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -1
  3. package/dist/constants/authoring.d.ts +4 -3
  4. package/dist/constants/authoring.d.ts.map +1 -1
  5. package/dist/constants/authoring.js +3 -0
  6. package/dist/constants/authoring.js.map +1 -1
  7. package/dist/features/accordion/accordionItemMeta.d.ts +1 -1
  8. package/dist/features/bottom-sheet/bottomSheetMeta.d.ts +1 -1
  9. package/dist/features/card/cardMeta.d.ts +1 -1
  10. package/dist/features/card/mediaCardMeta.d.ts +1 -1
  11. package/dist/features/card/postCardMeta.d.ts +1 -1
  12. package/dist/features/chat/messageBubbleMeta.d.ts +1 -1
  13. package/dist/features/dialog/dialogMeta.d.ts +2 -2
  14. package/dist/features/explorer/adapters/inbound/Explorer.d.ts +5 -0
  15. package/dist/features/explorer/adapters/inbound/Explorer.d.ts.map +1 -0
  16. package/dist/features/explorer/adapters/inbound/Explorer.js +82 -0
  17. package/dist/features/explorer/adapters/inbound/Explorer.js.map +1 -0
  18. package/dist/features/explorer/adapters/inbound/FileExplorer.d.ts +5 -0
  19. package/dist/features/explorer/adapters/inbound/FileExplorer.d.ts.map +1 -0
  20. package/dist/features/explorer/adapters/inbound/FileExplorer.js +7 -0
  21. package/dist/features/explorer/adapters/inbound/FileExplorer.js.map +1 -0
  22. package/dist/features/explorer/adapters/inbound/MediaExplorer.d.ts +5 -0
  23. package/dist/features/explorer/adapters/inbound/MediaExplorer.d.ts.map +1 -0
  24. package/dist/features/explorer/adapters/inbound/MediaExplorer.js +7 -0
  25. package/dist/features/explorer/adapters/inbound/MediaExplorer.js.map +1 -0
  26. package/dist/features/explorer/application/resolveExplorerSelection.d.ts +7 -0
  27. package/dist/features/explorer/application/resolveExplorerSelection.d.ts.map +1 -0
  28. package/dist/features/explorer/application/resolveExplorerSelection.js +22 -0
  29. package/dist/features/explorer/application/resolveExplorerSelection.js.map +1 -0
  30. package/dist/features/explorer/meta.d.ts +306 -0
  31. package/dist/features/explorer/meta.d.ts.map +1 -0
  32. package/dist/features/explorer/meta.js +89 -0
  33. package/dist/features/explorer/meta.js.map +1 -0
  34. package/dist/features/explorer/public.d.ts +6 -0
  35. package/dist/features/explorer/public.d.ts.map +1 -0
  36. package/dist/features/explorer/public.js +5 -0
  37. package/dist/features/explorer/public.js.map +1 -0
  38. package/dist/features/gradient/gradientMeta.d.ts +1 -1
  39. package/dist/features/grid-view/adapters/inbound/GridView.d.ts +10 -0
  40. package/dist/features/grid-view/adapters/inbound/GridView.d.ts.map +1 -0
  41. package/dist/features/grid-view/adapters/inbound/GridView.js +49 -0
  42. package/dist/features/grid-view/adapters/inbound/GridView.js.map +1 -0
  43. package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts +5 -0
  44. package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts.map +1 -0
  45. package/dist/features/grid-view/adapters/inbound/TileGrid.js +18 -0
  46. package/dist/features/grid-view/adapters/inbound/TileGrid.js.map +1 -0
  47. package/dist/features/grid-view/application/layoutTileGrid.d.ts +12 -0
  48. package/dist/features/grid-view/application/layoutTileGrid.d.ts.map +1 -0
  49. package/dist/features/grid-view/application/layoutTileGrid.js +25 -0
  50. package/dist/features/grid-view/application/layoutTileGrid.js.map +1 -0
  51. package/dist/features/grid-view/meta.d.ts +20 -0
  52. package/dist/features/grid-view/meta.d.ts.map +1 -0
  53. package/dist/features/grid-view/meta.js +20 -0
  54. package/dist/features/grid-view/meta.js.map +1 -0
  55. package/dist/features/grid-view/public.d.ts +5 -0
  56. package/dist/features/grid-view/public.d.ts.map +1 -0
  57. package/dist/features/grid-view/public.js +4 -0
  58. package/dist/features/grid-view/public.js.map +1 -0
  59. package/dist/features/keyboard-avoiding-view/keyboardAvoidingViewMeta.d.ts +1 -1
  60. package/dist/features/layout/gridMeta.d.ts +1 -1
  61. package/dist/features/layout/screenMeta.d.ts +1 -1
  62. package/dist/features/layout/scrollViewMeta.d.ts +1 -1
  63. package/dist/features/layout/viewMeta.d.ts +1 -1
  64. package/dist/features/list/flatListMeta.d.ts +1 -1
  65. package/dist/features/list/sectionListMeta.d.ts +1 -1
  66. package/dist/features/reader/meta.d.ts +2 -2
  67. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.d.ts.map +1 -1
  68. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js +7 -0
  69. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js.map +1 -1
  70. package/dist/features/registry/bindableComponentMeta.d.ts +2 -2
  71. package/dist/features/registry/componentMeta.d.ts.map +1 -1
  72. package/dist/features/registry/componentMeta.js +7 -0
  73. package/dist/features/registry/componentMeta.js.map +1 -1
  74. package/dist/features/scanner/meta.d.ts +2 -2
  75. package/dist/features/section/screenSectionMeta.d.ts +1 -1
  76. package/dist/features/surface/surfaceMeta.d.ts +1 -1
  77. package/dist/features/tabs/tabPanelMeta.d.ts +1 -1
  78. package/dist/features/uploader/adapters/inbound/Uploader.d.ts.map +1 -1
  79. package/dist/features/uploader/adapters/inbound/Uploader.js +73 -48
  80. package/dist/features/uploader/adapters/inbound/Uploader.js.map +1 -1
  81. package/dist/features/uploader/public.d.ts +1 -1
  82. package/dist/features/uploader/public.d.ts.map +1 -1
  83. package/dist/features/uploader/public.js.map +1 -1
  84. package/dist/features/uploader/uploaderMeta.d.ts +5 -0
  85. package/dist/features/uploader/uploaderMeta.d.ts.map +1 -1
  86. package/dist/features/uploader/uploaderMeta.js +1 -0
  87. package/dist/features/uploader/uploaderMeta.js.map +1 -1
  88. package/dist/index.d.ts +5 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +2 -0
  91. package/dist/index.js.map +1 -1
  92. package/dist/types/explorer.d.ts +40 -0
  93. package/dist/types/explorer.d.ts.map +1 -0
  94. package/dist/types/explorer.js +2 -0
  95. package/dist/types/explorer.js.map +1 -0
  96. package/dist/types/grid-view.d.ts +31 -0
  97. package/dist/types/grid-view.d.ts.map +1 -0
  98. package/dist/types/grid-view.js +2 -0
  99. package/dist/types/grid-view.js.map +1 -0
  100. package/dist/types/upload.d.ts +6 -0
  101. package/dist/types/upload.d.ts.map +1 -1
  102. package/dist/types/upload.js.map +1 -1
  103. package/package.json +7 -6
  104. package/src/constants/authoring.ts +3 -0
  105. package/src/features/explorer/adapters/inbound/Explorer.tsx +136 -0
  106. package/src/features/explorer/adapters/inbound/FileExplorer.tsx +9 -0
  107. package/src/features/explorer/adapters/inbound/MediaExplorer.tsx +16 -0
  108. package/src/features/explorer/application/resolveExplorerSelection.test.ts +35 -0
  109. package/src/features/explorer/application/resolveExplorerSelection.ts +29 -0
  110. package/src/features/explorer/meta.ts +94 -0
  111. package/src/features/explorer/public.ts +12 -0
  112. package/src/features/grid-view/adapters/inbound/GridView.tsx +95 -0
  113. package/src/features/grid-view/adapters/inbound/TileGrid.tsx +53 -0
  114. package/src/features/grid-view/application/layoutTileGrid.test.ts +36 -0
  115. package/src/features/grid-view/application/layoutTileGrid.ts +46 -0
  116. package/src/features/grid-view/meta.ts +22 -0
  117. package/src/features/grid-view/public.ts +4 -0
  118. package/src/features/layout/public.test.ts +5 -1
  119. package/src/features/registry/ZORA_COMPONENT_REGISTRY.ts +7 -0
  120. package/src/features/registry/componentMeta.test.ts +2 -0
  121. package/src/features/registry/componentMeta.ts +7 -0
  122. package/src/features/uploader/adapters/inbound/Uploader.tsx +65 -36
  123. package/src/features/uploader/public.ts +1 -0
  124. package/src/features/uploader/uploaderMeta.ts +1 -0
  125. package/src/index.ts +17 -0
  126. package/src/types/explorer.ts +45 -0
  127. package/src/types/grid-view.ts +34 -0
  128. package/src/types/upload.ts +5 -0
  129. package/web-dist/chunks/{Accordion-ansfkmye.js → Accordion-016wvwpg.js} +5 -5
  130. package/web-dist/chunks/{Accordion-3hg1wprb.js → Accordion-09qs8gt1.js} +1 -1
  131. package/web-dist/chunks/{Accordion-kpap0trj.js → Accordion-184r2r82.js} +1 -1
  132. package/web-dist/chunks/{Accordion-jdwwf626.js → Accordion-1p9r2ack.js} +3 -3
  133. package/web-dist/chunks/{Accordion-2q6p67xe.js → Accordion-2c759z0y.js} +7 -5
  134. package/web-dist/chunks/Accordion-2gvs3frs.js +197 -0
  135. package/web-dist/chunks/{Accordion-rkt7qdmj.js → Accordion-2nesr9cv.js} +2 -2
  136. package/web-dist/chunks/{Accordion-egq42kdy.js → Accordion-2rgexkze.js} +6 -4
  137. package/web-dist/chunks/{Accordion-7q1qf7c0.js → Accordion-3m3572sa.js} +7 -5
  138. package/web-dist/chunks/{Accordion-74rt38d4.js → Accordion-42jfy1a1.js} +1 -1
  139. package/web-dist/chunks/{Accordion-jkhq422b.js → Accordion-45nc4bte.js} +2 -2
  140. package/web-dist/chunks/{Accordion-jtrpmvzs.js → Accordion-5ga4549x.js} +6 -6
  141. package/web-dist/chunks/Accordion-6wrr910w.js +5227 -0
  142. package/web-dist/chunks/{Accordion-7rvtpcwt.js → Accordion-7asr7vb0.js} +6 -6
  143. package/web-dist/chunks/{Accordion-3f5vnfk8.js → Accordion-7yazfxr6.js} +7 -7
  144. package/web-dist/chunks/{Accordion-g0c439br.js → Accordion-8f0nekwe.js} +4 -2
  145. package/web-dist/chunks/{Accordion-apwk2wjr.js → Accordion-8jxc7tx9.js} +2 -2
  146. package/web-dist/chunks/Accordion-8m8p9wpw.js +179 -0
  147. package/web-dist/chunks/{Accordion-mdc214tk.js → Accordion-9dqkq9am.js} +12 -12
  148. package/web-dist/chunks/{Accordion-t3hm5tcv.js → Accordion-afmybp67.js} +7 -7
  149. package/web-dist/chunks/{Accordion-qj4qxx1p.js → Accordion-ajawc6nq.js} +7 -7
  150. package/web-dist/chunks/{Accordion-ae7m1dkn.js → Accordion-bb8y34wh.js} +2 -2
  151. package/web-dist/chunks/{Accordion-h46676ex.js → Accordion-be2yhfqz.js} +1 -1
  152. package/web-dist/chunks/{Accordion-x3tphbvw.js → Accordion-bff0p3x4.js} +1 -1
  153. package/web-dist/chunks/{Accordion-rg763dfb.js → Accordion-c69374jn.js} +8 -17
  154. package/web-dist/chunks/{Accordion-y2eyyqrk.js → Accordion-cbfa2b8j.js} +10 -10
  155. package/web-dist/chunks/{Accordion-x5v1p4df.js → Accordion-ch4q5w0z.js} +7 -5
  156. package/web-dist/chunks/{Accordion-vewrj1kr.js → Accordion-f0jsd9f9.js} +8 -6
  157. package/web-dist/chunks/{Accordion-2bsecqwf.js → Accordion-fkc50r9z.js} +4 -4
  158. package/web-dist/chunks/{Accordion-avnt7nkz.js → Accordion-fzcpm4xf.js} +1 -1
  159. package/web-dist/chunks/{Accordion-hwd5ntgm.js → Accordion-fzkrrc4z.js} +2 -2
  160. package/web-dist/chunks/{Accordion-7bb37pdc.js → Accordion-ggwxv6k3.js} +7 -7
  161. package/web-dist/chunks/{Accordion-sxfqnnx6.js → Accordion-hmhdwvqp.js} +12 -10
  162. package/web-dist/chunks/{Accordion-cs8k948c.js → Accordion-mej71qnw.js} +8 -6
  163. package/web-dist/chunks/{Accordion-kcwdwd5z.js → Accordion-mh67wb34.js} +10 -8
  164. package/web-dist/chunks/Accordion-n4et7etk.js +14 -0
  165. package/web-dist/chunks/{Accordion-0acrkcyd.js → Accordion-n9c5tsqw.js} +4 -4
  166. package/web-dist/chunks/{Accordion-nanvzve9.js → Accordion-ndf3jqhb.js} +5 -5
  167. package/web-dist/chunks/{Accordion-q1mnv5g8.js → Accordion-nmpmdrba.js} +5 -5
  168. package/web-dist/chunks/{Accordion-fvkwq99h.js → Accordion-nnv76yff.js} +6 -4
  169. package/web-dist/chunks/{Accordion-122fdtp0.js → Accordion-ntndskbj.js} +7 -7
  170. package/web-dist/chunks/{Accordion-brt4drx3.js → Accordion-pe66x9cv.js} +11 -9
  171. package/web-dist/chunks/{Accordion-nj9g6p48.js → Accordion-q09fjenx.js} +11 -9
  172. package/web-dist/chunks/{Accordion-3rv8psbv.js → Accordion-qkh5yy94.js} +4 -4
  173. package/web-dist/chunks/{Accordion-qsxx5q34.js → Accordion-sdcfa14w.js} +12 -10
  174. package/web-dist/chunks/{Accordion-1dah5bqg.js → Accordion-srjya6dz.js} +1 -1
  175. package/web-dist/chunks/{Accordion-nay7yexy.js → Accordion-t0hbez90.js} +13 -11
  176. package/web-dist/chunks/{Accordion-2afa2z5x.js → Accordion-teg40mpt.js} +4 -4
  177. package/web-dist/chunks/{Accordion-k8tfv274.js → Accordion-tmrjy46p.js} +8 -6
  178. package/web-dist/chunks/{Accordion-2d3hbryv.js → Accordion-wgejzesa.js} +8 -8
  179. package/web-dist/chunks/{Accordion-kpxyryke.js → Accordion-wyxmd0n0.js} +4 -2
  180. package/web-dist/chunks/{Accordion-2csc57rv.js → Accordion-x12fca21.js} +2 -2
  181. package/web-dist/chunks/{Accordion-sek2q4r1.js → Accordion-xgpzh4wq.js} +47 -5288
  182. package/web-dist/chunks/{Accordion-9rhbc32v.js → Accordion-xvzrx6bh.js} +16 -14
  183. package/web-dist/chunks/{Accordion-sxzax4x4.js → Accordion-z5a0tx18.js} +6 -4
  184. package/web-dist/components/accordion/Accordion.js +13 -12
  185. package/web-dist/components/accordion-item/AccordionItem.js +13 -12
  186. package/web-dist/components/activity-indicator/ActivityIndicator.js +6 -5
  187. package/web-dist/components/app-bar/AppBar.js +20 -19
  188. package/web-dist/components/app-header/AppHeader.js +20 -19
  189. package/web-dist/components/app-shell/AppShell.js +7 -6
  190. package/web-dist/components/auth-screen/AuthScreen.js +22 -21
  191. package/web-dist/components/avatar/Avatar.js +13 -12
  192. package/web-dist/components/avatar-group/AvatarGroup.js +13 -12
  193. package/web-dist/components/badge/Badge.js +8 -7
  194. package/web-dist/components/barcode-scanner-view/BarcodeScannerView.js +21 -20
  195. package/web-dist/components/bottom-sheet/BottomSheet.js +9 -8
  196. package/web-dist/components/bottom-sheet-flat-list/BottomSheetFlatList.js +9 -8
  197. package/web-dist/components/bottom-sheet-scroll-view/BottomSheetScrollView.js +9 -8
  198. package/web-dist/components/bottom-sheet-section-list/BottomSheetSectionList.js +9 -8
  199. package/web-dist/components/bottom-sheet-view/BottomSheetView.js +9 -8
  200. package/web-dist/components/bottom-sheet-virtualized-list/BottomSheetVirtualizedList.js +9 -8
  201. package/web-dist/components/breadcrumbs/Breadcrumbs.js +15 -14
  202. package/web-dist/components/button/Button.js +13 -12
  203. package/web-dist/components/button-group/ButtonGroup.js +13 -12
  204. package/web-dist/components/camera-permission-view/CameraPermissionView.js +21 -20
  205. package/web-dist/components/card/Card.js +20 -19
  206. package/web-dist/components/card-back/CardBack.js +5 -4
  207. package/web-dist/components/card-hand/CardHand.js +5 -4
  208. package/web-dist/components/chat-list-item/ChatListItem.js +17 -16
  209. package/web-dist/components/checkbox/Checkbox.js +13 -12
  210. package/web-dist/components/checkbox-group/CheckboxGroup.js +13 -12
  211. package/web-dist/components/chess-board/ChessBoard.js +5 -4
  212. package/web-dist/components/chip/Chip.js +14 -13
  213. package/web-dist/components/chip-group/ChipGroup.js +14 -13
  214. package/web-dist/components/collection-editor/CollectionEditor.js +20 -19
  215. package/web-dist/components/content-rail/ContentRail.js +16 -15
  216. package/web-dist/components/data-table/DataTable.js +29 -28
  217. package/web-dist/components/date-picker/DatePicker.js +18 -17
  218. package/web-dist/components/dialog/Dialog.js +13 -12
  219. package/web-dist/components/divider/Divider.js +7 -6
  220. package/web-dist/components/empty-state/EmptyState.js +21 -20
  221. package/web-dist/components/explorer/Explorer.d.ts +5 -0
  222. package/web-dist/components/explorer/Explorer.js +27 -0
  223. package/web-dist/components/explorer/index.d.ts +1 -0
  224. package/web-dist/components/explorer/index.js +2 -0
  225. package/web-dist/components/field/Field.js +13 -12
  226. package/web-dist/components/file-explorer/FileExplorer.d.ts +5 -0
  227. package/web-dist/components/file-explorer/FileExplorer.js +27 -0
  228. package/web-dist/components/file-explorer/index.d.ts +1 -0
  229. package/web-dist/components/file-explorer/index.js +2 -0
  230. package/web-dist/components/flat-list/FlatList.js +14 -13
  231. package/web-dist/components/forgot-password-form/ForgotPasswordForm.js +22 -21
  232. package/web-dist/components/form/Form.js +17 -16
  233. package/web-dist/components/form-actions/FormActions.js +17 -16
  234. package/web-dist/components/form-error/FormError.js +17 -16
  235. package/web-dist/components/game/Game.js +8 -7
  236. package/web-dist/components/game-entity/GameEntity.js +8 -7
  237. package/web-dist/components/game-field/GameField.js +8 -7
  238. package/web-dist/components/game-input-zone/GameInputZone.js +8 -7
  239. package/web-dist/components/game-measurement-probe/GameMeasurementProbe.js +8 -7
  240. package/web-dist/components/game-overlay/GameOverlay.js +8 -7
  241. package/web-dist/components/gradient/Gradient.js +8 -7
  242. package/web-dist/components/gradient-renderer-provider/GradientRendererProvider.js +8 -7
  243. package/web-dist/components/graph-view/GraphView.js +3 -3
  244. package/web-dist/components/grid/Grid.js +7 -6
  245. package/web-dist/components/grid-view/GridView.d.ts +4 -0
  246. package/web-dist/components/grid-view/GridView.js +10 -0
  247. package/web-dist/components/grid-view/index.d.ts +1 -0
  248. package/web-dist/components/grid-view/index.js +2 -0
  249. package/web-dist/components/heading/Heading.js +7 -6
  250. package/web-dist/components/hero/Hero.js +20 -19
  251. package/web-dist/components/icon/Icon.js +5 -4
  252. package/web-dist/components/icon-button/IconButton.js +13 -12
  253. package/web-dist/components/image/Image.js +11 -10
  254. package/web-dist/components/keyboard-avoiding-view/KeyboardAvoidingView.js +4 -3
  255. package/web-dist/components/list/List.js +14 -13
  256. package/web-dist/components/list-item/ListItem.js +14 -13
  257. package/web-dist/components/list-section/ListSection.js +14 -13
  258. package/web-dist/components/media-card/MediaCard.js +20 -19
  259. package/web-dist/components/media-explorer/MediaExplorer.d.ts +5 -0
  260. package/web-dist/components/media-explorer/MediaExplorer.js +27 -0
  261. package/web-dist/components/media-explorer/index.d.ts +1 -0
  262. package/web-dist/components/media-explorer/index.js +2 -0
  263. package/web-dist/components/message-bubble/MessageBubble.js +17 -16
  264. package/web-dist/components/metric-card/MetricCard.js +20 -19
  265. package/web-dist/components/missing-element/MissingElement.js +14 -13
  266. package/web-dist/components/o-auth-provider-button/OAuthProviderButton.js +22 -21
  267. package/web-dist/components/o-auth-provider-list/OAuthProviderList.js +22 -21
  268. package/web-dist/components/opening-book/OpeningBook.js +5 -4
  269. package/web-dist/components/otp-form/OtpForm.js +22 -21
  270. package/web-dist/components/pagination/Pagination.js +14 -13
  271. package/web-dist/components/palette-item/PaletteItem.js +20 -19
  272. package/web-dist/components/playing-card/PlayingCard.js +5 -4
  273. package/web-dist/components/poker-training-table/PokerTrainingTable.js +5 -4
  274. package/web-dist/components/popover-menu/PopoverMenu.js +15 -14
  275. package/web-dist/components/post-card/PostCard.js +20 -19
  276. package/web-dist/components/product-card/ProductCard.js +20 -19
  277. package/web-dist/components/progress/Progress.js +11 -10
  278. package/web-dist/components/progress-ring/ProgressRing.js +11 -10
  279. package/web-dist/components/radio/Radio.js +15 -14
  280. package/web-dist/components/radio-group/RadioGroup.js +15 -14
  281. package/web-dist/components/rating/Rating.js +10 -9
  282. package/web-dist/components/reader/Reader.js +25 -24
  283. package/web-dist/components/scan-overlay/ScanOverlay.js +21 -20
  284. package/web-dist/components/screen/Screen.js +7 -6
  285. package/web-dist/components/screen-section/ScreenSection.js +11 -10
  286. package/web-dist/components/scroll-view/ScrollView.js +7 -6
  287. package/web-dist/components/search-input/SearchInput.js +14 -13
  288. package/web-dist/components/section-header/SectionHeader.js +11 -10
  289. package/web-dist/components/section-list/SectionList.js +14 -13
  290. package/web-dist/components/select/Select.js +17 -16
  291. package/web-dist/components/selectable-item/SelectableItem.js +7 -6
  292. package/web-dist/components/selection-provider/SelectionProvider.js +7 -6
  293. package/web-dist/components/sign-in-form/SignInForm.js +22 -21
  294. package/web-dist/components/sign-up-form/SignUpForm.js +22 -21
  295. package/web-dist/components/skeleton/Skeleton.js +23 -22
  296. package/web-dist/components/skeleton-card/SkeletonCard.js +23 -22
  297. package/web-dist/components/skeleton-list/SkeletonList.js +23 -22
  298. package/web-dist/components/skeleton-text/SkeletonText.js +23 -22
  299. package/web-dist/components/surface/Surface.js +8 -7
  300. package/web-dist/components/switch/Switch.js +8 -7
  301. package/web-dist/components/tab/Tab.js +8 -7
  302. package/web-dist/components/tab-list/TabList.js +8 -7
  303. package/web-dist/components/tab-panel/TabPanel.js +8 -7
  304. package/web-dist/components/tabletop-table/TabletopTable.js +5 -4
  305. package/web-dist/components/tabs/Tabs.js +8 -7
  306. package/web-dist/components/text/Text.js +7 -6
  307. package/web-dist/components/text-input/TextInput.js +14 -13
  308. package/web-dist/components/tile-grid/TileGrid.d.ts +4 -0
  309. package/web-dist/components/tile-grid/TileGrid.js +10 -0
  310. package/web-dist/components/tile-grid/index.d.ts +1 -0
  311. package/web-dist/components/tile-grid/index.js +2 -0
  312. package/web-dist/components/time-picker/TimePicker.js +20 -19
  313. package/web-dist/components/timeline/Timeline.js +12 -11
  314. package/web-dist/components/toast/Toast.js +10 -9
  315. package/web-dist/components/toast-provider/ToastProvider.js +10 -9
  316. package/web-dist/components/toolbar/Toolbar.js +20 -19
  317. package/web-dist/components/tree-item/TreeItem.js +20 -19
  318. package/web-dist/components/uploader/Uploader.js +109 -70
  319. package/web-dist/components/view/View.js +7 -6
  320. package/web-dist/manifest.json +1748 -1497
  321. package/web-dist/runtime/ZoraProvider.js +14 -12
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explorer.d.ts","sourceRoot":"","sources":["../../src/types/explorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,IAAI,CAAC;IAClE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=explorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explorer.js","sourceRoot":"","sources":["../../src/types/explorer.ts"],"names":[],"mappings":"","sourcesContent":["import type { ZoraBaseProps } from './base';\n\n/** Portable catalogue row. Providers retain permissions, pagination and storage objects. */\nexport type ExplorerItemKind = 'image' | 'video' | 'audio' | 'document' | 'file' | 'folder';\n\nexport interface ExplorerItem {\n readonly id: string;\n readonly kind: ExplorerItemKind;\n readonly name: string;\n readonly thumbnailUri?: string;\n readonly uri?: string;\n readonly contentType?: string;\n readonly sizeBytes?: number;\n readonly durationSeconds?: number;\n readonly providerId?: string;\n readonly disabled?: boolean;\n}\n\nexport type ExplorerSelectionMode = 'single' | 'multi';\n\nexport interface ExplorerActivateEvent {\n readonly id: string;\n}\n\nexport interface ExplorerSelectionChangeEvent {\n readonly selectedIds: readonly string[];\n}\n\nexport interface ExplorerProps extends ZoraBaseProps {\n items: readonly ExplorerItem[];\n selectionMode?: ExplorerSelectionMode;\n selectedIds?: readonly string[];\n defaultSelectedIds?: readonly string[];\n onSelectionChange?: (event: ExplorerSelectionChangeEvent) => void;\n onActivate?: (event: ExplorerActivateEvent) => void;\n width?: number;\n height?: number;\n tileSize?: number;\n zoom?: number;\n loading?: boolean;\n errorText?: string;\n emptyText?: string;\n disabled?: boolean;\n readOnly?: boolean;\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import type { GridRectItem, GridViewport } from '@ankhorage/grid-view';
2
+ import type React from 'react';
3
+ import type { ZoraBaseProps } from './base';
4
+ /** The renderer owns presentation only; world geometry comes from grid-view. */
5
+ export interface GridViewProps extends ZoraBaseProps {
6
+ items: readonly GridRectItem[];
7
+ contentWidth: number;
8
+ contentHeight: number;
9
+ width: number;
10
+ height: number;
11
+ zoom?: number;
12
+ overscanPixels?: number;
13
+ onViewportChange?: (viewport: GridViewport) => void;
14
+ renderItem: (item: GridRectItem) => React.ReactNode;
15
+ }
16
+ /** An item needs a stable ID; visual positioning belongs to the TileGrid composition. */
17
+ export interface TileGridItem {
18
+ readonly id: string;
19
+ }
20
+ /** Reusable tile presentation based on the generic world/viewport engine. */
21
+ export interface TileGridProps extends ZoraBaseProps {
22
+ items: readonly TileGridItem[];
23
+ width?: number;
24
+ height?: number;
25
+ tileSize?: number;
26
+ gap?: number;
27
+ zoom?: number;
28
+ overscanPixels?: number;
29
+ renderItem: (item: TileGridItem) => React.ReactNode;
30
+ }
31
+ //# sourceMappingURL=grid-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-view.d.ts","sourceRoot":"","sources":["../../src/types/grid-view.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,gFAAgF;AAChF,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IACpD,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,KAAK,CAAC,SAAS,CAAC;CACrD;AAED,yFAAyF;AACzF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,6EAA6E;AAC7E,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,KAAK,CAAC,SAAS,CAAC;CACrD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=grid-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-view.js","sourceRoot":"","sources":["../../src/types/grid-view.ts"],"names":[],"mappings":"","sourcesContent":["import type { GridRectItem, GridViewport } from '@ankhorage/grid-view';\nimport type React from 'react';\n\nimport type { ZoraBaseProps } from './base';\n\n/** The renderer owns presentation only; world geometry comes from grid-view. */\nexport interface GridViewProps extends ZoraBaseProps {\n items: readonly GridRectItem[];\n contentWidth: number;\n contentHeight: number;\n width: number;\n height: number;\n zoom?: number;\n overscanPixels?: number;\n onViewportChange?: (viewport: GridViewport) => void;\n renderItem: (item: GridRectItem) => React.ReactNode;\n}\n\n/** An item needs a stable ID; visual positioning belongs to the TileGrid composition. */\nexport interface TileGridItem {\n readonly id: string;\n}\n\n/** Reusable tile presentation based on the generic world/viewport engine. */\nexport interface TileGridProps extends ZoraBaseProps {\n items: readonly TileGridItem[];\n width?: number;\n height?: number;\n tileSize?: number;\n gap?: number;\n zoom?: number;\n overscanPixels?: number;\n renderItem: (item: TileGridItem) => React.ReactNode;\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type React from 'react';
2
2
  import type { ZoraBaseProps } from './base';
3
+ import type { ExplorerItem } from './explorer';
3
4
  export type UploadType = 'image' | 'video' | 'document' | 'file';
4
5
  export interface UploadAssetBase {
5
6
  fileName?: string;
@@ -32,6 +33,9 @@ export interface ValidateUploadAssetInput {
32
33
  maxSizeBytes?: number;
33
34
  validate?: (asset: UploadAsset) => string | undefined;
34
35
  }
36
+ export type UploaderExplorerItem = ExplorerItem & {
37
+ readonly uploadAsset: UploadAsset;
38
+ };
35
39
  export interface UploaderProps extends ZoraBaseProps {
36
40
  value?: UploadAsset | null;
37
41
  onChange?: (next: UploadAsset | null) => void;
@@ -58,6 +62,8 @@ export interface UploaderProps extends ZoraBaseProps {
58
62
  disabled?: boolean;
59
63
  readOnly?: boolean;
60
64
  validatePicked?: (asset: UploadAsset) => string | undefined;
65
+ /** If supplied, Uploader opens the canonical app-owned Explorer instead of an OS picker. */
66
+ explorerItems?: readonly UploaderExplorerItem[];
61
67
  onUpload?: (asset: UploadAsset, context: UploadProgressContext) => Promise<UploadAsset>;
62
68
  onRemove?: (current: UploadAsset) => void | Promise<void>;
63
69
  aspectRatio?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/types/upload.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/types/upload.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/types/upload.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from './base';\n\nexport type UploadType = 'image' | 'video' | 'document' | 'file';\n\nexport interface UploadAssetBase {\n fileName?: string;\n sizeBytes?: number;\n contentType?: string;\n width?: number;\n height?: number;\n alt?: string;\n createdAt?: string;\n}\n\nexport type UploadAsset =\n | (UploadAssetBase & {\n kind: 'local';\n uri: string;\n })\n | (UploadAssetBase & {\n kind: 'url';\n url: string;\n })\n | (UploadAssetBase & {\n kind: 'storage';\n storageId?: string;\n bucket: string;\n path: string;\n publicUrl?: string;\n });\n\nexport interface UploadProgressContext {\n setProgress: (progress: number | null) => void;\n}\n\nexport interface ValidateUploadAssetInput {\n asset: UploadAsset;\n accept?: string;\n maxSizeBytes?: number;\n validate?: (asset: UploadAsset) => string | undefined;\n}\n\nexport interface UploaderProps extends ZoraBaseProps {\n value?: UploadAsset | null;\n onChange?: (next: UploadAsset | null) => void;\n onValueChange?: (next: UploadAsset | null) => void;\n onUploadRequest?: (event: { asset: UploadAsset }) => void;\n onRemoveRequest?: (event: { asset: UploadAsset }) => void;\n onValidationError?: (event: { message: string }) => void;\n uploadState?: 'idle' | 'uploading' | 'removing';\n uploadProgress?: number;\n label?: React.ReactNode;\n description?: React.ReactNode;\n helperText?: React.ReactNode;\n errorText?: React.ReactNode;\n type?: UploadType;\n accept?: string;\n maxSizeBytes?: number;\n required?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n validatePicked?: (asset: UploadAsset) => string | undefined;\n onUpload?: (asset: UploadAsset, context: UploadProgressContext) => Promise<UploadAsset>;\n onRemove?: (current: UploadAsset) => void | Promise<void>;\n aspectRatio?: number;\n}\n"]}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/types/upload.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from './base';\nimport type { ExplorerItem } from './explorer';\n\nexport type UploadType = 'image' | 'video' | 'document' | 'file';\n\nexport interface UploadAssetBase {\n fileName?: string;\n sizeBytes?: number;\n contentType?: string;\n width?: number;\n height?: number;\n alt?: string;\n createdAt?: string;\n}\n\nexport type UploadAsset =\n | (UploadAssetBase & {\n kind: 'local';\n uri: string;\n })\n | (UploadAssetBase & {\n kind: 'url';\n url: string;\n })\n | (UploadAssetBase & {\n kind: 'storage';\n storageId?: string;\n bucket: string;\n path: string;\n publicUrl?: string;\n });\n\nexport interface UploadProgressContext {\n setProgress: (progress: number | null) => void;\n}\n\nexport interface ValidateUploadAssetInput {\n asset: UploadAsset;\n accept?: string;\n maxSizeBytes?: number;\n validate?: (asset: UploadAsset) => string | undefined;\n}\n\nexport type UploaderExplorerItem = ExplorerItem & { readonly uploadAsset: UploadAsset };\n\nexport interface UploaderProps extends ZoraBaseProps {\n value?: UploadAsset | null;\n onChange?: (next: UploadAsset | null) => void;\n onValueChange?: (next: UploadAsset | null) => void;\n onUploadRequest?: (event: { asset: UploadAsset }) => void;\n onRemoveRequest?: (event: { asset: UploadAsset }) => void;\n onValidationError?: (event: { message: string }) => void;\n uploadState?: 'idle' | 'uploading' | 'removing';\n uploadProgress?: number;\n label?: React.ReactNode;\n description?: React.ReactNode;\n helperText?: React.ReactNode;\n errorText?: React.ReactNode;\n type?: UploadType;\n accept?: string;\n maxSizeBytes?: number;\n required?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n validatePicked?: (asset: UploadAsset) => string | undefined;\n /** If supplied, Uploader opens the canonical app-owned Explorer instead of an OS picker. */\n explorerItems?: readonly UploaderExplorerItem[];\n onUpload?: (asset: UploadAsset, context: UploadProgressContext) => Promise<UploadAsset>;\n onRemove?: (current: UploadAsset) => void | Promise<void>;\n aspectRatio?: number;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "24.0.3",
4
+ "version": "24.1.1",
5
5
  "description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
6
6
  "homepage": "https://github.com/ankhorage/zora#readme",
7
7
  "bugs": {
@@ -42,15 +42,16 @@
42
42
  "dependencies": {
43
43
  "@ankhorage/ankh": "^0.12.2",
44
44
  "@ankhorage/color-theory": "^0.3.1",
45
- "@ankhorage/contracts": "^24.2.0",
45
+ "@ankhorage/contracts": "^24.2.1",
46
46
  "@ankhorage/game": "^0.1.2",
47
- "@ankhorage/runtime": "^4.0.5",
47
+ "@ankhorage/grid-view": "^0.1.1",
48
+ "@ankhorage/reader": "^0.1.0",
49
+ "@ankhorage/runtime": "^4.0.6",
48
50
  "@ankhorage/surface": "^9.4.1",
49
51
  "@ankhorage/utility": "^1.9.85",
50
52
  "chess.js": "^1.4.0",
51
53
  "expo-document-picker": "~57.0.3",
52
- "expo-image-picker": "~57.0.20",
53
- "@ankhorage/reader": "^0.1.0"
54
+ "expo-image-picker": "~57.0.20"
54
55
  },
55
56
  "files": [
56
57
  "dist",
@@ -152,7 +153,7 @@
152
153
  "react-native-reanimated": "4.5.1",
153
154
  "react-native-safe-area-context": "~5.7.0",
154
155
  "react-native-svg": "15.15.4",
155
- "react-native-web": "~0.21.3",
156
+ "react-native-web": "~0.21.4",
156
157
  "react-native-worklets": "0.10.1",
157
158
  "typescript": "~6.0.3"
158
159
  },
@@ -28,6 +28,7 @@ export const FEATURE_MANIFEST_ELEMENTS = {
28
28
  chip: ['Chip', 'ChipGroup'],
29
29
  'data-table': ['DataTable'],
30
30
  'date-picker': ['DatePicker'],
31
+ explorer: ['MediaExplorer', 'FileExplorer'],
31
32
  dialog: ['Dialog'],
32
33
  form: ['Form', 'FormError', 'Field'],
33
34
  gradient: ['Gradient'],
@@ -85,6 +86,8 @@ export const CONTAINER_ALLOWED_CHILDREN = [
85
86
  'SkeletonText',
86
87
  'IconButton',
87
88
  'Uploader',
89
+ 'MediaExplorer',
90
+ 'FileExplorer',
88
91
  'FlatList',
89
92
  'SectionList',
90
93
  'BottomSheet',
@@ -0,0 +1,136 @@
1
+ import React from 'react';
2
+ import { Pressable as NativePressable, View as NativeView } from 'react-native';
3
+
4
+ import type { ExplorerItem, ExplorerProps } from '../../../../types/explorer';
5
+ import { TileGrid } from '../../../grid-view/public';
6
+ import { Icon } from '../../../icon/public';
7
+ import { Image } from '../../../image/public';
8
+ import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
9
+ import { useZoraTheme } from '../../../theme/composition/useZoraTheme';
10
+ import { Text } from '../../../typography/public';
11
+ import { resolveExplorerSelection } from '../../application/resolveExplorerSelection';
12
+
13
+ /*** Single canonical Explorer implementation for media and file catalogue presentation. */
14
+ export const Explorer = withZoraThemeScope(ExplorerInner);
15
+
16
+ /*** Presents provider-neutral asset tiles with controlled or uncontrolled selection. */
17
+ function ExplorerInner({
18
+ items,
19
+ selectedIds,
20
+ defaultSelectedIds = [],
21
+ selectionMode = 'single',
22
+ onSelectionChange,
23
+ onActivate,
24
+ width,
25
+ height,
26
+ tileSize = 120,
27
+ zoom = 1,
28
+ loading = false,
29
+ errorText,
30
+ emptyText = 'No items',
31
+ disabled = false,
32
+ readOnly = false,
33
+ interactionPolicy,
34
+ testID,
35
+ }: ExplorerProps) {
36
+ const { theme } = useZoraTheme();
37
+ const [internalSelectedIds, setInternalSelectedIds] =
38
+ React.useState<readonly string[]>(defaultSelectedIds);
39
+ const anchorId = React.useRef<string | null>(null);
40
+ const effectiveSelectedIds = selectedIds ?? internalSelectedIds;
41
+ const itemLookup = React.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
42
+ const ids = items.filter((item) => !item.disabled).map((item) => item.id);
43
+ const selected = new Set(effectiveSelectedIds);
44
+ const passive = interactionPolicy === 'passive' || disabled || readOnly;
45
+
46
+ const select = (item: ExplorerItem, intent: 'replace' | 'toggle' | 'range') => {
47
+ if (passive || item.disabled) return;
48
+ const next = resolveExplorerSelection(
49
+ ids,
50
+ effectiveSelectedIds,
51
+ item.id,
52
+ anchorId.current,
53
+ intent,
54
+ selectionMode,
55
+ );
56
+ if (intent !== 'range') anchorId.current = item.id;
57
+ if (selectedIds === undefined) setInternalSelectedIds(next);
58
+ onSelectionChange?.({ selectedIds: next });
59
+ };
60
+
61
+ const renderTile = (tile: { readonly id: string }) => {
62
+ const item = itemLookup.get(tile.id);
63
+ if (!item) return null;
64
+ const isSelected = selected.has(item.id);
65
+ const canInteract = !passive && !item.disabled;
66
+ return (
67
+ <NativePressable
68
+ accessibilityLabel={item.name}
69
+ accessibilityRole="button"
70
+ accessibilityState={{ selected: isSelected, disabled: !canInteract }}
71
+ disabled={!canInteract}
72
+ onLongPress={() => select(item, 'toggle')}
73
+ onPress={(event) => {
74
+ const intent = resolveExplorerPressIntent(event.nativeEvent);
75
+ select(item, intent);
76
+ if (selectionMode === 'single' && intent === 'replace') {
77
+ onActivate?.({ id: item.id });
78
+ }
79
+ }}
80
+ style={{
81
+ flex: 1,
82
+ overflow: 'hidden',
83
+ borderRadius: 8,
84
+ borderWidth: isSelected ? 2 : 1,
85
+ borderColor: isSelected ? theme.colors.primary : theme.semantics.neutral.divider,
86
+ backgroundColor: theme.semantics.neutral.surface,
87
+ padding: 8,
88
+ gap: 4,
89
+ }}
90
+ testID={`explorer-item-${item.id}`}
91
+ >
92
+ <NativeView style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
93
+ {item.thumbnailUri ? (
94
+ <Image
95
+ accessibilityLabel={item.name}
96
+ aspectRatio={1}
97
+ source={item.thumbnailUri}
98
+ width="100%"
99
+ />
100
+ ) : (
101
+ <Icon name={item.kind === 'folder' ? 'folder-outline' : 'document-outline'} size={32} />
102
+ )}
103
+ </NativeView>
104
+ <Text numberOfLines={1} variant="caption">
105
+ {item.name}
106
+ </Text>
107
+ </NativePressable>
108
+ );
109
+ };
110
+
111
+ if (errorText) return <Text testID={testID}>{errorText}</Text>;
112
+ if (loading) return <Text testID={testID}>Loading…</Text>;
113
+ if (items.length === 0) return <Text testID={testID}>{emptyText}</Text>;
114
+
115
+ return (
116
+ <TileGrid
117
+ height={height}
118
+ interactionPolicy={interactionPolicy}
119
+ items={items}
120
+ renderItem={renderTile}
121
+ testID={testID}
122
+ tileSize={tileSize}
123
+ width={width}
124
+ zoom={zoom}
125
+ />
126
+ );
127
+ }
128
+
129
+ /*** Normalize platform press modifiers for multi-selection without passing event objects into contracts. */
130
+ function resolveExplorerPressIntent(event: unknown): 'replace' | 'toggle' | 'range' {
131
+ if (typeof event !== 'object' || event === null) return 'replace';
132
+ if ('shiftKey' in event && event.shiftKey === true) return 'range';
133
+ if ('ctrlKey' in event && event.ctrlKey === true) return 'toggle';
134
+ if ('metaKey' in event && event.metaKey === true) return 'toggle';
135
+ return 'replace';
136
+ }
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+
3
+ import type { ExplorerProps } from '../../../../types/explorer';
4
+ import { Explorer } from './Explorer';
5
+
6
+ /*** File and folder presentation using the exact same TileGrid and selection model. */
7
+ export function FileExplorer(props: ExplorerProps) {
8
+ return <Explorer {...props} />;
9
+ }
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+
3
+ import type { ExplorerProps } from '../../../../types/explorer';
4
+ import { Explorer } from './Explorer';
5
+
6
+ /*** Specialized media catalogue presentation sharing the canonical Explorer/TileGrid path. */
7
+ export function MediaExplorer(props: ExplorerProps) {
8
+ return (
9
+ <Explorer
10
+ {...props}
11
+ items={props.items.filter(
12
+ (item) => item.kind === 'image' || item.kind === 'video' || item.kind === 'audio',
13
+ )}
14
+ />
15
+ );
16
+ }
@@ -0,0 +1,35 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+
3
+ import { resolveExplorerSelection } from './resolveExplorerSelection';
4
+
5
+ const ordered = ['a', 'b', 'c', 'd', 'e'];
6
+
7
+ describe('Explorer selection', () => {
8
+ test('supports single selection', () => {
9
+ expect(resolveExplorerSelection(ordered, ['a'], 'c', 'a', 'toggle', 'single')).toEqual(['c']);
10
+ });
11
+ test('supports toggle and deselect in multi mode', () => {
12
+ expect(resolveExplorerSelection(ordered, ['a'], 'b', 'a', 'toggle', 'multi')).toEqual([
13
+ 'a',
14
+ 'b',
15
+ ]);
16
+ expect(resolveExplorerSelection(ordered, ['a', 'b'], 'a', 'a', 'toggle', 'multi')).toEqual([
17
+ 'b',
18
+ ]);
19
+ });
20
+ test('supports contiguous range regardless of direction', () => {
21
+ expect(resolveExplorerSelection(ordered, ['a'], 'd', 'b', 'range', 'multi')).toEqual([
22
+ 'b',
23
+ 'c',
24
+ 'd',
25
+ ]);
26
+ expect(resolveExplorerSelection(ordered, ['a'], 'b', 'd', 'range', 'multi')).toEqual([
27
+ 'b',
28
+ 'c',
29
+ 'd',
30
+ ]);
31
+ });
32
+ test('ignores targets absent from catalogue', () => {
33
+ expect(resolveExplorerSelection(ordered, ['a'], 'z', 'a', 'replace', 'multi')).toEqual(['a']);
34
+ });
35
+ });
@@ -0,0 +1,29 @@
1
+ import { applySelectionIntent } from '@ankhorage/utility/selection';
2
+
3
+ import type { ExplorerSelectionMode } from '../../../types/explorer';
4
+
5
+ /***
6
+ * Resolve selection against ordered stable identities; shift-range extends from the last anchor.
7
+ * Range may replace or extend a multi-selection, but never affects the underlying catalogue.
8
+ */
9
+ export function resolveExplorerSelection(
10
+ orderedIds: readonly string[],
11
+ currentIds: readonly string[],
12
+ targetId: string,
13
+ anchorId: string | null,
14
+ intent: 'replace' | 'toggle' | 'range',
15
+ mode: ExplorerSelectionMode,
16
+ ): readonly string[] {
17
+ const targetIndex = orderedIds.indexOf(targetId);
18
+ if (targetIndex < 0) return currentIds;
19
+ if (mode === 'single' || intent === 'replace')
20
+ return applySelectionIntent(currentIds, targetId, 'replace');
21
+ if (intent === 'toggle') {
22
+ return applySelectionIntent(currentIds, targetId, 'toggle');
23
+ }
24
+ const anchorIndex = anchorId === null ? -1 : orderedIds.indexOf(anchorId);
25
+ if (anchorIndex < 0) return [targetId];
26
+ const start = Math.min(anchorIndex, targetIndex);
27
+ const end = Math.max(anchorIndex, targetIndex);
28
+ return orderedIds.slice(start, end + 1);
29
+ }
@@ -0,0 +1,94 @@
1
+ import type { ZoraComponentMeta } from '../../types/authoring';
2
+
3
+ const explorerProps = {
4
+ items: {
5
+ type: 'array',
6
+ category: 'Data',
7
+ itemSchema: [
8
+ { key: 'id', schema: { type: 'string', category: 'Identity' } },
9
+ {
10
+ key: 'kind',
11
+ schema: {
12
+ type: 'enum',
13
+ category: 'Data',
14
+ enum: ['image', 'video', 'audio', 'document', 'file', 'folder'],
15
+ },
16
+ },
17
+ { key: 'name', schema: { type: 'string', category: 'Content' } },
18
+ { key: 'uri', schema: { type: 'string', category: 'Data' } },
19
+ { key: 'thumbnailUri', schema: { type: 'string', category: 'Media' } },
20
+ { key: 'contentType', schema: { type: 'string', category: 'Data' } },
21
+ { key: 'sizeBytes', schema: { type: 'number', category: 'Data' } },
22
+ { key: 'providerId', schema: { type: 'string', category: 'Identity' } },
23
+ { key: 'disabled', schema: { type: 'boolean', category: 'State' } },
24
+ ],
25
+ },
26
+ selectionMode: {
27
+ type: 'enum',
28
+ category: 'Selection',
29
+ enum: ['single', 'multi'],
30
+ default: 'single',
31
+ },
32
+ selectedIds: { type: 'array', category: 'Selection' },
33
+ tileSize: { type: 'number', category: 'Layout', default: 120 },
34
+ height: { type: 'number', category: 'Layout', default: 440 },
35
+ zoom: { type: 'number', category: 'Layout', default: 1 },
36
+ loading: { type: 'boolean', category: 'State' },
37
+ errorText: { type: 'string', category: 'State' },
38
+ emptyText: { type: 'string', category: 'Content' },
39
+ disabled: { type: 'boolean', category: 'State' },
40
+ readOnly: { type: 'boolean', category: 'State' },
41
+ onSelectionChange: { type: 'action', category: 'Events' },
42
+ onActivate: { type: 'action', category: 'Events' },
43
+ } as const;
44
+
45
+ const explorerEvents = {
46
+ selectionChange: {
47
+ label: 'Selection change',
48
+ eventType: 'explorer.selectionChange',
49
+ payloadFields: [{ path: 'selectedIds', type: 'unknown' }],
50
+ },
51
+ activate: {
52
+ label: 'Activate item',
53
+ eventType: 'explorer.activate',
54
+ payloadFields: [{ path: 'id', type: 'string' }],
55
+ },
56
+ } as const;
57
+
58
+ /** Framework-bound Explorer is a composition primitive, not a separate manifest shape. */
59
+ export const explorerMeta = {
60
+ name: 'Explorer',
61
+ category: 'pattern',
62
+ directManifestNode: false,
63
+ note: 'Shared code-only Explorer composition; MediaExplorer and FileExplorer own manifest representation.',
64
+ allowedChildren: [],
65
+ props: {},
66
+ } as const satisfies ZoraComponentMeta;
67
+
68
+ export const mediaExplorerMeta = {
69
+ name: 'MediaExplorer',
70
+ category: 'pattern',
71
+ description: 'Virtualized media library with normalized selection and activation events.',
72
+ directManifestNode: true,
73
+ allowedChildren: [],
74
+ blueprint: {
75
+ label: 'Media explorer',
76
+ defaultProps: { items: [], selectionMode: 'single', tileSize: 120 },
77
+ },
78
+ events: explorerEvents,
79
+ props: explorerProps,
80
+ } as const satisfies ZoraComponentMeta;
81
+
82
+ export const fileExplorerMeta = {
83
+ name: 'FileExplorer',
84
+ category: 'pattern',
85
+ description: 'Virtualized file and folder collection with normalized selection and activation.',
86
+ directManifestNode: true,
87
+ allowedChildren: [],
88
+ blueprint: {
89
+ label: 'File explorer',
90
+ defaultProps: { items: [], selectionMode: 'single', tileSize: 120 },
91
+ },
92
+ events: explorerEvents,
93
+ props: explorerProps,
94
+ } as const satisfies ZoraComponentMeta;
@@ -0,0 +1,12 @@
1
+ export type {
2
+ ExplorerActivateEvent,
3
+ ExplorerItem,
4
+ ExplorerItemKind,
5
+ ExplorerProps,
6
+ ExplorerSelectionChangeEvent,
7
+ ExplorerSelectionMode,
8
+ } from '../../types/explorer';
9
+ export { Explorer } from './adapters/inbound/Explorer';
10
+ export { FileExplorer } from './adapters/inbound/FileExplorer';
11
+ export { MediaExplorer } from './adapters/inbound/MediaExplorer';
12
+ export { resolveExplorerSelection } from './application/resolveExplorerSelection';
@@ -0,0 +1,95 @@
1
+ import { getVisibleGridItems, type GridViewport, worldToViewport } from '@ankhorage/grid-view';
2
+ import React from 'react';
3
+ import { ScrollView as NativeScrollView, View as NativeView } from 'react-native';
4
+
5
+ import type { GridViewProps } from '../../../../types/grid-view';
6
+
7
+ /***
8
+ * Renders world-positioned items on native and web using the canonical viewport/culling engine.
9
+ *
10
+ * This first renderer uses nested native scroll regions. Only visible items are mounted;
11
+ * logical cells and invisible elements are never rendered.
12
+ */
13
+ export function GridView({
14
+ items,
15
+ contentWidth,
16
+ contentHeight,
17
+ width,
18
+ height,
19
+ zoom = 1,
20
+ overscanPixels = 160,
21
+ interactionPolicy,
22
+ onViewportChange,
23
+ renderItem,
24
+ testID,
25
+ }: GridViewProps) {
26
+ const [scrollX, setScrollX] = React.useState(0);
27
+ const [scrollY, setScrollY] = React.useState(0);
28
+ const scale = Math.max(0.01, zoom);
29
+ const viewport = React.useMemo<GridViewport>(
30
+ () => ({
31
+ width,
32
+ height,
33
+ offsetX: scrollX / scale,
34
+ offsetY: scrollY / scale,
35
+ pixelsPerUnitX: scale,
36
+ pixelsPerUnitY: scale,
37
+ }),
38
+ [height, scale, scrollX, scrollY, width],
39
+ );
40
+ const visibleItems = React.useMemo(
41
+ () => getVisibleGridItems(items, viewport, overscanPixels),
42
+ [items, overscanPixels, viewport],
43
+ );
44
+
45
+ React.useEffect(() => {
46
+ onViewportChange?.(viewport);
47
+ }, [onViewportChange, viewport]);
48
+
49
+ return (
50
+ <NativeScrollView
51
+ horizontal
52
+ scrollEnabled={interactionPolicy !== 'passive'}
53
+ scrollEventThrottle={32}
54
+ showsHorizontalScrollIndicator
55
+ style={{ width, height }}
56
+ testID={testID}
57
+ onScroll={(event) => setScrollX(event.nativeEvent.contentOffset.x)}
58
+ >
59
+ <NativeScrollView
60
+ scrollEnabled={interactionPolicy !== 'passive'}
61
+ scrollEventThrottle={32}
62
+ showsVerticalScrollIndicator
63
+ style={{ width: contentWidth * scale, height }}
64
+ onScroll={(event) => setScrollY(event.nativeEvent.contentOffset.y)}
65
+ >
66
+ <NativeView style={{ width: contentWidth * scale, height: contentHeight * scale }}>
67
+ {visibleItems.map((item) => {
68
+ const position = worldToViewport(
69
+ { x: item.x, y: item.y },
70
+ {
71
+ ...viewport,
72
+ offsetX: 0,
73
+ offsetY: 0,
74
+ },
75
+ );
76
+ return (
77
+ <NativeView
78
+ key={item.id}
79
+ style={{
80
+ position: 'absolute',
81
+ left: position.x,
82
+ top: position.y,
83
+ width: item.width * scale,
84
+ height: item.height * scale,
85
+ }}
86
+ >
87
+ {renderItem(item)}
88
+ </NativeView>
89
+ );
90
+ })}
91
+ </NativeView>
92
+ </NativeScrollView>
93
+ </NativeScrollView>
94
+ );
95
+ }
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { View as NativeView } from 'react-native';
3
+
4
+ import type { TileGridProps } from '../../../../types/grid-view';
5
+ import { layoutTileGrid } from '../../application/layoutTileGrid';
6
+ import { GridView } from './GridView';
7
+
8
+ /*** Composes a responsive, virtualized tile presentation over the generic GridView renderer. */
9
+ export function TileGrid({
10
+ items,
11
+ width,
12
+ height = 440,
13
+ tileSize = 120,
14
+ gap = 12,
15
+ zoom = 1,
16
+ overscanPixels,
17
+ renderItem,
18
+ interactionPolicy,
19
+ testID,
20
+ }: TileGridProps) {
21
+ const [measuredWidth, setMeasuredWidth] = React.useState(0);
22
+ const resolvedWidth = width ?? measuredWidth;
23
+ const layout = React.useMemo(
24
+ () => layoutTileGrid(items, resolvedWidth, tileSize, gap, zoom),
25
+ [items, resolvedWidth, tileSize, gap, zoom],
26
+ );
27
+ const itemLookup = React.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
28
+
29
+ return (
30
+ <NativeView
31
+ onLayout={(event) => setMeasuredWidth(event.nativeEvent.layout.width)}
32
+ style={{ width, height, overflow: 'hidden' }}
33
+ testID={testID}
34
+ >
35
+ {resolvedWidth > 0 ? (
36
+ <GridView
37
+ contentHeight={layout.height}
38
+ contentWidth={Math.max(resolvedWidth / zoom, layout.width)}
39
+ height={height}
40
+ interactionPolicy={interactionPolicy}
41
+ items={layout.items}
42
+ overscanPixels={overscanPixels}
43
+ renderItem={(item) => {
44
+ const source = itemLookup.get(item.id);
45
+ return source ? renderItem(source) : null;
46
+ }}
47
+ width={resolvedWidth}
48
+ zoom={zoom}
49
+ />
50
+ ) : null}
51
+ </NativeView>
52
+ );
53
+ }