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":"PropertyPanel.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
1
+ {"version":3,"file":"PropertyPanel.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
@@ -4,7 +4,7 @@ import { assignInlineVars } from '@vanilla-extract/dynamic';
4
4
  import { useState, useCallback, useDeferredValue, useMemo, createContext, useContext } from 'react';
5
5
  import { ScrollArea } from '../../layout/ScrollArea/ScrollArea.js';
6
6
  import { cx } from '../../../utils/cx.js';
7
- import { contentBottomSpacingVar, contentTopSpacingVar, panelContent, panelHeader, searchWrapper, searchInputBase, panelFooter, panelRoot } from './PropertyPanel.css.js';
7
+ import { contentBottomSpacingVar, contentTopSpacingVar, panelContent, panelHeader, searchWrapper, searchInputBase, panelContentScroll, panelFooter, panelRoot } from './PropertyPanel.css.js';
8
8
 
9
9
  // --- Context ---
10
10
  const PropertyPanelContext =
@@ -34,7 +34,7 @@ const SEARCH_SIZE_MAP = {
34
34
  },
35
35
  };
36
36
  // --- Component ---
37
- const PropertyPanel = ({ children, header, footer, size = 'md', maxHeight, searchable = false, searchPlaceholder = 'Search properties...', onSearchChange, contentTopSpacing, contentBottomSpacing, className, style, testId, ref, ...rest }) => {
37
+ const PropertyPanel = ({ children, header, footer, size = 'md', maxHeight, fillHeight = false, density = 'normal', searchable = false, searchPlaceholder = 'Search properties...', onSearchChange, contentTopSpacing, contentBottomSpacing, className, style, testId, ref, ...rest }) => {
38
38
  const [searchQuery, setSearchQuery] = useState('');
39
39
  const handleSearchChange = useCallback((e) => {
40
40
  const query = e.target.value;
@@ -47,8 +47,9 @@ const PropertyPanel = ({ children, header, footer, size = 'md', maxHeight, searc
47
47
  const deferredSearchQuery = useDeferredValue(searchQuery);
48
48
  const contextValue = useMemo(() => ({
49
49
  size,
50
+ density,
50
51
  searchQuery: deferredSearchQuery.toLowerCase(),
51
- }), [size, deferredSearchQuery]);
52
+ }), [size, density, deferredSearchQuery]);
52
53
  const hasHeader = header != null || searchable;
53
54
  const hasFooter = footer != null;
54
55
  const sizeConfig = SEARCH_SIZE_MAP[size];
@@ -65,7 +66,7 @@ const PropertyPanel = ({ children, header, footer, size = 'md', maxHeight, searc
65
66
  height: `${sizeConfig.height}px`,
66
67
  fontSize: sizeConfig.fontSize,
67
68
  padding: `0 ${sizeConfig.padding}`,
68
- } }) }))] })), maxHeight != null ? (jsx(ScrollArea, { maxHeight: maxHeight, direction: "vertical", scrollbarVisibility: "auto", fadeMask: true, children: content })) : (content), hasFooter && jsx("div", { className: panelFooter, children: footer })] }) }));
69
+ } }) }))] })), maxHeight != null ? (jsx(ScrollArea, { maxHeight: maxHeight, direction: "vertical", scrollbarVisibility: "auto", fadeMask: true, children: content })) : fillHeight ? (jsx(ScrollArea, { direction: "vertical", scrollbarVisibility: "auto", fadeMask: true, style: { flex: 1, minHeight: 0 }, children: jsx("div", { className: cx(panelContent, panelContentScroll), style: contentStyle, children: children }) })) : (content), hasFooter && jsx("div", { className: panelFooter, children: footer })] }) }));
69
70
  };
70
71
  PropertyPanel.displayName = 'PropertyPanel';
71
72
 
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyPanel.js","sources":["../../../../../../src/components/editor/PropertyInspector/PropertyPanel.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;AAgCA;AAEA;AACE;AAEF;;;AAGG;;AAED;AACF;AAYA;AACE;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;;AAGH;;;AAsBE;AAEI;;AAEA;AACF;;;;AAOF;AAEA;;AAGI;AACD;AAIH;AACA;AAEA;;AAGE;;AAGI;AACJ;;AAGI;AACL;AAED;AAMA;AAyBkB;;AAEA;;AAyBpB;AAEA;;"}
1
+ {"version":3,"file":"PropertyPanel.js","sources":["src/components/editor/PropertyInspector/PropertyPanel.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, {\n createContext,\n useCallback,\n useContext,\n useDeferredValue,\n useMemo,\n useState,\n} from 'react';\n\nimport { ScrollArea } from '@/components/layout/ScrollArea';\nimport { cx } from '@/utils/cx';\n\nimport {\n panelRoot,\n panelHeader,\n searchWrapper,\n searchInputBase,\n panelContent,\n panelContentScroll,\n panelFooter,\n contentTopSpacingVar,\n contentBottomSpacingVar,\n} from './PropertyPanel.css';\n\nimport type {\n PropertyInspectorSize,\n PropertyPanelContextValue,\n PropertyPanelProps,\n} from './PropertyInspector.types';\n\n// --- Context ---\n\nconst PropertyPanelContext =\n /*#__PURE__*/ createContext<PropertyPanelContextValue | null>(null);\n\n/**\n * Returns the PropertyPanel context value, or null if not inside a PropertyPanel.\n * Child components use this to inherit size and search query from the panel.\n */\nexport function usePropertyPanelContext(): PropertyPanelContextValue | null {\n return useContext(PropertyPanelContext);\n}\n\nexport { PropertyPanelContext };\n\n// --- Size map ---\n\ninterface SearchInputSizeConfig {\n height: number;\n fontSize: string;\n padding: string;\n}\n\nconst SEARCH_SIZE_MAP: Record<PropertyInspectorSize, SearchInputSizeConfig> = {\n sm: {\n height: 20,\n fontSize: 'var(--etui-font-size-md)',\n padding: 'var(--etui-spacing-sm)',\n },\n md: {\n height: 24,\n fontSize: 'var(--etui-font-size-md)',\n padding: 'var(--etui-spacing-md)',\n },\n lg: {\n height: 28,\n fontSize: 'var(--etui-font-size-lg)',\n padding: 'var(--etui-spacing-md)',\n },\n};\n\n// --- Component ---\n\nexport const PropertyPanel: React.FC<PropertyPanelProps> = ({\n children,\n header,\n footer,\n size = 'md',\n maxHeight,\n fillHeight = false,\n density = 'normal',\n searchable = false,\n searchPlaceholder = 'Search properties...',\n onSearchChange,\n contentTopSpacing,\n contentBottomSpacing,\n\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const [searchQuery, setSearchQuery] = useState('');\n\n const handleSearchChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const query = e.target.value;\n setSearchQuery(query);\n onSearchChange?.(query);\n },\n [onSearchChange]\n );\n\n // Defer the query handed to descendants for filtering so the search input\n // stays responsive while large property lists re-filter. The immediate\n // `searchQuery` still drives the input value.\n const deferredSearchQuery = useDeferredValue(searchQuery);\n\n const contextValue = useMemo<PropertyPanelContextValue>(\n () => ({\n size,\n density,\n searchQuery: deferredSearchQuery.toLowerCase(),\n }),\n [size, density, deferredSearchQuery]\n );\n\n const hasHeader = header != null || searchable;\n const hasFooter = footer != null;\n\n const sizeConfig = SEARCH_SIZE_MAP[size];\n\n const contentStyle = assignInlineVars({\n [contentTopSpacingVar]:\n contentTopSpacing != null\n ? `${contentTopSpacing}px`\n : 'var(--etui-spacing-sm)',\n [contentBottomSpacingVar]:\n contentBottomSpacing != null\n ? `${contentBottomSpacing}px`\n : 'var(--etui-spacing-md)',\n });\n\n const content = (\n <div className={panelContent} style={contentStyle}>\n {children}\n </div>\n );\n\n return (\n <PropertyPanelContext.Provider value={contextValue}>\n <div\n ref={ref}\n role=\"region\"\n aria-label=\"Properties\"\n className={cx(panelRoot, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {hasHeader && (\n <div className={panelHeader}>\n {header}\n {searchable && (\n <div className={searchWrapper}>\n <input\n type=\"search\"\n role=\"searchbox\"\n aria-label=\"Search properties\"\n placeholder={searchPlaceholder}\n value={searchQuery}\n onChange={handleSearchChange}\n className={searchInputBase}\n style={{\n height: `${sizeConfig.height}px`,\n fontSize: sizeConfig.fontSize,\n padding: `0 ${sizeConfig.padding}`,\n }}\n />\n </div>\n )}\n </div>\n )}\n\n {maxHeight != null ? (\n <ScrollArea\n maxHeight={maxHeight}\n direction=\"vertical\"\n scrollbarVisibility=\"auto\"\n fadeMask\n >\n {content}\n </ScrollArea>\n ) : fillHeight ? (\n <ScrollArea\n direction=\"vertical\"\n scrollbarVisibility=\"auto\"\n fadeMask\n style={{ flex: 1, minHeight: 0 }}\n >\n <div\n className={cx(panelContent, panelContentScroll)}\n style={contentStyle}\n >\n {children}\n </div>\n </ScrollArea>\n ) : (\n content\n )}\n\n {hasFooter && <div className={panelFooter}>{footer}</div>}\n </div>\n </PropertyPanelContext.Provider>\n );\n};\n\nPropertyPanel.displayName = 'PropertyPanel';\n"],"names":[],"mappings":";;;;;;;;AAiCA;AAEA;AACE;AAEF;;;AAGG;;AAED;AACF;AAYA;AACE;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;;AAGH;AAEO;;AAsBL;AAEI;;AAEA;AACF;;;;AAOF;AAEA;;;AAII;;AAKJ;AACA;AAEA;;AAGE;;AAGI;AACJ;;AAGI;AACL;AAED;AAMA;AAyBkB;;AAEA;;AAuCpB;AAEA;;"}
@@ -1,15 +1,16 @@
1
- import './../../../assets/src/components/editor/PropertyInspector/PropertyRow.css.ts.vanilla-C3YZnnHb.css';
1
+ import './../../../assets/src/components/editor/PropertyInspector/PropertyRow.css.ts.vanilla-pq1Uhd2a.css';
2
2
 
3
3
  var RESET_BUTTON_CLASS = 'property-row-reset';
4
4
  var controlRatioVar = 'var(--controlRatioVar__1ds48411)';
5
- var fullWidthControl = 'PropertyRow_fullWidthControl__1ds48417';
5
+ var fullWidthControl = 'PropertyRow_fullWidthControl__1ds48418';
6
6
  var fullWidthLabel = 'PropertyRow_fullWidthLabel__1ds48414';
7
- var modifiedDot = 'PropertyRow_modifiedDot__1ds48415';
8
- var resetButton = 'PropertyRow_resetButton__1ds48418';
9
- var rowControl = 'PropertyRow_rowControl__1ds48416';
7
+ var labelTooltipTarget = 'PropertyRow_labelTooltipTarget__1ds48415';
8
+ var modifiedDot = 'PropertyRow_modifiedDot__1ds48416';
9
+ var resetButton = 'PropertyRow_resetButton__1ds48419';
10
+ var rowControl = 'PropertyRow_rowControl__1ds48417';
10
11
  var rowLabel = 'PropertyRow_rowLabel__1ds48413';
11
12
  var rowRoot = 'PropertyRow_rowRoot__1ds48412';
12
13
  var splitRatioVar = 'var(--splitRatioVar__1ds48410)';
13
14
 
14
- export { RESET_BUTTON_CLASS, controlRatioVar, fullWidthControl, fullWidthLabel, modifiedDot, resetButton, rowControl, rowLabel, rowRoot, splitRatioVar };
15
+ export { RESET_BUTTON_CLASS, controlRatioVar, fullWidthControl, fullWidthLabel, labelTooltipTarget, modifiedDot, resetButton, rowControl, rowLabel, rowRoot, splitRatioVar };
15
16
  //# sourceMappingURL=PropertyRow.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyRow.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"PropertyRow.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -89,10 +89,16 @@ 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 { Tooltip } from '../../primitives/Tooltip/Tooltip.js';
93
99
  import { cx } from '../../../utils/cx.js';
94
100
  import { usePropertyPanelContext } from './PropertyPanel.js';
95
- import { modifiedDot, controlRatioVar, splitRatioVar, fullWidthLabel, fullWidthControl, rowLabel, rowControl, resetButton, RESET_BUTTON_CLASS, rowRoot } from './PropertyRow.css.js';
101
+ import { modifiedDot, labelTooltipTarget, controlRatioVar, splitRatioVar, fullWidthLabel, fullWidthControl, rowLabel, rowControl, resetButton, RESET_BUTTON_CLASS, rowRoot } from './PropertyRow.css.js';
96
102
 
