entangle-ui 0.10.0 → 0.12.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 (589) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +7 -5
  3. package/dist/esm/assets/src/components/controls/Select/{Select.css.ts.vanilla-oZnFUorL.css → Select.css.ts.vanilla-Cpu2BvWL.css} +3 -0
  4. package/dist/esm/assets/src/components/controls/Slider/{Slider.css.ts.vanilla-Cqm3fQ0S.css → Slider.css.ts.vanilla-CLf_RC0A.css} +50 -47
  5. package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertyPanel.css.ts.vanilla-RYv_XgOu.css → PropertyPanel.css.ts.vanilla-Dpr_k5I3.css} +4 -1
  6. package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertyRow.css.ts.vanilla-C3YZnnHb.css → PropertyRow.css.ts.vanilla-pq1Uhd2a.css} +15 -8
  7. package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertySection.css.ts.vanilla-DK12opZc.css → PropertySection.css.ts.vanilla-6MWWAqyd.css} +50 -32
  8. package/dist/esm/assets/src/components/navigation/Menu/{Menu.css.ts.vanilla-B5iVe5S2.css → Menu.css.ts.vanilla-Bhh1L5yl.css} +14 -11
  9. package/dist/esm/assets/src/components/primitives/Tooltip/{Tooltip.css.ts.vanilla-CrEFoLBX.css → Tooltip.css.ts.vanilla-BqaiGrFQ.css} +12 -9
  10. package/dist/esm/assets/src/components/shell/AppShell/{AppShell.css.ts.vanilla-BYmtU0O_.css → AppShell.css.ts.vanilla-BLK2-DRL.css} +1 -0
  11. package/dist/esm/assets/src/components/shell/MenuBar/{MenuBar.css.ts.vanilla-TgPcl4yA.css → MenuBar.css.ts.vanilla-Dt3w4f-q.css} +18 -6
  12. package/dist/esm/components/Icons/AddIcon.js.map +1 -1
  13. package/dist/esm/components/Icons/AiChatIcon.js.map +1 -1
  14. package/dist/esm/components/Icons/AiSparklesIcon.js.map +1 -1
  15. package/dist/esm/components/Icons/ArchiveIcon.js.map +1 -1
  16. package/dist/esm/components/Icons/ArrowDownIcon.js.map +1 -1
  17. package/dist/esm/components/Icons/ArrowLeftIcon.js.map +1 -1
  18. package/dist/esm/components/Icons/ArrowRightIcon.js.map +1 -1
  19. package/dist/esm/components/Icons/ArrowUpIcon.js.map +1 -1
  20. package/dist/esm/components/Icons/BookmarkIcon.js.map +1 -1
  21. package/dist/esm/components/Icons/BugIcon.js.map +1 -1
  22. package/dist/esm/components/Icons/BuildingIcon.js.map +1 -1
  23. package/dist/esm/components/Icons/CalendarIcon.js.map +1 -1
  24. package/dist/esm/components/Icons/CameraIcon.js +31 -0
  25. package/dist/esm/components/Icons/CameraIcon.js.map +1 -0
  26. package/dist/esm/components/Icons/CheckIcon.js.map +1 -1
  27. package/dist/esm/components/Icons/ChevronDownIcon.js.map +1 -1
  28. package/dist/esm/components/Icons/ChevronLeftIcon.js.map +1 -1
  29. package/dist/esm/components/Icons/ChevronRightIcon.js.map +1 -1
  30. package/dist/esm/components/Icons/ChevronUpIcon.js.map +1 -1
  31. package/dist/esm/components/Icons/CircleIcon.js.map +1 -1
  32. package/dist/esm/components/Icons/ClockIcon.js.map +1 -1
  33. package/dist/esm/components/Icons/CloseIcon.js.map +1 -1
  34. package/dist/esm/components/Icons/CloudUploadIcon.js.map +1 -1
  35. package/dist/esm/components/Icons/CodeIcon.js.map +1 -1
  36. package/dist/esm/components/Icons/CopyIcon.js.map +1 -1
  37. package/dist/esm/components/Icons/CubeIcon.js +31 -0
  38. package/dist/esm/components/Icons/CubeIcon.js.map +1 -0
  39. package/dist/esm/components/Icons/CutIcon.js.map +1 -1
  40. package/dist/esm/components/Icons/DotsHorizontalIcon.js.map +1 -1
  41. package/dist/esm/components/Icons/DotsVerticalIcon.js.map +1 -1
  42. package/dist/esm/components/Icons/DownloadIcon.js.map +1 -1
  43. package/dist/esm/components/Icons/EditIcon.js.map +1 -1
  44. package/dist/esm/components/Icons/ErrorIcon.js.map +1 -1
  45. package/dist/esm/components/Icons/ExternalLinkIcon.js.map +1 -1
  46. package/dist/esm/components/Icons/EyeDropperIcon.js.map +1 -1
  47. package/dist/esm/components/Icons/EyeIcon.js.map +1 -1
  48. package/dist/esm/components/Icons/FileTextIcon.js.map +1 -1
  49. package/dist/esm/components/Icons/FilterIcon.js.map +1 -1
  50. package/dist/esm/components/Icons/FirstIcon.js.map +1 -1
  51. package/dist/esm/components/Icons/FolderCogIcon.js.map +1 -1
  52. package/dist/esm/components/Icons/FolderIcon.js.map +1 -1
  53. package/dist/esm/components/Icons/FolderOpenIcon.js.map +1 -1
  54. package/dist/esm/components/Icons/FullscreenIcon.js.map +1 -1
  55. package/dist/esm/components/Icons/GitBranchIcon.js.map +1 -1
  56. package/dist/esm/components/Icons/GridIcon.js.map +1 -1
  57. package/dist/esm/components/Icons/HeartIcon.js.map +1 -1
  58. package/dist/esm/components/Icons/HelpIcon.js.map +1 -1
  59. package/dist/esm/components/Icons/HomeIcon.js.map +1 -1
  60. package/dist/esm/components/Icons/ImageIcon.js.map +1 -1
  61. package/dist/esm/components/Icons/InfoIcon.js.map +1 -1
  62. package/dist/esm/components/Icons/LastIcon.js.map +1 -1
  63. package/dist/esm/components/Icons/LinkIcon.js.map +1 -1
  64. package/dist/esm/components/Icons/ListIcon.js.map +1 -1
  65. package/dist/esm/components/Icons/LockIcon.js.map +1 -1
  66. package/dist/esm/components/Icons/MaximizeIcon.js.map +1 -1
  67. package/dist/esm/components/Icons/MenuIcon.js.map +1 -1
  68. package/dist/esm/components/Icons/MinimizeIcon.js.map +1 -1
  69. package/dist/esm/components/Icons/MinusIcon.js.map +1 -1
  70. package/dist/esm/components/Icons/OrbitIcon.js +31 -0
  71. package/dist/esm/components/Icons/OrbitIcon.js.map +1 -0
  72. package/dist/esm/components/Icons/PasteIcon.js.map +1 -1
  73. package/dist/esm/components/Icons/PauseIcon.js.map +1 -1
  74. package/dist/esm/components/Icons/PinIcon.js.map +1 -1
  75. package/dist/esm/components/Icons/PlayIcon.js.map +1 -1
  76. package/dist/esm/components/Icons/RedoIcon.js.map +1 -1
  77. package/dist/esm/components/Icons/RefreshIcon.js.map +1 -1
  78. package/dist/esm/components/Icons/RobotIcon.js.map +1 -1
  79. package/dist/esm/components/Icons/RotateIcon.js +32 -0
  80. package/dist/esm/components/Icons/RotateIcon.js.map +1 -0
  81. package/dist/esm/components/Icons/SaveIcon.js.map +1 -1
  82. package/dist/esm/components/Icons/SearchIcon.js.map +1 -1
  83. package/dist/esm/components/Icons/SendIcon.js.map +1 -1
  84. package/dist/esm/components/Icons/SettingsIcon.js.map +1 -1
  85. package/dist/esm/components/Icons/SortIcon.js.map +1 -1
  86. package/dist/esm/components/Icons/SpinIcon.js +32 -0
  87. package/dist/esm/components/Icons/SpinIcon.js.map +1 -0
  88. package/dist/esm/components/Icons/StarIcon.js.map +1 -1
  89. package/dist/esm/components/Icons/StopIcon.js.map +1 -1
  90. package/dist/esm/components/Icons/SuccessIcon.js.map +1 -1
  91. package/dist/esm/components/Icons/TagIcon.js.map +1 -1
  92. package/dist/esm/components/Icons/TangentAlignedIcon.js.map +1 -1
  93. package/dist/esm/components/Icons/TangentAutoIcon.js.map +1 -1
  94. package/dist/esm/components/Icons/TangentFreeIcon.js.map +1 -1
  95. package/dist/esm/components/Icons/TangentLinearIcon.js.map +1 -1
  96. package/dist/esm/components/Icons/TangentMirroredIcon.js.map +1 -1
  97. package/dist/esm/components/Icons/TangentStepIcon.js.map +1 -1
  98. package/dist/esm/components/Icons/TerminalIcon.js.map +1 -1
  99. package/dist/esm/components/Icons/TrashIcon.js.map +1 -1
  100. package/dist/esm/components/Icons/UndoIcon.js.map +1 -1
  101. package/dist/esm/components/Icons/UnlinkIcon.js.map +1 -1
  102. package/dist/esm/components/Icons/UnlockIcon.js.map +1 -1
  103. package/dist/esm/components/Icons/UploadIcon.js.map +1 -1
  104. package/dist/esm/components/Icons/UserIcon.js.map +1 -1
  105. package/dist/esm/components/Icons/UsersIcon.js.map +1 -1
  106. package/dist/esm/components/Icons/WarningIcon.js.map +1 -1
  107. package/dist/esm/components/Icons/ZoomFitIcon.js +32 -0
  108. package/dist/esm/components/Icons/ZoomFitIcon.js.map +1 -0
  109. package/dist/esm/components/Icons/ZoomInIcon.js.map +1 -1
  110. package/dist/esm/components/Icons/ZoomOutIcon.js.map +1 -1
  111. package/dist/esm/components/controls/CartesianPicker/CartesianPicker.js.map +1 -1
  112. package/dist/esm/components/controls/CartesianPicker/useCartesianInteraction.js.map +1 -1
  113. package/dist/esm/components/controls/CartesianPicker/useCartesianRenderer.js.map +1 -1
  114. package/dist/esm/components/controls/ColorPicker/AlphaSlider.js.map +1 -1
  115. package/dist/esm/components/controls/ColorPicker/ColorArea.js.map +1 -1
  116. package/dist/esm/components/controls/ColorPicker/ColorInputs.js.map +1 -1
  117. package/dist/esm/components/controls/ColorPicker/ColorPalette.js.map +1 -1
  118. package/dist/esm/components/controls/ColorPicker/ColorPicker.js.map +1 -1
  119. package/dist/esm/components/controls/ColorPicker/ColorPresets.js.map +1 -1
  120. package/dist/esm/components/controls/ColorPicker/ColorSwatch.js.map +1 -1
  121. package/dist/esm/components/controls/ColorPicker/EyeDropper.js.map +1 -1
  122. package/dist/esm/components/controls/ColorPicker/HueSlider.js.map +1 -1
  123. package/dist/esm/components/controls/ColorPicker/colorUtils.js.map +1 -1
  124. package/dist/esm/components/controls/ColorPicker/palettes/material.js.map +1 -1
  125. package/dist/esm/components/controls/ColorPicker/palettes/professional.js.map +1 -1
  126. package/dist/esm/components/controls/ColorPicker/palettes/tailwind.js.map +1 -1
  127. package/dist/esm/components/controls/ColorPicker/useColor.js.map +1 -1
  128. package/dist/esm/components/controls/Combobox/Combobox.js.map +1 -1
  129. package/dist/esm/components/controls/CurveEditor/CurveCanvas.js.map +1 -1
  130. package/dist/esm/components/controls/CurveEditor/CurveEditor.js.map +1 -1
  131. package/dist/esm/components/controls/CurveEditor/CurveToolbar.js.map +1 -1
  132. package/dist/esm/components/controls/CurveEditor/curvePresets.js.map +1 -1
  133. package/dist/esm/components/controls/CurveEditor/curveUtils.js.map +1 -1
  134. package/dist/esm/components/controls/CurveEditor/useCurveInteraction.js.map +1 -1
  135. package/dist/esm/components/controls/CurveEditor/useCurveRenderer.js.map +1 -1
  136. package/dist/esm/components/controls/FileTree/FileTree.js +7 -1
  137. package/dist/esm/components/controls/FileTree/FileTree.js.map +1 -1
  138. package/dist/esm/components/controls/FileTree/fileTreeIcons.js.map +1 -1
  139. package/dist/esm/components/controls/FileTree/fileTreeLabels.js.map +1 -1
  140. package/dist/esm/components/controls/FileTree/useFileTreeDrop.js +1 -1
  141. package/dist/esm/components/controls/FileTree/useFileTreeDrop.js.map +1 -1
  142. package/dist/esm/components/controls/FileUploader/FileUploader.js.map +1 -1
  143. package/dist/esm/components/controls/MultiSelect/MultiSelect.js.map +1 -1
  144. package/dist/esm/components/controls/NumberInput/NumberInput.js.map +1 -1
  145. package/dist/esm/components/controls/NumberInput/useNumberInput.js.map +1 -1
  146. package/dist/esm/components/controls/Select/Select.css.js +1 -1
  147. package/dist/esm/components/controls/Select/Select.js +15 -7
  148. package/dist/esm/components/controls/Select/Select.js.map +1 -1
  149. package/dist/esm/components/controls/Slider/Slider.css.js +10 -11
  150. package/dist/esm/components/controls/Slider/Slider.css.js.map +1 -1
  151. package/dist/esm/components/controls/Slider/Slider.js +40 -7
  152. package/dist/esm/components/controls/Slider/Slider.js.map +1 -1
  153. package/dist/esm/components/controls/TagInput/TagInput.js.map +1 -1
  154. package/dist/esm/components/controls/TreeView/TreeNode.js +6 -0
  155. package/dist/esm/components/controls/TreeView/TreeNode.js.map +1 -1
  156. package/dist/esm/components/controls/TreeView/TreeView.js.map +1 -1
  157. package/dist/esm/components/controls/TreeView/useTreeState.js.map +1 -1
  158. package/dist/esm/components/controls/VectorInput/VectorInput.js +6 -0
  159. package/dist/esm/components/controls/VectorInput/VectorInput.js.map +1 -1
  160. package/dist/esm/components/data/DataTable/DataTable.js.map +1 -1
  161. package/dist/esm/components/editor/AssetBrowser/AssetBrowser.js.map +1 -1
  162. package/dist/esm/components/editor/AssetBrowser/AssetBrowserAnnouncementLive.js.map +1 -1
  163. package/dist/esm/components/editor/AssetBrowser/AssetBrowserBreadcrumbs.js.map +1 -1
  164. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContent.js +6 -0
  165. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContent.js.map +1 -1
  166. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContext.js.map +1 -1
  167. package/dist/esm/components/editor/AssetBrowser/AssetBrowserContextMenu.js.map +1 -1
  168. package/dist/esm/components/editor/AssetBrowser/AssetBrowserDefaultMenus.js +6 -0
  169. package/dist/esm/components/editor/AssetBrowser/AssetBrowserDefaultMenus.js.map +1 -1
  170. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGrid.js +1 -1
  171. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGrid.js.map +1 -1
  172. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGridItem.js +6 -0
  173. package/dist/esm/components/editor/AssetBrowser/AssetBrowserGridItem.js.map +1 -1
  174. package/dist/esm/components/editor/AssetBrowser/AssetBrowserList.js +6 -0
  175. package/dist/esm/components/editor/AssetBrowser/AssetBrowserList.js.map +1 -1
  176. package/dist/esm/components/editor/AssetBrowser/AssetBrowserRenameField.js.map +1 -1
  177. package/dist/esm/components/editor/AssetBrowser/AssetBrowserSidebar.js.map +1 -1
  178. package/dist/esm/components/editor/AssetBrowser/AssetBrowserStatusBar.js.map +1 -1
  179. package/dist/esm/components/editor/AssetBrowser/AssetBrowserStore.js.map +1 -1
  180. package/dist/esm/components/editor/AssetBrowser/AssetBrowserSurface.js +6 -0
  181. package/dist/esm/components/editor/AssetBrowser/AssetBrowserSurface.js.map +1 -1
  182. package/dist/esm/components/editor/AssetBrowser/AssetBrowserToolbar.js +6 -0
  183. package/dist/esm/components/editor/AssetBrowser/AssetBrowserToolbar.js.map +1 -1
  184. package/dist/esm/components/editor/AssetBrowser/assetBrowserFilter.js.map +1 -1
  185. package/dist/esm/components/editor/AssetBrowser/assetBrowserFormat.js.map +1 -1
  186. package/dist/esm/components/editor/AssetBrowser/assetBrowserGeometry.js.map +1 -1
  187. package/dist/esm/components/editor/AssetBrowser/assetBrowserKeyboard.js.map +1 -1
  188. package/dist/esm/components/editor/AssetBrowser/assetBrowserLabels.js.map +1 -1
  189. package/dist/esm/components/editor/AssetBrowser/slots.js.map +1 -1
  190. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserAnnouncement.js.map +1 -1
  191. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserHandle.js +1 -1
  192. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserHandle.js.map +1 -1
  193. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserViewState.js +1 -1
  194. package/dist/esm/components/editor/AssetBrowser/useAssetBrowserViewState.js.map +1 -1
  195. package/dist/esm/components/editor/AssetBrowser/useAssetDnd.js +1 -1
  196. package/dist/esm/components/editor/AssetBrowser/useAssetDnd.js.map +1 -1
  197. package/dist/esm/components/editor/AssetBrowser/useAssetGridKeyboardNav.js.map +1 -1
  198. package/dist/esm/components/editor/AssetBrowser/useAssetGridVirtualizer.js +1 -1
  199. package/dist/esm/components/editor/AssetBrowser/useAssetGridVirtualizer.js.map +1 -1
  200. package/dist/esm/components/editor/AssetBrowser/useAssetMarqueeGesture.js +1 -1
  201. package/dist/esm/components/editor/AssetBrowser/useAssetMarqueeGesture.js.map +1 -1
  202. package/dist/esm/components/editor/AssetBrowser/useAssetMutationKeyboard.js +1 -1
  203. package/dist/esm/components/editor/AssetBrowser/useAssetMutationKeyboard.js.map +1 -1
  204. package/dist/esm/components/editor/AssetBrowser/useAssetMutations.js +1 -1
  205. package/dist/esm/components/editor/AssetBrowser/useAssetMutations.js.map +1 -1
  206. package/dist/esm/components/editor/AssetBrowser/useAssetNavigation.js +1 -1
  207. package/dist/esm/components/editor/AssetBrowser/useAssetNavigation.js.map +1 -1
  208. package/dist/esm/components/editor/AssetBrowser/useAssetSelectionController.js +1 -1
  209. package/dist/esm/components/editor/AssetBrowser/useAssetSelectionController.js.map +1 -1
  210. package/dist/esm/components/editor/ChatPanel/ChatActionBar.js.map +1 -1
  211. package/dist/esm/components/editor/ChatPanel/ChatAttachment.js.map +1 -1
  212. package/dist/esm/components/editor/ChatPanel/ChatBubble.js.map +1 -1
  213. package/dist/esm/components/editor/ChatPanel/ChatCodeBlock.js +6 -0
  214. package/dist/esm/components/editor/ChatPanel/ChatCodeBlock.js.map +1 -1
  215. package/dist/esm/components/editor/ChatPanel/ChatContextChip.js.map +1 -1
  216. package/dist/esm/components/editor/ChatPanel/ChatEmptyState.js.map +1 -1
  217. package/dist/esm/components/editor/ChatPanel/ChatIcons.js.map +1 -1
  218. package/dist/esm/components/editor/ChatPanel/ChatInput.js +6 -0
  219. package/dist/esm/components/editor/ChatPanel/ChatInput.js.map +1 -1
  220. package/dist/esm/components/editor/ChatPanel/ChatInputToolbar.js.map +1 -1
  221. package/dist/esm/components/editor/ChatPanel/ChatMarkdownRenderer.js.map +1 -1
  222. package/dist/esm/components/editor/ChatPanel/ChatMessage.js +6 -0
  223. package/dist/esm/components/editor/ChatPanel/ChatMessage.js.map +1 -1
  224. package/dist/esm/components/editor/ChatPanel/ChatMessageList.js.map +1 -1
  225. package/dist/esm/components/editor/ChatPanel/ChatPanel.js.map +1 -1
  226. package/dist/esm/components/editor/ChatPanel/ChatToolCall.js.map +1 -1
  227. package/dist/esm/components/editor/ChatPanel/ChatTypingIndicator.js.map +1 -1
  228. package/dist/esm/components/editor/ChatPanel/useChatInput.js.map +1 -1
  229. package/dist/esm/components/editor/ChatPanel/useChatMessages.js.map +1 -1
  230. package/dist/esm/components/editor/ChatPanel/useChatScroll.js.map +1 -1
  231. package/dist/esm/components/editor/Minimap/Minimap.js +1 -1
  232. package/dist/esm/components/editor/Minimap/Minimap.js.map +1 -1
  233. package/dist/esm/components/editor/Minimap/Minimap.types.js.map +1 -1
  234. package/dist/esm/components/editor/Minimap/MinimapContext.js.map +1 -1
  235. package/dist/esm/components/editor/Minimap/MinimapCorner.js.map +1 -1
  236. package/dist/esm/components/editor/Minimap/MinimapFooter.js.map +1 -1
  237. package/dist/esm/components/editor/Minimap/MinimapStore.js.map +1 -1
  238. package/dist/esm/components/editor/Minimap/MinimapTitle.js.map +1 -1
  239. package/dist/esm/components/editor/Minimap/ViewportMinimap.js +1 -1
  240. package/dist/esm/components/editor/Minimap/ViewportMinimap.js.map +1 -1
  241. package/dist/esm/components/editor/Minimap/computeBoundsFromItems.js.map +1 -1
  242. package/dist/esm/components/editor/Minimap/index.js.map +1 -1
  243. package/dist/esm/components/editor/Minimap/minimapCoords.js.map +1 -1
  244. package/dist/esm/components/editor/Minimap/minimapDrawing.js.map +1 -1
  245. package/dist/esm/components/editor/Minimap/minimapHitTest.js.map +1 -1
  246. package/dist/esm/components/editor/Minimap/useMinimapGestures.js +1 -1
  247. package/dist/esm/components/editor/Minimap/useMinimapGestures.js.map +1 -1
  248. package/dist/esm/components/editor/NodeGraph/NodeGraph.js +1 -1
  249. package/dist/esm/components/editor/NodeGraph/NodeGraph.js.map +1 -1
  250. package/dist/esm/components/editor/NodeGraph/NodeGraph.types.js.map +1 -1
  251. package/dist/esm/components/editor/NodeGraph/NodeGraphContext.js.map +1 -1
  252. package/dist/esm/components/editor/NodeGraph/NodeGraphEdgeLabels.js.map +1 -1
  253. package/dist/esm/components/editor/NodeGraph/NodeGraphGroup.js.map +1 -1
  254. package/dist/esm/components/editor/NodeGraph/NodeGraphMinimap.js.map +1 -1
  255. package/dist/esm/components/editor/NodeGraph/NodeGraphNode.js +1 -1
  256. package/dist/esm/components/editor/NodeGraph/NodeGraphNode.js.map +1 -1
  257. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeContext.js.map +1 -1
  258. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeParts.js.map +1 -1
  259. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSection.js +1 -1
  260. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSection.js.map +1 -1
  261. package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSectionContext.js.map +1 -1
  262. package/dist/esm/components/editor/NodeGraph/NodeGraphPin.js.map +1 -1
  263. package/dist/esm/components/editor/NodeGraph/NodeGraphPort.js +1 -1
  264. package/dist/esm/components/editor/NodeGraph/NodeGraphPort.js.map +1 -1
  265. package/dist/esm/components/editor/NodeGraph/NodeGraphPortVisual.js.map +1 -1
  266. package/dist/esm/components/editor/NodeGraph/NodeGraphSlots.js.map +1 -1
  267. package/dist/esm/components/editor/NodeGraph/NodeGraphSpawnPalette.js.map +1 -1
  268. package/dist/esm/components/editor/NodeGraph/NodeGraphStore.js.map +1 -1
  269. package/dist/esm/components/editor/NodeGraph/NodeGraphToolbar.js.map +1 -1
  270. package/dist/esm/components/editor/NodeGraph/createTypeMatchValidator.js.map +1 -1
  271. package/dist/esm/components/editor/NodeGraph/nodeGraphActions.js.map +1 -1
  272. package/dist/esm/components/editor/NodeGraph/nodeGraphDrawing.js.map +1 -1
  273. package/dist/esm/components/editor/NodeGraph/nodeGraphIds.js.map +1 -1
  274. package/dist/esm/components/editor/NodeGraph/nodeGraphMath.js.map +1 -1
  275. package/dist/esm/components/editor/NodeGraph/sortSlots.js.map +1 -1
  276. package/dist/esm/components/editor/NodeGraph/useDragGesture.js.map +1 -1
  277. package/dist/esm/components/editor/NodeGraph/useNodeGraph.js +1 -1
  278. package/dist/esm/components/editor/NodeGraph/useNodeGraph.js.map +1 -1
  279. package/dist/esm/components/editor/NodeGraph/useNodeGraphConnection.js +1 -1
  280. package/dist/esm/components/editor/NodeGraph/useNodeGraphConnection.js.map +1 -1
  281. package/dist/esm/components/editor/NodeGraph/useNodeGraphEdgeInteraction.js +1 -1
  282. package/dist/esm/components/editor/NodeGraph/useNodeGraphEdgeInteraction.js.map +1 -1
  283. package/dist/esm/components/editor/NodeGraph/useNodeGraphGroupDrag.js +1 -1
  284. package/dist/esm/components/editor/NodeGraph/useNodeGraphGroupDrag.js.map +1 -1
  285. package/dist/esm/components/editor/NodeGraph/useNodeGraphKeyboard.js +1 -1
  286. package/dist/esm/components/editor/NodeGraph/useNodeGraphKeyboard.js.map +1 -1
  287. package/dist/esm/components/editor/NodeGraph/useNodeGraphNodeDrag.js +1 -1
  288. package/dist/esm/components/editor/NodeGraph/useNodeGraphNodeDrag.js.map +1 -1
  289. package/dist/esm/components/editor/NodeGraph/useStoreSlice.js.map +1 -1
  290. package/dist/esm/components/editor/PropertyInspector/PropertyGroup.js.map +1 -1
  291. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.css.js +4 -3
  292. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.css.js.map +1 -1
  293. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.js +5 -4
  294. package/dist/esm/components/editor/PropertyInspector/PropertyPanel.js.map +1 -1
  295. package/dist/esm/components/editor/PropertyInspector/PropertyRow.css.js +7 -6
  296. package/dist/esm/components/editor/PropertyInspector/PropertyRow.css.js.map +1 -1
  297. package/dist/esm/components/editor/PropertyInspector/PropertyRow.js +18 -3
  298. package/dist/esm/components/editor/PropertyInspector/PropertyRow.js.map +1 -1
  299. package/dist/esm/components/editor/PropertyInspector/PropertySection.css.js +11 -10
  300. package/dist/esm/components/editor/PropertyInspector/PropertySection.css.js.map +1 -1
  301. package/dist/esm/components/editor/PropertyInspector/PropertySection.js +29 -21
  302. package/dist/esm/components/editor/PropertyInspector/PropertySection.js.map +1 -1
  303. package/dist/esm/components/editor/PropertyInspector/usePropertyUndo.js.map +1 -1
  304. package/dist/esm/components/editor/Timeline/Timeline.js +1 -1
  305. package/dist/esm/components/editor/Timeline/Timeline.js.map +1 -1
  306. package/dist/esm/components/editor/Timeline/Timeline.types.js.map +1 -1
  307. package/dist/esm/components/editor/Timeline/TimelineContext.js.map +1 -1
  308. package/dist/esm/components/editor/Timeline/TimelineFooter.js.map +1 -1
  309. package/dist/esm/components/editor/Timeline/TimelineMinimap.js +1 -1
  310. package/dist/esm/components/editor/Timeline/TimelineMinimap.js.map +1 -1
  311. package/dist/esm/components/editor/Timeline/TimelineStore.js.map +1 -1
  312. package/dist/esm/components/editor/Timeline/TimelineToolbar.js.map +1 -1
  313. package/dist/esm/components/editor/Timeline/TimelineTrackHeaders.js +1 -1
  314. package/dist/esm/components/editor/Timeline/TimelineTrackHeaders.js.map +1 -1
  315. package/dist/esm/components/editor/Timeline/TimelineTrackScale.js.map +1 -1
  316. package/dist/esm/components/editor/Timeline/index.js.map +1 -1
  317. package/dist/esm/components/editor/Timeline/timelineCoords.js.map +1 -1
  318. package/dist/esm/components/editor/Timeline/timelineDrawing.js.map +1 -1
  319. package/dist/esm/components/editor/Timeline/timelineEdits.js.map +1 -1
  320. package/dist/esm/components/editor/Timeline/timelineHitTest.js.map +1 -1
  321. package/dist/esm/components/editor/Timeline/timelineLayout.js.map +1 -1
  322. package/dist/esm/components/editor/Timeline/timelineSelection.js.map +1 -1
  323. package/dist/esm/components/editor/Timeline/useTimelineDraw.js +1 -1
  324. package/dist/esm/components/editor/Timeline/useTimelineDraw.js.map +1 -1
  325. package/dist/esm/components/editor/Timeline/useTimelineGestures.js +1 -1
  326. package/dist/esm/components/editor/Timeline/useTimelineGestures.js.map +1 -1
  327. package/dist/esm/components/editor/Timeline/useTimelinePlayback.js.map +1 -1
  328. package/dist/esm/components/editor/TransformControl/TransformControl.js.map +1 -1
  329. package/dist/esm/components/editor/ViewportGizmo/ViewportGizmo.js.map +1 -1
  330. package/dist/esm/components/editor/ViewportGizmo/gizmoMath.js.map +1 -1
  331. package/dist/esm/components/editor/ViewportGizmo/useGizmoInteraction.js.map +1 -1
  332. package/dist/esm/components/editor/ViewportGizmo/useGizmoRenderer.js.map +1 -1
  333. package/dist/esm/components/feedback/Alert/Alert.js.map +1 -1
  334. package/dist/esm/components/feedback/Alert/AlertActions.js.map +1 -1
  335. package/dist/esm/components/feedback/Alert/AlertDescription.js.map +1 -1
  336. package/dist/esm/components/feedback/Alert/AlertTitle.js.map +1 -1
  337. package/dist/esm/components/feedback/CommandPalette/CommandPalette.js.map +1 -1
  338. package/dist/esm/components/feedback/CommandPalette/fuzzySearch.js.map +1 -1
  339. package/dist/esm/components/feedback/CommandPalette/useRecentItems.js.map +1 -1
  340. package/dist/esm/components/feedback/Dialog/Dialog.js.map +1 -1
  341. package/dist/esm/components/feedback/Dialog/DialogBody.js.map +1 -1
  342. package/dist/esm/components/feedback/Dialog/DialogClose.js.map +1 -1
  343. package/dist/esm/components/feedback/Dialog/DialogFooter.js.map +1 -1
  344. package/dist/esm/components/feedback/Dialog/DialogHeader.js.map +1 -1
  345. package/dist/esm/components/feedback/Dialog/useDialogAnimation.js.map +1 -1
  346. package/dist/esm/components/feedback/Drawer/Drawer.js.map +1 -1
  347. package/dist/esm/components/feedback/Drawer/useDrawerAnimation.js.map +1 -1
  348. package/dist/esm/components/feedback/EmptyState/EmptyState.js.map +1 -1
  349. package/dist/esm/components/feedback/LogView/LogView.js.map +1 -1
  350. package/dist/esm/components/feedback/LogView/LogViewBody.js.map +1 -1
  351. package/dist/esm/components/feedback/LogView/LogViewContext.js.map +1 -1
  352. package/dist/esm/components/feedback/LogView/LogViewParts.js.map +1 -1
  353. package/dist/esm/components/feedback/LogView/LogViewStore.js.map +1 -1
  354. package/dist/esm/components/feedback/LogView/logViewLabels.js.map +1 -1
  355. package/dist/esm/components/feedback/LogView/logViewLevels.js.map +1 -1
  356. package/dist/esm/components/feedback/LogView/logViewUtils.js.map +1 -1
  357. package/dist/esm/components/feedback/LogView/useFollowTail.js.map +1 -1
  358. package/dist/esm/components/feedback/LogView/useLogSelection.js.map +1 -1
  359. package/dist/esm/components/feedback/ProgressBar/CircularProgress.js.map +1 -1
  360. package/dist/esm/components/feedback/ProgressBar/ProgressBar.js.map +1 -1
  361. package/dist/esm/components/feedback/Skeleton/Skeleton.js.map +1 -1
  362. package/dist/esm/components/feedback/Skeleton/SkeletonGroup.js.map +1 -1
  363. package/dist/esm/components/feedback/Skeleton/SkeletonLayout.js.map +1 -1
  364. package/dist/esm/components/feedback/Spinner/Spinner.js +12 -3
  365. package/dist/esm/components/feedback/Spinner/Spinner.js.map +1 -1
  366. package/dist/esm/components/feedback/Stat/Stat.js.map +1 -1
  367. package/dist/esm/components/feedback/Toast/ToastContainer.js.map +1 -1
  368. package/dist/esm/components/feedback/Toast/ToastItem.js.map +1 -1
  369. package/dist/esm/components/feedback/Toast/ToastProvider.js.map +1 -1
  370. package/dist/esm/components/feedback/Toast/useToast.js.map +1 -1
  371. package/dist/esm/components/form/FormHelperText.js.map +1 -1
  372. package/dist/esm/components/form/FormLabel.js.map +1 -1
  373. package/dist/esm/components/form/InputWrapper.js.map +1 -1
  374. package/dist/esm/components/layout/Accordion/Accordion.js.map +1 -1
  375. package/dist/esm/components/layout/Accordion/AccordionContent.js.map +1 -1
  376. package/dist/esm/components/layout/Accordion/AccordionItem.js.map +1 -1
  377. package/dist/esm/components/layout/Accordion/AccordionTrigger.js.map +1 -1
  378. package/dist/esm/components/layout/Card/Card.js.map +1 -1
  379. package/dist/esm/components/layout/Divider/Divider.js.map +1 -1
  380. package/dist/esm/components/layout/Flex/Flex.js.map +1 -1
  381. package/dist/esm/components/layout/Grid/Grid.js.map +1 -1
  382. package/dist/esm/components/layout/ListItem/ListItem.js.map +1 -1
  383. package/dist/esm/components/layout/PageHeader/PageHeader.js.map +1 -1
  384. package/dist/esm/components/layout/PanelSurface/PanelSurface.js.map +1 -1
  385. package/dist/esm/components/layout/ScrollArea/ScrollArea.js.map +1 -1
  386. package/dist/esm/components/layout/Spacer/Spacer.js.map +1 -1
  387. package/dist/esm/components/layout/SplitPane/SplitPane.js.map +1 -1
  388. package/dist/esm/components/layout/SplitPane/SplitPanePanel.js.map +1 -1
  389. package/dist/esm/components/layout/Stack/Stack.js.map +1 -1
  390. package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbEllipsis.js.map +1 -1
  391. package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbItem.js.map +1 -1
  392. package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbSeparator.js.map +1 -1
  393. package/dist/esm/components/navigation/Breadcrumbs/Breadcrumbs.js +6 -0
  394. package/dist/esm/components/navigation/Breadcrumbs/Breadcrumbs.js.map +1 -1
  395. package/dist/esm/components/navigation/ContextMenu/ContextMenu.js +2 -2
  396. package/dist/esm/components/navigation/ContextMenu/ContextMenu.js.map +1 -1
  397. package/dist/esm/components/navigation/Menu/Menu.css.js +11 -10
  398. package/dist/esm/components/navigation/Menu/Menu.css.js.map +1 -1
  399. package/dist/esm/components/navigation/Menu/Menu.js +2 -2
  400. package/dist/esm/components/navigation/Menu/Menu.js.map +1 -1
  401. package/dist/esm/components/navigation/Menu/MenuGapContext.js.map +1 -1
  402. package/dist/esm/components/navigation/Pagination/Pagination.js.map +1 -1
  403. package/dist/esm/components/navigation/Pagination/usePagination.js.map +1 -1
  404. package/dist/esm/components/navigation/PathBar/PathBar.js +7 -1
  405. package/dist/esm/components/navigation/PathBar/PathBar.js.map +1 -1
  406. package/dist/esm/components/navigation/PathBar/PathBarSiblingMenu.js +6 -0
  407. package/dist/esm/components/navigation/PathBar/PathBarSiblingMenu.js.map +1 -1
  408. package/dist/esm/components/navigation/PathBar/pathUtils.js.map +1 -1
  409. package/dist/esm/components/navigation/SegmentedControl/SegmentedControl.js.map +1 -1
  410. package/dist/esm/components/navigation/SegmentedControl/SegmentedControlItem.js.map +1 -1
  411. package/dist/esm/components/navigation/Tabs/Tab.js.map +1 -1
  412. package/dist/esm/components/navigation/Tabs/TabList.js.map +1 -1
  413. package/dist/esm/components/navigation/Tabs/TabPanel.js.map +1 -1
  414. package/dist/esm/components/navigation/Tabs/Tabs.js.map +1 -1
  415. package/dist/esm/components/primitives/Avatar/Avatar.js +6 -0
  416. package/dist/esm/components/primitives/Avatar/Avatar.js.map +1 -1
  417. package/dist/esm/components/primitives/Avatar/AvatarGroup.js.map +1 -1
  418. package/dist/esm/components/primitives/Badge/Badge.js +6 -0
  419. package/dist/esm/components/primitives/Badge/Badge.js.map +1 -1
  420. package/dist/esm/components/primitives/Button/Button.js.map +1 -1
  421. package/dist/esm/components/primitives/Checkbox/Checkbox.js.map +1 -1
  422. package/dist/esm/components/primitives/Checkbox/CheckboxGroup.js.map +1 -1
  423. package/dist/esm/components/primitives/Code/Code.js.map +1 -1
  424. package/dist/esm/components/primitives/Collapsible/Collapsible.js.map +1 -1
  425. package/dist/esm/components/primitives/HoverCard/HoverCard.js.map +1 -1
  426. package/dist/esm/components/primitives/Icon/Icon.js.map +1 -1
  427. package/dist/esm/components/primitives/IconButton/IconButton.js +4 -2
  428. package/dist/esm/components/primitives/IconButton/IconButton.js.map +1 -1
  429. package/dist/esm/components/primitives/Input/Input.js.map +1 -1
  430. package/dist/esm/components/primitives/Kbd/Kbd.js.map +1 -1
  431. package/dist/esm/components/primitives/Link/Link.js.map +1 -1
  432. package/dist/esm/components/primitives/Paper/Paper.js.map +1 -1
  433. package/dist/esm/components/primitives/Popover/Popover.js.map +1 -1
  434. package/dist/esm/components/primitives/Popover/PopoverClose.js.map +1 -1
  435. package/dist/esm/components/primitives/Popover/PopoverContent.js.map +1 -1
  436. package/dist/esm/components/primitives/Popover/PopoverTrigger.js.map +1 -1
  437. package/dist/esm/components/primitives/Radio/Radio.js.map +1 -1
  438. package/dist/esm/components/primitives/Radio/RadioGroup.js.map +1 -1
  439. package/dist/esm/components/primitives/Switch/Switch.js.map +1 -1
  440. package/dist/esm/components/primitives/Text/Text.js.map +1 -1
  441. package/dist/esm/components/primitives/TextArea/TextArea.js.map +1 -1
  442. package/dist/esm/components/primitives/Tooltip/Arrow.js.map +1 -1
  443. package/dist/esm/components/primitives/Tooltip/Tooltip.css.js +6 -5
  444. package/dist/esm/components/primitives/Tooltip/Tooltip.css.js.map +1 -1
  445. package/dist/esm/components/primitives/Tooltip/Tooltip.js +12 -2
  446. package/dist/esm/components/primitives/Tooltip/Tooltip.js.map +1 -1
  447. package/dist/esm/components/primitives/Tooltip/utils.js.map +1 -1
  448. package/dist/esm/components/primitives/VisuallyHidden/VisuallyHidden.js.map +1 -1
  449. package/dist/esm/components/primitives/canvas/CanvasContainer.js.map +1 -1
  450. package/dist/esm/components/primitives/canvas/canvasCoords.js.map +1 -1
  451. package/dist/esm/components/primitives/canvas/canvasDrawing.js.map +1 -1
  452. package/dist/esm/components/primitives/canvas/canvasTheme.js.map +1 -1
  453. package/dist/esm/components/primitives/canvas/useCanvasRenderer.js.map +1 -1
  454. package/dist/esm/components/primitives/viewport/Viewport.js +6 -3
  455. package/dist/esm/components/primitives/viewport/Viewport.js.map +1 -1
  456. package/dist/esm/components/primitives/viewport/ViewportContext.js.map +1 -1
  457. package/dist/esm/components/primitives/viewport/ViewportLayer.js +1 -1
  458. package/dist/esm/components/primitives/viewport/ViewportLayer.js.map +1 -1
  459. package/dist/esm/components/primitives/viewport/ViewportOverlay.js.map +1 -1
  460. package/dist/esm/components/primitives/viewport/ViewportStore.js.map +1 -1
  461. package/dist/esm/components/primitives/viewport/ViewportWorld.js.map +1 -1
  462. package/dist/esm/components/primitives/viewport/useViewportGestures.js +1 -1
  463. package/dist/esm/components/primitives/viewport/useViewportGestures.js.map +1 -1
  464. package/dist/esm/components/primitives/viewport/viewportCoords.js.map +1 -1
  465. package/dist/esm/components/primitives/viewport/viewportMath.js.map +1 -1
  466. package/dist/esm/components/shell/AppShell/AppShell.css.js +1 -1
  467. package/dist/esm/components/shell/AppShell/AppShell.js.map +1 -1
  468. package/dist/esm/components/shell/FloatingPanel/FloatingPanel.js.map +1 -1
  469. package/dist/esm/components/shell/MenuBar/MenuBar.css.js +7 -6
  470. package/dist/esm/components/shell/MenuBar/MenuBar.css.js.map +1 -1
  471. package/dist/esm/components/shell/MenuBar/MenuBar.js +52 -3
  472. package/dist/esm/components/shell/MenuBar/MenuBar.js.map +1 -1
  473. package/dist/esm/components/shell/StatusBar/StatusBar.js.map +1 -1
  474. package/dist/esm/components/shell/Toolbar/Toolbar.js.map +1 -1
  475. package/dist/esm/context/KeyboardContext.js.map +1 -1
  476. package/dist/esm/hooks/useBreakpoint/useBreakpoint.js.map +1 -1
  477. package/dist/esm/hooks/useClickOutside/useClickOutside.js.map +1 -1
  478. package/dist/esm/hooks/useClipboard/useClipboard.js.map +1 -1
  479. package/dist/esm/hooks/useControlledState/useControlledState.js.map +1 -1
  480. package/dist/esm/hooks/useDebounced/useDebouncedCallback.js.map +1 -1
  481. package/dist/esm/hooks/useDebounced/useDebouncedValue.js.map +1 -1
  482. package/dist/esm/hooks/useDisclosure/useDisclosure.js.map +1 -1
  483. package/dist/esm/hooks/useEventCallback/useEventCallback.js.map +1 -1
  484. package/dist/esm/hooks/useFocusTrap/useFocusTrap.js.map +1 -1
  485. package/dist/esm/hooks/useHotkey/useHotkey.js.map +1 -1
  486. package/dist/esm/hooks/useIntersectionObserver/useIntersectionObserver.js.map +1 -1
  487. package/dist/esm/hooks/useIsMounted/useIsMounted.js.map +1 -1
  488. package/dist/esm/hooks/useKeyboard/useKeyboard.js.map +1 -1
  489. package/dist/esm/hooks/useKeyboard/utils.js.map +1 -1
  490. package/dist/esm/hooks/useLatest/useLatest.js.map +1 -1
  491. package/dist/esm/hooks/useListboxNav/useListboxNav.js.map +1 -1
  492. package/dist/esm/hooks/useMediaQuery/useMediaQuery.js.map +1 -1
  493. package/dist/esm/hooks/useMergedRef/useMergedRef.js.map +1 -1
  494. package/dist/esm/hooks/useNavigationHistory/useNavigationHistory.js.map +1 -1
  495. package/dist/esm/hooks/useResizeObserver/useResizeObserver.js.map +1 -1
  496. package/dist/esm/hooks/useTheme/useTheme.js +1 -1
  497. package/dist/esm/hooks/useTheme/useTheme.js.map +1 -1
  498. package/dist/esm/hooks/useThrottledCallback/useThrottledCallback.js.map +1 -1
  499. package/dist/esm/index.js +6 -0
  500. package/dist/esm/index.js.map +1 -1
  501. package/dist/esm/node_modules/tslib/tslib.es6.js.map +1 -1
  502. package/dist/esm/styles.css.js +3 -0
  503. package/dist/esm/styles.css.js.map +1 -0
  504. package/dist/esm/theme/ThemeProvider.js +5 -3
  505. package/dist/esm/theme/ThemeProvider.js.map +1 -1
  506. package/dist/esm/theme/VanillaThemeProvider.js.map +1 -1
  507. package/dist/esm/theme/breakpoints.js.map +1 -1
  508. package/dist/esm/theme/createCustomTheme.js +1 -1
  509. package/dist/esm/theme/createCustomTheme.js.map +1 -1
  510. package/dist/esm/theme/createLightTheme.js.map +1 -1
  511. package/dist/esm/theme/darkThemeValues.js.map +1 -1
  512. package/dist/esm/theme/lightThemeValues.js.map +1 -1
  513. package/dist/esm/theme/themeContractData.js.map +1 -1
  514. package/dist/esm/utils/cx.js.map +1 -1
  515. package/dist/esm/utils/devWarn.js.map +1 -1
  516. package/dist/esm/utils/mathExpression.js.map +1 -1
  517. package/dist/esm/utils/mathUtils.js.map +1 -1
  518. package/dist/esm/utils/objects.js.map +1 -1
  519. package/dist/esm/utils/platform.js.map +1 -1
  520. package/dist/tokens/tokens.dark.css +1 -1
  521. package/dist/tokens/tokens.json +1 -1
  522. package/dist/tokens/tokens.light.css +1 -1
  523. package/dist/types/components/Icons/CameraIcon.d.ts +34 -0
  524. package/dist/types/components/Icons/CubeIcon.d.ts +34 -0
  525. package/dist/types/components/Icons/OrbitIcon.d.ts +34 -0
  526. package/dist/types/components/Icons/RotateIcon.d.ts +35 -0
  527. package/dist/types/components/Icons/SpinIcon.d.ts +35 -0
  528. package/dist/types/components/Icons/ZoomFitIcon.d.ts +35 -0
  529. package/dist/types/components/controls/Select/Select.d.ts +1 -1
  530. package/dist/types/components/controls/Select/Select.types.d.ts +43 -9
  531. package/dist/types/components/controls/Slider/Slider.d.ts +7 -0
  532. package/dist/types/components/editor/PropertyInspector/PropertyInspector.types.d.ts +49 -3
  533. package/dist/types/components/feedback/Spinner/Spinner.d.ts +6 -1
  534. package/dist/types/components/feedback/Spinner/Spinner.types.d.ts +8 -0
  535. package/dist/types/components/primitives/Button/Button.d.ts +1 -1
  536. package/dist/types/components/primitives/IconButton/IconButton.d.ts +3 -2
  537. package/dist/types/components/primitives/viewport/Viewport.d.ts +5 -2
  538. package/dist/types/components/shell/MenuBar/MenuBar.d.ts +862 -0
  539. package/dist/types/index.d.ts +6 -0
  540. package/dist/types/theme/ThemeProvider.d.ts +5 -3
  541. package/package.json +6 -2
  542. package/dist/esm/_virtual/_commonjsHelpers.js +0 -6
  543. package/dist/esm/_virtual/_commonjsHelpers.js.map +0 -1
  544. package/dist/esm/_virtual/cjs.js +0 -4
  545. package/dist/esm/_virtual/cjs.js.map +0 -1
  546. package/dist/esm/_virtual/cssesc.js +0 -8
  547. package/dist/esm/_virtual/cssesc.js.map +0 -1
  548. package/dist/esm/_virtual/picocolors.js +0 -8
  549. package/dist/esm/_virtual/picocolors.js.map +0 -1
  550. package/dist/esm/_virtual/picocolors2.js +0 -4
  551. package/dist/esm/_virtual/picocolors2.js.map +0 -1
  552. package/dist/esm/node_modules/@emotion/hash/dist/emotion-hash.esm.js +0 -56
  553. package/dist/esm/node_modules/@emotion/hash/dist/emotion-hash.esm.js.map +0 -1
  554. package/dist/esm/node_modules/@vanilla-extract/css/adapter/dist/vanilla-extract-css-adapter.esm.js +0 -46
  555. package/dist/esm/node_modules/@vanilla-extract/css/adapter/dist/vanilla-extract-css-adapter.esm.js.map +0 -1
  556. package/dist/esm/node_modules/@vanilla-extract/css/dist/taggedTemplateLiteral-10998315.esm.js +0 -13
  557. package/dist/esm/node_modules/@vanilla-extract/css/dist/taggedTemplateLiteral-10998315.esm.js.map +0 -1
  558. package/dist/esm/node_modules/@vanilla-extract/css/dist/transformCss-fd0786e1.esm.js +0 -962
  559. package/dist/esm/node_modules/@vanilla-extract/css/dist/transformCss-fd0786e1.esm.js.map +0 -1
  560. package/dist/esm/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js +0 -309
  561. package/dist/esm/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js.map +0 -1
  562. package/dist/esm/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.esm.js +0 -18
  563. package/dist/esm/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.esm.js.map +0 -1
  564. package/dist/esm/node_modules/@vanilla-extract/css/injectStyles/dist/vanilla-extract-css-injectStyles.esm.js +0 -23
  565. package/dist/esm/node_modules/@vanilla-extract/css/injectStyles/dist/vanilla-extract-css-injectStyles.esm.js.map +0 -1
  566. package/dist/esm/node_modules/@vanilla-extract/css/node_modules/lru-cache/dist/esm/index.js +0 -1543
  567. package/dist/esm/node_modules/@vanilla-extract/css/node_modules/lru-cache/dist/esm/index.js.map +0 -1
  568. package/dist/esm/node_modules/@vanilla-extract/private/dist/vanilla-extract-private.esm.js +0 -38
  569. package/dist/esm/node_modules/@vanilla-extract/private/dist/vanilla-extract-private.esm.js.map +0 -1
  570. package/dist/esm/node_modules/css-what/lib/es/parse.js +0 -424
  571. package/dist/esm/node_modules/css-what/lib/es/parse.js.map +0 -1
  572. package/dist/esm/node_modules/css-what/lib/es/types.js +0 -29
  573. package/dist/esm/node_modules/css-what/lib/es/types.js.map +0 -1
  574. package/dist/esm/node_modules/cssesc/cssesc.js +0 -120
  575. package/dist/esm/node_modules/cssesc/cssesc.js.map +0 -1
  576. package/dist/esm/node_modules/dedent/dist/dedent.js +0 -100
  577. package/dist/esm/node_modules/dedent/dist/dedent.js.map +0 -1
  578. package/dist/esm/node_modules/deep-object-diff/mjs/diff.js +0 -40
  579. package/dist/esm/node_modules/deep-object-diff/mjs/diff.js.map +0 -1
  580. package/dist/esm/node_modules/deep-object-diff/mjs/utils.js +0 -9
  581. package/dist/esm/node_modules/deep-object-diff/mjs/utils.js.map +0 -1
  582. package/dist/esm/node_modules/deepmerge/dist/cjs.js +0 -143
  583. package/dist/esm/node_modules/deepmerge/dist/cjs.js.map +0 -1
  584. package/dist/esm/node_modules/media-query-parser/dist/media-query-parser.esm.js +0 -1386
  585. package/dist/esm/node_modules/media-query-parser/dist/media-query-parser.esm.js.map +0 -1
  586. package/dist/esm/node_modules/modern-ahocorasick/dist/index.js +0 -102
  587. package/dist/esm/node_modules/modern-ahocorasick/dist/index.js.map +0 -1
  588. package/dist/esm/node_modules/picocolors/picocolors.js +0 -87
  589. package/dist/esm/node_modules/picocolors/picocolors.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","sources":["../../../../../../src/components/data/DataTable/DataTable.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;AAkDA;AACE;AACA;AACA;;AAGF;AACA;AAEA;;AAKoC;AAClC;AACA;AACF;AAEA;AAKE;;AACoC;;AAElC;AACF;AACF;AAEA;;AACe;AACb;AAAmC;AACnC;;;;AAEA;;;;AAGA;AACA;AACA;AACF;AAEA;;AAGwB;;AACC;AACvB;AACF;AAEA;;AAG2B;AACzB;AACF;AAOA;AAIE;;;AAGA;;AAEE;AACA;;AAEF;;AAEF;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH;;AAuCE;;;AAGE;;AAED;AAED;AAEI;AACA;AACA;AACA;AACD;;;AAKH;AACA;AAEA;AACE;AAAgB;AAChB;AACA;AAAqC;AACrC;AACA;AAAa;;;AAGX;AACA;AACA;AACE;AACA;AACF;AACF;AACA;;AAGF;AAKA;AACE;AAAoB;AACpB;AAAsB;;;AAGpB;AAA+B;AACjC;AACA;;AAGF;AAEE;AACE;;AAEF;;AAGA;AACE;;AAEF;AAEF;;;;;;;;AAQU;;;AAGN;AACF;AAIF;AACA;AAEA;AAEI;;;;AAEA;AACE;;;;AAOF;;;;AAKE;AACE;AACA;AACA;;;;AAEA;;;AAGA;;AAEA;AACE;AAAoB;;AACf;;AAEP;AACF;;;AAIF;;AAEE;AACA;AAA0B;;AACrB;AACL;AACF;AACF;AAIF;;;;;;;;;;;AAUA;;;;;;AAMC;AAED;AAEA;;;;;;;;;AAYE;AACA;;AAED;AAED;AACA;AAEA;;;;AAII;;;AAGF;AACE;AACA;AACA;AACF;AACA;;AAGF;;AACwB;AACtB;AAEA;AACA;AAEI;;AAEE;;;AAUR;AAEA;AAOI;AACA;AACA;AACE;AACA;AACA;AACF;;AAEE;AACA;;AAEE;;AAC8B;AAC9B;AACF;AACF;AACA;AACA;AACF;AAIF;AAEI;;;;;;;;AAUJ;AAEI;;AACA;AACA;AACE;;AAEE;;AAEF;;AAEE;;AAEF;;;;AAIA;;AAEE;;AAEF;;AAEE;;AAEF;;AAEE;;;;;;AAKA;;;AAEA;;AAEE;;AAEF;;;;;;;;;AAOA;AACA;AACA;;;;;AAIF;;;AAGJ;;;;;;;;AASC;;;AAKC;;;AAIJ;AACE;AAEI;AACE;AACA;AACE;AACA;;AAER;AAOQ;;;AAGD;;;;AAWC;;AAKI;;;;;;;;AAqBF;AAEE;;AAEA;AACF;;AAMZ;AAEA;AAgBY;AACF;AAUV;;;AASY;;AAED;AAMD;AACA;AACE;AACA;AACE;;AAEE;AACA;AAGd;;;;;AAWA;AAQU;AACF;;AAGA;AAEE;;;AAGF;;AAYI;;AAWZ;;AAEE;AACE;;;AAGJ;;AAGE;AACF;AAEA;AACE;;AAEE;AACE;;;;AAIN;;AAGE;;;;;;;AAQD;;;;;AA0BH;;;AAIE;;AAcF;AAEA;AACE;;;;AAIA;;;AAIF;;AAGE;AACA;AACD;AAED;AAkCc;AACD;;;AAIwB;AACvB;AACE;;AAED;AACH;AAWd;AAEA;AAEO;;"}
