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":"LogViewBody.js","sources":["../../../../../../src/components/feedback/LogView/LogViewBody.tsx"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8DA;;;;AAIG;AACH;;;AAII;AAEA;AACF;;AAGE;AACA;AAEA;AACF;AAGF;AAiCA;AACA;AAsBE;AACA;;AAGA;AAAiB;;AAEf;;;AAOA;AACI;;;;AAIJ;AACI;;;AAIN;;AAeQ;;;;;AAKD;;AAiCC;;;AAmBA;AAOV;AAEA;;;;;AAKG;AACI;AAOL;;AA+BA;AACA;AAEA;AACE;AACE;AAA8B;;AAEhC;AACF;AAEA;AACE;AAAoD;;AAElD;;;;AAID;AACH;;;;;;;AAOC;;;;;;;AAQD;AAIA;;AAOA;AAEA;;;;;;;;AAWE;AACA;;AAED;AAED;AACA;;;;;;AAOC;;AAGD;;AAMA;;;;;AAMI;;AAIF;AAIF;AAKA;AACA;AAEA;AAEI;AACA;AACA;;AAKJ;AACA;AAEA;AACE;AACA;;AACA;AACA;AACA;AACF;;;AAIA;AAKA;;;;;;;AAOE;AACD;;;;;AAMD;AACE;;;;AAG4B;AAC1B;AACA;AACA;AACF;AACF;AAEA;AA4BA;;;;AA4BqC;AACzB;AACF;AAiCZ;AAEA;;"}
|
|
1
|
+
{"version":3,"file":"LogViewBody.js","sources":["src/components/feedback/LogView/LogViewBody.tsx"],"sourcesContent":["'use client';\n\nimport { useVirtualizer } from '@tanstack/react-virtual';\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, {\n memo,\n useCallback,\n useDeferredValue,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\n\nimport { ChevronDownIcon } from '@/components/Icons/ChevronDownIcon';\nimport { CopyIcon } from '@/components/Icons/CopyIcon';\nimport { Badge } from '@/components/primitives/Badge';\nimport { Button } from '@/components/primitives/Button';\nimport { IconButton } from '@/components/primitives/IconButton';\nimport { useClipboard } from '@/hooks/useClipboard';\nimport { useLatest } from '@/hooks/useLatest';\nimport { cx } from '@/utils/cx';\n\nimport {\n DENSITY_ROW_HEIGHT,\n bodyDensityRecipe,\n bodyStyle,\n copyLineButtonStyle,\n emptyStateStyle,\n highlightStyle,\n jumpBadgeStyle,\n jumpButtonRecipe,\n levelColorVar,\n messageRecipe,\n plainBodyStyle,\n rowGlyphStyle,\n rowRecipe,\n scrollViewportStyle,\n sourceCellStyle,\n sourceTagStyle,\n timestampStyle,\n totalHeightVar,\n virtualBodyStyle,\n} from './LogView.css';\nimport { useLogEntries, useLogViewContext } from './LogViewContext';\nimport { levelVariant } from './logViewLevels';\nimport {\n entriesToText,\n entryToText,\n filterEntries,\n getHighlightSegments,\n} from './logViewUtils';\nimport { useFollowTail } from './useFollowTail';\nimport { useLogSelection } from './useLogSelection';\n\nimport type {\n LogEntryRenderInfo,\n LogLevel,\n LogViewBodyProps,\n ResolvedLogEntry,\n} from './LogView.types';\nimport type { ResolvedLevelDefinition } from './logViewLevels';\n\n/**\n * True when there is an active (non-collapsed) text selection whose anchor is\n * inside `container`. Scoped to the log body so a selection elsewhere on the\n * page does not suppress a row click or the copy shortcut.\n */\nfunction hasTextSelectionWithin(container: HTMLElement | null): boolean {\n if (\n container === null ||\n typeof window === 'undefined' ||\n typeof window.getSelection !== 'function'\n )\n return false;\n const selection = window.getSelection();\n if (\n selection === null ||\n selection.isCollapsed ||\n selection.toString() === ''\n )\n return false;\n return (\n selection.anchorNode !== null && container.contains(selection.anchorNode)\n );\n}\n\ninterface LogRowProps {\n entry: ResolvedLogEntry;\n index: number;\n query: string;\n caseSensitive: boolean;\n levelDef: ResolvedLevelDefinition;\n wrap: boolean;\n showTimestamps: boolean;\n formatTimestamp: (timestamp: number | Date) => string;\n showSource: boolean;\n interactive: boolean;\n selectable: boolean;\n selected: boolean;\n renderEntry: ((info: LogEntryRenderInfo) => React.ReactNode) | undefined;\n onRowClick: (\n entry: ResolvedLogEntry,\n index: number,\n event: React.MouseEvent | React.KeyboardEvent\n ) => void;\n onRowKeyDown: (\n entry: ResolvedLogEntry,\n index: number,\n event: React.KeyboardEvent<HTMLDivElement>\n ) => void;\n onCopyLine: (entry: ResolvedLogEntry) => void;\n copyLineLabel: string;\n virtualized: boolean;\n start: number;\n measureRef?: (node: Element | null) => void;\n}\n\n/** A single log line. Memoized so scrolling only renders newly-visible rows. */\nconst LogRow = memo(function LogRow({\n entry,\n index,\n query,\n caseSensitive,\n levelDef,\n wrap,\n showTimestamps,\n formatTimestamp,\n showSource,\n interactive,\n selectable,\n selected,\n renderEntry,\n onRowClick,\n onRowKeyDown,\n onCopyLine,\n copyLineLabel,\n virtualized,\n start,\n measureRef,\n}: LogRowProps): React.ReactElement {\n const Icon = levelDef.icon;\n const hasSource = entry.source != null && entry.source !== '';\n\n const rowStyle: React.CSSProperties = {};\n if (virtualized) rowStyle.transform = `translateY(${start}px)`;\n if (!levelDef.isBuiltIn && levelDef.color !== undefined) {\n Object.assign(\n rowStyle,\n assignInlineVars({ [levelColorVar]: levelDef.color })\n );\n }\n\n const handleClick = interactive\n ? (event: React.MouseEvent<HTMLDivElement>) => {\n onRowClick(entry, index, event);\n }\n : undefined;\n const handleKeyDown = interactive\n ? (event: React.KeyboardEvent<HTMLDivElement>) => {\n onRowKeyDown(entry, index, event);\n }\n : undefined;\n\n const segments = getHighlightSegments(entry.message, query, caseSensitive);\n\n return (\n <div\n ref={measureRef}\n data-index={index}\n data-log-row\n data-log-copy-host\n data-level={entry.level}\n data-selected={selected || undefined}\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n aria-pressed={selectable ? selected : undefined}\n className={cx(\n rowRecipe({\n level: levelVariant(levelDef),\n virtualized: virtualized || undefined,\n interactive: interactive || undefined,\n selected: selected || undefined,\n align: wrap ? 'start' : 'center',\n })\n )}\n style={rowStyle}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n >\n {showTimestamps && (\n <span className={timestampStyle} data-log-time>\n {entry.timestamp != null ? formatTimestamp(entry.timestamp) : ''}\n </span>\n )}\n\n <span className={rowGlyphStyle} aria-hidden=\"true\">\n {Icon ? <Icon size=\"md\" color=\"currentColor\" /> : null}\n </span>\n\n {showSource && (\n <span\n className={sourceCellStyle}\n data-log-source\n title={hasSource ? entry.source : undefined}\n >\n {hasSource ? (\n <Badge variant=\"subtle\" size=\"xs\" className={sourceTagStyle}>\n {entry.source}\n </Badge>\n ) : null}\n </span>\n )}\n\n <span className={messageRecipe({ wrap })}>\n {renderEntry\n ? renderEntry({ entry, index, query })\n : segments.map((segment, i) =>\n segment.match ? (\n <mark key={i} className={highlightStyle}>\n {segment.text}\n </mark>\n ) : (\n <React.Fragment key={i}>{segment.text}</React.Fragment>\n )\n )}\n </span>\n\n <span className={copyLineButtonStyle} data-log-copy>\n <IconButton\n aria-label={copyLineLabel}\n size=\"sm\"\n variant=\"ghost\"\n onClick={event => {\n event.stopPropagation();\n onCopyLine(entry);\n }}\n >\n <CopyIcon size=\"md\" />\n </IconButton>\n </span>\n </div>\n );\n});\n\n/**\n * The virtualized log body. Reads the entry stream from the store, applies the\n * deferred search + level filter, and renders only the visible window via\n * `@tanstack/react-virtual` (mirroring `DataTable`). Owns follow-tail behavior\n * and the floating jump-to-bottom button.\n */\nexport const LogViewBody = ({\n className,\n style,\n testId,\n ref,\n ...rest\n}: LogViewBodyProps): React.ReactElement => {\n const ctx = useLogViewContext();\n const {\n store,\n query,\n caseSensitive,\n activeLevels,\n knownLevels,\n follow,\n setFollow,\n getLevelDefinition,\n wrap,\n density,\n showTimestamps,\n formatTimestamp,\n showSource,\n virtualized,\n virtualizationThreshold,\n estimatedRowHeight,\n overscan,\n selectionMode,\n selectedIds,\n setSelectedIds,\n getCopyEntries,\n renderEntry,\n emptyState,\n onEntryClick,\n onCopy,\n bodyId,\n labels,\n } = ctx;\n\n const entries = useLogEntries(store);\n const deferredQuery = useDeferredValue(query);\n\n const allLevelsActive = useMemo(() => {\n for (const level of knownLevels) {\n if (!activeLevels.has(level)) return false;\n }\n return true;\n }, [knownLevels, activeLevels]);\n\n const filtered = useMemo<readonly ResolvedLogEntry[]>(() => {\n if (deferredQuery.trim() === '' && allLevelsActive) return entries;\n return filterEntries(entries, {\n query: deferredQuery,\n caseSensitive,\n knownLevels,\n activeLevels,\n });\n }, [\n entries,\n deferredQuery,\n caseSensitive,\n knownLevels,\n activeLevels,\n allLevelsActive,\n ]);\n\n // A prefix column is only reserved when its field is actually present in the\n // data. If nothing has a timestamp / source there is no column at all (the\n // message sits right after the icon, as if columns didn't exist); once at\n // least one entry uses the field, every row reserves it so they stay aligned.\n // Keyed off the full entry set (not the filtered view) so filtering can't make\n // a column appear/disappear and shift the layout.\n const hasAnyTimestamp = useMemo(\n () => showTimestamps && entries.some(entry => entry.timestamp != null),\n [showTimestamps, entries]\n );\n const hasAnySource = useMemo(\n () =>\n showSource &&\n entries.some(entry => entry.source != null && entry.source !== ''),\n [showSource, entries]\n );\n\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const shouldVirtualize =\n virtualized === true ||\n (virtualized === 'auto' && filtered.length > virtualizationThreshold);\n\n const rowHeightPx = estimatedRowHeight ?? DENSITY_ROW_HEIGHT[density];\n\n // TanStack Virtual returns functions that can't be memoized; the Compiler\n // flags it as an incompatible library. Reads are imperative per render.\n // eslint-disable-next-line react-hooks/incompatible-library\n const virtualizer = useVirtualizer({\n count: shouldVirtualize ? filtered.length : 0,\n getScrollElement: () => scrollRef.current,\n estimateSize: () => rowHeightPx,\n overscan,\n });\n\n const virtualItems = shouldVirtualize ? virtualizer.getVirtualItems() : [];\n const totalSize = shouldVirtualize ? virtualizer.getTotalSize() : 0;\n\n const { scrollToBottom, isDetached, newSinceDetach } = useFollowTail({\n scrollRef,\n follow,\n setFollow,\n entryCount: filtered.length,\n });\n\n // Let the imperative handle's scrollToBottom reach this body.\n useEffect(\n () => store.registerScroller(scrollToBottom),\n [store, scrollToBottom]\n );\n\n // Let the imperative handle's scrollToIndex reach this body.\n const scrollToIndex = useCallback(\n (index: number) => {\n if (shouldVirtualize) {\n virtualizer.scrollToIndex(index, { align: 'auto' });\n return;\n }\n const el = scrollRef.current?.querySelector<HTMLElement>(\n `[data-index=\"${index}\"]`\n );\n el?.scrollIntoView({ block: 'nearest' });\n },\n [shouldVirtualize, virtualizer]\n );\n\n useEffect(\n () => store.registerScrollToIndex(scrollToIndex),\n [store, scrollToIndex]\n );\n\n const { copy } = useClipboard();\n const onCopyRef = useLatest(onCopy);\n\n const handleCopyLine = useCallback(\n (entry: ResolvedLogEntry) => {\n const text = entryToText(entry, { showTimestamps, formatTimestamp });\n void copy(text);\n onCopyRef.current?.(text);\n },\n [copy, showTimestamps, formatTimestamp, onCopyRef]\n );\n\n const selectable = selectionMode !== false;\n const interactive = selectable || onEntryClick !== undefined;\n\n const copySelectionOrVisible = useCallback(() => {\n const entries = getCopyEntries();\n if (entries.length === 0) return;\n const text = entriesToText(entries, { showTimestamps, formatTimestamp });\n void copy(text);\n onCopyRef.current?.(text);\n }, [getCopyEntries, showTimestamps, formatTimestamp, copy, onCopyRef]);\n\n // Scoped to the scroll viewport so a selection elsewhere on the page doesn't\n // suppress a row click or the copy shortcut.\n const isTextSelected = useCallback(\n () => hasTextSelectionWithin(scrollRef.current),\n []\n );\n\n const { handleRowClick, handleRowKeyDown } = useLogSelection({\n selectionMode,\n selectedIds,\n setSelectedIds,\n filtered,\n onEntryClick,\n isTextSelected,\n onCopyShortcut: copySelectionOrVisible,\n });\n\n // Resolve level definitions through a per-render-stable cache: `LogRow` is\n // memoized, so handing it a fresh definition object each render would defeat\n // the memo. The cache resets whenever `getLevelDefinition` (i.e. levelConfig)\n // changes.\n const resolveLevelDef = useMemo(() => {\n const cache = new Map<LogLevel, ResolvedLevelDefinition>();\n return (level: LogLevel): ResolvedLevelDefinition => {\n const cached = cache.get(level);\n if (cached !== undefined) return cached;\n const def = getLevelDefinition(level);\n cache.set(level, def);\n return def;\n };\n }, [getLevelDefinition]);\n\n const renderRow = (entry: ResolvedLogEntry, index: number, start: number) => (\n <LogRow\n key={entry.id}\n entry={entry}\n index={index}\n query={deferredQuery}\n caseSensitive={caseSensitive}\n levelDef={resolveLevelDef(entry.level)}\n wrap={wrap}\n showTimestamps={hasAnyTimestamp}\n formatTimestamp={formatTimestamp}\n showSource={hasAnySource}\n interactive={interactive}\n selectable={selectable}\n selected={selectedIds.has(entry.id)}\n renderEntry={renderEntry}\n onRowClick={handleRowClick}\n onRowKeyDown={handleRowKeyDown}\n onCopyLine={handleCopyLine}\n copyLineLabel={labels.copyLineLabel}\n virtualized={shouldVirtualize}\n start={start}\n measureRef={\n shouldVirtualize && wrap ? virtualizer.measureElement : undefined\n }\n />\n );\n\n const isEmpty = filtered.length === 0;\n\n return (\n <div\n ref={ref}\n className={cx(bodyStyle, bodyDensityRecipe({ density }), className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n <div\n ref={scrollRef}\n id={bodyId}\n role=\"log\"\n aria-live=\"off\"\n className={scrollViewportStyle}\n >\n {isEmpty ? (\n <div className={emptyStateStyle}>\n {emptyState ?? labels.emptyLabel}\n </div>\n ) : shouldVirtualize ? (\n <div\n className={virtualBodyStyle}\n style={assignInlineVars({ [totalHeightVar]: `${totalSize}px` })}\n >\n {virtualItems.map(item => {\n const entry = filtered[item.index];\n if (entry === undefined) return null;\n return renderRow(entry, item.index, item.start);\n })}\n </div>\n ) : (\n <div className={plainBodyStyle}>\n {filtered.map((entry, index) => renderRow(entry, index, 0))}\n </div>\n )}\n </div>\n\n <div\n data-log-jump\n className={jumpButtonRecipe({ visible: isDetached || undefined })}\n aria-hidden={!isDetached}\n >\n <Button\n size=\"sm\"\n variant=\"default\"\n icon={<ChevronDownIcon size=\"md\" />}\n onClick={scrollToBottom}\n aria-label={labels.jumpToBottomLabel}\n tabIndex={isDetached ? 0 : -1}\n >\n {newSinceDetach > 0 ? (\n <span className={jumpBadgeStyle}>\n {labels.newLinesLabel(newSinceDetach)}\n </span>\n ) : (\n labels.jumpToBottomLabel\n )}\n </Button>\n </div>\n </div>\n );\n};\n\nLogViewBody.displayName = 'LogView.Body';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA8DA;;;;AAIG;AACH;;;AAII;AAEA;AACF;;AAGE;AACA;AAEA;AACF;AAGF;AAiCA;AACA;AAsBE;AACA;;AAGA;AAAiB;;AAEf;;;AAOA;AACI;;;;AAIJ;AACI;;;AAIN;;AAeQ;;;;;AAKD;;AAiCC;;;AAmBA;AAOV;AAEA;;;;;AAKG;AACI;AAOL;;AA+BA;AACA;AAEA;AACE;AACE;AAA8B;;AAEhC;AACF;AAEA;AACE;AAAoD;;AAElD;;;;AAID;AACH;;;;;;;AAOC;;;;;;;AAQD;AAIA;;AAOA;AAEA;;;;;;;;AAWE;AACA;;AAED;AAED;AACA;;;;;;AAOC;;AAGD;;AAMA;;;;;AAMI;;AAIF;AAIF;AAKA;AACA;AAEA;AAEI;AACA;AACA;;AAKJ;AACA;AAEA;AACE;AACA;;AACA;AACA;AACA;AACF;;;AAIA;AAKA;;;;;;;AAOE;AACD;;;;;AAMD;AACE;;;;AAG4B;AAC1B;AACA;AACA;AACF;AACF;AAEA;AA4BA;;;;AA4BqC;AACzB;AACF;AAiCZ;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogViewContext.js","sources":["
|
|
1
|
+
{"version":3,"file":"LogViewContext.js","sources":["src/components/feedback/LogView/LogViewContext.ts"],"sourcesContent":["'use client';\n\nimport { createContext, useContext, useSyncExternalStore } from 'react';\n\nimport type {\n LogEntryRenderInfo,\n LogLevel,\n LogViewDensity,\n LogViewLabels,\n LogViewSelectionMode,\n LogViewVirtualizationMode,\n ResolvedLogEntry,\n} from './LogView.types';\nimport type { ResolvedLevelDefinition } from './logViewLevels';\nimport type { LogLevelCounts, LogViewStore } from './LogViewStore';\nimport type React from 'react';\n\n/**\n * Value shared by `<LogView>` and its compound slots.\n *\n * It carries only **low-frequency** state — filter query, visible levels,\n * follow flag, and static config. The high-frequency entry stream is *not*\n * here: the body and level filter read it through {@link useLogEntries} /\n * {@link useLogCounts}, which subscribe to the store directly so a streaming\n * append re-renders only those two slots, not every consumer of the context.\n */\nexport interface LogViewContextValue {\n store: LogViewStore;\n\n // Filtering\n query: string;\n setQuery: (query: string) => void;\n caseSensitive: boolean;\n activeLevels: ReadonlySet<LogLevel>;\n knownLevels: ReadonlySet<LogLevel>;\n isLevelActive: (level: LogLevel) => boolean;\n toggleLevel: (level: LogLevel) => void;\n\n // Follow / auto-scroll\n follow: boolean;\n setFollow: (follow: boolean) => void;\n\n // Levels\n levelOrder: LogLevel[];\n getLevelDefinition: (level: LogLevel) => ResolvedLevelDefinition;\n\n // Layout / display config\n wrap: boolean;\n density: LogViewDensity;\n showTimestamps: boolean;\n formatTimestamp: (timestamp: number | Date) => string;\n showSource: boolean;\n\n // Virtualization config\n virtualized: LogViewVirtualizationMode;\n virtualizationThreshold: number;\n estimatedRowHeight: number | undefined;\n overscan: number;\n\n // Rendering\n renderEntry: ((info: LogEntryRenderInfo) => React.ReactNode) | undefined;\n emptyState: React.ReactNode;\n\n // i18n — resolved UI strings (defaults merged with the `labels` prop)\n labels: LogViewLabels;\n\n // Selection\n selectionMode: LogViewSelectionMode;\n selectedIds: ReadonlySet<string>;\n setSelectedIds: (ids: ReadonlySet<string>) => void;\n\n // Events / actions\n onEntryClick: ((entry: ResolvedLogEntry, index: number) => void) | undefined;\n onCopy: ((text: string) => void) | undefined;\n clearLog: () => void;\n\n // Ids\n bodyId: string;\n\n /** Compute the currently-visible (filtered) entries on demand (used by Copy). */\n getVisibleEntries: () => ResolvedLogEntry[];\n /** Entries to copy: the current selection if non-empty, else all visible. */\n getCopyEntries: () => ResolvedLogEntry[];\n}\n\nexport const LogViewContext =\n /*#__PURE__*/ createContext<LogViewContextValue | null>(null);\n\n/** Read the LogView context. Throws when used outside `<LogView>`. */\nexport function useLogViewContext(): LogViewContextValue {\n const ctx = useContext(LogViewContext);\n if (ctx === null) {\n throw new Error(\n 'LogView compound components must be rendered inside <LogView>.'\n );\n }\n return ctx;\n}\n\n/** Subscribe to the store's entry stream. Re-renders on each (rAF-batched) commit. */\nexport function useLogEntries(\n store: LogViewStore\n): readonly ResolvedLogEntry[] {\n return useSyncExternalStore(\n store.subscribeEntries,\n store.getEntries,\n store.getEntries\n );\n}\n\n/** Subscribe to the store's per-level counts. */\nexport function useLogCounts(store: LogViewStore): LogLevelCounts {\n return useSyncExternalStore(\n store.subscribeCounts,\n store.getCounts,\n store.getCounts\n );\n}\n\n/** Live stats for the current LogView. Call inside `<LogView>` (e.g. in a footer). */\nexport function useLogViewStats(): { total: number; counts: LogLevelCounts } {\n const { store } = useLogViewContext();\n const entries = useLogEntries(store);\n const counts = useLogCounts(store);\n return { total: entries.length, counts };\n}\n"],"names":[],"mappings":";;;;AAsFE;AAEF;;AAEE;AACA;AACE;;AAIF;AACF;AAEA;AACM;AAGJ;AAKF;AAEA;AACM;AACJ;AAKF;AAEA;;AAEE;AACA;AACA;;AAEF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogViewParts.js","sources":["
|
|
1
|
+
{"version":3,"file":"LogViewParts.js","sources":["src/components/feedback/LogView/LogViewParts.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { CopyIcon } from '@/components/Icons/CopyIcon';\nimport { SearchIcon } from '@/components/Icons/SearchIcon';\nimport { TrashIcon } from '@/components/Icons/TrashIcon';\nimport { IconButton } from '@/components/primitives/IconButton';\nimport { Input } from '@/components/primitives/Input';\nimport { useClipboard } from '@/hooks/useClipboard';\nimport { cx } from '@/utils/cx';\n\nimport {\n chipCountStyle,\n footerStyle,\n levelChipRecipe,\n levelColorVar,\n levelDotStyle,\n levelFilterStyle,\n levelGlyphStyle,\n searchWrapperStyle,\n toolbarStyle,\n} from './LogView.css';\nimport { useLogCounts, useLogViewContext } from './LogViewContext';\nimport { levelVariant } from './logViewLevels';\nimport { entriesToText } from './logViewUtils';\n\nimport type {\n LogViewClearProps,\n LogViewCopyProps,\n LogViewFooterProps,\n LogViewLevelFilterProps,\n LogViewSearchProps,\n LogViewToolbarProps,\n} from './LogView.types';\n\n/** Toolbar container. Lays out search, level chips, and action buttons. */\nexport const LogViewToolbar = ({\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n}: LogViewToolbarProps): React.ReactElement => (\n <div\n ref={ref}\n className={cx(toolbarStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n);\nLogViewToolbar.displayName = 'LogView.Toolbar';\n\n/** Footer container. A thin bar below the body for status / summary content. */\nexport const LogViewFooter = ({\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n}: LogViewFooterProps): React.ReactElement => (\n <div\n ref={ref}\n className={cx(footerStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n);\nLogViewFooter.displayName = 'LogView.Footer';\n\n/** Search field bound to the LogView query state. */\nexport const LogViewSearch = ({\n placeholder,\n size = 'md',\n className,\n style,\n testId,\n ref,\n ...rest\n}: LogViewSearchProps): React.ReactElement => {\n const { query, setQuery, labels } = useLogViewContext();\n return (\n <div\n ref={ref}\n className={cx(searchWrapperStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n <Input\n type=\"search\"\n size={size}\n value={query}\n onChange={setQuery}\n placeholder={placeholder ?? labels.searchPlaceholder}\n startIcon={<SearchIcon size=\"md\" />}\n aria-label={labels.searchLabel}\n />\n </div>\n );\n};\nLogViewSearch.displayName = 'LogView.Search';\n\n/** Multi-toggle level filter chips with live per-level counts. */\nexport const LogViewLevelFilter = ({\n className,\n style,\n testId,\n ref,\n ...rest\n}: LogViewLevelFilterProps): React.ReactElement => {\n const {\n store,\n levelOrder,\n getLevelDefinition,\n isLevelActive,\n toggleLevel,\n labels,\n } = useLogViewContext();\n const counts = useLogCounts(store);\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={labels.levelFilterLabel}\n className={cx(levelFilterStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {levelOrder.map(level => {\n const def = getLevelDefinition(level);\n const active = isLevelActive(level);\n const Icon = def.icon;\n const count = counts[level] ?? 0;\n const chipStyle =\n !def.isBuiltIn && def.color !== undefined\n ? assignInlineVars({ [levelColorVar]: def.color })\n : undefined;\n return (\n <button\n key={String(level)}\n type=\"button\"\n aria-pressed={active}\n className={levelChipRecipe({\n level: levelVariant(def),\n active,\n })}\n style={chipStyle}\n onClick={() => {\n toggleLevel(level);\n }}\n >\n {Icon ? (\n <span className={levelGlyphStyle} aria-hidden=\"true\">\n <Icon size=\"md\" color=\"currentColor\" />\n </span>\n ) : (\n <span className={levelDotStyle} aria-hidden=\"true\" />\n )}\n <span>{def.label}</span>\n <span className={chipCountStyle}>{count}</span>\n </button>\n );\n })}\n </div>\n );\n};\nLogViewLevelFilter.displayName = 'LogView.LevelFilter';\n\n/** Clear-all button. */\nexport const LogViewClear = ({\n children,\n className,\n style,\n testId,\n 'aria-label': ariaLabel,\n ref,\n ...rest\n}: LogViewClearProps): React.ReactElement => {\n const { clearLog, labels } = useLogViewContext();\n return (\n <IconButton\n ref={ref}\n aria-label={ariaLabel ?? labels.clearLabel}\n size=\"md\"\n variant=\"ghost\"\n className={className}\n style={style}\n data-testid={testId}\n onClick={() => {\n clearLog();\n }}\n {...rest}\n >\n {children ?? <TrashIcon size=\"md\" />}\n </IconButton>\n );\n};\nLogViewClear.displayName = 'LogView.Clear';\n\n/** Copy-all-visible button. Copies the currently-filtered lines to the clipboard. */\nexport const LogViewCopy = ({\n children,\n className,\n style,\n testId,\n 'aria-label': ariaLabel,\n ref,\n ...rest\n}: LogViewCopyProps): React.ReactElement => {\n const { getCopyEntries, showTimestamps, formatTimestamp, onCopy, labels } =\n useLogViewContext();\n const { copy } = useClipboard();\n return (\n <IconButton\n ref={ref}\n aria-label={ariaLabel ?? labels.copyLabel}\n size=\"md\"\n variant=\"ghost\"\n className={className}\n style={style}\n data-testid={testId}\n onClick={() => {\n const text = entriesToText(getCopyEntries(), {\n showTimestamps,\n formatTimestamp,\n });\n void copy(text);\n onCopy?.(text);\n }}\n {...rest}\n >\n {children ?? <CopyIcon size=\"md\" />}\n </IconButton>\n );\n};\nLogViewCopy.displayName = 'LogView.Copy';\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAqCA;;AAmBA;AAEA;;AAmBA;AAEA;AACO;;AAUL;AAmBF;AACA;AAEA;AACO;AAOL;AAQA;AAEA;AAWM;AACA;AACA;;;AAII;;;AAQE;;;;;;AAsBd;AACA;AAEA;AACO;;AAUL;AAUM;AACF;AAMN;AACA;AAEA;AACO;AASL;AAEA;AACA;AAUM;;;AAGC;AACD;AACA;AACF;AAMN;AACA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogViewStore.js","sources":["../../../../../../src/components/feedback/LogView/LogViewStore.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"LogViewStore.js","sources":["src/components/feedback/LogView/LogViewStore.ts"],"sourcesContent":["import type { LogEntry, LogLevel, ResolvedLogEntry } from './LogView.types';\n\n/** Per-level totals over the currently stored entries. */\nexport type LogLevelCounts = Readonly<Record<string, number>>;\n\ntype Listener = () => void;\n\nconst hasRaf = typeof requestAnimationFrame === 'function';\n\n/**\n * Single source of truth for a LogView instance's entries.\n *\n * Two write paths feed it:\n *\n * - **Controlled mirror** — `setEntries` replaces the whole list from the\n * `entries` prop (low frequency, consumer-driven).\n * - **Imperative append** — `append` / `appendMany` buffer entries and flush\n * once per animation frame (`flush`), so a streaming source pushing thousands\n * of lines per second collapses into one notification per frame. This mirrors\n * the rAF-throttled store-write invariant in\n * `docs/nodegraph-performance.md` (rule #1).\n *\n * Per-level `counts` are maintained incrementally so the level filter can show\n * live totals without an O(n) scan per frame. The entries array and the counts\n * snapshot are each replaced (never mutated in place) on change, so\n * `useSyncExternalStore` consumers see a fresh reference exactly when their\n * slice changes.\n */\nexport class LogViewStore {\n #entries: ResolvedLogEntry[] = [];\n #counts: Record<string, number> = {};\n #countsSnapshot: LogLevelCounts = {};\n #autoIdSeq = 0;\n /**\n * Auto-assigned ids, cached per entry *object*. A controlled re-mirror\n * (`setEntries` with the same entry objects) reuses the cached id instead of\n * minting a fresh one, so React/virtualization keys stay stable across\n * updates for id-less entries.\n */\n #idCache = new WeakMap<LogEntry, string>();\n #maxEntries: number | undefined;\n #getEntryId: ((entry: LogEntry, index: number) => string) | undefined;\n\n #pending: LogEntry[] | null = null;\n #rafId = 0;\n\n #entryListeners = new Set<Listener>();\n #countListeners = new Set<Listener>();\n #scrollToBottomFn: (() => void) | null = null;\n #scrollToIndexFn: ((index: number) => void) | null = null;\n\n constructor(\n options: {\n initial?: readonly LogEntry[];\n maxEntries?: number;\n getEntryId?: (entry: LogEntry, index: number) => string;\n } = {}\n ) {\n this.#maxEntries = options.maxEntries;\n this.#getEntryId = options.getEntryId;\n if (options.initial && options.initial.length > 0) {\n this.#entries = options.initial.map((entry, index) =>\n this.#normalize(entry, index)\n );\n this.#recomputeCounts();\n this.#trim();\n }\n }\n\n // ── Read API (arrow fns so they can be passed directly to subscribe hooks) ──\n\n getEntries = (): readonly ResolvedLogEntry[] => this.#entries;\n getCounts = (): LogLevelCounts => this.#countsSnapshot;\n\n subscribeEntries = (listener: Listener): (() => void) => {\n this.#entryListeners.add(listener);\n return () => {\n this.#entryListeners.delete(listener);\n };\n };\n\n subscribeCounts = (listener: Listener): (() => void) => {\n this.#countListeners.add(listener);\n return () => {\n this.#countListeners.delete(listener);\n };\n };\n\n // ── Configuration (re-applied by the root when props change) ──\n\n setMaxEntries(max: number | undefined): void {\n if (max === this.#maxEntries) return;\n this.#maxEntries = max;\n if (this.#trim()) this.#emit();\n }\n\n setGetEntryId(\n getEntryId: ((entry: LogEntry, index: number) => string) | undefined\n ): void {\n this.#getEntryId = getEntryId;\n }\n\n // ── Controlled mirror ──\n\n /** Replace all entries from the controlled `entries` prop. */\n setEntries(next: readonly LogEntry[]): void {\n // Cancel any buffered imperative appends — the controlled list wins.\n this.#pending = null;\n this.#entries = next.map((entry, index) => this.#normalize(entry, index));\n this.#recomputeCounts();\n this.#trim();\n this.#emit();\n }\n\n // ── Imperative (uncontrolled) writes — rAF-batched ──\n\n append(entry: LogEntry): void {\n (this.#pending ??= []).push(entry);\n this.#scheduleFlush();\n }\n\n appendMany(entries: readonly LogEntry[]): void {\n if (entries.length === 0) return;\n (this.#pending ??= []).push(...entries);\n this.#scheduleFlush();\n }\n\n clear(): void {\n this.#pending = null;\n if (this.#entries.length === 0) return;\n this.#entries = [];\n this.#counts = {};\n this.#countsSnapshot = {};\n this.#emit();\n }\n\n /** Flush buffered appends synchronously. Called on `pointerup`-style reads and in tests. */\n flush(): void {\n if (this.#rafId !== 0) {\n if (hasRaf) cancelAnimationFrame(this.#rafId);\n this.#rafId = 0;\n }\n const pending = this.#pending;\n if (!pending || pending.length === 0) {\n this.#pending = null;\n return;\n }\n this.#pending = null;\n\n const base = this.#entries.length;\n const appended = pending.map((entry, index) =>\n this.#normalize(entry, base + index)\n );\n this.#entries = this.#entries.concat(appended);\n for (const entry of appended) {\n this.#counts[entry.level] = (this.#counts[entry.level] ?? 0) + 1;\n }\n this.#trim();\n this.#publishCounts();\n this.#emit();\n }\n\n /** Cancel any scheduled flush. Call on unmount. */\n dispose(): void {\n if (this.#rafId !== 0 && hasRaf) cancelAnimationFrame(this.#rafId);\n this.#rafId = 0;\n this.#pending = null;\n this.#entryListeners.clear();\n this.#countListeners.clear();\n this.#scrollToBottomFn = null;\n this.#scrollToIndexFn = null;\n }\n\n // ── Scroll coordination (the Body registers its scroller) ──\n\n registerScroller(fn: () => void): () => void {\n this.#scrollToBottomFn = fn;\n return () => {\n if (this.#scrollToBottomFn === fn) this.#scrollToBottomFn = null;\n };\n }\n\n scrollToBottom(): void {\n this.#scrollToBottomFn?.();\n }\n\n registerScrollToIndex(fn: (index: number) => void): () => void {\n this.#scrollToIndexFn = fn;\n return () => {\n if (this.#scrollToIndexFn === fn) this.#scrollToIndexFn = null;\n };\n }\n\n scrollToIndex(index: number): void {\n this.#scrollToIndexFn?.(index);\n }\n\n // ── Internals ──\n\n #normalize(entry: LogEntry, index: number): ResolvedLogEntry {\n const level: LogLevel = entry.level ?? 'info';\n return {\n id: this.#resolveId(entry, index),\n level,\n message: entry.message,\n timestamp: entry.timestamp,\n source: entry.source,\n meta: entry.meta,\n };\n }\n\n /**\n * Resolve a stable id. An explicit `entry.id` or a `getEntryId` result wins;\n * otherwise an auto id is minted once per entry object and cached so the same\n * logical line keeps its key across controlled re-mirrors.\n */\n #resolveId(entry: LogEntry, index: number): string {\n if (entry.id !== undefined) return entry.id;\n const derived = this.#getEntryId?.(entry, index);\n if (derived !== undefined) return derived;\n const cached = this.#idCache.get(entry);\n if (cached !== undefined) return cached;\n const id = `__log_${this.#autoIdSeq++}__`;\n this.#idCache.set(entry, id);\n return id;\n }\n\n /** Drop oldest entries past the cap, decrementing counts. Returns true if trimmed. */\n #trim(): boolean {\n const max = this.#maxEntries;\n if (max === undefined || this.#entries.length <= max) return false;\n const removeCount = this.#entries.length - max;\n for (let i = 0; i < removeCount; i += 1) {\n const removed = this.#entries[i];\n if (removed) {\n const next = (this.#counts[removed.level] ?? 0) - 1;\n this.#counts[removed.level] = next > 0 ? next : 0;\n }\n }\n this.#entries = this.#entries.slice(removeCount);\n this.#publishCounts();\n return true;\n }\n\n #recomputeCounts(): void {\n const counts: Record<string, number> = {};\n for (const entry of this.#entries) {\n counts[entry.level] = (counts[entry.level] ?? 0) + 1;\n }\n this.#counts = counts;\n this.#publishCounts();\n }\n\n #publishCounts(): void {\n this.#countsSnapshot = { ...this.#counts };\n }\n\n #scheduleFlush(): void {\n if (this.#rafId !== 0) return;\n if (hasRaf) {\n this.#rafId = requestAnimationFrame(() => {\n this.#rafId = 0;\n this.flush();\n });\n } else {\n // SSR / non-DOM: flush on a microtask so behavior is still batched.\n this.#rafId = -1;\n queueMicrotask(() => {\n this.#rafId = 0;\n this.flush();\n });\n }\n }\n\n #emit(): void {\n this.#entryListeners.forEach(listener => {\n listener();\n });\n this.#countListeners.forEach(listener => {\n listener();\n });\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logViewLabels.js","sources":["
|
|
1
|
+
{"version":3,"file":"logViewLabels.js","sources":["src/components/feedback/LogView/logViewLabels.ts"],"sourcesContent":["import type { LogViewLabels } from './LogView.types';\n\n/**\n * English defaults for every user-facing string LogView renders. Override any\n * subset by passing `labels` to `<LogView>`; the rest fall back here.\n */\nexport const DEFAULT_LOG_VIEW_LABELS: LogViewLabels = {\n regionLabel: 'Log output',\n searchPlaceholder: 'Filter logs…',\n searchLabel: 'Filter logs',\n levelFilterLabel: 'Filter by level',\n clearLabel: 'Clear logs',\n copyLabel: 'Copy logs',\n copyLineLabel: 'Copy line',\n jumpToBottomLabel: 'Jump to bottom',\n newLinesLabel: count => `${count} new`,\n emptyLabel: 'No log entries',\n};\n\n/** Merge a partial `labels` override onto the English defaults. */\nexport function resolveLogViewLabels(\n overrides: Partial<LogViewLabels> | undefined\n): LogViewLabels {\n return overrides\n ? { ...DEFAULT_LOG_VIEW_LABELS, ...overrides }\n : DEFAULT_LOG_VIEW_LABELS;\n}\n"],"names":[],"mappings":"AAEA;;;AAGG;AACI,MAAM,uBAAuB,GAAkB;AACpD,IAAA,WAAW,EAAE,YAAY;AACzB,IAAA,iBAAiB,EAAE,cAAc;AACjC,IAAA,WAAW,EAAE,aAAa;AAC1B,IAAA,gBAAgB,EAAE,iBAAiB;AACnC,IAAA,UAAU,EAAE,YAAY;AACxB,IAAA,SAAS,EAAE,WAAW;AACtB,IAAA,aAAa,EAAE,WAAW;AAC1B,IAAA,iBAAiB,EAAE,gBAAgB;AACnC,IAAA,aAAa,EAAE,KAAK,IAAI,CAAA,EAAG,KAAK,CAAA,IAAA,CAAM;AACtC,IAAA,UAAU,EAAE,gBAAgB;;AAG9B;AACM,SAAU,oBAAoB,CAClC,SAA6C,EAAA;AAE7C,IAAA,OAAO;AACL,UAAE,EAAE,GAAG,uBAAuB,EAAE,GAAG,SAAS;UAC1C,uBAAuB;AAC7B;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logViewLevels.js","sources":["
|
|
1
|
+
{"version":3,"file":"logViewLevels.js","sources":["src/components/feedback/LogView/logViewLevels.ts"],"sourcesContent":["import { ErrorIcon } from '@/components/Icons/ErrorIcon';\nimport { InfoIcon } from '@/components/Icons/InfoIcon';\nimport { WarningIcon } from '@/components/Icons/WarningIcon';\n\nimport type {\n BuiltInLogLevel,\n LogLevel,\n LogLevelConfig,\n} from './LogView.types';\nimport type React from 'react';\n\n/** A component usable as a level icon (subset of the icon props we render). */\nexport type LevelIconComponent = React.ComponentType<{\n size?: 'sm' | 'md' | 'lg' | number;\n color?: string;\n}>;\n\n/** A level's fully-resolved visual definition. */\nexport interface ResolvedLevelDefinition {\n level: LogLevel;\n label: string;\n icon: LevelIconComponent | null;\n /** Inline color for custom levels; `undefined` for built-ins (themed via CSS). */\n color?: string;\n /** Whether this is one of the four built-in, CSS-themed levels. */\n isBuiltIn: boolean;\n}\n\n/** The four built-in levels, in default display order. */\nexport const BUILT_IN_LEVELS: readonly BuiltInLogLevel[] = [\n 'debug',\n 'info',\n 'warn',\n 'error',\n];\n\nconst BUILT_IN_DEFAULTS: Record<\n BuiltInLogLevel,\n { label: string; icon: LevelIconComponent | null; order: number }\n> = {\n debug: { label: 'Debug', icon: null, order: 0 },\n info: { label: 'Info', icon: InfoIcon, order: 1 },\n warn: { label: 'Warn', icon: WarningIcon, order: 2 },\n error: { label: 'Error', icon: ErrorIcon, order: 3 },\n};\n\nexport function isBuiltInLevel(level: LogLevel): level is BuiltInLogLevel {\n return (\n level === 'debug' ||\n level === 'info' ||\n level === 'warn' ||\n level === 'error'\n );\n}\n\nfunction capitalize(value: string): string {\n return value.length === 0\n ? value\n : value.charAt(0).toUpperCase() + value.slice(1);\n}\n\nfunction levelSortKey(\n level: LogLevel,\n config: LogLevelConfig | undefined\n): number {\n const configured = config?.[level]?.order;\n if (configured !== undefined) return configured;\n if (isBuiltInLevel(level)) return BUILT_IN_DEFAULTS[level].order;\n return 100;\n}\n\n/**\n * Resolve the ordered list of levels shown as filter chips. Defaults to the\n * four built-ins plus any keys present in `levelConfig`, sorted by `order`. An\n * explicit `levelOrder` short-circuits this.\n */\nexport function resolveLevelOrder(\n levelConfig: LogLevelConfig | undefined,\n explicit: readonly LogLevel[] | undefined\n): LogLevel[] {\n if (explicit) return [...explicit];\n const set = new Set<LogLevel>(BUILT_IN_LEVELS);\n if (levelConfig) {\n for (const key of Object.keys(levelConfig)) set.add(key);\n }\n return [...set].sort(\n (a, b) => levelSortKey(a, levelConfig) - levelSortKey(b, levelConfig)\n );\n}\n\n/** Resolve a single level's label, icon, and color. */\nexport function resolveLevelDefinition(\n level: LogLevel,\n config: LogLevelConfig | undefined\n): ResolvedLevelDefinition {\n const cfg = config?.[level];\n const builtIn = isBuiltInLevel(level);\n const defaults = builtIn ? BUILT_IN_DEFAULTS[level] : undefined;\n return {\n level,\n label: cfg?.label ?? defaults?.label ?? capitalize(String(level)),\n icon: cfg?.icon !== undefined ? cfg.icon : (defaults?.icon ?? null),\n color: builtIn ? undefined : cfg?.color,\n isBuiltIn: builtIn,\n };\n}\n\n/** Recipe `level` variant shared by the row and the filter chip. */\nexport type LevelVariant = BuiltInLogLevel | 'custom';\n\n/**\n * Map a resolved definition to the CSS recipe `level` variant: the concrete\n * built-in name (themed via CSS), or `'custom'` (colored via inline var).\n */\nexport function levelVariant(def: ResolvedLevelDefinition): LevelVariant {\n return def.isBuiltIn ? (def.level as BuiltInLogLevel) : 'custom';\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logViewUtils.js","sources":["
|
|
1
|
+
{"version":3,"file":"logViewUtils.js","sources":["src/components/feedback/LogView/logViewUtils.ts"],"sourcesContent":["import type { LogEntry, ResolvedLogEntry } from './LogView.types';\n\n/** A run of text, flagged as a search match or not. */\nexport interface HighlightSegment {\n text: string;\n match: boolean;\n}\n\n/**\n * Split `text` into alternating non-match / match segments for `query`.\n *\n * Pure and allocation-light: an empty (or whitespace-only) query returns a\n * single non-match segment so callers can render uniformly. Matching is\n * case-insensitive unless `caseSensitive` is set. All occurrences are marked.\n *\n * @example\n * getHighlightSegments('abcABC', 'bc')\n * // → [{text:'a',match:false},{text:'bc',match:true},\n * // {text:'A',match:false},{text:'BC',match:true}]\n */\nexport function getHighlightSegments(\n text: string,\n query: string,\n caseSensitive = false\n): HighlightSegment[] {\n const needle = query.trim();\n if (needle === '' || text === '') {\n return [{ text, match: false }];\n }\n\n const haystack = caseSensitive ? text : text.toLowerCase();\n const term = caseSensitive ? needle : needle.toLowerCase();\n\n const segments: HighlightSegment[] = [];\n let cursor = 0;\n let found = haystack.indexOf(term, cursor);\n\n if (found === -1) {\n return [{ text, match: false }];\n }\n\n while (found !== -1) {\n if (found > cursor) {\n segments.push({ text: text.slice(cursor, found), match: false });\n }\n segments.push({\n text: text.slice(found, found + term.length),\n match: true,\n });\n cursor = found + term.length;\n found = haystack.indexOf(term, cursor);\n }\n\n if (cursor < text.length) {\n segments.push({ text: text.slice(cursor), match: false });\n }\n\n return segments;\n}\n\n/** Pad a number to two digits. */\nfunction pad2(value: number): string {\n return value < 10 ? `0${value}` : String(value);\n}\n\n/** Pad a number to three digits. */\nfunction pad3(value: number): string {\n if (value < 10) return `00${value}`;\n if (value < 100) return `0${value}`;\n return String(value);\n}\n\n/**\n * Default timestamp formatter: `HH:mm:ss.SSS` in local time. Accepts epoch\n * milliseconds or a `Date`.\n */\nexport function defaultFormatTimestamp(timestamp: number | Date): string {\n const date = timestamp instanceof Date ? timestamp : new Date(timestamp);\n if (Number.isNaN(date.getTime())) return '';\n return `${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(\n date.getSeconds()\n )}.${pad3(date.getMilliseconds())}`;\n}\n\n/**\n * True when the entry matches the search query. Searches the message and the\n * optional source tag. An empty query always matches.\n */\nexport function entryMatchesQuery(\n entry: Pick<LogEntry, 'message' | 'source'>,\n query: string,\n caseSensitive = false\n): boolean {\n const needle = query.trim();\n if (needle === '') return true;\n const term = caseSensitive ? needle : needle.toLowerCase();\n const message = caseSensitive ? entry.message : entry.message.toLowerCase();\n if (message.includes(term)) return true;\n if (entry.source != null) {\n const source = caseSensitive ? entry.source : entry.source.toLowerCase();\n if (source.includes(term)) return true;\n }\n return false;\n}\n\n/**\n * Render one resolved entry to a plain-text line for copy/export. Includes the\n * timestamp and source when present, mirroring what the row shows.\n */\nexport function entryToText(\n entry: ResolvedLogEntry,\n options: {\n showTimestamps?: boolean;\n formatTimestamp?: (timestamp: number | Date) => string;\n } = {}\n): string {\n const { showTimestamps = false, formatTimestamp = defaultFormatTimestamp } =\n options;\n const parts: string[] = [];\n if (showTimestamps && entry.timestamp != null) {\n const formatted = formatTimestamp(entry.timestamp);\n if (formatted !== '') parts.push(formatted);\n }\n parts.push(`[${String(entry.level).toUpperCase()}]`);\n if (entry.source != null && entry.source !== '') {\n parts.push(`(${entry.source})`);\n }\n parts.push(entry.message);\n return parts.join(' ');\n}\n\n/**\n * Filter resolved entries by visible levels and a text query.\n *\n * Level rule: an entry is hidden only when its level is a *known* filter level\n * (has a chip) and that level is not active. Entries with an unknown level (no\n * chip) are always visible — toggling chips never hides them.\n */\nexport function filterEntries(\n entries: readonly ResolvedLogEntry[],\n options: {\n query: string;\n caseSensitive?: boolean;\n knownLevels: ReadonlySet<string>;\n activeLevels: ReadonlySet<string>;\n }\n): ResolvedLogEntry[] {\n const { query, caseSensitive = false, knownLevels, activeLevels } = options;\n const hasQuery = query.trim() !== '';\n return entries.filter(entry => {\n if (knownLevels.has(entry.level) && !activeLevels.has(entry.level)) {\n return false;\n }\n if (hasQuery && !entryMatchesQuery(entry, query, caseSensitive)) {\n return false;\n }\n return true;\n });\n}\n\n/** Join resolved entries into a copy/export blob. */\nexport function entriesToText(\n entries: readonly ResolvedLogEntry[],\n options?: {\n showTimestamps?: boolean;\n formatTimestamp?: (timestamp: number | Date) => string;\n }\n): string {\n return entries.map(entry => entryToText(entry, options)).join('\\n');\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFollowTail.js","sources":["
|
|
1
|
+
{"version":3,"file":"useFollowTail.js","sources":["src/components/feedback/LogView/useFollowTail.ts"],"sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { useLatest } from '@/hooks/useLatest';\n\nimport type { RefObject } from 'react';\n\nexport interface UseFollowTailOptions {\n /** The scroll viewport element. */\n scrollRef: RefObject<HTMLElement | null>;\n /** Whether to stick to the bottom as new entries arrive. */\n follow: boolean;\n /** Attach/detach follow. */\n setFollow: (follow: boolean) => void;\n /** Current number of (visible) entries — drives snap-on-append and the new-line badge. */\n entryCount: number;\n /** Distance from the bottom (px) still considered \"at bottom\". @default 8 */\n threshold?: number;\n}\n\nexport interface UseFollowTailResult {\n /** Scroll to the latest line and re-attach follow. */\n scrollToBottom: () => void;\n /** True when the user has scrolled up and detached from the tail. */\n isDetached: boolean;\n /** Entries appended since the user detached (0 while following). */\n newSinceDetach: number;\n}\n\n/**\n * Follow-tail behavior for a scrollable log body.\n *\n * - While `follow` is on, the viewport snaps to the bottom whenever the entry\n * count changes (a genuine scroll-position sync → `useLayoutEffect`).\n * - A manual scroll **up** detaches (`setFollow(false)`); scrolling back to the\n * bottom re-attaches. \"At bottom\" is read from live scroll metrics, never\n * from mirrored state, so it can't drift.\n * - Programmatic snaps are flagged so they don't read as a manual scroll.\n *\n * This logic is intentionally colocated with LogView (single consumer); promote\n * it to `src/hooks/` only if a second component needs it.\n */\nexport function useFollowTail({\n scrollRef,\n follow,\n setFollow,\n entryCount,\n threshold = 8,\n}: UseFollowTailOptions): UseFollowTailResult {\n const followRef = useLatest(follow);\n const setFollowRef = useLatest(setFollow);\n const entryCountRef = useLatest(entryCount);\n\n const isAutoScrollingRef = useRef(false);\n const resetRafRef = useRef(0);\n\n // Entry count captured at the moment of detach; `null` until the user\n // actually scrolls away (so a consumer starting with follow=false doesn't\n // miscount every existing line as \"new\"). The badge shows entryCount - this.\n const [detachedAtCount, setDetachedAtCount] = useState<number | null>(null);\n\n const performScrollToBottom = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n isAutoScrollingRef.current = true;\n el.scrollTop = el.scrollHeight;\n if (typeof requestAnimationFrame === 'function') {\n cancelAnimationFrame(resetRafRef.current);\n resetRafRef.current = requestAnimationFrame(() => {\n isAutoScrollingRef.current = false;\n });\n } else {\n isAutoScrollingRef.current = false;\n }\n }, [scrollRef]);\n\n // Snap to bottom on mount and whenever the entry count changes while attached.\n useLayoutEffect(() => {\n if (!follow) return;\n performScrollToBottom();\n }, [follow, entryCount, performScrollToBottom]);\n\n // Detach on manual scroll-up; re-attach on scroll-to-bottom. Listener attaches\n // once and reads live values through refs.\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const handleScroll = (): void => {\n if (isAutoScrollingRef.current) return;\n const atBottom =\n el.scrollHeight - el.clientHeight - el.scrollTop <= threshold;\n if (atBottom) {\n if (!followRef.current) {\n setDetachedAtCount(null);\n setFollowRef.current(true);\n }\n } else if (followRef.current) {\n setDetachedAtCount(entryCountRef.current);\n setFollowRef.current(false);\n }\n };\n\n el.addEventListener('scroll', handleScroll, { passive: true });\n return () => {\n el.removeEventListener('scroll', handleScroll);\n };\n }, [scrollRef, threshold, followRef, setFollowRef, entryCountRef]);\n\n useEffect(() => {\n return () => {\n if (typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(resetRafRef.current);\n }\n };\n }, []);\n\n const scrollToBottom = useCallback(() => {\n performScrollToBottom();\n setDetachedAtCount(null);\n setFollowRef.current(true);\n }, [performScrollToBottom, setFollowRef]);\n\n const newSinceDetach =\n follow || detachedAtCount === null\n ? 0\n : Math.max(0, entryCount - detachedAtCount);\n\n return { scrollToBottom, isDetached: !follow, newSinceDetach };\n}\n"],"names":[],"mappings":";;;;AAoCA;;;;;;;;;;;;AAYG;AACG;AAOJ;AACA;AACA;AAEA;AACA;;;;;AAOA;AACE;AACA;;AACA;AACA;AACA;AACE;AACA;AACE;AACF;;;AAEA;;AAEJ;;;AAIE;;AACA;;;;;AAMA;AACA;;;;;AAIE;;AAGE;;AAEE;;;AAEG;AACL;AACA;;AAEJ;AAEA;AACA;AACE;AACF;AACF;;AAGE;AACE;AACE;;AAEJ;;AAGF;AACE;;AAEA;AACF;AAEA;AAEI;;;AAIN;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLogSelection.js","sources":["
|
|
1
|
+
{"version":3,"file":"useLogSelection.js","sources":["src/components/feedback/LogView/useLogSelection.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useRef } from 'react';\n\nimport { useLatest } from '@/hooks/useLatest';\n\nimport type { LogViewSelectionMode, ResolvedLogEntry } from './LogView.types';\nimport type React from 'react';\n\nexport interface UseLogSelectionOptions {\n /** Active selection mode. */\n selectionMode: LogViewSelectionMode;\n /** Currently-selected entry ids. */\n selectedIds: ReadonlySet<string>;\n /** Replace the selection. */\n setSelectedIds: (ids: ReadonlySet<string>) => void;\n /** The currently-filtered entries (for range selection and select-all). */\n filtered: readonly ResolvedLogEntry[];\n /** Fired on row activation regardless of selection mode. */\n onEntryClick: ((entry: ResolvedLogEntry, index: number) => void) | undefined;\n /** True when the user has an active text selection inside the log body. */\n isTextSelected: () => boolean;\n /** Invoked on Cmd/Ctrl+C while a row selection exists. */\n onCopyShortcut: () => void;\n}\n\nexport interface UseLogSelectionResult {\n /** Click handler for a row (also reused for Enter/Space activation). */\n handleRowClick: (\n entry: ResolvedLogEntry,\n index: number,\n event: React.MouseEvent | React.KeyboardEvent\n ) => void;\n /** Keydown handler for a row: activation, copy, select-all, clear. */\n handleRowKeyDown: (\n entry: ResolvedLogEntry,\n index: number,\n event: React.KeyboardEvent<HTMLDivElement>\n ) => void;\n}\n\n/**\n * Row selection + keyboard behavior for the LogView body.\n *\n * - Click selects (single), Cmd/Ctrl+click toggles, Shift+click extends a range\n * from the anchor (multiple).\n * - Enter/Space activate the focused row; Cmd/Ctrl+C copies the selection (when\n * present and no text is selected); Cmd/Ctrl+A selects all visible; Escape\n * clears.\n * - A drag-to-select-text gesture is never treated as a row click.\n *\n * Consumer values are read through `useLatest` so the returned handlers stay\n * identity-stable (they never have to be memoized by the caller). Colocated\n * with LogView (single consumer); promote to `src/hooks/` only if a second\n * component needs it.\n */\nexport function useLogSelection({\n selectionMode,\n selectedIds,\n setSelectedIds,\n filtered,\n onEntryClick,\n isTextSelected,\n onCopyShortcut,\n}: UseLogSelectionOptions): UseLogSelectionResult {\n const anchorRef = useRef<number | null>(null);\n const filteredRef = useLatest(filtered);\n const selectedIdsRef = useLatest(selectedIds);\n const onEntryClickRef = useLatest(onEntryClick);\n const isTextSelectedRef = useLatest(isTextSelected);\n const onCopyShortcutRef = useLatest(onCopyShortcut);\n\n const handleRowClick = useCallback(\n (\n entry: ResolvedLogEntry,\n index: number,\n event: React.MouseEvent | React.KeyboardEvent\n ) => {\n // Don't treat a drag-to-select-text gesture as a row click.\n if (isTextSelectedRef.current()) return;\n onEntryClickRef.current?.(entry, index);\n if (selectionMode === false) return;\n\n const { id } = entry;\n if (selectionMode === 'single') {\n anchorRef.current = index;\n setSelectedIds(new Set([id]));\n return;\n }\n\n if (event.shiftKey && anchorRef.current !== null) {\n const list = filteredRef.current;\n const from = Math.min(anchorRef.current, index);\n const to = Math.max(anchorRef.current, index);\n const range = new Set<string>();\n for (let i = from; i <= to; i += 1) {\n const rangeEntry = list[i];\n if (rangeEntry) range.add(rangeEntry.id);\n }\n setSelectedIds(range);\n } else if (event.metaKey || event.ctrlKey) {\n const next = new Set(selectedIdsRef.current);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n anchorRef.current = index;\n setSelectedIds(next);\n } else {\n anchorRef.current = index;\n setSelectedIds(new Set([id]));\n }\n },\n [\n selectionMode,\n setSelectedIds,\n filteredRef,\n selectedIdsRef,\n onEntryClickRef,\n isTextSelectedRef,\n ]\n );\n\n const handleRowKeyDown = useCallback(\n (\n entry: ResolvedLogEntry,\n index: number,\n event: React.KeyboardEvent<HTMLDivElement>\n ) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleRowClick(entry, index, event);\n return;\n }\n const meta = event.metaKey || event.ctrlKey;\n if (meta && (event.key === 'c' || event.key === 'C')) {\n // Let the browser copy an active text selection instead.\n if (isTextSelectedRef.current() || selectedIdsRef.current.size === 0) {\n return;\n }\n event.preventDefault();\n onCopyShortcutRef.current();\n return;\n }\n if (selectionMode === false) return;\n if (meta && (event.key === 'a' || event.key === 'A')) {\n event.preventDefault();\n setSelectedIds(new Set(filteredRef.current.map(item => item.id)));\n return;\n }\n if (event.key === 'Escape' && selectedIdsRef.current.size > 0) {\n event.preventDefault();\n setSelectedIds(new Set());\n }\n },\n [\n handleRowClick,\n selectionMode,\n setSelectedIds,\n filteredRef,\n selectedIdsRef,\n isTextSelectedRef,\n onCopyShortcutRef,\n ]\n );\n\n return { handleRowClick, handleRowKeyDown };\n}\n"],"names":[],"mappings":";;;;AAyCA;;;;;;;;;;;;;;AAcG;;AAUD;AACA;AACA;AACA;AACA;AACA;;;;;;;;AAaI;AACA;AACE;;;;;AAMA;AACA;AACA;AACA;AACA;AACE;AACA;AAAgB;;;;;;AAKlB;AAAkB;;AACb;AACL;;;;AAGA;;;AAGJ;;;;;;;AAQC;;AASC;;AAEE;;;;AAIF;;AAEE;;;;;;;;;AAQF;;;;;AAKA;;AAEE;;AAEJ;;;;;;;;AASC;AAGH;AACF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CircularProgress.js","sources":["
|
|
1
|
+
{"version":3,"file":"CircularProgress.js","sources":["src/components/feedback/ProgressBar/CircularProgress.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\n\nimport {\n circularFillCircleStyle,\n circularIndeterminateStyle,\n circularLabelStyle,\n circularRootStyle,\n circularSvgStyle,\n circularTrackCircleStyle,\n progressColorVar,\n} from './ProgressBar.css';\n\nimport type {\n CircularProgressProps,\n CircularProgressSize,\n ProgressBarColor,\n} from './ProgressBar.types';\n\nconst SIZE_MAP: Record<CircularProgressSize, number> = {\n xs: 16,\n sm: 20,\n md: 24,\n lg: 32,\n xl: 48,\n};\n\nconst DEFAULT_THICKNESS: Record<CircularProgressSize, number> = {\n xs: 1.5,\n sm: 2,\n md: 2,\n lg: 2.5,\n xl: 3,\n};\n\nconst LABEL_FONT_SIZE: Record<CircularProgressSize, string> = {\n xs: vars.typography.fontSize.xxs,\n sm: vars.typography.fontSize.xxs,\n md: vars.typography.fontSize.xs,\n lg: vars.typography.fontSize.xs,\n xl: vars.typography.fontSize.sm,\n};\n\nconst NAMED_COLOR_MAP: Record<string, string> = {\n primary: vars.colors.accent.primary,\n success: vars.colors.accent.success,\n warning: vars.colors.accent.warning,\n error: vars.colors.accent.error,\n};\n\nfunction resolveColor(color: ProgressBarColor): string {\n return NAMED_COLOR_MAP[color] ?? color;\n}\n\nfunction clampValue(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n\nfunction toPercent(clamped: number, min: number, max: number): number {\n if (max === min) return 0;\n return ((clamped - min) / (max - min)) * 100;\n}\n\nfunction deriveValueText(\n ariaValueText: string | undefined,\n label: React.ReactNode\n): string | undefined {\n if (ariaValueText !== undefined) return ariaValueText;\n if (typeof label === 'string') return label;\n if (typeof label === 'number') return String(label);\n return undefined;\n}\n\n/**\n * Circular progress indicator.\n *\n * Determinate when `value` is provided; indeterminate (rotating arc) when\n * `value` is `undefined`. Renders an SVG with two stacked circles — track\n * and fill — using `stroke-dasharray` to draw the progress arc. Honors\n * `prefers-reduced-motion`.\n *\n * @example\n * ```tsx\n * <CircularProgress value={75} />\n * <CircularProgress size=\"xl\" value={42} showLabel />\n * <CircularProgress /> // indeterminate\n * ```\n */\nexport const CircularProgress = /*#__PURE__*/ React.memo<CircularProgressProps>(\n ({\n value,\n min = 0,\n max = 100,\n size = 'md',\n thickness,\n color = 'primary',\n showLabel = false,\n label,\n ariaLabel,\n ariaValueText,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const indeterminate = value === undefined;\n const clampedValue = indeterminate ? 0 : clampValue(value, min, max);\n const percent = toPercent(clampedValue, min, max);\n const resolvedColor = resolveColor(color);\n const diameter = SIZE_MAP[size];\n const stroke = thickness ?? DEFAULT_THICKNESS[size];\n const radius = (diameter - stroke) / 2;\n const circumference = 2 * Math.PI * radius;\n const dashOffset = indeterminate\n ? circumference * 0.75\n : circumference * (1 - percent / 100);\n\n const inlineVars = assignInlineVars({\n [progressColorVar]: resolvedColor,\n });\n\n const percentText = `${Math.round(percent)}%`;\n const labelContent = label ?? (indeterminate ? null : percentText);\n const showLabelText = showLabel && labelContent !== null;\n\n const ariaProps: React.AriaAttributes = {\n 'aria-valuemin': min,\n 'aria-valuemax': max,\n 'aria-label': ariaLabel ?? (indeterminate ? 'Loading' : undefined),\n };\n if (!indeterminate) {\n ariaProps['aria-valuenow'] = clampedValue;\n const valueText = deriveValueText(ariaValueText, label);\n if (valueText !== undefined) {\n ariaProps['aria-valuetext'] = valueText;\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"progressbar\"\n className={cx(circularRootStyle, className)}\n style={{\n ...inlineVars,\n width: diameter,\n height: diameter,\n ...style,\n }}\n data-testid={testId}\n data-indeterminate={indeterminate ? 'true' : undefined}\n {...ariaProps}\n {...rest}\n >\n <svg\n className={circularSvgStyle}\n width={diameter}\n height={diameter}\n viewBox={`0 0 ${diameter} ${diameter}`}\n aria-hidden\n >\n <circle\n className={circularTrackCircleStyle}\n cx={diameter / 2}\n cy={diameter / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n />\n <circle\n className={cx(\n circularFillCircleStyle,\n indeterminate && circularIndeterminateStyle\n )}\n cx={diameter / 2}\n cy={diameter / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={stroke}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={dashOffset}\n transform={\n indeterminate\n ? undefined\n : `rotate(-90 ${diameter / 2} ${diameter / 2})`\n }\n />\n </svg>\n {showLabelText ? (\n <span\n className={circularLabelStyle}\n style={{ fontSize: LABEL_FONT_SIZE[size] }}\n >\n {labelContent}\n </span>\n ) : null}\n </div>\n );\n }\n);\n\nCircularProgress.displayName = 'CircularProgress';\n"],"names":[],"mappings":";;;;;;;;AAwBA;AACE;AACA;AACA;AACA;AACA;;AAGF;AACE;AACA;AACA;AACA;AACA;;AAGF;AACE;AACA;AACA;AACA;AACA;;AAGF;AACE;AACA;AACA;AACA;;AAGF;AACE;AACF;AAEA;AACE;AACF;AAEA;;AACmB;AACjB;AACF;AAEA;;AAImC;;AACF;;AACA;AAC/B;AACF;AAEA;;;;;;;;;;;;;;AAcG;AACI;AAkBH;AACA;;AAEA;AACA;;;;;;;;;AAUC;;AAGD;AACA;AAEA;AACE;AACA;AACA;;;AAGA;;AAEA;AACE;;;;AAUE;AACA;AACA;AACA;;AAqCM;AACA;AAcd;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressBar.js","sources":["
|
|
1
|
+
{"version":3,"file":"ProgressBar.js","sources":["src/components/feedback/ProgressBar/ProgressBar.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\n\nimport {\n progressColorVar,\n progressFillBaseStyle,\n progressFillStripedAnimatedStyle,\n progressFillStripedStyle,\n progressFillWidthVar,\n progressIndeterminateStyle,\n progressInlineLabelStyle,\n progressOverlayLabelStyle,\n progressRootStyle,\n progressTrackRecipe,\n} from './ProgressBar.css';\n\nimport type { ProgressBarColor, ProgressBarProps } from './ProgressBar.types';\n\nconst NAMED_COLOR_MAP: Record<string, string> = {\n primary: vars.colors.accent.primary,\n success: vars.colors.accent.success,\n warning: vars.colors.accent.warning,\n error: vars.colors.accent.error,\n};\n\nfunction resolveColor(color: ProgressBarColor): string {\n return NAMED_COLOR_MAP[color] ?? color;\n}\n\nfunction clampValue(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max));\n}\n\nfunction toPercent(clamped: number, min: number, max: number): number {\n if (max === min) return 0;\n return ((clamped - min) / (max - min)) * 100;\n}\n\nfunction deriveValueText(\n ariaValueText: string | undefined,\n label: React.ReactNode\n): string | undefined {\n if (ariaValueText !== undefined) return ariaValueText;\n if (typeof label === 'string') return label;\n if (typeof label === 'number') return String(label);\n return undefined;\n}\n\n/**\n * Linear progress indicator.\n *\n * Determinate when `value` is provided; indeterminate (animated sliding bar)\n * when `value` is `undefined`. Supports inline / overlay / custom labels,\n * striped texture (optionally animated), and arbitrary CSS colors. Honors\n * `prefers-reduced-motion`.\n *\n * @example\n * ```tsx\n * <ProgressBar value={60} />\n * <ProgressBar value={50} showLabel=\"inline\" />\n * <ProgressBar size=\"lg\" value={75} striped animated />\n * <ProgressBar /> // indeterminate\n * ```\n */\nexport const ProgressBar = /*#__PURE__*/ React.memo<ProgressBarProps>(\n ({\n value,\n min = 0,\n max = 100,\n size = 'md',\n color = 'primary',\n showLabel = false,\n label,\n striped = false,\n animated = false,\n ariaLabel,\n ariaValueText,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const indeterminate = value === undefined;\n const clampedValue = indeterminate ? 0 : clampValue(value, min, max);\n const percent = toPercent(clampedValue, min, max);\n const resolvedColor = resolveColor(color);\n\n const inlineVars = assignInlineVars({\n [progressColorVar]: resolvedColor,\n [progressFillWidthVar]: `${percent}%`,\n });\n\n const fillClassName = cx(\n progressFillBaseStyle,\n striped && progressFillStripedStyle,\n striped && animated && progressFillStripedAnimatedStyle\n );\n\n const percentText = `${Math.round(percent)}%`;\n const labelContent = label ?? (indeterminate ? null : percentText);\n\n const ariaProps: React.AriaAttributes = {\n 'aria-valuemin': min,\n 'aria-valuemax': max,\n 'aria-label': ariaLabel ?? (indeterminate ? 'Loading' : undefined),\n };\n if (!indeterminate) {\n ariaProps['aria-valuenow'] = clampedValue;\n const valueText = deriveValueText(ariaValueText, label);\n if (valueText !== undefined) {\n ariaProps['aria-valuetext'] = valueText;\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"progressbar\"\n className={cx(progressRootStyle, className)}\n style={{ ...inlineVars, ...style }}\n data-testid={testId}\n data-indeterminate={indeterminate ? 'true' : undefined}\n {...ariaProps}\n {...rest}\n >\n <div className={progressTrackRecipe({ size })}>\n {indeterminate ? (\n <div className={progressIndeterminateStyle} aria-hidden />\n ) : (\n <div className={fillClassName} aria-hidden />\n )}\n {showLabel === 'overlay' && labelContent !== null ? (\n <span className={progressOverlayLabelStyle}>{labelContent}</span>\n ) : null}\n </div>\n {showLabel === 'inline' && labelContent !== null ? (\n <span className={progressInlineLabelStyle}>{labelContent}</span>\n ) : null}\n </div>\n );\n }\n);\n\nProgressBar.displayName = 'ProgressBar';\n"],"names":[],"mappings":";;;;;;;;AAuBA;AACE;AACA;AACA;AACA;;AAGF;AACE;AACF;AAEA;AACE;AACF;AAEA;;AACmB;AACjB;AACF;AAEA;;AAImC;;AACF;;AACA;AAC/B;AACF;AAEA;;;;;;;;;;;;;;;AAeG;AACI;AAmBH;AACA;;AAEA;;;AAIE;AACD;AAED;;AAOA;AAEA;AACE;AACA;AACA;;;AAGA;;AAEA;AACE;;;AAIJ;AA0BF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Skeleton.js","sources":["
|
|
1
|
+
{"version":3,"file":"Skeleton.js","sources":["src/components/feedback/Skeleton/Skeleton.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\nimport { devWarn } from '@/utils/devWarn';\n\nimport {\n skeletonHeightVar,\n skeletonRadiusVar,\n skeletonRecipe,\n skeletonWidthVar,\n} from './Skeleton.css';\n\nimport type { SkeletonProps, SkeletonShape } from './Skeleton.types';\n\nconst LINE_DEFAULT_HEIGHT = '12px';\n\nconst SHAPE_RADIUS_FALLBACK: Record<SkeletonShape, string> = {\n rect: vars.borderRadius.sm,\n line: vars.borderRadius.lg,\n circle: '50%',\n};\n\nfunction resolveDimension(\n value: number | string | undefined\n): string | undefined {\n if (value === undefined) return undefined;\n return typeof value === 'number' ? `${value}px` : value;\n}\n\nfunction resolveDefaults(\n shape: SkeletonShape,\n width: number | string | undefined,\n height: number | string | undefined,\n borderRadius: number | string | undefined\n): { width: string; height: string; radius: string } {\n const resolvedWidth = resolveDimension(width) ?? '100%';\n\n let resolvedHeight = resolveDimension(height);\n if (resolvedHeight === undefined) {\n if (shape === 'line') {\n resolvedHeight = LINE_DEFAULT_HEIGHT;\n } else if (shape === 'circle') {\n resolvedHeight = resolvedWidth;\n } else {\n resolvedHeight = '100%';\n }\n }\n\n const resolvedRadius =\n resolveDimension(borderRadius) ?? SHAPE_RADIUS_FALLBACK[shape];\n\n return {\n width: resolvedWidth,\n height: resolvedHeight,\n radius: resolvedRadius,\n };\n}\n\n/**\n * Loading-placeholder block.\n *\n * Renders a rectangle, circle, or line shape with a configurable animation\n * (`pulse`, `wave`, `none`). Use it while waiting for real content to load.\n *\n * Skeletons are decorative — they set `aria-hidden=\"true\"` and `aria-busy=\"true\"`\n * but do not announce themselves. The surrounding region should announce\n * the loading state (e.g. via `Spinner` or `EmptyState loading`).\n *\n * @example\n * ```tsx\n * <Skeleton width={120} height={16} />\n * <Skeleton shape=\"circle\" width={32} />\n * <Skeleton shape=\"line\" width=\"60%\" />\n * <Skeleton animation=\"wave\" height={80} />\n * ```\n */\nexport const Skeleton = /*#__PURE__*/ React.memo<SkeletonProps>(\n ({\n shape = 'rect',\n width,\n height,\n borderRadius,\n animation = 'pulse',\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n if (\n shape === 'circle' &&\n width !== undefined &&\n height !== undefined &&\n width !== height\n ) {\n devWarn(\n '[Skeleton] shape=\"circle\" expects equal width and height; received width=%o, height=%o.',\n width,\n height\n );\n }\n\n const {\n width: w,\n height: h,\n radius,\n } = resolveDefaults(shape, width, height, borderRadius);\n\n const inlineVars = assignInlineVars({\n [skeletonWidthVar]: w,\n [skeletonHeightVar]: h,\n [skeletonRadiusVar]: radius,\n });\n\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n aria-busy=\"true\"\n className={cx(skeletonRecipe({ shape, animation }), className)}\n style={{ ...inlineVars, ...style }}\n data-testid={testId}\n data-shape={shape}\n data-animation={animation}\n {...rest}\n />\n );\n }\n);\n\nSkeleton.displayName = 'Skeleton';\n"],"names":[],"mappings":";;;;;;;;;AAkBA;AAEA;AACE;AACA;AACA;;AAGF;;AAG2B;AACzB;AACF;AAEA;;AAQE;AACA;AACE;;;AAEO;;;;;;;;;AAWP;AACA;AACA;;AAEJ;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACI;;AAeD;AACA;;AAGA;;;;;;;AAiBD;;AAeH;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonGroup.js","sources":["
|
|
1
|
+
{"version":3,"file":"SkeletonGroup.js","sources":["src/components/feedback/Skeleton/SkeletonGroup.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\n\nimport { Skeleton } from './Skeleton';\nimport { skeletonGroupGapVar, skeletonGroupRecipe } from './Skeleton.css';\n\nimport type { SkeletonGroupProps } from './Skeleton.types';\n\nconst SPACING_SCALE: readonly string[] = [\n '0',\n vars.spacing.xs,\n vars.spacing.sm,\n vars.spacing.md,\n vars.spacing.lg,\n vars.spacing.xl,\n vars.spacing.xxl,\n vars.spacing.xxxl,\n];\n\nfunction resolveSpacing(value: number | string): string {\n if (typeof value === 'string') return value;\n const clamped = Math.max(0, Math.min(SPACING_SCALE.length - 1, value));\n const index = Math.floor(clamped);\n return SPACING_SCALE[index] ?? vars.spacing.sm;\n}\n\n/**\n * Lays out one or more `Skeleton` items consistently — handy for \"show\n * five skeleton rows then real data\" patterns.\n *\n * Pass `count` to auto-generate that many skeletons (using `itemProps` to\n * configure them), or pass `children` to lay out custom skeleton shapes\n * yourself. `direction` and `spacing` control the flex container.\n *\n * @example\n * ```tsx\n * // Five lines stacked vertically\n * <SkeletonGroup count={5} itemProps={{ shape: 'line' }} />\n *\n * // Custom composition\n * <SkeletonGroup direction=\"row\" spacing={3}>\n * <Skeleton shape=\"circle\" width={32} />\n * <Skeleton shape=\"line\" width={120} />\n * </SkeletonGroup>\n * ```\n */\nexport const SkeletonGroup = /*#__PURE__*/ React.memo<SkeletonGroupProps>(\n ({\n count,\n spacing = 2,\n direction = 'column',\n itemProps,\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const inlineVars = assignInlineVars({\n [skeletonGroupGapVar]: resolveSpacing(spacing),\n });\n\n const content =\n children ??\n Array.from({ length: count ?? 0 }, (_, i) => (\n <Skeleton key={i} {...itemProps} />\n ));\n\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n aria-busy=\"true\"\n className={cx(skeletonGroupRecipe({ direction }), className)}\n style={{ ...inlineVars, ...style }}\n data-testid={testId}\n {...rest}\n >\n {content}\n </div>\n );\n }\n);\n\nSkeletonGroup.displayName = 'SkeletonGroup';\n"],"names":[],"mappings":";;;;;;;;;AAaA;;;;;;;;;;AAWA;;AACiC;;;;AAIjC;AAEA;;;;;;;;;;;;;;;;;;;AAmBG;AACI;;AAcD;AACD;;AAIC;AAIF;AAaF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonLayout.js","sources":["
|
|
1
|
+
{"version":3,"file":"SkeletonLayout.js","sources":["src/components/feedback/Skeleton/SkeletonLayout.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { Skeleton } from './Skeleton';\nimport {\n cardBodyStyle,\n cardLayoutStyle,\n chatBubbleStyle,\n chatLayoutStyle,\n chatRowEndStyle,\n chatRowStyle,\n gridLayoutStyle,\n layoutColumnsVar,\n listLayoutStyle,\n listRowBodyStyle,\n listRowStyle,\n tableHeaderCellStyle,\n tableLayoutStyle,\n} from './SkeletonLayout.css';\n\nimport type {\n SkeletonAnimation,\n SkeletonLayoutProps,\n SkeletonLayoutVariant,\n} from './Skeleton.types';\n\nconst DEFAULT_COUNT: Record<SkeletonLayoutVariant, number> = {\n card: 1,\n list: 5,\n table: 5,\n grid: 12,\n chat: 4,\n};\n\nconst DEFAULT_ANIMATION: Record<SkeletonLayoutVariant, SkeletonAnimation> = {\n card: 'pulse',\n list: 'pulse',\n table: 'pulse',\n grid: 'none',\n chat: 'pulse',\n};\n\nconst DEFAULT_COLUMNS = 4;\n\nfunction renderCard(animation: SkeletonAnimation): React.ReactNode {\n return (\n <div className={cardLayoutStyle}>\n <Skeleton shape=\"circle\" width={40} animation={animation} />\n <div className={cardBodyStyle}>\n <Skeleton shape=\"line\" width=\"70%\" animation={animation} />\n <Skeleton shape=\"line\" width=\"100%\" animation={animation} />\n <Skeleton shape=\"line\" width=\"50%\" animation={animation} />\n <Skeleton width=\"100%\" height={80} animation={animation} />\n </div>\n </div>\n );\n}\n\nfunction renderList(\n count: number,\n animation: SkeletonAnimation\n): React.ReactNode {\n return (\n <div className={listLayoutStyle}>\n {Array.from({ length: count }, (_, i) => (\n <div key={i} className={listRowStyle}>\n <Skeleton shape=\"circle\" width={32} animation={animation} />\n <div className={listRowBodyStyle}>\n <Skeleton shape=\"line\" width=\"60%\" animation={animation} />\n <Skeleton shape=\"line\" width=\"90%\" animation={animation} />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderTable(\n rows: number,\n columns: number,\n animation: SkeletonAnimation\n): React.ReactNode {\n const totalCells = (rows + 1) * columns;\n return (\n <div\n className={tableLayoutStyle}\n style={assignInlineVars({ [layoutColumnsVar]: String(columns) })}\n >\n {Array.from({ length: totalCells }, (_, i) => {\n const isHeader = i < columns;\n return (\n <div key={i} className={isHeader ? tableHeaderCellStyle : undefined}>\n <Skeleton\n shape=\"line\"\n width={isHeader ? '50%' : '80%'}\n animation={animation}\n />\n </div>\n );\n })}\n </div>\n );\n}\n\nfunction renderGrid(\n count: number,\n columns: number,\n animation: SkeletonAnimation\n): React.ReactNode {\n return (\n <div\n className={gridLayoutStyle}\n style={assignInlineVars({ [layoutColumnsVar]: String(columns) })}\n >\n {Array.from({ length: count }, (_, i) => (\n <Skeleton key={i} width=\"100%\" height={80} animation={animation} />\n ))}\n </div>\n );\n}\n\nconst CHAT_BUBBLE_WIDTHS = ['85%', '60%', '95%', '70%', '50%', '80%'] as const;\n\nfunction renderChat(\n count: number,\n animation: SkeletonAnimation\n): React.ReactNode {\n return (\n <div className={chatLayoutStyle}>\n {Array.from({ length: count }, (_, i) => {\n const isOutgoing = i % 2 === 1;\n const bubbleWidth = CHAT_BUBBLE_WIDTHS[i % CHAT_BUBBLE_WIDTHS.length];\n return (\n <div\n key={i}\n className={cx(chatRowStyle, isOutgoing && chatRowEndStyle)}\n >\n <Skeleton shape=\"circle\" width={28} animation={animation} />\n <div className={chatBubbleStyle}>\n <Skeleton\n shape=\"line\"\n width={bubbleWidth}\n animation={animation}\n />\n {i % 3 === 0 ? (\n <Skeleton shape=\"line\" width=\"40%\" animation={animation} />\n ) : null}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * Pre-built skeleton layouts for common loading patterns — card, list, table,\n * grid, and chat. Drop one in when the surrounding UI shape is known and you\n * want the placeholder structure to mirror it without composing every block\n * by hand.\n *\n * Each variant uses the base `Skeleton` primitive underneath, so animation\n * and reduced-motion behavior match the rest of the library. Use `count` to\n * scale the number of rows/cells, `columns` for `grid` and `table`, and\n * `animation` to opt out of motion for dense surfaces.\n *\n * @example\n * ```tsx\n * <SkeletonLayout variant=\"card\" />\n * <SkeletonLayout variant=\"list\" count={8} />\n * <SkeletonLayout variant=\"table\" columns={5} count={6} />\n * <SkeletonLayout variant=\"grid\" columns={3} count={9} />\n * <SkeletonLayout variant=\"chat\" count={6} />\n * ```\n */\nexport const SkeletonLayout = /*#__PURE__*/ React.memo<SkeletonLayoutProps>(\n ({\n variant,\n count,\n columns = DEFAULT_COLUMNS,\n animation,\n width = '100%',\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const resolvedCount = count ?? DEFAULT_COUNT[variant];\n const resolvedAnimation = animation ?? DEFAULT_ANIMATION[variant];\n const resolvedWidth = typeof width === 'number' ? `${width}px` : width;\n\n let content: React.ReactNode;\n switch (variant) {\n case 'card':\n content = renderCard(resolvedAnimation);\n break;\n case 'list':\n content = renderList(resolvedCount, resolvedAnimation);\n break;\n case 'table':\n content = renderTable(resolvedCount, columns, resolvedAnimation);\n break;\n case 'grid':\n content = renderGrid(resolvedCount, columns, resolvedAnimation);\n break;\n case 'chat':\n content = renderChat(resolvedCount, resolvedAnimation);\n break;\n }\n\n return (\n <div\n ref={ref}\n aria-hidden=\"true\"\n aria-busy=\"true\"\n className={cx(className)}\n style={{ width: resolvedWidth, ...style }}\n data-testid={testId}\n data-variant={variant}\n {...rest}\n >\n {content}\n </div>\n );\n }\n);\n\nSkeletonLayout.displayName = 'SkeletonLayout';\n"],"names":[],"mappings":";;;;;;;;AA8BA;AACE;AACA;AACA;AACA;AACA;;AAGF;AACE;AACA;AACA;AACA;AACA;;AAGF;AAEA;;AAYA;AAEA;AAIE;AAaF;AAEA;;AAME;AAMM;AACA;;AAYR;AAEA;AAKE;AAUF;AAEA;AAEA;;AAOQ;;AAEA;;AAqBR;AAEA;;;;;;;;;;;;;;;;;;;AAmBG;AACI;;;AAeH;AAEA;;AAEE;AACE;;AAEF;AACE;;AAEF;;;AAGA;;;AAGA;AACE;;;AAIJ;AAcF;AAGF;;"}
|
|
@@ -25,16 +25,20 @@ function resolveColor(color) {
|
|
|
25
25
|
* Loading / activity indicator.
|
|
26
26
|
*
|
|
27
27
|
* Announces itself via `role="status"` and `aria-label`; honors
|
|
28
|
-
* `prefers-reduced-motion` by halting animation and dimming the indicator.
|
|
28
|
+
* `prefers-reduced-motion` by halting animation and dimming the indicator. Pass
|
|
29
|
+
* `decorative` to opt out of the live region when nested inside one (e.g. a
|
|
30
|
+
* `StatusBar`).
|
|
29
31
|
*
|
|
30
32
|
* @example
|
|
31
33
|
* ```tsx
|
|
32
34
|
* <Spinner />
|
|
33
35
|
* <Spinner variant="dots" size="lg" />
|
|
34
36
|
* <Spinner showLabel label="Fetching results..." />
|
|
37
|
+
* // Inside a StatusBar (already role="status"):
|
|
38
|
+
* <Spinner decorative size="sm" />
|
|
35
39
|
* ```
|
|
36
40
|
*/
|
|
37
|
-
const Spinner = /*#__PURE__*/ React.memo(({ size = 'md', variant = 'ring', color = 'accent', label = 'Loading...', showLabel = false, className, style, testId, ref, ...rest }) => {
|
|
41
|
+
const Spinner = /*#__PURE__*/ React.memo(({ size = 'md', variant = 'ring', color = 'accent', label = 'Loading...', showLabel = false, decorative = false, className, style, testId, ref, ...rest }) => {
|
|
38
42
|
const resolvedColor = resolveColor(color);
|
|
39
43
|
const resolvedSize = SIZE_MAP[size];
|
|
40
44
|
const inlineVars = assignInlineVars({
|
|
@@ -42,7 +46,12 @@ const Spinner = /*#__PURE__*/ React.memo(({ size = 'md', variant = 'ring', color
|
|
|
42
46
|
[spinnerSizeVar]: resolvedSize,
|
|
43
47
|
});
|
|
44
48
|
const indicator = variant === 'ring' ? (jsx("span", { className: spinnerRingStyle, "aria-hidden": true })) : variant === 'pulse' ? (jsx("span", { className: spinnerPulseStyle, "aria-hidden": true })) : (jsxs("span", { className: spinnerDotsSizerStyle, "aria-hidden": true, children: [jsx("span", { className: spinnerDotRecipe({ delay: '0' }) }), jsx("span", { className: spinnerDotRecipe({ delay: '1' }) }), jsx("span", { className: spinnerDotRecipe({ delay: '2' }) })] }));
|
|
45
|
-
|
|
49
|
+
// Decorative spinners drop the live region (and label) so a surrounding
|
|
50
|
+
// live region (e.g. StatusBar's role="status") is the single announcer.
|
|
51
|
+
const semanticProps = decorative
|
|
52
|
+
? { role: 'presentation', 'aria-hidden': true }
|
|
53
|
+
: { role: 'status', 'aria-live': 'polite', 'aria-label': label };
|
|
54
|
+
return (jsxs("span", { ref: ref, ...semanticProps, className: cx(spinnerRootStyle, className), style: { ...inlineVars, ...style }, "data-testid": testId, ...rest, children: [indicator, showLabel ? (jsx("span", { className: spinnerLabelStyle, children: label })) : decorative ? null : (jsx("span", { className: visuallyHiddenStyle, children: label }))] }));
|
|
46
55
|
});
|
|
47
56
|
Spinner.displayName = 'Spinner';
|
|
48
57
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Spinner.js","sources":["
|
|
1
|
+
{"version":3,"file":"Spinner.js","sources":["src/components/feedback/Spinner/Spinner.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\n\nimport {\n spinnerColorVar,\n spinnerDotRecipe,\n spinnerDotsSizerStyle,\n spinnerLabelStyle,\n spinnerPulseStyle,\n spinnerRingStyle,\n spinnerRootStyle,\n spinnerSizeVar,\n visuallyHiddenStyle,\n} from './Spinner.css';\n\nimport type { SpinnerColor, SpinnerProps, SpinnerSize } from './Spinner.types';\n\nconst SIZE_MAP: Record<SpinnerSize, string> = {\n xs: '12px',\n sm: '14px',\n md: '16px',\n lg: '20px',\n};\n\nconst NAMED_COLOR_MAP: Record<string, string> = {\n primary: vars.colors.text.primary,\n secondary: vars.colors.text.secondary,\n muted: vars.colors.text.muted,\n accent: vars.colors.accent.primary,\n};\n\nfunction resolveColor(color: SpinnerColor): string {\n return NAMED_COLOR_MAP[color] ?? color;\n}\n\n/**\n * Loading / activity indicator.\n *\n * Announces itself via `role=\"status\"` and `aria-label`; honors\n * `prefers-reduced-motion` by halting animation and dimming the indicator. Pass\n * `decorative` to opt out of the live region when nested inside one (e.g. a\n * `StatusBar`).\n *\n * @example\n * ```tsx\n * <Spinner />\n * <Spinner variant=\"dots\" size=\"lg\" />\n * <Spinner showLabel label=\"Fetching results...\" />\n * // Inside a StatusBar (already role=\"status\"):\n * <Spinner decorative size=\"sm\" />\n * ```\n */\nexport const Spinner = /*#__PURE__*/ React.memo<SpinnerProps>(\n ({\n size = 'md',\n variant = 'ring',\n color = 'accent',\n label = 'Loading...',\n showLabel = false,\n decorative = false,\n className,\n style,\n testId,\n ref,\n ...rest\n }) => {\n const resolvedColor = resolveColor(color);\n const resolvedSize = SIZE_MAP[size];\n\n const inlineVars = assignInlineVars({\n [spinnerColorVar]: resolvedColor,\n [spinnerSizeVar]: resolvedSize,\n });\n\n const indicator =\n variant === 'ring' ? (\n <span className={spinnerRingStyle} aria-hidden />\n ) : variant === 'pulse' ? (\n <span className={spinnerPulseStyle} aria-hidden />\n ) : (\n <span className={spinnerDotsSizerStyle} aria-hidden>\n <span className={spinnerDotRecipe({ delay: '0' })} />\n <span className={spinnerDotRecipe({ delay: '1' })} />\n <span className={spinnerDotRecipe({ delay: '2' })} />\n </span>\n );\n\n // Decorative spinners drop the live region (and label) so a surrounding\n // live region (e.g. StatusBar's role=\"status\") is the single announcer.\n const semanticProps: React.HTMLAttributes<HTMLSpanElement> = decorative\n ? { role: 'presentation', 'aria-hidden': true }\n : { role: 'status', 'aria-live': 'polite', 'aria-label': label };\n\n return (\n <span\n ref={ref}\n {...semanticProps}\n className={cx(spinnerRootStyle, className)}\n style={{ ...inlineVars, ...style }}\n data-testid={testId}\n {...rest}\n >\n {indicator}\n {showLabel ? (\n <span className={spinnerLabelStyle}>{label}</span>\n ) : decorative ? null : (\n <span className={visuallyHiddenStyle}>{label}</span>\n )}\n </span>\n );\n }\n);\n\nSpinner.displayName = 'Spinner';\n"],"names":[],"mappings":";;;;;;;;AAsBA;AACE;AACA;AACA;AACA;;AAGF;AACE;AACA;AACA;AACA;;AAGF;AACE;AACF;AAEA;;;;;;;;;;;;;;;;AAgBG;;AAeC;AACA;;;;AAKC;AAED;;;;;AAiBE;AAEF;AAiBF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Stat.js","sources":["
|
|
1
|
+
{"version":3,"file":"Stat.js","sources":["src/components/feedback/Stat/Stat.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { vars } from '@/theme/contract.css';\nimport { cx } from '@/utils/cx';\n\nimport {\n statContentStyle,\n statDeltaColorVar,\n statDeltaIconStyle,\n statDeltaStyle,\n statHelperStyle,\n statIconStyle,\n statLabelStyle,\n statRoot,\n statValueRecipe,\n} from './Stat.css';\n\nimport type {\n StatDelta,\n StatDeltaDirection,\n StatDeltaSemantics,\n StatProps,\n} from './Stat.types';\n\nconst ARROW_PATHS: Record<StatDeltaDirection, string> = {\n up: 'M6 2 L10 7 L7 7 L7 10 L5 10 L5 7 L2 7 Z',\n down: 'M6 10 L2 5 L5 5 L5 2 L7 2 L7 5 L10 5 Z',\n neutral: 'M2 6 L10 6 L10 7 L2 7 Z',\n};\n\nfunction deltaColor(\n direction: StatDeltaDirection,\n semantics: StatDeltaSemantics\n): string {\n if (semantics === 'neutral' || direction === 'neutral') {\n return vars.colors.text.muted;\n }\n const isUpGood = semantics === 'positive';\n const upColor = isUpGood\n ? vars.colors.accent.success\n : vars.colors.accent.error;\n const downColor = isUpGood\n ? vars.colors.accent.error\n : vars.colors.accent.success;\n return direction === 'up' ? upColor : downColor;\n}\n\nfunction DeltaIcon({ direction }: { direction: StatDeltaDirection }) {\n return (\n <svg\n className={statDeltaIconStyle}\n viewBox=\"0 0 12 12\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d={ARROW_PATHS[direction]} fill=\"currentColor\" />\n </svg>\n );\n}\n\nfunction DeltaDisplay({ delta }: { delta: StatDelta }) {\n const semantics = delta.semantics ?? 'positive';\n const color = deltaColor(delta.direction, semantics);\n return (\n <span\n className={statDeltaStyle}\n style={assignInlineVars({ [statDeltaColorVar]: color })}\n >\n <DeltaIcon direction={delta.direction} />\n {delta.value}\n </span>\n );\n}\n\n/**\n * KPI / metric display: label + value + optional trend delta.\n *\n * Use `delta.semantics` to indicate whether \"up\" is good. Errors and\n * latency, for example, want `semantics: \"negative\"` so an upward\n * direction shows red.\n *\n * @example\n * ```tsx\n * <Stat\n * label=\"MRR\"\n * value=\"$12,400\"\n * delta={{ value: '+8.2%', direction: 'up' }}\n * helper=\"vs. last month\"\n * />\n * ```\n */\nexport const Stat: React.FC<StatProps> = ({\n label,\n value,\n delta,\n helper,\n icon,\n size = 'md',\n className,\n style,\n testId,\n ref,\n ...rest\n}) => (\n <div\n ref={ref}\n className={cx(statRoot({ size }), className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {icon && <div className={statIconStyle}>{icon}</div>}\n <div className={statContentStyle}>\n <p className={statLabelStyle}>{label}</p>\n <p className={statValueRecipe({ size })}>{value}</p>\n {delta && <DeltaDisplay delta={delta} />}\n {helper && <p className={statHelperStyle}>{helper}</p>}\n </div>\n </div>\n);\n\nStat.displayName = 'Stat';\n"],"names":[],"mappings":";;;;;;;AA2BA;AACE;AACA;AACA;;AAGF;;AAKI;;AAEF;;AAEE;;;AAGA;;;AAGJ;AAEA;AACE;AAUF;AAEA;AACE;;AAEA;AASF;AAEA;;;;;;;;;;;;;;;;AAgBG;AACI;AA8BP;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastContainer.js","sources":["
|
|
1
|
+
{"version":3,"file":"ToastContainer.js","sources":["src/components/feedback/Toast/ToastContainer.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport {\n gapVar,\n zIndexVar,\n container,\n containerReverse,\n containerNormal,\n} from './ToastContainer.css';\nimport { ToastItem } from './ToastItem';\n\nimport type { ToastInternalData, ToastPosition } from './Toast.types';\n\n// --- Position style map ---\n\nconst POSITION_STYLES: Record<ToastPosition, React.CSSProperties> = {\n 'top-right': { top: 16, right: 16 },\n 'top-left': { top: 16, left: 16 },\n 'top-center': { top: 16, left: '50%', transform: 'translateX(-50%)' },\n 'bottom-right': { bottom: 16, right: 16 },\n 'bottom-left': { bottom: 16, left: 16 },\n 'bottom-center': { bottom: 16, left: '50%', transform: 'translateX(-50%)' },\n};\n\n// --- Props ---\n\ninterface ToastContainerProps {\n toasts: ToastInternalData[];\n position: ToastPosition;\n gap: number;\n zIndex: number;\n onDismiss: (id: string) => void;\n}\n\n/**\n * ToastContainer positions toast items at the specified screen edge.\n * Bottom positions use column-reverse so the newest toast appears at the bottom.\n */\nexport const ToastContainer: React.FC<ToastContainerProps> = ({\n toasts,\n position,\n gap,\n zIndex,\n onDismiss,\n}) => {\n const isBottom = position.startsWith('bottom');\n const positionStyle = POSITION_STYLES[position];\n\n const inlineVars = assignInlineVars({\n [gapVar]: `${gap}px`,\n [zIndexVar]: String(zIndex),\n });\n\n return (\n <div\n className={cx(container, isBottom ? containerReverse : containerNormal)}\n style={{\n ...positionStyle,\n ...inlineVars,\n }}\n aria-label=\"Notifications\"\n role=\"region\"\n >\n {toasts.map(toast => (\n <ToastItem key={toast.id} toast={toast} onDismiss={onDismiss} />\n ))}\n </div>\n );\n};\n\nToastContainer.displayName = 'ToastContainer';\n"],"names":[],"mappings":";;;;;;;AAkBA;AAEA;;;AAGE;;;AAGA;;AAaF;;;AAGG;AACI;;AAQL;;AAGE;AACA;AACD;;AAMK;AACA;AACD;AASP;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastItem.js","sources":["
|
|
1
|
+
{"version":3,"file":"ToastItem.js","sources":["src/components/feedback/Toast/ToastItem.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useEffect, useRef, useState, useCallback } from 'react';\n\nimport { CloseIcon } from '@/components/Icons/CloseIcon';\nimport { ErrorIcon } from '@/components/Icons/ErrorIcon';\nimport { InfoIcon } from '@/components/Icons/InfoIcon';\nimport { SuccessIcon } from '@/components/Icons/SuccessIcon';\nimport { WarningIcon } from '@/components/Icons/WarningIcon';\n\nimport {\n progressDurationVar,\n toast,\n content,\n iconWrapper,\n textContent,\n titleStyle,\n message,\n closeButton,\n actionButton,\n progressBar,\n} from './ToastItem.css';\n\nimport type { ToastInternalData, ToastSeverity } from './Toast.types';\n\n// --- Severity icons ---\n\nconst SeverityIcon: React.FC<{ severity: ToastSeverity }> = ({ severity }) => {\n switch (severity) {\n case 'info':\n return <InfoIcon size=\"md\" color=\"currentColor\" decorative />;\n case 'success':\n return <SuccessIcon size=\"md\" color=\"currentColor\" decorative />;\n case 'warning':\n return <WarningIcon size=\"md\" color=\"currentColor\" decorative />;\n case 'error':\n return <ErrorIcon size=\"md\" color=\"currentColor\" decorative />;\n }\n};\n\n// --- ToastItem component ---\n\ninterface ToastItemProps {\n toast: ToastInternalData;\n onDismiss: (id: string) => void;\n}\n\n/**\n * Individual toast notification with severity indicator, auto-dismiss,\n * optional progress bar, and action button support.\n *\n * - info/success: role=\"status\", aria-live=\"polite\"\n * - warning/error: role=\"alert\", aria-live=\"assertive\"\n * - Auto-dismiss pauses on hover\n */\nexport const ToastItem: React.FC<ToastItemProps> = ({\n toast: toastData,\n onDismiss,\n}) => {\n const {\n id,\n title,\n message: msg,\n severity,\n duration,\n closable,\n showProgress,\n icon,\n action,\n } = toastData;\n\n const [paused, setPaused] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const remainingRef = useRef(duration);\n // Seeded on mount by startTimer(); 0 is a safe placeholder and avoids calling\n // the impure Date.now() during render.\n const startRef = useRef(0);\n\n const isAlert = severity === 'warning' || severity === 'error';\n const role = isAlert ? 'alert' : 'status';\n const ariaLive = isAlert ? 'assertive' : 'polite';\n\n const clearTimer = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n }, []);\n\n const startTimer = useCallback(() => {\n if (duration <= 0) return;\n clearTimer();\n startRef.current = Date.now();\n timerRef.current = setTimeout(() => {\n onDismiss(id);\n }, remainingRef.current);\n }, [duration, clearTimer, onDismiss, id]);\n\n const handleMouseEnter = useCallback(() => {\n if (duration <= 0) return;\n setPaused(true);\n clearTimer();\n remainingRef.current -= Date.now() - startRef.current;\n }, [duration, clearTimer]);\n\n const handleMouseLeave = useCallback(() => {\n if (duration <= 0) return;\n setPaused(false);\n startTimer();\n }, [duration, startTimer]);\n\n useEffect(() => {\n startTimer();\n return clearTimer;\n }, [startTimer, clearTimer]);\n\n return (\n <div\n className={toast({ severity })}\n role={role}\n aria-live={ariaLive}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n data-testid={`toast-${id}`}\n >\n <div className={content}>\n <div className={iconWrapper}>\n {icon ?? <SeverityIcon severity={severity} />}\n </div>\n <div className={textContent}>\n {title && <div className={titleStyle}>{title}</div>}\n <div className={message}>{msg}</div>\n {action && (\n <button\n className={actionButton({ severity })}\n onClick={action.onClick}\n type=\"button\"\n >\n {action.label}\n </button>\n )}\n </div>\n {closable && (\n <button\n className={closeButton}\n onClick={() => {\n onDismiss(id);\n }}\n aria-label=\"Dismiss notification\"\n type=\"button\"\n >\n <CloseIcon size=\"sm\" decorative />\n </button>\n )}\n </div>\n {showProgress && duration > 0 && (\n <div\n className={progressBar({ severity, paused })}\n style={assignInlineVars({\n [progressDurationVar]: `${duration}ms`,\n })}\n data-testid={`toast-progress-${id}`}\n />\n )}\n </div>\n );\n};\n\nToastItem.displayName = 'ToastItem';\n"],"names":[],"mappings":";;;;;;;;;;;AA0BA;AAEA;;AAEI;AACE;AACF;AACE;AACF;AACE;AACF;AACE;;AAEN;AASA;;;;;;;AAOG;AACI;;;AAiBL;AACA;;;AAGA;;;;AAMA;AACE;AACE;AACA;;;AAIJ;;;AAEE;AACA;AACA;;AAEA;;AAGF;;;;AAGE;;AAEF;AAEA;;;;AAGE;AACF;;AAGE;AACA;AACF;;;AAiCU;AAYA;;AAOZ;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToastProvider.js","sources":["
|
|
1
|
+
{"version":3,"file":"ToastProvider.js","sources":["src/components/feedback/Toast/ToastProvider.tsx"],"sourcesContent":["'use client';\n\nimport React, { createContext, useReducer, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { ToastContainer } from './ToastContainer';\n\nimport type { ToastProviderProps, ToastInternalData } from './Toast.types';\n\n// --- Toast Actions ---\n\ntype ToastAction =\n | { type: 'ADD_TOAST'; toast: ToastInternalData }\n | { type: 'DISMISS_TOAST'; id: string }\n | { type: 'DISMISS_ALL' };\n\n// --- Toast Context ---\n\nexport interface ToastContextValue {\n dispatch: React.Dispatch<ToastAction>;\n defaultDuration: number;\n}\n\nexport const ToastContext =\n /*#__PURE__*/ createContext<ToastContextValue | null>(null);\n\n// --- Reducer ---\n\nfunction toastReducer(\n state: ToastInternalData[],\n action: ToastAction\n): ToastInternalData[] {\n switch (action.type) {\n case 'ADD_TOAST':\n return [...state, action.toast];\n case 'DISMISS_TOAST':\n return state.filter(t => t.id !== action.id);\n case 'DISMISS_ALL':\n return [];\n default:\n return state;\n }\n}\n\n/**\n * ToastProvider manages toast notification state and renders them via portal.\n *\n * Wrap your application (or a section of it) with this provider, then use\n * the `useToast()` hook to trigger notifications from any child component.\n *\n * @example\n * ```tsx\n * <ToastProvider position=\"bottom-right\" maxVisible={5}>\n * <App />\n * </ToastProvider>\n * ```\n */\nexport const ToastProvider: React.FC<ToastProviderProps> = ({\n children,\n position = 'bottom-right',\n maxVisible = 5,\n defaultDuration = 5000,\n gap = 8,\n zIndex = 1200,\n}) => {\n const [toasts, dispatch] = useReducer(toastReducer, []);\n\n const contextValue = useMemo<ToastContextValue>(\n () => ({ dispatch, defaultDuration }),\n [dispatch, defaultDuration]\n );\n\n const visibleToasts = toasts.slice(-maxVisible);\n\n const handleDismiss = (id: string) => {\n dispatch({ type: 'DISMISS_TOAST', id });\n };\n\n return (\n <ToastContext.Provider value={contextValue}>\n {children}\n {typeof document !== 'undefined' &&\n createPortal(\n <ToastContainer\n toasts={visibleToasts}\n position={position}\n gap={gap}\n zIndex={zIndex}\n onDismiss={handleDismiss}\n />,\n document.body\n )}\n </ToastContext.Provider>\n );\n};\n\nToastProvider.displayName = 'ToastProvider';\n"],"names":[],"mappings":";;;;;;;AAwBE;AAEF;AAEA;AAIE;AACE;;AAEA;AACE;AACF;AACE;AACF;AACE;;AAEN;AAEA;;;;;;;;;;;;AAYG;AACI;AAQL;;;AASA;;AAEA;AAEA;AAIM;AAYR;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useToast.js","sources":["
|
|
1
|
+
{"version":3,"file":"useToast.js","sources":["src/components/feedback/Toast/useToast.ts"],"sourcesContent":["'use client';\n\nimport { useContext, useCallback, useRef } from 'react';\n\nimport { ToastContext } from './ToastProvider';\n\nimport type {\n ToastData,\n ToastInternalData,\n UseToastReturn,\n} from './Toast.types';\n\n/**\n * Hook to trigger toast notifications from any component\n * inside a `<ToastProvider>`.\n *\n * @throws Error if used outside of a `<ToastProvider>`\n *\n * @example\n * ```tsx\n * const { toast, success, error, dismiss } = useToast();\n *\n * success('File saved successfully');\n * error('Failed to export', { title: 'Export Error' });\n *\n * const id = toast({ message: 'Custom toast', severity: 'info' });\n * dismiss(id);\n * ```\n */\nexport function useToast(): UseToastReturn {\n const context = useContext(ToastContext);\n if (!context) {\n throw new Error('useToast must be used within a ToastProvider');\n }\n\n const { dispatch, defaultDuration } = context;\n const counterRef = useRef(0);\n\n const generateId = useCallback(() => {\n counterRef.current += 1;\n return `toast-${Date.now()}-${counterRef.current}`;\n }, []);\n\n const toast = useCallback(\n (data: ToastData): string => {\n const id = data.id ?? generateId();\n const internalData: ToastInternalData = {\n ...data,\n id,\n severity: data.severity ?? 'info',\n duration: data.duration ?? defaultDuration,\n closable: data.closable ?? true,\n showProgress: data.showProgress ?? false,\n createdAt: Date.now(),\n };\n dispatch({ type: 'ADD_TOAST', toast: internalData });\n return id;\n },\n [dispatch, defaultDuration, generateId]\n );\n\n const info = useCallback(\n (message: string, options?: Partial<ToastData>): string =>\n toast({ message, severity: 'info', ...options }),\n [toast]\n );\n\n const success = useCallback(\n (message: string, options?: Partial<ToastData>): string =>\n toast({ message, severity: 'success', ...options }),\n [toast]\n );\n\n const warning = useCallback(\n (message: string, options?: Partial<ToastData>): string =>\n toast({ message, severity: 'warning', ...options }),\n [toast]\n );\n\n const error = useCallback(\n (message: string, options?: Partial<ToastData>): string =>\n toast({ message, severity: 'error', ...options }),\n [toast]\n );\n\n const dismiss = useCallback(\n (id: string) => {\n dispatch({ type: 'DISMISS_TOAST', id });\n },\n [dispatch]\n );\n\n const dismissAll = useCallback(() => {\n dispatch({ type: 'DISMISS_ALL' });\n }, [dispatch]);\n\n return { toast, info, success, warning, error, dismiss, dismissAll };\n}\n"],"names":[],"mappings":";;;;AAYA;;;;;;;;;;;;;;;;AAgBG;;AAED;;AAEE;;AAGF;AACA;AAEA;AACE;;;AAIF;;AAGI;AACE;;AAEA;AACA;AACA;AACA;AACA;;;AAGF;;AAKJ;AAMA;AAMA;AAMA;AAMA;;AAGE;AAIF;AACE;AACF;AAEA;AACF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormHelperText.js","sources":["
|
|
1
|
+
{"version":3,"file":"FormHelperText.js","sources":["src/components/form/FormHelperText.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { Prettify } from '@/types/utilities';\nimport { cx } from '@/utils/cx';\n\nimport { formHelperTextRecipe } from './FormHelperText.css';\n\nimport type { BaseComponent } from '@/types/common';\n\nexport interface FormHelperTextBaseProps extends BaseComponent {\n /**\n * Helper text content\n */\n children: React.ReactNode;\n\n /**\n * Whether to display in error state\n * @default false\n */\n error?: boolean;\n}\n\nexport type FormHelperTextProps = Prettify<FormHelperTextBaseProps>;\n\n/**\n * A standardized helper text component for use with form controls.\n *\n * Provides consistent styling for helper text and error messages\n * across different form components.\n *\n * @example\n * ```tsx\n * <Input label=\"Email\" />\n * <FormHelperText>We'll never share your email with anyone else.</FormHelperText>\n *\n * <Input label=\"Username\" error={!!usernameError} />\n * <FormHelperText error>{usernameError}</FormHelperText>\n * ```\n */\nexport const FormHelperText = /*#__PURE__*/ React.memo<FormHelperTextProps>(\n ({ children, error = false, className, style, ref, ...rest }) => {\n return (\n <div\n ref={ref}\n className={cx(formHelperTextRecipe({ error }), className)}\n style={style}\n {...rest}\n >\n {children}\n </div>\n );\n }\n);\n\nFormHelperText.displayName = 'FormHelperText';\n"],"names":[],"mappings":";;;;;;AA0BA;;;;;;;;;;;;;;AAcG;AACI;AAEH;AAUF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormLabel.js","sources":["
|
|
1
|
+
{"version":3,"file":"FormLabel.js","sources":["src/components/form/FormLabel.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { Prettify } from '@/types/utilities';\nimport { cx } from '@/utils/cx';\n\nimport { formLabelRecipe, requiredIndicatorStyle } from './FormLabel.css';\n\nimport type { BaseComponent } from '@/types/common';\n\nexport interface FormLabelBaseProps extends BaseComponent<HTMLLabelElement> {\n /**\n * Label content\n */\n children: React.ReactNode;\n\n /**\n * HTML for attribute to associate label with form control\n */\n htmlFor?: string;\n\n /**\n * Whether the associated form control is disabled\n * @default false\n */\n disabled?: boolean;\n\n /**\n * Whether the associated form control is required\n * @default false\n */\n required?: boolean;\n}\n\nexport type FormLabelProps = Prettify<FormLabelBaseProps>;\n\n/**\n * A standardized form label component for use with form controls.\n *\n * Provides consistent styling and behavior for labels across different\n * form components, with support for required indicators and disabled states.\n *\n * @example\n * ```tsx\n * <FormLabel htmlFor=\"name-input\" required>\n * Full Name\n * </FormLabel>\n * <Input id=\"name-input\" />\n * ```\n */\nexport const FormLabel = /*#__PURE__*/ React.memo<FormLabelProps>(\n ({\n children,\n htmlFor,\n disabled = false,\n required = false,\n className,\n style,\n ref,\n ...rest\n }) => {\n return (\n <label\n ref={ref}\n htmlFor={htmlFor}\n className={cx(formLabelRecipe({ disabled }), className)}\n style={style}\n {...rest}\n >\n {children}\n {required && <span className={requiredIndicatorStyle}> *</span>}\n </label>\n );\n }\n);\n\nFormLabel.displayName = 'FormLabel';\n"],"names":[],"mappings":";;;;;;AAqCA;;;;;;;;;;;;;AAaG;AACI;AAWH;AAYF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputWrapper.js","sources":["
|
|
1
|
+
{"version":3,"file":"InputWrapper.js","sources":["src/components/form/InputWrapper.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { Prettify } from '@/types/utilities';\nimport { cx } from '@/utils/cx';\n\nimport { inputWrapperRecipe } from './InputWrapper.css';\n\nimport type { BaseComponent, Size } from '@/types/common';\n\nexport interface InputWrapperBaseProps extends BaseComponent {\n /**\n * Input wrapper content\n */\n children: React.ReactNode;\n\n /**\n * Input size using standard library sizing\n * - `sm`: 20px height, compact for toolbars\n * - `md`: 24px height, standard for forms\n * - `lg`: 32px height, prominent inputs\n * @default \"md\"\n */\n size?: Size;\n\n /**\n * Whether the input has an error state\n * @default false\n */\n error?: boolean;\n\n /**\n * Whether the input is disabled\n * @default false\n */\n disabled?: boolean;\n\n /**\n * Whether the input is focused\n * @default false\n */\n focused?: boolean;\n}\n\nexport type InputWrapperProps = Prettify<InputWrapperBaseProps>;\n\n/**\n * A standardized wrapper component for form inputs.\n *\n * Provides consistent styling and behavior for input containers\n * across different form components, with support for different sizes,\n * states (error, disabled, focused), and consistent border styling.\n *\n * @example\n * ```tsx\n * <InputWrapper\n * size=\"md\"\n * error={!!inputError}\n * disabled={isDisabled}\n * focused={isFocused}\n * >\n * <input type=\"text\" />\n * </InputWrapper>\n * ```\n */\nexport const InputWrapper = /*#__PURE__*/ React.memo<InputWrapperProps>(\n ({\n children,\n size = 'md',\n error = false,\n disabled = false,\n focused = false,\n className,\n style,\n ref,\n ...rest\n }) => {\n return (\n <div\n ref={ref}\n className={cx(\n inputWrapperRecipe({ size, error, disabled, focused }),\n className\n )}\n style={style}\n {...rest}\n >\n {children}\n </div>\n );\n }\n);\n\nInputWrapper.displayName = 'InputWrapper';\n"],"names":[],"mappings":";;;;;;AA+CA;;;;;;;;;;;;;;;;;;AAkBG;AACI;AAYH;AAaF;AAGF;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.js","sources":["
|
|
1
|
+
{"version":3,"file":"Accordion.js","sources":["src/components/layout/Accordion/Accordion.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, {\n createContext,\n useCallback,\n useContext,\n useId,\n useState,\n} from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { accordionRoot, accordionGapVar } from './Accordion.css';\n\nimport type {\n AccordionContextValue,\n AccordionItemContextValue,\n AccordionProps,\n} from './Accordion.types';\n\n// --- Contexts ---\n\nconst AccordionContext =\n /*#__PURE__*/ createContext<AccordionContextValue | null>(null);\nconst AccordionItemContext =\n /*#__PURE__*/ createContext<AccordionItemContextValue | null>(null);\n\nexport function useAccordionContext(): AccordionContextValue {\n const ctx = useContext(AccordionContext);\n if (!ctx) {\n throw new Error(\n 'Accordion compound components must be used within <Accordion>'\n );\n }\n return ctx;\n}\n\nexport function useAccordionItemContext(): AccordionItemContextValue {\n const ctx = useContext(AccordionItemContext);\n if (!ctx) {\n throw new Error(\n 'AccordionTrigger/AccordionContent must be used within <AccordionItem>'\n );\n }\n return ctx;\n}\n\nexport { AccordionContext, AccordionItemContext };\n\n// --- Helpers ---\n\nfunction normalizeValue(value: string | string[] | undefined): string[] {\n if (value === undefined) return [];\n if (Array.isArray(value)) return value;\n return [value];\n}\n\n// --- Component ---\n\n/**\n * Accordion component for collapsible sections in property inspectors\n * and settings panels.\n *\n * Compound component pattern: use with AccordionItem, AccordionTrigger,\n * and AccordionContent.\n *\n * @example\n * ```tsx\n * <Accordion defaultValue=\"transform\">\n * <AccordionItem value=\"transform\">\n * <AccordionTrigger>Transform</AccordionTrigger>\n * <AccordionContent>Position, rotation, scale fields...</AccordionContent>\n * </AccordionItem>\n * </Accordion>\n * ```\n */\nexport const Accordion: React.FC<AccordionProps> = ({\n value: valueProp,\n defaultValue,\n multiple = false,\n collapsible = false,\n variant = 'default',\n size = 'md',\n gap = 0,\n width = '100%',\n children,\n onChange,\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const autoId = useId();\n\n const [internalValue, setInternalValue] = useState<string[]>(\n normalizeValue(defaultValue)\n );\n const isControlled = valueProp !== undefined;\n const expandedItems = isControlled\n ? normalizeValue(valueProp)\n : internalValue;\n\n const toggleItem = useCallback(\n (itemValue: string) => {\n const isExpanded = expandedItems.includes(itemValue);\n\n let nextExpanded: string[];\n\n if (multiple) {\n nextExpanded = isExpanded\n ? expandedItems.filter(v => v !== itemValue)\n : [...expandedItems, itemValue];\n } else {\n if (isExpanded) {\n nextExpanded = collapsible ? [] : expandedItems;\n } else {\n nextExpanded = [itemValue];\n }\n }\n\n if (!isControlled) {\n setInternalValue(nextExpanded);\n }\n\n if (multiple) {\n onChange?.(nextExpanded);\n } else {\n onChange?.(nextExpanded[0] ?? '');\n }\n },\n [expandedItems, multiple, collapsible, isControlled, onChange]\n );\n\n const contextValue: AccordionContextValue = {\n expandedItems,\n toggleItem,\n variant,\n size,\n accordionId: autoId,\n };\n\n const mergedStyle: React.CSSProperties = {\n ...assignInlineVars({\n [accordionGapVar]: `${gap}px`,\n }),\n width: typeof width === 'number' ? `${width}px` : width,\n ...style,\n };\n\n return (\n <AccordionContext.Provider value={contextValue}>\n <div\n ref={ref}\n className={cx(accordionRoot, className)}\n style={mergedStyle}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n </AccordionContext.Provider>\n );\n};\n\nAccordion.displayName = 'Accordion';\n"],"names":[],"mappings":";;;;;;;AAqBA;AAEA;AACE;AACF;AACE;;AAGA;;AAEE;;AAIF;AACF;;AAGE;;AAEE;;AAIF;AACF;AAIA;AAEA;;AAC2B;AACzB;AAA0B;;AAE5B;AAEA;AAEA;;;;;;;;;;;;;;;;AAgBG;AACI;AAiBL;AAEA;AAGA;;AAEE;;AAGF;;AAII;;AAGE;AACE;AACA;;;;;;;AAKA;;;;;;;AASF;;;;;AAIJ;AAIF;;;;;AAKE;;AAGF;AACE;AACE;;AAEF;AACA;;AAGF;AAaF;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionContent.js","sources":["
|
|
1
|
+
{"version":3,"file":"AccordionContent.js","sources":["src/components/layout/Accordion/AccordionContent.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { useAccordionContext, useAccordionItemContext } from './Accordion';\nimport {\n contentWrapper,\n contentWrapperExpanded,\n contentWrapperCollapsed,\n contentInner,\n contentBody,\n} from './Accordion.css';\n\nimport type { AccordionContentProps } from './Accordion.types';\n\n// --- Component ---\n\nexport const AccordionContent: React.FC<AccordionContentProps> = ({\n children,\n keepMounted = false,\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const { size, accordionId } = useAccordionContext();\n const { value, isExpanded } = useAccordionItemContext();\n\n const triggerId = `accordion-${accordionId}-trigger-${value}`;\n const contentId = `accordion-${accordionId}-content-${value}`;\n\n if (!isExpanded && !keepMounted) {\n return null;\n }\n\n return (\n <div\n className={cx(\n contentWrapper,\n isExpanded ? contentWrapperExpanded : contentWrapperCollapsed\n )}\n role=\"region\"\n id={contentId}\n aria-labelledby={triggerId}\n hidden={!isExpanded || undefined}\n >\n <div className={contentInner}>\n <div\n ref={ref}\n className={cx(contentBody({ size }), className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n </div>\n </div>\n );\n};\n\nAccordionContent.displayName = 'AccordionContent';\n"],"names":[],"mappings":";;;;;;AAiBA;AAEO;;;AAYL;AACA;AAEA;AACE;;AAGF;AAwBF;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionItem.js","sources":["
|
|
1
|
+
{"version":3,"file":"AccordionItem.js","sources":["src/components/layout/Accordion/AccordionItem.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport { useAccordionContext, AccordionItemContext } from './Accordion';\nimport { accordionItem } from './Accordion.css';\n\nimport type {\n AccordionItemContextValue,\n AccordionItemProps,\n} from './Accordion.types';\n\n// --- Component ---\n\nexport const AccordionItem: React.FC<AccordionItemProps> = ({\n value,\n disabled = false,\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const { expandedItems } = useAccordionContext();\n const isExpanded = expandedItems.includes(value);\n\n const itemContext: AccordionItemContextValue = {\n value,\n isExpanded,\n isDisabled: disabled,\n };\n\n return (\n <AccordionItemContext.Provider value={itemContext}>\n <div\n ref={ref}\n className={cx(accordionItem, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n </AccordionItemContext.Provider>\n );\n};\n\nAccordionItem.displayName = 'AccordionItem';\n"],"names":[],"mappings":";;;;;;AAcA;AAEO;AAUL;;AAGA;;;AAGE;;AAGF;AAaF;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccordionTrigger.js","sources":["
|
|
1
|
+
{"version":3,"file":"AccordionTrigger.js","sources":["src/components/layout/Accordion/AccordionTrigger.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback } from 'react';\n\nimport { ChevronRightIcon } from '@/components/Icons/ChevronRightIcon';\nimport { cx } from '@/utils/cx';\n\nimport { useAccordionContext, useAccordionItemContext } from './Accordion';\nimport {\n triggerButton,\n chevronStyle,\n chevronExpanded,\n chevronCollapsed,\n actionsArea,\n iconArea,\n} from './Accordion.css';\n\nimport type { AccordionSize, AccordionTriggerProps } from './Accordion.types';\n\n// --- Size maps ---\n\ninterface ChevronSizeConfig {\n chevronSize: number;\n}\n\nconst CHEVRON_SIZE_MAP: Record<AccordionSize, ChevronSizeConfig> = {\n sm: { chevronSize: 10 },\n md: { chevronSize: 12 },\n lg: { chevronSize: 14 },\n};\n\n// --- Component ---\n\nexport const AccordionTrigger: React.FC<AccordionTriggerProps> = ({\n children,\n icon,\n actions,\n indicator,\n className,\n style,\n testId,\n ref,\n ...rest\n}) => {\n const { toggleItem, variant, size, accordionId } = useAccordionContext();\n const { value, isExpanded, isDisabled } = useAccordionItemContext();\n const sizeConfig = CHEVRON_SIZE_MAP[size];\n\n const triggerId = `accordion-${accordionId}-trigger-${value}`;\n const contentId = `accordion-${accordionId}-content-${value}`;\n\n const handleClick = useCallback(() => {\n if (!isDisabled) {\n toggleItem(value);\n }\n }, [isDisabled, toggleItem, value]);\n\n // Prevent clicks/keypresses originating from the actions area (which hosts\n // its own interactive controls) from bubbling up and toggling the accordion.\n const handleActionsClick = useCallback((e: React.MouseEvent) => {\n e.stopPropagation();\n }, []);\n\n const handleActionsKeyDown = useCallback((e: React.KeyboardEvent) => {\n e.stopPropagation();\n }, []);\n\n const showIndicator = indicator !== null;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n id={triggerId}\n aria-expanded={isExpanded}\n aria-controls={contentId}\n aria-disabled={isDisabled || undefined}\n disabled={isDisabled}\n onClick={handleClick}\n className={cx(\n triggerButton({ variant, size, disabled: isDisabled }),\n className\n )}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {showIndicator && (\n <span\n className={cx(\n chevronStyle,\n isExpanded ? chevronExpanded : chevronCollapsed\n )}\n style={{\n width: `${sizeConfig.chevronSize}px`,\n height: `${sizeConfig.chevronSize}px`,\n }}\n >\n {indicator ?? (\n <ChevronRightIcon size={sizeConfig.chevronSize} decorative />\n )}\n </span>\n )}\n {icon && <span className={iconArea}>{icon}</span>}\n <span>{children}</span>\n {actions && (\n <span\n className={actionsArea}\n role=\"presentation\"\n onClick={handleActionsClick}\n onKeyDown={handleActionsKeyDown}\n >\n {actions}\n </span>\n )}\n </button>\n );\n};\n\nAccordionTrigger.displayName = 'AccordionTrigger';\n"],"names":[],"mappings":";;;;;;;;AAyBA;AACE;AACA;AACA;;AAGF;AAEO;AAWL;;AAEA;AAEA;AACA;AAEA;;;;;;;AAQA;;;AAIA;;;AAIA;AAEA;AAyBU;AACA;;AAsBZ;AAEA;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Card.js","sources":["
|
|
1
|
+
{"version":3,"file":"Card.js","sources":["src/components/layout/Card/Card.tsx"],"sourcesContent":["'use client';\n\nimport { assignInlineVars } from '@vanilla-extract/dynamic';\nimport React, { useCallback } from 'react';\n\nimport { cx } from '@/utils/cx';\n\nimport {\n cardBodyStyle,\n cardFooterStyle,\n cardHeaderLeadingStyle,\n cardHeaderStyle,\n cardHeaderSubtitleStyle,\n cardHeaderTextStyle,\n cardHeaderTitleStyle,\n cardHeaderTrailingStyle,\n cardMediaAspectVar,\n cardMediaImageStyle,\n cardMediaStyle,\n cardRecipe,\n} from './Card.css';\n\nimport type {\n CardBodyProps,\n CardFooterProps,\n CardHeaderProps,\n CardMediaProps,\n CardProps,\n} from './Card.types';\n\ninterface CardComponent extends React.FC<CardProps> {\n Header: React.FC<CardHeaderProps>;\n Media: React.FC<CardMediaProps>;\n Body: React.FC<CardBodyProps>;\n Footer: React.FC<CardFooterProps>;\n}\n\n/**\n * A bounded surface representing a single semantic unit (item, summary,\n * preview). Distinct from `Paper` (a generic surface): a Card has a\n * header / media / body / footer convention and can be made interactive.\n *\n * @example\n * ```tsx\n * <Card variant=\"elevated\" onClick={open}>\n * <Card.Header\n * title=\"Asset\"\n * subtitle=\"Updated 2h ago\"\n * trailing={<IconButton icon={<MoreIcon />} />}\n * />\n * <Card.Media src=\"/preview.png\" alt=\"Preview\" />\n * <Card.Body>Description...</Card.Body>\n * <Card.Footer>\n * <Button>Open</Button>\n * </Card.Footer>\n * </Card>\n * ```\n */\nconst CardRoot: React.FC<CardProps> = ({\n variant = 'outlined',\n onClick,\n selected = false,\n disabled = false,\n className,\n style,\n testId,\n children,\n ref,\n ...rest\n}) => {\n const interactive = onClick !== undefined && !disabled;\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!interactive) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n onClick(event as unknown as React.MouseEvent<HTMLDivElement>);\n }\n },\n [interactive, onClick]\n );\n\n return (\n <div\n ref={ref}\n className={cx(\n cardRecipe({\n variant,\n interactive: interactive || undefined,\n selected: selected || undefined,\n disabled: disabled || undefined,\n }),\n className\n )}\n style={style}\n data-testid={testId}\n onClick={interactive ? onClick : undefined}\n onKeyDown={interactive ? handleKeyDown : undefined}\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n aria-disabled={disabled || undefined}\n aria-pressed={interactive && selected ? true : undefined}\n {...rest}\n >\n {children}\n </div>\n );\n};\n\nCardRoot.displayName = 'Card';\n\nconst CardHeader: React.FC<CardHeaderProps> = ({\n title,\n subtitle,\n leading,\n trailing,\n children,\n className,\n style,\n testId,\n ref,\n ...rest\n}) => (\n <div\n ref={ref}\n className={cx(cardHeaderStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {leading && <div className={cardHeaderLeadingStyle}>{leading}</div>}\n <div className={cardHeaderTextStyle}>\n {children ?? (\n <>\n {title && <h3 className={cardHeaderTitleStyle}>{title}</h3>}\n {subtitle && <p className={cardHeaderSubtitleStyle}>{subtitle}</p>}\n </>\n )}\n </div>\n {trailing && <div className={cardHeaderTrailingStyle}>{trailing}</div>}\n </div>\n);\n\nCardHeader.displayName = 'Card.Header';\n\nconst CardMedia: React.FC<CardMediaProps> = ({\n src,\n alt,\n aspectRatio = 16 / 9,\n className,\n style,\n testId,\n children,\n ref,\n ...rest\n}) => (\n <div\n ref={ref}\n className={cx(cardMediaStyle, className)}\n style={{\n ...assignInlineVars({ [cardMediaAspectVar]: String(aspectRatio) }),\n ...style,\n }}\n data-testid={testId}\n {...rest}\n >\n {src ? (\n <img className={cardMediaImageStyle} src={src} alt={alt ?? ''} />\n ) : (\n children\n )}\n </div>\n);\n\nCardMedia.displayName = 'Card.Media';\n\nconst CardBody: React.FC<CardBodyProps> = ({\n className,\n style,\n testId,\n children,\n ref,\n ...rest\n}) => (\n <div\n ref={ref}\n className={cx(cardBodyStyle, className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n);\n\nCardBody.displayName = 'Card.Body';\n\nconst CardFooter: React.FC<CardFooterProps> = ({\n align = 'right',\n className,\n style,\n testId,\n children,\n ref,\n ...rest\n}) => (\n <div\n ref={ref}\n className={cx(cardFooterStyle({ align }), className)}\n style={style}\n data-testid={testId}\n {...rest}\n >\n {children}\n </div>\n);\n\nCardFooter.displayName = 'Card.Footer';\n\nexport const Card = Object.assign(CardRoot, {\n Header: CardHeader,\n Media: CardMedia,\n Body: CardBody,\n Footer: CardFooter,\n}) as CardComponent;\n"],"names":[],"mappings":";;;;;;;AAqCA;;;;;;;;;;;;;;;;;;;;AAoBG;AACH;;AAcE;AAEI;;AACA;;;;AAIF;;;;;;AAaK;AAgBT;AAEA;AAEA;AAgCA;AAEA;AAeM;AACA;AACD;AAYL;AAEA;AAmBA;AAEA;AAoBA;;AAGE;AACA;AACA;AACA;AACD;;"}
|