97
103
  const ROW_SIZE_MAP = {
98
104
  sm: {
@@ -111,18 +117,25 @@ const ROW_SIZE_MAP = {
111
117
  resetIconSize: 14,
112
118
  },
113
119
  };
120
+ const DENSITY_MAP = {
121
+ compact: { minHeightDelta: -4, paddingBlock: 0 },
122
+ normal: { minHeightDelta: 0, paddingBlock: 2 },
123
+ spacious: { minHeightDelta: 6, paddingBlock: 5 },
124
+ };
114
125
  // --- Component ---
115
126
  const PropertyRow = ({ label, tooltip, children, fullWidth = false, splitRatio = [40, 60], modified = false, disabled = false, visible = true, size: sizeProp, action, onLabelContextMenu, onReset, className, style, testId, ref, ...rest }) => {
116
127
  const panelCtx = usePropertyPanelContext();
117
128
  const size = sizeProp ?? panelCtx?.size ?? 'md';
118
129
  const sizeConfig = ROW_SIZE_MAP[size];
130
+ const densityConfig = DENSITY_MAP[panelCtx?.density ?? 'normal'];
131
+ const rowMinHeight = sizeConfig.minHeight + densityConfig.minHeightDelta;
119
132
  const handleResetClick = useCallback((e) => {
120
133
  e.stopPropagation();
121
134
  onReset?.();
122
135
  }, [onReset]);
123
136
  const modifiedDotEl = modified ? (jsx("span", { className: modifiedDot, "aria-label": "Modified", "data-testid": "modified-dot" })) : null;
124
137
  const labelText = jsx("span", { children: label });
125
- const labelElement = tooltip ? (jsx(Tooltip, { title: tooltip, children: jsxs("span", { style: { display: 'contents' }, children: [modifiedDotEl, labelText] }) })) : (jsxs(Fragment, { children: [modifiedDotEl, labelText] }));
138
+ const labelElement = tooltip ? (jsx(Tooltip, { title: tooltip, children: jsxs("span", { className: labelTooltipTarget, children: [modifiedDotEl, labelText] }) })) : (jsxs(Fragment, { children: [modifiedDotEl, labelText] }));
126
139
  const inlineVars = assignInlineVars({
127
140
  [splitRatioVar]: `${splitRatio[0]}%`,
128
141
  [controlRatioVar]: `${splitRatio[1]}%`,
@@ -133,7 +146,9 @@ const PropertyRow = ({ label, tooltip, children, fullWidth = false, splitRatio =
133
146
  display: visible ? 'flex' : 'none',
134
147
  flexDirection: fullWidth ? 'column' : 'row',
135
148
  alignItems: fullWidth ? 'stretch' : 'center',
136
- minHeight: `${sizeConfig.minHeight}px`,
149
+ minHeight: `${rowMinHeight}px`,
150
+ paddingTop: `${densityConfig.paddingBlock}px`,
151
+ paddingBottom: `${densityConfig.paddingBlock}px`,
137
152
  opacity: disabled ? 0.5 : 1,
138
153
  pointerEvents: disabled ? 'none' : 'auto',
139
154
  }, "data-testid": testId, ...rest, children: [fullWidth ? (jsxs(Fragment, { children: [jsx("div", { className: fullWidthLabel, onContextMenu: onLabelContextMenu, style: {
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyRow.js","sources":["../../../../../../src/components/editor/PropertyInspector/PropertyRow.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA;AACE;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;;AAGH;AAEO;AAoBL;;AAEA;AAEA;;;AAIE;;AAYF;AAEA;;;;AAiBC;AAED;AAKM;AACA;;;;AAIA;;;;;AAcM;AACE;AACA;;;AAcF;AACE;AACA;;AAmBJ;;AAEE;;AAEJ;AAQV;AAEA;;"}
1
+ {"version":3,"file":"PropertyRow.js","sources":["src/components/editor/PropertyInspector/PropertyRow.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useCallback } from 'react';\n\nimport { UndoIcon } from '@/components/Icons';\nimport { Tooltip } from '@/components/primitives/Tooltip';\nimport { cx } from '@/utils/cx';\n\nimport { usePropertyPanelContext } from './PropertyPanel';\nimport {\n RESET_BUTTON_CLASS,\n splitRatioVar,\n controlRatioVar,\n rowRoot,\n rowLabel,\n fullWidthLabel,\n labelTooltipTarget,\n modifiedDot,\n rowControl,\n fullWidthControl,\n resetButton,\n} from './PropertyRow.css';\n\nimport type {\n PropertyDensity,\n PropertyInspectorSize,\n PropertyRowProps,\n} from './PropertyInspector.types';\n\n// --- Size maps ---\n\ninterface RowSizeConfig {\n minHeight: number;\n fontSize: string;\n resetIconSize: number;\n}\n\nconst ROW_SIZE_MAP: Record<PropertyInspectorSize, RowSizeConfig> = {\n sm: {\n minHeight: 22,\n fontSize: 'var(--etui-font-size-md)',\n resetIconSize: 10,\n },\n md: {\n minHeight: 26,\n fontSize: 'var(--etui-font-size-md)',\n resetIconSize: 12,\n },\n lg: {\n minHeight: 30,\n fontSize: 'var(--etui-font-size-lg)',\n resetIconSize: 14,\n },\n};\n\n// --- Density maps ---\n\ninterface DensityConfig {\n /** Adjustment applied to the size-based min-height (px). */\n minHeightDelta: number;\n /** Vertical padding above/below the row content (px). */\n paddingBlock: number;\n}\n\nconst DENSITY_MAP: Record<PropertyDensity, DensityConfig> = {\n compact: { minHeightDelta: -4, paddingBlock: 0 },\n normal: { minHeightDelta: 0, paddingBlock: 2 },\n spacious: { minHeightDelta: 6, paddingBlock: 5 },\n};\n\n// --- Component ---\n\nexport const PropertyRow: React.FC<PropertyRowProps> = ({\n label,\n tooltip,\n children,\n fullWidth = false,\n splitRatio = [40, 60],\n modified = false,\n disabled = false,\n visible = true,\n size: sizeProp,\n action,\n onLabelContextMenu,\n onReset,\n\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const panelCtx = usePropertyPanelContext();\n const size = sizeProp ?? panelCtx?.size ?? 'md';\n const sizeConfig = ROW_SIZE_MAP[size];\n const densityConfig = DENSITY_MAP[panelCtx?.density ?? 'normal'];\n const rowMinHeight = sizeConfig.minHeight + densityConfig.minHeightDelta;\n\n const handleResetClick = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onReset?.();\n },\n [onReset]\n );\n\n const modifiedDotEl = modified ? (\n <span\n className={modifiedDot}\n aria-label=\"Modified\"\n data-testid=\"modified-dot\"\n />\n ) : null;\n\n const labelText = <span>{label}</span>;\n\n const labelElement = tooltip ? (\n <Tooltip title={tooltip}>\n <span className={labelTooltipTarget}>\n {modifiedDotEl}\n {labelText}\n </span>\n </Tooltip>\n ) : (\n <>\n {modifiedDotEl}\n {labelText}\n </>\n );\n\n const inlineVars = assignInlineVars({\n [splitRatioVar]: `${splitRatio[0]}%`,\n [controlRatioVar]: `${splitRatio[1]}%`,\n });\n\n return (\n <div\n ref={ref}\n className={cx(rowRoot, className)}\n style={{\n ...style,\n ...inlineVars,\n display: visible ? 'flex' : 'none',\n flexDirection: fullWidth ? 'column' : 'row',\n alignItems: fullWidth ? 'stretch' : 'center',\n minHeight: `${rowMinHeight}px`,\n paddingTop: `${densityConfig.paddingBlock}px`,\n paddingBottom: `${densityConfig.paddingBlock}px`,\n opacity: disabled ? 0.5 : 1,\n pointerEvents: disabled ? 'none' : 'auto',\n }}\n data-testid={testId}\n {...rest}\n >\n {fullWidth ? (\n <>\n <div\n className={fullWidthLabel}\n onContextMenu={onLabelContextMenu}\n style={{\n fontSize: sizeConfig.fontSize,\n fontWeight: modified\n ? 'var(--etui-font-weight-medium)'\n : 'var(--etui-font-weight-normal)',\n }}\n >\n {labelElement}\n </div>\n <div className={fullWidthControl}>{children}</div>\n </>\n ) : (\n <>\n <div\n className={rowLabel}\n onContextMenu={onLabelContextMenu}\n style={{\n fontSize: sizeConfig.fontSize,\n fontWeight: modified\n ? 'var(--etui-font-weight-medium)'\n : 'var(--etui-font-weight-normal)',\n }}\n >\n {labelElement}\n </div>\n <div className={rowControl}>{children}</div>\n </>\n )}\n\n {action}\n\n {onReset && (\n <span\n className={cx(RESET_BUTTON_CLASS, resetButton)}\n role=\"button\"\n tabIndex={0}\n aria-label=\"Reset to default\"\n onClick={handleResetClick}\n onKeyDown={(e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onReset();\n }\n }}\n data-testid=\"reset-button\"\n >\n <UndoIcon size={sizeConfig.resetIconSize} decorative />\n </span>\n )}\n </div>\n );\n};\n\nPropertyRow.displayName = 'PropertyRow';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA;AACE;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACD;;AAYH;;;;;AAMA;AAEO;AAoBL;;AAEA;;;AAIA;;;AAIE;;AAYF;AAEA;;;;AAiBC;AAED;AAKM;AACA;;;;;AAKA;AACA;;;;;AAcM;AACE;AACA;;;AAcF;AACE;AACA;;AAmBJ;;AAEE;;AAEJ;AAQV;AAEA;;"}
@@ -1,15 +1,16 @@
1
- import './../../../assets/src/components/editor/PropertyInspector/PropertySection.css.ts.vanilla-DK12opZc.css';
1
+ import './../../../assets/src/components/editor/PropertyInspector/PropertySection.css.ts.vanilla-6MWWAqyd.css';
2
2
  import { createRuntimeFn } from '@vanilla-extract/recipes/createRuntimeFn';
3
3
 
4
- var actionsArea = 'PropertySection_actionsArea__1xiu0w6d';
5
- var chevron = 'PropertySection_chevron__1xiu0w69';
6
- var chevronExpanded = 'PropertySection_chevronExpanded__1xiu0w6a';
7
- var contentInner = 'PropertySection_contentInner__1xiu0w6h';
8
- var contentWrapper = createRuntimeFn({defaultClassName:'PropertySection_contentWrapper__1xiu0w6e',variantClassNames:{expanded:{true:'PropertySection_contentWrapper_expanded_true__1xiu0w6f',false:'PropertySection_contentWrapper_expanded_false__1xiu0w6g'}},defaultVariants:{expanded:false},compoundVariants:[]});
9
- var iconArea = 'PropertySection_iconArea__1xiu0w6b';
10
- var sectionLabel = 'PropertySection_sectionLabel__1xiu0w6c';
4
+ var chevron = 'PropertySection_chevron__1xiu0w6f';
5
+ var chevronExpanded = 'PropertySection_chevronExpanded__1xiu0w6g';
6
+ var contentInner = 'PropertySection_contentInner__1xiu0w6n';
7
+ var contentWrapper = createRuntimeFn({defaultClassName:'PropertySection_contentWrapper__1xiu0w6k',variantClassNames:{expanded:{true:'PropertySection_contentWrapper_expanded_true__1xiu0w6l',false:'PropertySection_contentWrapper_expanded_false__1xiu0w6m'}},defaultVariants:{expanded:false},compoundVariants:[]});
8
+ var headerControls = 'PropertySection_headerControls__1xiu0w6j';
9
+ var iconArea = 'PropertySection_iconArea__1xiu0w6h';
10
+ var sectionHeader = createRuntimeFn({defaultClassName:'PropertySection_sectionHeader__1xiu0w61',variantClassNames:{size:{sm:'PropertySection_sectionHeader_size_sm__1xiu0w62',md:'PropertySection_sectionHeader_size_md__1xiu0w63',lg:'PropertySection_sectionHeader_size_lg__1xiu0w64'},disabled:{true:'PropertySection_sectionHeader_disabled_true__1xiu0w65',false:'PropertySection_sectionHeader_disabled_false__1xiu0w66'},expanded:{true:'PropertySection_sectionHeader_expanded_true__1xiu0w67',false:'PropertySection_sectionHeader_expanded_false__1xiu0w68'}},defaultVariants:{size:'md',disabled:false,expanded:false},compoundVariants:[]});
11
+ var sectionLabel = 'PropertySection_sectionLabel__1xiu0w6i';
11
12
  var sectionRoot = 'PropertySection_sectionRoot__1xiu0w60';
12
- var sectionTrigger = createRuntimeFn({defaultClassName:'PropertySection_sectionTrigger__1xiu0w61',variantClassNames:{size:{sm:'PropertySection_sectionTrigger_size_sm__1xiu0w62',md:'PropertySection_sectionTrigger_size_md__1xiu0w63',lg:'PropertySection_sectionTrigger_size_lg__1xiu0w64'},disabled:{true:'PropertySection_sectionTrigger_disabled_true__1xiu0w65',false:'PropertySection_sectionTrigger_disabled_false__1xiu0w66'},expanded:{true:'PropertySection_sectionTrigger_expanded_true__1xiu0w67',false:'PropertySection_sectionTrigger_expanded_false__1xiu0w68'}},defaultVariants:{size:'md',disabled:false,expanded:false},compoundVariants:[]});
13
+ var sectionTrigger = createRuntimeFn({defaultClassName:'PropertySection_sectionTrigger__1xiu0w69',variantClassNames:{size:{sm:'PropertySection_sectionTrigger_size_sm__1xiu0w6a',md:'PropertySection_sectionTrigger_size_md__1xiu0w6b',lg:'PropertySection_sectionTrigger_size_lg__1xiu0w6c'},disabled:{true:'PropertySection_sectionTrigger_disabled_true__1xiu0w6d',false:'PropertySection_sectionTrigger_disabled_false__1xiu0w6e'}},defaultVariants:{size:'md',disabled:false},compoundVariants:[]});
13
14
 
14
- export { actionsArea, chevron, chevronExpanded, contentInner, contentWrapper, iconArea, sectionLabel, sectionRoot, sectionTrigger };
15
+ export { chevron, chevronExpanded, contentInner, contentWrapper, headerControls, iconArea, sectionHeader, sectionLabel, sectionRoot, sectionTrigger };
15
16
  //# sourceMappingURL=PropertySection.css.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PropertySection.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"PropertySection.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;"}
@@ -88,9 +88,16 @@ import '../../Icons/GitBranchIcon.js';
88
88
  import '../../Icons/BugIcon.js';
89
89
  import '../../Icons/MinusIcon.js';
90
90
  import '../../Icons/PinIcon.js';
91
+ import '../../Icons/OrbitIcon.js';
92
+ import '../../Icons/RotateIcon.js';
93
+ import '../../Icons/SpinIcon.js';
94
+ import '../../Icons/CameraIcon.js';
95
+ import '../../Icons/CubeIcon.js';
96
+ import '../../Icons/ZoomFitIcon.js';
97
+ import { Switch } from '../../primitives/Switch/Switch.js';
91
98
  import { cx } from '../../../utils/cx.js';
92
99
  import { usePropertyPanelContext } from './PropertyPanel.js';
93
- import { chevronExpanded, chevron, iconArea, sectionLabel, actionsArea, sectionTrigger, contentInner, contentWrapper, sectionRoot } from './PropertySection.css.js';
100
+ import { chevronExpanded, chevron, iconArea, sectionLabel, sectionTrigger, headerControls, sectionHeader, contentInner, contentWrapper, sectionRoot } from './PropertySection.css.js';
94
101
 
95
102
  const TRIGGER_SIZE_MAP = {
96
103
  sm: { chevronSize: 10 },
@@ -98,7 +105,7 @@ const TRIGGER_SIZE_MAP = {
98
105
  lg: { chevronSize: 14 },
99
106
  };
100
107
  // --- Component ---
101
- const PropertySection = ({ title, icon, actions, expanded: expandedProp, defaultExpanded = true, onExpandedChange, keepMounted = false, disabled = false, size: sizeProp, indicator, onContextMenu, children, className, style, testId, ref, ...rest }) => {
108
+ const PropertySection = ({ title, icon, actions, expanded: expandedProp, defaultExpanded = true, onExpandedChange, keepMounted = false, disabled = false, checkable = false, checked: checkedProp, defaultChecked = true, onCheckedChange, checkLabel, size: sizeProp, indicator, onContextMenu, children, className, style, testId, ref, ...rest }) => {
102
109
  const autoId = useId();
103
110
  const triggerId = `property-section-${autoId}-trigger`;
104
111
  const contentId = `property-section-${autoId}-content`;
@@ -108,6 +115,11 @@ const PropertySection = ({ title, icon, actions, expanded: expandedProp, default
108
115
  const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
109
116
  const isControlled = expandedProp !== undefined;
110
117
  const resolvedExpanded = isControlled ? expandedProp : internalExpanded;
118
+ // Enable/disable toggle state (controlled or uncontrolled), mirroring the
119
+ // expanded-state bridge above. Independent of the collapse state.
120
+ const [internalChecked, setInternalChecked] = useState(defaultChecked);
121
+ const isCheckedControlled = checkedProp !== undefined;
122
+ const resolvedChecked = isCheckedControlled ? checkedProp : internalChecked;
111
123
  const handleToggle = useCallback(() => {
112
124
  if (disabled)
113
125
  return;
@@ -117,30 +129,26 @@ const PropertySection = ({ title, icon, actions, expanded: expandedProp, default
117
129
  }
118
130
  onExpandedChange?.(nextExpanded);
119
131
  }, [disabled, resolvedExpanded, isControlled, onExpandedChange]);
120
- const handleActionsClick = useCallback((e) => {
121
- e.stopPropagation();
122
- }, []);
123
- // Prevent keyboard activation on nested action controls from bubbling up
124
- // and toggling the section trigger.
125
- const handleActionsKeyDown = useCallback((e) => {
126
- if (e.key === 'Enter' || e.key === ' ') {
127
- e.stopPropagation();
132
+ const handleCheckedChange = useCallback((next) => {
133
+ if (!isCheckedControlled) {
134
+ setInternalChecked(next);
128
135
  }
129
- }, []);
136
+ onCheckedChange?.(next);
137
+ }, [isCheckedControlled, onCheckedChange]);
138
+ // When the section is checkable and switched off, the body is dimmed and made
139
+ // non-interactive but stays mounted (so its state is preserved).
140
+ const isBodyDisabled = checkable && !resolvedChecked;
130
141
  const showIndicator = indicator !== null;
131
- return (jsxs("div", { ref: ref, className: cx(sectionRoot, className), style: style, "data-testid": testId, ...rest, children: [jsxs("button", { type: "button", id: triggerId, "aria-expanded": resolvedExpanded, "aria-controls": contentId, "aria-disabled": disabled || undefined, disabled: disabled, onClick: handleToggle, onContextMenu: onContextMenu, className: sectionTrigger({
142
+ return (jsxs("div", { ref: ref, className: cx(sectionRoot, className), style: style, "data-testid": testId, ...rest, children: [jsxs("div", { className: sectionHeader({
132
143
  size,
133
144
  disabled,
134
145
  expanded: resolvedExpanded,
135
- }), children: [showIndicator && (jsx("span", { className: cx(chevron, resolvedExpanded && chevronExpanded), style: {
136
- width: `${sizeConfig.chevronSize}px`,
137
- height: `${sizeConfig.chevronSize}px`,
138
- }, children: indicator ?? (jsx(ChevronRightIcon, { size: sizeConfig.chevronSize, decorative: true })) })), icon && jsx("span", { className: iconArea, children: icon }), jsx("span", { className: sectionLabel, children: title }), actions && (
139
- // This wrapper is a non-semantic propagation boundary for the
140
- // user-supplied action controls it hosts; it is not itself
141
- // interactive, so it intentionally has no role.
142
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions
143
- jsx("span", { className: actionsArea, onClick: handleActionsClick, onKeyDown: handleActionsKeyDown, children: actions }))] }), (resolvedExpanded || keepMounted) && (jsx("div", { className: contentWrapper({ expanded: resolvedExpanded }), role: "region", id: contentId, "aria-labelledby": triggerId, hidden: !resolvedExpanded || undefined, children: jsx("div", { className: contentInner, children: children }) }))] }));
146
+ }), children: [jsxs("button", { type: "button", id: triggerId, "aria-expanded": resolvedExpanded, "aria-controls": contentId, "aria-disabled": disabled || undefined, disabled: disabled, onClick: handleToggle, onContextMenu: onContextMenu, className: sectionTrigger({ size, disabled }), children: [showIndicator && (jsx("span", { className: cx(chevron, resolvedExpanded && chevronExpanded), style: {
147
+ width: `${sizeConfig.chevronSize}px`,
148
+ height: `${sizeConfig.chevronSize}px`,
149
+ }, children: indicator ?? (jsx(ChevronRightIcon, { size: sizeConfig.chevronSize, decorative: true })) })), icon && jsx("span", { className: iconArea, children: icon }), jsx("span", { className: sectionLabel, children: title })] }), (checkable || actions) && (jsxs("span", { className: headerControls, children: [checkable && (jsx(Switch, { size: size, checked: resolvedChecked, onChange: handleCheckedChange, disabled: disabled, "aria-label": checkLabel ?? title, testId: "section-toggle" })), actions] }))] }), (resolvedExpanded || keepMounted) && (jsx("div", { className: contentWrapper({ expanded: resolvedExpanded }), role: "region", id: contentId, "aria-labelledby": triggerId, hidden: !resolvedExpanded || undefined, children: jsx("div", { className: contentInner, style: isBodyDisabled
150
+ ? { opacity: 0.5, pointerEvents: 'none' }
151
+ : undefined, "aria-disabled": isBodyDisabled || undefined, children: children }) }))] }));
144
152
  };
145
153
  PropertySection.displayName = 'PropertySection';
146
154
 
@@ -1 +1 @@
1
- {"version":3,"file":"PropertySection.js","sources":["../../../../../../src/components/editor/PropertyInspector/PropertySection.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA;AACE;AACA;AACA;;AAGF;AAEO;AAoBL;AACA;AACA;AAEA;;AAEA;;AAGA;;AAGA;AACE;;AAEA;;;;AAMA;;AAGF;;;;;AAMA;AACE;;;;AAKF;;;;AAsBQ;AACD;AAMK;AACA;AACD;;;;;AAcH;AAuBV;AAEA;;"}
1
+ {"version":3,"file":"PropertySection.js","sources":["src/components/editor/PropertyInspector/PropertySection.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useId, useState } from 'react';\n\nimport { ChevronRightIcon } from '@/components/Icons';\nimport { Switch } from '@/components/primitives/Switch';\nimport { cx } from '@/utils/cx';\n\nimport { usePropertyPanelContext } from './PropertyPanel';\nimport {\n sectionRoot,\n sectionHeader,\n sectionTrigger,\n chevron,\n chevronExpanded,\n iconArea,\n sectionLabel,\n headerControls,\n contentWrapper,\n contentInner,\n} from './PropertySection.css';\n\nimport type {\n PropertyInspectorSize,\n PropertySectionProps,\n} from './PropertyInspector.types';\n\n// --- Size maps ---\n\ninterface TriggerSizeConfig {\n chevronSize: number;\n}\n\nconst TRIGGER_SIZE_MAP: Record<PropertyInspectorSize, TriggerSizeConfig> = {\n sm: { chevronSize: 10 },\n md: { chevronSize: 12 },\n lg: { chevronSize: 14 },\n};\n\n// --- Component ---\n\nexport const PropertySection: React.FC<PropertySectionProps> = ({\n title,\n icon,\n actions,\n expanded: expandedProp,\n defaultExpanded = true,\n onExpandedChange,\n keepMounted = false,\n disabled = false,\n checkable = false,\n checked: checkedProp,\n defaultChecked = true,\n onCheckedChange,\n checkLabel,\n size: sizeProp,\n indicator,\n onContextMenu,\n children,\n\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const autoId = useId();\n const triggerId = `property-section-${autoId}-trigger`;\n const contentId = `property-section-${autoId}-content`;\n\n const panelCtx = usePropertyPanelContext();\n const size = sizeProp ?? panelCtx?.size ?? 'md';\n const sizeConfig = TRIGGER_SIZE_MAP[size];\n\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n const isControlled = expandedProp !== undefined;\n const resolvedExpanded = isControlled ? expandedProp : internalExpanded;\n\n // Enable/disable toggle state (controlled or uncontrolled), mirroring the\n // expanded-state bridge above. Independent of the collapse state.\n const [internalChecked, setInternalChecked] = useState(defaultChecked);\n const isCheckedControlled = checkedProp !== undefined;\n const resolvedChecked = isCheckedControlled ? checkedProp : internalChecked;\n\n const handleToggle = useCallback(() => {\n if (disabled) return;\n\n const nextExpanded = !resolvedExpanded;\n\n if (!isControlled) {\n setInternalExpanded(nextExpanded);\n }\n\n onExpandedChange?.(nextExpanded);\n }, [disabled, resolvedExpanded, isControlled, onExpandedChange]);\n\n const handleCheckedChange = useCallback(\n (next: boolean) => {\n if (!isCheckedControlled) {\n setInternalChecked(next);\n }\n onCheckedChange?.(next);\n },\n [isCheckedControlled, onCheckedChange]\n );\n\n // When the section is checkable and switched off, the body is dimmed and made\n // non-interactive but stays mounted (so its state is preserved).\n const isBodyDisabled = checkable && !resolvedChecked;\n\n const showIndicator = indicator !== null;\n\n return (\n <div\n ref={ref}\n className={cx(sectionRoot, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n <div\n className={sectionHeader({\n size,\n disabled,\n expanded: resolvedExpanded,\n })}\n >\n <button\n type=\"button\"\n id={triggerId}\n aria-expanded={resolvedExpanded}\n aria-controls={contentId}\n aria-disabled={disabled || undefined}\n disabled={disabled}\n onClick={handleToggle}\n onContextMenu={onContextMenu}\n className={sectionTrigger({ size, disabled })}\n >\n {showIndicator && (\n <span\n className={cx(chevron, resolvedExpanded && chevronExpanded)}\n style={{\n width: `${sizeConfig.chevronSize}px`,\n height: `${sizeConfig.chevronSize}px`,\n }}\n >\n {indicator ?? (\n <ChevronRightIcon size={sizeConfig.chevronSize} decorative />\n )}\n </span>\n )}\n {icon && <span className={iconArea}>{icon}</span>}\n <span className={sectionLabel}>{title}</span>\n </button>\n {(checkable || actions) && (\n <span className={headerControls}>\n {checkable && (\n <Switch\n size={size}\n checked={resolvedChecked}\n onChange={handleCheckedChange}\n disabled={disabled}\n aria-label={checkLabel ?? title}\n testId=\"section-toggle\"\n />\n )}\n {actions}\n </span>\n )}\n </div>\n\n {(resolvedExpanded || keepMounted) && (\n <div\n className={contentWrapper({ expanded: resolvedExpanded })}\n role=\"region\"\n id={contentId}\n aria-labelledby={triggerId}\n hidden={!resolvedExpanded || undefined}\n >\n <div\n className={contentInner}\n style={\n isBodyDisabled\n ? { opacity: 0.5, pointerEvents: 'none' }\n : undefined\n }\n aria-disabled={isBodyDisabled || undefined}\n >\n {children}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nPropertySection.displayName = 'PropertySection';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA;AACE;AACA;AACA;;AAGF;AAEO;AAyBL;AACA;AACA;AAEA;;AAEA;;AAGA;;;;;AAMA;;AAGA;AACE;;AAEA;;;;AAMA;;AAGF;;;;AAKI;AACF;;;AAMF;AAEA;;;;AAcQ;;AAkBM;AACA;AACD;;AAwCC;AAUhB;AAEA;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"usePropertyUndo.js","sources":["../../../../../../src/components/editor/PropertyInspector/usePropertyUndo.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAuBA;AAIE;;AAEI;;;;;AAKE;AACA;;;;AAIF;AAAkC;AAClC;;;;;;;AASA;AAAkC;AAClC;;;;;;AAQF;;AAEA;AACE;;AAEN;AAEA;AAEA;;;AAGG;AACG;AAGJ;;AAGE;AACA;AACD;AAED;AAEI;AACE;;;AAGD;AACH;AAIF;AACE;AAAkC;AAClC;AAGA;AACA;AACF;AAEA;AACE;AAAkC;AAClC;AAGA;AACA;AACF;AAEA;AACE;;;;;;AAOA;AACA;;;;AAIJ;;"}
1
+ {"version":3,"file":"usePropertyUndo.js","sources":["src/components/editor/PropertyInspector/usePropertyUndo.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useReducer } from 'react';\n\nimport type {\n PropertyUndoEntry,\n UsePropertyUndoOptions,\n UsePropertyUndoReturn,\n} from './PropertyInspector.types';\n\n// --- Reducer ---\n\ninterface UndoState<T> {\n undoStack: PropertyUndoEntry<T>[];\n redoStack: PropertyUndoEntry<T>[];\n}\n\ntype UndoAction<T> =\n | { type: 'RECORD'; entry: PropertyUndoEntry<T>; maxHistory: number }\n | { type: 'UNDO' }\n | { type: 'REDO' }\n | { type: 'CLEAR' };\n\nfunction undoReducer<T>(\n state: UndoState<T>,\n action: UndoAction<T>\n): UndoState<T> {\n switch (action.type) {\n case 'RECORD': {\n const newStack = [...state.undoStack, action.entry];\n if (newStack.length > action.maxHistory) {\n newStack.shift();\n }\n return {\n undoStack: newStack,\n redoStack: [],\n };\n }\n case 'UNDO': {\n if (state.undoStack.length === 0) return state;\n const entry = state.undoStack[\n state.undoStack.length - 1\n ] as PropertyUndoEntry<T>;\n return {\n undoStack: state.undoStack.slice(0, -1),\n redoStack: [...state.redoStack, entry],\n };\n }\n case 'REDO': {\n if (state.redoStack.length === 0) return state;\n const entry = state.redoStack[\n state.redoStack.length - 1\n ] as PropertyUndoEntry<T>;\n return {\n undoStack: [...state.undoStack, entry],\n redoStack: state.redoStack.slice(0, -1),\n };\n }\n case 'CLEAR':\n return { undoStack: [], redoStack: [] };\n default:\n return state;\n }\n}\n\n// --- Hook ---\n\n/**\n * Lightweight undo/redo stack for property changes.\n * Records entries with property identifiers and values for precise undo control.\n */\nexport function usePropertyUndo<T = unknown>(\n options?: UsePropertyUndoOptions\n): UsePropertyUndoReturn<T> {\n const maxHistory = options?.maxHistory ?? 50;\n\n const [state, dispatch] = useReducer(undoReducer<T>, {\n undoStack: [],\n redoStack: [],\n });\n\n const record = useCallback(\n (entry: Omit<PropertyUndoEntry<T>, 'timestamp'>) => {\n dispatch({\n type: 'RECORD',\n entry: { ...entry, timestamp: Date.now() },\n maxHistory,\n });\n },\n [maxHistory]\n );\n\n const undo = useCallback((): PropertyUndoEntry<T> | null => {\n if (state.undoStack.length === 0) return null;\n const entry = state.undoStack[\n state.undoStack.length - 1\n ] as PropertyUndoEntry<T>;\n dispatch({ type: 'UNDO' });\n return entry;\n }, [state.undoStack]);\n\n const redo = useCallback((): PropertyUndoEntry<T> | null => {\n if (state.redoStack.length === 0) return null;\n const entry = state.redoStack[\n state.redoStack.length - 1\n ] as PropertyUndoEntry<T>;\n dispatch({ type: 'REDO' });\n return entry;\n }, [state.redoStack]);\n\n const clear = useCallback(() => {\n dispatch({ type: 'CLEAR' });\n }, []);\n\n return {\n record,\n undo,\n redo,\n canUndo: state.undoStack.length > 0,\n canRedo: state.redoStack.length > 0,\n history: state.undoStack,\n clear,\n };\n}\n"],"names":[],"mappings":";;;AAuBA;AAIE;;AAEI;;;;;AAKE;AACA;;;;AAIF;AAAkC;AAClC;;;;;;;AASA;AAAkC;AAClC;;;;;;AAQF;;AAEA;AACE;;AAEN;AAEA;AAEA;;;AAGG;AACG;AAGJ;;AAGE;AACA;AACD;AAED;AAEI;AACE;;;AAGD;AACH;AAIF;AACE;AAAkC;AAClC;AAGA;AACA;AACF;AAEA;AACE;AAAkC;AAClC;AAGA;AACA;AACF;AAEA;AACE;;;;;;AAOA;AACA;;;;AAIJ;;"}
@@ -7,7 +7,7 @@ import { useLatest } from '../../../hooks/useLatest/useLatest.js';
7
7
  import { useResizeObserver } from '../../../hooks/useResizeObserver/useResizeObserver.js';
8
8
  import '../../../hooks/useBreakpoint/useBreakpoint.js';
9
9
  import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
10
- import '../../../node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js';
10
+ import '@vanilla-extract/css';
11
11
  import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
12
12
  import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
13
13
  import '../../../hooks/useNavigationHistory/useNavigationHistory.js';
@@ -1 +1 @@
1
- {"version":3,"file":"Timeline.js","sources":["../../../../../../src/components/editor/Timeline/Timeline.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA;AACA;AAWA;;;AAGA;AAEA;AACE;AACE;AACA;AACA;AACA;AACA;;;;AAIE;AACE;;;;AAIJ;AACA;AAKA;AACE;;;AAGF;;;AASO;;;AASA;AACL;;;AAEA;;AAEJ;AACA;AACF;AAEA;;;;;;;;AAQG;AACI;AACL;AA4DA;AACA;AACA;AAEA;;;;AAUA;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;;;AAQD;AAGA;AACA;;;AAGI;AACF;;;;AAUI;;;AAGA;AACD;;;;;;;AAQF;;AAKH;AACA;AACA;AACA;AAIA;;;AAOI;;;;;;;AAOA;AACD;AACH;;;;;;;;;;AAUC;;AAGC;;;AAIA;AACF;;AAIA;AAIA;AAEI;AACF;;;;AAMF;AACA;AAEI;;AAEA;;;AAOJ;;;AAMA;;AAEA;AACA;AACE;AACA;;;;AAIA;AACA;AACA;AACD;;;;;;;;AASC;;AACA;AAOA;;AACF;;;;;;;;AAQC;;;;;AAOD;AACA;AACA;AAEI;AACF;AAGF;AAEI;AACF;AAGF;;;AAIE;AAGF;AAEI;;;;AAQJ;AAEI;AAKF;;AAMF;AACA;AAEI;;AAKA;AACA;;AAKJ;AAEI;AACA;;;;AASJ;AACA;AACA;AACE;AACA;;;;;AAIA;AACA;;AAEE;;;AAEA;;AACA;AAAgB;AAChB;AAAgB;;AAElB;;AACA;AACA;;AAGF;AAEI;AACF;;;;AAOE;AACA;;AAEA;AACA;AACA;AACD;AACH;;;;;;;AAOC;AAED;;AAIA;;AAEE;AAGF;;;;AAMA;;;;;;AAUA;;;AAIA;AAEI;AACF;;AAMF;AACE;;AAEA;;;AAGA;AACA;;;;;;;;;;;;;;;AAeA;AACA;;;;;;;;AAQA;AACA;;;;;AAKD;;;;;;;AAQC;AACA;AACA;AACA;AACA;AACE;AACA;AACF;AACF;;AAIA;;;AAIA;;;AAGE;;;;AAIA;;;;;;;AAOA;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;AACD;;;;;;;;AAcD;AAmCc;AACA;AACE;AACA;AACE;;AAEE;;;AAOV;;AAsBE;;;AAOd;AAEA;;"}
1
+ {"version":3,"file":"Timeline.js","sources":["src/components/editor/Timeline/Timeline.tsx"],"sourcesContent":["'use client';\n\nimport React, {\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\n\nimport { useControlledState, useLatest, useResizeObserver } from '@/hooks';\nimport { cx } from '@/utils/cx';\n\nimport {\n timelineShellStyle,\n timelineBodyStyle,\n timelineCanvasStyle,\n timelineOverlayLayerStyle,\n timelineMainRowStyle,\n timelineToolbarStyle,\n timelineFooterStyle,\n ariaLiveRegionStyle,\n} from './Timeline.css';\nimport { TIMELINE_SLOT } from './Timeline.types';\nimport { TimelineStoreContext } from './TimelineContext';\nimport {\n clamp,\n nextFollowView,\n resolveLoop,\n snapFrame,\n} from './timelineCoords';\nimport { computeRows } from './timelineLayout';\nimport { TimelineStore } from './TimelineStore';\nimport { TimelineTrackHeaders } from './TimelineTrackHeaders';\nimport { useTimelineDraw } from './useTimelineDraw';\nimport { useTimelineGestures } from './useTimelineGestures';\nimport { useTimelinePlayback } from './useTimelinePlayback';\n\nimport type {\n TimelineGroup,\n TimelineLoop,\n TimelineMinimapProps,\n TimelineMode,\n TimelineProps,\n TimelineSelection,\n TimelineSlotKind,\n TimelineSlotMarker,\n TimelineTrack,\n TimelineTrackScaleProps,\n TimelineView,\n} from './Timeline.types';\nimport type { ViewportSize } from '@/components/primitives/viewport';\n\nconst RULER_HEIGHT = 22;\nconst LOOP_STRIP_HEIGHT = 12;\n\ninterface CategorizedSlots {\n toolbar: React.ReactNode;\n footer: React.ReactNode;\n minimap: React.ReactElement | null;\n /** Deprecated: prefer the `trackScale` prop on `<Timeline>`. */\n trackScale: TimelineTrackScaleProps | null;\n overlay: React.ReactNode[];\n}\n\nfunction getSlotKind(el: React.ReactElement): TimelineSlotKind | null {\n const marker = (el.type as Partial<TimelineSlotMarker>)[TIMELINE_SLOT];\n return marker ?? null;\n}\n\nfunction categorizeChildren(children: React.ReactNode): CategorizedSlots {\n const slots: CategorizedSlots = {\n toolbar: null,\n footer: null,\n minimap: null,\n trackScale: null,\n overlay: [],\n };\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) {\n if (child !== null && child !== undefined && child !== false) {\n slots.overlay.push(child);\n }\n return;\n }\n const kind = getSlotKind(child);\n const props = child.props as {\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n };\n if (kind === 'track-scale') {\n slots.trackScale = child.props as TimelineTrackScaleProps;\n return;\n }\n if (kind === 'toolbar') {\n slots.toolbar = (\n <div\n className={cx(timelineToolbarStyle, props.className)}\n style={props.style}\n >\n {props.children}\n </div>\n );\n } else if (kind === 'footer') {\n slots.footer = (\n <div\n className={cx(timelineFooterStyle, props.className)}\n style={props.style}\n >\n {props.children}\n </div>\n );\n } else if (kind === 'minimap') {\n slots.minimap = child;\n } else {\n slots.overlay.push(child);\n }\n });\n return slots;\n}\n\n/**\n * Horizontal multi-track animation timeline / dope sheet. Tracks hold\n * keyframes (the shared `CurveKeyframe` model) along a frame-based time axis;\n * a playhead scrubs across all tracks. Canvas-rendered keyframes with DOM\n * chrome, store-driven via `useSyncExternalStore`.\n *\n * Children read live state via `useTimelineContext()` / `useTimelineGeometry()`\n * / `useTimelinePlayhead()` / `useTimelineSelection()`.\n */\nexport const Timeline = (props: TimelineProps): React.ReactElement => {\n const {\n tracks,\n onTracksChange,\n onTracksChangeComplete,\n startFrame = 0,\n endFrame,\n fps = 30,\n frame,\n defaultFrame,\n onFrameChange,\n onFrameChangeComplete,\n view,\n defaultView,\n onViewChange,\n minFramesVisible = 1,\n maxFramesVisible,\n selection,\n defaultSelection,\n onSelectionChange,\n editable = true,\n allowAddKeyframe = true,\n allowDeleteKeyframe = true,\n snap = true,\n mode,\n defaultMode,\n onModeChange,\n playing,\n defaultPlaying,\n onPlayingChange,\n loop,\n defaultLoop,\n onLoopChange,\n followMode = 'smooth',\n loopStrip = false,\n loopHandles = 'edges',\n groups,\n onGroupsChange,\n trackHeight = 28,\n expandedTrackHeight = 96,\n groupHeaderHeight = 22,\n showRuler = true,\n showPlayhead = true,\n trackHeaderWidth = 160,\n responsive = true,\n height,\n playheadColor,\n backgroundColor,\n trackScale: trackScaleProp,\n renderOverlay,\n renderTrackHeader,\n formatTime,\n ariaLabel = 'Timeline',\n className,\n style,\n testId,\n id,\n children,\n ref,\n } = props;\n\n const bodyRef = useRef<HTMLDivElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const headerColumnRef = useRef<HTMLDivElement>(null);\n\n const [size, setSize] = useState<ViewportSize>({ width: 0, height: 0 });\n const [scrollTop, setScrollTop] = useState(0);\n\n const fullView = useMemo<TimelineView>(\n () => ({ startFrame, endFrame }),\n [startFrame, endFrame]\n );\n\n // ── Controlled / uncontrolled state ──\n\n const [frameState, setFrame] = useControlledState<number>({\n value: frame,\n defaultValue: defaultFrame,\n onChange: onFrameChange,\n fallback: startFrame,\n });\n const [viewState, setView] = useControlledState<TimelineView>({\n value: view,\n defaultValue: defaultView,\n onChange: onViewChange,\n fallback: fullView,\n });\n const [selectionState, setSelection] = useControlledState<TimelineSelection>({\n value: selection,\n defaultValue: defaultSelection,\n onChange: onSelectionChange,\n fallback: [],\n });\n const [modeState] = useControlledState<TimelineMode>({\n value: mode,\n defaultValue: defaultMode,\n onChange: onModeChange,\n fallback: 'dope-sheet',\n });\n const [playingState, setPlaying] = useControlledState<boolean>({\n value: playing,\n defaultValue: defaultPlaying,\n onChange: onPlayingChange,\n fallback: false,\n });\n const [loopState, setLoop] = useControlledState<TimelineLoop>({\n value: loop,\n defaultValue: defaultLoop,\n onChange: onLoopChange,\n fallback: false,\n });\n const loopRegion = useMemo(\n () => resolveLoop(loopState, startFrame, endFrame),\n [loopState, startFrame, endFrame]\n );\n\n // ── Groups (controlled or uncontrolled) ──\n\n const [internalGroups, setInternalGroups] = useState<\n ReadonlyArray<TimelineGroup>\n >(groups ?? []);\n const groupsState = groups ?? internalGroups;\n const setGroups = useCallback(\n (next: TimelineGroup[]): void => {\n if (groups === undefined) setInternalGroups(next);\n onGroupsChange?.(next);\n },\n [groups, onGroupsChange]\n );\n\n // ── Row layout (variable heights: expanded lanes + group headers) ──\n\n const layout = useMemo(\n () =>\n computeRows(tracks, {\n trackHeight,\n expandedHeight: expandedTrackHeight,\n groupHeaderHeight,\n globalGraph: modeState === 'graph',\n groups: groupsState,\n }),\n [\n tracks,\n trackHeight,\n expandedTrackHeight,\n groupHeaderHeight,\n modeState,\n groupsState,\n ]\n );\n\n // ── Store ──\n\n const store = useMemo(() => new TimelineStore(), []);\n const drag = useSyncExternalStore(store.subscribeDrag, store.getDrag);\n const hover = useSyncExternalStore(store.subscribeHover, store.getHover);\n const hoverPlayhead = useSyncExternalStore(\n store.subscribeHoverPlayhead,\n store.getHoverPlayhead\n );\n const hoverLoop = useSyncExternalStore(\n store.subscribeHoverLoop,\n store.getHoverLoop\n );\n\n useLayoutEffect(() => {\n store.setGeometry({\n view: viewState,\n size,\n trackHeight,\n scrollTop,\n startFrame,\n endFrame,\n fps,\n mode: modeState,\n });\n }, [\n store,\n viewState,\n size,\n trackHeight,\n scrollTop,\n startFrame,\n endFrame,\n fps,\n modeState,\n ]);\n\n useLayoutEffect(() => {\n store.setPlayhead({ frame: frameState, playing: playingState });\n }, [store, frameState, playingState]);\n\n useLayoutEffect(() => {\n store.setSelection(selectionState);\n }, [store, selectionState]);\n\n // ── Seek helpers (snap + clamp) ──\n\n const applyFrame = useCallback(\n (f: number): number => clamp(snapFrame(f, snap), startFrame, endFrame),\n [snap, startFrame, endFrame]\n );\n const seekLive = useCallback(\n (f: number): void => {\n setFrame(applyFrame(f));\n },\n [setFrame, applyFrame]\n );\n // Consumer callbacks live behind refs so the handlers that fire them keep a\n // stable identity even when the parent passes a fresh inline function every\n // render (component-patterns.md rules #3 / #11).\n const onFrameCompleteRef = useLatest(onFrameChangeComplete);\n const seekCommit = useCallback(\n (f: number): void => {\n const v = applyFrame(f);\n setFrame(v);\n onFrameCompleteRef.current?.(v);\n },\n [setFrame, applyFrame, onFrameCompleteRef]\n );\n\n // ── Playback (optional built-in rAF loop) ──\n\n const setFrameRaw = useCallback(\n (f: number): void => {\n setFrame(clamp(f, startFrame, endFrame));\n },\n [setFrame, startFrame, endFrame]\n );\n const handlePlaybackEnd = useCallback((): void => {\n setPlaying(false);\n }, [setPlaying]);\n useTimelinePlayback({\n playing: playingState,\n frame: frameState,\n fps,\n startFrame,\n endFrame,\n loop: loopState,\n onAdvance: setFrameRaw,\n onEnd: handlePlaybackEnd,\n });\n\n // ── Follow-playhead during playback ──\n // `smooth` keeps the playhead centred in the view — the view slides\n // continuously once the playhead reaches the centre (one frame per tick,\n // so visually smooth). `paged` waits until the playhead leaves the view\n // and then jumps forward by a full span (After Effects vs Premiere style).\n // `off` leaves the view alone.\n useLayoutEffect(() => {\n if (!playingState) return;\n const next = nextFollowView(\n followMode,\n viewState,\n frameState,\n startFrame,\n endFrame\n );\n if (next) setView(next);\n }, [\n playingState,\n followMode,\n frameState,\n viewState,\n setView,\n startFrame,\n endFrame,\n ]);\n\n // ── Track-edit helpers ──\n\n // Track-change callbacks behind refs (same rationale as `seekCommit`): the\n // gesture hook + header handlers stay stable while the parent may pass fresh\n // inline `onTracksChange` / `onTracksChangeComplete` each render.\n const onTracksChangeRef = useLatest(onTracksChange);\n const onTracksChangeCompleteRef = useLatest(onTracksChangeComplete);\n const setTracksLive = useCallback(\n (t: TimelineTrack[]): void => {\n onTracksChangeRef.current?.(t);\n },\n [onTracksChangeRef]\n );\n const commitTracks = useCallback(\n (t: TimelineTrack[]): void => {\n onTracksChangeCompleteRef.current?.(t);\n },\n [onTracksChangeCompleteRef]\n );\n const handleReorderTracks = useCallback(\n (next: TimelineTrack[]): void => {\n setTracksLive(next);\n commitTracks(next);\n },\n [setTracksLive, commitTracks]\n );\n const handleToggleTrackExpanded = useCallback(\n (trackId: string): void => {\n const next = tracks.map(t =>\n t.id === trackId ? { ...t, expanded: !t.expanded } : t\n );\n setTracksLive(next);\n commitTracks(next);\n },\n [tracks, setTracksLive, commitTracks]\n );\n const handleToggleGroupCollapsed = useCallback(\n (groupId: string): void => {\n setGroups(\n groupsState.map(g =>\n g.id === groupId ? { ...g, collapsed: !g.collapsed } : g\n )\n );\n },\n [groupsState, setGroups]\n );\n\n // ── View helpers + imperative handle ──\n\n const rangeSpan = Math.max(1, endFrame - startFrame);\n const clampView = useCallback(\n (v: TimelineView): TimelineView => {\n const maxSpan = maxFramesVisible ?? rangeSpan;\n const span = Math.min(\n maxSpan,\n Math.max(minFramesVisible, v.endFrame - v.startFrame)\n );\n const center = (v.startFrame + v.endFrame) / 2;\n return { startFrame: center - span / 2, endFrame: center + span / 2 };\n },\n [minFramesVisible, maxFramesVisible, rangeSpan]\n );\n\n const requestZoomToFit = useCallback(\n (paddingFrames?: number): void => {\n const p = paddingFrames ?? 0;\n setView(\n clampView({ startFrame: startFrame - p, endFrame: endFrame + p })\n );\n },\n [setView, clampView, startFrame, endFrame]\n );\n\n // Live reads for the imperative `zoomToSelection`, kept in refs so the\n // callback (wired into the store handle below) has a stable identity.\n const selectionRef = useLatest(selectionState);\n const tracksRef = useLatest(tracks);\n const requestZoomToSelection = useCallback((): void => {\n const sel = selectionRef.current;\n if (sel.length === 0) return;\n // O(|selection|) walk: index tracks once, look up the keyframe per ref.\n const tracksById = new Map(tracksRef.current.map(t => [t.id, t]));\n let min = Infinity;\n let max = -Infinity;\n for (const ref of sel) {\n const track = tracksById.get(ref.trackId);\n if (!track) continue;\n const kf = track.keyframes.find(k => k.id === ref.keyframeId);\n if (!kf) continue;\n if (kf.x < min) min = kf.x;\n if (kf.x > max) max = kf.x;\n }\n if (!Number.isFinite(min) || !Number.isFinite(max)) return;\n const pad = Math.max(1, (max - min) * 0.1);\n setView(clampView({ startFrame: min - pad, endFrame: max + pad }));\n }, [selectionRef, tracksRef, setView, clampView]);\n\n const requestSetView = useCallback(\n (v: TimelineView): void => {\n setView(clampView(v));\n },\n [setView, clampView]\n );\n\n useLayoutEffect(() => {\n store.configureHandle({\n focus: () => bodyRef.current?.focus(),\n getElement: () => bodyRef.current,\n seek: seekCommit,\n setPlaying,\n setView: requestSetView,\n zoomToFit: requestZoomToFit,\n zoomToSelection: requestZoomToSelection,\n });\n }, [\n store,\n seekCommit,\n setPlaying,\n requestSetView,\n requestZoomToFit,\n requestZoomToSelection,\n ]);\n\n useImperativeHandle(ref, () => store.handle, [store]);\n\n // ── Responsive sizing ──\n\n useResizeObserver(bodyRef, entry => {\n const { width, height: h } = entry.contentRect;\n setSize(prev =>\n prev.width === width && prev.height === h ? prev : { width, height: h }\n );\n });\n\n // ── Vertical scroll ──\n\n const rulerHeight = showRuler ? RULER_HEIGHT : 0;\n const loopStripHeight = loopStrip ? LOOP_STRIP_HEIGHT : 0;\n const chromeHeight = rulerHeight + loopStripHeight;\n const maxScrollTop = Math.max(\n 0,\n layout.contentHeight - (size.height - chromeHeight)\n );\n\n // Clamp the scroll offset when the scrollable area shrinks (content removed\n // or viewport grown). Adjusting state during render is React's documented\n // alternative to a layout effect here — it avoids an extra commit, and the\n // guard makes it self-terminating.\n if (scrollTop > maxScrollTop) {\n setScrollTop(maxScrollTop);\n }\n\n const scrollBy = useCallback(\n (deltaPixels: number): void => {\n setScrollTop(s => clamp(s + deltaPixels, 0, maxScrollTop));\n },\n [maxScrollTop]\n );\n\n // ── Gestures ──\n\n const { handlers, onWheel } = useTimelineGestures({\n containerRef: bodyRef,\n store,\n view: viewState,\n size,\n tracks,\n selection: selectionState,\n frame: frameState,\n startFrame,\n endFrame,\n trackHeight,\n scrollTop,\n rulerHeight,\n loopStripHeight,\n loopHandles,\n snap,\n editable,\n allowAddKeyframe,\n allowDeleteKeyframe,\n showPlayhead,\n rows: layout.rows,\n trackTops: layout.trackTops,\n expandedHeight: expandedTrackHeight,\n groups: groupsState,\n minFramesVisible,\n maxFramesVisible,\n loopRegion,\n maxScrollTop,\n seekLive,\n seekCommit,\n setSelection,\n setTracks: setTracksLive,\n commitTracks: commitTracks,\n setView,\n setLoop,\n scrollBy,\n setGroups,\n });\n\n // Native non-passive wheel listener (React onWheel is passive). Attach to\n // both the track body and the left header column so vertical scrolling works\n // when the cursor is over the track names too. `onWheel` is a stable\n // `useCallback` (it reads live state through a ref), so this effect attaches\n // once and never re-subscribes.\n useEffect(() => {\n const body = bodyRef.current;\n const header = headerColumnRef.current;\n body?.addEventListener('wheel', onWheel, { passive: false });\n header?.addEventListener('wheel', onWheel, { passive: false });\n return () => {\n body?.removeEventListener('wheel', onWheel);\n header?.removeEventListener('wheel', onWheel);\n };\n }, [onWheel]);\n\n // ── Slots + draw ──\n\n const slots = useMemo(() => categorizeChildren(children), [children]);\n // Prop wins; the deprecated `<Timeline.TrackScale />` slot still works.\n const trackScale = trackScaleProp ?? slots.trackScale ?? undefined;\n\n useTimelineDraw({\n canvasRef,\n size,\n view: viewState,\n startFrame,\n endFrame,\n fps,\n frame: frameState,\n rows: layout.rows,\n scrollTop,\n rulerHeight,\n loopStripHeight,\n loopHandles,\n showPlayhead,\n selection: selectionState,\n hover,\n hoverPlayhead,\n marquee: drag.marquee,\n loopRegion,\n loopHover: drag.kind === 'none' ? hoverLoop : null,\n ...(backgroundColor !== undefined ? { backgroundColor } : {}),\n ...(playheadColor !== undefined ? { playheadColor } : {}),\n ...(trackScale ? { trackScale } : {}),\n ...(renderOverlay ? { renderOverlay } : {}),\n ...(formatTime ? { formatTime } : {}),\n });\n\n // ── Layout ──\n\n // Announce the playhead on discrete moves (keyboard / click), but stay quiet\n // during continuous scrub drags and playback so AT isn't flooded.\n const liveMessage =\n drag.kind === 'none' && !playingState\n ? `Playhead at frame ${Math.round(frameState)}`\n : '';\n\n const shellHeight =\n height !== undefined ? `${height}px` : responsive ? '100%' : '240px';\n\n return (\n <TimelineStoreContext.Provider value={store}>\n <div\n className={cx(timelineShellStyle, className)}\n data-testid={testId}\n id={id}\n style={{ height: shellHeight, ...style }}\n >\n {slots.toolbar}\n <div className={timelineMainRowStyle}>\n <TimelineTrackHeaders\n ref={headerColumnRef}\n rows={layout.rows}\n contentHeight={layout.contentHeight}\n tracks={tracks}\n rulerHeight={chromeHeight}\n scrollTop={scrollTop}\n width={trackHeaderWidth}\n selection={selectionState}\n editable={editable}\n renderTrackHeader={renderTrackHeader}\n onReorderTracks={handleReorderTracks}\n onToggleGroupCollapsed={handleToggleGroupCollapsed}\n onToggleTrackExpanded={handleToggleTrackExpanded}\n />\n {/* The timeline body is a labelled group that doubles as an\n interactive canvas surface (focusable, with pointer + key\n handlers driving the gesture model). */}\n {/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}\n <div\n ref={bodyRef}\n className={timelineBodyStyle}\n data-dragging={drag.kind !== 'none' || undefined}\n data-hover-target={\n drag.kind !== 'none'\n ? undefined\n : hoverPlayhead\n ? 'playhead'\n : hoverLoop === 'start' || hoverLoop === 'end'\n ? 'loop-edge'\n : hoverLoop === 'body'\n ? 'loop-body'\n : undefined\n }\n role=\"group\"\n aria-label={ariaLabel}\n aria-roledescription=\"Timeline\"\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- focusable interactive canvas surface\n tabIndex={0}\n onPointerDown={handlers.onPointerDown}\n onPointerMove={handlers.onPointerMove}\n onPointerUp={handlers.onPointerUp}\n onPointerCancel={handlers.onPointerCancel}\n onPointerLeave={handlers.onPointerLeave}\n onDoubleClick={handlers.onDoubleClick}\n onKeyDown={handlers.onKeyDown}\n >\n <canvas ref={canvasRef} className={timelineCanvasStyle} />\n <div className={timelineOverlayLayerStyle}>{slots.overlay}</div>\n <div\n className={ariaLiveRegionStyle}\n aria-live=\"polite\"\n role=\"status\"\n >\n {liveMessage}\n </div>\n </div>\n </div>\n {slots.minimap\n ? React.cloneElement(slots.minimap, {\n setView: requestSetView,\n } as Partial<TimelineMinimapProps>)\n : null}\n {slots.footer}\n </div>\n </TimelineStoreContext.Provider>\n );\n};\n\nTimeline.displayName = 'Timeline';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA;AACA;AAWA;;;AAGA;AAEA;AACE;AACE;AACA;AACA;AACA;AACA;;;;AAIE;AACE;;;;AAIJ;AACA;AAKA;AACE;;;AAGF;;;AASO;;;AASA;AACL;;;AAEA;;AAEJ;AACA;AACF;AAEA;;;;;;;;AAQG;AACI;AACL;AA4DA;AACA;AACA;AAEA;;;;AAUA;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;AACD;AACE;AACA;AACA;AACA;AACD;;;AAQD;AAGA;AACA;;;AAGI;AACF;;;;AAUI;;;AAGA;AACD;;;;;;;AAQF;;AAKH;AACA;AACA;AACA;AAIA;;;AAOI;;;;;;;AAOA;AACD;AACH;;;;;;;;;;AAUC;;AAGC;;;AAIA;AACF;;AAIA;AAIA;AAEI;AACF;;;;AAMF;AACA;AAEI;;AAEA;;;AAOJ;;;AAMA;;AAEA;AACA;AACE;AACA;;;;AAIA;AACA;AACA;AACD;;;;;;;;AASC;;AACA;AAOA;;AACF;;;;;;;;AAQC;;;;;AAOD;AACA;AACA;AAEI;AACF;AAGF;AAEI;AACF;AAGF;;;AAIE;AAGF;AAEI;;;;AAQJ;AAEI;AAKF;;AAMF;AACA;AAEI;;AAKA;AACA;;AAKJ;AAEI;AACA;;;;AASJ;AACA;AACA;AACE;AACA;;;;;AAIA;AACA;;AAEE;;;AAEA;;AACA;AAAgB;AAChB;AAAgB;;AAElB;;AACA;AACA;;AAGF;AAEI;AACF;;;;AAOE;AACA;;AAEA;AACA;AACA;AACD;AACH;;;;;;;AAOC;AAED;;AAIA;;AAEE;AAGF;;;;AAMA;;;;;;AAUA;;;AAIA;AAEI;AACF;;AAMF;AACE;;AAEA;;;AAGA;AACA;;;;;;;;;;;;;;;AAeA;AACA;;;;;;;;AAQA;AACA;;;;;AAKD;;;;;;;AAQC;AACA;AACA;AACA;AACA;AACE;AACA;AACF;AACF;;AAIA;;;AAIA;;;AAGE;;;;AAIA;;;;;;;AAOA;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;AACD;;;;;;;;AAcD;AAmCc;AACA;AACE;AACA;AACE;;AAEE;;;AAOV;;AAsBE;;;AAOd;AAEA;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Timeline.types.js","sources":["../../../../../../src/components/editor/Timeline/Timeline.types.ts"],"sourcesContent":[null],"names":[],"mappings":"AAyGA;AAEA;;;;AAIG;AACI,MAAM,aAAa,GAAkB,MAAM,CAAC,GAAG,CAAC,oBAAoB;;;;"}
1
+ {"version":3,"file":"Timeline.types.js","sources":["src/components/editor/Timeline/Timeline.types.ts"],"sourcesContent":["import type { ViewportSize } from '@/components/primitives/viewport';\nimport type { BaseComponent } from '@/types/common';\nimport type { CurveData, CurveKeyframe } from '@/types/keyframe';\nimport type { Prettify } from '@/types/utilities';\nimport type React from 'react';\n\n// ─── Core model ───\n\n/** Dope sheet (keyframe timing) or graph editor (value curves). */\nexport type TimelineMode = 'dope-sheet' | 'graph';\n\n/** Pre/post-infinity behaviour, reused from the shared curve model. */\nexport type TimelineInfinity = {\n pre?: CurveData['preInfinity'];\n post?: CurveData['postInfinity'];\n};\n\n/**\n * One animated property. Keyframes use the shared `CurveKeyframe` model\n * (`x` = frame, `y` = value); graph mode assembles a `CurveData` per track\n * from `{ keyframes, domainX: [startFrame, endFrame], domainY: valueRange }`.\n */\nexport interface TimelineTrack {\n id: string;\n /** Display label in the header column. */\n label?: string;\n /** Keyframe / lane accent color (theme accent fallback). */\n color?: string;\n /** Keyframes — `x` is a frame, `y` is the value at that frame. */\n keyframes: CurveKeyframe[];\n /** Value range (graph-mode domainY). Auto-fit from keyframes when omitted. */\n valueRange?: [number, number];\n /** Pre/post-infinity behaviour for graph mode. */\n infinity?: TimelineInfinity;\n /** Visible but not editable. */\n locked?: boolean;\n /** Collapsed / not drawn. */\n hidden?: boolean;\n /** Expand this track into a graph (curve) lane regardless of the global mode. */\n expanded?: boolean;\n /** Group this track belongs to (matches a `TimelineGroup.id`). */\n groupId?: string;\n /** Row-height override (CSS px). */\n height?: number;\n}\n\n/** A collapsible group of tracks (matched by `TimelineTrack.groupId`). */\nexport interface TimelineGroup {\n id: string;\n label?: string;\n color?: string;\n collapsed?: boolean;\n}\n\n/** A reference to one keyframe on one track. */\nexport interface TimelineKeyframeRef {\n trackId: string;\n keyframeId: string;\n}\n\n/** Current keyframe selection, flat across tracks. */\nexport type TimelineSelection = ReadonlyArray<TimelineKeyframeRef>;\n\n/** The visible frame window (zoom/pan over time). */\nexport interface TimelineView {\n startFrame: number;\n endFrame: number;\n}\n\n/** A loop sub-range, or `true` for the whole timeline range. */\nexport type TimelineLoop = boolean | { startFrame: number; endFrame: number };\n\n// ─── Render info ───\n\n/**\n * Helpers + current state passed to `renderOverlay`. Exposes the same\n * frame ↔ pixel math the built-in drawing uses, so consumer drawing stays\n * aligned with everything else.\n */\nexport interface TimelineDrawInfo {\n /** Track-area size in CSS pixels (canvas already DPR-scaled). */\n size: ViewportSize;\n /** Visible frame window. */\n view: TimelineView;\n /** Global frame range. */\n startFrame: number;\n endFrame: number;\n /** Frames per second. */\n fps: number;\n /** Current playhead frame. */\n frame: number;\n /** Map a frame to a track-area CSS-pixel X. */\n frameToX: (frame: number) => number;\n /** Inverse of `frameToX`. */\n xToFrame: (x: number) => number;\n}\n\n/** State passed to the `renderTrackHeader` render prop. */\nexport interface TimelineTrackHeaderInfo {\n /** Row index of the track. */\n index: number;\n /** Whether any of this track's keyframes are currently selected. */\n hasSelection: boolean;\n}\n\n// ─── Slot markers ───\n\n/**\n * Symbol attached to `Timeline.Toolbar` / `.Footer` so the parent\n * `<Timeline>` can identify slot children without relying on `displayName`\n * (clobbered by `React.memo` / Vanilla Extract recipes).\n */\nexport const TIMELINE_SLOT: unique symbol = Symbol.for('etui.timeline.slot');\n\nexport type TimelineSlotKind = 'toolbar' | 'footer' | 'minimap' | 'track-scale';\n\nexport interface TimelineSlotMarker {\n [TIMELINE_SLOT]: TimelineSlotKind;\n}\n\n// ─── Imperative handle ───\n\n/**\n * Imperative handle exposed via `ref` on `<Timeline>`. Stable for the\n * lifetime of the component.\n */\nexport interface TimelineHandle {\n /** Focus the timeline body so keyboard navigation starts working. */\n focus(): void;\n /** Access the underlying body DOM element. */\n getElement(): HTMLDivElement | null;\n /** Move the playhead to a frame (snapped + clamped). */\n seek(frame: number): void;\n /** Start playback. */\n play(): void;\n /** Pause playback. */\n pause(): void;\n /** Toggle playback. */\n toggle(): void;\n /** Current playhead frame. */\n getFrame(): number;\n /** Fit the view to the whole frame range, with optional padding (frames). */\n zoomToFit(paddingFrames?: number): void;\n /** Fit the view to the current selection. No-op when nothing is selected. */\n zoomToSelection(): void;\n /** Current visible frame window. */\n getView(): TimelineView;\n /** Set the visible frame window (clamped to bounds + minFramesVisible). */\n setView(view: TimelineView): void;\n /** Map a frame to a track-area CSS-pixel X. */\n frameToX(frame: number): number;\n /** Inverse of `frameToX`. */\n xToFrame(x: number): number;\n}\n\n// ─── Props ───\n\nexport interface TimelineBaseProps extends Omit<\n BaseComponent,\n 'onChange' | 'ref'\n> {\n /** Tracks rendered top-to-bottom. */\n tracks: ReadonlyArray<TimelineTrack>;\n /** Fires continuously during keyframe drag. */\n onTracksChange?: (tracks: TimelineTrack[]) => void;\n /** Fires once on commit (drag end, add, delete) — use for undo integration. */\n onTracksChangeComplete?: (tracks: TimelineTrack[]) => void;\n\n /** First frame of the global range. @default 0 */\n startFrame?: number;\n /** Last frame of the global range (the duration). */\n endFrame: number;\n /** Frames per second — drives timecode display + the snap grid. @default 30 */\n fps?: number;\n\n /** Playhead frame (controlled). */\n frame?: number;\n /** Initial playhead frame (uncontrolled). @default startFrame */\n defaultFrame?: number;\n /** Fires continuously while scrubbing. */\n onFrameChange?: (frame: number) => void;\n /** Fires once on scrub end. */\n onFrameChangeComplete?: (frame: number) => void;\n\n /** Visible frame window (controlled). */\n view?: TimelineView;\n /** Initial visible frame window (uncontrolled). @default whole range */\n defaultView?: TimelineView;\n /** Fires when the view zooms/pans. */\n onViewChange?: (view: TimelineView) => void;\n /** Minimum frames visible (max zoom-in). @default 1 */\n minFramesVisible?: number;\n /** Maximum frames visible (max zoom-out). @default range span */\n maxFramesVisible?: number;\n\n /** Keyframe selection (controlled). */\n selection?: TimelineSelection;\n /** Initial selection (uncontrolled). @default [] */\n defaultSelection?: TimelineSelection;\n /** Fires when the selection changes. */\n onSelectionChange?: (selection: TimelineSelection) => void;\n\n /** Master editing switch. @default true */\n editable?: boolean;\n /** Allow double-click to add keyframes. @default true */\n allowAddKeyframe?: boolean;\n /** Allow Delete/Backspace to remove keyframes. @default true */\n allowDeleteKeyframe?: boolean;\n /** Snap-to-frame: `true` = 1 frame, number = N-frame grid, `false` = off. @default true */\n snap?: boolean | number;\n\n /** Editor mode (controlled). */\n mode?: TimelineMode;\n /** Initial mode (uncontrolled). @default 'dope-sheet' */\n defaultMode?: TimelineMode;\n /** Fires when the mode toggles. */\n onModeChange?: (mode: TimelineMode) => void;\n\n /** Playback running (controlled). */\n playing?: boolean;\n /** Initial playback state (uncontrolled). @default false */\n defaultPlaying?: boolean;\n /** Fires when playback starts/stops. */\n onPlayingChange?: (playing: boolean) => void;\n /** Loop the whole range (`true`) or a sub-range (controlled). @default false */\n loop?: TimelineLoop;\n /** Initial loop (uncontrolled). */\n defaultLoop?: TimelineLoop;\n /** Fires when the loop region is dragged on the ruler. */\n onLoopChange?: (loop: TimelineLoop) => void;\n /**\n * How the view tracks the playhead during playback.\n * - `'smooth'` — keep the playhead centred in the view; the view slides\n * continuously once the playhead reaches the centre.\n * - `'paged'` — leave the view still until the playhead leaves it, then\n * jump forward by one full view span.\n * - `'off'` — never auto-scroll; user manages the view.\n * @default 'smooth'\n */\n followMode?: 'smooth' | 'paged' | 'off';\n\n /**\n * Adds a thin dedicated **loop strip** directly under the time ruler. A\n * plain drag on the strip creates / re-draws the loop region (no Alt\n * needed); the strip also makes loop edges easier to grab. The main ruler\n * keeps its scrub behaviour. @default false\n */\n loopStrip?: boolean;\n\n /**\n * Visual style for the loop region's edge markers.\n * - `'edges'` — full-height vertical bars on each loop edge (default).\n * - `'brackets'` — `[ ]` bracket markers in the chrome (ruler / loop\n * strip) with serifs at the top and bottom, no full-height bars. Bigger\n * pick targets, less visual noise across the track area.\n * @default 'edges'\n */\n loopHandles?: 'edges' | 'brackets';\n\n /** Track groups (collapsible). Tracks join a group via `groupId`. */\n groups?: ReadonlyArray<TimelineGroup>;\n /** Fires when a group is collapsed / expanded via its header. */\n onGroupsChange?: (groups: TimelineGroup[]) => void;\n\n /** Default row height in CSS px. @default 28 */\n trackHeight?: number;\n /** Row height for a graph-expanded track in CSS px. @default 96 */\n expandedTrackHeight?: number;\n /** Group header row height in CSS px. @default 22 */\n groupHeaderHeight?: number;\n /** Show the time ruler. @default true */\n showRuler?: boolean;\n /** Show the playhead. @default true */\n showPlayhead?: boolean;\n /** Width of the left track-header column in CSS px. @default 160 */\n trackHeaderWidth?: number;\n /** Fill the parent container (ResizeObserver). @default true */\n responsive?: boolean;\n /** Fixed height in CSS px (ignored when `responsive`). */\n height?: number;\n\n /** Playhead line color. Defaults to theme accent. */\n playheadColor?: string;\n /** Background color. Defaults to theme `--etui-color-bg-secondary`. */\n backgroundColor?: string;\n\n /**\n * Per-track value scale on graph / expanded-track lanes (axis line + min/max\n * labels, optional midpoint + gridlines). Omit to hide the scale entirely.\n */\n trackScale?: TimelineTrackScaleProps;\n\n /** Custom canvas pass, drawn after built-in content, before the playhead. */\n renderOverlay?: (\n ctx: CanvasRenderingContext2D,\n info: TimelineDrawInfo\n ) => void;\n /** Custom track-header renderer. Falls back to a built-in header. */\n renderTrackHeader?: (\n track: TimelineTrack,\n info: TimelineTrackHeaderInfo\n ) => React.ReactNode;\n /** Ruler label formatter. Defaults to `HH:MM:SS:FF` timecode. */\n formatTime?: (frame: number, fps: number) => string;\n\n /** @default 'Timeline' */\n ariaLabel?: string;\n\n /**\n * Slot children: `<Timeline.Toolbar>`, `<Timeline.Footer>`. Unrecognised\n * children render as a free-form overlay layer.\n */\n children?: React.ReactNode;\n\n /** Imperative handle. */\n ref?: React.Ref<TimelineHandle>;\n}\n\nexport type TimelineProps = Prettify<TimelineBaseProps>;\n\n// ─── Subcomponent props ───\n\nexport interface TimelineToolbarProps {\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface TimelineFooterProps {\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface TimelineTrackScaleProps {\n /**\n * Which side of the lane the scale axis is drawn on.\n * @default 'start'\n */\n position?: 'start' | 'end';\n /**\n * Custom value formatter. Receives the raw value and returns the label.\n * @default `(v) => Number(v.toFixed(2)).toString()`\n */\n format?: (value: number) => string;\n /**\n * Draw a tick + label at the midpoint of the range too. @default false\n */\n showMidpoint?: boolean;\n /**\n * Draw thin horizontal gridlines across the whole lane width at each tick\n * (`min` / `max`, plus midpoint when `showMidpoint` is on). @default false\n */\n gridlines?: boolean;\n /**\n * Lanes shorter than this (CSS px) skip the scale, so the labels never\n * overlap into an unreadable blob on a short / collapsed graph lane.\n * @default 48\n */\n minLaneHeight?: number;\n /**\n * Override the axis / label color. Defaults to the muted text colour.\n */\n color?: string;\n}\n\nexport interface TimelineMinimapProps {\n /**\n * Tracks to summarize as keyframe markers in the minimap.\n * Pass the same array you pass to `<Timeline tracks={...} />`.\n */\n tracks: ReadonlyArray<TimelineTrack>;\n /** Strip height in CSS px. @default 40 */\n height?: number;\n /** Override the keyframe marker color. */\n markerColor?: string;\n /** Override the viewport rectangle color. */\n viewportColor?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n// ─── Context value ───\n\n/**\n * Live state available to children of a `<Timeline>` via\n * `useTimelineContext()`. Prefer the per-slice hooks for perf-conscious\n * consumers — each subscribes to a single slice.\n */\nexport interface TimelineContextValue {\n view: TimelineView;\n size: ViewportSize;\n startFrame: number;\n endFrame: number;\n fps: number;\n frame: number;\n playing: boolean;\n mode: TimelineMode;\n selection: TimelineSelection;\n frameToX: (frame: number) => number;\n xToFrame: (x: number) => number;\n}\n"],"names":[],"mappings":"AAyGA;AAEA;;;;AAIG;AACI,MAAM,aAAa,GAAkB,MAAM,CAAC,GAAG,CAAC,oBAAoB;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineContext.js","sources":["../../../../../../src/components/editor/Timeline/TimelineContext.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;AA0BA;AACE;;AAEE;;AAIF;AACF;AAEA;;;;AAIG;;AAED;;AAEF;AAEA;;AAEE;;AAEF;AAEA;;AAEE;;AAEF;AAEA;;AAEE;;AAEF;AAYA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG;AAIJ;;AAKA;;;AAMA;AACF;;"}
1
+ {"version":3,"file":"TimelineContext.js","sources":["src/components/editor/Timeline/TimelineContext.ts"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useSyncExternalStore,\n} from 'react';\n\nimport { selectedTangentMode, setSelectedTangentMode } from './timelineEdits';\n\nimport type {\n TimelineContextValue,\n TimelineSelection,\n TimelineTrack,\n} from './Timeline.types';\nimport type {\n TimelineGeometryState,\n TimelinePlayheadState,\n TimelineStore,\n} from './TimelineStore';\nimport type { TangentMode } from '@/types/keyframe';\n\nexport const TimelineStoreContext = createContext<TimelineStore | null>(null);\n\nfunction useTimelineStoreInternal(): TimelineStore {\n const store = useContext(TimelineStoreContext);\n if (!store) {\n throw new Error(\n 'useTimeline* hooks must be called inside a <Timeline> component'\n );\n }\n return store;\n}\n\n/**\n * Subscribe to **all** Timeline state. Convenient catch-all but re-renders on\n * every store mutation. For perf-sensitive consumers, prefer the slice hooks\n * (`useTimelineGeometry`, `useTimelinePlayhead`, `useTimelineSelection`).\n */\nexport function useTimelineContext(): TimelineContextValue {\n const store = useTimelineStoreInternal();\n return useSyncExternalStore(store.subscribe, store.getSnapshot);\n}\n\n/** Subscribe to the geometry slice (view / sizes / range / mode). */\nexport function useTimelineGeometry(): TimelineGeometryState {\n const store = useTimelineStoreInternal();\n return useSyncExternalStore(store.subscribeGeometry, store.getGeometry);\n}\n\n/** Subscribe to the playhead slice (frame / playing). */\nexport function useTimelinePlayhead(): TimelinePlayheadState {\n const store = useTimelineStoreInternal();\n return useSyncExternalStore(store.subscribePlayhead, store.getPlayhead);\n}\n\n/** Subscribe to the selection slice. */\nexport function useTimelineSelection(): TimelineSelection {\n const store = useTimelineStoreInternal();\n return useSyncExternalStore(store.subscribeSelection, store.getSelection);\n}\n\nexport interface TimelineSelectedTangentMode {\n /**\n * The tangent mode shared by all selected keyframes; `'mixed'` if they\n * disagree; `null` when nothing applicable is selected.\n */\n current: TangentMode | 'mixed' | null;\n /** Apply a tangent mode to every selected keyframe. */\n set: (mode: TangentMode) => void;\n}\n\n/**\n * Convenience hook for building a tangent-mode toggle UI (the six modes:\n * `auto` / `linear` / `step` / `aligned` / `mirrored` / `free`). Reads the\n * current selection from the Timeline store, exposes the unified mode (or\n * `'mixed'`), and applies a chosen mode to every selected keyframe via the\n * caller's `onTracksChange`.\n *\n * @example\n * ```tsx\n * function TangentBar({ tracks, onTracksChange }) {\n * const t = useTimelineSelectedTangentMode(tracks, onTracksChange);\n * if (t.current === null) return null;\n * return (\n * <>\n * <button onClick={() => t.set('auto')} aria-pressed={t.current === 'auto'}>auto</button>\n * <button onClick={() => t.set('aligned')} aria-pressed={t.current === 'aligned'}>aligned</button>\n * …\n * </>\n * );\n * }\n * ```\n */\nexport function useTimelineSelectedTangentMode(\n tracks: ReadonlyArray<TimelineTrack>,\n onTracksChange: (next: TimelineTrack[]) => void\n): TimelineSelectedTangentMode {\n const selection = useTimelineSelection();\n const current = useMemo(\n () => selectedTangentMode(tracks, selection),\n [tracks, selection]\n );\n const set = useCallback(\n (mode: TangentMode): void => {\n onTracksChange(setSelectedTangentMode(tracks, selection, mode));\n },\n [tracks, selection, onTracksChange]\n );\n return { current, set };\n}\n"],"names":[],"mappings":";;;;;AA0BA;AACE;;AAEE;;AAIF;AACF;AAEA;;;;AAIG;;AAED;;AAEF;AAEA;;AAEE;;AAEF;AAEA;;AAEE;;AAEF;AAEA;;AAEE;;AAEF;AAYA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACG;AAIJ;;AAKA;;;AAMA;AACF;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineFooter.js","sources":["../../../../../../src/components/editor/Timeline/TimelineFooter.tsx"],"sourcesContent":[null],"names":[],"mappings":";;AAIA;;;;;AAKG;AACH,MAAM,kBAAkB,GAAyC,MAAM,IAAI;MAE9D,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE;AAC9D,IAAA,WAAW,EAAE,iBAAiB;IAC9B,CAAC,aAAa,GAAG,QAAiB;AACnC,CAAA;;;;"}
1
+ {"version":3,"file":"TimelineFooter.js","sources":["src/components/editor/Timeline/TimelineFooter.tsx"],"sourcesContent":["import { TIMELINE_SLOT } from './Timeline.types';\n\nimport type { TimelineFooterProps } from './Timeline.types';\n\n/**\n * Footer strip rendered below the timeline body (status bar — selected\n * keyframe info, current frame / timecode). Picked out of `<Timeline>`\n * children by the `TIMELINE_SLOT` symbol — its position in the child tree\n * does not affect placement.\n */\nconst TimelineFooterImpl: (props: TimelineFooterProps) => null = () => null;\n\nexport const TimelineFooter = Object.assign(TimelineFooterImpl, {\n displayName: 'Timeline.Footer',\n [TIMELINE_SLOT]: 'footer' as const,\n});\n"],"names":[],"mappings":";;AAIA;;;;;AAKG;AACH,MAAM,kBAAkB,GAAyC,MAAM,IAAI;MAE9D,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE;AAC9D,IAAA,WAAW,EAAE,iBAAiB;IAC9B,CAAC,aAAa,GAAG,QAAiB;AACnC,CAAA;;;;"}
@@ -7,7 +7,7 @@ import { useResizeObserver } from '../../../hooks/useResizeObserver/useResizeObs
7
7
  import '../../../hooks/useBreakpoint/useBreakpoint.js';
8
8
  import { vars } from '../../../theme/contract.css.js';
9
9
  import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
10
- import '../../../node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js';
10
+ import '@vanilla-extract/css';
11
11
  import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
12
12
  import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
13
13
  import '../../../hooks/useNavigationHistory/useNavigationHistory.js';
@@ -1 +1 @@
1
- {"version":3,"file":"TimelineMinimap.js","sources":["../../../../../../src/components/editor/Timeline/TimelineMinimap.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AA4BA;;;;;;AAMG;AACH;AACE;;;AAYA;AACA;AACA;AACA;;AAGA;;AAIA;AAEA;;;;;;;AAYA;AAEA;AACE;AACA;AACE;AACA;;;AAEA;;;;AAIA;AAEA;AACA;AACA;AACE;AACA;;AAEF;AAEA;AACA;AACA;AAEA;;AAIA;;;AAIA;AACA;AACA;;;AAEE;;AAEE;;;AAGJ;;AAGA;;;AAIA;AACA;;AAEA;AACA;AACA;;;;AAKA;;AAEA;AACA;;;;AAMA;AACA;;AAEA;AACA;;;AAIA;;AAEF;AACF;;;;AAIE;;;AAGA;;;;AAID;;AAGC;AACA;AACE;AACF;AACF;;;AAMA;AAMA;AACA;AAEI;;AACA;AAKA;AACF;AAIF;AAEI;;;AAEF;AAIF;AAMA;AAEI;;AACA;AACA;;AACA;;AAEA;;AAEA;;;;;;;;AAQI;AACA;;;;;;;AAOA;AACA;;;;AAIJ;;;;AAKI;AACA;;;;;;AAKA;AACA;;AAEF;;AAEJ;;;;;;;AAQC;AAGH;AAEI;AACA;;AACA;AACA;;AACA;;AAEA;AACA;AACE;AACE;;AAEF;AACE;;;AAGA;AAKA;AACE;AACA;AACD;;;;AAID;AAKA;AACE;AACA;AACD;;;;AAIP;;;;;AAME;AACA;;;AAGD;AAGH;AACE;AACA;;AACA;;AAEE;;AAEF;;;;;;AAMA;;AAIE;AACF;AACA;AACA;AACE;AACF;AACF;;AAOA;AAkBF;;AAGE;;AAED;;"}
1
+ {"version":3,"file":"TimelineMinimap.js","sources":["src/components/editor/Timeline/TimelineMinimap.tsx"],"sourcesContent":["'use client';\n\nimport React, {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { resolveVarValue } from '@/components/primitives/canvas/canvasTheme';\nimport { useResizeObserver } from '@/hooks';\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\n\nimport { timelineMinimapStyle } from './Timeline.css';\nimport { TIMELINE_SLOT } from './Timeline.types';\nimport { useTimelineGeometry, useTimelinePlayhead } from './TimelineContext';\nimport { clamp } from './timelineCoords';\n\nimport type { TimelineMinimapProps, TimelineView } from './Timeline.types';\n\ninterface InternalProps extends TimelineMinimapProps {\n /** Wired by the Timeline parent via the slot mechanism. */\n setView?: (view: TimelineView) => void;\n}\n\n/**\n * Compact overview strip showing the full frame range, the current viewport\n * rectangle (draggable), the playhead, and small dots for every keyframe.\n * Picked out of `<Timeline>` children by the `TIMELINE_SLOT` symbol — its\n * position in the child tree does not affect placement (always rendered below\n * the track area).\n */\nfunction TimelineMinimapImpl(props: InternalProps): React.ReactElement {\n const {\n tracks,\n height = 40,\n markerColor,\n viewportColor,\n className,\n style,\n setView,\n } = props;\n\n // Subscribe only to the slices the minimap actually reads — selection,\n // hover, drag and mode changes do not invalidate this strip.\n const geometry = useTimelineGeometry();\n const playhead = useTimelinePlayhead();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState(0);\n\n useResizeObserver(containerRef, entry => {\n setWidth(w =>\n w === entry.contentRect.width ? w : entry.contentRect.width\n );\n });\n\n const range = Math.max(1, geometry.endFrame - geometry.startFrame);\n const pxToFrame = useCallback(\n (px: number): number =>\n geometry.startFrame + (clamp(px, 0, width) / Math.max(1, width)) * range,\n [geometry.startFrame, range, width]\n );\n\n // ── Render ──\n // Canonical canvas template (component-patterns.md rule #7): the whole draw\n // body lives inside `scheduleDraw`, closing over its reactive inputs and\n // listing them in deps. Theme colors are resolved per-frame (never cached in\n // state). The layout effect just depends on `scheduleDraw`.\n const rafRef = useRef<number>(0);\n\n const scheduleDraw = useCallback((): void => {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = requestAnimationFrame(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const renderCtx = canvas.getContext('2d');\n if (!renderCtx) return;\n\n const w = Math.max(1, width);\n const h = Math.max(1, height);\n const dpr =\n typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;\n const targetW = Math.max(1, Math.round(w * dpr));\n const targetH = Math.max(1, Math.round(h * dpr));\n if (canvas.width !== targetW || canvas.height !== targetH) {\n canvas.width = targetW;\n canvas.height = targetH;\n }\n renderCtx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n const bg = resolveVarValue(canvas, vars.colors.background.inset);\n const border = resolveVarValue(canvas, vars.colors.border.default);\n const marker =\n markerColor ?? resolveVarValue(canvas, vars.colors.accent.secondary);\n const accent =\n viewportColor ?? resolveVarValue(canvas, vars.colors.accent.primary);\n\n renderCtx.clearRect(0, 0, w, h);\n renderCtx.fillStyle = bg;\n renderCtx.fillRect(0, 0, w, h);\n\n // Keyframe markers (small vertical ticks)\n renderCtx.fillStyle = marker;\n renderCtx.globalAlpha = 0.6;\n for (const track of tracks) {\n if (track.hidden) continue;\n for (const kf of track.keyframes) {\n const x = Math.round(((kf.x - geometry.startFrame) / range) * w);\n renderCtx.fillRect(x, h * 0.25, 1, h * 0.5);\n }\n }\n renderCtx.globalAlpha = 1;\n\n // Viewport rectangle\n const vx = ((geometry.view.startFrame - geometry.startFrame) / range) * w;\n const vw =\n ((geometry.view.endFrame - geometry.view.startFrame) / range) * w;\n renderCtx.save();\n renderCtx.fillStyle = accent;\n renderCtx.globalAlpha = 0.16;\n renderCtx.fillRect(vx, 0, vw, h);\n renderCtx.globalAlpha = 1;\n renderCtx.strokeStyle = accent;\n renderCtx.lineWidth = 1;\n renderCtx.strokeRect(vx + 0.5, 0.5, Math.max(0, vw - 1), h - 1);\n\n // Edge \"grippers\" — small filled bars centred vertically on each edge\n // hint that the viewport rectangle is resizable (zoom).\n const gripH = Math.max(6, h * 0.4);\n const gripY = (h - gripH) / 2;\n renderCtx.fillRect(vx - 1, gripY, 2, gripH);\n renderCtx.fillRect(vx + vw - 1, gripY, 2, gripH);\n renderCtx.restore();\n\n // Playhead\n const px =\n Math.round(((playhead.frame - geometry.startFrame) / range) * w) + 0.5;\n renderCtx.strokeStyle = accent;\n renderCtx.lineWidth = 1;\n renderCtx.beginPath();\n renderCtx.moveTo(px, 0);\n renderCtx.lineTo(px, h);\n renderCtx.stroke();\n\n // Top + bottom borders\n renderCtx.fillStyle = border;\n renderCtx.fillRect(0, 0, w, 1);\n });\n }, [\n width,\n height,\n range,\n geometry.startFrame,\n geometry.view.startFrame,\n geometry.view.endFrame,\n playhead.frame,\n tracks,\n markerColor,\n viewportColor,\n ]);\n\n useLayoutEffect(() => {\n scheduleDraw();\n return () => {\n cancelAnimationFrame(rafRef.current);\n };\n }, [scheduleDraw]);\n\n // ── Interactions: drag viewport, resize edges, click outside to center ──\n\n const EDGE_PICK_PX = 6;\n\n const dragRef = useRef<{\n pointerId: number;\n mode: 'move' | 'jump' | 'resize-start' | 'resize-end';\n grabOffset: number;\n } | null>(null);\n\n const span = geometry.view.endFrame - geometry.view.startFrame;\n const setViewSpan = useCallback(\n (start: number): void => {\n if (!setView) return;\n const clamped = clamp(\n start,\n geometry.startFrame,\n geometry.endFrame - span\n );\n setView({ startFrame: clamped, endFrame: clamped + span });\n },\n [setView, geometry.startFrame, geometry.endFrame, span]\n );\n\n const setViewRaw = useCallback(\n (next: TimelineView): void => {\n if (!setView) return;\n setView(next);\n },\n [setView]\n );\n\n const frameToPx = useCallback(\n (frame: number): number =>\n ((frame - geometry.startFrame) / range) * Math.max(1, width),\n [geometry.startFrame, range, width]\n );\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const frame = pxToFrame(x);\n e.preventDefault();\n container.setPointerCapture(e.pointerId);\n const startPx = frameToPx(geometry.view.startFrame);\n const endPx = frameToPx(geometry.view.endFrame);\n // Edge-resize takes priority: lets the user zoom by dragging the\n // viewport rect's left or right edge.\n if (Math.abs(x - startPx) <= EDGE_PICK_PX) {\n dragRef.current = {\n pointerId: e.pointerId,\n mode: 'resize-start',\n grabOffset: 0,\n };\n return;\n }\n if (Math.abs(x - endPx) <= EDGE_PICK_PX) {\n dragRef.current = {\n pointerId: e.pointerId,\n mode: 'resize-end',\n grabOffset: 0,\n };\n return;\n }\n const inside =\n frame >= geometry.view.startFrame && frame <= geometry.view.endFrame;\n if (inside) {\n dragRef.current = {\n pointerId: e.pointerId,\n mode: 'move',\n grabOffset: frame - geometry.view.startFrame,\n };\n } else {\n dragRef.current = {\n pointerId: e.pointerId,\n mode: 'jump',\n grabOffset: 0,\n };\n setViewSpan(frame - span / 2);\n }\n },\n [\n pxToFrame,\n frameToPx,\n geometry.view.startFrame,\n geometry.view.endFrame,\n setViewSpan,\n span,\n ]\n );\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent<HTMLDivElement>): void => {\n const drag = dragRef.current;\n if (drag?.pointerId !== e.pointerId) return;\n const container = containerRef.current;\n if (!container) return;\n const rect = container.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const frame = pxToFrame(x);\n switch (drag.mode) {\n case 'move':\n setViewSpan(frame - drag.grabOffset);\n break;\n case 'jump':\n setViewSpan(frame - span / 2);\n break;\n case 'resize-start': {\n const newStart = clamp(\n frame,\n geometry.startFrame,\n geometry.view.endFrame - 1\n );\n setViewRaw({\n startFrame: newStart,\n endFrame: geometry.view.endFrame,\n });\n break;\n }\n case 'resize-end': {\n const newEnd = clamp(\n frame,\n geometry.view.startFrame + 1,\n geometry.endFrame\n );\n setViewRaw({\n startFrame: geometry.view.startFrame,\n endFrame: newEnd,\n });\n break;\n }\n }\n },\n [\n pxToFrame,\n setViewSpan,\n setViewRaw,\n span,\n geometry.startFrame,\n geometry.endFrame,\n geometry.view.startFrame,\n geometry.view.endFrame,\n ]\n );\n\n const endDrag = useCallback((e: React.PointerEvent<HTMLDivElement>): void => {\n const drag = dragRef.current;\n if (drag?.pointerId !== e.pointerId) return;\n const container = containerRef.current;\n if (container?.hasPointerCapture(e.pointerId)) {\n container.releasePointerCapture(e.pointerId);\n }\n dragRef.current = null;\n }, []);\n\n // Redraw when DPR changes\n useEffect(() => {\n if (typeof window === 'undefined') return;\n const mq = window.matchMedia(\n `(resolution: ${window.devicePixelRatio}dppx)`\n );\n const handler = (): void => {\n scheduleDraw();\n };\n mq.addEventListener('change', handler);\n return () => {\n mq.removeEventListener('change', handler);\n };\n }, [scheduleDraw]);\n\n const wrapperStyle = useMemo<React.CSSProperties>(\n () => ({ height, ...style }),\n [height, style]\n );\n\n return (\n <div\n ref={containerRef}\n className={cx(timelineMinimapStyle, className)}\n style={wrapperStyle}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n role=\"region\"\n aria-label=\"Timeline overview\"\n >\n <canvas\n ref={canvasRef}\n style={{ width: '100%', height: '100%', display: 'block' }}\n />\n </div>\n );\n}\n\nexport const TimelineMinimap = Object.assign(TimelineMinimapImpl, {\n displayName: 'Timeline.Minimap',\n [TIMELINE_SLOT]: 'minimap' as const,\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AA4BA;;;;;;AAMG;AACH;AACE;;;AAYA;AACA;AACA;AACA;;AAGA;;AAIA;AAEA;;;;;;;AAYA;AAEA;AACE;AACA;AACE;AACA;;;AAEA;;;;AAIA;AAEA;AACA;AACA;AACE;AACA;;AAEF;AAEA;AACA;AACA;AAEA;;AAIA;;;AAIA;AACA;AACA;;;AAEE;;AAEE;;;AAGJ;;AAGA;;;AAIA;AACA;;AAEA;AACA;AACA;;;;AAKA;;AAEA;AACA;;;;AAMA;AACA;;AAEA;AACA;;;AAIA;;AAEF;AACF;;;;AAIE;;;AAGA;;;;AAID;;AAGC;AACA;AACE;AACF;AACF;;;AAMA;AAMA;AACA;AAEI;;AACA;AAKA;AACF;AAIF;AAEI;;;AAEF;AAIF;AAMA;AAEI;;AACA;AACA;;AACA;;AAEA;;AAEA;;;;;;;;AAQI;AACA;;;;;;;AAOA;AACA;;;;AAIJ;;;;AAKI;AACA;;;;;;AAKA;AACA;;AAEF;;AAEJ;;;;;;;AAQC;AAGH;AAEI;AACA;;AACA;AACA;;AACA;;AAEA;AACA;AACE;AACE;;AAEF;AACE;;;AAGA;AAKA;AACE;AACA;AACD;;;;AAID;AAKA;AACE;AACA;AACD;;;;AAIP;;;;;AAME;AACA;;;AAGD;AAGH;AACE;AACA;;AACA;;AAEE;;AAEF;;;;;;AAMA;;AAIE;AACF;AACA;AACA;AACE;AACF;AACF;;AAOA;AAkBF;;AAGE;;AAED;;"}