1
+ {"version":3,"file":"DataTable.js","sources":["src/components/data/DataTable/DataTable.tsx"],"sourcesContent":["'use client';\n\nimport { useVirtualizer } from '@tanstack/react-virtual';\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { ChevronDownIcon } from '@/components/Icons/ChevronDownIcon';\nimport { ChevronUpIcon } from '@/components/Icons/ChevronUpIcon';\nimport { SortIcon } from '@/components/Icons/SortIcon';\nimport { Checkbox } from '@/components/primitives/Checkbox';\nimport { useControlledState } from '@/hooks/useControlledState';\nimport { cx } from '@/utils/cx';\n\nimport {\n bodyStyle,\n cellRecipe,\n emptyStateStyle,\n gridTemplateColumnsVar,\n headerCellInnerStyle,\n headerCellRecipe,\n headerStyle,\n innerWrapperStyle,\n resizeHandleStyle,\n rootRecipe,\n rowRecipe,\n scrollContainerStyle,\n skeletonBarStyle,\n skeletonCellStyle,\n skeletonRowStyle,\n sortIndicatorRecipe,\n tableMinWidthVar,\n totalHeightVar,\n virtualBodyStyle,\n} from './DataTable.css';\n\nimport type {\n DataTableColumn,\n DataTableDensity,\n DataTableProps,\n DataTableSelectionState,\n DataTableSortDirection,\n DataTableSortState,\n} from './DataTable.types';\n\nconst DENSITY_ROW_HEIGHT: Record<DataTableDensity, number> = {\n comfortable: 40,\n compact: 32,\n dense: 24,\n};\n\nconst VIRTUALIZATION_THRESHOLD_DEFAULT = 100;\nconst SELECT_COLUMN_WIDTH = 40;\n\nfunction getRowKey<R>(\n rowKey: keyof R | ((row: R, rowIndex: number) => string),\n row: R,\n rowIndex: number\n): string {\n if (typeof rowKey === 'function') return rowKey(row, rowIndex);\n const value = row[rowKey];\n return typeof value === 'string' ? value : String(value);\n}\n\nfunction readCellValue<R>(\n column: DataTableColumn<R>,\n row: R,\n rowIndex: number\n): unknown {\n const accessor = column.accessor;\n if (typeof accessor === 'function') return accessor(row, rowIndex);\n if (typeof accessor === 'string')\n return (row as Record<string, unknown>)[accessor];\n return (row as Record<string, unknown>)[column.id];\n}\n\nfunction defaultCompare(a: unknown, b: unknown): number {\n if (a === b) return 0;\n if (a === null || a === undefined) return 1;\n if (b === null || b === undefined) return -1;\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n if (typeof a === 'boolean' && typeof b === 'boolean')\n return a === b ? 0 : a ? 1 : -1;\n const sa = typeof a === 'string' ? a : JSON.stringify(a);\n const sb = typeof b === 'string' ? b : JSON.stringify(b);\n return sa.localeCompare(sb);\n}\n\nfunction nextSortDirection(\n current: DataTableSortDirection\n): DataTableSortDirection {\n if (current === null) return 'asc';\n if (current === 'asc') return 'desc';\n return null;\n}\n\nfunction resolveDimension(\n value: number | string | undefined\n): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\ninterface ColumnTrack {\n templateValue: string;\n minPx: number;\n}\n\nfunction getColumnTrack<R>(\n column: DataTableColumn<R>,\n override: number | undefined\n): ColumnTrack {\n if (override !== undefined) {\n return { templateValue: `${override}px`, minPx: override };\n }\n if (column.width !== undefined) {\n const resolved = resolveDimension(column.width) ?? '1fr';\n const minPx = typeof column.width === 'number' ? column.width : 0;\n return { templateValue: resolved, minPx };\n }\n const minWidth = column.minWidth ?? 80;\n return { templateValue: `minmax(${minWidth}px, 1fr)`, minPx: minWidth };\n}\n\n/**\n * Data-driven table with sortable columns, row selection, sticky header,\n * optional sticky first column, optional column resizing, and optional\n * row virtualization (auto-enabled above 100 rows).\n *\n * Uses a CSS grid layout under `role=\"grid\"` so columns line up across the\n * sticky header and individual virtualized rows without depending on real\n * `<table>` semantics.\n *\n * @example\n * ```tsx\n * <DataTable\n * rows={users}\n * rowKey=\"id\"\n * columns={[\n * { id: 'name', header: 'Name', accessor: 'name', sortable: true },\n * { id: 'role', header: 'Role', accessor: 'role' },\n * ]}\n * selectionMode=\"multiple\"\n * onSelectionChange={setSelected}\n * />\n * ```\n */\nfunction DataTableInner<R>(props: DataTableProps<R>): React.ReactElement {\n const {\n rows,\n columns,\n rowKey,\n density = 'comfortable',\n stickyHeader = true,\n sort,\n defaultSort,\n onSortChange,\n manualSort = false,\n selectionMode = false,\n selection,\n defaultSelection,\n onSelectionChange,\n isRowSelectable,\n onRowClick,\n onRowActivate,\n renderRow,\n emptyState,\n loading = false,\n loadingRowCount = 5,\n virtualized = 'auto',\n virtualizationThreshold = VIRTUALIZATION_THRESHOLD_DEFAULT,\n estimatedRowHeight,\n overscan = 8,\n height = 480,\n maxHeight,\n resizableColumns = false,\n onColumnResize,\n className,\n style,\n testId,\n ref,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n ...rest\n } = props;\n\n const [sortState, setSortState] = useControlledState<DataTableSortState>({\n value: sort ?? undefined,\n defaultValue: defaultSort ?? undefined,\n onChange: onSortChange,\n fallback: { columnId: null, direction: null },\n });\n\n const [selectionState, setSelectionState] =\n useControlledState<DataTableSelectionState>({\n value: selection,\n defaultValue: defaultSelection,\n onChange: onSelectionChange,\n fallback: [],\n });\n\n const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});\n const [activeRowIndex, setActiveRowIndex] = useState<number | null>(null);\n\n const showSelectColumn = selectionMode === 'multiple';\n const selectedSet = useMemo(() => new Set(selectionState), [selectionState]);\n\n const sortedRows = useMemo(() => {\n if (manualSort) return rows;\n const { columnId, direction } = sortState;\n if (!columnId || direction === null) return rows;\n const column = columns.find(c => c.id === columnId);\n if (!column) return rows;\n const indexed = rows.map((row, idx) => ({ row, idx }));\n indexed.sort((a, b) => {\n const valueA = readCellValue(column, a.row, a.idx);\n const valueB = readCellValue(column, b.row, b.idx);\n const cmp = column.sortComparator\n ? column.sortComparator(valueA, valueB, a.row, b.row)\n : defaultCompare(valueA, valueB);\n return direction === 'asc' ? cmp : -cmp;\n });\n return indexed.map(item => item.row);\n }, [rows, sortState, columns, manualSort]);\n\n const rowKeys = useMemo(\n () => sortedRows.map((row, idx) => getRowKey(rowKey, row, idx)),\n [sortedRows, rowKey]\n );\n\n const selectableIndexes = useMemo(() => {\n if (!selectionMode) return [];\n if (!isRowSelectable) return sortedRows.map((_, idx) => idx);\n const result: number[] = [];\n sortedRows.forEach((row, idx) => {\n if (isRowSelectable(row, idx)) result.push(idx);\n });\n return result;\n }, [sortedRows, isRowSelectable, selectionMode]);\n\n const allSelectableSelected =\n selectableIndexes.length > 0 &&\n selectableIndexes.every(idx => {\n const k = rowKeys[idx];\n return k !== undefined && selectedSet.has(k);\n });\n const someSelectableSelected =\n !allSelectableSelected &&\n selectableIndexes.some(idx => {\n const k = rowKeys[idx];\n return k !== undefined && selectedSet.has(k);\n });\n\n const handleSortClick = useCallback(\n (column: DataTableColumn<R>) => {\n if (!column.sortable) return;\n setSortState(prev => {\n if (prev.columnId === column.id) {\n const next = nextSortDirection(prev.direction);\n return next === null\n ? { columnId: null, direction: null }\n : { columnId: column.id, direction: next };\n }\n return { columnId: column.id, direction: 'asc' };\n });\n },\n [setSortState]\n );\n\n const selectionAnchorRef = useRef<number | null>(null);\n const selectionShiftKeyRef = useRef(false);\n\n const toggleRowSelection = useCallback(\n (rowKeyValue: string, row: R, rowIdx: number, rangeMode = false) => {\n if (!selectionMode) return;\n if (isRowSelectable && !isRowSelectable(row, rowIdx)) return;\n if (selectionMode === 'single') {\n selectionAnchorRef.current = rowIdx;\n setSelectionState(prev =>\n prev[0] === rowKeyValue ? [] : [rowKeyValue]\n );\n return;\n }\n\n const anchor = selectionAnchorRef.current;\n if (rangeMode && anchor !== null && anchor !== rowIdx) {\n const [start, end] =\n anchor < rowIdx ? [anchor, rowIdx] : [rowIdx, anchor];\n const rangeKeys: string[] = [];\n for (let i = start; i <= end; i += 1) {\n const candidate = sortedRows[i];\n const candidateKey = rowKeys[i];\n if (candidate === undefined || candidateKey === undefined) continue;\n if (isRowSelectable && !isRowSelectable(candidate, i)) continue;\n rangeKeys.push(candidateKey);\n }\n setSelectionState(prev => {\n const set = new Set(prev);\n const shouldDeselect = set.has(rowKeyValue);\n for (const key of rangeKeys) {\n if (shouldDeselect) set.delete(key);\n else set.add(key);\n }\n return Array.from(set);\n });\n return;\n }\n\n selectionAnchorRef.current = rowIdx;\n setSelectionState(prev => {\n const set = new Set(prev);\n if (set.has(rowKeyValue)) set.delete(rowKeyValue);\n else set.add(rowKeyValue);\n return Array.from(set);\n });\n },\n [selectionMode, isRowSelectable, setSelectionState, sortedRows, rowKeys]\n );\n\n const toggleSelectAll = useCallback(() => {\n if (selectionMode !== 'multiple') return;\n if (allSelectableSelected) {\n setSelectionState([]);\n return;\n }\n const next = selectableIndexes\n .map(idx => rowKeys[idx])\n .filter((k): k is string => typeof k === 'string');\n setSelectionState(next);\n }, [\n allSelectableSelected,\n selectableIndexes,\n rowKeys,\n selectionMode,\n setSelectionState,\n ]);\n\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const shouldVirtualize =\n virtualized === true ||\n (virtualized === 'auto' && sortedRows.length > virtualizationThreshold);\n\n const rowHeightPx = estimatedRowHeight ?? DENSITY_ROW_HEIGHT[density];\n\n // TanStack Virtual's useVirtualizer returns functions that cannot be safely\n // memoized; the Compiler flags it as an incompatible library. Behavior is\n // correct here because the virtualizer is read imperatively per render.\n // eslint-disable-next-line react-hooks/incompatible-library\n const virtualizer = useVirtualizer({\n count: shouldVirtualize ? sortedRows.length : 0,\n getScrollElement: () => scrollContainerRef.current,\n estimateSize: () => rowHeightPx,\n overscan,\n });\n\n const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];\n const totalSize = shouldVirtualize ? virtualizer.getTotalSize() : 0;\n\n const tracks = useMemo(() => {\n const items: string[] = [];\n let minWidth = 0;\n if (showSelectColumn) {\n items.push(`${SELECT_COLUMN_WIDTH}px`);\n minWidth += SELECT_COLUMN_WIDTH;\n }\n columns.forEach(column => {\n const t = getColumnTrack(column, columnWidths[column.id]);\n items.push(t.templateValue);\n minWidth += t.minPx;\n });\n return { template: items.join(' '), minWidth };\n }, [columns, columnWidths, showSelectColumn]);\n\n const renderSortIndicator = (column: DataTableColumn<R>) => {\n if (!column.sortable) return null;\n const active =\n sortState.columnId === column.id && sortState.direction !== null;\n const direction = active ? sortState.direction : null;\n const Icon =\n direction === 'asc'\n ? ChevronUpIcon\n : direction === 'desc'\n ? ChevronDownIcon\n : SortIcon;\n return (\n <span\n className={sortIndicatorRecipe({ active: active || undefined })}\n aria-hidden=\"true\"\n >\n <Icon size=\"sm\" />\n </span>\n );\n };\n\n const beginResize = useCallback(\n (\n columnId: string,\n startX: number,\n startWidth: number,\n column: DataTableColumn<R>\n ) => {\n const minWidth = column.minWidth ?? 40;\n const maxWidth = column.maxWidth ?? Infinity;\n const handleMove = (event: PointerEvent) => {\n const delta = event.clientX - startX;\n const next = Math.max(minWidth, Math.min(maxWidth, startWidth + delta));\n setColumnWidths(prev => ({ ...prev, [columnId]: next }));\n };\n const handleUp = () => {\n window.removeEventListener('pointermove', handleMove);\n window.removeEventListener('pointerup', handleUp);\n setColumnWidths(prev => {\n const finalWidth = prev[columnId];\n if (finalWidth !== undefined) onColumnResize?.(columnId, finalWidth);\n return prev;\n });\n };\n window.addEventListener('pointermove', handleMove);\n window.addEventListener('pointerup', handleUp);\n },\n [onColumnResize]\n );\n\n const focusRow = useCallback(\n (index: number) => {\n if (sortedRows.length === 0) return;\n const clamped = Math.max(0, Math.min(sortedRows.length - 1, index));\n setActiveRowIndex(clamped);\n if (shouldVirtualize) {\n virtualizer.scrollToIndex(clamped, { align: 'auto' });\n }\n },\n [sortedRows.length, shouldVirtualize, virtualizer]\n );\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (sortedRows.length === 0) return;\n const current = activeRowIndex ?? -1;\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n focusRow(current + 1);\n return;\n case 'ArrowUp':\n event.preventDefault();\n focusRow(current - 1);\n return;\n case 'Home':\n event.preventDefault();\n focusRow(0);\n return;\n case 'End':\n event.preventDefault();\n focusRow(sortedRows.length - 1);\n return;\n case 'PageDown':\n event.preventDefault();\n focusRow(current + 10);\n return;\n case 'PageUp':\n event.preventDefault();\n focusRow(current - 10);\n return;\n case 'Enter': {\n if (current < 0) return;\n event.preventDefault();\n const row = sortedRows[current];\n if (row === undefined) return;\n const k = rowKeys[current];\n if (selectionMode === 'single' && k !== undefined) {\n toggleRowSelection(k, row, current);\n }\n onRowActivate?.(row, current);\n return;\n }\n case ' ': {\n if (current < 0) return;\n if (selectionMode !== 'multiple') return;\n event.preventDefault();\n const row = sortedRows[current];\n const k = rowKeys[current];\n if (row === undefined || k === undefined) return;\n toggleRowSelection(k, row, current, event.shiftKey);\n return;\n }\n default:\n return;\n }\n },\n [\n activeRowIndex,\n focusRow,\n sortedRows,\n rowKeys,\n selectionMode,\n toggleRowSelection,\n onRowActivate,\n ]\n );\n\n useEffect(() => {\n if (activeRowIndex !== null && activeRowIndex >= sortedRows.length) {\n setActiveRowIndex(sortedRows.length === 0 ? null : sortedRows.length - 1);\n }\n }, [activeRowIndex, sortedRows.length]);\n\n const renderHeaderCell = (column: DataTableColumn<R>) => {\n const ariaSort: 'ascending' | 'descending' | 'none' | undefined =\n column.sortable\n ? sortState.columnId === column.id && sortState.direction === 'asc'\n ? 'ascending'\n : sortState.columnId === column.id && sortState.direction === 'desc'\n ? 'descending'\n : 'none'\n : undefined;\n return (\n <div\n key={column.id}\n role=\"columnheader\"\n data-column-id={column.id}\n className={cx(\n headerCellRecipe({\n align: column.align ?? 'left',\n sortable: column.sortable ? true : undefined,\n sticky: column.sticky ? true : undefined,\n }),\n column.className\n )}\n aria-sort={ariaSort}\n aria-hidden={column.ariaHidden ? true : undefined}\n tabIndex={column.sortable ? 0 : undefined}\n onClick={\n column.sortable\n ? () => {\n handleSortClick(column);\n }\n : undefined\n }\n onKeyDown={\n column.sortable\n ? event => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleSortClick(column);\n }\n }\n : undefined\n }\n >\n <span className={headerCellInnerStyle}>\n <span>{column.header}</span>\n {renderSortIndicator(column)}\n </span>\n {resizableColumns && !column.disableResize && (\n <span\n className={resizeHandleStyle}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={`Resize column ${column.id}`}\n onPointerDown={event => {\n event.preventDefault();\n event.stopPropagation();\n const startWidth =\n columnWidths[column.id] ??\n event.currentTarget.parentElement?.getBoundingClientRect()\n .width ??\n 100;\n beginResize(column.id, event.clientX, startWidth, column);\n }}\n />\n )}\n </div>\n );\n };\n\n const renderHeader = () => (\n <div\n role=\"row\"\n aria-rowindex={1}\n className={headerStyle({ sticky: stickyHeader || undefined })}\n >\n {showSelectColumn && (\n <div\n role=\"columnheader\"\n className={headerCellRecipe({ selectColumn: true, sticky: true })}\n aria-label=\"Select all rows\"\n >\n <Checkbox\n checked={allSelectableSelected}\n indeterminate={someSelectableSelected}\n onChange={() => {\n toggleSelectAll();\n }}\n aria-label=\"Select all rows\"\n size=\"sm\"\n />\n </div>\n )}\n {columns.map(renderHeaderCell)}\n </div>\n );\n\n const renderCells = (row: R, rowIdx: number) =>\n columns.map(column => {\n const value = readCellValue(column, row, rowIdx);\n return (\n <div\n key={column.id}\n role=\"gridcell\"\n className={cx(\n cellRecipe({\n align: column.align ?? 'left',\n sticky: column.sticky ? true : undefined,\n }),\n column.className\n )}\n data-column-id={column.id}\n >\n {column.cell\n ? column.cell({ value, row, rowIndex: rowIdx, column })\n : value === null || value === undefined\n ? ''\n : typeof value === 'string'\n ? value\n : typeof value === 'number' || typeof value === 'boolean'\n ? String(value)\n : JSON.stringify(value)}\n </div>\n );\n });\n\n const renderRowElement = (\n row: R,\n rowIdx: number,\n options: { virtualized?: boolean; transformY?: number } = {}\n ) => {\n const k = rowKeys[rowIdx] ?? `__row_${rowIdx}__`;\n const isSelected = selectedSet.has(k);\n const interactive = selectionMode === 'single' || onRowClick !== undefined;\n\n const cells = (\n <>\n {showSelectColumn && (\n <div\n role=\"gridcell\"\n tabIndex={-1}\n className={cellRecipe({ selectColumn: true, sticky: true })}\n onClickCapture={event => {\n selectionShiftKeyRef.current = event.shiftKey;\n }}\n onClick={event => {\n event.stopPropagation();\n }}\n onKeyDown={event => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.stopPropagation();\n }\n }}\n >\n <Checkbox\n checked={isSelected}\n disabled={isRowSelectable ? !isRowSelectable(row, rowIdx) : false}\n onChange={() => {\n toggleRowSelection(\n k,\n row,\n rowIdx,\n selectionShiftKeyRef.current\n );\n selectionShiftKeyRef.current = false;\n }}\n aria-label={`Select row ${rowIdx + 1}`}\n size=\"sm\"\n />\n </div>\n )}\n {renderCells(row, rowIdx)}\n </>\n );\n\n const handleRowClick = (event: React.MouseEvent<HTMLDivElement>) => {\n onRowClick?.(row, rowIdx, event);\n if (selectionMode === 'single') {\n toggleRowSelection(k, row, rowIdx);\n }\n setActiveRowIndex(rowIdx);\n };\n\n const handleRowDoubleClick = () => {\n onRowActivate?.(row, rowIdx);\n };\n\n const handleRowKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n if (selectionMode === 'single') {\n toggleRowSelection(k, row, rowIdx);\n }\n setActiveRowIndex(rowIdx);\n }\n };\n\n const rowContent = renderRow\n ? renderRow({ row, rowIndex: rowIdx, selected: isSelected }, cells)\n : cells;\n\n const rowClassName = rowRecipe({\n virtualized: options.virtualized ? true : undefined,\n interactive: interactive ? true : undefined,\n selected: isSelected ? true : undefined,\n active: activeRowIndex === rowIdx ? true : undefined,\n });\n\n const rowStyle: React.CSSProperties | undefined =\n options.virtualized && options.transformY !== undefined\n ? { transform: `translateY(${options.transformY}px)` }\n : undefined;\n\n return (\n <div\n key={k}\n role=\"row\"\n aria-rowindex={rowIdx + 2}\n aria-selected={selectionMode ? isSelected : undefined}\n data-row-key={k}\n data-row-index={rowIdx}\n data-row-interactive={interactive ? 'true' : undefined}\n className={rowClassName}\n style={rowStyle}\n tabIndex={interactive ? -1 : undefined}\n onClick={interactive ? handleRowClick : undefined}\n onKeyDown={interactive ? handleRowKeyDown : undefined}\n onDoubleClick={onRowActivate ? handleRowDoubleClick : undefined}\n >\n {rowContent}\n </div>\n );\n };\n\n const renderSkeletonRows = () => {\n const rowsToRender = Array.from({ length: loadingRowCount }, (_, i) => i);\n const cellCount = columns.length + (showSelectColumn ? 1 : 0);\n return rowsToRender.map(idx => (\n <div\n key={`__skeleton_${idx}__`}\n className={skeletonRowStyle}\n aria-hidden=\"true\"\n >\n {Array.from({ length: cellCount }, (_, ci) => (\n <div key={ci} className={skeletonCellStyle}>\n <span className={skeletonBarStyle} />\n </div>\n ))}\n </div>\n ));\n };\n\n const containerStyle: React.CSSProperties = {\n height: resolveDimension(height),\n ...(maxHeight !== undefined\n ? { maxHeight: resolveDimension(maxHeight) }\n : {}),\n ...style,\n };\n\n const isEmpty = !loading && sortedRows.length === 0;\n const totalColumnsCount = columns.length + (showSelectColumn ? 1 : 0);\n\n const gridVars = assignInlineVars({\n [gridTemplateColumnsVar]: tracks.template,\n [tableMinWidthVar]: `${tracks.minWidth}px`,\n });\n\n return (\n <div\n ref={ref}\n role=\"grid\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-rowcount={sortedRows.length + 1}\n aria-colcount={totalColumnsCount}\n aria-multiselectable={selectionMode === 'multiple' ? true : undefined}\n data-testid={testId}\n data-density={density}\n tabIndex={0}\n className={cx(rootRecipe({ density }), className)}\n style={{ ...containerStyle, ...gridVars }}\n onKeyDown={handleKeyDown}\n {...rest}\n >\n <div ref={scrollContainerRef} className={scrollContainerStyle}>\n <div className={innerWrapperStyle}>\n {renderHeader()}\n {loading ? (\n <div className={bodyStyle}>{renderSkeletonRows()}</div>\n ) : isEmpty ? (\n <div className={bodyStyle}>\n <div className={emptyStateStyle} role=\"row\">\n <div role=\"gridcell\" aria-colspan={totalColumnsCount}>\n {emptyState ?? 'No rows to display'}\n </div>\n </div>\n </div>\n ) : shouldVirtualize ? (\n <div\n className={virtualBodyStyle}\n style={assignInlineVars({\n [totalHeightVar]: `${totalSize}px`,\n })}\n >\n {virtualItems.map(item => {\n const row = sortedRows[item.index];\n if (row === undefined) return null;\n return renderRowElement(row, item.index, {\n virtualized: true,\n transformY: item.start,\n });\n })}\n </div>\n ) : (\n <div className={bodyStyle}>\n {sortedRows.map((row, rowIdx) => renderRowElement(row, rowIdx))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nDataTableInner.displayName = 'DataTable';\n\nexport const DataTable = DataTableInner as <R>(\n props: DataTableProps<R> & { ref?: React.Ref<HTMLDivElement> }\n) => React.ReactElement;\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAkDA;AACE;AACA;AACA;;AAGF;AACA;AAEA;;AAKoC;AAClC;AACA;AACF;AAEA;AAKE;;AACoC;;AAElC;AACF;AACF;AAEA;;AACe;AACb;AAAmC;AACnC;;;;AAEA;;;;AAGA;AACA;AACA;AACF;AAEA;;AAGwB;;AACC;AACvB;AACF;AAEA;;AAG2B;AACzB;AACF;AAOA;AAIE;;;AAGA;;AAEE;AACA;;AAEF;;AAEF;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH;;AAuCE;;;AAGE;;AAED;AAED;AAEI;AACA;AACA;AACA;AACD;;;AAKH;AACA;AAEA;AACE;AAAgB;AAChB;AACA;AAAqC;AACrC;AACA;AAAa;;;AAGX;AACA;AACA;AACE;AACA;AACF;AACF;AACA;;AAGF;AAKA;AACE;AAAoB;AACpB;AAAsB;;;AAGpB;AAA+B;AACjC;AACA;;AAGF;AAEE;AACE;;AAEF;;AAGA;AACE;;AAEF;AAEF;;;;;;;;AAQU;;;AAGN;AACF;AAIF;AACA;AAEA;AAEI;;;;AAEA;AACE;;;;AAOF;;;;AAKE;AACE;AACA;AACA;;;;AAEA;;;AAGA;;AAEA;AACE;AAAoB;;AACf;;AAEP;AACF;;;AAIF;;AAEE;AACA;AAA0B;;AACrB;AACL;AACF;AACF;AAIF;;;;;;;;;;;AAUA;;;;;;AAMC;AAED;AAEA;;;;;;;;;AAYE;AACA;;AAED;AAED;AACA;AAEA;;;;AAII;;;AAGF;AACE;AACA;AACA;AACF;AACA;;AAGF;;AACwB;AACtB;AAEA;AACA;AAEI;;AAEE;;;AAUR;AAEA;AAOI;AACA;AACA;AACE;AACA;AACA;AACF;;AAEE;AACA;;AAEE;;AAC8B;AAC9B;AACF;AACF;AACA;AACA;AACF;AAIF;AAEI;;;;;;;;AAUJ;AAEI;;AACA;AACA;AACE;;AAEE;;AAEF;;AAEE;;AAEF;;;;AAIA;;AAEE;;AAEF;;AAEE;;AAEF;;AAEE;;;;;;AAKA;;;AAEA;;AAEE;;AAEF;;;;;;;;;AAOA;AACA;AACA;;;;;AAIF;;;AAGJ;;;;;;;;AASC;;;AAKC;;;AAIJ;AACE;AAEI;AACE;AACA;AACE;AACA;;AAER;AAOQ;;;AAGD;;;;AAWC;;AAKI;;;;;;;;AAqBF;AAEE;;AAEA;AACF;;AAMZ;AAEA;AAgBY;AACF;AAUV;;;AASY;;AAED;AAMD;AACA;AACE;AACA;AACE;;AAEE;AACA;AAGd;;;;;AAWA;AAQU;AACF;;AAGA;AAEE;;;AAGF;;AAYI;;AAWZ;;AAEE;AACE;;;AAGJ;;AAGE;AACF;AAEA;AACE;;AAEE;AACE;;;;AAIN;;AAGE;;;;;;;AAQD;;;;;AA0BH;;;AAIE;;AAcF;AAEA;AACE;;;;AAIA;;;AAIF;;AAGE;AACA;AACD;AAED;AAkCc;AACD;;;AAIwB;AACvB;AACE;;AAED;AACH;AAWd;AAEA;AAEO;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowser.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowser.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoCA;AAMA;AACA;AAEA;;;;;AAKG;AACH;;;;AAOI;;AACA;AACA;;;;;AAGF;AACA;AACF;AAEA;AACE;;;;;AAuEA;;;;;AAKA;AAEA;AAEA;;;;AAmBE;;;AAGA;;;AAGA;;;;AAIA;;;;AAIA;;;;;AAKD;AAED;;;;AAIE;;;AAGD;AAED;;;;;;AAcC;;;AAIC;;AAEA;;;;;;;AAOD;;;;AAKC;;;;;;AAMD;;;;AAKC;AACD;AAED;;;;;;;;;AASC;;;;;;AAOD;AAEI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCD;;;;;;;;;;;;;;;;;;AAmBC;;;;;;;;;;;;AAYD;AAGH;;;;;;;;;;;;;;;;AAiBG;;;;;;;;;;;;;;;;AAiBA;;;AAMH;AA2CF;AAEA;AAEO;AACL;AACA;AACD;;"}
1
+ {"version":3,"file":"AssetBrowser.js","sources":["src/components/editor/AssetBrowser/AssetBrowser.tsx"],"sourcesContent":["'use client';\n\nimport React, { useMemo, useRef, useState } from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { body, root } from './AssetBrowser.css';\nimport { AssetBrowserAnnouncementLive } from './AssetBrowserAnnouncementLive';\nimport { AssetBrowserBreadcrumbs } from './AssetBrowserBreadcrumbs';\nimport {\n AssetBrowserChromeContext,\n AssetBrowserContext,\n AssetBrowserStoreContext,\n} from './AssetBrowserContext';\nimport { resolveLabels } from './assetBrowserLabels';\nimport { AssetBrowserSidebar } from './AssetBrowserSidebar';\nimport { AssetBrowserStatusBar } from './AssetBrowserStatusBar';\nimport { AssetBrowserStore } from './AssetBrowserStore';\nimport { AssetBrowserSurface } from './AssetBrowserSurface';\nimport { AssetBrowserToolbar } from './AssetBrowserToolbar';\nimport { getSlotKind, markSlot } from './slots';\nimport { useAssetBrowserHandle } from './useAssetBrowserHandle';\nimport { useAssetBrowserViewState } from './useAssetBrowserViewState';\nimport { useAssetDnd } from './useAssetDnd';\nimport { useAssetMutationKeyboard } from './useAssetMutationKeyboard';\nimport { useAssetMutations } from './useAssetMutations';\nimport { useAssetNavigation } from './useAssetNavigation';\nimport { useAssetSelectionController } from './useAssetSelectionController';\n\nimport type { AssetBrowserProps } from './AssetBrowser.types';\nimport type {\n AssetBrowserChromeValue,\n AssetBrowserContextValue,\n} from './AssetBrowserContext';\nimport type { ReactNode } from 'react';\n\nconst DEFAULT_MIME = 'application/x-entangle-asset';\n\ninterface SlotProps {\n children?: ReactNode;\n}\n\nconst ToolbarSlot = markSlot(() => null, 'toolbar');\nconst SidebarSlot = markSlot(() => null, 'sidebar');\n\n/**\n * Pull the optional `Toolbar` / `Sidebar` slot children out of `children`.\n * Returns through an explicit type so the slots stay `ReactNode` at the call\n * site (a `let x: ReactNode = null` assigned only inside the forEach callback\n * would otherwise stay flow-narrowed to `null`).\n */\nfunction extractSlots(children: ReactNode): {\n toolbarSlot: ReactNode;\n sidebarSlot: ReactNode;\n} {\n let toolbarSlot: ReactNode = null;\n let sidebarSlot: ReactNode = null;\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) return;\n const kind = getSlotKind(child);\n const slotChildren = (child.props as SlotProps).children;\n if (kind === 'toolbar') toolbarSlot = slotChildren;\n else if (kind === 'sidebar') sidebarSlot = slotChildren;\n });\n return { toolbarSlot, sidebarSlot };\n}\n\nfunction AssetBrowserRoot(props: AssetBrowserProps): React.ReactElement {\n const {\n items,\n path = [],\n folderTree,\n currentFolderId,\n selectionMode = 'multiple',\n density = 'comfortable',\n showStatusBar = false,\n manualSearch = false,\n manualFilter = false,\n manualSort = false,\n filterableTypes: filterableTypesProp,\n loading = false,\n loadingItemCount = 12,\n emptyState,\n error,\n onErrorRetry,\n columns,\n marquee = true,\n history = false,\n renderThumbnail,\n renderItem,\n renderItemContextMenu,\n renderEmptyContextMenu,\n defaultItemActions = false,\n onItemRename,\n onItemsDelete,\n onCreateFolder,\n onItemsDuplicate,\n virtualized = 'auto',\n virtualizationThreshold = 200,\n overscanRows = 4,\n dragOutMimeType = DEFAULT_MIME,\n getDragData,\n onItemDragStart,\n onItemDragEnd,\n onItemsMove,\n onFilesImport,\n className,\n style,\n testId,\n children,\n ref,\n labels: labelsProp,\n 'aria-label': ariaLabel = 'Asset browser',\n // Controlled-state props — destructured so they don't leak onto the DOM\n // root via `...rest`. Consumed by the view-state / selection / navigation\n // hooks below.\n view: viewProp,\n defaultView,\n onViewChange,\n thumbnailSize: thumbnailSizeProp,\n defaultThumbnailSize,\n onThumbnailSizeChange,\n search: searchProp,\n defaultSearch,\n onSearchChange,\n filters: filtersProp,\n defaultFilters,\n onFiltersChange,\n sort: sortProp,\n defaultSort,\n onSortChange,\n selection: selectionProp,\n defaultSelection,\n onSelectionChange,\n onItemOpen,\n onNavigate,\n ...rest\n } = props;\n\n const rootRef = useRef<HTMLDivElement>(null);\n // Lazy `useState` initializer (not `useMemo`) so the per-instance store\n // identity is guaranteed stable for the component's lifetime — `useMemo` may\n // legally drop its cache, which would orphan every slice subscription. Mirrors\n // `useNavigationHistory`'s store-creation idiom.\n const [store] = useState(() => new AssetBrowserStore());\n\n const labels = useMemo(() => resolveLabels(labelsProp), [labelsProp]);\n\n const {\n view,\n setView,\n thumbnailSize,\n setThumbnailSize,\n thumbnailSizePx,\n search,\n setSearch,\n filters,\n setFilters,\n sort,\n setSort,\n filterableTypes,\n displayed,\n marqueeEnabled,\n } = useAssetBrowserViewState({\n items,\n selectionMode,\n marquee,\n view: viewProp,\n defaultView,\n onViewChange,\n thumbnailSize: thumbnailSizeProp,\n defaultThumbnailSize,\n onThumbnailSizeChange,\n search: searchProp,\n defaultSearch,\n onSearchChange,\n manualSearch,\n filters: filtersProp,\n defaultFilters,\n onFiltersChange,\n manualFilter,\n sort: sortProp,\n defaultSort,\n onSortChange,\n manualSort,\n filterableTypesProp,\n });\n\n const { selectionSet, handlers } = useAssetSelectionController({\n store,\n displayed,\n selectionMode,\n selection: selectionProp,\n defaultSelection,\n onSelectionChange,\n });\n\n const {\n navigate,\n activateItem,\n goBack,\n goForward,\n canGoBack,\n canGoForward,\n handleRootKeyDown,\n } = useAssetNavigation({\n history,\n path,\n currentFolderId,\n onNavigate,\n onItemOpen,\n });\n\n const dnd = useAssetDnd({\n store,\n mime: dragOutMimeType,\n items,\n selection: selectionSet,\n currentFolderId,\n getDragData,\n onItemDragStart,\n onItemDragEnd,\n onItemsMove,\n onFilesImport,\n });\n\n const mutations = useAssetMutations({\n store,\n displayed,\n selection: selectionSet,\n currentFolderId,\n onItemRename,\n onItemsDelete,\n onCreateFolder,\n onItemsDuplicate,\n });\n\n const mutationKeyboard = useAssetMutationKeyboard({\n store,\n mutations,\n selection: selectionSet,\n });\n\n useAssetBrowserHandle({\n ref,\n rootRef,\n store,\n items,\n displayed,\n selectAll: handlers.selectAll,\n clearSelection: handlers.clearSelection,\n beginRename: mutations.beginRename,\n });\n\n // Render-props are forwarded through the item context as-is. They are called\n // during render (by grid/list cells), so they can't be stabilized with a\n // render-phase ref write (react-hooks/refs) or `useLatest` (its ref updates\n // in an effect, one render late). Consumers that pass inline render-props and\n // care about per-cell render cost should memoize them, mirroring `TreeView`.\n const itemValue = useMemo<AssetBrowserContextValue>(\n () => ({\n displayedItems: displayed,\n thumbnailSizePx,\n density,\n selectionMode,\n marqueeEnabled,\n handleItemClick: handlers.handleItemClick,\n activateItem,\n selectAll: handlers.selectAll,\n clearSelection: handlers.clearSelection,\n contextMenuSelect: handlers.contextMenuSelect,\n selectByKeyboard: handlers.selectByKeyboard,\n toggleSelectId: handlers.toggleSelectId,\n setSelectionIds: handlers.setSelectionIds,\n commitMarquee: handlers.commitMarquee,\n path,\n folderTree,\n currentFolderId,\n navigate,\n renderThumbnail,\n renderItem,\n renderItemContextMenu,\n renderEmptyContextMenu,\n defaultItemActions,\n mutations,\n mutationKeyDown: mutationKeyboard.onKeyDown,\n loading,\n loadingItemCount,\n emptyState,\n error,\n onErrorRetry,\n columns,\n dnd,\n virtualized,\n virtualizationThreshold,\n overscanRows,\n labels,\n }),\n [\n displayed,\n thumbnailSizePx,\n density,\n selectionMode,\n marqueeEnabled,\n handlers,\n activateItem,\n path,\n folderTree,\n currentFolderId,\n navigate,\n renderThumbnail,\n renderItem,\n renderItemContextMenu,\n renderEmptyContextMenu,\n defaultItemActions,\n mutations,\n mutationKeyboard.onKeyDown,\n loading,\n loadingItemCount,\n emptyState,\n error,\n onErrorRetry,\n columns,\n dnd,\n virtualized,\n virtualizationThreshold,\n overscanRows,\n labels,\n ]\n );\n\n const chromeValue = useMemo<AssetBrowserChromeValue>(\n () => ({\n view,\n setView,\n search,\n setSearch,\n filters,\n setFilters,\n filterableTypes,\n sort,\n setSort,\n history,\n canGoBack,\n canGoForward,\n goBack,\n goForward,\n labels,\n }),\n [\n view,\n setView,\n search,\n setSearch,\n filters,\n setFilters,\n filterableTypes,\n sort,\n setSort,\n history,\n canGoBack,\n canGoForward,\n goBack,\n goForward,\n labels,\n ]\n );\n\n // Slot extraction.\n const { toolbarSlot, sidebarSlot } = extractSlots(children);\n\n return (\n <AssetBrowserStoreContext.Provider value={store}>\n <AssetBrowserChromeContext.Provider value={chromeValue}>\n <AssetBrowserContext.Provider value={itemValue}>\n {/* The root is a labelled region that hosts the asset-browser widget;\n its onKeyDown adds widget-level shortcuts (Backspace / Alt+ArrowUp\n → parent folder), so the handler on a non-interactive role is\n intentional. */}\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}\n <div\n ref={rootRef}\n className={cx(root, className)}\n style={style}\n data-testid={testId}\n role=\"region\"\n tabIndex={-1}\n aria-label={ariaLabel}\n onKeyDown={handleRootKeyDown}\n {...rest}\n >\n {toolbarSlot ?? <AssetBrowserToolbar />}\n <AssetBrowserBreadcrumbs />\n <div className={body}>\n {sidebarSlot ?? <AssetBrowserSidebar />}\n <AssetBrowserSurface\n onDragOver={dnd.onSurfaceDragOver}\n onDragLeave={dnd.onSurfaceDragLeave}\n onDrop={dnd.onSurfaceDrop}\n />\n </div>\n {showStatusBar && (\n <AssetBrowserStatusBar\n view={view}\n thumbnailSize={thumbnailSize}\n setThumbnailSize={setThumbnailSize}\n />\n )}\n <AssetBrowserAnnouncementLive />\n </div>\n </AssetBrowserContext.Provider>\n </AssetBrowserChromeContext.Provider>\n </AssetBrowserStoreContext.Provider>\n );\n}\n\nAssetBrowserRoot.displayName = 'AssetBrowser';\n\nexport const AssetBrowser = /*#__PURE__*/ Object.assign(AssetBrowserRoot, {\n Toolbar: ToolbarSlot,\n Sidebar: SidebarSlot,\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoCA;AAMA;AACA;AAEA;;;;;AAKG;AACH;;;;AAOI;;AACA;AACA;;;;;AAGF;AACA;AACF;AAEA;AACE;;;;;AAuEA;;;;;AAKA;AAEA;AAEA;;;;AAmBE;;;AAGA;;;AAGA;;;;AAIA;;;;AAIA;;;;;AAKD;AAED;;;;AAIE;;;AAGD;AAED;;;;;;AAcC;;;AAIC;;AAEA;;;;;;;AAOD;;;;AAKC;;;;;;AAMD;;;;AAKC;AACD;AAED;;;;;;;;;AASC;;;;;;AAOD;AAEI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCD;;;;;;;;;;;;;;;;;;AAmBC;;;;;;;;;;;;AAYD;AAGH;;;;;;;;;;;;;;;;AAiBG;;;;;;;;;;;;;;;;AAiBA;;;AAMH;AA2CF;AAEA;AAEO;AACL;AACA;AACD;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserAnnouncementLive.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserAnnouncementLive.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;AAOA;;;;AAIG;;AAED;AACA;AAKF;;"}
1
+ {"version":3,"file":"AssetBrowserAnnouncementLive.js","sources":["src/components/editor/AssetBrowser/AssetBrowserAnnouncementLive.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { srOnly } from './AssetBrowser.css';\nimport { useAssetBrowserAnnouncement } from './useAssetBrowserAnnouncement';\n\n/**\n * Screen-reader-only `aria-live=\"polite\"` region carrying the current\n * \"N items, M selected\" announcement. Subscribes to the displayed-count and\n * selection slices via {@link useAssetBrowserAnnouncement}.\n */\nexport function AssetBrowserAnnouncementLive(): React.ReactElement {\n const announcement = useAssetBrowserAnnouncement();\n return (\n <div className={srOnly} aria-live=\"polite\" role=\"status\">\n {announcement}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;AAOA;;;;AAIG;;AAED;AACA;AAKF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserBreadcrumbs.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserBreadcrumbs.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;AAaE;AACA;AAA2B;AAE3B;;;AAWgB;;;;AASV;AAIR;;"}
1
+ {"version":3,"file":"AssetBrowserBreadcrumbs.js","sources":["src/components/editor/AssetBrowser/AssetBrowserBreadcrumbs.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport {\n Breadcrumbs,\n BreadcrumbItem,\n} from '@/components/navigation/Breadcrumbs';\n\nimport { breadcrumbsBar } from './AssetBrowser.css';\nimport { useAssetBrowserContext } from './AssetBrowserContext';\n\nexport function AssetBrowserBreadcrumbs(): React.ReactElement | null {\n const ctx = useAssetBrowserContext();\n if (ctx.path.length === 0) return null;\n\n return (\n <div className={breadcrumbsBar}>\n <Breadcrumbs maxItems={4} itemsAfterCollapse={2} itemsBeforeCollapse={1}>\n {ctx.path.map((segment, index) => {\n const isLast = index === ctx.path.length - 1;\n return (\n <BreadcrumbItem\n key={segment.id}\n isCurrent={isLast}\n onClick={\n isLast\n ? undefined\n : () => {\n ctx.navigate(segment.id, 'breadcrumb');\n }\n }\n >\n {segment.name}\n </BreadcrumbItem>\n );\n })}\n </Breadcrumbs>\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;AAaE;AACA;AAA2B;AAE3B;;;AAWgB;;;;AASV;AAIR;;"}
@@ -92,6 +92,12 @@ import '../../Icons/GitBranchIcon.js';
92
92
  import '../../Icons/BugIcon.js';
93
93
  import '../../Icons/MinusIcon.js';
94
94
  import '../../Icons/PinIcon.js';
95
+ import '../../Icons/OrbitIcon.js';
96
+ import '../../Icons/RotateIcon.js';
97
+ import '../../Icons/SpinIcon.js';
98
+ import '../../Icons/CameraIcon.js';
99
+ import '../../Icons/CubeIcon.js';
100
+ import '../../Icons/ZoomFitIcon.js';
95
101
  import { Button } from '../../primitives/Button/Button.js';
96
102
  import { emptyWrap, emptyText, loadingGrid, skeletonCell, cellWidthVar } from './AssetBrowser.css.js';
97
103
  import { useAssetBrowserContext, useAssetBrowserChrome } from './AssetBrowserContext.js';
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserContent.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserContent.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;;AAKG;AACH;;AAuBA;AAEA;;;;AAIG;;;AAYD;;;AAIA;AACE;;;AAsBA;;AAQF;AACE;;AAMF;AACF;;"}
1
+ {"version":3,"file":"AssetBrowserContent.js","sources":["src/components/editor/AssetBrowser/AssetBrowserContent.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { EmptyState } from '@/components/feedback/EmptyState';\nimport { Skeleton } from '@/components/feedback/Skeleton';\nimport { ErrorIcon } from '@/components/Icons';\nimport { Button } from '@/components/primitives/Button';\n\nimport {\n cellWidthVar,\n emptyText,\n emptyWrap,\n loadingGrid,\n skeletonCell,\n} from './AssetBrowser.css';\nimport {\n useAssetBrowserChrome,\n useAssetBrowserContext,\n} from './AssetBrowserContext';\nimport { cellWidth } from './assetBrowserGeometry';\nimport { AssetBrowserGrid } from './AssetBrowserGrid';\nimport { AssetBrowserList } from './AssetBrowserList';\n\n/**\n * Skeleton placeholder grid shown while `loading`. Renders `loadingItemCount`\n * cells sized to the current thumbnail scale (a square block + a label line)\n * so the loading state matches the real grid's geometry instead of a lone\n * spinner. Static (`animation=\"none\"`) — dozens of pulsing blocks are noise.\n */\nfunction LoadingGrid({\n count,\n thumbPx,\n}: {\n count: number;\n thumbPx: number;\n}): React.ReactElement {\n return (\n <div\n className={loadingGrid}\n style={assignInlineVars({ [cellWidthVar]: `${cellWidth(thumbPx)}px` })}\n role=\"presentation\"\n aria-hidden\n data-testid=\"asset-browser-loading\"\n >\n {Array.from({ length: Math.max(0, count) }, (_, i) => (\n <div key={i} className={skeletonCell}>\n <Skeleton width={thumbPx} height={thumbPx} animation=\"none\" />\n <Skeleton shape=\"line\" width=\"80%\" animation=\"none\" />\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Resolves the main content area: error → error state, loading → skeleton grid,\n * empty → empty state, otherwise the grid or list view depending on\n * `chrome.view`.\n */\nexport function AssetBrowserContent(): React.ReactElement {\n const {\n loading,\n loadingItemCount,\n thumbnailSizePx,\n displayedItems,\n emptyState,\n error,\n onErrorRetry,\n labels,\n } = useAssetBrowserContext();\n const { view } = useAssetBrowserChrome();\n\n // `null` / `undefined` / `false` → no error; `true` → built-in message;\n // any other node → custom replacement.\n if (error !== undefined && error !== null && error !== false) {\n return (\n <div className={emptyWrap}>\n {error === true ? (\n <EmptyState\n icon={<ErrorIcon />}\n title={labels.errorTitle}\n description={labels.errorDescription}\n action={\n onErrorRetry ? (\n <Button size=\"sm\" variant=\"default\" onClick={onErrorRetry}>\n {labels.retry}\n </Button>\n ) : undefined\n }\n />\n ) : (\n error\n )}\n </div>\n );\n }\n if (loading) {\n return view === 'grid' ? (\n <LoadingGrid count={loadingItemCount} thumbPx={thumbnailSizePx} />\n ) : (\n <div className={emptyWrap}>\n <EmptyState loading title={labels.loading} />\n </div>\n );\n }\n if (displayedItems.length === 0) {\n return (\n <div className={emptyWrap}>\n {emptyState ?? <span className={emptyText}>{labels.empty}</span>}\n </div>\n );\n }\n return view === 'grid' ? <AssetBrowserGrid /> : <AssetBrowserList />;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;;AAKG;AACH;;AAuBA;AAEA;;;;AAIG;;;AAYD;;;AAIA;AACE;;;AAsBA;;AAQF;AACE;;AAMF;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserContext.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserContext.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AA8BA;;AAGE;;AAGA;;AAEE;;AAIF;AACF;AAOA;;;;AAIG;AACG;AACJ;AACA;AAIF;AAEA;;;;AAIG;AACG;AACJ;AACA;AAIF;;AAGE;;AAEF;;AAGE;;AAEF;AAEA;AACM;AACJ;AACA;AACE;;AAEF;AACF;AAEA;;AAEE;;AAEF;AAEA;;;AAGG;AACG;AACJ;AACA;AAGF;;AAiGE;;AAGA;;AAEE;;AAIF;AACF;;AA8BE;;AAGA;;AAEE;;AAIF;AACF;;"}
1
+ {"version":3,"file":"AssetBrowserContext.js","sources":["src/components/editor/AssetBrowser/AssetBrowserContext.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext, useSyncExternalStore } from 'react';\n\nimport type {\n AssetFilterState,\n AssetItem,\n AssetItemActions,\n AssetItemState,\n AssetNavigationSource,\n AssetPathSegment,\n AssetSelectionReason,\n AssetSortState,\n AssetView,\n} from './AssetBrowser.types';\nimport type { AssetBrowserLabels } from './assetBrowserLabels';\nimport type {\n AssetBrowserStore,\n DragState,\n MarqueeState,\n} from './AssetBrowserStore';\nimport type { AssetMutationsApi } from './useAssetMutations';\nimport type { TreeNodeData } from '@/components/controls/TreeView';\nimport type {\n DataTableColumn,\n DataTableDensity,\n} from '@/components/data/DataTable';\nimport type { ReactNode } from 'react';\nimport type React from 'react';\n\n// ── Store context (hot path) ─────────────────────────────────────────────\n\nexport const AssetBrowserStoreContext =\n /*#__PURE__*/ createContext<AssetBrowserStore | null>(null);\n\nexport function useAssetBrowserStore(): AssetBrowserStore {\n const store = useContext(AssetBrowserStoreContext);\n if (!store) {\n throw new Error(\n 'AssetBrowser slice hooks must be used inside an <AssetBrowser> subtree.'\n );\n }\n return store;\n}\n\nexport function useAssetFocus(): string | null {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(store.subscribeFocus, store.getFocusedId);\n}\n\n/**\n * Per-id focus slice: `true` only for the roving-focus item. Returns a boolean\n * so arrow-key navigation re-renders just the two affected cells, not the whole\n * grid.\n */\nexport function useAssetFocused(id: string): boolean {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(\n store.subscribeFocus,\n () => store.getFocusedId() === id\n );\n}\n\n/**\n * Per-id rename slice: `true` only for the item whose label is being edited\n * inline. Returns a boolean so entering/leaving rename re-renders only that\n * cell.\n */\nexport function useAssetEditing(id: string): boolean {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(\n store.subscribeEditing,\n () => store.getEditingId() === id\n );\n}\n\nexport function useAssetMarquee(): MarqueeState {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(store.subscribeMarquee, store.getMarquee);\n}\n\nexport function useAssetDrag(): DragState {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(store.subscribeDrag, store.getDrag);\n}\n\n/** Per-id drop-target slice: `true` while an active drag hovers this folder. */\nexport function useAssetDropTarget(id: string): boolean {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(store.subscribeDrag, () => {\n const drag = store.getDrag();\n return drag.active && drag.dropTargetId === id;\n });\n}\n\n/** The full selection set (whole-set consumers: list view, status bar). */\nexport function useAssetSelection(): ReadonlySet<string> {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(store.subscribeSelection, store.getSelection);\n}\n\n/**\n * Per-id selection slice. Returns a boolean so selecting an item re-renders\n * only the cells whose state actually flipped.\n */\nexport function useAssetSelected(id: string): boolean {\n const store = useAssetBrowserStore();\n return useSyncExternalStore(store.subscribeSelection, () =>\n store.getSelection().has(id)\n );\n}\n\n// ── Item context (data + interaction; consumed by every grid cell) ──────────\n\nexport interface AssetDndContext {\n internalEnabled: boolean;\n externalEnabled: boolean;\n onItemDragStart: (item: AssetItem, event: React.DragEvent) => void;\n onItemDragEnd: (item: AssetItem, event: React.DragEvent) => void;\n onFolderDragOver: (folderId: string, event: React.DragEvent) => void;\n onFolderDragLeave: (folderId: string, event: React.DragEvent) => void;\n onFolderDrop: (folderId: string, event: React.DragEvent) => void;\n onSurfaceDragOver: (event: React.DragEvent) => void;\n onSurfaceDragLeave: (event: React.DragEvent) => void;\n onSurfaceDrop: (event: React.DragEvent) => void;\n}\n\nexport interface AssetBrowserContextValue {\n // data\n displayedItems: readonly AssetItem[];\n\n // layout / mode (read by cells)\n thumbnailSizePx: number;\n density: DataTableDensity;\n selectionMode: 'single' | 'multiple' | false;\n /** Whether rubber-band marquee selection is active (multiple + `marquee`). */\n marqueeEnabled: boolean;\n\n // interaction handlers\n handleItemClick: (\n item: AssetItem,\n index: number,\n event: React.MouseEvent\n ) => void;\n activateItem: (item: AssetItem) => void;\n selectAll: () => void;\n clearSelection: () => void;\n contextMenuSelect: (item: AssetItem) => void;\n /** Select-or-extend driven by keyboard navigation over displayed order. */\n selectByKeyboard: (index: number, extend: boolean) => void;\n /** Toggle a single id (Space / Ctrl-click parity). */\n toggleSelectId: (id: string) => void;\n /** Replace selection with a raw id list (DataTable bridge). */\n setSelectionIds: (ids: string[], reason: AssetSelectionReason) => void;\n /** Commit a marquee result (additive merges with current selection). */\n commitMarquee: (ids: string[], additive: boolean) => void;\n\n // navigation\n path: readonly AssetPathSegment[];\n folderTree?: readonly TreeNodeData[];\n currentFolderId?: string;\n navigate: (folderId: string, source: AssetNavigationSource) => void;\n\n // render props\n renderThumbnail?: (\n item: AssetItem,\n ctx: { size: number; selected: boolean }\n ) => ReactNode;\n renderItem?: (item: AssetItem, state: AssetItemState) => ReactNode;\n renderItemContextMenu?: (\n items: AssetItem[],\n actions: AssetItemActions\n ) => ReactNode;\n renderEmptyContextMenu?: () => ReactNode;\n /** Auto-build default Rename/Duplicate/Delete/New-folder menu entries. */\n defaultItemActions: boolean;\n\n // mutations (inline rename, delete, create-folder, duplicate)\n mutations: AssetMutationsApi;\n /**\n * Mutation keyboard handler (F2 / Delete / Ctrl+D). Attached by each view to\n * its own scroller so the shortcuts work in both grid and list without\n * relying on event bubbling to the root.\n */\n mutationKeyDown: (event: React.KeyboardEvent) => void;\n\n // states\n loading: boolean;\n loadingItemCount: number;\n emptyState?: ReactNode;\n error?: ReactNode;\n onErrorRetry?: () => void;\n columns?: readonly DataTableColumn<AssetItem>[];\n\n // drag & drop\n dnd: AssetDndContext;\n\n // virtualization\n virtualized: boolean | 'auto';\n virtualizationThreshold: number;\n overscanRows: number;\n\n // i18n (resolved: defaults merged with the consumer's overrides)\n labels: AssetBrowserLabels;\n}\n\nexport const AssetBrowserContext =\n /*#__PURE__*/ createContext<AssetBrowserContextValue | null>(null);\n\nexport function useAssetBrowserContext(): AssetBrowserContextValue {\n const value = useContext(AssetBrowserContext);\n if (!value) {\n throw new Error(\n 'AssetBrowser subcomponents must be used inside an <AssetBrowser>.'\n );\n }\n return value;\n}\n\n// ── Chrome context (view / search / filter / sort / history) ────────────────\n// Split from the item context so typing in the search box (a per-keystroke\n// update) re-renders only the toolbar, not every grid cell.\n\nexport interface AssetBrowserChromeValue {\n view: AssetView;\n setView: (view: AssetView) => void;\n\n search: string;\n setSearch: (query: string) => void;\n filters: AssetFilterState;\n setFilters: (filters: AssetFilterState) => void;\n filterableTypes: string[];\n sort: AssetSortState;\n setSort: (sort: AssetSortState) => void;\n\n // history (only meaningful when the `history` prop is enabled)\n history: boolean;\n canGoBack: boolean;\n canGoForward: boolean;\n goBack: () => void;\n goForward: () => void;\n\n // i18n (resolved: defaults merged with the consumer's overrides)\n labels: AssetBrowserLabels;\n}\n\nexport const AssetBrowserChromeContext =\n /*#__PURE__*/ createContext<AssetBrowserChromeValue | null>(null);\n\nexport function useAssetBrowserChrome(): AssetBrowserChromeValue {\n const value = useContext(AssetBrowserChromeContext);\n if (!value) {\n throw new Error(\n 'AssetBrowser chrome subcomponents must be used inside an <AssetBrowser>.'\n );\n }\n return value;\n}\n"],"names":[],"mappings":";;;AA8BA;;AAGE;;AAGA;;AAEE;;AAIF;AACF;AAOA;;;;AAIG;AACG;AACJ;AACA;AAIF;AAEA;;;;AAIG;AACG;AACJ;AACA;AAIF;;AAGE;;AAEF;;AAGE;;AAEF;AAEA;AACM;AACJ;AACA;AACE;;AAEF;AACF;AAEA;;AAEE;;AAEF;AAEA;;;AAGG;AACG;AACJ;AACA;AAGF;;AAiGE;;AAGA;;AAEE;;AAIF;AACF;;AA8BE;;AAGA;;AAEE;;AAIF;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserContextMenu.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserContextMenu.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;AAgBA;AACA;;AACiC;;AAG7B;;AAEE;AAEN;AAEA;AACA;;AACkC;;AAElC;AAEA;;;;;;AAMG;AACH;AACE;AACA;AACA;;;AAGI;;;AAIJ;;;AAGI;AACA;;;;AAGA;;;AAGA;;;AAIJ;;;AAGA;AACF;AAEA;AACA;AACE;;AACgC;;AAElC;AAEA;;;;;;;;;;;;;AAaG;AACG;AAKJ;;;;;AAKA;AAEA;AACA;;AAGA;;AAEA;;;AAGE;;;AAIA;AAEE;AACA;AACF;;;AAGE;AACA;AAAU;;AAEd;AAEA;AAEA;;;AAMQ;;;;;;;AA0BV;;"}
1
+ {"version":3,"file":"AssetBrowserContextMenu.js","sources":["src/components/editor/AssetBrowser/AssetBrowserContextMenu.tsx"],"sourcesContent":["'use client';\n\nimport React, { useRef, useState } from 'react';\n\nimport { ContextMenu } from '@/components/navigation/ContextMenu';\n\nimport { contextMenuTrigger } from './AssetBrowser.css';\nimport {\n useAssetBrowserContext,\n useAssetSelection,\n} from './AssetBrowserContext';\nimport { DefaultEmptyMenu, DefaultItemMenu } from './AssetBrowserDefaultMenus';\n\nimport type { AssetItem, AssetItemActions } from './AssetBrowser.types';\nimport type { AssetBrowserContextValue } from './AssetBrowserContext';\n\n/** Whether any item-level menu can be shown (custom render-prop or auto-built). */\nfunction hasItemMenu(ctx: AssetBrowserContextValue): boolean {\n if (ctx.renderItemContextMenu) return true;\n return (\n ctx.defaultItemActions &&\n (ctx.mutations.canRename ||\n ctx.mutations.canDelete ||\n ctx.mutations.canDuplicate)\n );\n}\n\n/** Whether any empty-area menu can be shown. */\nfunction hasEmptyMenu(ctx: AssetBrowserContextValue): boolean {\n if (ctx.renderEmptyContextMenu) return true;\n return ctx.defaultItemActions && ctx.mutations.canCreateFolder;\n}\n\n/**\n * Item context-menu body for the right-clicked item. Resolves the acted-on\n * items (the whole selection when the target is part of it, otherwise just the\n * target), builds the mutation `actions` bound to them, and renders either the\n * consumer's `renderItemContextMenu` or the auto-built default menu. Rendered\n * only while the menu is open (base-ui unmounts closed popups).\n */\nfunction ItemMenuBody({ targetId }: { targetId: string }): React.ReactElement {\n const ctx = useAssetBrowserContext();\n const selection = useAssetSelection();\n const target = ctx.displayedItems.find(it => it.id === targetId);\n const items: AssetItem[] = target\n ? selection.has(target.id)\n ? ctx.displayedItems.filter(it => selection.has(it.id))\n : [target]\n : [];\n\n const actions: AssetItemActions = {\n items,\n rename: () => {\n const first = items[0];\n if (first) ctx.mutations.beginRename(first.id);\n },\n delete: () => {\n ctx.mutations.deleteItems(items);\n },\n duplicate: () => {\n ctx.mutations.duplicateItems(items);\n },\n };\n\n if (ctx.renderItemContextMenu) {\n return <>{ctx.renderItemContextMenu(items, actions)}</>;\n }\n return <DefaultItemMenu actions={actions} />;\n}\n\n/** Empty-area context-menu body (consumer render-prop or the default). */\nfunction EmptyMenuBody(): React.ReactElement {\n const ctx = useAssetBrowserContext();\n if (ctx.renderEmptyContextMenu) return <>{ctx.renderEmptyContextMenu()}</>;\n return <DefaultEmptyMenu />;\n}\n\n/**\n * Single, view-agnostic context-menu mechanism for the whole content surface.\n *\n * One `ContextMenu` wraps both the grid and the list. On right-click it walks up\n * from the event target to the nearest item element — a grid cell\n * (`[data-asset-id]`) or a list row (`[data-row-key]`, set by DataTable to the\n * row's id) — to decide whether an **item** was hit (show the item menu + select\n * it) or **empty space** (show the empty-area menu). The same code path runs\n * regardless of view, so grid and list share identical right-click behaviour\n * with no per-cell / per-row wrapping and no DataTable changes.\n *\n * Open state is controlled so a right-click that resolves to no body (e.g. blank\n * space when only an item menu is configured) never opens an empty popup.\n */\nexport function AssetBrowserContextMenuLayer({\n children,\n}: {\n children: React.ReactNode;\n}): React.ReactElement {\n const ctx = useAssetBrowserContext();\n const [open, setOpen] = useState(false);\n const [targetId, setTargetId] = useState<string | null>(null);\n // Synchronous mirror of the right-clicked target, read by `onOpenChange`\n // (which fires in the same event, before the `setTargetId` render flushes).\n const targetIdRef = useRef<string | null>(null);\n\n const itemEnabled = hasItemMenu(ctx);\n const emptyEnabled = hasEmptyMenu(ctx);\n\n // No menus configured → render the surface untouched.\n if (!itemEnabled && !emptyEnabled) return <>{children}</>;\n\n const handleContextMenuCapture = (event: React.MouseEvent): void => {\n // Grid cells carry `data-asset-id`; DataTable list rows carry `data-row-key`\n // (the asset id, since `rowKey=\"id\"`). Match either to find the hit item.\n const el =\n event.target instanceof Element\n ? event.target.closest('[data-asset-id], [data-row-key]')\n : null;\n const id =\n el?.getAttribute('data-asset-id') ??\n el?.getAttribute('data-row-key') ??\n null;\n targetIdRef.current = id;\n setTargetId(id);\n if (id) {\n const item = ctx.displayedItems.find(it => it.id === id);\n if (item) ctx.contextMenuSelect(item);\n }\n };\n\n const showItemBody = targetId !== null && itemEnabled;\n\n return (\n <ContextMenu\n open={open}\n onOpenChange={next => {\n // Only allow opening when the resolved target has a body to show.\n if (next) {\n const willShow = targetIdRef.current ? itemEnabled : emptyEnabled;\n setOpen(willShow);\n } else {\n setOpen(false);\n }\n }}\n >\n <ContextMenu.Trigger\n render={\n <div\n className={contextMenuTrigger}\n onContextMenuCapture={handleContextMenuCapture}\n >\n {children}\n </div>\n }\n />\n <ContextMenu.Content>\n {showItemBody ? (\n <ItemMenuBody targetId={targetId} />\n ) : emptyEnabled ? (\n <EmptyMenuBody />\n ) : null}\n </ContextMenu.Content>\n </ContextMenu>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAgBA;AACA;;AACiC;;AAG7B;;AAEE;AAEN;AAEA;AACA;;AACkC;;AAElC;AAEA;;;;;;AAMG;AACH;AACE;AACA;AACA;;;AAGI;;;AAIJ;;;AAGI;AACA;;;;AAGA;;;AAGA;;;AAIJ;;;AAGA;AACF;AAEA;AACA;AACE;;AACgC;;AAElC;AAEA;;;;;;;;;;;;;AAaG;AACG;AAKJ;;;;;AAKA;AAEA;AACA;;AAGA;;AAEA;;;AAGE;;;AAIA;AAEE;AACA;AACF;;;AAGE;AACA;AAAU;;AAEd;AAEA;AAEA;;;AAMQ;;;;;;;AA0BV;;"}
@@ -87,6 +87,12 @@ import '../../Icons/GitBranchIcon.js';
87
87
  import '../../Icons/BugIcon.js';
88
88
  import '../../Icons/MinusIcon.js';
89
89
  import '../../Icons/PinIcon.js';
90
+ import '../../Icons/OrbitIcon.js';
91
+ import '../../Icons/RotateIcon.js';
92
+ import '../../Icons/SpinIcon.js';
93
+ import '../../Icons/CameraIcon.js';
94
+ import '../../Icons/CubeIcon.js';
95
+ import '../../Icons/ZoomFitIcon.js';
90
96
  import { Menu } from '../../navigation/Menu/Menu.js';
91
97
  import { useAssetBrowserContext } from './AssetBrowserContext.js';
92
98
 
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserDefaultMenus.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserDefaultMenus.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA;;;;AAIG;AACG;;;;AASJ;AACE;;AAYF;;;AAWA;AACE;;;;AAQF;AAA0B;;AAE5B;AAEA;;;;AAIG;;;;AAG+B;;AAMlC;;"}
1
+ {"version":3,"file":"AssetBrowserDefaultMenus.js","sources":["src/components/editor/AssetBrowser/AssetBrowserDefaultMenus.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { CopyIcon, EditIcon, FolderIcon, TrashIcon } from '@/components/Icons';\nimport { Menu } from '@/components/navigation/Menu';\n\nimport { useAssetBrowserContext } from './AssetBrowserContext';\n\nimport type { AssetItemActions } from './AssetBrowser.types';\n\n/**\n * Auto-generated item context-menu body used when `defaultItemActions` is set\n * and the consumer hasn't supplied `renderItemContextMenu`. Renders only the\n * entries whose mutation callback is present. Rename targets a single item.\n */\nexport function DefaultItemMenu({\n actions,\n}: {\n actions: AssetItemActions;\n}): React.ReactElement | null {\n const { mutations, labels } = useAssetBrowserContext();\n const single = actions.items.length === 1;\n\n const entries: React.ReactNode[] = [];\n if (mutations.canRename) {\n entries.push(\n <Menu.Item\n key=\"rename\"\n icon={<EditIcon />}\n shortcut=\"F2\"\n disabled={!single}\n onClick={actions.rename}\n >\n {labels.rename}\n </Menu.Item>\n );\n }\n if (mutations.canDuplicate) {\n entries.push(\n <Menu.Item\n key=\"duplicate\"\n icon={<CopyIcon />}\n onClick={actions.duplicate}\n >\n {labels.duplicate}\n </Menu.Item>\n );\n }\n if (mutations.canDelete) {\n if (entries.length > 0) entries.push(<Menu.Separator key=\"sep\" />);\n entries.push(\n <Menu.Item key=\"delete\" icon={<TrashIcon />} onClick={actions.delete}>\n {labels.delete}\n </Menu.Item>\n );\n }\n\n if (entries.length === 0) return null;\n return <>{entries}</>;\n}\n\n/**\n * Auto-generated empty-area context-menu body used when `defaultItemActions` is\n * set and the consumer hasn't supplied `renderEmptyContextMenu`. Currently just\n * the New-folder entry (when `onCreateFolder` is present).\n */\nexport function DefaultEmptyMenu(): React.ReactElement | null {\n const { mutations, labels } = useAssetBrowserContext();\n if (!mutations.canCreateFolder) return null;\n return (\n <Menu.Item icon={<FolderIcon />} onClick={mutations.createFolder}>\n {labels.newFolder}\n </Menu.Item>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA;;;;AAIG;AACG;;;;AASJ;AACE;;AAYF;;;AAWA;AACE;;;;AAQF;AAA0B;;AAE5B;AAEA;;;;AAIG;;;;AAG+B;;AAMlC;;"}
@@ -6,7 +6,7 @@ import '../../../utils/devWarn.js';
6
6
  import { useLatest } from '../../../hooks/useLatest/useLatest.js';
7
7
  import '../../../hooks/useBreakpoint/useBreakpoint.js';
8
8
  import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
9
- import '../../../node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js';
9
+ import '@vanilla-extract/css';
10
10
  import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
11
11
  import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
12
12
  import '../../../hooks/useNavigationHistory/useNavigationHistory.js';
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserGrid.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserGrid.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA0CA;AACE;;AACsC;;;;;;;AAYxC;;AAGE;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;AAQE;AACA;;;AAEE;;AACwB;;AAEtB;AACJ;AACA;AACA;AACF;AAEA;AAEE;;AAGA;;;;AAIA;AACD;;AAIG;AACA;;AACA;AACA;AACA;AACA;AAAwB;;;;;;AAS5B;;AAIM;;;;;;;;;;;;;;AAiBL;;;;;;;;AASA;;;AAIC;;AAED;;;;;AAMD;AACA;AAEI;;AAEF;;AAKF;AACE;AACA;;AACA;;AAWF;AAoBU;;AAOE;AACA;AACD;AAgBb;;"}
1
+ {"version":3,"file":"AssetBrowserGrid.js","sources":["src/components/editor/AssetBrowser/AssetBrowserGrid.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n} from 'react';\n\nimport { useLatest } from '@/hooks';\n\nimport {\n columnsVar,\n gridGapVar,\n gridScroller,\n gridSizer,\n gridWindow,\n gridFlow,\n cellWidthVar,\n marquee as marqueeClass,\n marqueeHVar,\n marqueeWVar,\n marqueeXVar,\n marqueeYVar,\n offsetYVar,\n totalHeightVar,\n} from './AssetBrowser.css';\nimport {\n useAssetBrowserContext,\n useAssetBrowserStore,\n useAssetMarquee,\n} from './AssetBrowserContext';\nimport { GRID_GAP, cellDomId, cellWidth } from './assetBrowserGeometry';\nimport { AssetBrowserGridItem } from './AssetBrowserGridItem';\nimport { useAssetGridKeyboardNav } from './useAssetGridKeyboardNav';\nimport { useAssetGridVirtualizer } from './useAssetGridVirtualizer';\nimport { useAssetMarqueeGesture } from './useAssetMarqueeGesture';\n\nimport type { AssetGridWindow } from './useAssetGridVirtualizer';\n\nfunction MarqueeLayer(): React.ReactElement | null {\n const marquee = useAssetMarquee();\n if (!marquee.active || !marquee.rect) return null;\n return (\n <div\n className={marqueeClass}\n style={assignInlineVars({\n [marqueeXVar]: `${marquee.rect.x}px`,\n [marqueeYVar]: `${marquee.rect.y}px`,\n [marqueeWVar]: `${marquee.rect.width}px`,\n [marqueeHVar]: `${marquee.rect.height}px`,\n })}\n />\n );\n}\n\nexport function AssetBrowserGrid(): React.ReactElement {\n const ctx = useAssetBrowserContext();\n const store = useAssetBrowserStore();\n const scrollerRef = useRef<HTMLDivElement>(null);\n const gridId = useId();\n\n const items = ctx.displayedItems;\n const count = items.length;\n const thumbPx = ctx.thumbnailSizePx;\n\n // Mirror the store's roving focus onto the grid's `aria-activedescendant`\n // imperatively, so a screen reader announces the focused cell without us\n // re-rendering the whole grid on every arrow-key (the per-id focus slices keep\n // re-renders to the two affected cells). The matching cell `id` is built from\n // the same `gridId` in AssetBrowserGridItem via `cellDomId`.\n useEffect(() => {\n const el = scrollerRef.current;\n if (!el) return;\n const apply = (): void => {\n const focusedId = store.getFocusedId();\n if (focusedId === null) el.removeAttribute('aria-activedescendant');\n else\n el.setAttribute('aria-activedescendant', cellDomId(gridId, focusedId));\n };\n apply();\n return store.subscribeFocus(apply);\n }, [store, gridId]);\n\n const windowed =\n ctx.virtualized === true ||\n (ctx.virtualized === 'auto' && count > ctx.virtualizationThreshold);\n\n const win = useAssetGridVirtualizer({\n containerRef: scrollerRef,\n count,\n thumbPx,\n overscanRows: ctx.overscanRows,\n enabled: windowed,\n });\n\n const scrollIndexIntoView = useCallback(\n (index: number, w: AssetGridWindow): void => {\n const el = scrollerRef.current;\n if (!el) return;\n const row = Math.floor(index / w.columns);\n const top = row * w.rowHeight;\n const bottom = top + w.rowHeight;\n if (top < el.scrollTop) el.scrollTop = top;\n else if (bottom > el.scrollTop + el.clientHeight)\n el.scrollTop = bottom - el.clientHeight;\n },\n []\n );\n\n // Bridge the imperative `scrollToItem` handle through the store so it works\n // even when the target row is outside the virtualization window.\n const winRef = useLatest(win);\n useLayoutEffect(\n () =>\n store.registerScrollToIndex(index => {\n scrollIndexIntoView(index, winRef.current);\n }),\n [store, winRef, scrollIndexIntoView]\n );\n\n const keyboard = useAssetGridKeyboardNav({\n store,\n items,\n win,\n scrollerRef,\n selectionMode: ctx.selectionMode,\n selectAll: ctx.selectAll,\n clearSelection: ctx.clearSelection,\n activateItem: ctx.activateItem,\n toggleSelectId: ctx.toggleSelectId,\n selectByKeyboard: ctx.selectByKeyboard,\n scrollIndexIntoView,\n });\n\n const marquee = useAssetMarqueeGesture({\n scrollerRef,\n enabled: ctx.marqueeEnabled,\n items,\n columns: win.columns,\n thumbPx,\n commitMarquee: ctx.commitMarquee,\n });\n\n const sharedVars = assignInlineVars({\n [columnsVar]: String(win.columns),\n [gridGapVar]: `${GRID_GAP}px`,\n [cellWidthVar]: `${cellWidth(thumbPx)}px`,\n });\n\n // Grid keydown = 2D navigation + the shared mutation shortcuts (F2 / Delete /\n // Ctrl+D). Both are attached here, on the element that receives the event, so\n // the shortcuts fire without depending on bubbling to the root. The key sets\n // are disjoint, so order doesn't matter.\n const mutationKeyDown = ctx.mutationKeyDown;\n const onGridKeyDown = useCallback(\n (event: React.KeyboardEvent): void => {\n keyboard.onKeyDown(event);\n mutationKeyDown(event);\n },\n [keyboard, mutationKeyDown]\n );\n\n const rendered: React.ReactNode[] = [];\n for (let i = win.startIndex; i < win.endIndex; i += 1) {\n const item = items[i];\n if (!item) continue;\n rendered.push(\n <AssetBrowserGridItem\n key={item.id}\n item={item}\n index={i}\n gridId={gridId}\n columns={win.columns}\n />\n );\n }\n\n return (\n <div\n ref={scrollerRef}\n className={gridScroller}\n role=\"grid\"\n aria-label={ctx.labels.gridAria}\n aria-multiselectable={ctx.selectionMode === 'multiple'}\n aria-rowcount={win.totalRows}\n aria-colcount={win.columns}\n tabIndex={0}\n onKeyDown={onGridKeyDown}\n onPointerDown={marquee.onPointerDown}\n onPointerMove={marquee.onPointerMove}\n onPointerUp={marquee.onPointerUp}\n onPointerCancel={marquee.onPointerCancel}\n >\n {windowed ? (\n <div\n className={gridSizer}\n style={assignInlineVars({\n [totalHeightVar]: `${win.totalHeight}px`,\n })}\n >\n <MarqueeLayer />\n <div\n className={gridWindow}\n style={{\n ...sharedVars,\n ...assignInlineVars({ [offsetYVar]: `${win.offsetY}px` }),\n }}\n role=\"presentation\"\n >\n {rendered}\n </div>\n </div>\n ) : (\n <>\n <MarqueeLayer />\n <div className={gridFlow} style={sharedVars} role=\"presentation\">\n {rendered}\n </div>\n </>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA0CA;AACE;;AACsC;;;;;;;AAYxC;;AAGE;AACA;AACA;AACA;AAEA;AACA;AACA;;;;;;;AAQE;AACA;;;AAEE;;AACwB;;AAEtB;AACJ;AACA;AACA;AACF;AAEA;AAEE;;AAGA;;;;AAIA;AACD;;AAIG;AACA;;AACA;AACA;AACA;AACA;AAAwB;;;;;;AAS5B;;AAIM;;;;;;;;;;;;;;AAiBL;;;;;;;;AASA;;;AAIC;;AAED;;;;;AAMD;AACA;AAEI;;AAEF;;AAKF;AACE;AACA;;AACA;;AAWF;AAoBU;;AAOE;AACA;AACD;AAgBb;;"}
@@ -89,6 +89,12 @@ import '../../Icons/GitBranchIcon.js';
89
89
  import '../../Icons/BugIcon.js';
90
90
  import '../../Icons/MinusIcon.js';
91
91
  import '../../Icons/PinIcon.js';
92
+ import '../../Icons/OrbitIcon.js';
93
+ import '../../Icons/RotateIcon.js';
94
+ import '../../Icons/SpinIcon.js';
95
+ import '../../Icons/CameraIcon.js';
96
+ import '../../Icons/CubeIcon.js';
97
+ import '../../Icons/ZoomFitIcon.js';
92
98
  import { Icon } from '../../primitives/Icon/Icon.js';
93
99
  import { cellLabel, thumbSizeVar, cellHeightVar, cellWidthVar, cellRecipe, thumb, thumbImage } from './AssetBrowser.css.js';
94
100
  import { useAssetBrowserContext, useAssetSelected, useAssetFocused, useAssetDropTarget, useAssetEditing } from './AssetBrowserContext.js';
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserGridItem.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserGridItem.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA;;;;AAIG;AACH;;AAII;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;;AAGJ;AAEA;;AACiB;AACf;AASF;AAEA;AASE;AACA;;;;;;AAMA;AACA;AACE;;;AAGF;AACA;AAGM;;AAUI;AAOZ;AAEA;AAME;;;;;;AAOA;;;;AAIA;;AAGA;AACA;;AAGE;AAEF;;;;AAKI;AACA;;AAaJ;;;;;;;AAiBM;AACA;AACD;;;AAIC;;;;;AAOE;;;;AAOA;;AAEI;AACF;;;;AAOF;;;;AAOA;;;;AAOA;;;;AAOA;;;;AAOA;;;;AAUR;AACF;AAEO;AACP;;"}
1
+ {"version":3,"file":"AssetBrowserGridItem.js","sources":["src/components/editor/AssetBrowser/AssetBrowserGridItem.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useState } from 'react';\n\nimport {\n CodeIcon,\n EyeDropperIcon,\n FileTextIcon,\n FolderIcon,\n GridIcon,\n PlayIcon,\n} from '@/components/Icons';\nimport { Icon } from '@/components/primitives/Icon';\n\nimport {\n cellLabel,\n cellRecipe,\n cellWidthVar,\n cellHeightVar,\n thumb,\n thumbImage,\n thumbSizeVar,\n} from './AssetBrowser.css';\nimport {\n useAssetBrowserContext,\n useAssetDropTarget,\n useAssetEditing,\n useAssetFocused,\n useAssetSelected,\n} from './AssetBrowserContext';\nimport { cellDomId, cellHeight, cellWidth } from './assetBrowserGeometry';\nimport { AssetBrowserRenameField } from './AssetBrowserRenameField';\n\nimport type { AssetItem, AssetType } from './AssetBrowser.types';\n\nexport interface AssetBrowserGridItemProps {\n item: AssetItem;\n index: number;\n /** Grid `useId` base — builds the cell `id` for `aria-activedescendant`. */\n gridId: string;\n /** Current column count — derives 1-based `aria-rowindex`/`aria-colindex`. */\n columns: number;\n}\n\n/**\n * Type-derived fallback glyph for files without a thumbnail or explicit `icon`.\n * Only the asset types whose fallback is actually seen (image/model usually\n * carry a thumbnail) get a distinct icon; the rest share the generic file icon.\n */\nfunction typeFallbackIcon(\n assetType: AssetType | undefined\n): React.ReactElement {\n switch (assetType) {\n case 'material':\n return <EyeDropperIcon />;\n case 'audio':\n case 'video':\n return <PlayIcon />;\n case 'scene':\n return <GridIcon />;\n case 'text':\n return <CodeIcon />;\n default:\n return <FileTextIcon />;\n }\n}\n\nfunction FallbackIcon({ item }: { item: AssetItem }): React.ReactElement {\n if (item.icon) return <>{item.icon}</>;\n return (\n <Icon size=\"lg\" color=\"muted\" decorative>\n {item.kind === 'folder' ? (\n <FolderIcon />\n ) : (\n typeFallbackIcon(item.assetType)\n )}\n </Icon>\n );\n}\n\nfunction Thumbnail({\n item,\n thumbPx,\n selected,\n}: {\n item: AssetItem;\n thumbPx: number;\n selected: boolean;\n}): React.ReactElement {\n const { renderThumbnail } = useAssetBrowserContext();\n const custom = renderThumbnail?.(item, { size: thumbPx, selected });\n // Broken / expired / CORS-failed thumbnail URLs fall back to the type icon\n // instead of the browser's broken-image glyph. The error flag resets when the\n // source changes via the adjust-state-during-render pattern (a previous-prop\n // sentinel in state — component-patterns.md §14), so no effect is needed.\n const [errored, setErrored] = useState(false);\n const [errorUrl, setErrorUrl] = useState(item.thumbnailUrl);\n if (item.thumbnailUrl !== errorUrl) {\n setErrorUrl(item.thumbnailUrl);\n setErrored(false);\n }\n const showImg = !custom && item.thumbnailUrl !== undefined && !errored;\n return (\n <div className={thumb}>\n {custom ??\n (showImg ? (\n <img\n className={thumbImage}\n src={item.thumbnailUrl}\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n draggable={false}\n onError={() => {\n setErrored(true);\n }}\n />\n ) : (\n <FallbackIcon item={item} />\n ))}\n </div>\n );\n}\n\nfunction GridItemImpl({\n item,\n index,\n gridId,\n columns,\n}: AssetBrowserGridItemProps): React.ReactElement {\n const ctx = useAssetBrowserContext();\n const selected = useAssetSelected(item.id);\n const focused = useAssetFocused(item.id);\n const dropActive = useAssetDropTarget(item.id);\n const editing = useAssetEditing(item.id);\n\n const isDropTarget = item.kind === 'folder' && dropActive;\n const thumbPx = ctx.thumbnailSizePx;\n // 1-based grid position for assistive tech, computed from display index so it\n // reflects true totals even though only the virtualization window is mounted.\n const cols = Math.max(1, columns);\n const ariaRowIndex = Math.floor(index / cols) + 1;\n const ariaColIndex = (index % cols) + 1;\n\n const isDraggable = item.draggable !== false && item.disabled !== true;\n const isFolderTarget =\n item.kind === 'folder' &&\n item.droppable !== false &&\n ctx.dnd.internalEnabled;\n\n const inner = ctx.renderItem ? (\n ctx.renderItem(item, {\n selected,\n focused,\n index,\n view: 'grid',\n dropTarget: isDropTarget,\n })\n ) : (\n <>\n <Thumbnail item={item} thumbPx={thumbPx} selected={selected} />\n {editing ? (\n <AssetBrowserRenameField item={item} />\n ) : (\n <span className={cellLabel}>{item.name}</span>\n )}\n </>\n );\n\n const cell = (\n // Keyboard interaction is centralized at the grid level: cells use roving\n // tabIndex and AssetBrowserGrid's onKeyDown drives Enter/Space/arrow nav,\n // so a redundant per-cell key handler is intentionally omitted.\n // eslint-disable-next-line jsx-a11y/click-events-have-key-events\n <div\n role=\"gridcell\"\n id={cellDomId(gridId, item.id)}\n data-asset-id={item.id}\n aria-selected={selected}\n aria-label={item.name}\n aria-rowindex={ariaRowIndex}\n aria-colindex={ariaColIndex}\n title={item.name}\n tabIndex={focused ? 0 : -1}\n className={cellRecipe({\n selected,\n dropTarget: isDropTarget,\n disabled: item.disabled === true,\n })}\n style={assignInlineVars({\n [cellWidthVar]: `${cellWidth(thumbPx)}px`,\n [cellHeightVar]: `${cellHeight(thumbPx)}px`,\n [thumbSizeVar]: `${thumbPx}px`,\n })}\n // While renaming, the cell is non-interactive for selection/open/drag —\n // clicks on the thumbnail above the field must not reselect or navigate.\n draggable={isDraggable && !editing}\n onClick={\n editing\n ? undefined\n : e => {\n ctx.handleItemClick(item, index, e);\n }\n }\n onDoubleClick={\n editing\n ? undefined\n : () => {\n ctx.activateItem(item);\n }\n }\n onDragStart={\n isDraggable && !editing\n ? e => {\n ctx.dnd.onItemDragStart(item, e);\n }\n : undefined\n }\n onDragEnd={\n isDraggable\n ? e => {\n ctx.dnd.onItemDragEnd(item, e);\n }\n : undefined\n }\n onDragOver={\n isFolderTarget\n ? e => {\n ctx.dnd.onFolderDragOver(item.id, e);\n }\n : undefined\n }\n onDragLeave={\n isFolderTarget\n ? e => {\n ctx.dnd.onFolderDragLeave(item.id, e);\n }\n : undefined\n }\n onDrop={\n isFolderTarget\n ? e => {\n ctx.dnd.onFolderDrop(item.id, e);\n }\n : undefined\n }\n >\n {inner}\n </div>\n );\n\n // The right-click menu and roving-focus marker `data-asset-id` are handled by\n // the shared AssetBrowserContextMenuLayer at the surface level — the cell is a\n // plain grid child with no per-cell ContextMenu wrapper.\n return cell;\n}\n\nexport const AssetBrowserGridItem = /*#__PURE__*/ React.memo(GridItemImpl);\nAssetBrowserGridItem.displayName = 'AssetBrowserGridItem';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA;;;;AAIG;AACH;;AAII;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;;AAGJ;AAEA;;AACiB;AACf;AASF;AAEA;AASE;AACA;;;;;;AAMA;AACA;AACE;;;AAGF;AACA;AAGM;;AAUI;AAOZ;AAEA;AAME;;;;;;AAOA;;;;AAIA;;AAGA;AACA;;AAGE;AAEF;;;;AAKI;AACA;;AAaJ;;;;;;;AAiBM;AACA;AACD;;;AAIC;;;;;AAOE;;;;AAOA;;AAEI;AACF;;;;AAOF;;;;AAOA;;;;AAOA;;;;AAOA;;;;AAOA;;;;AAUR;AACF;AAEO;AACP;;"}
@@ -89,6 +89,12 @@ import '../../Icons/GitBranchIcon.js';
89
89
  import '../../Icons/BugIcon.js';
90
90
  import '../../Icons/MinusIcon.js';
91
91
  import '../../Icons/PinIcon.js';
92
+ import '../../Icons/OrbitIcon.js';
93
+ import '../../Icons/RotateIcon.js';
94
+ import '../../Icons/SpinIcon.js';
95
+ import '../../Icons/CameraIcon.js';
96
+ import '../../Icons/CubeIcon.js';
97
+ import '../../Icons/ZoomFitIcon.js';
92
98
  import { Icon } from '../../primitives/Icon/Icon.js';
93
99
  import { listScroller, nameCell } from './AssetBrowser.css.js';
94
100
  import { useAssetBrowserContext, useAssetBrowserChrome, useAssetSelection, useAssetEditing } from './AssetBrowserContext.js';
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserList.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserList.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;AAIG;AACH;;AAEE;AAAa;;AASf;AAEA;;;AAGG;AACH;;AAII;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;;AAGD;AACD;AACE;AACA;AACA;AACA;AACA;AACA;;AAED;AACD;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACD;;AAEL;;AAGE;AACA;AACA;;AAMA;;;AAIA;AACE;AACA;;AAGF;;;;;;;;AAkBU;;;AAGF;AACF;AAIE;;AAMA;AACF;AAOR;;"}
1
+ {"version":3,"file":"AssetBrowserList.js","sources":["src/components/editor/AssetBrowser/AssetBrowserList.tsx"],"sourcesContent":["'use client';\n\nimport React, { useMemo } from 'react';\n\nimport { DataTable } from '@/components/data/DataTable';\nimport { FileTextIcon, FolderIcon } from '@/components/Icons';\nimport { Icon } from '@/components/primitives/Icon';\n\nimport { listScroller, nameCell } from './AssetBrowser.css';\nimport {\n useAssetBrowserChrome,\n useAssetBrowserContext,\n useAssetEditing,\n useAssetSelection,\n} from './AssetBrowserContext';\nimport { formatBytes, formatDate } from './assetBrowserFormat';\nimport { AssetBrowserRenameField } from './AssetBrowserRenameField';\n\nimport type { AssetItem } from './AssetBrowser.types';\nimport type { AssetBrowserLabels } from './assetBrowserLabels';\nimport type {\n DataTableColumn,\n DataTableSortState,\n} from '@/components/data/DataTable';\n\n/**\n * Name cell — swaps to the inline rename field when this row is the rename\n * target. A component (not an inline `cell` fn) so the `useAssetEditing` hook is\n * valid; this is the same shared rename mechanism the grid uses.\n */\nfunction ListNameCell({ item }: { item: AssetItem }): React.ReactElement {\n const editing = useAssetEditing(item.id);\n if (editing) return <AssetBrowserRenameField item={item} />;\n return (\n <span className={nameCell}>\n <Icon size=\"sm\" color=\"muted\" decorative>\n {item.kind === 'folder' ? <FolderIcon /> : <FileTextIcon />}\n </Icon>\n <span>{item.name}</span>\n </span>\n );\n}\n\n/**\n * Default name/type/size/modified columns, built from the resolved labels so\n * the headers and the folder \"Type\" value follow the `labels` prop.\n */\nfunction buildDefaultColumns(\n labels: AssetBrowserLabels\n): readonly DataTableColumn<AssetItem>[] {\n return [\n {\n id: 'name',\n header: labels.sortFields.name,\n accessor: 'name',\n sortable: true,\n sticky: true,\n minWidth: 160,\n cell: ({ row }) => <ListNameCell item={row} />,\n },\n {\n id: 'type',\n header: labels.sortFields.type,\n sortable: true,\n width: 120,\n accessor: row =>\n row.kind === 'folder' ? labels.folder : (row.assetType ?? ''),\n },\n {\n id: 'size',\n header: labels.sortFields.size,\n sortable: true,\n align: 'right',\n width: 100,\n accessor: 'size',\n cell: ({ row }) => (row.kind === 'folder' ? '—' : formatBytes(row.size)),\n },\n {\n id: 'modified',\n header: labels.sortFields.modified,\n sortable: true,\n align: 'right',\n width: 140,\n accessor: 'modifiedAt',\n cell: ({ row }) => formatDate(row.modifiedAt),\n },\n ];\n}\n\nexport function AssetBrowserList(): React.ReactElement {\n const ctx = useAssetBrowserContext();\n const chrome = useAssetBrowserChrome();\n const selectionSet = useAssetSelection();\n\n const defaultColumns = useMemo(\n () => buildDefaultColumns(ctx.labels),\n [ctx.labels]\n );\n const columns = ctx.columns ?? defaultColumns;\n\n // We own sorting (rows arrive already shaped); DataTable only reflects the\n // indicator and reports the next desired sort.\n const sort: DataTableSortState = {\n columnId: chrome.sort.field,\n direction: chrome.sort.direction,\n };\n\n const selection = useMemo(() => Array.from(selectionSet), [selectionSet]);\n\n return (\n // The mutation shortcuts (F2 / Delete / Ctrl+D) attach to this wrapper;\n // DataTable's own keydowns bubble up to it. F2 targets the sole selected row\n // (the list has no store roving-focus). Static-element handler is intentional.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div className={listScroller} onKeyDown={ctx.mutationKeyDown}>\n <DataTable<AssetItem>\n rows={ctx.displayedItems}\n columns={columns}\n rowKey=\"id\"\n density={ctx.density}\n height=\"100%\"\n sort={sort}\n manualSort\n onSortChange={next => {\n if (!next.columnId || !next.direction) {\n chrome.setSort({ field: 'name', direction: 'asc' });\n return;\n }\n chrome.setSort({ field: next.columnId, direction: next.direction });\n }}\n selectionMode={ctx.selectionMode}\n selection={selection}\n onSelectionChange={ids => {\n ctx.setSelectionIds(ids, 'click');\n }}\n isRowSelectable={row =>\n row.selectable !== false && row.disabled !== true\n }\n onRowActivate={row => {\n ctx.activateItem(row);\n }}\n emptyState={ctx.emptyState}\n loading={ctx.loading}\n aria-label=\"Assets\"\n />\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA;;;;AAIG;AACH;;AAEE;AAAa;;AASf;AAEA;;;AAGG;AACH;;AAII;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;;AAGD;AACD;AACE;AACA;AACA;AACA;AACA;AACA;;AAED;AACD;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACD;;AAEL;;AAGE;AACA;AACA;;AAMA;;;AAIA;AACE;AACA;;AAGF;;;;;;;;AAkBU;;;AAGF;AACF;AAIE;;AAMA;AACF;AAOR;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserRenameField.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserRenameField.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;AAeA;;;;;;AAMG;AACG;;AAIJ;AACA;;AAEA;;;AAIE;AACA;;;;;AAKF;;;AAEE;AACA;;AAEE;AAAe;AACjB;;AAGF;AACE;;AAEF;AAEA;;;AAWM;;AAEE;;AACK;;AAEL;;;;;AAOJ;;;AAMN;;"}
1
+ {"version":3,"file":"AssetBrowserRenameField.js","sources":["src/components/editor/AssetBrowser/AssetBrowserRenameField.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useLayoutEffect, useRef, useState } from 'react';\n\nimport { Input } from '@/components/primitives/Input';\n\nimport { renameField } from './AssetBrowser.css';\nimport { useAssetBrowserContext } from './AssetBrowserContext';\n\nimport type { AssetItem } from './AssetBrowser.types';\n\nexport interface AssetBrowserRenameFieldProps {\n item: AssetItem;\n}\n\n/**\n * Inline label editor shown in place of a grid cell's name while the cell is\n * the rename target. Owns only the transient text buffer; the \"is editing\" flag\n * lives in the store. Commits on Enter / blur (changed value), cancels on\n * Escape, and stops key propagation so the grid's roving navigation doesn't\n * steal keystrokes.\n */\nexport function AssetBrowserRenameField({\n item,\n}: AssetBrowserRenameFieldProps): React.ReactElement {\n const { mutations, labels } = useAssetBrowserContext();\n const [value, setValue] = useState(item.name);\n const inputRef = useRef<HTMLInputElement>(null);\n // Guard against the blur fired by our own Enter/Escape commit double-firing.\n const committedRef = useRef(false);\n\n // Focus + select the basename once, after the field mounts.\n useLayoutEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n el.select();\n }, []);\n\n const commit = useCallback((): void => {\n if (committedRef.current) return;\n committedRef.current = true;\n void mutations.commitRename(item, value).then(accepted => {\n // Rejected name → reopen for another attempt.\n if (!accepted) committedRef.current = false;\n });\n }, [mutations, item, value]);\n\n const cancel = useCallback((): void => {\n committedRef.current = true;\n mutations.cancelRename();\n }, [mutations]);\n\n return (\n <Input\n ref={inputRef}\n className={renameField}\n size=\"sm\"\n value={value}\n aria-label={`${labels.rename} ${item.name}`}\n onChange={setValue}\n onKeyDown={e => {\n // Keep arrows / Space / type-ahead inside the field, away from the grid.\n e.stopPropagation();\n if (e.key === 'Enter') {\n e.preventDefault();\n commit();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n cancel();\n }\n }}\n onBlur={commit}\n onClick={e => {\n // A click on the field shouldn't reselect / navigate the cell.\n e.stopPropagation();\n }}\n onDoubleClick={e => {\n e.stopPropagation();\n }}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;;AAeA;;;;;;AAMG;AACG;;AAIJ;AACA;;AAEA;;;AAIE;AACA;;;;;AAKF;;;AAEE;AACA;;AAEE;AAAe;AACjB;;AAGF;AACE;;AAEF;AAEA;;;AAWM;;AAEE;;AACK;;AAEL;;;;;AAOJ;;;AAMN;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserSidebar.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserSidebar.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;AAYE;;AACqB;AAErB;AAOQ;AACA;AAAQ;;AAKlB;;"}
1
+ {"version":3,"file":"AssetBrowserSidebar.js","sources":["src/components/editor/AssetBrowser/AssetBrowserSidebar.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { TreeView } from '@/components/controls/TreeView';\n\nimport { sidebar } from './AssetBrowser.css';\nimport { useAssetBrowserContext } from './AssetBrowserContext';\n\nimport type { TreeNodeData } from '@/components/controls/TreeView';\n\nexport function AssetBrowserSidebar(): React.ReactElement | null {\n const ctx = useAssetBrowserContext();\n if (!ctx.folderTree) return null;\n\n return (\n <div className={sidebar}>\n <TreeView\n nodes={ctx.folderTree as TreeNodeData[]}\n selectionMode=\"single\"\n selectedIds={ctx.currentFolderId ? [ctx.currentFolderId] : []}\n onSelectionChange={ids => {\n const id = ids[0];\n if (id) ctx.navigate(id, 'sidebar');\n }}\n />\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAYE;;AACqB;AAErB;AAOQ;AACA;AAAQ;;AAKlB;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserStatusBar.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserStatusBar.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;AAsBA;;;;;AAKG;AACG;AAKJ;AACA;AACA;;AASQ;AAWV;;"}
1
+ {"version":3,"file":"AssetBrowserStatusBar.js","sources":["src/components/editor/AssetBrowser/AssetBrowserStatusBar.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport {\n SegmentedControl,\n SegmentedControlItem,\n} from '@/components/navigation/SegmentedControl';\n\nimport { statusBar, statusSpacer } from './AssetBrowser.css';\nimport { useAssetBrowserContext } from './AssetBrowserContext';\nimport { useAssetBrowserAnnouncement } from './useAssetBrowserAnnouncement';\n\nimport type { AssetThumbnailSize, AssetView } from './AssetBrowser.types';\n\nexport interface AssetBrowserStatusBarProps {\n /** Current view — drives whether the thumbnail-size control is rendered. */\n view: AssetView;\n thumbnailSize: AssetThumbnailSize;\n setThumbnailSize: (size: AssetThumbnailSize) => void;\n}\n\n/**\n * Optional footer bar showing the live announcement and (in grid view) a\n * thumbnail-size segmented control. The announcement is sourced from the\n * `useAssetBrowserAnnouncement` slice hook, so the bar updates without the\n * root recomputing it.\n */\nexport function AssetBrowserStatusBar({\n view,\n thumbnailSize,\n setThumbnailSize,\n}: AssetBrowserStatusBarProps): React.ReactElement {\n const announcement = useAssetBrowserAnnouncement();\n const { labels } = useAssetBrowserContext();\n return (\n <div className={statusBar}>\n <span>{announcement}</span>\n <span className={statusSpacer} />\n {view === 'grid' && (\n <SegmentedControl\n value={typeof thumbnailSize === 'string' ? thumbnailSize : 'md'}\n onChange={value => {\n setThumbnailSize(value as AssetThumbnailSize);\n }}\n size=\"sm\"\n aria-label={labels.thumbnailSizeAria}\n >\n <SegmentedControlItem value=\"sm\">S</SegmentedControlItem>\n <SegmentedControlItem value=\"md\">M</SegmentedControlItem>\n <SegmentedControlItem value=\"lg\">L</SegmentedControlItem>\n </SegmentedControl>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAsBA;;;;;AAKG;AACG;AAKJ;AACA;AACA;;AASQ;AAWV;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserStore.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserStore.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AssetBrowserStore.js","sources":["src/components/editor/AssetBrowser/AssetBrowserStore.ts"],"sourcesContent":["/** Screen-space rectangle (px, relative to the grid scroll container). */\nexport interface MarqueeRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface MarqueeState {\n active: boolean;\n rect: MarqueeRect | null;\n /** Whether the marquee adds to (Ctrl/Cmd) or replaces the selection. */\n additive: boolean;\n}\n\nexport interface DragState {\n active: boolean;\n draggingIds: string[];\n /** Folder id currently hovered as a drop target, or `'root'`/null for the surface. */\n dropTargetId: string | null;\n /** An external OS-file drag is hovering the surface. */\n externalOver: boolean;\n}\n\nconst EMPTY_SELECTION: ReadonlySet<string> = new Set<string>();\n\nconst INITIAL_MARQUEE: MarqueeState = {\n active: false,\n rect: null,\n additive: false,\n};\nconst INITIAL_DRAG: DragState = {\n active: false,\n draggingIds: [],\n dropTargetId: null,\n externalOver: false,\n};\n\nfunction sameDrag(a: DragState, b: DragState): boolean {\n return (\n a.active === b.active &&\n a.dropTargetId === b.dropTargetId &&\n a.externalOver === b.externalOver &&\n a.draggingIds.length === b.draggingIds.length &&\n a.draggingIds.every((id, i) => id === b.draggingIds[i])\n );\n}\n\nfunction sameMarquee(a: MarqueeState, b: MarqueeState): boolean {\n if (a.active !== b.active || a.additive !== b.additive) return false;\n if (a.rect === b.rect) return true;\n if (!a.rect || !b.rect) return false;\n return (\n a.rect.x === b.rect.x &&\n a.rect.y === b.rect.y &&\n a.rect.width === b.rect.width &&\n a.rect.height === b.rect.height\n );\n}\n\n/**\n * Per-instance hot-path store for AssetBrowser. Holds only state that updates\n * faster than a click — roving focus, the marquee rectangle, and drag state.\n *\n * View, search, filters, and sort are low-frequency and live in React state\n * (via `useControlledState`), not here. Selection is owned by React state too\n * (for the controlled API) but mirrored into this store so each grid item can\n * subscribe to its own \"am I selected?\" slice via `useAssetSelected(id)` rather\n * than re-rendering every cell on every selection change. Each slice exposes\n * its own `subscribe`/`get` pair for `useSyncExternalStore` so a marquee drag\n * does not re-render the toolbar.\n */\nexport class AssetBrowserStore {\n #focusedId: string | null = null;\n #editingId: string | null = null;\n #marquee: MarqueeState = INITIAL_MARQUEE;\n #drag: DragState = INITIAL_DRAG;\n #selection: ReadonlySet<string> = EMPTY_SELECTION;\n\n #focusListeners = new Set<() => void>();\n #editingListeners = new Set<() => void>();\n #marqueeListeners = new Set<() => void>();\n #dragListeners = new Set<() => void>();\n #selectionListeners = new Set<() => void>();\n\n /** Set by the grid so the imperative `scrollToItem` works under windowing. */\n #scrollToIndex: ((index: number) => void) | null = null;\n\n // ── Reads (arrow fns so they pass straight to useSyncExternalStore) ──\n getFocusedId = (): string | null => this.#focusedId;\n getEditingId = (): string | null => this.#editingId;\n getMarquee = (): MarqueeState => this.#marquee;\n getDrag = (): DragState => this.#drag;\n getSelection = (): ReadonlySet<string> => this.#selection;\n\n // ── Subscriptions ──\n subscribeFocus = (cb: () => void): (() => void) => {\n this.#focusListeners.add(cb);\n return () => {\n this.#focusListeners.delete(cb);\n };\n };\n subscribeEditing = (cb: () => void): (() => void) => {\n this.#editingListeners.add(cb);\n return () => {\n this.#editingListeners.delete(cb);\n };\n };\n subscribeSelection = (cb: () => void): (() => void) => {\n this.#selectionListeners.add(cb);\n return () => {\n this.#selectionListeners.delete(cb);\n };\n };\n subscribeMarquee = (cb: () => void): (() => void) => {\n this.#marqueeListeners.add(cb);\n return () => {\n this.#marqueeListeners.delete(cb);\n };\n };\n subscribeDrag = (cb: () => void): (() => void) => {\n this.#dragListeners.add(cb);\n return () => {\n this.#dragListeners.delete(cb);\n };\n };\n\n // ── Mutations (no-op when unchanged to keep snapshots stable) ──\n setFocusedId(next: string | null): void {\n if (next === this.#focusedId) return;\n this.#focusedId = next;\n this.#focusListeners.forEach(cb => {\n cb();\n });\n }\n\n /**\n * Id of the item whose label is being renamed inline, or `null`. Lives here\n * (not in React state) so rename can be triggered from outside the cell —\n * the F2 keyboard handler, a context-menu action, or the imperative\n * `beginRename` handle — and only the affected cell re-renders via its own\n * `useAssetEditing(id)` slice.\n */\n setEditingId(next: string | null): void {\n if (next === this.#editingId) return;\n this.#editingId = next;\n this.#editingListeners.forEach(cb => {\n cb();\n });\n }\n\n setMarquee(next: MarqueeState): void {\n if (sameMarquee(this.#marquee, next)) return;\n this.#marquee = next;\n this.#marqueeListeners.forEach(cb => {\n cb();\n });\n }\n\n clearMarquee(): void {\n this.setMarquee(INITIAL_MARQUEE);\n }\n\n setDrag(next: DragState): void {\n if (sameDrag(this.#drag, next)) return;\n this.#drag = next;\n this.#dragListeners.forEach(cb => {\n cb();\n });\n }\n\n clearDrag(): void {\n this.setDrag(INITIAL_DRAG);\n }\n\n /**\n * Mirror the React-owned selection. Callers pass a memoized Set, so a cheap\n * reference check keeps the snapshot stable when nothing changed.\n */\n setSelection(next: ReadonlySet<string>): void {\n if (next === this.#selection) return;\n this.#selection = next;\n this.#selectionListeners.forEach(cb => {\n cb();\n });\n }\n\n // ── Imperative scroll bridge ──\n registerScrollToIndex(fn: (index: number) => void): () => void {\n this.#scrollToIndex = fn;\n return () => {\n if (this.#scrollToIndex === fn) this.#scrollToIndex = null;\n };\n }\n\n /** Returns true when a grid was mounted to handle the scroll. */\n scrollToIndex(index: number): boolean {\n if (!this.#scrollToIndex) return false;\n this.#scrollToIndex(index);\n return true;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -87,6 +87,12 @@ import '../../Icons/GitBranchIcon.js';
87
87
  import '../../Icons/BugIcon.js';
88
88
  import '../../Icons/MinusIcon.js';
89
89
  import '../../Icons/PinIcon.js';
90
+ import '../../Icons/OrbitIcon.js';
91
+ import '../../Icons/RotateIcon.js';
92
+ import '../../Icons/SpinIcon.js';
93
+ import '../../Icons/CameraIcon.js';
94
+ import '../../Icons/CubeIcon.js';
95
+ import '../../Icons/ZoomFitIcon.js';
90
96
  import { Icon } from '../../primitives/Icon/Icon.js';
91
97
  import { main, importOverlay } from './AssetBrowser.css.js';
92
98
  import { AssetBrowserContent } from './AssetBrowserContent.js';
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserSurface.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserSurface.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA;AACE;AACA;;AACwB;;AAS1B;AAQA;;;;;AAKG;AACG;AAKJ;AAaF;;"}
1
+ {"version":3,"file":"AssetBrowserSurface.js","sources":["src/components/editor/AssetBrowser/AssetBrowserSurface.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { CloudUploadIcon } from '@/components/Icons';\nimport { Icon } from '@/components/primitives/Icon';\n\nimport { importOverlay, main } from './AssetBrowser.css';\nimport { AssetBrowserContent } from './AssetBrowserContent';\nimport { useAssetBrowserContext, useAssetDrag } from './AssetBrowserContext';\nimport { AssetBrowserContextMenuLayer } from './AssetBrowserContextMenu';\n\nfunction ImportOverlay(): React.ReactElement | null {\n const drag = useAssetDrag();\n const { labels } = useAssetBrowserContext();\n if (!drag.externalOver) return null;\n return (\n <div className={importOverlay}>\n <Icon size=\"lg\" decorative>\n <CloudUploadIcon />\n </Icon>\n <span>{labels.importOverlay}</span>\n </div>\n );\n}\n\nexport interface AssetBrowserSurfaceProps {\n onDragOver: (event: React.DragEvent) => void;\n onDragLeave: (event: React.DragEvent) => void;\n onDrop: (event: React.DragEvent) => void;\n}\n\n/**\n * The scrollable content surface (grid/list/empty/loading/error) plus the\n * file-import overlay. Right-click menus (item + empty area) are handled by the\n * single view-agnostic {@link AssetBrowserContextMenuLayer}, which detects the\n * target from `data-asset-id` — so grid cells and list rows behave identically.\n */\nexport function AssetBrowserSurface({\n onDragOver,\n onDragLeave,\n onDrop,\n}: AssetBrowserSurfaceProps): React.ReactElement {\n return (\n <AssetBrowserContextMenuLayer>\n <div\n className={main}\n onDragOver={onDragOver}\n onDragLeave={onDragLeave}\n onDrop={onDrop}\n >\n <AssetBrowserContent />\n <ImportOverlay />\n </div>\n </AssetBrowserContextMenuLayer>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA;AACE;AACA;;AACwB;;AAS1B;AAQA;;;;;AAKG;AACG;AAKJ;AAaF;;"}
@@ -87,6 +87,12 @@ import '../../Icons/GitBranchIcon.js';
87
87
  import '../../Icons/BugIcon.js';
88
88
  import '../../Icons/MinusIcon.js';
89
89
  import '../../Icons/PinIcon.js';
90
+ import '../../Icons/OrbitIcon.js';
91
+ import '../../Icons/RotateIcon.js';
92
+ import '../../Icons/SpinIcon.js';
93
+ import '../../Icons/CameraIcon.js';
94
+ import '../../Icons/CubeIcon.js';
95
+ import '../../Icons/ZoomFitIcon.js';
90
96
  import { Menu } from '../../navigation/Menu/Menu.js';
91
97
  import { SegmentedControl } from '../../navigation/SegmentedControl/SegmentedControl.js';
92
98
  import { SegmentedControlItem } from '../../navigation/SegmentedControl/SegmentedControlItem.js';
@@ -1 +1 @@
1
- {"version":3,"file":"AssetBrowserToolbar.js","sources":["../../../../../../src/components/editor/AssetBrowser/AssetBrowserToolbar.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA;;AAGE;AACA;AAEA;AACE;AACA;AAAa;;AACR;AACL;AACF;;AA4BQ;AACF;AAuBE;AACF;AAqBM;;;AAcE;;AAED;;AAyBG;AACF;AAUhB;;"}
1
+ {"version":3,"file":"AssetBrowserToolbar.js","sources":["src/components/editor/AssetBrowser/AssetBrowserToolbar.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n FilterIcon,\n GridIcon,\n ListIcon,\n SearchIcon,\n SortIcon,\n} from '@/components/Icons';\nimport { Menu } from '@/components/navigation/Menu';\nimport {\n SegmentedControl,\n SegmentedControlItem,\n} from '@/components/navigation/SegmentedControl';\nimport { Icon } from '@/components/primitives/Icon';\nimport { IconButton } from '@/components/primitives/IconButton';\nimport { Input } from '@/components/primitives/Input';\n\nimport { searchField, toolbar, toolbarSpacer } from './AssetBrowser.css';\nimport { useAssetBrowserChrome } from './AssetBrowserContext';\n\nimport type { AssetSortField, AssetView } from './AssetBrowser.types';\n\nconst SORT_FIELDS: AssetSortField[] = ['name', 'type', 'size', 'modified'];\n\nexport function AssetBrowserToolbar(): React.ReactElement {\n const chrome = useAssetBrowserChrome();\n const { labels } = chrome;\n\n const toggleType = (type: string, checked: boolean): void => {\n const current = new Set(chrome.filters.types ?? []);\n if (checked) current.add(type);\n else current.delete(type);\n chrome.setFilters({ types: Array.from(current) });\n };\n\n return (\n <div className={toolbar}>\n {chrome.history && (\n <>\n <IconButton\n aria-label={labels.back}\n size=\"sm\"\n disabled={!chrome.canGoBack}\n onClick={chrome.goBack}\n >\n <ChevronLeftIcon size=\"sm\" decorative />\n </IconButton>\n <IconButton\n aria-label={labels.forward}\n size=\"sm\"\n disabled={!chrome.canGoForward}\n onClick={chrome.goForward}\n >\n <ChevronRightIcon size=\"sm\" decorative />\n </IconButton>\n </>\n )}\n\n <SegmentedControl\n value={chrome.view}\n onChange={value => {\n chrome.setView(value as AssetView);\n }}\n size=\"sm\"\n aria-label={labels.viewModeAria}\n >\n <SegmentedControlItem\n value=\"grid\"\n icon={<GridIcon />}\n tooltip={labels.gridViewTooltip}\n />\n <SegmentedControlItem\n value=\"list\"\n icon={<ListIcon />}\n tooltip={labels.listViewTooltip}\n />\n </SegmentedControl>\n\n <Input\n className={searchField}\n type=\"search\"\n size=\"sm\"\n placeholder={labels.searchPlaceholder}\n value={chrome.search}\n onChange={value => {\n chrome.setSearch(value);\n }}\n startIcon={\n <Icon size=\"sm\" decorative>\n <SearchIcon />\n </Icon>\n }\n />\n\n <span className={toolbarSpacer} />\n\n <Menu>\n <Menu.Trigger>\n <Icon size=\"sm\" decorative>\n <SortIcon />\n </Icon>\n {labels.sort}\n </Menu.Trigger>\n <Menu.Content>\n <Menu.RadioGroup\n value={chrome.sort.field}\n onValueChange={field => {\n chrome.setSort({ field, direction: chrome.sort.direction });\n }}\n >\n {SORT_FIELDS.map(field => (\n <Menu.RadioItem key={field} value={field}>\n {labels.sortFields[field]}\n </Menu.RadioItem>\n ))}\n </Menu.RadioGroup>\n <Menu.Separator />\n <Menu.RadioGroup\n value={chrome.sort.direction}\n onValueChange={direction => {\n chrome.setSort({\n field: chrome.sort.field,\n direction: direction === 'desc' ? 'desc' : 'asc',\n });\n }}\n >\n <Menu.RadioItem value=\"asc\">{labels.sortAscending}</Menu.RadioItem>\n <Menu.RadioItem value=\"desc\">\n {labels.sortDescending}\n </Menu.RadioItem>\n </Menu.RadioGroup>\n </Menu.Content>\n </Menu>\n\n {chrome.filterableTypes.length > 0 && (\n <Menu>\n <Menu.Trigger>\n <Icon size=\"sm\" decorative>\n <FilterIcon />\n </Icon>\n {labels.filter}\n </Menu.Trigger>\n <Menu.Content>\n {chrome.filterableTypes.map(type => (\n <Menu.CheckboxItem\n key={type}\n checked={(chrome.filters.types ?? []).includes(type)}\n onCheckedChange={checked => {\n toggleType(type, checked);\n }}\n >\n {type}\n </Menu.CheckboxItem>\n ))}\n </Menu.Content>\n </Menu>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA;;AAGE;AACA;AAEA;AACE;AACA;AAAa;;AACR;AACL;AACF;;AA4BQ;AACF;AAuBE;AACF;AAqBM;;;AAcE;;AAED;;AAyBG;AACF;AAUhB;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"assetBrowserFilter.js","sources":["../../../../../../src/components/editor/AssetBrowser/assetBrowserFilter.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assetBrowserFilter.js","sources":["src/components/editor/AssetBrowser/assetBrowserFilter.ts"],"sourcesContent":["import type {\n AssetFilterState,\n AssetItem,\n AssetSortState,\n} from './AssetBrowser.types';\n\n/** Case-insensitive name match. An empty/blank query keeps every item. */\nexport function filterBySearch(\n items: readonly AssetItem[],\n query: string\n): AssetItem[] {\n const q = query.trim().toLowerCase();\n if (q === '') return items.slice();\n return items.filter(item => item.name.toLowerCase().includes(q));\n}\n\n/**\n * Type filter. Folders always pass (they have no asset type and must stay\n * navigable). An empty/undefined `types` list keeps every item.\n */\nexport function filterByType(\n items: readonly AssetItem[],\n types: readonly string[] | undefined\n): AssetItem[] {\n if (!types || types.length === 0) return items.slice();\n const set = new Set(types);\n return items.filter(\n item => item.kind === 'folder' || set.has(item.assetType ?? 'unknown')\n );\n}\n\nfunction toTime(value: number | Date | undefined): number {\n if (value === undefined) return Number.NEGATIVE_INFINITY;\n return value instanceof Date ? value.getTime() : value;\n}\n\nfunction compareField(a: AssetItem, b: AssetItem, field: string): number {\n switch (field) {\n case 'name':\n return a.name.localeCompare(b.name);\n case 'type':\n return (a.assetType ?? '').localeCompare(b.assetType ?? '');\n case 'size':\n return (a.size ?? 0) - (b.size ?? 0);\n case 'modified':\n return toTime(a.modifiedAt) - toTime(b.modifiedAt);\n default: {\n const av = a.meta?.[field];\n const bv = b.meta?.[field];\n if (typeof av === 'number' && typeof bv === 'number') return av - bv;\n const as = typeof av === 'string' ? av : '';\n const bs = typeof bv === 'string' ? bv : '';\n return as.localeCompare(bs);\n }\n }\n}\n\n/**\n * Sort a stable copy. Folders always group before files; within a group the\n * chosen field + direction applies. Name is the tiebreaker for equal fields.\n */\nexport function sortItems(\n items: readonly AssetItem[],\n sort: AssetSortState\n): AssetItem[] {\n const dir = sort.direction === 'desc' ? -1 : 1;\n return items.slice().sort((a, b) => {\n if (a.kind !== b.kind) return a.kind === 'folder' ? -1 : 1;\n const primary = compareField(a, b, sort.field);\n if (primary !== 0) return primary * dir;\n return a.name.localeCompare(b.name) * dir;\n });\n}\n\nexport interface ShapeAssetsOptions {\n search: string;\n filters: AssetFilterState;\n sort: AssetSortState;\n manualSearch: boolean;\n manualFilter: boolean;\n manualSort: boolean;\n}\n\n/**\n * Apply the non-manual axes (search → filter → sort) to produce the displayed\n * list. Manual axes trust `items` as already shaped for that axis.\n */\nexport function shapeAssets(\n items: readonly AssetItem[],\n options: ShapeAssetsOptions\n): AssetItem[] {\n let result: AssetItem[] = items.slice();\n if (!options.manualSearch) result = filterBySearch(result, options.search);\n if (!options.manualFilter)\n result = filterByType(result, options.filters.types);\n if (!options.manualSort) result = sortItems(result, options.sort);\n return result;\n}\n\n/** Distinct asset types present among files, in first-seen order. */\nexport function collectTypes(items: readonly AssetItem[]): string[] {\n const seen: string[] = [];\n const set = new Set<string>();\n for (const item of items) {\n if (item.kind !== 'file') continue;\n const type = item.assetType ?? 'unknown';\n if (!set.has(type)) {\n set.add(type);\n seen.push(type);\n }\n }\n return seen;\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"assetBrowserFormat.js","sources":["../../../../../../src/components/editor/AssetBrowser/assetBrowserFormat.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;AACM,SAAU,WAAW,CAAC,KAAyB,EAAA;IACnD,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,EAAE;IACzD,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,CAAA,EAAG,KAAK,CAAA,EAAA,CAAI;IACrC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;AACtC,IAAA,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI;IACxB,IAAI,IAAI,GAAG,CAAC;AACZ,IAAA,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;QAC/C,KAAK,IAAI,IAAI;QACb,IAAI,IAAI,CAAC;IACX;IACA,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE;IAC7E,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,KAAK,CAAC,IAAI,CAAC,EAAE;AACpC;AAEA;AACM,SAAU,UAAU,CAAC,KAAgC,EAAA;IACzD,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,OAAO,EAAE;AAClC,IAAA,MAAM,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAAE,QAAA,OAAO,EAAE;AAC3C,IAAA,OAAO,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE;AACxC,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,GAAG,EAAE,SAAS;AACf,KAAA,CAAC;AACJ;;;;"}
1
+ {"version":3,"file":"assetBrowserFormat.js","sources":["src/components/editor/AssetBrowser/assetBrowserFormat.ts"],"sourcesContent":["/** Humanize a byte count (e.g. 2048 → \"2 KB\"). Empty for undefined. */\nexport function formatBytes(bytes: number | undefined): string {\n if (bytes === undefined || Number.isNaN(bytes)) return '';\n if (bytes < 1024) return `${bytes} B`;\n const units = ['KB', 'MB', 'GB', 'TB'];\n let value = bytes / 1024;\n let unit = 0;\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024;\n unit += 1;\n }\n const rounded = value >= 10 ? Math.round(value) : Math.round(value * 10) / 10;\n return `${rounded} ${units[unit]}`;\n}\n\n/** Short locale date string. Empty for undefined. */\nexport function formatDate(value: number | Date | undefined): string {\n if (value === undefined) return '';\n const date = value instanceof Date ? value : new Date(value);\n if (Number.isNaN(date.getTime())) return '';\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n"],"names":[],"mappings":"AAAA;AACM,SAAU,WAAW,CAAC,KAAyB,EAAA;IACnD,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;AAAE,QAAA,OAAO,EAAE;IACzD,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,CAAA,EAAG,KAAK,CAAA,EAAA,CAAI;IACrC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;AACtC,IAAA,IAAI,KAAK,GAAG,KAAK,GAAG,IAAI;IACxB,IAAI,IAAI,GAAG,CAAC;AACZ,IAAA,OAAO,KAAK,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;QAC/C,KAAK,IAAI,IAAI;QACb,IAAI,IAAI,CAAC;IACX;IACA,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,GAAG,EAAE;IAC7E,OAAO,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,KAAK,CAAC,IAAI,CAAC,EAAE;AACpC;AAEA;AACM,SAAU,UAAU,CAAC,KAAgC,EAAA;IACzD,IAAI,KAAK,KAAK,SAAS;AAAE,QAAA,OAAO,EAAE;AAClC,IAAA,MAAM,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAAE,QAAA,OAAO,EAAE;AAC3C,IAAA,OAAO,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE;AACxC,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,KAAK,EAAE,OAAO;AACd,QAAA,GAAG,EAAE,SAAS;AACf,KAAA,CAAC;AACJ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"assetBrowserGeometry.js","sources":["../../../../../../src/components/editor/AssetBrowser/assetBrowserGeometry.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assetBrowserGeometry.js","sources":["src/components/editor/AssetBrowser/assetBrowserGeometry.ts"],"sourcesContent":["import type { AssetThumbnailSize } from './AssetBrowser.types';\nimport type { MarqueeRect } from './AssetBrowserStore';\n\n/** Thumbnail edge length (px) for the named scales. */\nexport const THUMB_PX: Record<'sm' | 'md' | 'lg', number> = {\n sm: 72,\n md: 104,\n lg: 144,\n};\n\nexport const CELL_PADDING = 6;\nexport const LABEL_HEIGHT = 32;\nexport const GRID_GAP = 8;\n\nexport function resolveThumbPx(size: AssetThumbnailSize): number {\n if (typeof size === 'number') return Math.max(32, size);\n return THUMB_PX[size];\n}\n\nexport function cellWidth(thumbPx: number): number {\n return thumbPx + CELL_PADDING * 2 + 2; // + border\n}\n\nexport function cellHeight(thumbPx: number): number {\n return thumbPx + CELL_PADDING * 2 + LABEL_HEIGHT + 2;\n}\n\nexport function rowHeight(thumbPx: number): number {\n return cellHeight(thumbPx) + GRID_GAP;\n}\n\n/** How many columns fit in `width` px of usable (padding-excluded) space. */\nexport function columnsFor(width: number, thumbPx: number): number {\n if (width <= 0) return 1;\n const stride = cellWidth(thumbPx) + GRID_GAP;\n return Math.max(1, Math.floor((width + GRID_GAP) / stride));\n}\n\n/** Content-space rectangle of the item at `index` for a given column count. */\nexport function itemRect(\n index: number,\n columns: number,\n thumbPx: number\n): MarqueeRect {\n const cols = Math.max(1, columns);\n const col = index % cols;\n const row = Math.floor(index / cols);\n const stride = cellWidth(thumbPx) + GRID_GAP;\n return {\n x: col * stride,\n y: row * rowHeight(thumbPx),\n width: cellWidth(thumbPx),\n height: cellHeight(thumbPx),\n };\n}\n\nexport function rectsIntersect(a: MarqueeRect, b: MarqueeRect): boolean {\n return (\n a.x < b.x + b.width &&\n a.x + a.width > b.x &&\n a.y < b.y + b.height &&\n a.y + a.height > b.y\n );\n}\n\n/**\n * Stable DOM id for a grid cell, namespaced by the grid's `useId`. Used to\n * wire the grid's `aria-activedescendant` to the roving-focus cell. CSS.escape\n * is unnecessary — this is set on the element's `id`/attribute as a raw value,\n * never used in a selector.\n */\nexport function cellDomId(gridId: string, assetId: string): string {\n return `${gridId}-cell-${assetId}`;\n}\n\n/** Normalize two content-space points into a positive-size rectangle. */\nexport function rectFromPoints(\n ax: number,\n ay: number,\n bx: number,\n by: number\n): MarqueeRect {\n return {\n x: Math.min(ax, bx),\n y: Math.min(ay, by),\n width: Math.abs(ax - bx),\n height: Math.abs(ay - by),\n };\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"assetBrowserKeyboard.js","sources":["../../../../../../src/components/editor/AssetBrowser/assetBrowserKeyboard.ts"],"sourcesContent":[null],"names":[],"mappings":"AASA;;;;AAIG;SACa,aAAa,CAC3B,OAAe,EACf,GAAW,EACX,MAAqB,EAAA;AAErB,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM;IACxB,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE;AAE1B,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;AAC3C,IAAA,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC;AACnD,IAAA,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC;IACtB,MAAM,KAAK,GAAG,CAAC,CAAS,KAAa,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;;AAGnE,IAAA,IAAI,OAAO,GAAG,CAAC,EAAE;QACf,QAAQ,GAAG;AACT,YAAA,KAAK,YAAY;AACjB,YAAA,KAAK,WAAW;AAChB,YAAA,KAAK,WAAW;AAChB,YAAA,KAAK,SAAS;AACd,YAAA,KAAK,MAAM;AACX,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,CAAC;AACV,YAAA,KAAK,KAAK;AACV,YAAA,KAAK,UAAU;AACb,gBAAA,OAAO,IAAI;AACb,YAAA;AACE,gBAAA,OAAO,OAAO;;IAEpB;IAEA,QAAQ,GAAG;AACT,QAAA,KAAK,YAAY;AACf,YAAA,OAAO,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,CAAC,GAAG,OAAO;AAC/C,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG,CAAC,GAAG,OAAO;QAC5C,KAAK,WAAW,EAAE;AAChB,YAAA,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO;YAChC,OAAO,MAAM,IAAI,IAAI,GAAG,MAAM,GAAG,OAAO;QAC1C;QACA,KAAK,SAAS,EAAE;AACd,YAAA,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO;YAChC,OAAO,MAAM,IAAI,CAAC,GAAG,MAAM,GAAG,OAAO;QACvC;AACA,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,CAAC;AACV,QAAA,KAAK,KAAK;AACR,YAAA,OAAO,IAAI;AACb,QAAA,KAAK,UAAU;YACb,OAAO,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;AAC/C,QAAA,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;AAC/C,QAAA;AACE,YAAA,OAAO,OAAO;;AAEpB;AAEA;AACM,SAAU,UAAU,CAAC,CAAS,EAAE,CAAS,EAAA;AAC7C,IAAA,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AACjC;;;;"}
1
+ {"version":3,"file":"assetBrowserKeyboard.js","sources":["src/components/editor/AssetBrowser/assetBrowserKeyboard.ts"],"sourcesContent":["export interface GridNavParams {\n /** Number of columns currently laid out. */\n columns: number;\n /** Total item count. */\n count: number;\n /** Rows that fit in one viewport — used by PageUp/PageDown. */\n rowsPerPage: number;\n}\n\n/**\n * Pure 2D grid keyboard navigation. Given the focused index and a key, return\n * the next index. Returns the clamped target, or the original index when the\n * key is not a navigation key or the move would leave the grid.\n */\nexport function nextGridIndex(\n current: number,\n key: string,\n params: GridNavParams\n): number {\n const { count } = params;\n if (count === 0) return -1;\n\n const columns = Math.max(1, params.columns);\n const rowsPerPage = Math.max(1, params.rowsPerPage);\n const last = count - 1;\n const clamp = (n: number): number => Math.min(last, Math.max(0, n));\n\n // Starting from \"nothing focused\", any nav key lands on the first item.\n if (current < 0) {\n switch (key) {\n case 'ArrowRight':\n case 'ArrowDown':\n case 'ArrowLeft':\n case 'ArrowUp':\n case 'Home':\n case 'PageUp':\n return 0;\n case 'End':\n case 'PageDown':\n return last;\n default:\n return current;\n }\n }\n\n switch (key) {\n case 'ArrowRight':\n return current < last ? current + 1 : current;\n case 'ArrowLeft':\n return current > 0 ? current - 1 : current;\n case 'ArrowDown': {\n const target = current + columns;\n return target <= last ? target : current;\n }\n case 'ArrowUp': {\n const target = current - columns;\n return target >= 0 ? target : current;\n }\n case 'Home':\n return 0;\n case 'End':\n return last;\n case 'PageDown':\n return clamp(current + columns * rowsPerPage);\n case 'PageUp':\n return clamp(current - columns * rowsPerPage);\n default:\n return current;\n }\n}\n\n/** Inclusive index range between two indices, regardless of order. */\nexport function indexRange(a: number, b: number): [number, number] {\n return a <= b ? [a, b] : [b, a];\n}\n"],"names":[],"mappings":"AASA;;;;AAIG;SACa,aAAa,CAC3B,OAAe,EACf,GAAW,EACX,MAAqB,EAAA;AAErB,IAAA,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM;IACxB,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE;AAE1B,IAAA,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC;AAC3C,IAAA,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC;AACnD,IAAA,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC;IACtB,MAAM,KAAK,GAAG,CAAC,CAAS,KAAa,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;;AAGnE,IAAA,IAAI,OAAO,GAAG,CAAC,EAAE;QACf,QAAQ,GAAG;AACT,YAAA,KAAK,YAAY;AACjB,YAAA,KAAK,WAAW;AAChB,YAAA,KAAK,WAAW;AAChB,YAAA,KAAK,SAAS;AACd,YAAA,KAAK,MAAM;AACX,YAAA,KAAK,QAAQ;AACX,gBAAA,OAAO,CAAC;AACV,YAAA,KAAK,KAAK;AACV,YAAA,KAAK,UAAU;AACb,gBAAA,OAAO,IAAI;AACb,YAAA;AACE,gBAAA,OAAO,OAAO;;IAEpB;IAEA,QAAQ,GAAG;AACT,QAAA,KAAK,YAAY;AACf,YAAA,OAAO,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,CAAC,GAAG,OAAO;AAC/C,QAAA,KAAK,WAAW;AACd,YAAA,OAAO,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG,CAAC,GAAG,OAAO;QAC5C,KAAK,WAAW,EAAE;AAChB,YAAA,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO;YAChC,OAAO,MAAM,IAAI,IAAI,GAAG,MAAM,GAAG,OAAO;QAC1C;QACA,KAAK,SAAS,EAAE;AACd,YAAA,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO;YAChC,OAAO,MAAM,IAAI,CAAC,GAAG,MAAM,GAAG,OAAO;QACvC;AACA,QAAA,KAAK,MAAM;AACT,YAAA,OAAO,CAAC;AACV,QAAA,KAAK,KAAK;AACR,YAAA,OAAO,IAAI;AACb,QAAA,KAAK,UAAU;YACb,OAAO,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;AAC/C,QAAA,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,OAAO,GAAG,OAAO,GAAG,WAAW,CAAC;AAC/C,QAAA;AACE,YAAA,OAAO,OAAO;;AAEpB;AAEA;AACM,SAAU,UAAU,CAAC,CAAS,EAAE,CAAS,EAAA;AAC7C,IAAA,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;AACjC;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"assetBrowserLabels.js","sources":["../../../../../../src/components/editor/AssetBrowser/assetBrowserLabels.ts"],"sourcesContent":[null],"names":[],"mappings":"AAmEO,MAAM,4BAA4B,GAAuB;AAC9D,IAAA,iBAAiB,EAAE,gBAAgB;AACnC,IAAA,YAAY,EAAE,WAAW;AACzB,IAAA,eAAe,EAAE,WAAW;AAC5B,IAAA,eAAe,EAAE,WAAW;AAC5B,IAAA,QAAQ,EAAE,QAAQ;AAClB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,aAAa,EAAE,WAAW;AAC1B,IAAA,cAAc,EAAE,YAAY;AAC5B,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,iBAAiB,EAAE,gBAAgB;AACnC,IAAA,KAAK,EAAE,uBAAuB;AAC9B,IAAA,OAAO,EAAE,iBAAiB;AAC1B,IAAA,UAAU,EAAE,sBAAsB;AAClC,IAAA,gBAAgB,EAAE,iDAAiD;AACnE,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,aAAa,EAAE,sBAAsB;AACrC,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,UAAU,EAAE;AACV,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,QAAQ,EAAE,UAAU;AACrB,KAAA;AACD,IAAA,SAAS,EAAE,KAAK,IAAI,CAAA,EAAG,KAAK,CAAA,KAAA,EAAQ,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA,CAAE;AAC5D,IAAA,aAAa,EAAE,KAAK,IAAI,CAAA,EAAA,EAAK,KAAK,CAAA,SAAA,CAAW;;AAG/C;;;AAGG;AACG,SAAU,aAAa,CAC3B,SAAkD,EAAA;AAElD,IAAA,IAAI,CAAC,SAAS;AAAE,QAAA,OAAO,4BAA4B;IACnD,OAAO;AACL,QAAA,GAAG,4BAA4B;AAC/B,QAAA,GAAG,SAAS;AACZ,QAAA,UAAU,EAAE;YACV,GAAG,4BAA4B,CAAC,UAAU;YAC1C,GAAG,SAAS,CAAC,UAAU;AACxB,SAAA;KACF;AACH;;;;"}
1
+ {"version":3,"file":"assetBrowserLabels.js","sources":["src/components/editor/AssetBrowser/assetBrowserLabels.ts"],"sourcesContent":["import type { AssetSortField } from './AssetBrowser.types';\n\n/**\n * Every user-facing string in the AssetBrowser chrome. Pass a partial\n * `labels` prop to translate or reword any subset; unspecified keys fall back\n * to {@link DEFAULT_ASSET_BROWSER_LABELS} (English).\n *\n * The `*Aria` keys are accessible names (screen-reader only); the rest are\n * visible text. `sortFields` maps each sortable field id to its menu/column\n * label. `itemCount` / `selectedCount` build the live-region announcement and\n * receive the relevant counts.\n */\nexport interface AssetBrowserLabels {\n /** Search input placeholder. @default \"Search assets…\" */\n searchPlaceholder: string;\n /** Accessible name of the view-mode toggle. @default \"View mode\" */\n viewModeAria: string;\n /** Grid-view tooltip. @default \"Grid view\" */\n gridViewTooltip: string;\n /** List-view tooltip. @default \"List view\" */\n listViewTooltip: string;\n /** Accessible name of the grid region. @default \"Assets\" */\n gridAria: string;\n /** Sort menu trigger. @default \"Sort\" */\n sort: string;\n /** Ascending radio item. @default \"Ascending\" */\n sortAscending: string;\n /** Descending radio item. @default \"Descending\" */\n sortDescending: string;\n /** Filter menu trigger. @default \"Filter\" */\n filter: string;\n /** Back button accessible name. @default \"Back\" */\n back: string;\n /** Forward button accessible name. @default \"Forward\" */\n forward: string;\n /** Thumbnail-size control accessible name. @default \"Thumbnail size\" */\n thumbnailSizeAria: string;\n /** Default empty-folder message. @default \"This folder is empty.\" */\n empty: string;\n /** Loading message (list view) / skeleton aria. @default \"Loading assets…\" */\n loading: string;\n /** Built-in error title. @default \"Couldn’t load assets\" */\n errorTitle: string;\n /** Built-in error description. */\n errorDescription: string;\n /** Retry button. @default \"Retry\" */\n retry: string;\n /** File-import drop overlay. @default \"Drop files to import\" */\n importOverlay: string;\n /** List \"Type\" value for folders. @default \"Folder\" */\n folder: string;\n /** Rename default-action label + rename-field accessible name. @default \"Rename\" */\n rename: string;\n /** Delete default-action label. @default \"Delete\" */\n delete: string;\n /** Duplicate default-action label. @default \"Duplicate\" */\n duplicate: string;\n /** New-folder default-action label. @default \"New folder\" */\n newFolder: string;\n /** Per-sort-field labels (also the list column headers). */\n sortFields: Record<AssetSortField, string>;\n /** Live-region item count, e.g. `n => \\`${n} items\\``. */\n itemCount: (count: number) => string;\n /** Live-region selected count suffix, e.g. `n => \\`, ${n} selected\\``. */\n selectedCount: (count: number) => string;\n}\n\nexport const DEFAULT_ASSET_BROWSER_LABELS: AssetBrowserLabels = {\n searchPlaceholder: 'Search assets…',\n viewModeAria: 'View mode',\n gridViewTooltip: 'Grid view',\n listViewTooltip: 'List view',\n gridAria: 'Assets',\n sort: 'Sort',\n sortAscending: 'Ascending',\n sortDescending: 'Descending',\n filter: 'Filter',\n back: 'Back',\n forward: 'Forward',\n thumbnailSizeAria: 'Thumbnail size',\n empty: 'This folder is empty.',\n loading: 'Loading assets…',\n errorTitle: 'Couldn’t load assets',\n errorDescription: 'Something went wrong while loading this folder.',\n retry: 'Retry',\n importOverlay: 'Drop files to import',\n folder: 'Folder',\n rename: 'Rename',\n delete: 'Delete',\n duplicate: 'Duplicate',\n newFolder: 'New folder',\n sortFields: {\n name: 'Name',\n type: 'Type',\n size: 'Size',\n modified: 'Modified',\n },\n itemCount: count => `${count} item${count === 1 ? '' : 's'}`,\n selectedCount: count => `, ${count} selected`,\n};\n\n/**\n * Merge a consumer's partial `labels` onto the English defaults. `sortFields`\n * is merged one level deep so overriding a single column label keeps the rest.\n */\nexport function resolveLabels(\n overrides: Partial<AssetBrowserLabels> | undefined\n): AssetBrowserLabels {\n if (!overrides) return DEFAULT_ASSET_BROWSER_LABELS;\n return {\n ...DEFAULT_ASSET_BROWSER_LABELS,\n ...overrides,\n sortFields: {\n ...DEFAULT_ASSET_BROWSER_LABELS.sortFields,\n ...overrides.sortFields,\n },\n };\n}\n"],"names":[],"mappings":"AAmEO,MAAM,4BAA4B,GAAuB;AAC9D,IAAA,iBAAiB,EAAE,gBAAgB;AACnC,IAAA,YAAY,EAAE,WAAW;AACzB,IAAA,eAAe,EAAE,WAAW;AAC5B,IAAA,eAAe,EAAE,WAAW;AAC5B,IAAA,QAAQ,EAAE,QAAQ;AAClB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,aAAa,EAAE,WAAW;AAC1B,IAAA,cAAc,EAAE,YAAY;AAC5B,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,OAAO,EAAE,SAAS;AAClB,IAAA,iBAAiB,EAAE,gBAAgB;AACnC,IAAA,KAAK,EAAE,uBAAuB;AAC9B,IAAA,OAAO,EAAE,iBAAiB;AAC1B,IAAA,UAAU,EAAE,sBAAsB;AAClC,IAAA,gBAAgB,EAAE,iDAAiD;AACnE,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,aAAa,EAAE,sBAAsB;AACrC,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,MAAM,EAAE,QAAQ;AAChB,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,SAAS,EAAE,YAAY;AACvB,IAAA,UAAU,EAAE;AACV,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,IAAI,EAAE,MAAM;AACZ,QAAA,QAAQ,EAAE,UAAU;AACrB,KAAA;AACD,IAAA,SAAS,EAAE,KAAK,IAAI,CAAA,EAAG,KAAK,CAAA,KAAA,EAAQ,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAA,CAAE;AAC5D,IAAA,aAAa,EAAE,KAAK,IAAI,CAAA,EAAA,EAAK,KAAK,CAAA,SAAA,CAAW;;AAG/C;;;AAGG;AACG,SAAU,aAAa,CAC3B,SAAkD,EAAA;AAElD,IAAA,IAAI,CAAC,SAAS;AAAE,QAAA,OAAO,4BAA4B;IACnD,OAAO;AACL,QAAA,GAAG,4BAA4B;AAC/B,QAAA,GAAG,SAAS;AACZ,QAAA,UAAU,EAAE;YACV,GAAG,4BAA4B,CAAC,UAAU;YAC1C,GAAG,SAAS,CAAC,UAAU;AACxB,SAAA;KACF;AACH;;;;"}