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.
- package/CHANGELOG.md +145 -0
- package/README.md +7 -5
- package/dist/esm/assets/src/components/controls/Select/{Select.css.ts.vanilla-oZnFUorL.css → Select.css.ts.vanilla-Cpu2BvWL.css} +3 -0
- package/dist/esm/assets/src/components/controls/Slider/{Slider.css.ts.vanilla-Cqm3fQ0S.css → Slider.css.ts.vanilla-CLf_RC0A.css} +50 -47
- package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertyPanel.css.ts.vanilla-RYv_XgOu.css → PropertyPanel.css.ts.vanilla-Dpr_k5I3.css} +4 -1
- package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertyRow.css.ts.vanilla-C3YZnnHb.css → PropertyRow.css.ts.vanilla-pq1Uhd2a.css} +15 -8
- package/dist/esm/assets/src/components/editor/PropertyInspector/{PropertySection.css.ts.vanilla-DK12opZc.css → PropertySection.css.ts.vanilla-6MWWAqyd.css} +50 -32
- package/dist/esm/assets/src/components/navigation/Menu/{Menu.css.ts.vanilla-B5iVe5S2.css → Menu.css.ts.vanilla-Bhh1L5yl.css} +14 -11
- package/dist/esm/assets/src/components/primitives/Tooltip/{Tooltip.css.ts.vanilla-CrEFoLBX.css → Tooltip.css.ts.vanilla-BqaiGrFQ.css} +12 -9
- package/dist/esm/assets/src/components/shell/AppShell/{AppShell.css.ts.vanilla-BYmtU0O_.css → AppShell.css.ts.vanilla-BLK2-DRL.css} +1 -0
- package/dist/esm/assets/src/components/shell/MenuBar/{MenuBar.css.ts.vanilla-TgPcl4yA.css → MenuBar.css.ts.vanilla-Dt3w4f-q.css} +18 -6
- package/dist/esm/components/Icons/AddIcon.js.map +1 -1
- package/dist/esm/components/Icons/AiChatIcon.js.map +1 -1
- package/dist/esm/components/Icons/AiSparklesIcon.js.map +1 -1
- package/dist/esm/components/Icons/ArchiveIcon.js.map +1 -1
- package/dist/esm/components/Icons/ArrowDownIcon.js.map +1 -1
- package/dist/esm/components/Icons/ArrowLeftIcon.js.map +1 -1
- package/dist/esm/components/Icons/ArrowRightIcon.js.map +1 -1
- package/dist/esm/components/Icons/ArrowUpIcon.js.map +1 -1
- package/dist/esm/components/Icons/BookmarkIcon.js.map +1 -1
- package/dist/esm/components/Icons/BugIcon.js.map +1 -1
- package/dist/esm/components/Icons/BuildingIcon.js.map +1 -1
- package/dist/esm/components/Icons/CalendarIcon.js.map +1 -1
- package/dist/esm/components/Icons/CameraIcon.js +31 -0
- package/dist/esm/components/Icons/CameraIcon.js.map +1 -0
- package/dist/esm/components/Icons/CheckIcon.js.map +1 -1
- package/dist/esm/components/Icons/ChevronDownIcon.js.map +1 -1
- package/dist/esm/components/Icons/ChevronLeftIcon.js.map +1 -1
- package/dist/esm/components/Icons/ChevronRightIcon.js.map +1 -1
- package/dist/esm/components/Icons/ChevronUpIcon.js.map +1 -1
- package/dist/esm/components/Icons/CircleIcon.js.map +1 -1
- package/dist/esm/components/Icons/ClockIcon.js.map +1 -1
- package/dist/esm/components/Icons/CloseIcon.js.map +1 -1
- package/dist/esm/components/Icons/CloudUploadIcon.js.map +1 -1
- package/dist/esm/components/Icons/CodeIcon.js.map +1 -1
- package/dist/esm/components/Icons/CopyIcon.js.map +1 -1
- package/dist/esm/components/Icons/CubeIcon.js +31 -0
- package/dist/esm/components/Icons/CubeIcon.js.map +1 -0
- package/dist/esm/components/Icons/CutIcon.js.map +1 -1
- package/dist/esm/components/Icons/DotsHorizontalIcon.js.map +1 -1
- package/dist/esm/components/Icons/DotsVerticalIcon.js.map +1 -1
- package/dist/esm/components/Icons/DownloadIcon.js.map +1 -1
- package/dist/esm/components/Icons/EditIcon.js.map +1 -1
- package/dist/esm/components/Icons/ErrorIcon.js.map +1 -1
- package/dist/esm/components/Icons/ExternalLinkIcon.js.map +1 -1
- package/dist/esm/components/Icons/EyeDropperIcon.js.map +1 -1
- package/dist/esm/components/Icons/EyeIcon.js.map +1 -1
- package/dist/esm/components/Icons/FileTextIcon.js.map +1 -1
- package/dist/esm/components/Icons/FilterIcon.js.map +1 -1
- package/dist/esm/components/Icons/FirstIcon.js.map +1 -1
- package/dist/esm/components/Icons/FolderCogIcon.js.map +1 -1
- package/dist/esm/components/Icons/FolderIcon.js.map +1 -1
- package/dist/esm/components/Icons/FolderOpenIcon.js.map +1 -1
- package/dist/esm/components/Icons/FullscreenIcon.js.map +1 -1
- package/dist/esm/components/Icons/GitBranchIcon.js.map +1 -1
- package/dist/esm/components/Icons/GridIcon.js.map +1 -1
- package/dist/esm/components/Icons/HeartIcon.js.map +1 -1
- package/dist/esm/components/Icons/HelpIcon.js.map +1 -1
- package/dist/esm/components/Icons/HomeIcon.js.map +1 -1
- package/dist/esm/components/Icons/ImageIcon.js.map +1 -1
- package/dist/esm/components/Icons/InfoIcon.js.map +1 -1
- package/dist/esm/components/Icons/LastIcon.js.map +1 -1
- package/dist/esm/components/Icons/LinkIcon.js.map +1 -1
- package/dist/esm/components/Icons/ListIcon.js.map +1 -1
- package/dist/esm/components/Icons/LockIcon.js.map +1 -1
- package/dist/esm/components/Icons/MaximizeIcon.js.map +1 -1
- package/dist/esm/components/Icons/MenuIcon.js.map +1 -1
- package/dist/esm/components/Icons/MinimizeIcon.js.map +1 -1
- package/dist/esm/components/Icons/MinusIcon.js.map +1 -1
- package/dist/esm/components/Icons/OrbitIcon.js +31 -0
- package/dist/esm/components/Icons/OrbitIcon.js.map +1 -0
- package/dist/esm/components/Icons/PasteIcon.js.map +1 -1
- package/dist/esm/components/Icons/PauseIcon.js.map +1 -1
- package/dist/esm/components/Icons/PinIcon.js.map +1 -1
- package/dist/esm/components/Icons/PlayIcon.js.map +1 -1
- package/dist/esm/components/Icons/RedoIcon.js.map +1 -1
- package/dist/esm/components/Icons/RefreshIcon.js.map +1 -1
- package/dist/esm/components/Icons/RobotIcon.js.map +1 -1
- package/dist/esm/components/Icons/RotateIcon.js +32 -0
- package/dist/esm/components/Icons/RotateIcon.js.map +1 -0
- package/dist/esm/components/Icons/SaveIcon.js.map +1 -1
- package/dist/esm/components/Icons/SearchIcon.js.map +1 -1
- package/dist/esm/components/Icons/SendIcon.js.map +1 -1
- package/dist/esm/components/Icons/SettingsIcon.js.map +1 -1
- package/dist/esm/components/Icons/SortIcon.js.map +1 -1
- package/dist/esm/components/Icons/SpinIcon.js +32 -0
- package/dist/esm/components/Icons/SpinIcon.js.map +1 -0
- package/dist/esm/components/Icons/StarIcon.js.map +1 -1
- package/dist/esm/components/Icons/StopIcon.js.map +1 -1
- package/dist/esm/components/Icons/SuccessIcon.js.map +1 -1
- package/dist/esm/components/Icons/TagIcon.js.map +1 -1
- package/dist/esm/components/Icons/TangentAlignedIcon.js.map +1 -1
- package/dist/esm/components/Icons/TangentAutoIcon.js.map +1 -1
- package/dist/esm/components/Icons/TangentFreeIcon.js.map +1 -1
- package/dist/esm/components/Icons/TangentLinearIcon.js.map +1 -1
- package/dist/esm/components/Icons/TangentMirroredIcon.js.map +1 -1
- package/dist/esm/components/Icons/TangentStepIcon.js.map +1 -1
- package/dist/esm/components/Icons/TerminalIcon.js.map +1 -1
- package/dist/esm/components/Icons/TrashIcon.js.map +1 -1
- package/dist/esm/components/Icons/UndoIcon.js.map +1 -1
- package/dist/esm/components/Icons/UnlinkIcon.js.map +1 -1
- package/dist/esm/components/Icons/UnlockIcon.js.map +1 -1
- package/dist/esm/components/Icons/UploadIcon.js.map +1 -1
- package/dist/esm/components/Icons/UserIcon.js.map +1 -1
- package/dist/esm/components/Icons/UsersIcon.js.map +1 -1
- package/dist/esm/components/Icons/WarningIcon.js.map +1 -1
- package/dist/esm/components/Icons/ZoomFitIcon.js +32 -0
- package/dist/esm/components/Icons/ZoomFitIcon.js.map +1 -0
- package/dist/esm/components/Icons/ZoomInIcon.js.map +1 -1
- package/dist/esm/components/Icons/ZoomOutIcon.js.map +1 -1
- package/dist/esm/components/controls/CartesianPicker/CartesianPicker.js.map +1 -1
- package/dist/esm/components/controls/CartesianPicker/useCartesianInteraction.js.map +1 -1
- package/dist/esm/components/controls/CartesianPicker/useCartesianRenderer.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/AlphaSlider.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/ColorArea.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/ColorInputs.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/ColorPalette.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/ColorPicker.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/ColorPresets.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/ColorSwatch.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/EyeDropper.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/HueSlider.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/colorUtils.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/palettes/material.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/palettes/professional.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/palettes/tailwind.js.map +1 -1
- package/dist/esm/components/controls/ColorPicker/useColor.js.map +1 -1
- package/dist/esm/components/controls/Combobox/Combobox.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/CurveCanvas.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/CurveEditor.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/CurveToolbar.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/curvePresets.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/curveUtils.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/useCurveInteraction.js.map +1 -1
- package/dist/esm/components/controls/CurveEditor/useCurveRenderer.js.map +1 -1
- package/dist/esm/components/controls/FileTree/FileTree.js +7 -1
- package/dist/esm/components/controls/FileTree/FileTree.js.map +1 -1
- package/dist/esm/components/controls/FileTree/fileTreeIcons.js.map +1 -1
- package/dist/esm/components/controls/FileTree/fileTreeLabels.js.map +1 -1
- package/dist/esm/components/controls/FileTree/useFileTreeDrop.js +1 -1
- package/dist/esm/components/controls/FileTree/useFileTreeDrop.js.map +1 -1
- package/dist/esm/components/controls/FileUploader/FileUploader.js.map +1 -1
- package/dist/esm/components/controls/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/esm/components/controls/NumberInput/NumberInput.js.map +1 -1
- package/dist/esm/components/controls/NumberInput/useNumberInput.js.map +1 -1
- package/dist/esm/components/controls/Select/Select.css.js +1 -1
- package/dist/esm/components/controls/Select/Select.js +15 -7
- package/dist/esm/components/controls/Select/Select.js.map +1 -1
- package/dist/esm/components/controls/Slider/Slider.css.js +10 -11
- package/dist/esm/components/controls/Slider/Slider.css.js.map +1 -1
- package/dist/esm/components/controls/Slider/Slider.js +40 -7
- package/dist/esm/components/controls/Slider/Slider.js.map +1 -1
- package/dist/esm/components/controls/TagInput/TagInput.js.map +1 -1
- package/dist/esm/components/controls/TreeView/TreeNode.js +6 -0
- package/dist/esm/components/controls/TreeView/TreeNode.js.map +1 -1
- package/dist/esm/components/controls/TreeView/TreeView.js.map +1 -1
- package/dist/esm/components/controls/TreeView/useTreeState.js.map +1 -1
- package/dist/esm/components/controls/VectorInput/VectorInput.js +6 -0
- package/dist/esm/components/controls/VectorInput/VectorInput.js.map +1 -1
- package/dist/esm/components/data/DataTable/DataTable.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowser.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserAnnouncementLive.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserBreadcrumbs.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserContent.js +6 -0
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserContent.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserContext.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserContextMenu.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserDefaultMenus.js +6 -0
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserDefaultMenus.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserGrid.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserGrid.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserGridItem.js +6 -0
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserGridItem.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserList.js +6 -0
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserList.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserRenameField.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserSidebar.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserStatusBar.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserStore.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserSurface.js +6 -0
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserSurface.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserToolbar.js +6 -0
- package/dist/esm/components/editor/AssetBrowser/AssetBrowserToolbar.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/assetBrowserFilter.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/assetBrowserFormat.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/assetBrowserGeometry.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/assetBrowserKeyboard.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/assetBrowserLabels.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/slots.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetBrowserAnnouncement.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetBrowserHandle.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetBrowserHandle.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetBrowserViewState.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetBrowserViewState.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetDnd.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetDnd.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetGridKeyboardNav.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetGridVirtualizer.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetGridVirtualizer.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetMarqueeGesture.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetMarqueeGesture.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetMutationKeyboard.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetMutationKeyboard.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetMutations.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetMutations.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetNavigation.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetNavigation.js.map +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetSelectionController.js +1 -1
- package/dist/esm/components/editor/AssetBrowser/useAssetSelectionController.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatActionBar.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatAttachment.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatBubble.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatCodeBlock.js +6 -0
- package/dist/esm/components/editor/ChatPanel/ChatCodeBlock.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatContextChip.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatEmptyState.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatIcons.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatInput.js +6 -0
- package/dist/esm/components/editor/ChatPanel/ChatInput.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatInputToolbar.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatMarkdownRenderer.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatMessage.js +6 -0
- package/dist/esm/components/editor/ChatPanel/ChatMessage.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatMessageList.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatPanel.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatToolCall.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/ChatTypingIndicator.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/useChatInput.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/useChatMessages.js.map +1 -1
- package/dist/esm/components/editor/ChatPanel/useChatScroll.js.map +1 -1
- package/dist/esm/components/editor/Minimap/Minimap.js +1 -1
- package/dist/esm/components/editor/Minimap/Minimap.js.map +1 -1
- package/dist/esm/components/editor/Minimap/Minimap.types.js.map +1 -1
- package/dist/esm/components/editor/Minimap/MinimapContext.js.map +1 -1
- package/dist/esm/components/editor/Minimap/MinimapCorner.js.map +1 -1
- package/dist/esm/components/editor/Minimap/MinimapFooter.js.map +1 -1
- package/dist/esm/components/editor/Minimap/MinimapStore.js.map +1 -1
- package/dist/esm/components/editor/Minimap/MinimapTitle.js.map +1 -1
- package/dist/esm/components/editor/Minimap/ViewportMinimap.js +1 -1
- package/dist/esm/components/editor/Minimap/ViewportMinimap.js.map +1 -1
- package/dist/esm/components/editor/Minimap/computeBoundsFromItems.js.map +1 -1
- package/dist/esm/components/editor/Minimap/index.js.map +1 -1
- package/dist/esm/components/editor/Minimap/minimapCoords.js.map +1 -1
- package/dist/esm/components/editor/Minimap/minimapDrawing.js.map +1 -1
- package/dist/esm/components/editor/Minimap/minimapHitTest.js.map +1 -1
- package/dist/esm/components/editor/Minimap/useMinimapGestures.js +1 -1
- package/dist/esm/components/editor/Minimap/useMinimapGestures.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraph.js +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraph.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraph.types.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphContext.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphEdgeLabels.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphGroup.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphMinimap.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNode.js +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNode.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNodeContext.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNodeParts.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSection.js +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSection.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphNodeSectionContext.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphPin.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphPort.js +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphPort.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphPortVisual.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphSlots.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphSpawnPalette.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphStore.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/NodeGraphToolbar.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/createTypeMatchValidator.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/nodeGraphActions.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/nodeGraphDrawing.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/nodeGraphIds.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/nodeGraphMath.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/sortSlots.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useDragGesture.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraph.js +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraph.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphConnection.js +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphConnection.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphEdgeInteraction.js +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphEdgeInteraction.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphGroupDrag.js +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphGroupDrag.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphKeyboard.js +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphKeyboard.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphNodeDrag.js +1 -1
- package/dist/esm/components/editor/NodeGraph/useNodeGraphNodeDrag.js.map +1 -1
- package/dist/esm/components/editor/NodeGraph/useStoreSlice.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertyGroup.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertyPanel.css.js +4 -3
- package/dist/esm/components/editor/PropertyInspector/PropertyPanel.css.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertyPanel.js +5 -4
- package/dist/esm/components/editor/PropertyInspector/PropertyPanel.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertyRow.css.js +7 -6
- package/dist/esm/components/editor/PropertyInspector/PropertyRow.css.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertyRow.js +18 -3
- package/dist/esm/components/editor/PropertyInspector/PropertyRow.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertySection.css.js +11 -10
- package/dist/esm/components/editor/PropertyInspector/PropertySection.css.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/PropertySection.js +29 -21
- package/dist/esm/components/editor/PropertyInspector/PropertySection.js.map +1 -1
- package/dist/esm/components/editor/PropertyInspector/usePropertyUndo.js.map +1 -1
- package/dist/esm/components/editor/Timeline/Timeline.js +1 -1
- package/dist/esm/components/editor/Timeline/Timeline.js.map +1 -1
- package/dist/esm/components/editor/Timeline/Timeline.types.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineContext.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineFooter.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineMinimap.js +1 -1
- package/dist/esm/components/editor/Timeline/TimelineMinimap.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineStore.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineToolbar.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineTrackHeaders.js +1 -1
- package/dist/esm/components/editor/Timeline/TimelineTrackHeaders.js.map +1 -1
- package/dist/esm/components/editor/Timeline/TimelineTrackScale.js.map +1 -1
- package/dist/esm/components/editor/Timeline/index.js.map +1 -1
- package/dist/esm/components/editor/Timeline/timelineCoords.js.map +1 -1
- package/dist/esm/components/editor/Timeline/timelineDrawing.js.map +1 -1
- package/dist/esm/components/editor/Timeline/timelineEdits.js.map +1 -1
- package/dist/esm/components/editor/Timeline/timelineHitTest.js.map +1 -1
- package/dist/esm/components/editor/Timeline/timelineLayout.js.map +1 -1
- package/dist/esm/components/editor/Timeline/timelineSelection.js.map +1 -1
- package/dist/esm/components/editor/Timeline/useTimelineDraw.js +1 -1
- package/dist/esm/components/editor/Timeline/useTimelineDraw.js.map +1 -1
- package/dist/esm/components/editor/Timeline/useTimelineGestures.js +1 -1
- package/dist/esm/components/editor/Timeline/useTimelineGestures.js.map +1 -1
- package/dist/esm/components/editor/Timeline/useTimelinePlayback.js.map +1 -1
- package/dist/esm/components/editor/TransformControl/TransformControl.js.map +1 -1
- package/dist/esm/components/editor/ViewportGizmo/ViewportGizmo.js.map +1 -1
- package/dist/esm/components/editor/ViewportGizmo/gizmoMath.js.map +1 -1
- package/dist/esm/components/editor/ViewportGizmo/useGizmoInteraction.js.map +1 -1
- package/dist/esm/components/editor/ViewportGizmo/useGizmoRenderer.js.map +1 -1
- package/dist/esm/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/esm/components/feedback/Alert/AlertActions.js.map +1 -1
- package/dist/esm/components/feedback/Alert/AlertDescription.js.map +1 -1
- package/dist/esm/components/feedback/Alert/AlertTitle.js.map +1 -1
- package/dist/esm/components/feedback/CommandPalette/CommandPalette.js.map +1 -1
- package/dist/esm/components/feedback/CommandPalette/fuzzySearch.js.map +1 -1
- package/dist/esm/components/feedback/CommandPalette/useRecentItems.js.map +1 -1
- package/dist/esm/components/feedback/Dialog/Dialog.js.map +1 -1
- package/dist/esm/components/feedback/Dialog/DialogBody.js.map +1 -1
- package/dist/esm/components/feedback/Dialog/DialogClose.js.map +1 -1
- package/dist/esm/components/feedback/Dialog/DialogFooter.js.map +1 -1
- package/dist/esm/components/feedback/Dialog/DialogHeader.js.map +1 -1
- package/dist/esm/components/feedback/Dialog/useDialogAnimation.js.map +1 -1
- package/dist/esm/components/feedback/Drawer/Drawer.js.map +1 -1
- package/dist/esm/components/feedback/Drawer/useDrawerAnimation.js.map +1 -1
- package/dist/esm/components/feedback/EmptyState/EmptyState.js.map +1 -1
- package/dist/esm/components/feedback/LogView/LogView.js.map +1 -1
- package/dist/esm/components/feedback/LogView/LogViewBody.js.map +1 -1
- package/dist/esm/components/feedback/LogView/LogViewContext.js.map +1 -1
- package/dist/esm/components/feedback/LogView/LogViewParts.js.map +1 -1
- package/dist/esm/components/feedback/LogView/LogViewStore.js.map +1 -1
- package/dist/esm/components/feedback/LogView/logViewLabels.js.map +1 -1
- package/dist/esm/components/feedback/LogView/logViewLevels.js.map +1 -1
- package/dist/esm/components/feedback/LogView/logViewUtils.js.map +1 -1
- package/dist/esm/components/feedback/LogView/useFollowTail.js.map +1 -1
- package/dist/esm/components/feedback/LogView/useLogSelection.js.map +1 -1
- package/dist/esm/components/feedback/ProgressBar/CircularProgress.js.map +1 -1
- package/dist/esm/components/feedback/ProgressBar/ProgressBar.js.map +1 -1
- package/dist/esm/components/feedback/Skeleton/Skeleton.js.map +1 -1
- package/dist/esm/components/feedback/Skeleton/SkeletonGroup.js.map +1 -1
- package/dist/esm/components/feedback/Skeleton/SkeletonLayout.js.map +1 -1
- package/dist/esm/components/feedback/Spinner/Spinner.js +12 -3
- package/dist/esm/components/feedback/Spinner/Spinner.js.map +1 -1
- package/dist/esm/components/feedback/Stat/Stat.js.map +1 -1
- package/dist/esm/components/feedback/Toast/ToastContainer.js.map +1 -1
- package/dist/esm/components/feedback/Toast/ToastItem.js.map +1 -1
- package/dist/esm/components/feedback/Toast/ToastProvider.js.map +1 -1
- package/dist/esm/components/feedback/Toast/useToast.js.map +1 -1
- package/dist/esm/components/form/FormHelperText.js.map +1 -1
- package/dist/esm/components/form/FormLabel.js.map +1 -1
- package/dist/esm/components/form/InputWrapper.js.map +1 -1
- package/dist/esm/components/layout/Accordion/Accordion.js.map +1 -1
- package/dist/esm/components/layout/Accordion/AccordionContent.js.map +1 -1
- package/dist/esm/components/layout/Accordion/AccordionItem.js.map +1 -1
- package/dist/esm/components/layout/Accordion/AccordionTrigger.js.map +1 -1
- package/dist/esm/components/layout/Card/Card.js.map +1 -1
- package/dist/esm/components/layout/Divider/Divider.js.map +1 -1
- package/dist/esm/components/layout/Flex/Flex.js.map +1 -1
- package/dist/esm/components/layout/Grid/Grid.js.map +1 -1
- package/dist/esm/components/layout/ListItem/ListItem.js.map +1 -1
- package/dist/esm/components/layout/PageHeader/PageHeader.js.map +1 -1
- package/dist/esm/components/layout/PanelSurface/PanelSurface.js.map +1 -1
- package/dist/esm/components/layout/ScrollArea/ScrollArea.js.map +1 -1
- package/dist/esm/components/layout/Spacer/Spacer.js.map +1 -1
- package/dist/esm/components/layout/SplitPane/SplitPane.js.map +1 -1
- package/dist/esm/components/layout/SplitPane/SplitPanePanel.js.map +1 -1
- package/dist/esm/components/layout/Stack/Stack.js.map +1 -1
- package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbEllipsis.js.map +1 -1
- package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbItem.js.map +1 -1
- package/dist/esm/components/navigation/Breadcrumbs/BreadcrumbSeparator.js.map +1 -1
- package/dist/esm/components/navigation/Breadcrumbs/Breadcrumbs.js +6 -0
- package/dist/esm/components/navigation/Breadcrumbs/Breadcrumbs.js.map +1 -1
- package/dist/esm/components/navigation/ContextMenu/ContextMenu.js +2 -2
- package/dist/esm/components/navigation/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/esm/components/navigation/Menu/Menu.css.js +11 -10
- package/dist/esm/components/navigation/Menu/Menu.css.js.map +1 -1
- package/dist/esm/components/navigation/Menu/Menu.js +2 -2
- package/dist/esm/components/navigation/Menu/Menu.js.map +1 -1
- package/dist/esm/components/navigation/Menu/MenuGapContext.js.map +1 -1
- package/dist/esm/components/navigation/Pagination/Pagination.js.map +1 -1
- package/dist/esm/components/navigation/Pagination/usePagination.js.map +1 -1
- package/dist/esm/components/navigation/PathBar/PathBar.js +7 -1
- package/dist/esm/components/navigation/PathBar/PathBar.js.map +1 -1
- package/dist/esm/components/navigation/PathBar/PathBarSiblingMenu.js +6 -0
- package/dist/esm/components/navigation/PathBar/PathBarSiblingMenu.js.map +1 -1
- package/dist/esm/components/navigation/PathBar/pathUtils.js.map +1 -1
- package/dist/esm/components/navigation/SegmentedControl/SegmentedControl.js.map +1 -1
- package/dist/esm/components/navigation/SegmentedControl/SegmentedControlItem.js.map +1 -1
- package/dist/esm/components/navigation/Tabs/Tab.js.map +1 -1
- package/dist/esm/components/navigation/Tabs/TabList.js.map +1 -1
- package/dist/esm/components/navigation/Tabs/TabPanel.js.map +1 -1
- package/dist/esm/components/navigation/Tabs/Tabs.js.map +1 -1
- package/dist/esm/components/primitives/Avatar/Avatar.js +6 -0
- package/dist/esm/components/primitives/Avatar/Avatar.js.map +1 -1
- package/dist/esm/components/primitives/Avatar/AvatarGroup.js.map +1 -1
- package/dist/esm/components/primitives/Badge/Badge.js +6 -0
- package/dist/esm/components/primitives/Badge/Badge.js.map +1 -1
- package/dist/esm/components/primitives/Button/Button.js.map +1 -1
- package/dist/esm/components/primitives/Checkbox/Checkbox.js.map +1 -1
- package/dist/esm/components/primitives/Checkbox/CheckboxGroup.js.map +1 -1
- package/dist/esm/components/primitives/Code/Code.js.map +1 -1
- package/dist/esm/components/primitives/Collapsible/Collapsible.js.map +1 -1
- package/dist/esm/components/primitives/HoverCard/HoverCard.js.map +1 -1
- package/dist/esm/components/primitives/Icon/Icon.js.map +1 -1
- package/dist/esm/components/primitives/IconButton/IconButton.js +4 -2
- package/dist/esm/components/primitives/IconButton/IconButton.js.map +1 -1
- package/dist/esm/components/primitives/Input/Input.js.map +1 -1
- package/dist/esm/components/primitives/Kbd/Kbd.js.map +1 -1
- package/dist/esm/components/primitives/Link/Link.js.map +1 -1
- package/dist/esm/components/primitives/Paper/Paper.js.map +1 -1
- package/dist/esm/components/primitives/Popover/Popover.js.map +1 -1
- package/dist/esm/components/primitives/Popover/PopoverClose.js.map +1 -1
- package/dist/esm/components/primitives/Popover/PopoverContent.js.map +1 -1
- package/dist/esm/components/primitives/Popover/PopoverTrigger.js.map +1 -1
- package/dist/esm/components/primitives/Radio/Radio.js.map +1 -1
- package/dist/esm/components/primitives/Radio/RadioGroup.js.map +1 -1
- package/dist/esm/components/primitives/Switch/Switch.js.map +1 -1
- package/dist/esm/components/primitives/Text/Text.js.map +1 -1
- package/dist/esm/components/primitives/TextArea/TextArea.js.map +1 -1
- package/dist/esm/components/primitives/Tooltip/Arrow.js.map +1 -1
- package/dist/esm/components/primitives/Tooltip/Tooltip.css.js +6 -5
- package/dist/esm/components/primitives/Tooltip/Tooltip.css.js.map +1 -1
- package/dist/esm/components/primitives/Tooltip/Tooltip.js +12 -2
- package/dist/esm/components/primitives/Tooltip/Tooltip.js.map +1 -1
- package/dist/esm/components/primitives/Tooltip/utils.js.map +1 -1
- package/dist/esm/components/primitives/VisuallyHidden/VisuallyHidden.js.map +1 -1
- package/dist/esm/components/primitives/canvas/CanvasContainer.js.map +1 -1
- package/dist/esm/components/primitives/canvas/canvasCoords.js.map +1 -1
- package/dist/esm/components/primitives/canvas/canvasDrawing.js.map +1 -1
- package/dist/esm/components/primitives/canvas/canvasTheme.js.map +1 -1
- package/dist/esm/components/primitives/canvas/useCanvasRenderer.js.map +1 -1
- package/dist/esm/components/primitives/viewport/Viewport.js +6 -3
- package/dist/esm/components/primitives/viewport/Viewport.js.map +1 -1
- package/dist/esm/components/primitives/viewport/ViewportContext.js.map +1 -1
- package/dist/esm/components/primitives/viewport/ViewportLayer.js +1 -1
- package/dist/esm/components/primitives/viewport/ViewportLayer.js.map +1 -1
- package/dist/esm/components/primitives/viewport/ViewportOverlay.js.map +1 -1
- package/dist/esm/components/primitives/viewport/ViewportStore.js.map +1 -1
- package/dist/esm/components/primitives/viewport/ViewportWorld.js.map +1 -1
- package/dist/esm/components/primitives/viewport/useViewportGestures.js +1 -1
- package/dist/esm/components/primitives/viewport/useViewportGestures.js.map +1 -1
- package/dist/esm/components/primitives/viewport/viewportCoords.js.map +1 -1
- package/dist/esm/components/primitives/viewport/viewportMath.js.map +1 -1
- package/dist/esm/components/shell/AppShell/AppShell.css.js +1 -1
- package/dist/esm/components/shell/AppShell/AppShell.js.map +1 -1
- package/dist/esm/components/shell/FloatingPanel/FloatingPanel.js.map +1 -1
- package/dist/esm/components/shell/MenuBar/MenuBar.css.js +7 -6
- package/dist/esm/components/shell/MenuBar/MenuBar.css.js.map +1 -1
- package/dist/esm/components/shell/MenuBar/MenuBar.js +52 -3
- package/dist/esm/components/shell/MenuBar/MenuBar.js.map +1 -1
- package/dist/esm/components/shell/StatusBar/StatusBar.js.map +1 -1
- package/dist/esm/components/shell/Toolbar/Toolbar.js.map +1 -1
- package/dist/esm/context/KeyboardContext.js.map +1 -1
- package/dist/esm/hooks/useBreakpoint/useBreakpoint.js.map +1 -1
- package/dist/esm/hooks/useClickOutside/useClickOutside.js.map +1 -1
- package/dist/esm/hooks/useClipboard/useClipboard.js.map +1 -1
- package/dist/esm/hooks/useControlledState/useControlledState.js.map +1 -1
- package/dist/esm/hooks/useDebounced/useDebouncedCallback.js.map +1 -1
- package/dist/esm/hooks/useDebounced/useDebouncedValue.js.map +1 -1
- package/dist/esm/hooks/useDisclosure/useDisclosure.js.map +1 -1
- package/dist/esm/hooks/useEventCallback/useEventCallback.js.map +1 -1
- package/dist/esm/hooks/useFocusTrap/useFocusTrap.js.map +1 -1
- package/dist/esm/hooks/useHotkey/useHotkey.js.map +1 -1
- package/dist/esm/hooks/useIntersectionObserver/useIntersectionObserver.js.map +1 -1
- package/dist/esm/hooks/useIsMounted/useIsMounted.js.map +1 -1
- package/dist/esm/hooks/useKeyboard/useKeyboard.js.map +1 -1
- package/dist/esm/hooks/useKeyboard/utils.js.map +1 -1
- package/dist/esm/hooks/useLatest/useLatest.js.map +1 -1
- package/dist/esm/hooks/useListboxNav/useListboxNav.js.map +1 -1
- package/dist/esm/hooks/useMediaQuery/useMediaQuery.js.map +1 -1
- package/dist/esm/hooks/useMergedRef/useMergedRef.js.map +1 -1
- package/dist/esm/hooks/useNavigationHistory/useNavigationHistory.js.map +1 -1
- package/dist/esm/hooks/useResizeObserver/useResizeObserver.js.map +1 -1
- package/dist/esm/hooks/useTheme/useTheme.js +1 -1
- package/dist/esm/hooks/useTheme/useTheme.js.map +1 -1
- package/dist/esm/hooks/useThrottledCallback/useThrottledCallback.js.map +1 -1
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/node_modules/tslib/tslib.es6.js.map +1 -1
- package/dist/esm/styles.css.js +3 -0
- package/dist/esm/styles.css.js.map +1 -0
- package/dist/esm/theme/ThemeProvider.js +5 -3
- package/dist/esm/theme/ThemeProvider.js.map +1 -1
- package/dist/esm/theme/VanillaThemeProvider.js.map +1 -1
- package/dist/esm/theme/breakpoints.js.map +1 -1
- package/dist/esm/theme/createCustomTheme.js +1 -1
- package/dist/esm/theme/createCustomTheme.js.map +1 -1
- package/dist/esm/theme/createLightTheme.js.map +1 -1
- package/dist/esm/theme/darkThemeValues.js.map +1 -1
- package/dist/esm/theme/lightThemeValues.js.map +1 -1
- package/dist/esm/theme/themeContractData.js.map +1 -1
- package/dist/esm/utils/cx.js.map +1 -1
- package/dist/esm/utils/devWarn.js.map +1 -1
- package/dist/esm/utils/mathExpression.js.map +1 -1
- package/dist/esm/utils/mathUtils.js.map +1 -1
- package/dist/esm/utils/objects.js.map +1 -1
- package/dist/esm/utils/platform.js.map +1 -1
- package/dist/tokens/tokens.dark.css +1 -1
- package/dist/tokens/tokens.json +1 -1
- package/dist/tokens/tokens.light.css +1 -1
- package/dist/types/components/Icons/CameraIcon.d.ts +34 -0
- package/dist/types/components/Icons/CubeIcon.d.ts +34 -0
- package/dist/types/components/Icons/OrbitIcon.d.ts +34 -0
- package/dist/types/components/Icons/RotateIcon.d.ts +35 -0
- package/dist/types/components/Icons/SpinIcon.d.ts +35 -0
- package/dist/types/components/Icons/ZoomFitIcon.d.ts +35 -0
- package/dist/types/components/controls/Select/Select.d.ts +1 -1
- package/dist/types/components/controls/Select/Select.types.d.ts +43 -9
- package/dist/types/components/controls/Slider/Slider.d.ts +7 -0
- package/dist/types/components/editor/PropertyInspector/PropertyInspector.types.d.ts +49 -3
- package/dist/types/components/feedback/Spinner/Spinner.d.ts +6 -1
- package/dist/types/components/feedback/Spinner/Spinner.types.d.ts +8 -0
- package/dist/types/components/primitives/Button/Button.d.ts +1 -1
- package/dist/types/components/primitives/IconButton/IconButton.d.ts +3 -2
- package/dist/types/components/primitives/viewport/Viewport.d.ts +5 -2
- package/dist/types/components/shell/MenuBar/MenuBar.d.ts +862 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/theme/ThemeProvider.d.ts +5 -3
- package/package.json +6 -2
- package/dist/esm/_virtual/_commonjsHelpers.js +0 -6
- package/dist/esm/_virtual/_commonjsHelpers.js.map +0 -1
- package/dist/esm/_virtual/cjs.js +0 -4
- package/dist/esm/_virtual/cjs.js.map +0 -1
- package/dist/esm/_virtual/cssesc.js +0 -8
- package/dist/esm/_virtual/cssesc.js.map +0 -1
- package/dist/esm/_virtual/picocolors.js +0 -8
- package/dist/esm/_virtual/picocolors.js.map +0 -1
- package/dist/esm/_virtual/picocolors2.js +0 -4
- package/dist/esm/_virtual/picocolors2.js.map +0 -1
- package/dist/esm/node_modules/@emotion/hash/dist/emotion-hash.esm.js +0 -56
- package/dist/esm/node_modules/@emotion/hash/dist/emotion-hash.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/adapter/dist/vanilla-extract-css-adapter.esm.js +0 -46
- package/dist/esm/node_modules/@vanilla-extract/css/adapter/dist/vanilla-extract-css-adapter.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/dist/taggedTemplateLiteral-10998315.esm.js +0 -13
- package/dist/esm/node_modules/@vanilla-extract/css/dist/taggedTemplateLiteral-10998315.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/dist/transformCss-fd0786e1.esm.js +0 -962
- package/dist/esm/node_modules/@vanilla-extract/css/dist/transformCss-fd0786e1.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js +0 -309
- package/dist/esm/node_modules/@vanilla-extract/css/dist/vanilla-extract-css.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.esm.js +0 -18
- package/dist/esm/node_modules/@vanilla-extract/css/fileScope/dist/vanilla-extract-css-fileScope.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/injectStyles/dist/vanilla-extract-css-injectStyles.esm.js +0 -23
- package/dist/esm/node_modules/@vanilla-extract/css/injectStyles/dist/vanilla-extract-css-injectStyles.esm.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/css/node_modules/lru-cache/dist/esm/index.js +0 -1543
- package/dist/esm/node_modules/@vanilla-extract/css/node_modules/lru-cache/dist/esm/index.js.map +0 -1
- package/dist/esm/node_modules/@vanilla-extract/private/dist/vanilla-extract-private.esm.js +0 -38
- package/dist/esm/node_modules/@vanilla-extract/private/dist/vanilla-extract-private.esm.js.map +0 -1
- package/dist/esm/node_modules/css-what/lib/es/parse.js +0 -424
- package/dist/esm/node_modules/css-what/lib/es/parse.js.map +0 -1
- package/dist/esm/node_modules/css-what/lib/es/types.js +0 -29
- package/dist/esm/node_modules/css-what/lib/es/types.js.map +0 -1
- package/dist/esm/node_modules/cssesc/cssesc.js +0 -120
- package/dist/esm/node_modules/cssesc/cssesc.js.map +0 -1
- package/dist/esm/node_modules/dedent/dist/dedent.js +0 -100
- package/dist/esm/node_modules/dedent/dist/dedent.js.map +0 -1
- package/dist/esm/node_modules/deep-object-diff/mjs/diff.js +0 -40
- package/dist/esm/node_modules/deep-object-diff/mjs/diff.js.map +0 -1
- package/dist/esm/node_modules/deep-object-diff/mjs/utils.js +0 -9
- package/dist/esm/node_modules/deep-object-diff/mjs/utils.js.map +0 -1
- package/dist/esm/node_modules/deepmerge/dist/cjs.js +0 -143
- package/dist/esm/node_modules/deepmerge/dist/cjs.js.map +0 -1
- package/dist/esm/node_modules/media-query-parser/dist/media-query-parser.esm.js +0 -1386
- package/dist/esm/node_modules/media-query-parser/dist/media-query-parser.esm.js.map +0 -1
- package/dist/esm/node_modules/modern-ahocorasick/dist/index.js +0 -102
- package/dist/esm/node_modules/modern-ahocorasick/dist/index.js.map +0 -1
- package/dist/esm/node_modules/picocolors/picocolors.js +0 -87
- package/dist/esm/node_modules/picocolors/picocolors.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slots.js","sources":["
|
|
1
|
+
{"version":3,"file":"slots.js","sources":["src/components/editor/AssetBrowser/slots.ts"],"sourcesContent":["import type React from 'react';\n\n/**\n * Symbol marker identifying an AssetBrowser compound slot. Survives\n * `React.memo`, function wrapping, and minification — unlike `displayName`.\n */\nexport const ASSET_BROWSER_SLOT: unique symbol = Symbol.for(\n 'etui.assetBrowser.slot'\n);\n\nexport type AssetBrowserSlotKind = 'toolbar' | 'sidebar';\n\ninterface SlotMarker {\n [ASSET_BROWSER_SLOT]: AssetBrowserSlotKind;\n}\n\n/** Tags a component function with its slot kind. */\nexport function markSlot<T>(component: T, kind: AssetBrowserSlotKind): T {\n (component as unknown as SlotMarker)[ASSET_BROWSER_SLOT] = kind;\n return component;\n}\n\n/** Reads the slot kind off a React element's component type, or `null`. */\nexport function getSlotKind(\n el: React.ReactElement\n): AssetBrowserSlotKind | null {\n const type = el.type as Partial<SlotMarker> | null | undefined;\n return type?.[ASSET_BROWSER_SLOT] ?? null;\n}\n"],"names":[],"mappings":"AAEA;;;AAGG;AACI,MAAM,kBAAkB,GAAkB,MAAM,CAAC,GAAG,CACzD,wBAAwB;AAS1B;AACM,SAAU,QAAQ,CAAI,SAAY,EAAE,IAA0B,EAAA;AACjE,IAAA,SAAmC,CAAC,kBAAkB,CAAC,GAAG,IAAI;AAC/D,IAAA,OAAO,SAAS;AAClB;AAEA;AACM,SAAU,WAAW,CACzB,EAAsB,EAAA;AAEtB,IAAA,MAAM,IAAI,GAAG,EAAE,CAAC,IAA8C;AAC9D,IAAA,OAAO,IAAI,GAAG,kBAAkB,CAAC,IAAI,IAAI;AAC3C;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetBrowserAnnouncement.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetBrowserAnnouncement.js","sources":["src/components/editor/AssetBrowser/useAssetBrowserAnnouncement.ts"],"sourcesContent":["'use client';\n\nimport {\n useAssetBrowserContext,\n useAssetSelection,\n} from './AssetBrowserContext';\n\n/**\n * The polite-live a11y announcement string (\"N items, M selected\"). Subscribes\n * to the displayed-items count from the item context and the selection-size\n * slice from the store, so consumers can use it inside a tightly-scoped\n * subcomponent without lifting the value to the root.\n */\nexport function useAssetBrowserAnnouncement(): string {\n const { displayedItems, labels } = useAssetBrowserContext();\n const selectionSet = useAssetSelection();\n const count = displayedItems.length;\n const selected = selectionSet.size;\n return `${labels.itemCount(count)}${selected > 0 ? labels.selectedCount(selected) : ''}`;\n}\n"],"names":[],"mappings":";;;AAOA;;;;;AAKG;;;AAGD;AACA;AACA;;AAEF;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetBrowserHandle.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetBrowserHandle.js","sources":["src/components/editor/AssetBrowser/useAssetBrowserHandle.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useImperativeHandle } from 'react';\n\nimport { useLatest } from '@/hooks';\n\nimport type { AssetBrowserHandle, AssetItem } from './AssetBrowser.types';\nimport type { AssetBrowserStore } from './AssetBrowserStore';\nimport type { Ref, RefObject } from 'react';\n\nfunction cssEscape(value: string): string {\n if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {\n return CSS.escape(value);\n }\n return value.replace(/[\"\\\\]/g, '\\\\$&');\n}\n\nexport interface UseAssetBrowserHandleOptions {\n ref: Ref<AssetBrowserHandle> | undefined;\n rootRef: RefObject<HTMLDivElement | null>;\n store: AssetBrowserStore;\n /** Latest `items` — read by `getSelectedItems`. */\n items: readonly AssetItem[];\n /** Latest displayed (filtered + sorted) list — used to resolve scroll targets. */\n displayed: readonly AssetItem[];\n selectAll: () => void;\n clearSelection: () => void;\n /** Stable mutation handler — enters inline rename for an id. */\n beginRename: (id: string) => void;\n}\n\n/**\n * Wires the imperative `AssetBrowserHandle` onto the consumer-provided ref.\n * Each handle method has a stable identity (`useCallback`) and reads the latest\n * props through `useLatest` refs, so the handle object is built once and its\n * methods always see the latest props. `scrollToItem` prefers the\n * store-registered grid scroller (works under virtualization) and falls back\n * to a `data-asset-id` DOM query for the list view or when no grid is mounted.\n */\nexport function useAssetBrowserHandle(\n options: UseAssetBrowserHandleOptions\n): void {\n const {\n ref,\n rootRef,\n store,\n items,\n displayed,\n selectAll,\n clearSelection,\n beginRename,\n } = options;\n\n const itemsRef = useLatest(items);\n const displayedRef = useLatest(displayed);\n\n const focus = useCallback((): void => {\n rootRef.current?.focus();\n }, [rootRef]);\n\n const getElement = useCallback(\n (): HTMLDivElement | null => rootRef.current,\n [rootRef]\n );\n\n const scrollToItem = useCallback(\n (id: string): void => {\n store.setFocusedId(id);\n const index = displayedRef.current.findIndex(it => it.id === id);\n if (index >= 0 && store.scrollToIndex(index)) return;\n const el = rootRef.current?.querySelector(\n `[data-asset-id=\"${cssEscape(id)}\"]`\n );\n el?.scrollIntoView({ block: 'nearest' });\n },\n [store, rootRef, displayedRef]\n );\n\n const getSelectedItems = useCallback(\n (): AssetItem[] =>\n itemsRef.current.filter(it => store.getSelection().has(it.id)),\n [store, itemsRef]\n );\n\n const beginRenameHandle = useCallback(\n (id: string): void => {\n // Bring the target into view first so the rename field is visible even\n // when it was outside the virtualization window.\n scrollToItem(id);\n beginRename(id);\n },\n [scrollToItem, beginRename]\n );\n\n useImperativeHandle(\n ref,\n (): AssetBrowserHandle => ({\n focus,\n getElement,\n selectAll,\n clearSelection,\n scrollToItem,\n getSelectedItems,\n beginRename: beginRenameHandle,\n }),\n [\n focus,\n getElement,\n selectAll,\n clearSelection,\n scrollToItem,\n getSelectedItems,\n beginRenameHandle,\n ]\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAUA;AACE;AACE;;;AAGJ;AAgBA;;;;;;;AAOG;AACG;AAGJ;AAWA;AACA;AAEA;AACE;AACF;AAEA;AAKA;AAEI;AACA;;;AAEA;;;AAQJ;AAMA;;;;;AAME;AAIF;;;;;;;AASI;AACD;;;;;;;;AASA;AAEL;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useControlledState } from '../../../hooks/useControlledState/useControlledState.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetBrowserViewState.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetBrowserViewState.js","sources":["src/components/editor/AssetBrowser/useAssetBrowserViewState.ts"],"sourcesContent":["'use client';\n\nimport { useDeferredValue, useMemo } from 'react';\n\nimport { useControlledState } from '@/hooks';\n\nimport { collectTypes, shapeAssets } from './assetBrowserFilter';\nimport { resolveThumbPx } from './assetBrowserGeometry';\n\nimport type {\n AssetFilterState,\n AssetItem,\n AssetSortState,\n AssetThumbnailSize,\n AssetType,\n AssetView,\n} from './AssetBrowser.types';\n\nconst DEFAULT_SORT: AssetSortState = { field: 'name', direction: 'asc' };\n\nexport interface UseAssetBrowserViewStateOptions {\n items: readonly AssetItem[];\n selectionMode: 'single' | 'multiple' | false;\n marquee: boolean;\n\n view?: AssetView;\n defaultView?: AssetView;\n onViewChange?: (view: AssetView) => void;\n\n thumbnailSize?: AssetThumbnailSize;\n defaultThumbnailSize?: AssetThumbnailSize;\n onThumbnailSizeChange?: (size: AssetThumbnailSize) => void;\n\n search?: string;\n defaultSearch?: string;\n onSearchChange?: (query: string) => void;\n manualSearch: boolean;\n\n filters?: AssetFilterState;\n defaultFilters?: AssetFilterState;\n onFiltersChange?: (filters: AssetFilterState) => void;\n manualFilter: boolean;\n\n sort?: AssetSortState;\n defaultSort?: AssetSortState;\n onSortChange?: (sort: AssetSortState) => void;\n manualSort: boolean;\n\n filterableTypesProp?: AssetType[];\n}\n\nexport interface AssetBrowserViewState {\n view: AssetView;\n setView: (view: AssetView) => void;\n thumbnailSize: AssetThumbnailSize;\n setThumbnailSize: (size: AssetThumbnailSize) => void;\n thumbnailSizePx: number;\n search: string;\n setSearch: (query: string) => void;\n filters: AssetFilterState;\n setFilters: (filters: AssetFilterState) => void;\n sort: AssetSortState;\n setSort: (sort: AssetSortState) => void;\n filterableTypes: string[];\n /** Search (deferred) + filter + sort applied — what the views render. */\n displayed: AssetItem[];\n /** Resolved from `selectionMode === 'multiple'` and the `marquee` prop. */\n marqueeEnabled: boolean;\n}\n\n/**\n * View-state aggregate for `AssetBrowser`. Wraps the five `useControlledState`\n * pairs (view / thumbnailSize / search / filters / sort) and computes the\n * derived values (`thumbnailSizePx`, `filterableTypes`, `displayed`,\n * `marqueeEnabled`). Search is run through `useDeferredValue` so heavy filter\n * + sort passes can lag behind responsive keystrokes.\n */\nexport function useAssetBrowserViewState(\n options: UseAssetBrowserViewStateOptions\n): AssetBrowserViewState {\n const [view, setView] = useControlledState<AssetView>({\n value: options.view,\n defaultValue: options.defaultView,\n onChange: options.onViewChange,\n fallback: 'grid',\n });\n const [thumbnailSize, setThumbnailSize] =\n useControlledState<AssetThumbnailSize>({\n value: options.thumbnailSize,\n defaultValue: options.defaultThumbnailSize,\n onChange: options.onThumbnailSizeChange,\n fallback: 'md',\n });\n const [search, setSearch] = useControlledState<string>({\n value: options.search,\n defaultValue: options.defaultSearch,\n onChange: options.onSearchChange,\n fallback: '',\n });\n const [filters, setFilters] = useControlledState<AssetFilterState>({\n value: options.filters,\n defaultValue: options.defaultFilters,\n onChange: options.onFiltersChange,\n fallback: {},\n });\n const [sort, setSort] = useControlledState<AssetSortState>({\n value: options.sort,\n defaultValue: options.defaultSort,\n onChange: options.onSortChange,\n fallback: DEFAULT_SORT,\n });\n\n const deferredSearch = useDeferredValue(search);\n const thumbnailSizePx = resolveThumbPx(thumbnailSize);\n const marqueeEnabled =\n options.selectionMode === 'multiple' && options.marquee;\n\n const filterableTypes = useMemo(\n () => options.filterableTypesProp ?? collectTypes(options.items),\n [options.filterableTypesProp, options.items]\n );\n\n const displayed = useMemo(\n () =>\n shapeAssets(options.items, {\n search: deferredSearch,\n filters,\n sort,\n manualSearch: options.manualSearch,\n manualFilter: options.manualFilter,\n manualSort: options.manualSort,\n }),\n [\n options.items,\n deferredSearch,\n filters,\n sort,\n options.manualSearch,\n options.manualFilter,\n options.manualSort,\n ]\n );\n\n return useMemo(\n () => ({\n view,\n setView,\n thumbnailSize,\n setThumbnailSize,\n thumbnailSizePx,\n search,\n setSearch,\n filters,\n setFilters,\n sort,\n setSort,\n filterableTypes,\n displayed,\n marqueeEnabled,\n }),\n [\n view,\n setView,\n thumbnailSize,\n setThumbnailSize,\n thumbnailSizePx,\n search,\n setSearch,\n filters,\n setFilters,\n sort,\n setSort,\n filterableTypes,\n displayed,\n marqueeEnabled,\n ]\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAkBA;AAoDA;;;;;;AAMG;AACG;AAGJ;;;;AAIE;AACD;AACD;;;;AAKI;AACD;AACH;;;;AAIE;AACD;AACD;;;;AAIE;AACD;AACD;;;;AAIE;AACD;AAED;AACA;;AAIA;AAKA;AAGM;;;;;;AAMD;AAED;;;;AAIA;AACA;AACA;AACD;AAGH;;;;;;;;;;;;;;;AAgBG;;;;;;;;;;;;;;;AAgBA;AAEL;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetDnd.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetDnd.js","sources":["src/components/editor/AssetBrowser/useAssetDnd.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo } from 'react';\n\nimport { useLatest } from '@/hooks';\n\nimport type { AssetItem } from './AssetBrowser.types';\nimport type { AssetDndContext } from './AssetBrowserContext';\nimport type { AssetBrowserStore } from './AssetBrowserStore';\nimport type { DragEvent } from 'react';\n\nexport interface UseAssetDndOptions {\n store: AssetBrowserStore;\n mime: string;\n items: readonly AssetItem[];\n selection: ReadonlySet<string>;\n currentFolderId: string | undefined;\n getDragData?: (items: AssetItem[]) => Record<string, string>;\n onItemDragStart?: (items: AssetItem[], event: DragEvent) => void;\n onItemDragEnd?: (items: AssetItem[], event: DragEvent) => void;\n onItemsMove?: (payload: {\n itemIds: string[];\n targetFolderId: string;\n }) => void;\n onFilesImport?: (payload: {\n files: File[];\n targetFolderId: string | null;\n }) => void;\n}\n\nfunction hasFiles(event: DragEvent): boolean {\n return Array.from(event.dataTransfer.types).includes('Files');\n}\n\n/** True when the drag is leaving the element entirely (not into a child). */\nfunction leftElement(event: DragEvent): boolean {\n const related = event.relatedTarget as Node | null;\n return !(related && event.currentTarget.contains(related));\n}\n\n/**\n * Drag-and-drop wiring for the AssetBrowser: internal item moves (gated by\n * `onItemsMove`) and external file import (gated by `onFilesImport`). Every\n * handler has a stable identity (`useCallback`) and reads the latest props\n * through `useLatest` refs, matching `component-patterns.md` rules #3/#11.\n */\nexport function useAssetDnd(options: UseAssetDndOptions): AssetDndContext {\n const {\n store,\n mime,\n items,\n selection,\n currentFolderId,\n getDragData,\n onItemDragStart: cbItemDragStart,\n onItemDragEnd: cbItemDragEnd,\n onItemsMove,\n onFilesImport,\n } = options;\n\n const internalEnabled = onItemsMove !== undefined;\n const externalEnabled = onFilesImport !== undefined;\n\n const mimeRef = useLatest(mime);\n const itemsRef = useLatest(items);\n const selectionRef = useLatest(selection);\n const currentFolderIdRef = useLatest(currentFolderId);\n const getDragDataRef = useLatest(getDragData);\n const cbItemDragStartRef = useLatest(cbItemDragStart);\n const cbItemDragEndRef = useLatest(cbItemDragEnd);\n const onItemsMoveRef = useLatest(onItemsMove);\n const onFilesImportRef = useLatest(onFilesImport);\n\n const resolveItems = useCallback(\n (ids: string[]): AssetItem[] => {\n const map = new Map(itemsRef.current.map(item => [item.id, item]));\n return ids\n .map(id => map.get(id))\n .filter((item): item is AssetItem => item !== undefined);\n },\n [itemsRef]\n );\n\n const onItemDragStart = useCallback(\n (item: AssetItem, event: DragEvent): void => {\n const sel = selectionRef.current;\n const ids = sel.has(item.id) ? Array.from(sel) : [item.id];\n const dragged = resolveItems(ids);\n const payload = getDragDataRef.current?.(dragged) ?? {\n [mimeRef.current]: JSON.stringify(ids),\n };\n for (const [type, value] of Object.entries(payload)) {\n event.dataTransfer.setData(type, value);\n }\n event.dataTransfer.effectAllowed = 'copyMove';\n store.setDrag({\n active: true,\n draggingIds: ids,\n dropTargetId: null,\n externalOver: false,\n });\n cbItemDragStartRef.current?.(dragged, event);\n },\n [\n store,\n resolveItems,\n selectionRef,\n getDragDataRef,\n mimeRef,\n cbItemDragStartRef,\n ]\n );\n\n const onItemDragEnd = useCallback(\n (item: AssetItem, event: DragEvent): void => {\n const ids = store.getDrag().draggingIds;\n const dragged = resolveItems(ids.length > 0 ? ids : [item.id]);\n store.clearDrag();\n cbItemDragEndRef.current?.(dragged, event);\n },\n [store, resolveItems, cbItemDragEndRef]\n );\n\n const onFolderDragOver = useCallback(\n (folderId: string, event: DragEvent): void => {\n const drag = store.getDrag();\n const external =\n onFilesImportRef.current !== undefined && hasFiles(event);\n const internal = onItemsMoveRef.current !== undefined && drag.active;\n if (!external && !internal) return;\n event.preventDefault();\n event.dataTransfer.dropEffect = external ? 'copy' : 'move';\n store.setDrag({\n active: true,\n draggingIds: drag.draggingIds,\n dropTargetId: folderId,\n externalOver: external,\n });\n },\n [store, onFilesImportRef, onItemsMoveRef]\n );\n\n const onFolderDragLeave = useCallback(\n (folderId: string, event: DragEvent): void => {\n if (!leftElement(event)) return;\n const drag = store.getDrag();\n if (drag.dropTargetId !== folderId) return;\n store.setDrag({ ...drag, dropTargetId: null });\n },\n [store]\n );\n\n const onFolderDrop = useCallback(\n (folderId: string, event: DragEvent): void => {\n event.preventDefault();\n const files = Array.from(event.dataTransfer.files);\n const filesImport = onFilesImportRef.current;\n const itemsMove = onItemsMoveRef.current;\n if (files.length > 0 && filesImport) {\n filesImport({ files, targetFolderId: folderId });\n } else if (itemsMove) {\n const drag = store.getDrag();\n let ids = drag.draggingIds;\n if (ids.length === 0) {\n const raw = event.dataTransfer.getData(mimeRef.current);\n if (raw) {\n try {\n ids = JSON.parse(raw) as string[];\n } catch {\n ids = [];\n }\n }\n }\n if (ids.length > 0) {\n itemsMove({ itemIds: ids, targetFolderId: folderId });\n }\n }\n store.clearDrag();\n },\n [store, onFilesImportRef, onItemsMoveRef, mimeRef]\n );\n\n const onSurfaceDragOver = useCallback(\n (event: DragEvent): void => {\n if (onFilesImportRef.current === undefined || !hasFiles(event)) return;\n event.preventDefault();\n event.dataTransfer.dropEffect = 'copy';\n const drag = store.getDrag();\n store.setDrag({\n active: true,\n draggingIds: drag.draggingIds,\n dropTargetId: null,\n externalOver: true,\n });\n },\n [store, onFilesImportRef]\n );\n\n const onSurfaceDragLeave = useCallback(\n (event: DragEvent): void => {\n if (!leftElement(event)) return;\n const drag = store.getDrag();\n if (!drag.externalOver) return;\n store.setDrag({ ...drag, externalOver: false });\n },\n [store]\n );\n\n const onSurfaceDrop = useCallback(\n (event: DragEvent): void => {\n const filesImport = onFilesImportRef.current;\n if (!filesImport) return;\n const files = Array.from(event.dataTransfer.files);\n if (files.length === 0) {\n store.clearDrag();\n return;\n }\n event.preventDefault();\n filesImport({\n files,\n targetFolderId: currentFolderIdRef.current ?? null,\n });\n store.clearDrag();\n },\n [store, onFilesImportRef, currentFolderIdRef]\n );\n\n return useMemo<AssetDndContext>(\n () => ({\n internalEnabled,\n externalEnabled,\n onItemDragStart,\n onItemDragEnd,\n onFolderDragOver,\n onFolderDragLeave,\n onFolderDrop,\n onSurfaceDragOver,\n onSurfaceDragLeave,\n onSurfaceDrop,\n }),\n [\n internalEnabled,\n externalEnabled,\n onItemDragStart,\n onItemDragEnd,\n onFolderDragOver,\n onFolderDragLeave,\n onFolderDrop,\n onSurfaceDragOver,\n onSurfaceDragLeave,\n onSurfaceDrop,\n ]\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA8BA;AACE;AACF;AAEA;AACA;AACE;AACA;AACF;AAEA;;;;;AAKG;AACG;;AAcJ;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;AAGI;;;AAGF;;AAME;;AAEA;;;;AAIA;;;AAGA;;AAEE;AACA;AACA;AACA;AACD;;AAEH;;;;;;;AAQC;;;;;;;;AAeC;AACA;;AAGA;;;AAEA;;AAEE;;AAEA;AACA;AACD;;;AAOD;;AACA;AACA;;AACA;AACF;;;AAOE;AACA;AACA;;;;;AAIE;AACA;AACA;AACE;;AAEE;AACE;;AACA;;;;;AAKN;;;;;;AASN;;;;AAII;AACA;;AAEE;;AAEA;AACA;AACD;AACH;AAIF;AAEI;;AACA;;;AAEA;AACF;AAIF;AAEI;AACA;;AACA;AACA;;;;;AAKA;;AAEE;AACD;;;AAML;;;;;;;;;;;AAYG;;;;;;;;;;;AAYA;AAEL;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetGridKeyboardNav.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetGridKeyboardNav.js","sources":["src/components/editor/AssetBrowser/useAssetGridKeyboardNav.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo } from 'react';\n\nimport { nextGridIndex } from './assetBrowserKeyboard';\n\nimport type { AssetItem } from './AssetBrowser.types';\nimport type { AssetBrowserStore } from './AssetBrowserStore';\nimport type { AssetGridWindow } from './useAssetGridVirtualizer';\nimport type { KeyboardEvent, RefObject } from 'react';\n\nexport interface UseAssetGridKeyboardNavOptions {\n store: AssetBrowserStore;\n items: readonly AssetItem[];\n /** Current windowed layout (columns, rowHeight). */\n win: AssetGridWindow;\n /** The grid scroller — used to derive `rowsPerPage` from clientHeight. */\n scrollerRef: RefObject<HTMLElement | null>;\n selectionMode: 'single' | 'multiple' | false;\n selectAll: () => void;\n clearSelection: () => void;\n activateItem: (item: AssetItem) => void;\n toggleSelectId: (id: string) => void;\n selectByKeyboard: (index: number, extend: boolean) => void;\n /** Bring the row containing the given item index into view. */\n scrollIndexIntoView: (index: number, w: AssetGridWindow) => void;\n}\n\nexport interface AssetGridKeyboardNav {\n onKeyDown: (event: KeyboardEvent) => void;\n}\n\n/**\n * 2D grid keyboard navigation for `AssetBrowserGrid`. Handles arrows, Home/End,\n * PageUp/PageDown, Enter (activate), Space (toggle), Ctrl/Cmd+A (select all),\n * Escape (clear). `onKeyDown` is a `useCallback` — the selection/navigation\n * callbacks it depends on are themselves stable, and the handler is only spread\n * onto the grid `onKeyDown` so re-attaching on layout changes is free.\n *\n * Alt+ArrowUp is intentionally **not** handled here — it bubbles to the root's\n * \"go to parent\" handler when `history` is on.\n */\nexport function useAssetGridKeyboardNav(\n options: UseAssetGridKeyboardNavOptions\n): AssetGridKeyboardNav {\n const {\n store,\n items,\n win,\n scrollerRef,\n selectionMode,\n selectAll,\n clearSelection,\n activateItem,\n toggleSelectId,\n selectByKeyboard,\n scrollIndexIntoView,\n } = options;\n\n const indexById = useMemo(() => {\n const map = new Map<string, number>();\n items.forEach((item, i) => map.set(item.id, i));\n return map;\n }, [items]);\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent): void => {\n const count = items.length;\n if (count === 0) return;\n const key = event.key;\n // Let Alt+ArrowUp bubble to the root's \"go to parent\" handler.\n if (event.altKey && key === 'ArrowUp') return;\n const focusedId = store.getFocusedId();\n const current = focusedId ? (indexById.get(focusedId) ?? -1) : -1;\n const multiple = selectionMode === 'multiple';\n\n if ((event.ctrlKey || event.metaKey) && (key === 'a' || key === 'A')) {\n event.preventDefault();\n selectAll();\n return;\n }\n if (key === 'Escape') {\n clearSelection();\n return;\n }\n if (key === 'Enter') {\n const item = current >= 0 ? items[current] : undefined;\n if (item) {\n event.preventDefault();\n activateItem(item);\n }\n return;\n }\n if (key === ' ') {\n const item = current >= 0 ? items[current] : undefined;\n if (item) {\n event.preventDefault();\n toggleSelectId(item.id);\n }\n return;\n }\n\n const rowsPerPage = Math.max(\n 1,\n Math.floor(\n (scrollerRef.current?.clientHeight ?? win.rowHeight) / win.rowHeight\n )\n );\n const next = nextGridIndex(current, key, {\n columns: win.columns,\n count,\n rowsPerPage,\n });\n const target = next >= 0 ? items[next] : undefined;\n if (next !== current && target) {\n event.preventDefault();\n store.setFocusedId(target.id);\n scrollIndexIntoView(next, win);\n if (selectionMode !== false) {\n selectByKeyboard(next, multiple && event.shiftKey);\n }\n }\n },\n [\n store,\n items,\n win,\n scrollerRef,\n selectionMode,\n indexById,\n selectAll,\n clearSelection,\n activateItem,\n toggleSelectId,\n selectByKeyboard,\n scrollIndexIntoView,\n ]\n );\n\n return { onKeyDown };\n}\n"],"names":[],"mappings":";;;;AAgCA;;;;;;;;;AASG;AACG;;AAiBJ;AACE;;AAEA;AACF;AAEA;AAEI;;;AAEA;;AAEA;;AACA;;AAEA;;;AAIE;;;AAGF;AACE;;;AAGF;AACE;;;;;;;AAOF;AACE;;;AAGE;;;;AAKJ;AAMA;;;;AAIC;AACD;AACA;;AAEE;AACA;AACA;;;;AAIJ;;;;;;;;;;;;;AAcC;;AAIL;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useResizeObserver } from '../../../hooks/useResizeObserver/useResizeObserver.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetGridVirtualizer.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetGridVirtualizer.js","sources":["src/components/editor/AssetBrowser/useAssetGridVirtualizer.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\nimport { useResizeObserver } from '@/hooks';\n\nimport { columnsFor, rowHeight as rowHeightFor } from './assetBrowserGeometry';\n\nimport type { RefObject } from 'react';\n\nexport interface UseAssetGridVirtualizerOptions {\n containerRef: RefObject<HTMLElement | null>;\n count: number;\n thumbPx: number;\n overscanRows: number;\n /** When false, the window spans the whole list (no virtualization). */\n enabled: boolean;\n}\n\nexport interface AssetGridWindow {\n columns: number;\n rowHeight: number;\n totalRows: number;\n totalHeight: number;\n /** First rendered item index (row-aligned). */\n startIndex: number;\n /** One past the last rendered item index. */\n endIndex: number;\n /** Pixel offset of the rendered window from the top. */\n offsetY: number;\n /** Whether windowing is currently active. */\n windowed: boolean;\n}\n\n/**\n * Windowed grid math. Tracks container width + height via `useResizeObserver`\n * and scroll position via a throttled (rAF) scroll listener, then derives the\n * row-aligned slice of items to render.\n *\n * When `enabled` is false it still reports `columns`/`rowHeight` (needed for\n * keyboard navigation) but renders the whole list.\n */\nexport function useAssetGridVirtualizer(\n options: UseAssetGridVirtualizerOptions\n): AssetGridWindow {\n const { containerRef, count, thumbPx, overscanRows, enabled } = options;\n const [size, setSize] = useState({ width: 0, height: 0 });\n const [scrollTop, setScrollTop] = useState(0);\n\n useResizeObserver(containerRef, entry => {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n });\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el || !enabled) return;\n let raf = 0;\n const onScroll = (): void => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n setScrollTop(el.scrollTop);\n });\n };\n el.addEventListener('scroll', onScroll, { passive: true });\n return () => {\n el.removeEventListener('scroll', onScroll);\n cancelAnimationFrame(raf);\n };\n }, [containerRef, enabled]);\n\n return useMemo<AssetGridWindow>(() => {\n const columns = columnsFor(size.width, thumbPx);\n const rh = rowHeightFor(thumbPx);\n const totalRows = Math.ceil(count / columns);\n const totalHeight = totalRows * rh;\n\n if (!enabled) {\n return {\n columns,\n rowHeight: rh,\n totalRows,\n totalHeight,\n startIndex: 0,\n endIndex: count,\n offsetY: 0,\n windowed: false,\n };\n }\n\n const startRow = Math.max(0, Math.floor(scrollTop / rh) - overscanRows);\n const viewportRows = Math.ceil((size.height || rh) / rh);\n const endRow = Math.min(\n totalRows,\n startRow + viewportRows + overscanRows * 2\n );\n\n return {\n columns,\n rowHeight: rh,\n totalRows,\n totalHeight,\n startIndex: startRow * columns,\n endIndex: Math.min(count, endRow * columns),\n offsetY: startRow * rh,\n windowed: true,\n };\n }, [\n size.width,\n size.height,\n scrollTop,\n count,\n thumbPx,\n overscanRows,\n enabled,\n ]);\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;AAkCA;;;;;;;AAOG;AACG;AAGJ;AACA;;AAGA;AACE;AACE;AACA;AACD;AACH;;AAGE;AACA;;;;;AAIE;AACE;AACF;AACF;AACA;AACA;AACE;;AAEF;AACF;;;AAIE;;AAEA;;;;AAKI;;;AAGA;AACA;AACA;AACA;;;AAIJ;AACA;AACA;;;AAOE;;;;;;AAMA;;AAEJ;AACE;AACA;;;;;;AAMD;AACH;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetMarqueeGesture.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetMarqueeGesture.js","sources":["src/components/editor/AssetBrowser/useAssetMarqueeGesture.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport { useLatest } from '@/hooks';\n\nimport { useAssetBrowserStore } from './AssetBrowserContext';\nimport {\n itemRect,\n rectFromPoints,\n rectsIntersect,\n} from './assetBrowserGeometry';\n\nimport type { AssetItem } from './AssetBrowser.types';\nimport type { PointerEvent, RefObject } from 'react';\n\nexport interface UseAssetMarqueeGestureOptions {\n /** The scroll container — also the pointer-capture target and coordinate origin. */\n scrollerRef: RefObject<HTMLElement | null>;\n /** When false, pointer-down is ignored. */\n enabled: boolean;\n /** Currently displayed items, in display order. */\n items: readonly AssetItem[];\n /** Current grid column count (from the virtualizer). */\n columns: number;\n /** Current thumbnail pixel size. */\n thumbPx: number;\n /** Called once on pointer-up with the items that intersect the marquee rect. */\n commitMarquee: (ids: string[], additive: boolean) => void;\n}\n\nexport interface AssetMarqueeGestureHandlers {\n onPointerDown: (event: PointerEvent) => void;\n onPointerMove: (event: PointerEvent) => void;\n onPointerUp: (event: PointerEvent) => void;\n /** Abort an in-flight marquee (system gesture cancel, touch interruption). */\n onPointerCancel: (event: PointerEvent) => void;\n}\n\ninterface MarqueeDrag {\n startX: number;\n startY: number;\n additive: boolean;\n moved: boolean;\n}\n\n/**\n * Pointer-driven rubber-band selection for the grid. The active rect lives in\n * the AssetBrowser store (so the marquee overlay can subscribe via its own\n * slice), while pointer-move updates are RAF-throttled. The hit-test runs once\n * on pointer-up and reports through `commitMarquee`.\n *\n * Handlers have stable identities (`useCallback`) and read the latest props\n * through `useLatest` refs, matching `component-patterns.md` rules #3/#11.\n */\nexport function useAssetMarqueeGesture(\n options: UseAssetMarqueeGestureOptions\n): AssetMarqueeGestureHandlers {\n const { scrollerRef, enabled, items, columns, thumbPx, commitMarquee } =\n options;\n const store = useAssetBrowserStore();\n\n const dragRef = useRef<MarqueeDrag | null>(null);\n const rafRef = useRef(0);\n\n const enabledRef = useLatest(enabled);\n const itemsRef = useLatest(items);\n const columnsRef = useLatest(columns);\n const thumbPxRef = useLatest(thumbPx);\n const commitMarqueeRef = useLatest(commitMarquee);\n\n const contentPoint = useCallback(\n (event: PointerEvent): { x: number; y: number } => {\n const el = scrollerRef.current;\n if (!el) return { x: 0, y: 0 };\n const rect = el.getBoundingClientRect();\n return {\n x: event.clientX - rect.left + el.scrollLeft,\n y: event.clientY - rect.top + el.scrollTop,\n };\n },\n [scrollerRef]\n );\n\n const onPointerDown = useCallback(\n (event: PointerEvent): void => {\n if (event.button !== 0 || !enabledRef.current) return;\n // Started on an item, not empty space — let the item handle the click.\n if (event.target !== event.currentTarget) return;\n const p = contentPoint(event);\n dragRef.current = {\n startX: p.x,\n startY: p.y,\n additive: event.ctrlKey || event.metaKey,\n moved: false,\n };\n scrollerRef.current?.setPointerCapture(event.pointerId);\n store.setMarquee({\n active: true,\n rect: { x: p.x, y: p.y, width: 0, height: 0 },\n additive: dragRef.current.additive,\n });\n },\n [store, scrollerRef, contentPoint, enabledRef]\n );\n\n const onPointerMove = useCallback(\n (event: PointerEvent): void => {\n const drag = dragRef.current;\n if (!drag) return;\n drag.moved = true;\n cancelAnimationFrame(rafRef.current);\n const p = contentPoint(event);\n rafRef.current = requestAnimationFrame(() => {\n store.setMarquee({\n active: true,\n rect: rectFromPoints(drag.startX, drag.startY, p.x, p.y),\n additive: drag.additive,\n });\n });\n },\n [store, contentPoint]\n );\n\n const onPointerUp = useCallback(\n (event: PointerEvent): void => {\n const drag = dragRef.current;\n if (!drag) return;\n cancelAnimationFrame(rafRef.current);\n dragRef.current = null;\n scrollerRef.current?.releasePointerCapture(event.pointerId);\n const p = contentPoint(event);\n const rect = rectFromPoints(drag.startX, drag.startY, p.x, p.y);\n const ids: string[] = [];\n const currentItems = itemsRef.current;\n for (let i = 0; i < currentItems.length; i += 1) {\n const item = currentItems[i];\n if (!item || item.selectable === false) continue;\n if (\n rectsIntersect(\n rect,\n itemRect(i, columnsRef.current, thumbPxRef.current)\n )\n ) {\n ids.push(item.id);\n }\n }\n commitMarqueeRef.current(ids, drag.additive);\n store.clearMarquee();\n },\n [\n store,\n scrollerRef,\n contentPoint,\n itemsRef,\n columnsRef,\n thumbPxRef,\n commitMarqueeRef,\n ]\n );\n\n // Abort an in-flight marquee without committing a selection. Fires on a\n // system/touch `pointercancel`, which would otherwise leave `dragRef` set and\n // the marquee rect stuck active in the store until the next pointer-down.\n const onPointerCancel = useCallback(\n (event: PointerEvent): void => {\n if (!dragRef.current) return;\n cancelAnimationFrame(rafRef.current);\n dragRef.current = null;\n scrollerRef.current?.releasePointerCapture(event.pointerId);\n store.clearMarquee();\n },\n [store, scrollerRef]\n );\n\n // Cancel any in-flight RAF on unmount.\n useEffect(\n () => () => {\n cancelAnimationFrame(rafRef.current);\n },\n []\n );\n\n return { onPointerDown, onPointerMove, onPointerUp, onPointerCancel };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA8CA;;;;;;;;AAQG;AACG;AAGJ;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAEI;AACA;;AACA;;;;;AAKF;AAIF;;;;AAII;;AACA;;;;AAIE;AACA;;;;AAIA;;AAEA;AACD;;AAKL;AAEI;AACA;;AACA;AACA;AACA;AACA;;AAEI;AACA;;AAED;AACH;AACF;AAIF;AAEI;AACA;;AACA;AACA;;AAEA;;;AAGA;AACA;AACE;AACA;;AACA;AAME;;;;;AAKN;;;;;;;;AASC;;;;AAMH;;;AAGI;AACA;;;AAGF;;AAKF;AAEI;;;AAMN;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetMutationKeyboard.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetMutationKeyboard.js","sources":["src/components/editor/AssetBrowser/useAssetMutationKeyboard.ts"],"sourcesContent":["'use client';\n\nimport { useCallback } from 'react';\n\nimport { useLatest } from '@/hooks';\n\nimport type { AssetBrowserStore } from './AssetBrowserStore';\nimport type { AssetMutationsApi } from './useAssetMutations';\nimport type { KeyboardEvent } from 'react';\n\nexport interface UseAssetMutationKeyboardOptions {\n store: AssetBrowserStore;\n mutations: AssetMutationsApi;\n /** Live selection set — the F2 rename target falls back to a single selection. */\n selection: ReadonlySet<string>;\n}\n\nexport interface AssetMutationKeyboard {\n /** Attach to the AssetBrowser root: F2 / Delete / Ctrl+D, view-agnostic. */\n onKeyDown: (event: KeyboardEvent) => void;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable\n );\n}\n\n/**\n * View-agnostic mutation keyboard shortcuts. The same handler is exposed through\n * context (`mutationKeyDown`) and attached by each view to its own scroller —\n * the grid (merged with its 2D nav) and the list wrapper — so the shortcuts\n * work identically in both without relying on event bubbling to the root.\n *\n * - **F2** — inline-rename the focused item, or the sole selected item (the list\n * has no store roving-focus, so it falls back to a single selection).\n * - **Delete** (and **⌘⌫** on macOS) — delete the selection. Plain `Backspace`\n * stays reserved for the root's \"go to parent\" shortcut.\n * - **Ctrl/⌘+D** — duplicate the selection.\n *\n * Each shortcut is a no-op unless its mutation callback is wired, and all are\n * skipped while the focus is in an editable element (search box, rename field).\n * The handler is `useCallback`-stable; live state is read through `useLatest`.\n */\nexport function useAssetMutationKeyboard(\n options: UseAssetMutationKeyboardOptions\n): AssetMutationKeyboard {\n const { store, mutations } = options;\n const mutationsRef = useLatest(mutations);\n const selectionRef = useLatest(options.selection);\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent): void => {\n if (isEditableTarget(event.target)) return;\n const key = event.key;\n const m = mutationsRef.current;\n\n if (\n (event.ctrlKey || event.metaKey) &&\n (key === 'd' || key === 'D') &&\n m.canDuplicate\n ) {\n event.preventDefault();\n m.duplicateItems();\n return;\n }\n if (key === 'F2' && m.canRename) {\n const focusedId = store.getFocusedId();\n const sel = selectionRef.current;\n const targetId =\n focusedId ?? (sel.size === 1 ? [...sel][0] : undefined);\n if (targetId !== undefined) {\n event.preventDefault();\n m.beginRename(targetId);\n }\n return;\n }\n if (\n (key === 'Delete' || (event.metaKey && key === 'Backspace')) &&\n m.canDelete\n ) {\n event.preventDefault();\n m.deleteItems();\n }\n },\n [store, mutationsRef, selectionRef]\n );\n\n return { onKeyDown };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAsBA;AACE;AAAsC;AACtC;;;AAKF;AAEA;;;;;;;;;;;;;;;AAeG;AACG;AAGJ;AACA;;AAGA;AAEI;;AACA;AACA;;AAIE;;;;;;;AAQA;AACA;;AAGA;;AAEE;;;;AAIJ;;;;;;;AAYN;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetMutations.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetMutations.js","sources":["src/components/editor/AssetBrowser/useAssetMutations.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useMemo } from 'react';\n\nimport { useLatest } from '@/hooks';\n\nimport type { AssetItem, AssetRenameResult } from './AssetBrowser.types';\nimport type { AssetBrowserStore } from './AssetBrowserStore';\n\nexport interface UseAssetMutationsOptions {\n store: AssetBrowserStore;\n /** Displayed (filtered + sorted) list — used to resolve the focus-after-delete target. */\n displayed: readonly AssetItem[];\n /** Live selection set — delete/duplicate default to acting on it. */\n selection: ReadonlySet<string>;\n currentFolderId: string | undefined;\n onItemRename?: (item: AssetItem, newName: string) => AssetRenameResult;\n onItemsDelete?: (items: AssetItem[]) => void;\n onCreateFolder?: (parentFolderId: string | null) => void;\n onItemsDuplicate?: (items: AssetItem[]) => void;\n}\n\nexport interface AssetMutationsApi {\n /** Whether each operation is enabled (its callback is present). */\n canRename: boolean;\n canDelete: boolean;\n canCreateFolder: boolean;\n canDuplicate: boolean;\n /** Enter inline-rename on `id` (no-op when rename is disabled). */\n beginRename: (id: string) => void;\n /**\n * Commit a rename. Returns whether the editor should close (`true`) or stay\n * open (`false`, e.g. the consumer rejected the name). Empty / unchanged\n * names close without firing the callback.\n */\n commitRename: (item: AssetItem, newName: string) => Promise<boolean>;\n /** Leave rename mode without committing. */\n cancelRename: () => void;\n /** Delete the given items (defaults to the current selection when omitted). */\n deleteItems: (items?: readonly AssetItem[]) => void;\n /** Create a folder in the current folder. */\n createFolder: () => void;\n /** Duplicate the given items (defaults to the current selection when omitted). */\n duplicateItems: (items?: readonly AssetItem[]) => void;\n}\n\n/**\n * Owns the mutation intents — inline rename (begin/commit/cancel), delete,\n * create-folder, duplicate — for `AssetBrowser`. AssetBrowser is presentational:\n * these report intent through the consumer's callbacks and never touch `items`.\n *\n * The \"which cell is editing\" flag lives in the store (so rename can be started\n * from the keyboard, a menu, or the imperative handle — all outside the cell);\n * the transient text buffer is local to the rename field. Every handler has a\n * stable identity (`useCallback`) and reads the latest props through `useLatest`\n * refs, matching `component-patterns.md` rules #3/#11.\n */\nexport function useAssetMutations(\n options: UseAssetMutationsOptions\n): AssetMutationsApi {\n const { store } = options;\n\n const canRename = options.onItemRename !== undefined;\n const canDelete = options.onItemsDelete !== undefined;\n const canCreateFolder = options.onCreateFolder !== undefined;\n const canDuplicate = options.onItemsDuplicate !== undefined;\n\n const displayedRef = useLatest(options.displayed);\n const selectionRef = useLatest(options.selection);\n const currentFolderIdRef = useLatest(options.currentFolderId);\n const onItemRenameRef = useLatest(options.onItemRename);\n const onItemsDeleteRef = useLatest(options.onItemsDelete);\n const onCreateFolderRef = useLatest(options.onCreateFolder);\n const onItemsDuplicateRef = useLatest(options.onItemsDuplicate);\n\n /** Resolve the items an operation targets: the explicit arg, else the selection. */\n const resolveTargets = useCallback(\n (items?: readonly AssetItem[]): AssetItem[] => {\n if (items) return [...items];\n const sel = selectionRef.current;\n return displayedRef.current.filter(it => sel.has(it.id));\n },\n [displayedRef, selectionRef]\n );\n\n const beginRename = useCallback(\n (id: string): void => {\n if (onItemRenameRef.current === undefined) return;\n store.setFocusedId(id);\n store.setEditingId(id);\n },\n [store, onItemRenameRef]\n );\n\n const cancelRename = useCallback((): void => {\n store.setEditingId(null);\n }, [store]);\n\n const commitRename = useCallback(\n async (item: AssetItem, newName: string): Promise<boolean> => {\n const trimmed = newName.trim();\n const cb = onItemRenameRef.current;\n // Empty or unchanged → close silently without firing the callback.\n if (cb === undefined || trimmed === '' || trimmed === item.name) {\n store.setEditingId(null);\n return true;\n }\n const result = await cb(item, trimmed);\n // Only an explicit `false` keeps the editor open (rejected name).\n const accepted = result !== false;\n if (accepted) store.setEditingId(null);\n return accepted;\n },\n [store, onItemRenameRef]\n );\n\n const deleteItems = useCallback(\n (items?: readonly AssetItem[]): void => {\n const cb = onItemsDeleteRef.current;\n if (cb === undefined) return;\n const targets = resolveTargets(items);\n if (targets.length === 0) return;\n // Move roving focus to a survivor before the data updates, so focus\n // doesn't vanish when the deleted cells unmount.\n const list = displayedRef.current;\n const doomed = new Set(targets.map(it => it.id));\n const focusedId = store.getFocusedId();\n if (focusedId !== null && doomed.has(focusedId)) {\n const from = list.findIndex(it => it.id === focusedId);\n let survivor: string | null = null;\n for (let i = from + 1; i < list.length; i += 1) {\n const it = list[i];\n if (it && !doomed.has(it.id)) {\n survivor = it.id;\n break;\n }\n }\n if (survivor === null) {\n for (let i = from - 1; i >= 0; i -= 1) {\n const it = list[i];\n if (it && !doomed.has(it.id)) {\n survivor = it.id;\n break;\n }\n }\n }\n store.setFocusedId(survivor);\n }\n cb(targets);\n },\n [store, resolveTargets, displayedRef, onItemsDeleteRef]\n );\n\n const createFolder = useCallback((): void => {\n onCreateFolderRef.current?.(currentFolderIdRef.current ?? null);\n }, [onCreateFolderRef, currentFolderIdRef]);\n\n const duplicateItems = useCallback(\n (items?: readonly AssetItem[]): void => {\n const cb = onItemsDuplicateRef.current;\n if (cb === undefined) return;\n const targets = resolveTargets(items);\n if (targets.length === 0) return;\n cb(targets);\n },\n [resolveTargets, onItemsDuplicateRef]\n );\n\n return useMemo<AssetMutationsApi>(\n () => ({\n canRename,\n canDelete,\n canCreateFolder,\n canDuplicate,\n beginRename,\n commitRename,\n cancelRename,\n deleteItems,\n createFolder,\n duplicateItems,\n }),\n [\n canRename,\n canDelete,\n canCreateFolder,\n canDuplicate,\n beginRename,\n commitRename,\n cancelRename,\n deleteItems,\n createFolder,\n duplicateItems,\n ]\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AA8CA;;;;;;;;;;AAUG;AACG;AAGJ;AAEA;AACA;AACA;AACA;;;;;;;;;AAWA;AAEI;AAAW;AACX;AACA;AACF;AAIF;AAEI;;AACA;AACA;AACF;AAIF;AACE;AACF;;AAII;AACA;;AAEA;AACE;AACA;;;;AAIF;AACA;AAAc;AACd;AACF;AAIF;AAEI;;;AAEA;AACA;;;;AAGA;AACA;AACA;;AAEE;;AAEA;AACE;AACA;AACE;;;;AAIJ;AACE;AACE;AACA;AACE;;;;;AAKN;;;;AAON;;AAEA;AAEA;AAEI;;;AAEA;AACA;;;AAEF;AAIF;;;;;;;;;;;AAYG;;;;;;;;;;;AAYA;AAEL;;"}
|
|
@@ -4,7 +4,7 @@ import '../../../utils/devWarn.js';
|
|
|
4
4
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
5
5
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
6
6
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
7
|
-
import '
|
|
7
|
+
import '@vanilla-extract/css';
|
|
8
8
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
9
9
|
import 'react/jsx-runtime';
|
|
10
10
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetNavigation.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetNavigation.js","sources":["src/components/editor/AssetBrowser/useAssetNavigation.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo } from 'react';\n\nimport { useLatest, useNavigationHistory } from '@/hooks';\n\nimport type {\n AssetItem,\n AssetNavigationSource,\n AssetPathSegment,\n} from './AssetBrowser.types';\nimport type { KeyboardEvent } from 'react';\n\nexport interface UseAssetNavigationOptions {\n /** Enables Back/Forward + parent-nav. When false, the hook is a thin pass-through. */\n history: boolean;\n /** Current location (oldest → newest). Used to resolve \"go to parent\". */\n path: readonly AssetPathSegment[];\n /** Seeds the history stack on mount. */\n currentFolderId: string | undefined;\n onNavigate?: (folderId: string, source: AssetNavigationSource) => void;\n onItemOpen?: (item: AssetItem) => void;\n}\n\nexport interface AssetNavigationApi {\n /** Pass-through for navigation (breadcrumb / sidebar / folder open). Pushes onto history. */\n navigate: (folderId: string, source: AssetNavigationSource) => void;\n /** Open a file or enter a folder (file → onItemOpen; folder → navigate). */\n activateItem: (item: AssetItem) => void;\n goBack: () => void;\n goForward: () => void;\n canGoBack: boolean;\n canGoForward: boolean;\n /** Pass-through of the prop so consumers can gate UI on it. */\n history: boolean;\n /** Attach to the AssetBrowser root: Backspace / Alt+ArrowUp → parent folder. */\n handleRootKeyDown: (event: KeyboardEvent) => void;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return (\n target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable\n );\n}\n\n/**\n * Folder navigation + back/forward stack + \"go to parent\" keyboard shortcuts,\n * built on top of the library's `useNavigationHistory` primitive. Every handler\n * has a stable identity (`useCallback`) and reads the latest props through\n * `useLatest` refs, matching `component-patterns.md` rules #3/#11.\n */\nexport function useAssetNavigation(\n options: UseAssetNavigationOptions\n): AssetNavigationApi {\n const { history, path, onNavigate, onItemOpen, currentFolderId } = options;\n\n const histApi = useNavigationHistory({\n initial: currentFolderId,\n enabled: history,\n });\n const { push, canGoBack, canGoForward } = histApi;\n const histGoBack = histApi.goBack;\n const histGoForward = histApi.goForward;\n\n // Keep the back/forward stack in sync with the controlled `currentFolderId`.\n // `useNavigationHistory` only seeds `initial` once on mount, so an out-of-band\n // change (deep link, \"reveal in browser\", or a parent that updates\n // `currentFolderId` without routing through `navigate`) would otherwise leave\n // the stack — and `canGoBack`/`canGoForward` — stale. `push` no-ops when the\n // entry already equals the current one, so navigate/back/forward (which leave\n // `current === currentFolderId`) don't double-push and the forward branch\n // survives; only a genuine external change advances the stack. This is the\n // \"mirror React state into an external store\" bridge that component-patterns.md\n // §2 lists as a legitimate `useEffect` use.\n useEffect(() => {\n if (!history || currentFolderId === undefined) return;\n push(currentFolderId);\n }, [history, currentFolderId, push]);\n\n const onNavigateRef = useLatest(onNavigate);\n const onItemOpenRef = useLatest(onItemOpen);\n const historyRef = useLatest(history);\n const pathRef = useLatest(path);\n\n const navigate = useCallback(\n (folderId: string, source: AssetNavigationSource): void => {\n push(folderId);\n onNavigateRef.current?.(folderId, source);\n },\n [push, onNavigateRef]\n );\n\n const goBack = useCallback((): void => {\n const target = histGoBack();\n if (target === undefined) return;\n onNavigateRef.current?.(target, 'back');\n }, [histGoBack, onNavigateRef]);\n\n const goForward = useCallback((): void => {\n const target = histGoForward();\n if (target === undefined) return;\n onNavigateRef.current?.(target, 'forward');\n }, [histGoForward, onNavigateRef]);\n\n const activateItem = useCallback(\n (item: AssetItem): void => {\n if (item.kind === 'folder') navigate(item.id, 'open');\n else onItemOpenRef.current?.(item);\n },\n [navigate, onItemOpenRef]\n );\n\n const handleRootKeyDown = useCallback(\n (event: KeyboardEvent): void => {\n if (!historyRef.current) return;\n if (isEditableTarget(event.target)) return;\n const goToParent =\n event.key === 'Backspace' || (event.altKey && event.key === 'ArrowUp');\n if (!goToParent) return;\n const currentPath = pathRef.current;\n const parent = currentPath[currentPath.length - 2];\n if (parent) {\n event.preventDefault();\n navigate(parent.id, 'breadcrumb');\n }\n },\n [navigate, historyRef, pathRef]\n );\n\n return useMemo(\n () => ({\n navigate,\n activateItem,\n goBack,\n goForward,\n canGoBack,\n canGoForward,\n history,\n handleRootKeyDown,\n }),\n [\n navigate,\n activateItem,\n goBack,\n goForward,\n canGoBack,\n canGoForward,\n history,\n handleRootKeyDown,\n ]\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAuCA;AACE;AAAsC;AACtC;;;AAKF;AAEA;;;;;AAKG;AACG;AAGJ;;AAGE;AACA;AACD;;AAED;AACA;;;;;;;;;;;;AAaE;;;;AAIF;AACA;AACA;AACA;;;;AAME;AAIF;AACE;;;;AAGF;AAEA;AACE;;;;AAGF;AAEA;AAEI;AAA4B;;AACvB;AACP;AAIF;;;AAGI;;AACA;AAEA;;AACA;;;;AAIE;;;AAMN;;;;;;;;;AAUG;;;;;;;;;AAUA;AAEL;;"}
|
|
@@ -5,7 +5,7 @@ import { useControlledState } from '../../../hooks/useControlledState/useControl
|
|
|
5
5
|
import { useLatest } from '../../../hooks/useLatest/useLatest.js';
|
|
6
6
|
import '../../../hooks/useBreakpoint/useBreakpoint.js';
|
|
7
7
|
import './../../../assets/src/theme/lightTheme.css.ts.vanilla-Ct6f9Iym.css';
|
|
8
|
-
import '
|
|
8
|
+
import '@vanilla-extract/css';
|
|
9
9
|
import './../../../assets/src/theme/darkTheme.css.ts.vanilla-BHZ3ecRn.css';
|
|
10
10
|
import 'react/jsx-runtime';
|
|
11
11
|
import './../../../assets/src/theme/globalScrollbars.css.ts.vanilla-BAJwnUEJ.css';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAssetSelectionController.js","sources":["
|
|
1
|
+
{"version":3,"file":"useAssetSelectionController.js","sources":["src/components/editor/AssetBrowser/useAssetSelectionController.ts"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useTransition,\n} from 'react';\n\nimport { useControlledState, useLatest } from '@/hooks';\n\nimport { indexRange } from './assetBrowserKeyboard';\n\nimport type { AssetItem, AssetSelectionReason } from './AssetBrowser.types';\nimport type { AssetBrowserStore } from './AssetBrowserStore';\nimport type { MouseEvent } from 'react';\n\nexport interface UseAssetSelectionControllerOptions {\n store: AssetBrowserStore;\n /** The filtered + sorted list, in display order (anchor ranges run over it). */\n displayed: readonly AssetItem[];\n selectionMode: 'single' | 'multiple' | false;\n selection?: readonly string[];\n defaultSelection?: readonly string[];\n onSelectionChange?: (\n ids: string[],\n meta: { reason: AssetSelectionReason }\n ) => void;\n}\n\nexport interface AssetSelectionHandlers {\n handleItemClick: (item: AssetItem, index: number, event: MouseEvent) => void;\n selectByKeyboard: (index: number, extend: boolean) => void;\n toggleSelectId: (id: string) => void;\n setSelectionIds: (ids: string[], reason: AssetSelectionReason) => void;\n commitMarquee: (ids: string[], additive: boolean) => void;\n selectAll: () => void;\n clearSelection: () => void;\n contextMenuSelect: (item: AssetItem) => void;\n}\n\nexport interface AssetSelectionController {\n selectionSet: ReadonlySet<string>;\n /** Stable identity — the handlers never change, so they're safe context deps. */\n handlers: AssetSelectionHandlers;\n}\n\nfunction selectableIds(list: readonly AssetItem[]): string[] {\n return list.filter(it => it.selectable !== false).map(it => it.id);\n}\n\n/**\n * Owns selection state and the click/keyboard/marquee gestures that mutate it.\n *\n * Selection stays in React state (so the controlled `selection` prop and\n * `onSelectionChange` work) but is mirrored into the store on commit, letting\n * each cell subscribe to its own `useAssetSelected(id)` slice instead of\n * re-rendering the whole grid. The anchor is tracked by **id**, not index, so\n * shift-ranges survive a re-sort or re-filter between clicks. All handlers have\n * stable identities (`useCallback`) and read the latest props/state through\n * `useLatest` refs, matching `component-patterns.md` rules #3/#11.\n */\nexport function useAssetSelectionController(\n options: UseAssetSelectionControllerOptions\n): AssetSelectionController {\n const { store, displayed, selectionMode, onSelectionChange } = options;\n const [, startTransition] = useTransition();\n\n const [selectionArr, setSelectionArr] = useControlledState<readonly string[]>(\n {\n value: options.selection,\n defaultValue: options.defaultSelection,\n fallback: [],\n }\n );\n\n const selectionSet = useMemo(() => new Set(selectionArr), [selectionArr]);\n\n // Mirror into the store so per-id slices stay in sync. useLayoutEffect runs\n // before paint, so initially-selected items never flash unselected.\n useLayoutEffect(() => {\n store.setSelection(selectionSet);\n }, [store, selectionSet]);\n\n const anchorRef = useRef<string | null>(null);\n\n // Live props/state read inside the stable handlers below.\n const displayedRef = useLatest(displayed);\n const selectionModeRef = useLatest(selectionMode);\n const selectionSetRef = useLatest(selectionSet);\n const onSelectionChangeRef = useLatest(onSelectionChange);\n\n /** Resolve the anchor id to its current position in the displayed list. */\n const anchorIndex = useCallback((): number => {\n if (anchorRef.current === null) return -1;\n return displayedRef.current.findIndex(it => it.id === anchorRef.current);\n }, [displayedRef]);\n\n const commitSelection = useCallback(\n (ids: string[], reason: AssetSelectionReason): void => {\n setSelectionArr(ids);\n onSelectionChangeRef.current?.(ids, { reason });\n },\n [setSelectionArr, onSelectionChangeRef]\n );\n\n const handleItemClick = useCallback(\n (item: AssetItem, index: number, event: MouseEvent): void => {\n store.setFocusedId(item.id);\n if (\n selectionModeRef.current === false ||\n item.selectable === false ||\n item.disabled\n ) {\n return;\n }\n if (selectionModeRef.current === 'single') {\n commitSelection([item.id], 'click');\n anchorRef.current = item.id;\n return;\n }\n if (event.shiftKey) {\n const a = anchorIndex();\n if (a !== -1) {\n const [from, to] = indexRange(a, index);\n commitSelection(\n selectableIds(displayedRef.current.slice(from, to + 1)),\n 'click'\n );\n return;\n }\n }\n if (event.ctrlKey || event.metaKey) {\n const next = new Set(selectionSetRef.current);\n if (next.has(item.id)) next.delete(item.id);\n else next.add(item.id);\n commitSelection(Array.from(next), 'click');\n anchorRef.current = item.id;\n return;\n }\n commitSelection([item.id], 'click');\n anchorRef.current = item.id;\n },\n [\n store,\n commitSelection,\n anchorIndex,\n selectionModeRef,\n displayedRef,\n selectionSetRef,\n ]\n );\n\n const selectByKeyboard = useCallback(\n (index: number, extend: boolean): void => {\n const item = displayedRef.current[index];\n if (!item) return;\n if (extend) {\n const a = anchorIndex();\n if (a !== -1) {\n const [from, to] = indexRange(a, index);\n commitSelection(\n selectableIds(displayedRef.current.slice(from, to + 1)),\n 'keyboard'\n );\n return;\n }\n }\n commitSelection(item.selectable === false ? [] : [item.id], 'keyboard');\n anchorRef.current = item.id;\n },\n [commitSelection, anchorIndex, displayedRef]\n );\n\n const toggleSelectId = useCallback(\n (id: string): void => {\n const next = new Set(selectionSetRef.current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n commitSelection(Array.from(next), 'keyboard');\n },\n [commitSelection, selectionSetRef]\n );\n\n const setSelectionIds = useCallback(\n (ids: string[], reason: AssetSelectionReason): void => {\n commitSelection(ids, reason);\n },\n [commitSelection]\n );\n\n const commitMarquee = useCallback(\n (ids: string[], additive: boolean): void => {\n startTransition(() => {\n if (additive) {\n const next = new Set(selectionSetRef.current);\n ids.forEach(id => next.add(id));\n commitSelection(Array.from(next), 'marquee');\n return;\n }\n commitSelection(ids, 'marquee');\n });\n },\n [commitSelection, selectionSetRef]\n );\n\n const selectAll = useCallback((): void => {\n startTransition(() => {\n commitSelection(selectableIds(displayedRef.current), 'selectAll');\n });\n }, [commitSelection, displayedRef]);\n\n const clearSelection = useCallback((): void => {\n commitSelection([], 'clear');\n }, [commitSelection]);\n\n const contextMenuSelect = useCallback(\n (item: AssetItem): void => {\n store.setFocusedId(item.id);\n if (!selectionSetRef.current.has(item.id) && item.selectable !== false) {\n commitSelection([item.id], 'contextMenu');\n }\n anchorRef.current = item.id;\n },\n [store, commitSelection, selectionSetRef]\n );\n\n const handlers = useMemo<AssetSelectionHandlers>(\n () => ({\n handleItemClick,\n selectByKeyboard,\n toggleSelectId,\n setSelectionIds,\n commitMarquee,\n selectAll,\n clearSelection,\n contextMenuSelect,\n }),\n [\n handleItemClick,\n selectByKeyboard,\n toggleSelectId,\n setSelectionIds,\n commitMarquee,\n selectAll,\n clearSelection,\n contextMenuSelect,\n ]\n );\n\n return { selectionSet, handlers };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAgDA;;AAEA;AAEA;;;;;;;;;;AAUG;AACG;;AAIJ;AAEA;;;AAII;AACD;AAGH;;;;AAKE;AACF;AAEA;;AAGA;AACA;AACA;AACA;;AAGA;AACE;;AACA;AACF;;;;AAME;;AAME;AACA;;;;;AAOA;;AAEE;;;AAGF;AACE;AACA;AACE;AACA;;;;;;AASF;AAAuB;;AAClB;;AAEL;;;;AAIF;AACF;;;;;;;AAQC;;;AAMC;;;AAEE;AACA;AACE;AACA;;;;;AAQJ;;AAKJ;;AAGI;AAAkB;;AACb;;AAEP;;AAME;AACF;;;;;AASM;;;;AAIF;AACF;AACF;AAIF;;;AAGE;AACF;AAEA;AACE;AACF;AAEA;AAEI;AACA;;;AAGA;;AAKJ;;;;;;;;;AAUG;;;;;;;;;AAUA;AAGH;AACF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatActionBar.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatActionBar.js","sources":["src/components/editor/ChatPanel/ChatActionBar.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { actionBarStyle } from './ChatPanel.css';\n\nimport type { ChatActionBarProps } from './ChatPanel.types';\n\nexport const ChatActionBar = /*#__PURE__*/ React.memo<ChatActionBarProps>(\n ({ children, className, style, testId, ref, ...rest }) => {\n return (\n <div\n ref={ref}\n className={cx(actionBarStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n );\n }\n);\n\nChatActionBar.displayName = 'ChatActionBar';\n"],"names":[],"mappings":";;;;;;AAUO;;AAaL;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatAttachment.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatAttachment.js","sources":["src/components/editor/ChatPanel/ChatAttachment.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback } from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport {\n MiniCloseIcon,\n MiniFileIcon,\n MiniImageIcon,\n MiniCodeIcon,\n MiniSelectionIcon,\n} from './ChatIcons';\nimport {\n attachmentChipStyle,\n attachmentChipIconStyle,\n attachmentChipNameStyle,\n attachmentChipRemoveStyle,\n attachmentThumbnailStyle,\n} from './ChatPanel.css';\n\nimport type { ChatAttachmentChipProps } from './ChatPanel.types';\n\nconst TYPE_ICONS: Record<string, React.FC> = {\n file: MiniFileIcon,\n image: MiniImageIcon,\n code: MiniCodeIcon,\n selection: MiniSelectionIcon,\n};\n\n// ─── Component ───────────────────────────────────────────────────\n\nexport const ChatAttachmentChip =\n /*#__PURE__*/ React.memo<ChatAttachmentChipProps>(\n ({\n attachment,\n onRemove,\n onClick,\n removable = false,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const handleClick = useCallback(() => {\n onClick?.(attachment);\n }, [onClick, attachment]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.(attachment);\n }\n },\n [onClick, attachment]\n );\n\n const handleRemove = useCallback(\n (e: React.MouseEvent) => {\n e.stopPropagation();\n onRemove?.(attachment.id);\n },\n [onRemove, attachment.id]\n );\n\n const TypeIcon = TYPE_ICONS[attachment.type] ?? MiniFileIcon;\n const isClickable = !!onClick;\n\n return (\n <div\n ref={ref}\n className={cx(attachmentChipStyle, className)}\n style={style}\n data-testid={testId}\n data-clickable={isClickable || undefined}\n onClick={isClickable ? handleClick : undefined}\n onKeyDown={isClickable ? handleKeyDown : undefined}\n role={isClickable ? 'button' : undefined}\n tabIndex={isClickable ? 0 : undefined}\n {...rest}\n >\n {attachment.type === 'image' && attachment.thumbnailUrl ? (\n <img\n src={attachment.thumbnailUrl}\n alt={attachment.name}\n className={attachmentThumbnailStyle}\n />\n ) : (\n <span className={attachmentChipIconStyle}>\n <TypeIcon />\n </span>\n )}\n\n <span className={attachmentChipNameStyle}>{attachment.name}</span>\n\n {removable && (\n <button\n type=\"button\"\n className={attachmentChipRemoveStyle}\n onClick={handleRemove}\n aria-label={`Remove ${attachment.name}`}\n >\n <MiniCloseIcon />\n </button>\n )}\n </div>\n );\n }\n );\n\nChatAttachmentChip.displayName = 'ChatAttachmentChip';\n"],"names":[],"mappings":";;;;;;;AAuBA;AACE;AACA;AACA;AACA;;AAGF;;AAGE;AAYI;AACE;AACF;AAEA;AAEI;;AAEE;;AAEJ;AAIF;;AAGI;;;AAMJ;AAEA;AAuCF;AAGJ;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatBubble.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatBubble.js","sources":["src/components/editor/ChatPanel/ChatBubble.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { bubbleRecipe } from './ChatPanel.css';\n\nimport type { ChatBubbleProps } from './ChatPanel.types';\n\nexport const ChatBubble = /*#__PURE__*/ React.memo<ChatBubbleProps>(\n ({\n role = 'assistant',\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n return (\n <div\n ref={ref}\n className={cx(bubbleRecipe({ role }), className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n );\n }\n);\n\nChatBubble.displayName = 'ChatBubble';\n"],"names":[],"mappings":";;;;;;AAUO;AAUH;AAWF;AAGF;;"}
|
|
@@ -89,6 +89,12 @@ import '../../Icons/GitBranchIcon.js';
|
|
|
89
89
|
import '../../Icons/BugIcon.js';
|
|
90
90
|
import '../../Icons/MinusIcon.js';
|
|
91
91
|
import '../../Icons/PinIcon.js';
|
|
92
|
+
import '../../Icons/OrbitIcon.js';
|
|
93
|
+
import '../../Icons/RotateIcon.js';
|
|
94
|
+
import '../../Icons/SpinIcon.js';
|
|
95
|
+
import '../../Icons/CameraIcon.js';
|
|
96
|
+
import '../../Icons/CubeIcon.js';
|
|
97
|
+
import '../../Icons/ZoomFitIcon.js';
|
|
92
98
|
import { useIsMounted } from '../../../hooks/useIsMounted/useIsMounted.js';
|
|
93
99
|
import { cx } from '../../../utils/cx.js';
|
|
94
100
|
import { codeBlockHeaderStyle, codeBlockLanguageStyle, codeBlockActionsStyle, codeBlockCopyButtonStyle, codeBlockLineNumbersColumnStyle, codeBlockPreStyle, codeBlockMaxHeightVar, codeBlockContentWithLineNumbersStyle, codeBlockContentStyle, codeBlockContainerStyle } from './ChatPanel.css.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatCodeBlock.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatCodeBlock.js","sources":["src/components/editor/ChatPanel/ChatCodeBlock.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useState, useCallback } from 'react';\n\nimport { CheckIcon, CopyIcon } from '@/components/Icons';\nimport { useIsMounted } from '@/hooks/useIsMounted';\nimport { cx } from '@/utils/cx';\n\nimport {\n codeBlockContainerStyle,\n codeBlockHeaderStyle,\n codeBlockLanguageStyle,\n codeBlockActionsStyle,\n codeBlockCopyButtonStyle,\n codeBlockContentStyle,\n codeBlockContentWithLineNumbersStyle,\n codeBlockLineNumbersColumnStyle,\n codeBlockPreStyle,\n codeBlockMaxHeightVar,\n} from './ChatPanel.css';\n\nimport type { ChatCodeBlockProps } from './ChatPanel.types';\n\nexport const ChatCodeBlock = /*#__PURE__*/ React.memo<ChatCodeBlockProps>(\n ({\n code,\n language,\n copyable = true,\n lineNumbers = false,\n maxHeight = 400,\n actions,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const [copied, setCopied] = useState(false);\n const isMounted = useIsMounted();\n\n const handleCopy = useCallback(() => {\n navigator.clipboard\n .writeText(code)\n .then(() => {\n // clipboard.writeText can't be cancelled, so guard the state writes:\n // the block may unmount before it resolves, or within the 2s reset.\n if (!isMounted()) return;\n setCopied(true);\n setTimeout(() => {\n if (isMounted()) setCopied(false);\n }, 2000);\n })\n .catch(() => {\n // Fallback: older browsers — no-op\n });\n }, [code, isMounted]);\n\n const lines = code.split('\\n');\n const showHeader = language != null || copyable || actions != null;\n\n return (\n <div\n ref={ref}\n className={cx(codeBlockContainerStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {showHeader && (\n <div className={codeBlockHeaderStyle}>\n {language != null && (\n <span className={codeBlockLanguageStyle}>{language}</span>\n )}\n <div className={codeBlockActionsStyle}>\n {actions}\n {copyable && (\n <button\n type=\"button\"\n className={codeBlockCopyButtonStyle}\n onClick={handleCopy}\n aria-label={copied ? 'Copied' : 'Copy code'}\n >\n {copied ? (\n <CheckIcon size={12} decorative />\n ) : (\n <CopyIcon size={12} decorative />\n )}\n </button>\n )}\n </div>\n </div>\n )}\n\n <div\n className={cx(\n codeBlockContentStyle,\n lineNumbers && codeBlockContentWithLineNumbersStyle\n )}\n style={assignInlineVars({\n [codeBlockMaxHeightVar]: `${maxHeight}px`,\n })}\n data-testid={testId ? `${testId}-content` : undefined}\n >\n {lineNumbers && (\n <div\n className={codeBlockLineNumbersColumnStyle}\n aria-hidden=\"true\"\n data-testid={testId ? `${testId}-line-numbers` : undefined}\n >\n {lines.map((_, i) => (\n <div key={i}>{i + 1}</div>\n ))}\n </div>\n )}\n <pre className={codeBlockPreStyle}>\n <code>{code}</code>\n </pre>\n </div>\n </div>\n );\n }\n);\n\nChatCodeBlock.displayName = 'ChatCodeBlock';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBO;;AAeH;AAEA;AACE;;;;;;;;;AAQM;;;AAEJ;;;AAGA;AACJ;;;AAKA;AAuCQ;AACD;AAoBT;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatContextChip.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatContextChip.js","sources":["src/components/editor/ChatPanel/ChatContextChip.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { MiniCloseIcon } from './ChatIcons';\nimport {\n contextChipStyle,\n contextChipIconStyle,\n contextChipLabelStyle,\n contextChipItemsStyle,\n contextChipDismissStyle,\n} from './ChatPanel.css';\n\nimport type { ChatContextChipProps } from './ChatPanel.types';\n\nexport const ChatContextChip = /*#__PURE__*/ React.memo<ChatContextChipProps>(\n ({\n label,\n items,\n icon,\n onDismiss,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n return (\n <div\n ref={ref}\n className={cx(contextChipStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {icon && <span className={contextChipIconStyle}>{icon}</span>}\n <span className={contextChipLabelStyle}>{label}:</span>\n <span className={contextChipItemsStyle}>{items.join(', ')}</span>\n {onDismiss && (\n <button\n type=\"button\"\n className={contextChipDismissStyle}\n onClick={onDismiss}\n aria-label={`Dismiss ${label}`}\n >\n <MiniCloseIcon />\n </button>\n )}\n </div>\n );\n }\n);\n\nChatContextChip.displayName = 'ChatContextChip';\n"],"names":[],"mappings":";;;;;;;AAiBO;AAYH;AAuBF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatEmptyState.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatEmptyState.js","sources":["src/components/editor/ChatPanel/ChatEmptyState.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback } from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport {\n emptyStateStyle,\n emptyStateIconStyle,\n emptyStateTitleStyle,\n emptyStateDescriptionStyle,\n emptyStateSuggestionsStyle,\n emptyStateSuggestionStyle,\n} from './ChatPanel.css';\n\nimport type { ChatEmptyStateProps } from './ChatPanel.types';\n\nexport const ChatEmptyState = /*#__PURE__*/ React.memo<ChatEmptyStateProps>(\n ({\n title,\n description,\n icon,\n suggestions,\n onSuggestionClick,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const handleSuggestionClick = useCallback(\n (suggestion: string) => {\n onSuggestionClick?.(suggestion);\n },\n [onSuggestionClick]\n );\n\n return (\n <div\n ref={ref}\n className={cx(emptyStateStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {icon && <div className={emptyStateIconStyle}>{icon}</div>}\n {title && <div className={emptyStateTitleStyle}>{title}</div>}\n {description && (\n <div className={emptyStateDescriptionStyle}>{description}</div>\n )}\n {suggestions && suggestions.length > 0 && (\n <div className={emptyStateSuggestionsStyle}>\n {suggestions.map(suggestion => (\n <button\n key={suggestion}\n type=\"button\"\n className={emptyStateSuggestionStyle}\n onClick={() => {\n handleSuggestionClick(suggestion);\n }}\n >\n {suggestion}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n }\n);\n\nChatEmptyState.displayName = 'ChatEmptyState';\n"],"names":[],"mappings":";;;;;;AAiBO;AAaH;AAEI;AACF;AAIF;;;AA+BF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatIcons.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatIcons.js","sources":["src/components/editor/ChatPanel/ChatIcons.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\n/**\n * Shared mini-icons for Chat components.\n * These use smaller viewBoxes (8x8, 16x16) than the library's Icon system (24x24)\n * and are designed for inline use in compact chat UI elements.\n */\n\nexport const MiniCloseIcon: React.FC = () => (\n <svg width=\"8\" height=\"8\" viewBox=\"0 0 8 8\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M1 1l6 6M7 1L1 7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n);\n\nexport const MiniFileIcon: React.FC = () => (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M9 2H4.5A1.5 1.5 0 003 3.5v9A1.5 1.5 0 004.5 14h7a1.5 1.5 0 001.5-1.5V6L9 2z\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M9 2v4h4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const MiniImageIcon: React.FC = () => (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"2\"\n y=\"2\"\n width=\"12\"\n height=\"12\"\n rx=\"1.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <circle cx=\"5.5\" cy=\"5.5\" r=\"1.5\" fill=\"currentColor\" />\n <path\n d=\"M2 11l3-3 2 2 3-3 4 4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const MiniCodeIcon: React.FC = () => (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5 4L1 8l4 4M11 4l4 4-4 4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const MiniSelectionIcon: React.FC = () => (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <rect\n x=\"2\"\n y=\"2\"\n width=\"5\"\n height=\"5\"\n rx=\"0.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <rect\n x=\"9\"\n y=\"9\"\n width=\"5\"\n height=\"5\"\n rx=\"0.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </svg>\n);\n\nexport const MiniWrenchIcon: React.FC = () => (\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M14.25 1.75L12.5 3.5L13 5L11.5 6.5L10.5 5.5L5.5 10.5L6.5 11.5L5 13L3.5 12.5L1.75 14.25\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M8.5 2.5L10 4L8 6L6.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nexport const MiniChevronIcon: React.FC<{ size?: number }> = ({ size = 10 }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M4.5 3L7.5 6L4.5 9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n"],"names":[],"mappings":";;;AAIA;;;;AAIG;;AAaI;;;AAqEA;AA6BA;AAyBA;;"}
|
|
@@ -89,6 +89,12 @@ import '../../Icons/GitBranchIcon.js';
|
|
|
89
89
|
import '../../Icons/BugIcon.js';
|
|
90
90
|
import '../../Icons/MinusIcon.js';
|
|
91
91
|
import '../../Icons/PinIcon.js';
|
|
92
|
+
import '../../Icons/OrbitIcon.js';
|
|
93
|
+
import '../../Icons/RotateIcon.js';
|
|
94
|
+
import '../../Icons/SpinIcon.js';
|
|
95
|
+
import '../../Icons/CameraIcon.js';
|
|
96
|
+
import '../../Icons/CubeIcon.js';
|
|
97
|
+
import '../../Icons/ZoomFitIcon.js';
|
|
92
98
|
import { cx } from '../../../utils/cx.js';
|
|
93
99
|
import { ChatAttachmentChip } from './ChatAttachment.js';
|
|
94
100
|
import { inputPrefixStyle, inputAttachmentsStyle, inputWrapperStyle, inputTextareaStyle, inputMaxHeightVar, inputBottomBarStyle, inputStopButtonStyle, inputButtonStyle, inputContainerStyle } from './ChatPanel.css.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatInput.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatInput.js","sources":["src/components/editor/ChatPanel/ChatInput.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useCallback, useId } from 'react';\n\nimport { SendIcon, StopIcon } from '@/components/Icons';\nimport { cx } from '@/utils/cx';\n\nimport { ChatAttachmentChip } from './ChatAttachment';\nimport {\n inputContainerStyle,\n inputAttachmentsStyle,\n inputPrefixStyle,\n inputWrapperStyle,\n inputTextareaStyle,\n inputButtonStyle,\n inputStopButtonStyle,\n inputMaxHeightVar,\n inputBottomBarStyle,\n} from './ChatPanel.css';\nimport { useChatInput } from './useChatInput';\n\nimport type { ChatInputProps } from './ChatPanel.types';\n\nexport const ChatInput = /*#__PURE__*/ React.memo<ChatInputProps>(\n ({\n value: controlledValue,\n onChange: controlledOnChange,\n onSubmit,\n onStop,\n placeholder = 'Type a message...',\n streaming = false,\n disabled = false,\n submitKey = 'enter',\n maxLines = 6,\n attachments,\n onRemoveAttachment,\n prefix,\n suffix,\n toolbar,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const inputId = useId();\n\n const handleSubmit = useCallback(\n (text: string) => {\n onSubmit?.(text, attachments ?? []);\n },\n [onSubmit, attachments]\n );\n\n const chatInput = useChatInput({\n submitKey,\n onSubmit: handleSubmit,\n maxLines,\n attachmentsCount: attachments?.length ?? 0,\n });\n\n // Support controlled mode\n const currentValue = controlledValue ?? chatInput.value;\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n if (controlledOnChange) {\n controlledOnChange(e.target.value);\n }\n chatInput.handleChange(e);\n },\n [controlledOnChange, chatInput]\n );\n\n const attachmentsCount = attachments?.length ?? 0;\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n // In controlled mode, override the internal value check\n if (controlledValue !== undefined) {\n const isSubmitKey =\n submitKey === 'enter'\n ? e.key === 'Enter' && !e.shiftKey\n : e.key === 'Enter' && (e.ctrlKey || e.metaKey);\n\n if (isSubmitKey && (controlledValue.trim() || attachmentsCount > 0)) {\n e.preventDefault();\n onSubmit?.(controlledValue.trim(), attachments ?? []);\n return;\n }\n }\n chatInput.handleKeyDown(e);\n },\n [\n controlledValue,\n submitKey,\n onSubmit,\n attachments,\n attachmentsCount,\n chatInput,\n ]\n );\n\n const handleSendClick = useCallback(() => {\n const val = controlledValue ?? chatInput.value;\n const canSubmit = val.trim() || attachmentsCount > 0;\n if (canSubmit) {\n onSubmit?.(val.trim(), attachments ?? []);\n if (controlledValue === undefined) {\n chatInput.clear();\n }\n }\n }, [controlledValue, chatInput, onSubmit, attachments, attachmentsCount]);\n\n const canSubmit =\n (currentValue.trim().length > 0 || attachmentsCount > 0) && !disabled;\n\n const lineHeight = 18; // approximate line-height in px\n const maxHeightPx = `${maxLines * lineHeight}px`;\n\n const shortcutLabel =\n submitKey === 'enter'\n ? 'Enter to send, Shift+Enter for newline'\n : 'Ctrl+Enter to send, Enter for newline';\n\n return (\n <div\n ref={ref}\n className={cx(inputContainerStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {prefix && <div className={inputPrefixStyle}>{prefix}</div>}\n\n {attachments && attachments.length > 0 && (\n <div className={inputAttachmentsStyle}>\n {attachments.map(att => (\n <ChatAttachmentChip\n key={att.id}\n attachment={att}\n removable={!!onRemoveAttachment}\n onRemove={onRemoveAttachment}\n />\n ))}\n </div>\n )}\n\n <div className={inputWrapperStyle}>\n <textarea\n ref={chatInput.textareaRef}\n id={`chat-input-${inputId}`}\n className={inputTextareaStyle}\n style={assignInlineVars({\n [inputMaxHeightVar]: maxHeightPx,\n })}\n value={currentValue}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n rows={1}\n aria-label=\"Chat message input\"\n aria-keyshortcuts={shortcutLabel}\n />\n\n {suffix}\n\n <div className={inputBottomBarStyle}>\n {toolbar}\n\n {streaming ? (\n <button\n type=\"button\"\n className={inputStopButtonStyle}\n onClick={onStop}\n aria-label=\"Stop generating\"\n >\n <StopIcon size={12} decorative />\n </button>\n ) : (\n <button\n type=\"button\"\n className={inputButtonStyle}\n onClick={handleSendClick}\n disabled={!canSubmit}\n aria-label=\"Send message\"\n >\n <SendIcon size={14} decorative />\n </button>\n )}\n </div>\n </div>\n </div>\n );\n }\n);\n\nChatInput.displayName = 'ChatInput';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBO;AAsBH;AAEA;;AAGE;;;AAMA;;AAEA;AACD;;AAGD;AAEA;;AAGM;;AAEF;AACF;AAIF;AAEA;;AAGI;AACE;;AAGI;AAEJ;;;;;;AAMF;AACF;;;;;;;AAQC;AAGH;AACE;;;;AAIE;;;;AAIJ;AAEA;AAGA;AACA;AAEA;AAEI;;;;;AAyEN;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatInputToolbar.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatInputToolbar.js","sources":["src/components/editor/ChatPanel/ChatInputToolbar.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { inputToolbarStyle } from './ChatPanel.css';\n\nimport type { ChatInputToolbarProps } from './ChatPanel.types';\n\nexport const ChatInputToolbar = /*#__PURE__*/ React.memo<ChatInputToolbarProps>(\n ({ children, className, style, testId, ref, ...rest }) => {\n return (\n <div\n ref={ref}\n className={cx(inputToolbarStyle, className)}\n style={style}\n data-testid={testId}\n role=\"toolbar\"\n aria-label=\"Chat input actions\"\n {...rest}\n >\n {children}\n </div>\n );\n }\n);\n\nChatInputToolbar.displayName = 'ChatInputToolbar';\n"],"names":[],"mappings":";;;;;;AAUO;AAEH;AAaF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatMarkdownRenderer.js","sources":["../../../../../../src/components/editor/ChatPanel/ChatMarkdownRenderer.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;AAwCA;AACE;AACF;AAEA;;;;;;AAWE;AAIE;AACE;AACA;AACD;AACD;AACE;AACA;AAQD;AACD;AACE;;AAcD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;;AAGH;;;;AAMI;;AACA;AACE;;AAEE;;;;;;;;;AAWN;AACE;;AAEF;AACA;;AAGF;AACF;AAoBA;AACE;;;AAIA;;;AAIE;AACE;;;;;;AAOA;;AAEA;AACA;;AAEE;;;;AAIA;AACA;;AAED;;;;AAKH;;AAEE;;;;;;;;;AAUE;;AAEA;AACD;AACD;;;;AAKF;;AAEE;AACE;AACA;;AAEF;;;;AAKF;;AAEE;AACE;AACA;;;;;;AAOJ;;AAEE;AACE;AACA;;;;;;AAOJ;AAEE;AACA;AACA;AAEA;AAEK;AACA;;;AAIL;AACA;;;;;AAIqB;AACnB;AAAW;AACX;AAAU;AACV;AACF;AAEA;;AAEA;AACE;AACA;;AAEF;;;;;AAMF;;AAEE;AAEE;AACA;AACA;AACA;AACA;AACA;;;AAIF;AACA;;AAEF;;AAGF;AACF;AAEA;;;;;;;;;;;;;;;;;AAiBG;;AAED;;AAcI;;AAMA;AASM;AACA;AACE;;;;AAcE;;;AAOF;;AAUA;;AAUA;;AAMA;;AAQA;AACE;;AAEA;AACA;AACA;;AAWgB;;;;AAsClB;AACE;;;AAKZ;AAGJ;;"}
|
|
1
|
+
{"version":3,"file":"ChatMarkdownRenderer.js","sources":["src/components/editor/ChatPanel/ChatMarkdownRenderer.tsx"],"sourcesContent":["'use client';\n\nimport React, { useMemo } from 'react';\n\nimport { Code } from '@/components/primitives/Code';\nimport { cx } from '@/utils/cx';\n\nimport { ChatCodeBlock } from './ChatCodeBlock';\nimport {\n markdownBlockquoteStyle,\n markdownHeadingStyle,\n markdownHrStyle,\n markdownLinkStyle,\n markdownListItemStyle,\n markdownListStyle,\n markdownParagraphStyle,\n markdownRootStyle,\n markdownTableStyle,\n markdownTdStyle,\n markdownThStyle,\n} from './ChatPanel.css';\n\nimport type { ChatMarkdownRendererProps } from './ChatMarkdownRenderer.types';\n\n// ─────────────────────────────────────────────────────────────────\n// Minimal markdown → React renderer.\n//\n// Covers what chat LLMs typically produce: paragraphs, headings,\n// lists, blockquotes, horizontal rules, inline emphasis / code, links,\n// fenced code blocks, and (with `gfm`) pipe tables.\n//\n// Intentionally lightweight — for advanced CommonMark edge cases or\n// full AST control, consumers can supply their own `renderContent`\n// function on `ChatMessage`.\n// ─────────────────────────────────────────────────────────────────\n\ninterface InlineRenderOptions {\n linkTarget: '_self' | '_blank';\n}\n\nfunction escapeHtmlInText(text: string): string {\n return text;\n}\n\nfunction renderInline(\n text: string,\n options: InlineRenderOptions,\n keyPrefix: string\n): React.ReactNode[] {\n const parts: React.ReactNode[] = [];\n let rest = text;\n let index = 0;\n\n // Ordered by precedence. Each pattern captures the full match so we\n // can slice around it, and the content(s) we want to render.\n const patterns: Array<{\n regex: RegExp;\n render: (match: RegExpExecArray, key: string) => React.ReactNode;\n }> = [\n {\n regex: /`([^`]+)`/,\n render: (m, key) => <Code key={key}>{m[1]}</Code>,\n },\n {\n regex: /!\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/,\n render: (m, key) => (\n <img\n key={key}\n src={m[2]}\n alt={m[1] ?? ''}\n style={{ maxWidth: '100%' }}\n />\n ),\n },\n {\n regex: /\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/,\n render: (m, key) => (\n <a\n key={key}\n href={m[2]}\n target={options.linkTarget}\n rel={\n options.linkTarget === '_blank' ? 'noopener noreferrer' : undefined\n }\n className={markdownLinkStyle}\n >\n {m[1]}\n </a>\n ),\n },\n {\n regex: /\\*\\*([^*]+)\\*\\*/,\n render: (m, key) => <strong key={key}>{m[1]}</strong>,\n },\n {\n regex: /__([^_]+)__/,\n render: (m, key) => <strong key={key}>{m[1]}</strong>,\n },\n {\n regex: /(?<![*\\w])\\*([^*\\n]+)\\*(?![*\\w])/,\n render: (m, key) => <em key={key}>{m[1]}</em>,\n },\n {\n regex: /(?<![_\\w])_([^_\\n]+)_(?![_\\w])/,\n render: (m, key) => <em key={key}>{m[1]}</em>,\n },\n {\n regex: /~~([^~]+)~~/,\n render: (m, key) => <del key={key}>{m[1]}</del>,\n },\n ];\n\n while (rest.length > 0) {\n let best: { start: number; length: number; node: React.ReactNode } | null =\n null;\n\n for (const { regex, render } of patterns) {\n const match = regex.exec(rest);\n if (!match) continue;\n if (best === null || match.index < best.start) {\n best = {\n start: match.index,\n length: match[0].length,\n node: render(match, `${keyPrefix}-i-${index++}`),\n };\n }\n }\n\n if (!best) {\n parts.push(escapeHtmlInText(rest));\n break;\n }\n\n if (best.start > 0) {\n parts.push(escapeHtmlInText(rest.slice(0, best.start)));\n }\n parts.push(best.node);\n rest = rest.slice(best.start + best.length);\n }\n\n return parts;\n}\n\ninterface Block {\n type:\n | 'paragraph'\n | 'heading'\n | 'list'\n | 'orderedList'\n | 'blockquote'\n | 'codeBlock'\n | 'hr'\n | 'table';\n content?: string;\n level?: number;\n items?: string[];\n language?: string;\n rows?: string[][];\n align?: Array<'left' | 'right' | 'center' | null>;\n}\n\nfunction parseBlocks(source: string, gfm: boolean): Block[] {\n const lines = source.replace(/\\r\\n/g, '\\n').split('\\n');\n const blocks: Block[] = [];\n\n let i = 0;\n while (i < lines.length) {\n const line = lines[i] ?? '';\n\n // Skip blank lines between blocks.\n if (/^\\s*$/.test(line)) {\n i++;\n continue;\n }\n\n // Fenced code block\n const fenceMatch = /^```(\\w+)?\\s*$/.exec(line);\n if (fenceMatch) {\n const language = fenceMatch[1];\n const codeLines: string[] = [];\n i++;\n while (i < lines.length && !/^```\\s*$/.test(lines[i] ?? '')) {\n codeLines.push(lines[i] ?? '');\n i++;\n }\n i++; // skip closing fence\n blocks.push({\n type: 'codeBlock',\n content: codeLines.join('\\n'),\n language,\n });\n continue;\n }\n\n // Horizontal rule\n if (/^\\s*(---|\\*\\*\\*|___)\\s*$/.test(line)) {\n blocks.push({ type: 'hr' });\n i++;\n continue;\n }\n\n // Heading (# through ######)\n const headingMatch = /^(#{1,6})\\s+(.*)$/.exec(line);\n if (headingMatch) {\n const hashes = headingMatch[1] ?? '';\n const headingContent = headingMatch[2] ?? '';\n blocks.push({\n type: 'heading',\n level: hashes.length,\n content: headingContent.trim(),\n });\n i++;\n continue;\n }\n\n // Blockquote — consecutive `> ` lines\n if (/^\\s*>/.test(line)) {\n const quoteLines: string[] = [];\n while (i < lines.length && /^\\s*>/.test(lines[i] ?? '')) {\n quoteLines.push((lines[i] ?? '').replace(/^\\s*>\\s?/, ''));\n i++;\n }\n blocks.push({ type: 'blockquote', content: quoteLines.join('\\n') });\n continue;\n }\n\n // Unordered list — lines beginning with `- `, `* `, or `+ `\n if (/^\\s*[-*+]\\s+/.test(line)) {\n const items: string[] = [];\n while (i < lines.length && /^\\s*[-*+]\\s+/.test(lines[i] ?? '')) {\n items.push((lines[i] ?? '').replace(/^\\s*[-*+]\\s+/, ''));\n i++;\n }\n blocks.push({ type: 'list', items });\n continue;\n }\n\n // Ordered list — `1. ...`\n if (/^\\s*\\d+\\.\\s+/.test(line)) {\n const items: string[] = [];\n while (i < lines.length && /^\\s*\\d+\\.\\s+/.test(lines[i] ?? '')) {\n items.push((lines[i] ?? '').replace(/^\\s*\\d+\\.\\s+/, ''));\n i++;\n }\n blocks.push({ type: 'orderedList', items });\n continue;\n }\n\n // GFM pipe table — a header row, a separator `---|---`, then rows.\n if (\n gfm &&\n /\\|/.test(line) &&\n i + 1 < lines.length &&\n /^\\s*\\|?\\s*:?-+:?\\s*(\\|\\s*:?-+:?\\s*)+\\|?\\s*$/.test(lines[i + 1] ?? '')\n ) {\n const split = (row: string) =>\n row\n .replace(/^\\s*\\|/, '')\n .replace(/\\|\\s*$/, '')\n .split('|')\n .map(cell => cell.trim());\n\n const header = split(line);\n const rawAlign = split(lines[i + 1] ?? '');\n const align = rawAlign.map(cell => {\n const left = cell.startsWith(':');\n const right = cell.endsWith(':');\n if (left && right) return 'center' as const;\n if (right) return 'right' as const;\n if (left) return 'left' as const;\n return null;\n });\n\n const rows: string[][] = [header];\n i += 2;\n while (i < lines.length && /\\|/.test(lines[i] ?? '')) {\n rows.push(split(lines[i] ?? ''));\n i++;\n }\n blocks.push({ type: 'table', rows, align });\n continue;\n }\n\n // Paragraph — consecutive non-blank non-block-starting lines.\n const paraLines: string[] = [];\n while (i < lines.length) {\n const ln = lines[i] ?? '';\n if (\n /^\\s*$/.test(ln) ||\n /^```/.test(ln) ||\n /^(#{1,6})\\s+/.test(ln) ||\n /^\\s*>/.test(ln) ||\n /^\\s*[-*+]\\s+/.test(ln) ||\n /^\\s*\\d+\\.\\s+/.test(ln) ||\n /^\\s*(---|\\*\\*\\*|___)\\s*$/.test(ln)\n ) {\n break;\n }\n paraLines.push(ln);\n i++;\n }\n blocks.push({ type: 'paragraph', content: paraLines.join('\\n') });\n }\n\n return blocks;\n}\n\n/**\n * Lightweight markdown renderer for chat messages.\n *\n * Pass it to `ChatMessage.renderContent` to render assistant responses\n * with bold / italic / inline code, links, fenced code blocks, lists,\n * blockquotes, horizontal rules, and GFM pipe tables.\n *\n * For advanced markdown features, supply a custom `renderContent`\n * function that uses your markdown library of choice.\n *\n * @example\n * ```tsx\n * <ChatMessage\n * message={msg}\n * renderContent={content => <ChatMarkdownRenderer content={content} />}\n * />\n * ```\n */\nexport const ChatMarkdownRenderer =\n /*#__PURE__*/ React.memo<ChatMarkdownRendererProps>(\n ({\n content,\n gfm = true,\n linkTarget = '_blank',\n components,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const blocks = useMemo(() => parseBlocks(content, gfm), [content, gfm]);\n\n const CodeBlock =\n components?.codeBlock ??\n (({ code, language }: { code: string; language?: string }) => (\n <ChatCodeBlock code={code} language={language} />\n ));\n\n return (\n <div\n ref={ref}\n className={cx(markdownRootStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {blocks.map((block, idx) => {\n const key = `b-${idx}`;\n switch (block.type) {\n case 'paragraph':\n return (\n <p key={key} className={markdownParagraphStyle}>\n {renderInline(block.content ?? '', { linkTarget }, key)}\n </p>\n );\n case 'heading': {\n const level = Math.min(Math.max(block.level ?? 1, 1), 6) as\n | 1\n | 2\n | 3\n | 4\n | 5\n | 6;\n const Tag = `h${level}` as keyof React.JSX.IntrinsicElements;\n return (\n <Tag key={key} className={markdownHeadingStyle}>\n {renderInline(block.content ?? '', { linkTarget }, key)}\n </Tag>\n );\n }\n case 'list':\n return (\n <ul key={key} className={markdownListStyle}>\n {(block.items ?? []).map((item, j) => (\n <li key={`${key}-${j}`} className={markdownListItemStyle}>\n {renderInline(item, { linkTarget }, `${key}-${j}`)}\n </li>\n ))}\n </ul>\n );\n case 'orderedList':\n return (\n <ol key={key} className={markdownListStyle}>\n {(block.items ?? []).map((item, j) => (\n <li key={`${key}-${j}`} className={markdownListItemStyle}>\n {renderInline(item, { linkTarget }, `${key}-${j}`)}\n </li>\n ))}\n </ol>\n );\n case 'blockquote':\n return (\n <blockquote key={key} className={markdownBlockquoteStyle}>\n {renderInline(block.content ?? '', { linkTarget }, key)}\n </blockquote>\n );\n case 'codeBlock':\n return (\n <CodeBlock\n key={key}\n code={block.content ?? ''}\n language={block.language}\n />\n );\n case 'hr':\n return <hr key={key} className={markdownHrStyle} />;\n case 'table': {\n const [header, ...rows] = block.rows ?? [];\n const align = block.align ?? [];\n return (\n <table key={key} className={markdownTableStyle}>\n <thead>\n <tr>\n {(header ?? []).map((cell, j) => (\n <th\n key={`${key}-h-${j}`}\n className={markdownThStyle}\n style={\n align[j]\n ? { textAlign: align[j] ?? undefined }\n : undefined\n }\n >\n {renderInline(\n cell,\n { linkTarget },\n `${key}-h-${j}`\n )}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((row, rIdx) => (\n <tr key={`${key}-r-${rIdx}`}>\n {row.map((cell, j) => (\n <td\n key={`${key}-r-${rIdx}-${j}`}\n className={markdownTdStyle}\n style={\n align[j]\n ? { textAlign: align[j] ?? undefined }\n : undefined\n }\n >\n {renderInline(\n cell,\n { linkTarget },\n `${key}-r-${rIdx}-${j}`\n )}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n );\n }\n default:\n return null;\n }\n })}\n </div>\n );\n }\n );\n\nChatMarkdownRenderer.displayName = 'ChatMarkdownRenderer';\n"],"names":[],"mappings":";;;;;;;;AAwCA;AACE;AACF;AAEA;;;;;;AAWE;AAIE;AACE;AACA;AACD;AACD;AACE;AACA;AAQD;AACD;AACE;;AAcD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;AACD;AACE;AACA;AACD;;AAGH;;;;AAMI;;AACA;AACE;;AAEE;;;;;;;;;AAWN;AACE;;AAEF;AACA;;AAGF;AACF;AAoBA;AACE;;;AAIA;;;AAIE;AACE;;;;;;AAOA;;AAEA;AACA;;AAEE;;;;AAIA;AACA;;AAED;;;;AAKH;;AAEE;;;;;;;;;AAUE;;AAEA;AACD;AACD;;;;AAKF;;AAEE;AACE;AACA;;AAEF;;;;AAKF;;AAEE;AACE;AACA;;;;;;AAOJ;;AAEE;AACE;AACA;;;;;;AAOJ;AAEE;AACA;AACA;AAEA;AAEK;AACA;;;AAIL;AACA;;;;;AAIqB;AACnB;AAAW;AACX;AAAU;AACV;AACF;AAEA;;AAEA;AACE;AACA;;AAEF;;;;;AAMF;;AAEE;AAEE;AACA;AACA;AACA;AACA;AACA;;;AAIF;AACA;;AAEF;;AAGF;AACF;AAEA;;;;;;;;;;;;;;;;;AAiBG;;AAED;;AAcI;;AAMA;AASM;AACA;AACE;;;;AAcE;;;AAOF;;AAUA;;AAUA;;AAMA;;AAQA;AACE;;AAEA;AACA;AACA;;AAWgB;;;;AAsClB;AACE;;;AAKZ;AAGJ;;"}
|
|
@@ -88,6 +88,12 @@ 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';
|
|
91
97
|
import { Avatar } from '../../primitives/Avatar/Avatar.js';
|
|
92
98
|
import '../../primitives/Avatar/AvatarGroup.js';
|
|
93
99
|
import { cx } from '../../../utils/cx.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatMessage.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatMessage.js","sources":["src/components/editor/ChatPanel/ChatMessage.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { ErrorIcon } from '@/components/Icons';\nimport { Avatar } from '@/components/primitives/Avatar';\nimport { cx } from '@/utils/cx';\n\nimport { ChatBubble } from './ChatBubble';\nimport {\n bubbleErrorStyle,\n messageContentStyle,\n messageErrorCaptionStyle,\n messageErrorIconStyle,\n messageMaxWidthVarName,\n messageRecipe,\n messageTextStyle,\n messageTimestampStyle,\n} from './ChatPanel.css';\n\nimport type { ChatMessageProps } from './ChatPanel.types';\n\nfunction resolveMaxWidth(\n value: number | string | undefined\n): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nfunction formatTimestamp(iso: string): string {\n try {\n const date = new Date(iso);\n return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n } catch {\n return '';\n }\n}\n\nexport const ChatMessage = /*#__PURE__*/ React.memo<ChatMessageProps>(\n ({\n message,\n showTimestamp = false,\n showAvatar = false,\n actions,\n renderContent,\n maxWidth,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const { role, content, status, timestamp, avatar, displayName } = message;\n const isError = status === 'error';\n\n const renderedContent = renderContent ? (\n renderContent(content)\n ) : (\n <span className={messageTextStyle}>{content}</span>\n );\n\n const resolvedMaxWidth = resolveMaxWidth(maxWidth);\n const rootStyle: React.CSSProperties = resolvedMaxWidth\n ? ({\n [messageMaxWidthVarName]: resolvedMaxWidth,\n ...style,\n } as React.CSSProperties)\n : (style ?? {});\n\n return (\n <div\n ref={ref}\n className={cx(messageRecipe({ role }), className)}\n style={rootStyle}\n data-testid={testId}\n {...rest}\n >\n {showAvatar && role !== 'system' && (\n <Avatar\n size=\"md\"\n src={avatar}\n name={displayName ?? role}\n alt={displayName ?? role}\n />\n )}\n\n <div className={messageContentStyle}>\n <ChatBubble\n role={role}\n className={isError ? bubbleErrorStyle : undefined}\n >\n {renderedContent}\n </ChatBubble>\n\n {isError && (\n <span className={messageErrorCaptionStyle}>\n <span className={messageErrorIconStyle}>\n <ErrorIcon size={12} decorative />\n </span>\n Error generating response\n </span>\n )}\n\n {actions && <div>{actions}</div>}\n\n {showTimestamp && timestamp && (\n <span className={messageTimestampStyle}>\n {formatTimestamp(timestamp)}\n </span>\n )}\n </div>\n </div>\n );\n }\n);\n\nChatMessage.displayName = 'ChatMessage';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA;;AAG2B;AACzB;AACF;AAEA;AACE;AACE;AACA;;AACA;AACA;;AAEJ;AAEO;AAcH;AACA;;AAQA;;AAEE;;AAEI;AACuB;AAC3B;AAEF;AA4CF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatMessageList.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatMessageList.js","sources":["src/components/editor/ChatPanel/ChatMessageList.tsx"],"sourcesContent":["'use client';\n\nimport React, { useImperativeHandle, useMemo } from 'react';\n\nimport { ScrollArea } from '@/components/layout/ScrollArea';\nimport { useMergedRef } from '@/hooks/useMergedRef';\n\nimport { ChatMessage } from './ChatMessage';\nimport {\n messageListContentStyle,\n newMessagesBannerStyle,\n} from './ChatPanel.css';\nimport { useChatScroll } from './useChatScroll';\n\nimport type {\n ChatMessageListProps,\n ChatMessageListScrollApi,\n} from './ChatPanel.types';\n\nexport const ChatMessageList = /*#__PURE__*/ React.memo<ChatMessageListProps>(\n ({\n messages,\n renderMessage,\n emptyState,\n autoScroll = true,\n scrollApiRef,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const {\n scrollContainerRef,\n scrollContentRef,\n hasNewMessages,\n scrollToBottom,\n scrollTo,\n scrollToElement,\n } = useChatScroll({\n messages,\n enabled: autoScroll,\n });\n\n // ScrollArea forwards ref to its viewport div — merge with our internal\n // scroll container ref and the consumer's ref.\n const mergedRef = useMergedRef<HTMLDivElement>(scrollContainerRef, ref);\n\n const isAtBottomGetter = React.useCallback(() => {\n const container = scrollContainerRef.current;\n if (!container) return true;\n const { scrollTop, scrollHeight, clientHeight } = container;\n return scrollHeight - scrollTop - clientHeight <= 100;\n }, [scrollContainerRef]);\n\n const scrollApi = useMemo<ChatMessageListScrollApi>(\n () => ({\n scrollToBottom,\n scrollTo,\n scrollToElement,\n isAtBottom: isAtBottomGetter,\n }),\n [scrollToBottom, scrollTo, scrollToElement, isAtBottomGetter]\n );\n\n useImperativeHandle(scrollApiRef, () => scrollApi, [scrollApi]);\n\n if (messages.length === 0 && emptyState) {\n return (\n <ScrollArea\n ref={mergedRef}\n autoFill\n className={className}\n style={style}\n testId={testId}\n {...rest}\n >\n <div\n ref={scrollContentRef}\n className={messageListContentStyle}\n role=\"log\"\n aria-live=\"polite\"\n >\n {emptyState}\n </div>\n </ScrollArea>\n );\n }\n\n return (\n <ScrollArea\n ref={mergedRef}\n autoFill\n className={className}\n style={style}\n testId={testId}\n {...rest}\n >\n <div\n ref={scrollContentRef}\n className={messageListContentStyle}\n role=\"log\"\n aria-live=\"polite\"\n >\n {messages.map((message, index) =>\n renderMessage ? (\n <React.Fragment key={message.id}>\n {renderMessage(message, index)}\n </React.Fragment>\n ) : (\n <ChatMessage key={message.id} message={message} />\n )\n )}\n\n {hasNewMessages && (\n <button\n className={newMessagesBannerStyle}\n onClick={() => {\n scrollToBottom('smooth');\n }}\n type=\"button\"\n >\n New messages\n </button>\n )}\n </div>\n </ScrollArea>\n );\n }\n);\n\nChatMessageList.displayName = 'ChatMessageList';\n"],"names":[],"mappings":";;;;;;;;;AAmBO;AAaH;;AASE;AACD;;;;AAMD;AACE;AACA;AAAgB;;AAEhB;AACF;AAEA;;;;AAKI;;AAKJ;;AAGE;;;;;AA4DJ;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatPanel.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatPanel.js","sources":["src/components/editor/ChatPanel/ChatPanel.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { chatPanelRecipe, messageMaxWidthVarName } from './ChatPanel.css';\n\nimport type { ChatPanelProps } from './ChatPanel.types';\n\nfunction resolveMaxWidth(\n value: number | string | undefined\n): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nexport const ChatPanel = /*#__PURE__*/ React.memo<ChatPanelProps>(\n ({\n density = 'comfortable',\n messageMaxWidth,\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const resolvedMaxWidth = resolveMaxWidth(messageMaxWidth);\n const rootStyle: React.CSSProperties = resolvedMaxWidth\n ? ({\n [messageMaxWidthVarName]: resolvedMaxWidth,\n ...style,\n } as React.CSSProperties)\n : (style ?? {});\n\n return (\n <div\n ref={ref}\n className={cx(chatPanelRecipe({ density }), className)}\n style={rootStyle}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n );\n }\n);\n\nChatPanel.displayName = 'ChatPanel';\n"],"names":[],"mappings":";;;;;;AAUA;;AAG2B;AACzB;AACF;AAEO;AAWH;;AAEE;;AAEI;AACuB;AAC3B;AAEF;AAWF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatToolCall.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatToolCall.js","sources":["src/components/editor/ChatPanel/ChatToolCall.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState, useCallback } from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { MiniWrenchIcon, MiniChevronIcon } from './ChatIcons';\nimport {\n toolCallContainerStyle,\n toolCallHeaderStyle,\n toolCallIconStyle,\n toolCallNameStyle,\n toolCallStatusRecipe,\n toolCallChevronRecipe,\n toolCallDetailsStyle,\n toolCallSectionLabelStyle,\n toolCallPreStyle,\n toolCallErrorStyle,\n toolCallDurationStyle,\n} from './ChatPanel.css';\n\nimport type { ChatToolCallProps } from './ChatPanel.types';\n\n// ─── Status label map ────────────────────────────────────────────\n\nconst STATUS_LABELS = {\n pending: 'Pending',\n running: 'Running',\n completed: 'Completed',\n error: 'Error',\n} as const;\n\n// ─── Component ───────────────────────────────────────────────────\n\nexport const ChatToolCall = /*#__PURE__*/ React.memo<ChatToolCallProps>(\n ({\n toolCall,\n collapsible = true,\n defaultExpanded = false,\n icon,\n renderOutput,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const [expanded, setExpanded] = useState(defaultExpanded);\n\n const handleToggle = useCallback(() => {\n if (collapsible) {\n setExpanded(prev => !prev);\n }\n }, [collapsible]);\n\n const statusLabel = STATUS_LABELS[toolCall.status];\n const ariaLabel = `Tool ${toolCall.name}: ${statusLabel}`;\n\n return (\n <div\n ref={ref}\n className={cx(toolCallContainerStyle, className)}\n style={style}\n data-testid={testId}\n aria-label={ariaLabel}\n {...rest}\n >\n <button\n type=\"button\"\n className={toolCallHeaderStyle}\n onClick={handleToggle}\n aria-expanded={collapsible ? expanded : undefined}\n >\n <span className={toolCallIconStyle}>\n {icon ?? <MiniWrenchIcon />}\n </span>\n\n <span className={toolCallNameStyle}>{toolCall.name}</span>\n\n <span className={toolCallStatusRecipe({ status: toolCall.status })}>\n {statusLabel}\n </span>\n\n {toolCall.durationMs !== undefined &&\n toolCall.status === 'completed' && (\n <span className={toolCallDurationStyle}>\n {toolCall.durationMs}ms\n </span>\n )}\n\n {collapsible && (\n <span\n className={toolCallChevronRecipe({\n open: expanded || undefined,\n })}\n >\n <MiniChevronIcon />\n </span>\n )}\n </button>\n\n {expanded && (\n <div className={toolCallDetailsStyle}>\n {toolCall.input && (\n <>\n <span className={toolCallSectionLabelStyle}>Input</span>\n <pre className={toolCallPreStyle}>\n {JSON.stringify(toolCall.input, null, 2)}\n </pre>\n </>\n )}\n\n {toolCall.output && (\n <>\n <span className={toolCallSectionLabelStyle}>Output</span>\n {renderOutput ? (\n renderOutput(toolCall.output)\n ) : (\n <pre className={toolCallPreStyle}>\n {JSON.stringify(toolCall.output, null, 2)}\n </pre>\n )}\n </>\n )}\n\n {toolCall.error && (\n <>\n <span className={toolCallSectionLabelStyle}>Error</span>\n <span className={toolCallErrorStyle}>{toolCall.error}</span>\n </>\n )}\n </div>\n )}\n </div>\n );\n }\n);\n\nChatToolCall.displayName = 'ChatToolCall';\n"],"names":[],"mappings":";;;;;;;AAuBA;AAEA;AACE;AACA;AACA;AACA;;AAGF;AAEO;;AAeH;;;;AAIA;;;AAKA;;;AAoCW;AAyCb;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatTypingIndicator.js","sources":["
|
|
1
|
+
{"version":3,"file":"ChatTypingIndicator.js","sources":["src/components/editor/ChatPanel/ChatTypingIndicator.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport {\n typingIndicatorStyle,\n typingDotsContainerStyle,\n typingDotStyle,\n typingPulseStyle,\n typingLabelStyle,\n} from './ChatPanel.css';\n\nimport type { ChatTypingIndicatorProps } from './ChatPanel.types';\n\nexport const ChatTypingIndicator =\n /*#__PURE__*/ React.memo<ChatTypingIndicatorProps>(\n ({\n label = 'Thinking...',\n variant = 'dots',\n visible = true,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n if (!visible) return null;\n\n return (\n <div\n ref={ref}\n className={cx(typingIndicatorStyle, className)}\n style={style}\n data-testid={testId}\n role=\"status\"\n aria-label={label}\n {...rest}\n >\n {variant === 'dots' ? (\n <div className={typingDotsContainerStyle} aria-hidden=\"true\">\n <span className={typingDotStyle} />\n <span className={typingDotStyle} />\n <span className={typingDotStyle} />\n </div>\n ) : (\n <div className={typingPulseStyle} aria-hidden=\"true\" />\n )}\n <span className={typingLabelStyle}>{label}</span>\n </div>\n );\n }\n );\n\nChatTypingIndicator.displayName = 'ChatTypingIndicator';\n"],"names":[],"mappings":";;;;;;;AAiBE;AAWI;AAAc;AAEd;AAsBF;AAGJ;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatInput.js","sources":["
|
|
1
|
+
{"version":3,"file":"useChatInput.js","sources":["src/components/editor/ChatPanel/useChatInput.ts"],"sourcesContent":["'use client';\n\nimport React, { useState, useCallback, useRef, useEffect } from 'react';\n\nimport type {\n UseChatInputOptions,\n UseChatInputReturn,\n} from './ChatPanel.types';\n\nexport function useChatInput(\n options: UseChatInputOptions = {}\n): UseChatInputReturn {\n const {\n submitKey = 'enter',\n onSubmit,\n maxLines = 6,\n attachmentsCount = 0,\n } = options;\n const [value, setValue] = useState('');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const autoResize = useCallback(() => {\n const textarea = textareaRef.current;\n if (!textarea) return;\n\n // Reset height to measure scroll height\n textarea.style.height = 'auto';\n\n const lineHeight = parseInt(\n getComputedStyle(textarea).lineHeight || '18',\n 10\n );\n const maxHeight = maxLines * lineHeight;\n const newHeight = Math.min(textarea.scrollHeight, maxHeight);\n\n textarea.style.height = `${newHeight}px`;\n }, [maxLines]);\n\n // Auto-resize on value change\n useEffect(() => {\n autoResize();\n }, [value, autoResize]);\n\n const clear = useCallback(() => {\n setValue('');\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n }\n }, []);\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n setValue(event.target.value);\n },\n []\n );\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n const isSubmit =\n submitKey === 'enter'\n ? event.key === 'Enter' &&\n !event.shiftKey &&\n !event.ctrlKey &&\n !event.metaKey\n : event.key === 'Enter' && (event.ctrlKey || event.metaKey);\n\n if (isSubmit) {\n event.preventDefault();\n const trimmed = value.trim();\n if (trimmed || attachmentsCount > 0) {\n onSubmit?.(trimmed);\n clear();\n }\n }\n },\n [submitKey, value, onSubmit, clear, attachmentsCount]\n );\n\n return {\n value,\n setValue,\n clear,\n textareaRef,\n handleKeyDown,\n handleChange,\n };\n}\n"],"names":[],"mappings":";;;AASM;AAGJ;;AAOA;AAEA;AACE;AACA;;;AAGA;AAEA;AAIA;AACA;;AAGF;;;AAIE;AACF;AAEA;;AAEE;;AAEE;;;AAIJ;AAEI;;AAKJ;AAEI;AAEI;;;;AAIA;;;AAIF;AACA;AACE;AACA;;;AAGN;;;;;;;;;AAYJ;;"}
|