dishui 0.0.106 → 0.0.110
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/dist/.release-verified.json +3 -2
- package/dist/components/Accordion/index.js.map +1 -1
- package/dist/components/Avatar/index.js.map +1 -1
- package/dist/components/Badge/index.js.map +1 -1
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/ButtonMenu/index.js.map +1 -1
- package/dist/components/Card/Metric2.js.map +1 -1
- package/dist/components/Card/Ticket2.js.map +1 -1
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/Chart/Chart.js.map +1 -1
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/ChoicePicker/index.js.map +1 -1
- package/dist/components/Column/index.js.map +1 -1
- package/dist/components/ConfirmDialog/index.js.map +1 -1
- package/dist/components/DateTimeInput/index.js.map +1 -1
- package/dist/components/Demo/index.js.map +1 -1
- package/dist/components/Demo/source.js.map +1 -1
- package/dist/components/Divider/index.js.map +1 -1
- package/dist/components/EmptyState/index.js.map +1 -1
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/FileUploader/DropZone.js.map +1 -1
- package/dist/components/FileUploader/FileItem.js.map +1 -1
- package/dist/components/FileUploader/FileUploader.js.map +1 -1
- package/dist/components/FileUploader/UploadQueue.js.map +1 -1
- package/dist/components/GroupButton/index.js.map +1 -1
- package/dist/components/GroupedTable/index.js.map +1 -1
- package/dist/components/Icon/index.js.map +1 -1
- package/dist/components/Image/index.js.map +1 -1
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/Label/index.js.map +1 -1
- package/dist/components/Layout/index.js.map +1 -1
- package/dist/components/LayoutSuite/DashboardSuite.js.map +1 -1
- package/dist/components/LayoutSuite/index.js.map +1 -1
- package/dist/components/List/index.js.map +1 -1
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Markdown/codeThemes.js.map +1 -1
- package/dist/components/Markdown/markdownComponents.js.map +1 -1
- package/dist/components/Markdown/parseCodeBlockMeta.js.map +1 -1
- package/dist/components/Markdown/useMarkdownSource.js.map +1 -1
- package/dist/components/Markdown/useMarkmapRenderer.js.map +1 -1
- package/dist/components/Markdown/useMermaidRenderer.js.map +1 -1
- package/dist/components/Modal/focusScope.js.map +1 -1
- package/dist/components/Modal/index.js.map +1 -1
- package/dist/components/MultipleChoice/index.js.map +1 -1
- package/dist/components/NavigationList/index.js.map +1 -1
- package/dist/components/Page/Float2.js.map +1 -1
- package/dist/components/Page/index.js.map +1 -1
- package/dist/components/Page/resize2.js.map +1 -1
- package/dist/components/PageHeader/index.js.map +1 -1
- package/dist/components/PagePanel/index.js.map +1 -1
- package/dist/components/ProtectedRoute/index.js.map +1 -1
- package/dist/components/Resizable/ResizeGrip.js.map +1 -1
- package/dist/components/Resizable/index.js.map +1 -1
- package/dist/components/Resizable/useResize.js.map +1 -1
- package/dist/components/Row/index.js.map +1 -1
- package/dist/components/Section/index.js.map +1 -1
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/SidebarToggleButton/index.js.map +1 -1
- package/dist/components/Skeleton/index.js.map +1 -1
- package/dist/components/Slider/index.js.map +1 -1
- package/dist/components/Switch/index.js.map +1 -1
- package/dist/components/Tab/index.js.map +1 -1
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/Tabs/index.js.map +1 -1
- package/dist/components/Tabs/tabNavigation.js.map +1 -1
- package/dist/components/Text/index.js.map +1 -1
- package/dist/components/Textarea/index.js.map +1 -1
- package/dist/components/Tooltip/index.js.map +1 -1
- package/dist/components/Tree/Tree.js.map +1 -1
- package/dist/components/ai/AgentChat/index.js.map +1 -1
- package/dist/components/ai/AgentRunCard/index.js.map +1 -1
- package/dist/components/ai/AgentScreen/index.js.map +1 -1
- package/dist/components/ai/ApprovalCard/index.js.map +1 -1
- package/dist/components/ai/CodeView/index.js.map +1 -1
- package/dist/components/ai/CommandSearch/index.js.map +1 -1
- package/dist/components/ai/ContextCards/index.js.map +1 -1
- package/dist/components/ai/DiffTable/index.js.map +1 -1
- package/dist/components/ai/FilterTable/index.js.map +1 -1
- package/dist/components/ai/FineTuneCard/index.js.map +1 -1
- package/dist/components/ai/InsightCards/index.js.map +1 -1
- package/dist/components/ai/IssueCard/index.js.map +1 -1
- package/dist/components/ai/LoadingState/index.js.map +1 -1
- package/dist/components/ai/PromptBar/index.js.map +1 -1
- package/dist/components/ai/RecommendationCard/index.js.map +1 -1
- package/dist/components/ai/RecordsTable/index.js.map +1 -1
- package/dist/components/ai/SelectionActions/index.js.map +1 -1
- package/dist/components/ai/StateFlow/index.js.map +1 -1
- package/dist/components/ai/StreamingText/index.js.map +1 -1
- package/dist/components/ai/TaskRows/index.js.map +1 -1
- package/dist/components/ai/Thinking/index.js.map +1 -1
- package/dist/components/ai/ToolChips/index.js.map +1 -1
- package/dist/components/ai/shared.js.map +1 -1
- package/dist/components/pro/ArticleContextMenu/index.js.map +1 -1
- package/dist/components/pro/ArticleControl/ArticleControl2.js.map +1 -1
- package/dist/components/pro/ArticleControl/buildHeadingTree.js.map +1 -1
- package/dist/components/pro/ArticleControl/useArticleToc.js.map +1 -1
- package/dist/components/pro/Calendar/Calendar.js +165 -160
- package/dist/components/pro/Calendar/Calendar.js.map +1 -1
- package/dist/components/pro/Calendar/hooks/useCalendarDrag.js.map +1 -1
- package/dist/components/pro/Calendar/hooks/useCalendarState.js +31 -31
- package/dist/components/pro/Calendar/hooks/useCalendarState.js.map +1 -1
- package/dist/components/pro/Calendar/utils.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/markdownExtensions.js.map +1 -1
- package/dist/components/pro/CodeEditor/extensions/contextMenu.js.map +1 -1
- package/dist/components/pro/CodeEditor/extensions/index.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/index.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/javascript.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/python.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/snippets.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/FootnotePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/HistoryPanel.js +65 -59
- package/dist/components/pro/CodeEditor/panels/HistoryPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/TableOfContentsPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/VariablePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/themes.js.map +1 -1
- package/dist/components/pro/CodeEditor/utils.js.map +1 -1
- package/dist/components/pro/DataTable/DataTable.js.map +1 -1
- package/dist/components/pro/DataTable/Filters.js.map +1 -1
- package/dist/components/pro/DataTable/PivotPanel.js.map +1 -1
- package/dist/components/pro/DataTable/PivotView.js.map +1 -1
- package/dist/components/pro/DataTable/components/BulkActions.js.map +1 -1
- package/dist/components/pro/DataTable/components/ColumnSelector.js.map +1 -1
- package/dist/components/pro/DataTable/components/FilterBar.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableHeader.js.map +1 -1
- package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
- package/dist/components/pro/DataTable/extension.js.map +1 -1
- package/dist/components/pro/DataTable/pivotEngine.js.map +1 -1
- package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
- package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
- package/dist/components/pro/DataTable/treeDataUtils.js.map +1 -1
- package/dist/components/pro/DataTable/useColumnDragReorder.js.map +1 -1
- package/dist/components/pro/DataTable/useDataTableModel.js +119 -104
- package/dist/components/pro/DataTable/useDataTableModel.js.map +1 -1
- package/dist/components/pro/DataTable/utils.js.map +1 -1
- package/dist/components/pro/FileExplorer/Breadcrumb.js.map +1 -1
- package/dist/components/pro/FileExplorer/CreateDialog.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileExplorer.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileIcon.js.map +1 -1
- package/dist/components/pro/FileExplorer/GridView.js.map +1 -1
- package/dist/components/pro/FileExplorer/ListView.js.map +1 -1
- package/dist/components/pro/FileExplorer/Toolbar.js.map +1 -1
- package/dist/components/pro/Flow/Flow.js.map +1 -1
- package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
- package/dist/components/pro/Flow/archify/build.js.map +1 -1
- package/dist/components/pro/Flow/archify/convert.js.map +1 -1
- package/dist/components/pro/Flow/archify/palette.js.map +1 -1
- package/dist/components/pro/Flow/archify/presets.js.map +1 -1
- package/dist/components/pro/Flow/archify/spec.js.map +1 -1
- package/dist/components/pro/Flow/canvas/AlignmentGuides.js.map +1 -1
- package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
- package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
- package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
- package/dist/components/pro/Flow/canvas/SelectionOverlay.js.map +1 -1
- package/dist/components/pro/Flow/canvas/ViewportContainer.js.map +1 -1
- package/dist/components/pro/Flow/constants.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowContext.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
- package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/edges/edgeMarkers.js.map +1 -1
- package/dist/components/pro/Flow/edges/edgePaths.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useAlignmentGuides.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useCompactMode.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useDraggablePanel.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useEdgeMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLineMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useNodeMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/usePdfExport.js.map +1 -1
- package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useResizablePanel.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useSelection.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useUndoRedo.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useViewport.js.map +1 -1
- package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
- package/dist/components/pro/Flow/lines/lineSmoothing.js.map +1 -1
- package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeHandles.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeText.js.map +1 -1
- package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
- package/dist/components/pro/Flow/nodes/animAnchors.js.map +1 -1
- package/dist/components/pro/Flow/nodes/chartGeometryBudget.js.map +1 -1
- package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -1
- package/dist/components/pro/Flow/nodes/demandRender.js.map +1 -1
- package/dist/components/pro/Flow/nodes/nodeUtils.js.map +1 -1
- package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
- package/dist/components/pro/Flow/nodes/svgIconTexture.js.map +1 -1
- package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
- package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/Breadcrumb.js.map +1 -1
- package/dist/components/pro/Flow/panels/ContextMenu.js.map +1 -1
- package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -1
- package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
- package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/PresentationMode.js.map +1 -1
- package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -1
- package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
- package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
- package/dist/components/pro/Flow/types.js.map +1 -1
- package/dist/components/pro/Flow/utils/dashedLine.js.map +1 -1
- package/dist/components/pro/Flow/utils/gradient.js.map +1 -1
- package/dist/components/pro/Flow/utils/pdfExport.js.map +1 -1
- package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
- package/dist/components/pro/Gantt/Gantt.js.map +1 -1
- package/dist/components/pro/Gantt/hooks/useGanttDrag.js.map +1 -1
- package/dist/components/pro/Gantt/hooks/useGanttState.js +79 -71
- package/dist/components/pro/Gantt/hooks/useGanttState.js.map +1 -1
- package/dist/components/pro/Gantt/utils.js.map +1 -1
- package/dist/components/pro/Kanban/Kanban.js.map +1 -1
- package/dist/components/pro/Kanban/Swimlanes.js.map +1 -1
- package/dist/components/pro/Kanban/useKanbanDrag.js.map +1 -1
- package/dist/components/pro/Kanban/utils.js.map +1 -1
- package/dist/components/pro/RichTextEditor/AIRewrite.d.ts +1 -0
- package/dist/components/pro/RichTextEditor/AIRewrite.js +109 -88
- package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
- package/dist/components/pro/RichTextEditor/ContextMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/RichTextEditor.js +133 -132
- package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
- package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/SelectDropdown.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CommentMark.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FontSize.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/ResizableImage.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/legacyMermaid.js.map +1 -1
- package/dist/components/pro/RichTextEditor/types.d.ts +2 -0
- package/dist/components/pro/RichTextEditor/types.js.map +1 -1
- package/dist/components/pro/Sprite/Molly/animations.d.ts +6 -0
- package/dist/components/pro/Sprite/Molly/animations.js +52 -0
- package/dist/components/pro/Sprite/Molly/animations.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/events.d.ts +2 -0
- package/dist/components/pro/Sprite/Molly/events.js +46 -0
- package/dist/components/pro/Sprite/Molly/events.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/index.d.ts +1 -0
- package/dist/components/pro/Sprite/Molly/index.js +12 -0
- package/dist/components/pro/Sprite/Molly/index.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/legFlexion.d.ts +3 -0
- package/dist/components/pro/Sprite/Molly/legFlexion.js +48 -0
- package/dist/components/pro/Sprite/Molly/legFlexion.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/locomotion.d.ts +4 -0
- package/dist/components/pro/Sprite/Molly/locomotion.js +51 -0
- package/dist/components/pro/Sprite/Molly/locomotion.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/model.d.ts +23 -0
- package/dist/components/pro/Sprite/Molly/model.js +614 -0
- package/dist/components/pro/Sprite/Molly/model.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/rig.d.ts +25 -0
- package/dist/components/pro/Sprite/Molly/rig.js +102 -0
- package/dist/components/pro/Sprite/Molly/rig.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/animations.d.ts +6 -0
- package/dist/components/pro/Sprite/Ruby/animations.js +58 -0
- package/dist/components/pro/Sprite/Ruby/animations.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/events.d.ts +2 -0
- package/dist/components/pro/Sprite/Ruby/events.js +46 -0
- package/dist/components/pro/Sprite/Ruby/events.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/index.d.ts +1 -0
- package/dist/components/pro/Sprite/Ruby/index.js +12 -0
- package/dist/components/pro/Sprite/Ruby/index.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/locomotion.d.ts +4 -0
- package/dist/components/pro/Sprite/Ruby/locomotion.js +41 -0
- package/dist/components/pro/Sprite/Ruby/locomotion.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/model.d.ts +23 -0
- package/dist/components/pro/Sprite/Ruby/model.js +605 -0
- package/dist/components/pro/Sprite/Ruby/model.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/rig.d.ts +26 -0
- package/dist/components/pro/Sprite/Ruby/rig.js +112 -0
- package/dist/components/pro/Sprite/Ruby/rig.js.map +1 -0
- package/dist/components/pro/Sprite/Sprite.d.ts +23 -0
- package/dist/components/pro/Sprite/Sprite2.js +224 -0
- package/dist/components/pro/Sprite/Sprite2.js.map +1 -0
- package/dist/components/pro/Sprite/actions.d.ts +3 -0
- package/dist/components/pro/Sprite/actions.js +16 -0
- package/dist/components/pro/Sprite/actions.js.map +1 -0
- package/dist/components/pro/Sprite/createSpriteScene.d.ts +4 -0
- package/dist/components/pro/Sprite/createSpriteScene.js +14 -0
- package/dist/components/pro/Sprite/createSpriteScene.js.map +1 -0
- package/dist/components/pro/Sprite/index.d.ts +4 -0
- package/dist/components/pro/Sprite/shared/animation.d.ts +33 -0
- package/dist/components/pro/Sprite/shared/animation.js +39 -0
- package/dist/components/pro/Sprite/shared/animation.js.map +1 -0
- package/dist/components/pro/Sprite/shared/createSpriteStage.d.ts +14 -0
- package/dist/components/pro/Sprite/shared/createSpriteStage.js +127 -0
- package/dist/components/pro/Sprite/shared/createSpriteStage.js.map +1 -0
- package/dist/components/pro/Sprite/shared/events.d.ts +5 -0
- package/dist/components/pro/Sprite/shared/events.js +21 -0
- package/dist/components/pro/Sprite/shared/events.js.map +1 -0
- package/dist/components/pro/Sprite/shared/face.d.ts +15 -0
- package/dist/components/pro/Sprite/shared/face.js +33 -0
- package/dist/components/pro/Sprite/shared/face.js.map +1 -0
- package/dist/components/pro/Sprite/shared/faceSurface.d.ts +6 -0
- package/dist/components/pro/Sprite/shared/faceSurface.js +66 -0
- package/dist/components/pro/Sprite/shared/faceSurface.js.map +1 -0
- package/dist/components/pro/Sprite/shared/gait.d.ts +5 -0
- package/dist/components/pro/Sprite/shared/gait.js +19 -0
- package/dist/components/pro/Sprite/shared/gait.js.map +1 -0
- package/dist/components/pro/Sprite/shared/geometry.d.ts +8 -0
- package/dist/components/pro/Sprite/shared/geometry.js +59 -0
- package/dist/components/pro/Sprite/shared/geometry.js.map +1 -0
- package/dist/components/pro/Sprite/shared/magicEffect.d.ts +27 -0
- package/dist/components/pro/Sprite/shared/magicEffect.js +61 -0
- package/dist/components/pro/Sprite/shared/magicEffect.js.map +1 -0
- package/dist/components/pro/Sprite/shared/playback.d.ts +8 -0
- package/dist/components/pro/Sprite/shared/playback.js +74 -0
- package/dist/components/pro/Sprite/shared/playback.js.map +1 -0
- package/dist/components/pro/Sprite/shared/rig.d.ts +6 -0
- package/dist/components/pro/Sprite/shared/rig.js +48 -0
- package/dist/components/pro/Sprite/shared/rig.js.map +1 -0
- package/dist/components/pro/Sprite/shared/scene.d.ts +9 -0
- package/dist/components/pro/Sprite/shared/scene.js +21 -0
- package/dist/components/pro/Sprite/shared/scene.js.map +1 -0
- package/dist/components/pro/Sprite/shared/sculptor.d.ts +14 -0
- package/dist/components/pro/Sprite/shared/sculptor.js +78 -0
- package/dist/components/pro/Sprite/shared/sculptor.js.map +1 -0
- package/dist/components/pro/Sprite/shared/speechBubble.d.ts +15 -0
- package/dist/components/pro/Sprite/shared/speechBubble.js +129 -0
- package/dist/components/pro/Sprite/shared/speechBubble.js.map +1 -0
- package/dist/components/pro/Sprite/types.d.ts +40 -0
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/contexts/authentication.js.map +1 -1
- package/dist/data-table.js +3 -3
- package/dist/data-table.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/hooks/useClickOutside.js.map +1 -1
- package/dist/hooks/useContainerElement.js.map +1 -1
- package/dist/hooks/useControllableState.js.map +1 -1
- package/dist/hooks/useCopyToClipboard.js.map +1 -1
- package/dist/hooks/useDebounce.js.map +1 -1
- package/dist/hooks/useDraggable.js.map +1 -1
- package/dist/hooks/useTableColumns.js.map +1 -1
- package/dist/hooks/useTableData.js.map +1 -1
- package/dist/index-nostyled.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +116 -115
- package/dist/layouts/MainLayout.js.map +1 -1
- package/dist/layouts/Navbar.js.map +1 -1
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/layouts/headbar/Headbar.js.map +1 -1
- package/dist/layouts/headbar/HeadbarLangSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarSearch.js.map +1 -1
- package/dist/layouts/headbar/HeadbarThemeSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarTitle.js.map +1 -1
- package/dist/sprite.js +2 -0
- package/dist/styles/themeStyles.js.map +1 -1
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/flexLayout.js.map +1 -1
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/menu.js.map +1 -1
- package/dist/utils/rehype-code-meta.js.map +1 -1
- package/dist/utils/remark-code-meta.js.map +1 -1
- package/dist/utils/routerBuilder.js.map +1 -1
- package/dist/utils/safeStorage.js.map +1 -1
- package/dist/utils/selection.js +29 -20
- package/dist/utils/selection.js.map +1 -1
- package/dist/utils/themes.js.map +1 -1
- package/package.json +15 -11
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { DEFAULT_SCALE_CONFIGS as e, computeDateRange as t, dateToX as n, flattenTree as r, generateDateRange as i, generateHeaderGroups as a,
|
|
2
|
-
import { useCallback as
|
|
1
|
+
import { DEFAULT_SCALE_CONFIGS as e, computeDateRange as t, dateToX as n, flattenTree as r, generateDateRange as i, generateHeaderGroups as a, isSameDay as o, startOfDay as s } from "../utils.js";
|
|
2
|
+
import { useCallback as c, useEffect as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
3
3
|
//#region src/components/pro/Gantt/hooks/useGanttState.ts
|
|
4
|
-
function
|
|
5
|
-
let { data:
|
|
6
|
-
|
|
7
|
-
}, [
|
|
4
|
+
function p(p) {
|
|
5
|
+
let { data: m, defaultScale: h = "day", defaultExpandedIds: g, defaultExpandAll: _ = !0, scaleConfigs: v, categories: y = {}, holidays: b, timeWindow: x, availableScales: S, onScaleChange: C, onNodeToggle: w, onViewChange: T } = p, [E, D] = f(h), O = c((e) => {
|
|
6
|
+
D(e), C?.(e);
|
|
7
|
+
}, [C]), k = u(() => ({
|
|
8
8
|
...e,
|
|
9
|
-
...
|
|
10
|
-
}), [
|
|
9
|
+
...v
|
|
10
|
+
}), [v]), A = k[E], j = u(() => S || [
|
|
11
11
|
"year",
|
|
12
12
|
"quarter",
|
|
13
13
|
"month",
|
|
@@ -15,81 +15,89 @@ function d(d) {
|
|
|
15
15
|
"day",
|
|
16
16
|
"halfday",
|
|
17
17
|
"hour"
|
|
18
|
-
], [
|
|
19
|
-
|
|
20
|
-
let r = new Set(n), i =
|
|
21
|
-
return
|
|
18
|
+
], [S]), [M, N] = f(() => g ? new Set(g) : /* @__PURE__ */ new Set()), P = c((e, t) => {
|
|
19
|
+
N((n) => {
|
|
20
|
+
let r = new Set(n), i = _ ? !n.has(e) : n.has(e), a = t ?? !i;
|
|
21
|
+
return _ ? a ? r.delete(e) : r.add(e) : a ? r.add(e) : r.delete(e), w?.(e, a), r;
|
|
22
22
|
});
|
|
23
|
-
}, [
|
|
24
|
-
|
|
25
|
-
}, []),
|
|
23
|
+
}, [_, w]), F = c(() => {
|
|
24
|
+
N(/* @__PURE__ */ new Set());
|
|
25
|
+
}, []), I = c(() => {
|
|
26
26
|
let e = /* @__PURE__ */ new Set();
|
|
27
27
|
function t(n) {
|
|
28
28
|
for (let r of n) r.children && r.children.length > 0 && (e.add(r.id), t(r.children));
|
|
29
29
|
}
|
|
30
|
-
t(
|
|
31
|
-
}, [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
h,
|
|
35
|
-
L,
|
|
36
|
-
O,
|
|
30
|
+
t(m), N(_ ? e : /* @__PURE__ */ new Set());
|
|
31
|
+
}, [m, _]), [L, R] = f(null), z = u(() => t(m, b), [m, b]), B = u(() => i(z.start, z.end), [z]), V = u(() => a(B, E), [B, E]), H = u(() => r(m, M, _, z, A, y, b, x), [
|
|
32
|
+
m,
|
|
33
|
+
M,
|
|
37
34
|
_,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
z,
|
|
36
|
+
A,
|
|
37
|
+
y,
|
|
38
|
+
b,
|
|
39
|
+
x
|
|
40
|
+
]), U = B.length * A.cellWidth * A.slotsPerDay, [W, G] = f(() => s(/* @__PURE__ */ new Date()));
|
|
41
|
+
l(() => {
|
|
42
|
+
let e = setInterval(() => {
|
|
43
|
+
let e = s(/* @__PURE__ */ new Date());
|
|
44
|
+
G((t) => o(t, e) ? t : e);
|
|
45
|
+
}, 6e4);
|
|
46
|
+
return () => clearInterval(e);
|
|
47
|
+
}, []);
|
|
48
|
+
let K = n(W, z.start, A), q = d(null), J = d(null), Y = d(null), X = d(!1), Z = c((e) => {
|
|
49
|
+
if (X.current) return;
|
|
50
|
+
X.current = !0;
|
|
51
|
+
let t = e === "tree" ? q.current : J.current, n = e === "tree" ? J.current : q.current;
|
|
44
52
|
t && n && (n.scrollTop = t.scrollTop), requestAnimationFrame(() => {
|
|
45
|
-
|
|
53
|
+
X.current = !1;
|
|
46
54
|
});
|
|
47
|
-
}, []),
|
|
48
|
-
|
|
49
|
-
}, []),
|
|
50
|
-
let t = n(e,
|
|
51
|
-
if (
|
|
52
|
-
let e =
|
|
53
|
-
|
|
55
|
+
}, []), Q = c(() => {
|
|
56
|
+
J.current && Y.current && (Y.current.scrollLeft = J.current.scrollLeft);
|
|
57
|
+
}, []), $ = c((e) => {
|
|
58
|
+
let t = n(e, z.start, A);
|
|
59
|
+
if (J.current) {
|
|
60
|
+
let e = J.current.clientWidth;
|
|
61
|
+
J.current.scrollLeft = Math.max(0, t - e / 3);
|
|
54
62
|
}
|
|
55
|
-
}, [
|
|
63
|
+
}, [z.start, A]);
|
|
56
64
|
return {
|
|
57
|
-
scale:
|
|
58
|
-
setScale:
|
|
59
|
-
scales:
|
|
60
|
-
currentScaleConfig:
|
|
61
|
-
mergedScaleConfigs:
|
|
62
|
-
expandedIds:
|
|
63
|
-
toggleNode:
|
|
64
|
-
expandAll:
|
|
65
|
-
collapseAll:
|
|
66
|
-
selectedNodeId:
|
|
67
|
-
setSelectedNodeId:
|
|
68
|
-
dateRange:
|
|
69
|
-
dates:
|
|
70
|
-
headerGroups:
|
|
71
|
-
today:
|
|
72
|
-
todayX:
|
|
73
|
-
totalTimelineWidth:
|
|
74
|
-
flatNodes:
|
|
75
|
-
treeBodyRef:
|
|
76
|
-
timelineBodyRef:
|
|
77
|
-
timelineHeaderRef:
|
|
78
|
-
syncScrollVertical:
|
|
79
|
-
syncScrollHorizontal:
|
|
80
|
-
scrollToDate:
|
|
81
|
-
scrollToToday:
|
|
82
|
-
|
|
83
|
-
}, [
|
|
84
|
-
scrollToNode:
|
|
85
|
-
let t =
|
|
86
|
-
t >= 0 &&
|
|
87
|
-
let n =
|
|
88
|
-
n?.resolvedStartDate &&
|
|
89
|
-
}, [
|
|
65
|
+
scale: E,
|
|
66
|
+
setScale: O,
|
|
67
|
+
scales: j,
|
|
68
|
+
currentScaleConfig: A,
|
|
69
|
+
mergedScaleConfigs: k,
|
|
70
|
+
expandedIds: M,
|
|
71
|
+
toggleNode: P,
|
|
72
|
+
expandAll: F,
|
|
73
|
+
collapseAll: I,
|
|
74
|
+
selectedNodeId: L,
|
|
75
|
+
setSelectedNodeId: R,
|
|
76
|
+
dateRange: z,
|
|
77
|
+
dates: B,
|
|
78
|
+
headerGroups: V,
|
|
79
|
+
today: W,
|
|
80
|
+
todayX: K,
|
|
81
|
+
totalTimelineWidth: U,
|
|
82
|
+
flatNodes: H,
|
|
83
|
+
treeBodyRef: q,
|
|
84
|
+
timelineBodyRef: J,
|
|
85
|
+
timelineHeaderRef: Y,
|
|
86
|
+
syncScrollVertical: Z,
|
|
87
|
+
syncScrollHorizontal: Q,
|
|
88
|
+
scrollToDate: $,
|
|
89
|
+
scrollToToday: c(() => {
|
|
90
|
+
$(s(/* @__PURE__ */ new Date()));
|
|
91
|
+
}, [$]),
|
|
92
|
+
scrollToNode: c((e) => {
|
|
93
|
+
let t = H.findIndex((t) => t.node.id === e);
|
|
94
|
+
t >= 0 && q.current && (q.current.scrollTop = t * 36);
|
|
95
|
+
let n = H.find((t) => t.node.id === e);
|
|
96
|
+
n?.resolvedStartDate && $(n.resolvedStartDate);
|
|
97
|
+
}, [H, $])
|
|
90
98
|
};
|
|
91
99
|
}
|
|
92
100
|
//#endregion
|
|
93
|
-
export {
|
|
101
|
+
export { p as useGanttState };
|
|
94
102
|
|
|
95
103
|
//# sourceMappingURL=useGanttState.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGanttState.js","names":[],"sources":["../../../../../src/components/pro/Gantt/hooks/useGanttState.ts"],"sourcesContent":["/**\n * Core state management hook for the Gantt component.\n * Manages expansion, selection, scale, date range, and scroll synchronization.\n */\n\nimport { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport type {\n GanttNode,\n GanttNodeId,\n GanttScaleLevel,\n GanttScaleConfig,\n GanttCategoryConfig,\n HolidayCalendar,\n TimeWindow,\n FlatGanttNode,\n} from '../types';\nimport {\n DEFAULT_SCALE_CONFIGS,\n computeDateRange,\n generateDateRange,\n generateHeaderGroups,\n flattenTree,\n startOfDay,\n dateToX,\n isSameDay,\n} from '../utils';\n\nexport interface UseGanttStateOptions {\n data: GanttNode[];\n defaultScale?: GanttScaleLevel;\n defaultExpandedIds?: GanttNodeId[];\n defaultExpandAll?: boolean;\n scaleConfigs?: Partial<Record<GanttScaleLevel, GanttScaleConfig>>;\n categories?: Record<string, GanttCategoryConfig>;\n holidays?: HolidayCalendar;\n timeWindow?: TimeWindow;\n availableScales?: GanttScaleLevel[];\n onScaleChange?: (scale: GanttScaleLevel) => void;\n onNodeToggle?: (nodeId: GanttNodeId, expanded: boolean) => void;\n onViewChange?: (start: Date, end: Date, scale: GanttScaleLevel) => void;\n}\n\nexport function useGanttState(options: UseGanttStateOptions) {\n const {\n data,\n defaultScale = 'day',\n defaultExpandedIds,\n defaultExpandAll = true,\n scaleConfigs: customScaleConfigs,\n categories = {},\n holidays,\n timeWindow,\n availableScales,\n onScaleChange,\n onNodeToggle,\n onViewChange,\n } = options;\n\n // ─── Scale state ────────────────────────────────────────────\n const [scale, setScaleRaw] = useState<GanttScaleLevel>(defaultScale);\n const setScale = useCallback(\n (newScale: GanttScaleLevel) => {\n setScaleRaw(newScale);\n onScaleChange?.(newScale);\n },\n [onScaleChange]\n );\n\n const mergedScaleConfigs = useMemo(\n () => ({ ...DEFAULT_SCALE_CONFIGS, ...customScaleConfigs }),\n [customScaleConfigs]\n );\n\n const currentScaleConfig = mergedScaleConfigs[scale];\n\n const scales = useMemo(\n () => availableScales || (['year', 'quarter', 'month', 'week', 'day', 'halfday', 'hour'] as GanttScaleLevel[]),\n [availableScales]\n );\n\n // ─── Expansion state ────────────────────────────────────────\n // In defaultExpandAll mode, this set tracks COLLAPSED node IDs.\n // Otherwise, it tracks EXPANDED node IDs.\n const [expandedIds, setExpandedIds] = useState<Set<GanttNodeId>>(() => {\n if (defaultExpandedIds) {\n return new Set(defaultExpandedIds);\n }\n return new Set<GanttNodeId>();\n });\n\n const toggleNode = useCallback(\n (nodeId: GanttNodeId, expanded?: boolean) => {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n const isCurrentlyExpanded = defaultExpandAll ? !prev.has(nodeId) : prev.has(nodeId);\n const shouldExpand = expanded ?? !isCurrentlyExpanded;\n\n if (defaultExpandAll) {\n // In expandAll mode, the set tracks collapsed IDs\n if (shouldExpand) {\n next.delete(nodeId);\n } else {\n next.add(nodeId);\n }\n } else {\n if (shouldExpand) {\n next.add(nodeId);\n } else {\n next.delete(nodeId);\n }\n }\n\n onNodeToggle?.(nodeId, shouldExpand);\n return next;\n });\n },\n [defaultExpandAll, onNodeToggle]\n );\n\n const expandAll = useCallback(() => {\n setExpandedIds(new Set());\n }, []);\n\n const collapseAll = useCallback(() => {\n // Collect all node IDs that have children\n const allParentIds = new Set<GanttNodeId>();\n function collect(nodes: GanttNode[]) {\n for (const n of nodes) {\n if (n.children && n.children.length > 0) {\n allParentIds.add(n.id);\n collect(n.children);\n }\n }\n }\n collect(data);\n\n if (defaultExpandAll) {\n // In expandAll mode, collapsed set = all parent IDs\n setExpandedIds(allParentIds);\n } else {\n setExpandedIds(new Set());\n }\n }, [data, defaultExpandAll]);\n\n // ─── Selection state ────────────────────────────────────────\n const [selectedNodeId, setSelectedNodeId] = useState<GanttNodeId | null>(null);\n\n // ─── Date range ─────────────────────────────────────────────\n const dateRange = useMemo(() => computeDateRange(data, holidays), [data, holidays]);\n\n const dates = useMemo(() => generateDateRange(dateRange.start, dateRange.end), [dateRange]);\n\n const headerGroups = useMemo(\n () => generateHeaderGroups(dates, scale),\n [dates, scale]\n );\n\n // ─── Flattened tree ─────────────────────────────────────────\n const flatNodes = useMemo(\n () =>\n flattenTree(\n data,\n expandedIds,\n defaultExpandAll,\n dateRange,\n currentScaleConfig,\n categories,\n holidays,\n timeWindow\n ),\n [data, expandedIds, defaultExpandAll, dateRange, currentScaleConfig, categories, holidays, timeWindow]\n );\n\n // ─── Total timeline width ───────────────────────────────────\n const totalTimelineWidth = dates.length * currentScaleConfig.cellWidth * currentScaleConfig.slotsPerDay;\n\n // ─── Today position ─────────────────────────────────────────\n const today = startOfDay(new Date());\n const todayX = dateToX(today, dateRange.start, currentScaleConfig);\n\n // ─── Scroll refs ────────────────────────────────────────────\n const treeBodyRef = useRef<HTMLDivElement>(null);\n const timelineBodyRef = useRef<HTMLDivElement>(null);\n const timelineHeaderRef = useRef<HTMLDivElement>(null);\n const isSyncingScroll = useRef(false);\n\n const syncScrollVertical = useCallback((source: 'tree' | 'timeline') => {\n if (isSyncingScroll.current) return;\n isSyncingScroll.current = true;\n\n const sourceEl = source === 'tree' ? treeBodyRef.current : timelineBodyRef.current;\n const targetEl = source === 'tree' ? timelineBodyRef.current : treeBodyRef.current;\n\n if (sourceEl && targetEl) {\n targetEl.scrollTop = sourceEl.scrollTop;\n }\n\n requestAnimationFrame(() => {\n isSyncingScroll.current = false;\n });\n }, []);\n\n const syncScrollHorizontal = useCallback(() => {\n if (timelineBodyRef.current && timelineHeaderRef.current) {\n timelineHeaderRef.current.scrollLeft = timelineBodyRef.current.scrollLeft;\n }\n }, []);\n\n // ─── Scroll to date ─────────────────────────────────────────\n const scrollToDate = useCallback(\n (date: Date) => {\n const x = dateToX(date, dateRange.start, currentScaleConfig);\n if (timelineBodyRef.current) {\n const viewportWidth = timelineBodyRef.current.clientWidth;\n timelineBodyRef.current.scrollLeft = Math.max(0, x - viewportWidth / 3);\n }\n },\n [dateRange.start, currentScaleConfig]\n );\n\n const scrollToToday = useCallback(() => {\n scrollToDate(today);\n }, [scrollToDate, today]);\n\n const scrollToNode = useCallback(\n (nodeId: GanttNodeId) => {\n const idx = flatNodes.findIndex((fn) => fn.node.id === nodeId);\n if (idx >= 0 && treeBodyRef.current) {\n const rowHeight = 36; // will be from props\n treeBodyRef.current.scrollTop = idx * rowHeight;\n }\n // Also scroll timeline to node's start date\n const node = flatNodes.find((fn) => fn.node.id === nodeId);\n if (node?.resolvedStartDate) {\n scrollToDate(node.resolvedStartDate);\n }\n },\n [flatNodes, scrollToDate]\n );\n\n return {\n // Scale\n scale,\n setScale,\n scales,\n currentScaleConfig,\n mergedScaleConfigs,\n\n // Expansion\n expandedIds,\n toggleNode,\n expandAll,\n collapseAll,\n\n // Selection\n selectedNodeId,\n setSelectedNodeId,\n\n // Date data\n dateRange,\n dates,\n headerGroups,\n today,\n todayX,\n totalTimelineWidth,\n\n // Flattened tree\n flatNodes,\n\n // Scroll\n treeBodyRef,\n timelineBodyRef,\n timelineHeaderRef,\n syncScrollVertical,\n syncScrollHorizontal,\n scrollToDate,\n scrollToToday,\n scrollToNode,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useGanttState.js","names":["useGanttState","customScaleConfigs","options","scale","setScaleRaw","useState","defaultScale","setScale","useCallback","newScale","onScaleChange","mergedScaleConfigs","useMemo","DEFAULT_SCALE_CONFIGS","currentScaleConfig","scales","availableScales","expandedIds","setExpandedIds","defaultExpandedIds","toggleNode","next","prev","isCurrentlyExpanded","defaultExpandAll","nodeId","shouldExpand","expanded","onNodeToggle","expandAll","collapseAll","allParentIds","collect","n","nodes","data","selectedNodeId","setSelectedNodeId","dateRange","computeDateRange","holidays","dates","generateDateRange","headerGroups","generateHeaderGroups","flatNodes","flattenTree","categories","timeWindow","totalTimelineWidth","today","setToday","startOfDay","timer","current","isSameDay","previous","todayX","dateToX","treeBodyRef","useRef","timelineBodyRef","timelineHeaderRef","isSyncingScroll","syncScrollVertical","sourceEl","source","targetEl","syncScrollHorizontal","scrollToDate","x","date","viewportWidth","idx","fn","node"],"sources":["../../../../../src/components/pro/Gantt/hooks/useGanttState.ts"],"sourcesContent":["/**\n * Core state management hook for the Gantt component.\n * Manages expansion, selection, scale, date range, and scroll synchronization.\n */\n\nimport { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport type {\n GanttNode,\n GanttNodeId,\n GanttScaleLevel,\n GanttScaleConfig,\n GanttCategoryConfig,\n HolidayCalendar,\n TimeWindow,\n FlatGanttNode,\n} from '../types';\nimport {\n DEFAULT_SCALE_CONFIGS,\n computeDateRange,\n generateDateRange,\n generateHeaderGroups,\n flattenTree,\n startOfDay,\n dateToX,\n isSameDay,\n} from '../utils';\n\nexport interface UseGanttStateOptions {\n data: GanttNode[];\n defaultScale?: GanttScaleLevel;\n defaultExpandedIds?: GanttNodeId[];\n defaultExpandAll?: boolean;\n scaleConfigs?: Partial<Record<GanttScaleLevel, GanttScaleConfig>>;\n categories?: Record<string, GanttCategoryConfig>;\n holidays?: HolidayCalendar;\n timeWindow?: TimeWindow;\n availableScales?: GanttScaleLevel[];\n onScaleChange?: (scale: GanttScaleLevel) => void;\n onNodeToggle?: (nodeId: GanttNodeId, expanded: boolean) => void;\n onViewChange?: (start: Date, end: Date, scale: GanttScaleLevel) => void;\n}\n\nexport function useGanttState(options: UseGanttStateOptions) {\n const {\n data,\n defaultScale = 'day',\n defaultExpandedIds,\n defaultExpandAll = true,\n scaleConfigs: customScaleConfigs,\n categories = {},\n holidays,\n timeWindow,\n availableScales,\n onScaleChange,\n onNodeToggle,\n onViewChange,\n } = options;\n\n // ─── Scale state ────────────────────────────────────────────\n const [scale, setScaleRaw] = useState<GanttScaleLevel>(defaultScale);\n const setScale = useCallback(\n (newScale: GanttScaleLevel) => {\n setScaleRaw(newScale);\n onScaleChange?.(newScale);\n },\n [onScaleChange]\n );\n\n const mergedScaleConfigs = useMemo(\n () => ({ ...DEFAULT_SCALE_CONFIGS, ...customScaleConfigs }),\n [customScaleConfigs]\n );\n\n const currentScaleConfig = mergedScaleConfigs[scale];\n\n const scales = useMemo(\n () => availableScales || (['year', 'quarter', 'month', 'week', 'day', 'halfday', 'hour'] as GanttScaleLevel[]),\n [availableScales]\n );\n\n // ─── Expansion state ────────────────────────────────────────\n // In defaultExpandAll mode, this set tracks COLLAPSED node IDs.\n // Otherwise, it tracks EXPANDED node IDs.\n const [expandedIds, setExpandedIds] = useState<Set<GanttNodeId>>(() => {\n if (defaultExpandedIds) {\n return new Set(defaultExpandedIds);\n }\n return new Set<GanttNodeId>();\n });\n\n const toggleNode = useCallback(\n (nodeId: GanttNodeId, expanded?: boolean) => {\n setExpandedIds((prev) => {\n const next = new Set(prev);\n const isCurrentlyExpanded = defaultExpandAll ? !prev.has(nodeId) : prev.has(nodeId);\n const shouldExpand = expanded ?? !isCurrentlyExpanded;\n\n if (defaultExpandAll) {\n // In expandAll mode, the set tracks collapsed IDs\n if (shouldExpand) {\n next.delete(nodeId);\n } else {\n next.add(nodeId);\n }\n } else {\n if (shouldExpand) {\n next.add(nodeId);\n } else {\n next.delete(nodeId);\n }\n }\n\n onNodeToggle?.(nodeId, shouldExpand);\n return next;\n });\n },\n [defaultExpandAll, onNodeToggle]\n );\n\n const expandAll = useCallback(() => {\n setExpandedIds(new Set());\n }, []);\n\n const collapseAll = useCallback(() => {\n // Collect all node IDs that have children\n const allParentIds = new Set<GanttNodeId>();\n function collect(nodes: GanttNode[]) {\n for (const n of nodes) {\n if (n.children && n.children.length > 0) {\n allParentIds.add(n.id);\n collect(n.children);\n }\n }\n }\n collect(data);\n\n if (defaultExpandAll) {\n // In expandAll mode, collapsed set = all parent IDs\n setExpandedIds(allParentIds);\n } else {\n setExpandedIds(new Set());\n }\n }, [data, defaultExpandAll]);\n\n // ─── Selection state ────────────────────────────────────────\n const [selectedNodeId, setSelectedNodeId] = useState<GanttNodeId | null>(null);\n\n // ─── Date range ─────────────────────────────────────────────\n const dateRange = useMemo(() => computeDateRange(data, holidays), [data, holidays]);\n\n const dates = useMemo(() => generateDateRange(dateRange.start, dateRange.end), [dateRange]);\n\n const headerGroups = useMemo(\n () => generateHeaderGroups(dates, scale),\n [dates, scale]\n );\n\n // ─── Flattened tree ─────────────────────────────────────────\n const flatNodes = useMemo(\n () =>\n flattenTree(\n data,\n expandedIds,\n defaultExpandAll,\n dateRange,\n currentScaleConfig,\n categories,\n holidays,\n timeWindow\n ),\n [data, expandedIds, defaultExpandAll, dateRange, currentScaleConfig, categories, holidays, timeWindow]\n );\n\n // ─── Total timeline width ───────────────────────────────────\n const totalTimelineWidth = dates.length * currentScaleConfig.cellWidth * currentScaleConfig.slotsPerDay;\n\n // ─── Today position ─────────────────────────────────────────\n const [today, setToday] = useState(() => startOfDay(new Date()));\n useEffect(() => {\n const updateToday = () => {\n const current = startOfDay(new Date());\n setToday((previous) => isSameDay(previous, current) ? previous : current);\n };\n const timer = setInterval(updateToday, 60_000);\n return () => clearInterval(timer);\n }, []);\n const todayX = dateToX(today, dateRange.start, currentScaleConfig);\n\n // ─── Scroll refs ────────────────────────────────────────────\n const treeBodyRef = useRef<HTMLDivElement>(null);\n const timelineBodyRef = useRef<HTMLDivElement>(null);\n const timelineHeaderRef = useRef<HTMLDivElement>(null);\n const isSyncingScroll = useRef(false);\n\n const syncScrollVertical = useCallback((source: 'tree' | 'timeline') => {\n if (isSyncingScroll.current) return;\n isSyncingScroll.current = true;\n\n const sourceEl = source === 'tree' ? treeBodyRef.current : timelineBodyRef.current;\n const targetEl = source === 'tree' ? timelineBodyRef.current : treeBodyRef.current;\n\n if (sourceEl && targetEl) {\n targetEl.scrollTop = sourceEl.scrollTop;\n }\n\n requestAnimationFrame(() => {\n isSyncingScroll.current = false;\n });\n }, []);\n\n const syncScrollHorizontal = useCallback(() => {\n if (timelineBodyRef.current && timelineHeaderRef.current) {\n timelineHeaderRef.current.scrollLeft = timelineBodyRef.current.scrollLeft;\n }\n }, []);\n\n // ─── Scroll to date ─────────────────────────────────────────\n const scrollToDate = useCallback(\n (date: Date) => {\n const x = dateToX(date, dateRange.start, currentScaleConfig);\n if (timelineBodyRef.current) {\n const viewportWidth = timelineBodyRef.current.clientWidth;\n timelineBodyRef.current.scrollLeft = Math.max(0, x - viewportWidth / 3);\n }\n },\n [dateRange.start, currentScaleConfig]\n );\n\n const scrollToToday = useCallback(() => {\n scrollToDate(startOfDay(new Date()));\n }, [scrollToDate]);\n\n const scrollToNode = useCallback(\n (nodeId: GanttNodeId) => {\n const idx = flatNodes.findIndex((fn) => fn.node.id === nodeId);\n if (idx >= 0 && treeBodyRef.current) {\n const rowHeight = 36; // will be from props\n treeBodyRef.current.scrollTop = idx * rowHeight;\n }\n // Also scroll timeline to node's start date\n const node = flatNodes.find((fn) => fn.node.id === nodeId);\n if (node?.resolvedStartDate) {\n scrollToDate(node.resolvedStartDate);\n }\n },\n [flatNodes, scrollToDate]\n );\n\n return {\n // Scale\n scale,\n setScale,\n scales,\n currentScaleConfig,\n mergedScaleConfigs,\n\n // Expansion\n expandedIds,\n toggleNode,\n expandAll,\n collapseAll,\n\n // Selection\n selectedNodeId,\n setSelectedNodeId,\n\n // Date data\n dateRange,\n dates,\n headerGroups,\n today,\n todayX,\n totalTimelineWidth,\n\n // Flattened tree\n flatNodes,\n\n // Scroll\n treeBodyRef,\n timelineBodyRef,\n timelineHeaderRef,\n syncScrollVertical,\n syncScrollHorizontal,\n scrollToDate,\n scrollToToday,\n scrollToNode,\n };\n}\n"],"mappings":";;;AA0CA,SAAgBA,EAAc,GAA+B;CAC3D,IAAM,EACJ,SACA,kBAAe,OACf,uBACA,sBAAmB,IACnB,cAAcC,GACd,gBAAa,CAAC,GACd,aACA,eACA,oBACA,kBACA,iBACA,oBACEC,GAGE,CAACC,GAAOC,KAAeC,EAA0BC,CAAY,GAC7DC,IAAWC,GACd,MAA8B;EAE7B,AADAJ,EAAYK,CAAQ,GACpBC,IAAgBD,CAAQ;CAC1B,GACA,CAACC,CAAa,CAChB,GAEMC,IAAqBC,SAClB;EAAE,GAAGC;EAAuB,GAAGZ;CAAmB,IACzD,CAACA,CAAkB,CACrB,GAEMa,IAAqBH,EAAmBR,IAExCY,IAASH,QACPI,KAAoB;EAAC;EAAQ;EAAW;EAAS;EAAQ;EAAO;EAAW;CAAM,GACvF,CAACA,CAAe,CAClB,GAKM,CAACC,GAAaC,KAAkBb,QAChCc,IACK,IAAI,IAAIA,CAAkB,oBAE5B,IAAI,IAAiB,CAC7B,GAEKC,IAAaZ,GAChB,GAAqB,MAAuB;EAC3C,GAAgB,MAAS;GACvB,IAAMa,IAAO,IAAI,IAAIC,CAAI,GACnBC,IAAsBC,IAAmB,CAACF,EAAK,IAAIG,CAAM,IAAIH,EAAK,IAAIG,CAAM,GAC5EC,IAAeC,KAAY,CAACJ;GAkBlC,OAhBIC,IAEEE,IACFL,EAAK,OAAOI,CAAM,IAElBJ,EAAK,IAAII,CAAM,IAGbC,IACFL,EAAK,IAAII,CAAM,IAEfJ,EAAK,OAAOI,CAAM,GAItBG,IAAeH,GAAQC,CAAY,GAC5BL;EACT,CAAC;CACH,GACA,CAACG,GAAkBI,CAAY,CACjC,GAEMC,IAAYrB,QAAkB;EAClC,kBAAe,IAAI,IAAI,CAAC;CAC1B,GAAG,CAAC,CAAC,GAECsB,IAActB,QAAkB;EAEpC,IAAMuB,oBAAe,IAAI,IAAiB;EAC1C,SAASC,EAAQ,GAAoB;GACnC,KAAK,IAAMC,KAAKC,GACd,AAAID,EAAE,YAAYA,EAAE,SAAS,SAAS,MACpCF,EAAa,IAAIE,EAAE,EAAE,GACrBD,EAAQC,EAAE,QAAQ;EAGxB;EAGA,AAFAD,EAAQG,CAAI,GAIVjB,EAFEM,IAEaO,oBAEA,IAAI,IAAI,CAAC;CAE5B,GAAG,CAACI,GAAMX,CAAgB,CAAC,GAGrB,CAACY,GAAgBC,KAAqBhC,EAA6B,IAAI,GAGvEiC,IAAY1B,QAAc2B,EAAiBJ,GAAMK,CAAQ,GAAG,CAACL,GAAMK,CAAQ,CAAC,GAE5EC,IAAQ7B,QAAc8B,EAAkBJ,EAAU,OAAOA,EAAU,GAAG,GAAG,CAACA,CAAS,CAAC,GAEpFK,IAAe/B,QACbgC,EAAqBH,GAAOtC,CAAK,GACvC,CAACsC,GAAOtC,CAAK,CACf,GAGM0C,IAAYjC,QAEdkC,EACEX,GACAlB,GACAO,GACAc,GACAxB,GACAiC,GACAP,GACAQ,CACF,GACF;EAACb;EAAMlB;EAAaO;EAAkBc;EAAWxB;EAAoBiC;EAAYP;EAAUQ;CAAU,CACvG,GAGMC,IAAqBR,EAAM,SAAS3B,EAAmB,YAAYA,EAAmB,aAGtF,CAACoC,GAAOC,KAAY9C,QAAe+C,kBAAW,IAAI,KAAK,CAAC,CAAC;CAC/D,QAAgB;EAKd,IAAMC,IAAQ,kBAJY;GACxB,IAAMC,IAAUF,kBAAW,IAAI,KAAK,CAAC;GACrC,GAAU,MAAaG,EAAUC,GAAUF,CAAO,IAAIE,IAAWF,CAAO;EAC1E,GACuC,GAAM;EAC7C,aAAa,cAAcD,CAAK;CAClC,GAAG,CAAC,CAAC;CACL,IAAMI,IAASC,EAAQR,GAAOZ,EAAU,OAAOxB,CAAkB,GAG3D6C,IAAcC,EAAuB,IAAI,GACzCC,IAAkBD,EAAuB,IAAI,GAC7CE,IAAoBF,EAAuB,IAAI,GAC/CG,IAAkBH,EAAO,EAAK,GAE9BI,IAAqBxD,GAAa,MAAgC;EACtE,IAAIuD,EAAgB,SAAS;EAC7B,EAAgB,UAAU;EAE1B,IAAME,IAAWC,MAAW,SAASP,EAAY,UAAUE,EAAgB,SACrEM,IAAWD,MAAW,SAASL,EAAgB,UAAUF,EAAY;EAM3E,AAJIM,KAAYE,MACd,EAAS,YAAYF,EAAS,YAGhC,4BAA4B;GAC1B,EAAgB,UAAU;EAC5B,CAAC;CACH,GAAG,CAAC,CAAC,GAECG,IAAuB5D,QAAkB;EAC7C,AAAIqD,EAAgB,WAAWC,EAAkB,YAC/C,EAAkB,QAAQ,aAAaD,EAAgB,QAAQ;CAEnE,GAAG,CAAC,CAAC,GAGCQ,IAAe7D,GAClB,MAAe;EACd,IAAM8D,IAAIZ,EAAQa,GAAMjC,EAAU,OAAOxB,CAAkB;EAC3D,IAAI+C,EAAgB,SAAS;GAC3B,IAAMW,IAAgBX,EAAgB,QAAQ;GAC9C,EAAgB,QAAQ,aAAa,KAAK,IAAI,GAAGS,IAAIE,IAAgB,CAAC;EACxE;CACF,GACA,CAAClC,EAAU,OAAOxB,CAAkB,CACtC;CAsBA,OAAO;EAEL;EACA;EACA;EACA;EACA;EAGA;EACA;EACA;EACA;EAGA;EACA;EAGA;EACA;EACA;EACA;EACA;EACA;EAGA;EAGA;EACA;EACA;EACA;EACA;EACA;EACA,eAxDoBN,QAAkB;GACtC,EAAa4C,kBAAW,IAAI,KAAK,CAAC,CAAC;EACrC,GAAG,CAACiB,CAAY,CAsDd;EACA,cArDmB7D,GAClB,MAAwB;GACvB,IAAMiE,IAAM5B,EAAU,WAAW,MAAO6B,EAAG,KAAK,OAAOjD,CAAM;GAC7D,AAAIgD,KAAO,KAAKd,EAAY,YAE1B,EAAY,QAAQ,YAAYc,IAAM;GAGxC,IAAME,IAAO9B,EAAU,MAAM,MAAO6B,EAAG,KAAK,OAAOjD,CAAM;GACzD,AAAIkD,GAAM,qBACRN,EAAaM,EAAK,iBAAiB;EAEvC,GACA,CAAC9B,GAAWwB,CAAY,CAwCxB;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../../src/components/pro/Gantt/utils.ts"],"sourcesContent":["/**\n * DishUI Gantt Chart - Utility Functions\n *\n * Core utilities for date math, working day calculations,\n * and coordinate conversions in the Gantt timeline.\n */\n\nimport type {\n GanttNode,\n HolidayCalendar,\n TimeWindow,\n GanttScaleLevel,\n GanttScaleConfig,\n GanttCategoryConfig,\n FlatGanttNode,\n GanttNodeId,\n} from \"./types\";\n\n// ─── Default Scale Configurations ─────────────────────────────────\n\nexport const DEFAULT_SCALE_CONFIGS: Record<GanttScaleLevel, GanttScaleConfig> =\n {\n year: { label: \"Year\", cellWidth: 4, slotsPerDay: 1 },\n quarter: { label: \"Quarter\", cellWidth: 8, slotsPerDay: 1 },\n month: { label: \"Month\", cellWidth: 16, slotsPerDay: 1 },\n week: { label: \"Week\", cellWidth: 24, slotsPerDay: 1 },\n day: { label: \"Day\", cellWidth: 40, slotsPerDay: 1 },\n halfday: { label: \"Half Day\", cellWidth: 40, slotsPerDay: 2 },\n hour: { label: \"Hour\", cellWidth: 30, slotsPerDay: 24 },\n };\n\nexport const DEFAULT_CATEGORY_CONFIG: GanttCategoryConfig = {\n color: \"#3b82f6\",\n backgroundColor: \"#3b82f6\",\n barHeight: 0.6,\n borderRadius: 4,\n showProgress: false,\n skipNonWorkingDays: false,\n draggable: undefined, // inherit from global\n resizable: undefined,\n renderStyle: \"bar\",\n};\n\nexport const DEFAULT_TIME_WINDOW: TimeWindow = {\n startHour: 0,\n endHour: 24,\n};\n\n// ─── Date Utilities ───────────────────────────────────────────────\n\n/**\n * Parse a date value (string or Date) into a Date object.\n * Handles ISO 8601 strings, YYYY-MM-DD strings, and Date objects.\n */\nexport function parseDate(\n value: string | Date | undefined | null,\n): Date | null {\n if (!value) return null;\n if (value instanceof Date) return isNaN(value.getTime()) ? null : value;\n\n const str = String(value);\n\n // ISO format with time/timezone\n if (str.includes(\"T\") || str.includes(\"+\") || str.includes(\"Z\")) {\n const d = new Date(str);\n return isNaN(d.getTime()) ? null : d;\n }\n\n // YYYY-MM-DD format → create in local timezone\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(str)) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n }\n\n const d = new Date(str);\n return isNaN(d.getTime()) ? null : d;\n}\n\n/**\n * Format a Date to YYYY-MM-DD string in local timezone\n */\nexport function formatDate(date: Date): string {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, \"0\");\n const d = String(date.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${d}`;\n}\n\n/**\n * Format a Date to a display string based on scale level\n */\nexport function formatDateForScale(date: Date, scale: GanttScaleLevel): string {\n switch (scale) {\n case \"year\":\n return `${date.getFullYear()}`;\n case \"quarter\":\n return `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}`;\n case \"month\":\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n case \"week\":\n case \"day\":\n return formatDate(date);\n case \"halfday\":\n case \"hour\":\n return `${formatDate(date)} ${String(date.getHours()).padStart(2, \"0\")}:00`;\n }\n}\n\n/**\n * Check if a given date is a weekend (Saturday or Sunday)\n */\nexport function isWeekend(date: Date): boolean {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\n/**\n * Check if a date is a non-working day based on the holiday calendar.\n * Priority: custom function > entries > weekends\n */\nexport function isNonWorkingDay(\n date: Date,\n calendar?: HolidayCalendar,\n): boolean {\n if (!calendar) return isWeekend(date);\n\n // Custom function takes priority\n if (calendar.isNonWorkingDay) {\n return calendar.isNonWorkingDay(date);\n }\n\n const dateStr = formatDate(date);\n\n // Check entries\n if (calendar.entries && calendar.entries.length > 0) {\n const entry = calendar.entries.find((e) => e.date === dateStr);\n if (entry) {\n // If it's a compensatory workday, it's a working day\n return !entry.isWorkday;\n }\n }\n\n // Fall back to weekend check\n if (calendar.weekendsOff !== false) {\n return isWeekend(date);\n }\n\n return false;\n}\n\n/**\n * Calculate the number of working days between two dates (inclusive of both start and end).\n */\nexport function calculateWorkingDays(\n startDate: Date,\n endDate: Date,\n calendar?: HolidayCalendar,\n): number {\n let count = 0;\n const current = new Date(startDate);\n current.setHours(0, 0, 0, 0);\n const end = new Date(endDate);\n end.setHours(0, 0, 0, 0);\n\n while (current <= end) {\n if (!isNonWorkingDay(current, calendar)) {\n count++;\n }\n current.setDate(current.getDate() + 1);\n }\n\n return count;\n}\n\n/**\n * Compute the end date from a start date and N working days.\n * The returned date is the day AFTER the last working day (open interval end).\n */\nexport function addWorkingDays(\n startDate: Date,\n workingDays: number,\n calendar?: HolidayCalendar,\n): Date {\n if (workingDays <= 0) return new Date(startDate);\n const current = new Date(startDate);\n current.setHours(0, 0, 0, 0);\n let remaining = workingDays;\n\n while (remaining > 0) {\n const isNonWorking = isNonWorkingDay(current, calendar);\n current.setDate(current.getDate() + 1);\n if (!isNonWorking) {\n remaining--;\n }\n }\n\n return current;\n}\n\n/**\n * Get the number of calendar days between two dates\n */\nexport function daysBetween(start: Date, end: Date): number {\n const s = new Date(start);\n s.setHours(0, 0, 0, 0);\n const e = new Date(end);\n e.setHours(0, 0, 0, 0);\n return Math.round((e.getTime() - s.getTime()) / (24 * 60 * 60 * 1000));\n}\n\n/**\n * Add calendar days to a date\n */\nexport function addDays(date: Date, days: number): Date {\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n\n/**\n * Get the start of a day (midnight)\n */\nexport function startOfDay(date: Date): Date {\n const d = new Date(date);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\n/**\n * Get the start of a month\n */\nexport function startOfMonth(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), 1);\n}\n\n/**\n * Get the start of a year\n */\nexport function startOfYear(date: Date): Date {\n return new Date(date.getFullYear(), 0, 1);\n}\n\n/**\n * Get the start of a quarter\n */\nexport function startOfQuarter(date: Date): Date {\n const q = Math.floor(date.getMonth() / 3);\n return new Date(date.getFullYear(), q * 3, 1);\n}\n\n/**\n * Get the start of a week (Monday)\n */\nexport function startOfWeek(date: Date): Date {\n const d = new Date(date);\n const day = d.getDay();\n const diff = (day === 0 ? -6 : 1) - day; // Monday = 1\n d.setDate(d.getDate() + diff);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\n/**\n * Check if two dates are the same calendar day\n */\nexport function isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/**\n * Get the ISO 8601 week number. The week containing January 4 is week 1.\n * Weeks start on Monday.\n */\nexport function getISOWeekNumber(date: Date): number {\n const d = new Date(\n Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),\n );\n // Set to nearest Thursday: current date + 4 - current day number (Monday = 1, Sunday = 7)\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n // Get first day of year\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n // Calculate full weeks to nearest Thursday\n const weekNo = Math.ceil(\n ((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7,\n );\n return weekNo;\n}\n\n/**\n * Get the ISO week-numbering year. This may differ from the calendar year\n * for dates near the start/end of a year.\n */\nexport function getISOWeekYear(date: Date): number {\n const d = new Date(\n Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),\n );\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n return d.getUTCFullYear();\n}\n\n// ─── Timeline Computation ─────────────────────────────────────────\n\n/**\n * Compute the date range needed to display all data in the Gantt chart,\n * with some padding.\n */\nexport function computeDateRange(\n data: GanttNode[],\n calendar?: HolidayCalendar,\n paddingDays: number = 14,\n): { start: Date; end: Date } {\n let minDate: Date | null = null;\n let maxDate: Date | null = null;\n\n function traverse(nodes: GanttNode[]) {\n for (const node of nodes) {\n const s = parseDate(node.startDate);\n const e = parseDate(node.endDate);\n\n if (s) {\n if (!minDate || s < minDate) minDate = new Date(s);\n if (!maxDate || s > maxDate) maxDate = new Date(s);\n }\n if (e) {\n if (!minDate || e < minDate) minDate = new Date(e);\n if (!maxDate || e > maxDate) maxDate = new Date(e);\n }\n\n // If we have startDate + workingDays but no endDate, compute end\n if (s && node.workingDays && !e) {\n const computed = addWorkingDays(s, node.workingDays, calendar);\n if (!maxDate || computed > maxDate) maxDate = new Date(computed);\n }\n\n if (node.children) traverse(node.children);\n }\n }\n\n traverse(data);\n\n // Default to ±30 days from today if no dates found\n const today = startOfDay(new Date());\n if (!minDate) minDate = addDays(today, -30);\n if (!maxDate) maxDate = addDays(today, 30);\n\n // Extend range to include today if data exists but today is outside\n if (minDate && today < minDate) minDate = new Date(today);\n if (maxDate && today > maxDate) maxDate = new Date(today);\n\n return {\n start: addDays(minDate, -paddingDays),\n end: addDays(maxDate, paddingDays),\n };\n}\n\n/**\n * Generate an array of dates between start and end (inclusive)\n */\nexport function generateDateRange(start: Date, end: Date): Date[] {\n const dates: Date[] = [];\n const current = startOfDay(new Date(start));\n const endDay = startOfDay(new Date(end));\n\n while (current <= endDay) {\n dates.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n\n return dates;\n}\n\n/**\n * Generate header groups for the timeline (top row: months/years, bottom row: days/hours)\n */\nexport interface TimelineHeaderGroup {\n label: string;\n span: number; // number of cells this group spans\n date: Date;\n}\n\nexport function generateHeaderGroups(\n dates: Date[],\n scale: GanttScaleLevel,\n): TimelineHeaderGroup[] {\n const groups: TimelineHeaderGroup[] = [];\n if (dates.length === 0) return groups;\n\n let currentLabel = \"\";\n let currentSpan = 0;\n let currentDate = dates[0];\n\n for (const date of dates) {\n let label: string;\n\n switch (scale) {\n case \"year\":\n label = `${date.getFullYear()}`;\n break;\n case \"quarter\":\n label = `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}`;\n break;\n case \"week\": {\n const wk = getISOWeekNumber(date);\n const wy = getISOWeekYear(date);\n const mon = date.getMonth() + 1;\n label = `${wy}-W${String(wk).padStart(2, \"0\")} (${mon}月)`;\n break;\n }\n case \"month\":\n case \"day\":\n label = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n break;\n case \"halfday\":\n case \"hour\":\n label = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}-${String(date.getDate()).padStart(2, \"0\")}`;\n break;\n default:\n label = \"\";\n }\n\n if (label === currentLabel) {\n currentSpan++;\n } else {\n if (currentLabel) {\n groups.push({\n label: currentLabel,\n span: currentSpan,\n date: currentDate,\n });\n }\n currentLabel = label;\n currentSpan = 1;\n currentDate = date;\n }\n }\n\n if (currentLabel) {\n groups.push({ label: currentLabel, span: currentSpan, date: currentDate });\n }\n\n return groups;\n}\n\n// ─── Tree Flattening ──────────────────────────────────────────────\n\n/**\n * Flatten the hierarchical GanttNode tree into a list of FlatGanttNode,\n * respecting expanded/collapsed state.\n */\nexport function flattenTree(\n data: GanttNode[],\n expandedIds: Set<GanttNodeId>,\n defaultExpandAll: boolean,\n dateRange: { start: Date; end: Date },\n scaleConfig: GanttScaleConfig,\n categoryConfigs: Record<string, GanttCategoryConfig>,\n calendar?: HolidayCalendar,\n globalTimeWindow?: TimeWindow,\n): FlatGanttNode[] {\n const result: FlatGanttNode[] = [];\n const timelineStart = startOfDay(dateRange.start);\n let visibleIndex = 0;\n\n function traverse(nodes: GanttNode[], depth: number) {\n for (const node of nodes) {\n const hasChildren = !!(node.children && node.children.length > 0);\n const expanded = defaultExpandAll\n ? !expandedIds.has(node.id) // In defaultExpandAll mode, expandedIds is the set of COLLAPSED nodes\n : expandedIds.has(node.id);\n\n // Resolve category config\n const catConfig = {\n ...DEFAULT_CATEGORY_CONFIG,\n ...categoryConfigs[\"default\"],\n ...(node.category && categoryConfigs[node.category]\n ? categoryConfigs[node.category]\n : {}),\n };\n\n // Resolve dates\n const startDate = parseDate(node.startDate);\n let endDate = parseDate(node.endDate);\n\n // If workingDays is set and no endDate, compute endDate\n if (startDate && node.workingDays && !endDate) {\n if (catConfig.skipNonWorkingDays) {\n endDate = addWorkingDays(startDate, node.workingDays, calendar);\n } else {\n endDate = addDays(startDate, node.workingDays);\n }\n }\n\n // Calculate bar position\n let barLeft = 0;\n let barWidth = 0;\n const isRenderable = node.renderable !== false && !!startDate;\n\n if (isRenderable && startDate) {\n const end = endDate || addDays(startDate, 1);\n const daysFromStart = daysBetween(timelineStart, startDate);\n const durationDays = Math.max(daysBetween(startDate, end), 1);\n\n barLeft =\n daysFromStart * scaleConfig.cellWidth * scaleConfig.slotsPerDay;\n barWidth =\n durationDays * scaleConfig.cellWidth * scaleConfig.slotsPerDay;\n }\n\n const flatNode: FlatGanttNode = {\n node,\n depth,\n expanded,\n hasChildren,\n barLeft,\n barWidth,\n resolvedStartDate: startDate,\n resolvedEndDate: endDate,\n isRenderable,\n categoryConfig: catConfig,\n visibleIndex: visibleIndex++,\n };\n\n result.push(flatNode);\n\n // Recurse into expanded children\n if (hasChildren && expanded) {\n traverse(node.children!, depth + 1);\n }\n }\n }\n\n traverse(data, 0);\n return result;\n}\n\n// ─── Coordinate Helpers ───────────────────────────────────────────\n\n/**\n * Convert a pixel x-position on the timeline to a Date\n */\nexport function xToDate(\n x: number,\n timelineStart: Date,\n scaleConfig: GanttScaleConfig,\n): Date {\n const days = x / (scaleConfig.cellWidth * scaleConfig.slotsPerDay);\n return addDays(timelineStart, Math.floor(days));\n}\n\n/**\n * Convert a Date to a pixel x-position on the timeline\n */\nexport function dateToX(\n date: Date,\n timelineStart: Date,\n scaleConfig: GanttScaleConfig,\n): number {\n const days = daysBetween(timelineStart, date);\n return days * scaleConfig.cellWidth * scaleConfig.slotsPerDay;\n}\n\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","names":["DEFAULT_SCALE_CONFIGS","DEFAULT_CATEGORY_CONFIG","DEFAULT_TIME_WINDOW","parseDate","value","str","d","y","m","formatDate","date","isWeekend","day","isNonWorkingDay","calendar","dateStr","entry","calculateWorkingDays","count","current","startDate","end","endDate","addWorkingDays","workingDays","remaining","isNonWorking","daysBetween","s","start","e","addDays","result","days","startOfDay","isSameDay","a","b","getISOWeekNumber","dayNum","yearStart","getISOWeekYear","computeDateRange","minDate","maxDate","traverse","node","nodes","computed","data","today","paddingDays","generateDateRange","dates","endDay","generateHeaderGroups","groups","currentLabel","currentSpan","currentDate","label","scale","wk","wy","mon","flattenTree","timelineStart","dateRange","visibleIndex","hasChildren","expanded","defaultExpandAll","expandedIds","catConfig","categoryConfigs","\"default\"","barLeft","barWidth","isRenderable","daysFromStart","durationDays","scaleConfig","flatNode","depth","xToDate","x","dateToX"],"sources":["../../../../src/components/pro/Gantt/utils.ts"],"sourcesContent":["/**\n * DishUI Gantt Chart - Utility Functions\n *\n * Core utilities for date math, working day calculations,\n * and coordinate conversions in the Gantt timeline.\n */\n\nimport type {\n GanttNode,\n HolidayCalendar,\n TimeWindow,\n GanttScaleLevel,\n GanttScaleConfig,\n GanttCategoryConfig,\n FlatGanttNode,\n GanttNodeId,\n} from \"./types\";\n\n// ─── Default Scale Configurations ─────────────────────────────────\n\nexport const DEFAULT_SCALE_CONFIGS: Record<GanttScaleLevel, GanttScaleConfig> =\n {\n year: { label: \"Year\", cellWidth: 4, slotsPerDay: 1 },\n quarter: { label: \"Quarter\", cellWidth: 8, slotsPerDay: 1 },\n month: { label: \"Month\", cellWidth: 16, slotsPerDay: 1 },\n week: { label: \"Week\", cellWidth: 24, slotsPerDay: 1 },\n day: { label: \"Day\", cellWidth: 40, slotsPerDay: 1 },\n halfday: { label: \"Half Day\", cellWidth: 40, slotsPerDay: 2 },\n hour: { label: \"Hour\", cellWidth: 30, slotsPerDay: 24 },\n };\n\nexport const DEFAULT_CATEGORY_CONFIG: GanttCategoryConfig = {\n color: \"#3b82f6\",\n backgroundColor: \"#3b82f6\",\n barHeight: 0.6,\n borderRadius: 4,\n showProgress: false,\n skipNonWorkingDays: false,\n draggable: undefined, // inherit from global\n resizable: undefined,\n renderStyle: \"bar\",\n};\n\nexport const DEFAULT_TIME_WINDOW: TimeWindow = {\n startHour: 0,\n endHour: 24,\n};\n\n// ─── Date Utilities ───────────────────────────────────────────────\n\n/**\n * Parse a date value (string or Date) into a Date object.\n * Handles ISO 8601 strings, YYYY-MM-DD strings, and Date objects.\n */\nexport function parseDate(\n value: string | Date | undefined | null,\n): Date | null {\n if (!value) return null;\n if (value instanceof Date) return isNaN(value.getTime()) ? null : value;\n\n const str = String(value);\n\n // ISO format with time/timezone\n if (str.includes(\"T\") || str.includes(\"+\") || str.includes(\"Z\")) {\n const d = new Date(str);\n return isNaN(d.getTime()) ? null : d;\n }\n\n // YYYY-MM-DD format → create in local timezone\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(str)) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n }\n\n const d = new Date(str);\n return isNaN(d.getTime()) ? null : d;\n}\n\n/**\n * Format a Date to YYYY-MM-DD string in local timezone\n */\nexport function formatDate(date: Date): string {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, \"0\");\n const d = String(date.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${d}`;\n}\n\n/**\n * Format a Date to a display string based on scale level\n */\nexport function formatDateForScale(date: Date, scale: GanttScaleLevel): string {\n switch (scale) {\n case \"year\":\n return `${date.getFullYear()}`;\n case \"quarter\":\n return `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}`;\n case \"month\":\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n case \"week\":\n case \"day\":\n return formatDate(date);\n case \"halfday\":\n case \"hour\":\n return `${formatDate(date)} ${String(date.getHours()).padStart(2, \"0\")}:00`;\n }\n}\n\n/**\n * Check if a given date is a weekend (Saturday or Sunday)\n */\nexport function isWeekend(date: Date): boolean {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\n/**\n * Check if a date is a non-working day based on the holiday calendar.\n * Priority: custom function > entries > weekends\n */\nexport function isNonWorkingDay(\n date: Date,\n calendar?: HolidayCalendar,\n): boolean {\n if (!calendar) return isWeekend(date);\n\n // Custom function takes priority\n if (calendar.isNonWorkingDay) {\n return calendar.isNonWorkingDay(date);\n }\n\n const dateStr = formatDate(date);\n\n // Check entries\n if (calendar.entries && calendar.entries.length > 0) {\n const entry = calendar.entries.find((e) => e.date === dateStr);\n if (entry) {\n // If it's a compensatory workday, it's a working day\n return !entry.isWorkday;\n }\n }\n\n // Fall back to weekend check\n if (calendar.weekendsOff !== false) {\n return isWeekend(date);\n }\n\n return false;\n}\n\n/**\n * Calculate the number of working days between two dates (inclusive of both start and end).\n */\nexport function calculateWorkingDays(\n startDate: Date,\n endDate: Date,\n calendar?: HolidayCalendar,\n): number {\n let count = 0;\n const current = new Date(startDate);\n current.setHours(0, 0, 0, 0);\n const end = new Date(endDate);\n end.setHours(0, 0, 0, 0);\n\n while (current <= end) {\n if (!isNonWorkingDay(current, calendar)) {\n count++;\n }\n current.setDate(current.getDate() + 1);\n }\n\n return count;\n}\n\n/**\n * Compute the end date from a start date and N working days.\n * The returned date is the day AFTER the last working day (open interval end).\n */\nexport function addWorkingDays(\n startDate: Date,\n workingDays: number,\n calendar?: HolidayCalendar,\n): Date {\n if (workingDays <= 0) return new Date(startDate);\n const current = new Date(startDate);\n current.setHours(0, 0, 0, 0);\n let remaining = workingDays;\n\n while (remaining > 0) {\n const isNonWorking = isNonWorkingDay(current, calendar);\n current.setDate(current.getDate() + 1);\n if (!isNonWorking) {\n remaining--;\n }\n }\n\n return current;\n}\n\n/**\n * Get the number of calendar days between two dates\n */\nexport function daysBetween(start: Date, end: Date): number {\n const s = new Date(start);\n s.setHours(0, 0, 0, 0);\n const e = new Date(end);\n e.setHours(0, 0, 0, 0);\n return Math.round((e.getTime() - s.getTime()) / (24 * 60 * 60 * 1000));\n}\n\n/**\n * Add calendar days to a date\n */\nexport function addDays(date: Date, days: number): Date {\n const result = new Date(date);\n result.setDate(result.getDate() + days);\n return result;\n}\n\n/**\n * Get the start of a day (midnight)\n */\nexport function startOfDay(date: Date): Date {\n const d = new Date(date);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\n/**\n * Get the start of a month\n */\nexport function startOfMonth(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), 1);\n}\n\n/**\n * Get the start of a year\n */\nexport function startOfYear(date: Date): Date {\n return new Date(date.getFullYear(), 0, 1);\n}\n\n/**\n * Get the start of a quarter\n */\nexport function startOfQuarter(date: Date): Date {\n const q = Math.floor(date.getMonth() / 3);\n return new Date(date.getFullYear(), q * 3, 1);\n}\n\n/**\n * Get the start of a week (Monday)\n */\nexport function startOfWeek(date: Date): Date {\n const d = new Date(date);\n const day = d.getDay();\n const diff = (day === 0 ? -6 : 1) - day; // Monday = 1\n d.setDate(d.getDate() + diff);\n d.setHours(0, 0, 0, 0);\n return d;\n}\n\n/**\n * Check if two dates are the same calendar day\n */\nexport function isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/**\n * Get the ISO 8601 week number. The week containing January 4 is week 1.\n * Weeks start on Monday.\n */\nexport function getISOWeekNumber(date: Date): number {\n const d = new Date(\n Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),\n );\n // Set to nearest Thursday: current date + 4 - current day number (Monday = 1, Sunday = 7)\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n // Get first day of year\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n // Calculate full weeks to nearest Thursday\n const weekNo = Math.ceil(\n ((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7,\n );\n return weekNo;\n}\n\n/**\n * Get the ISO week-numbering year. This may differ from the calendar year\n * for dates near the start/end of a year.\n */\nexport function getISOWeekYear(date: Date): number {\n const d = new Date(\n Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),\n );\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n return d.getUTCFullYear();\n}\n\n// ─── Timeline Computation ─────────────────────────────────────────\n\n/**\n * Compute the date range needed to display all data in the Gantt chart,\n * with some padding.\n */\nexport function computeDateRange(\n data: GanttNode[],\n calendar?: HolidayCalendar,\n paddingDays: number = 14,\n): { start: Date; end: Date } {\n let minDate: Date | null = null;\n let maxDate: Date | null = null;\n\n function traverse(nodes: GanttNode[]) {\n for (const node of nodes) {\n const s = parseDate(node.startDate);\n const e = parseDate(node.endDate);\n\n if (s) {\n if (!minDate || s < minDate) minDate = new Date(s);\n if (!maxDate || s > maxDate) maxDate = new Date(s);\n }\n if (e) {\n if (!minDate || e < minDate) minDate = new Date(e);\n if (!maxDate || e > maxDate) maxDate = new Date(e);\n }\n\n // If we have startDate + workingDays but no endDate, compute end\n if (s && node.workingDays && !e) {\n const computed = addWorkingDays(s, node.workingDays, calendar);\n if (!maxDate || computed > maxDate) maxDate = new Date(computed);\n }\n\n if (node.children) traverse(node.children);\n }\n }\n\n traverse(data);\n\n // Default to ±30 days from today if no dates found\n const today = startOfDay(new Date());\n if (!minDate) minDate = addDays(today, -30);\n if (!maxDate) maxDate = addDays(today, 30);\n\n // Extend range to include today if data exists but today is outside\n if (minDate && today < minDate) minDate = new Date(today);\n if (maxDate && today > maxDate) maxDate = new Date(today);\n\n return {\n start: addDays(minDate, -paddingDays),\n end: addDays(maxDate, paddingDays),\n };\n}\n\n/**\n * Generate an array of dates between start and end (inclusive)\n */\nexport function generateDateRange(start: Date, end: Date): Date[] {\n const dates: Date[] = [];\n const current = startOfDay(new Date(start));\n const endDay = startOfDay(new Date(end));\n\n while (current <= endDay) {\n dates.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n\n return dates;\n}\n\n/**\n * Generate header groups for the timeline (top row: months/years, bottom row: days/hours)\n */\nexport interface TimelineHeaderGroup {\n label: string;\n span: number; // number of cells this group spans\n date: Date;\n}\n\nexport function generateHeaderGroups(\n dates: Date[],\n scale: GanttScaleLevel,\n): TimelineHeaderGroup[] {\n const groups: TimelineHeaderGroup[] = [];\n if (dates.length === 0) return groups;\n\n let currentLabel = \"\";\n let currentSpan = 0;\n let currentDate = dates[0];\n\n for (const date of dates) {\n let label: string;\n\n switch (scale) {\n case \"year\":\n label = `${date.getFullYear()}`;\n break;\n case \"quarter\":\n label = `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}`;\n break;\n case \"week\": {\n const wk = getISOWeekNumber(date);\n const wy = getISOWeekYear(date);\n const mon = date.getMonth() + 1;\n label = `${wy}-W${String(wk).padStart(2, \"0\")} (${mon}月)`;\n break;\n }\n case \"month\":\n case \"day\":\n label = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n break;\n case \"halfday\":\n case \"hour\":\n label = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}-${String(date.getDate()).padStart(2, \"0\")}`;\n break;\n default:\n label = \"\";\n }\n\n if (label === currentLabel) {\n currentSpan++;\n } else {\n if (currentLabel) {\n groups.push({\n label: currentLabel,\n span: currentSpan,\n date: currentDate,\n });\n }\n currentLabel = label;\n currentSpan = 1;\n currentDate = date;\n }\n }\n\n if (currentLabel) {\n groups.push({ label: currentLabel, span: currentSpan, date: currentDate });\n }\n\n return groups;\n}\n\n// ─── Tree Flattening ──────────────────────────────────────────────\n\n/**\n * Flatten the hierarchical GanttNode tree into a list of FlatGanttNode,\n * respecting expanded/collapsed state.\n */\nexport function flattenTree(\n data: GanttNode[],\n expandedIds: Set<GanttNodeId>,\n defaultExpandAll: boolean,\n dateRange: { start: Date; end: Date },\n scaleConfig: GanttScaleConfig,\n categoryConfigs: Record<string, GanttCategoryConfig>,\n calendar?: HolidayCalendar,\n globalTimeWindow?: TimeWindow,\n): FlatGanttNode[] {\n const result: FlatGanttNode[] = [];\n const timelineStart = startOfDay(dateRange.start);\n let visibleIndex = 0;\n\n function traverse(nodes: GanttNode[], depth: number) {\n for (const node of nodes) {\n const hasChildren = !!(node.children && node.children.length > 0);\n const expanded = defaultExpandAll\n ? !expandedIds.has(node.id) // In defaultExpandAll mode, expandedIds is the set of COLLAPSED nodes\n : expandedIds.has(node.id);\n\n // Resolve category config\n const catConfig = {\n ...DEFAULT_CATEGORY_CONFIG,\n ...categoryConfigs[\"default\"],\n ...(node.category && categoryConfigs[node.category]\n ? categoryConfigs[node.category]\n : {}),\n };\n\n // Resolve dates\n const startDate = parseDate(node.startDate);\n let endDate = parseDate(node.endDate);\n\n // If workingDays is set and no endDate, compute endDate\n if (startDate && node.workingDays && !endDate) {\n if (catConfig.skipNonWorkingDays) {\n endDate = addWorkingDays(startDate, node.workingDays, calendar);\n } else {\n endDate = addDays(startDate, node.workingDays);\n }\n }\n\n // Calculate bar position\n let barLeft = 0;\n let barWidth = 0;\n const isRenderable = node.renderable !== false && !!startDate;\n\n if (isRenderable && startDate) {\n const end = endDate || addDays(startDate, 1);\n const daysFromStart = daysBetween(timelineStart, startDate);\n const durationDays = Math.max(daysBetween(startDate, end), 1);\n\n barLeft =\n daysFromStart * scaleConfig.cellWidth * scaleConfig.slotsPerDay;\n barWidth =\n durationDays * scaleConfig.cellWidth * scaleConfig.slotsPerDay;\n }\n\n const flatNode: FlatGanttNode = {\n node,\n depth,\n expanded,\n hasChildren,\n barLeft,\n barWidth,\n resolvedStartDate: startDate,\n resolvedEndDate: endDate,\n isRenderable,\n categoryConfig: catConfig,\n visibleIndex: visibleIndex++,\n };\n\n result.push(flatNode);\n\n // Recurse into expanded children\n if (hasChildren && expanded) {\n traverse(node.children!, depth + 1);\n }\n }\n }\n\n traverse(data, 0);\n return result;\n}\n\n// ─── Coordinate Helpers ───────────────────────────────────────────\n\n/**\n * Convert a pixel x-position on the timeline to a Date\n */\nexport function xToDate(\n x: number,\n timelineStart: Date,\n scaleConfig: GanttScaleConfig,\n): Date {\n const days = x / (scaleConfig.cellWidth * scaleConfig.slotsPerDay);\n return addDays(timelineStart, Math.floor(days));\n}\n\n/**\n * Convert a Date to a pixel x-position on the timeline\n */\nexport function dateToX(\n date: Date,\n timelineStart: Date,\n scaleConfig: GanttScaleConfig,\n): number {\n const days = daysBetween(timelineStart, date);\n return days * scaleConfig.cellWidth * scaleConfig.slotsPerDay;\n}\n\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Kanban.js","names":[],"sources":["../../../../src/components/pro/Kanban/Kanban.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport Card from \"../../Card\";\nimport Swimlanes from \"./Swimlanes\";\nimport type {\n KanbanCard,\n KanbanColumn,\n KanbanDragTarget,\n KanbanId,\n KanbanLane,\n KanbanLabels,\n KanbanLocation,\n KanbanProps,\n} from \"./types\";\nimport { useKanbanDrag } from \"./useKanbanDrag\";\nimport { cardsAt, createCardMove, getCardLocation, idText, idsEqual, locationEquals } from \"./utils\";\nimport \"./styles.css\";\n\nconst DEFAULT_LABELS: Required<KanbanLabels> = {\n loading: \"Loading board\",\n empty: \"No cards\",\n error: \"Could not load the board.\",\n stale: \"Outdated data\",\n retry: \"Try again\",\n unnamedColumn: \"Untitled column\",\n unnamedLane: \"Untitled lane\",\n card: \"card\",\n lift: \"Lifted\",\n move: \"Move with the arrow keys.\",\n drop: \"Dropped\",\n cancel: \"Move cancelled\",\n};\n\nconst DefaultTicket = Card.Ticket;\n\nfunction cssSize(value: number | string | undefined): string | undefined {\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nfunction resolveId(value: KanbanId | undefined, items: readonly { id: KanbanId }[]): KanbanId | undefined {\n if (value === undefined) return undefined;\n return items.find(item => String(item.id) === String(value))?.id ?? value;\n}\n\nfunction displayText(value: React.ReactNode, fallback: string): string {\n return typeof value === \"string\" || typeof value === \"number\" ? String(value) : fallback;\n}\n\nfunction renderDefaultCard(card: KanbanCard) {\n return (\n <DefaultTicket\n issueKey={card.issueKey ?? card.id}\n title={card.title}\n description={card.description}\n status={card.status}\n issueType={card.issueType}\n assignees={card.assignees}\n priority={card.priority}\n labels={card.labels}\n dueDate={card.dueDate}\n estimate={card.estimate}\n subtaskProgress={card.subtaskProgress}\n disabled={card.disabled}\n />\n );\n}\n\nexport default function Kanban({\n columns,\n lanes,\n cards,\n onCardMove,\n renderCard,\n renderColumnHeader,\n renderLaneHeader,\n readOnly = false,\n loading = false,\n error,\n stale = false,\n empty,\n onRetry,\n labels: labelsInput,\n dragThreshold = 5,\n columnWidth = 280,\n height,\n collapsedLaneIds,\n defaultCollapsedLaneIds,\n onCollapsedLaneIdsChange,\n className = \"\",\n style,\n ...rest\n}: KanbanProps) {\n const labels = useMemo(() => ({ ...DEFAULT_LABELS, ...labelsInput }), [labelsInput]);\n const [keyboardCardId, setKeyboardCardId] = useState<KanbanId | null>(null);\n const [keyboardTarget, setKeyboardTarget] = useState<KanbanLocation | null>(null);\n const [announcement, setAnnouncement] = useState(\"\");\n const keyboardCardRef = useRef<HTMLElement | null>(null);\n\n const commitMove = useCallback((cardId: KanbanId, rawTarget: KanbanDragTarget) => {\n const target: KanbanLocation = {\n columnId: resolveId(rawTarget.columnId, columns) as KanbanId,\n laneId: lanes ? resolveId(rawTarget.laneId, lanes) : undefined,\n index: rawTarget.index,\n };\n const move = createCardMove(cards, cardId, target);\n if (!move || locationEquals(move.from, move.to)) return;\n onCardMove?.(move);\n }, [cards, columns, lanes, onCardMove]);\n\n const drag = useKanbanDrag({\n threshold: dragThreshold,\n disabled: readOnly || !onCardMove,\n onDrop: commitMove,\n });\n\n const activeCardId = drag.draggingId ?? keyboardCardId;\n const activeTarget = drag.target ?? keyboardTarget;\n\n const cancelKeyboard = useCallback((announce = true) => {\n if (keyboardCardId === null) return;\n setKeyboardCardId(null);\n setKeyboardTarget(null);\n if (announce) setAnnouncement(labels.cancel);\n requestAnimationFrame(() => keyboardCardRef.current?.focus());\n }, [keyboardCardId, labels.cancel]);\n\n useEffect(() => {\n const onBlur = () => cancelKeyboard(false);\n window.addEventListener(\"blur\", onBlur);\n return () => window.removeEventListener(\"blur\", onBlur);\n }, [cancelKeyboard]);\n\n const describeLocation = useCallback((target: KanbanLocation) => {\n const column = columns.find(item => idsEqual(item.id, target.columnId));\n const lane = lanes?.find(item => idsEqual(item.id, target.laneId));\n const columnName = displayText(column?.title, labels.unnamedColumn);\n const laneName = lane ? `, ${displayText(lane.title, labels.unnamedLane)}` : \"\";\n return `${columnName}${laneName}, position ${target.index + 1}`;\n }, [columns, lanes, labels.unnamedColumn, labels.unnamedLane]);\n\n const moveKeyboardTarget = useCallback((key: string) => {\n if (keyboardCardId === null || !keyboardTarget) return;\n const columnIndex = Math.max(0, columns.findIndex(column => idsEqual(column.id, keyboardTarget.columnId)));\n const laneIndex = lanes ? Math.max(0, lanes.findIndex(lane => idsEqual(lane.id, keyboardTarget.laneId))) : 0;\n let nextColumnIndex = columnIndex;\n let nextLaneIndex = laneIndex;\n let nextIndex = keyboardTarget.index;\n\n if (key === \"ArrowLeft\") nextColumnIndex = Math.max(0, columnIndex - 1);\n if (key === \"ArrowRight\") nextColumnIndex = Math.min(columns.length - 1, columnIndex + 1);\n if (key === \"ArrowUp\") {\n if (nextIndex > 0) nextIndex -= 1;\n else if (lanes && laneIndex > 0) nextLaneIndex -= 1;\n }\n if (key === \"ArrowDown\") {\n const count = cardsAt(cards.filter(card => !idsEqual(card.id, keyboardCardId)), keyboardTarget.columnId, keyboardTarget.laneId).length;\n if (nextIndex < count) nextIndex += 1;\n else if (lanes && laneIndex < lanes.length - 1) nextLaneIndex += 1;\n }\n\n const columnId = columns[nextColumnIndex]?.id ?? keyboardTarget.columnId;\n const laneId = lanes?.[nextLaneIndex]?.id;\n if (nextColumnIndex !== columnIndex || nextLaneIndex !== laneIndex) {\n const targetCount = cardsAt(cards.filter(card => !idsEqual(card.id, keyboardCardId)), columnId, laneId).length;\n nextIndex = Math.min(nextIndex, targetCount);\n }\n const next = { columnId, laneId, index: nextIndex };\n setKeyboardTarget(next);\n setAnnouncement(describeLocation(next));\n }, [cards, columns, describeLocation, keyboardCardId, keyboardTarget, lanes]);\n\n const onCardKeyDown = useCallback((event: React.KeyboardEvent<HTMLElement>, card: KanbanCard) => {\n if (event.target !== event.currentTarget || card.disabled || readOnly || !onCardMove) return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n cancelKeyboard();\n return;\n }\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n if (event.repeat) return;\n if (keyboardCardId === null) {\n const from = getCardLocation(cards, card.id);\n if (!from) return;\n keyboardCardRef.current = event.currentTarget;\n setKeyboardCardId(card.id);\n setKeyboardTarget(from);\n setAnnouncement(`${labels.lift} ${displayText(card.title, labels.card)}. ${labels.move}`);\n } else if (idsEqual(keyboardCardId, card.id) && keyboardTarget) {\n commitMove(card.id, keyboardTarget);\n setKeyboardCardId(null);\n setKeyboardTarget(null);\n setAnnouncement(`${labels.drop} ${displayText(card.title, labels.card)}. ${describeLocation(keyboardTarget)}.`);\n requestAnimationFrame(() => keyboardCardRef.current?.focus());\n }\n return;\n }\n if (keyboardCardId !== null && [\"ArrowLeft\", \"ArrowRight\", \"ArrowUp\", \"ArrowDown\"].includes(event.key)) {\n event.preventDefault();\n moveKeyboardTarget(event.key);\n }\n }, [cancelKeyboard, cards, commitMove, describeLocation, keyboardCardId, keyboardTarget, labels, moveKeyboardTarget, onCardMove, readOnly]);\n\n\n const renderCell = (column: KanbanColumn, lane?: KanbanLane) => {\n const cellCards = cardsAt(cards, column.id, lane?.id);\n const disabledCell = readOnly || !!column.disabled || !!lane?.disabled || !onCardMove;\n let insertionIndex = 0;\n return (\n <div\n className=\"dishui-kanban__column\"\n key={`${idText(lane?.id)}:${idText(column.id)}`}\n role=\"group\"\n aria-label={displayText(column.title, labels.unnamedColumn)}\n data-column-id={idText(column.id)}\n data-lane-id={idText(lane?.id)}\n data-disabled={disabledCell || undefined}\n >\n {!lanes && (\n <div className=\"dishui-kanban__column-header\">\n {renderColumnHeader ? renderColumnHeader(column, cellCards) : (\n <><span>{column.title}</span><span className=\"dishui-kanban__count\">{cellCards.length}</span></>\n )}\n </div>\n )}\n <div className=\"dishui-kanban__cards\">\n {cellCards.length === 0 && activeCardId === null && <span className=\"dishui-kanban__cell-empty\">{labels.empty}</span>}\n <DropIndicator columnId={column.id} laneId={lane?.id} index={0} active={locationEquals(activeTarget, { columnId: column.id, laneId: lane?.id, index: 0 })} />\n {cellCards.map(card => {\n const isActive = activeCardId !== null && idsEqual(activeCardId, card.id);\n const cardIndex = insertionIndex;\n if (!isActive) insertionIndex += 1;\n const cardDisabled = disabledCell || !!card.disabled;\n return (\n <React.Fragment key={String(card.id)}>\n <div\n className=\"dishui-kanban__card\"\n role=\"button\"\n tabIndex={cardDisabled ? -1 : 0}\n aria-disabled={cardDisabled}\n aria-describedby=\"dishui-kanban-instructions\"\n data-kanban-disabled={cardDisabled || undefined}\n data-dragging={isActive || undefined}\n onPointerDown={event => drag.onPointerDown(event, card.id)}\n onPointerMove={drag.onPointerMove}\n onPointerUp={drag.onPointerUp}\n onPointerCancel={drag.onPointerCancel}\n onLostPointerCapture={drag.onLostPointerCapture}\n onKeyDown={event => onCardKeyDown(event, card)}\n >\n {renderCard ? renderCard(card, { dragging: isActive, keyboardDragging: idsEqual(keyboardCardId ?? undefined, card.id), disabled: cardDisabled }) : renderDefaultCard(card)}\n </div>\n {!isActive && (\n <DropIndicator\n columnId={column.id}\n laneId={lane?.id}\n index={cardIndex + 1}\n active={locationEquals(activeTarget, { columnId: column.id, laneId: lane?.id, index: cardIndex + 1 })}\n />\n )}\n </React.Fragment>\n );\n })}\n </div>\n </div>\n );\n };\n\n const boardStyle = {\n ...style,\n height: cssSize(height) ?? style?.height,\n \"--dishui-kanban-column-width\": cssSize(columnWidth),\n } as React.CSSProperties;\n\n return (\n <div {...rest} className={`dishui-kanban ${className}`.trim()} style={boardStyle} aria-busy={loading || undefined}>\n <span id=\"dishui-kanban-instructions\" className=\"dishui-kanban__sr-only\">\n Press Space or Enter to lift and drop. Use arrow keys to choose a destination. Press Escape to cancel.\n </span>\n <div className=\"dishui-kanban__sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">{announcement}</div>\n\n {stale && <div className=\"dishui-kanban__stale\" role=\"status\">{labels.stale}</div>}\n {loading ? (\n <div className=\"dishui-kanban__state\" role=\"status\">\n <span>{labels.loading}</span>\n <div className=\"dishui-kanban__skeletons\" aria-hidden=\"true\"><i /><i /><i /></div>\n </div>\n ) : error ? (\n <div className=\"dishui-kanban__state dishui-kanban__state--error\" role=\"alert\">\n <strong>{labels.error}</strong><span>{error}</span>\n {onRetry && <button type=\"button\" onClick={onRetry}>{labels.retry}</button>}\n </div>\n ) : columns.length === 0 || cards.length === 0 ? (\n <div className=\"dishui-kanban__state dishui-kanban__state--empty\">{empty ?? labels.empty}</div>\n ) : (\n <div className=\"dishui-kanban__scroll\" data-dragging={activeCardId !== null || undefined}>\n {lanes && lanes.length > 0 && (\n <div className=\"dishui-kanban__column-headers\" style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(var(--dishui-kanban-column-width), 1fr))` }}>\n {columns.map(column => {\n const columnCards = cards.filter(card => idsEqual(card.columnId, column.id));\n return <div className=\"dishui-kanban__column-header\" key={String(column.id)}>{renderColumnHeader ? renderColumnHeader(column, columnCards) : <><span>{column.title}</span><span className=\"dishui-kanban__count\">{columnCards.length}</span></>}</div>;\n })}\n </div>\n )}\n {lanes && lanes.length > 0 ? (\n <Swimlanes\n lanes={lanes}\n collapsedLaneIds={collapsedLaneIds}\n defaultCollapsedLaneIds={defaultCollapsedLaneIds}\n onCollapsedLaneIdsChange={onCollapsedLaneIdsChange}\n renderLaneHeader={(lane, context) => {\n const laneCards = cards.filter(card => idsEqual(card.laneId, lane.id));\n return (\n <button className=\"dishui-swimlane__toggle\" type=\"button\" aria-expanded={!context.collapsed} onClick={context.toggle}>\n <span className=\"dishui-swimlane__chevron\" aria-hidden=\"true\">▾</span>\n <span className=\"dishui-swimlane__header-content\">{renderLaneHeader ? renderLaneHeader(lane, laneCards) : lane.title}</span>\n <span className=\"dishui-kanban__count\">{laneCards.length}</span>\n </button>\n );\n }}\n >\n {({ lane }) => <div className=\"dishui-kanban__grid\" style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(var(--dishui-kanban-column-width), 1fr))` }}>{columns.map(column => renderCell(column, lane))}</div>}\n </Swimlanes>\n ) : (\n <div className=\"dishui-kanban__grid\" style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(var(--dishui-kanban-column-width), 1fr))` }}>{columns.map(column => renderCell(column))}</div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction DropIndicator({ columnId, laneId, index, active }: KanbanLocation & { active: boolean }) {\n return (\n <div\n className=\"dishui-kanban__drop-zone\"\n data-kanban-drop=\"true\"\n data-column-id={String(columnId)}\n data-lane-id={laneId === undefined ? \"\" : String(laneId)}\n data-index={index}\n data-active={active || undefined}\n aria-hidden=\"true\"\n ><span /></div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Kanban.js","names":["Card","_Fragment","CardWithCompounds","Swimlanes","React","DEFAULT_LABELS","DefaultTicket","cssSize","value","resolveId","items","item","displayText","fallback","renderDefaultCard","card","Kanban","labelsInput","rest","labels","useMemo","keyboardCardId","setKeyboardCardId","useState","keyboardTarget","setKeyboardTarget","announcement","setAnnouncement","keyboardCardRef","useRef","commitMove","useCallback","target","rawTarget","columns","lanes","move","createCardMove","cards","cardId","onCardMove","drag","useKanbanDrag","dragThreshold","readOnly","activeCardId","activeTarget","cancelKeyboard","announce","onBlur","describeLocation","column","idsEqual","lane","moveKeyboardTarget","columnIndex","laneIndex","nextColumnIndex","nextLaneIndex","nextIndex","key","count","cardsAt","columnId","laneId","targetCount","next","onCardKeyDown","event","from","getCardLocation","renderCell","cellCards","disabledCell","insertionIndex","idText","renderColumnHeader","Fragment","DropIndicator","locationEquals","isActive","cardIndex","cardDisabled","renderCard","boardStyle","style","height","columnWidth","className","loading","stale","error","onRetry","empty","columnCards","laneCards","context","renderLaneHeader","index","active"],"sources":["../../../../src/components/pro/Kanban/Kanban.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport Card from \"../../Card\";\nimport Swimlanes from \"./Swimlanes\";\nimport type {\n KanbanCard,\n KanbanColumn,\n KanbanDragTarget,\n KanbanId,\n KanbanLane,\n KanbanLabels,\n KanbanLocation,\n KanbanProps,\n} from \"./types\";\nimport { useKanbanDrag } from \"./useKanbanDrag\";\nimport { cardsAt, createCardMove, getCardLocation, idText, idsEqual, locationEquals } from \"./utils\";\nimport \"./styles.css\";\n\nconst DEFAULT_LABELS: Required<KanbanLabels> = {\n loading: \"Loading board\",\n empty: \"No cards\",\n error: \"Could not load the board.\",\n stale: \"Outdated data\",\n retry: \"Try again\",\n unnamedColumn: \"Untitled column\",\n unnamedLane: \"Untitled lane\",\n card: \"card\",\n lift: \"Lifted\",\n move: \"Move with the arrow keys.\",\n drop: \"Dropped\",\n cancel: \"Move cancelled\",\n};\n\nconst DefaultTicket = Card.Ticket;\n\nfunction cssSize(value: number | string | undefined): string | undefined {\n return typeof value === \"number\" ? `${value}px` : value;\n}\n\nfunction resolveId(value: KanbanId | undefined, items: readonly { id: KanbanId }[]): KanbanId | undefined {\n if (value === undefined) return undefined;\n return items.find(item => String(item.id) === String(value))?.id ?? value;\n}\n\nfunction displayText(value: React.ReactNode, fallback: string): string {\n return typeof value === \"string\" || typeof value === \"number\" ? String(value) : fallback;\n}\n\nfunction renderDefaultCard(card: KanbanCard) {\n return (\n <DefaultTicket\n issueKey={card.issueKey ?? card.id}\n title={card.title}\n description={card.description}\n status={card.status}\n issueType={card.issueType}\n assignees={card.assignees}\n priority={card.priority}\n labels={card.labels}\n dueDate={card.dueDate}\n estimate={card.estimate}\n subtaskProgress={card.subtaskProgress}\n disabled={card.disabled}\n />\n );\n}\n\nexport default function Kanban({\n columns,\n lanes,\n cards,\n onCardMove,\n renderCard,\n renderColumnHeader,\n renderLaneHeader,\n readOnly = false,\n loading = false,\n error,\n stale = false,\n empty,\n onRetry,\n labels: labelsInput,\n dragThreshold = 5,\n columnWidth = 280,\n height,\n collapsedLaneIds,\n defaultCollapsedLaneIds,\n onCollapsedLaneIdsChange,\n className = \"\",\n style,\n ...rest\n}: KanbanProps) {\n const labels = useMemo(() => ({ ...DEFAULT_LABELS, ...labelsInput }), [labelsInput]);\n const [keyboardCardId, setKeyboardCardId] = useState<KanbanId | null>(null);\n const [keyboardTarget, setKeyboardTarget] = useState<KanbanLocation | null>(null);\n const [announcement, setAnnouncement] = useState(\"\");\n const keyboardCardRef = useRef<HTMLElement | null>(null);\n\n const commitMove = useCallback((cardId: KanbanId, rawTarget: KanbanDragTarget) => {\n const target: KanbanLocation = {\n columnId: resolveId(rawTarget.columnId, columns) as KanbanId,\n laneId: lanes ? resolveId(rawTarget.laneId, lanes) : undefined,\n index: rawTarget.index,\n };\n const move = createCardMove(cards, cardId, target);\n if (!move || locationEquals(move.from, move.to)) return;\n onCardMove?.(move);\n }, [cards, columns, lanes, onCardMove]);\n\n const drag = useKanbanDrag({\n threshold: dragThreshold,\n disabled: readOnly || !onCardMove,\n onDrop: commitMove,\n });\n\n const activeCardId = drag.draggingId ?? keyboardCardId;\n const activeTarget = drag.target ?? keyboardTarget;\n\n const cancelKeyboard = useCallback((announce = true) => {\n if (keyboardCardId === null) return;\n setKeyboardCardId(null);\n setKeyboardTarget(null);\n if (announce) setAnnouncement(labels.cancel);\n requestAnimationFrame(() => keyboardCardRef.current?.focus());\n }, [keyboardCardId, labels.cancel]);\n\n useEffect(() => {\n const onBlur = () => cancelKeyboard(false);\n window.addEventListener(\"blur\", onBlur);\n return () => window.removeEventListener(\"blur\", onBlur);\n }, [cancelKeyboard]);\n\n const describeLocation = useCallback((target: KanbanLocation) => {\n const column = columns.find(item => idsEqual(item.id, target.columnId));\n const lane = lanes?.find(item => idsEqual(item.id, target.laneId));\n const columnName = displayText(column?.title, labels.unnamedColumn);\n const laneName = lane ? `, ${displayText(lane.title, labels.unnamedLane)}` : \"\";\n return `${columnName}${laneName}, position ${target.index + 1}`;\n }, [columns, lanes, labels.unnamedColumn, labels.unnamedLane]);\n\n const moveKeyboardTarget = useCallback((key: string) => {\n if (keyboardCardId === null || !keyboardTarget) return;\n const columnIndex = Math.max(0, columns.findIndex(column => idsEqual(column.id, keyboardTarget.columnId)));\n const laneIndex = lanes ? Math.max(0, lanes.findIndex(lane => idsEqual(lane.id, keyboardTarget.laneId))) : 0;\n let nextColumnIndex = columnIndex;\n let nextLaneIndex = laneIndex;\n let nextIndex = keyboardTarget.index;\n\n if (key === \"ArrowLeft\") nextColumnIndex = Math.max(0, columnIndex - 1);\n if (key === \"ArrowRight\") nextColumnIndex = Math.min(columns.length - 1, columnIndex + 1);\n if (key === \"ArrowUp\") {\n if (nextIndex > 0) nextIndex -= 1;\n else if (lanes && laneIndex > 0) nextLaneIndex -= 1;\n }\n if (key === \"ArrowDown\") {\n const count = cardsAt(cards.filter(card => !idsEqual(card.id, keyboardCardId)), keyboardTarget.columnId, keyboardTarget.laneId).length;\n if (nextIndex < count) nextIndex += 1;\n else if (lanes && laneIndex < lanes.length - 1) nextLaneIndex += 1;\n }\n\n const columnId = columns[nextColumnIndex]?.id ?? keyboardTarget.columnId;\n const laneId = lanes?.[nextLaneIndex]?.id;\n if (nextColumnIndex !== columnIndex || nextLaneIndex !== laneIndex) {\n const targetCount = cardsAt(cards.filter(card => !idsEqual(card.id, keyboardCardId)), columnId, laneId).length;\n nextIndex = Math.min(nextIndex, targetCount);\n }\n const next = { columnId, laneId, index: nextIndex };\n setKeyboardTarget(next);\n setAnnouncement(describeLocation(next));\n }, [cards, columns, describeLocation, keyboardCardId, keyboardTarget, lanes]);\n\n const onCardKeyDown = useCallback((event: React.KeyboardEvent<HTMLElement>, card: KanbanCard) => {\n if (event.target !== event.currentTarget || card.disabled || readOnly || !onCardMove) return;\n if (event.key === \"Escape\") {\n event.preventDefault();\n cancelKeyboard();\n return;\n }\n if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n if (event.repeat) return;\n if (keyboardCardId === null) {\n const from = getCardLocation(cards, card.id);\n if (!from) return;\n keyboardCardRef.current = event.currentTarget;\n setKeyboardCardId(card.id);\n setKeyboardTarget(from);\n setAnnouncement(`${labels.lift} ${displayText(card.title, labels.card)}. ${labels.move}`);\n } else if (idsEqual(keyboardCardId, card.id) && keyboardTarget) {\n commitMove(card.id, keyboardTarget);\n setKeyboardCardId(null);\n setKeyboardTarget(null);\n setAnnouncement(`${labels.drop} ${displayText(card.title, labels.card)}. ${describeLocation(keyboardTarget)}.`);\n requestAnimationFrame(() => keyboardCardRef.current?.focus());\n }\n return;\n }\n if (keyboardCardId !== null && [\"ArrowLeft\", \"ArrowRight\", \"ArrowUp\", \"ArrowDown\"].includes(event.key)) {\n event.preventDefault();\n moveKeyboardTarget(event.key);\n }\n }, [cancelKeyboard, cards, commitMove, describeLocation, keyboardCardId, keyboardTarget, labels, moveKeyboardTarget, onCardMove, readOnly]);\n\n\n const renderCell = (column: KanbanColumn, lane?: KanbanLane) => {\n const cellCards = cardsAt(cards, column.id, lane?.id);\n const disabledCell = readOnly || !!column.disabled || !!lane?.disabled || !onCardMove;\n let insertionIndex = 0;\n return (\n <div\n className=\"dishui-kanban__column\"\n key={`${idText(lane?.id)}:${idText(column.id)}`}\n role=\"group\"\n aria-label={displayText(column.title, labels.unnamedColumn)}\n data-column-id={idText(column.id)}\n data-lane-id={idText(lane?.id)}\n data-disabled={disabledCell || undefined}\n >\n {!lanes && (\n <div className=\"dishui-kanban__column-header\">\n {renderColumnHeader ? renderColumnHeader(column, cellCards) : (\n <><span>{column.title}</span><span className=\"dishui-kanban__count\">{cellCards.length}</span></>\n )}\n </div>\n )}\n <div className=\"dishui-kanban__cards\">\n {cellCards.length === 0 && activeCardId === null && <span className=\"dishui-kanban__cell-empty\">{labels.empty}</span>}\n <DropIndicator columnId={column.id} laneId={lane?.id} index={0} active={locationEquals(activeTarget, { columnId: column.id, laneId: lane?.id, index: 0 })} />\n {cellCards.map(card => {\n const isActive = activeCardId !== null && idsEqual(activeCardId, card.id);\n const cardIndex = insertionIndex;\n if (!isActive) insertionIndex += 1;\n const cardDisabled = disabledCell || !!card.disabled;\n return (\n <React.Fragment key={String(card.id)}>\n <div\n className=\"dishui-kanban__card\"\n role=\"button\"\n tabIndex={cardDisabled ? -1 : 0}\n aria-disabled={cardDisabled}\n aria-describedby=\"dishui-kanban-instructions\"\n data-kanban-disabled={cardDisabled || undefined}\n data-dragging={isActive || undefined}\n onPointerDown={event => drag.onPointerDown(event, card.id)}\n onPointerMove={drag.onPointerMove}\n onPointerUp={drag.onPointerUp}\n onPointerCancel={drag.onPointerCancel}\n onLostPointerCapture={drag.onLostPointerCapture}\n onKeyDown={event => onCardKeyDown(event, card)}\n >\n {renderCard ? renderCard(card, { dragging: isActive, keyboardDragging: idsEqual(keyboardCardId ?? undefined, card.id), disabled: cardDisabled }) : renderDefaultCard(card)}\n </div>\n {!isActive && (\n <DropIndicator\n columnId={column.id}\n laneId={lane?.id}\n index={cardIndex + 1}\n active={locationEquals(activeTarget, { columnId: column.id, laneId: lane?.id, index: cardIndex + 1 })}\n />\n )}\n </React.Fragment>\n );\n })}\n </div>\n </div>\n );\n };\n\n const boardStyle = {\n ...style,\n height: cssSize(height) ?? style?.height,\n \"--dishui-kanban-column-width\": cssSize(columnWidth),\n } as React.CSSProperties;\n\n return (\n <div {...rest} className={`dishui-kanban ${className}`.trim()} style={boardStyle} aria-busy={loading || undefined}>\n <span id=\"dishui-kanban-instructions\" className=\"dishui-kanban__sr-only\">\n Press Space or Enter to lift and drop. Use arrow keys to choose a destination. Press Escape to cancel.\n </span>\n <div className=\"dishui-kanban__sr-only\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">{announcement}</div>\n\n {stale && <div className=\"dishui-kanban__stale\" role=\"status\">{labels.stale}</div>}\n {loading ? (\n <div className=\"dishui-kanban__state\" role=\"status\">\n <span>{labels.loading}</span>\n <div className=\"dishui-kanban__skeletons\" aria-hidden=\"true\"><i /><i /><i /></div>\n </div>\n ) : error ? (\n <div className=\"dishui-kanban__state dishui-kanban__state--error\" role=\"alert\">\n <strong>{labels.error}</strong><span>{error}</span>\n {onRetry && <button type=\"button\" onClick={onRetry}>{labels.retry}</button>}\n </div>\n ) : columns.length === 0 || cards.length === 0 ? (\n <div className=\"dishui-kanban__state dishui-kanban__state--empty\">{empty ?? labels.empty}</div>\n ) : (\n <div className=\"dishui-kanban__scroll\" data-dragging={activeCardId !== null || undefined}>\n {lanes && lanes.length > 0 && (\n <div className=\"dishui-kanban__column-headers\" style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(var(--dishui-kanban-column-width), 1fr))` }}>\n {columns.map(column => {\n const columnCards = cards.filter(card => idsEqual(card.columnId, column.id));\n return <div className=\"dishui-kanban__column-header\" key={String(column.id)}>{renderColumnHeader ? renderColumnHeader(column, columnCards) : <><span>{column.title}</span><span className=\"dishui-kanban__count\">{columnCards.length}</span></>}</div>;\n })}\n </div>\n )}\n {lanes && lanes.length > 0 ? (\n <Swimlanes\n lanes={lanes}\n collapsedLaneIds={collapsedLaneIds}\n defaultCollapsedLaneIds={defaultCollapsedLaneIds}\n onCollapsedLaneIdsChange={onCollapsedLaneIdsChange}\n renderLaneHeader={(lane, context) => {\n const laneCards = cards.filter(card => idsEqual(card.laneId, lane.id));\n return (\n <button className=\"dishui-swimlane__toggle\" type=\"button\" aria-expanded={!context.collapsed} onClick={context.toggle}>\n <span className=\"dishui-swimlane__chevron\" aria-hidden=\"true\">▾</span>\n <span className=\"dishui-swimlane__header-content\">{renderLaneHeader ? renderLaneHeader(lane, laneCards) : lane.title}</span>\n <span className=\"dishui-kanban__count\">{laneCards.length}</span>\n </button>\n );\n }}\n >\n {({ lane }) => <div className=\"dishui-kanban__grid\" style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(var(--dishui-kanban-column-width), 1fr))` }}>{columns.map(column => renderCell(column, lane))}</div>}\n </Swimlanes>\n ) : (\n <div className=\"dishui-kanban__grid\" style={{ gridTemplateColumns: `repeat(${columns.length}, minmax(var(--dishui-kanban-column-width), 1fr))` }}>{columns.map(column => renderCell(column))}</div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nfunction DropIndicator({ columnId, laneId, index, active }: KanbanLocation & { active: boolean }) {\n return (\n <div\n className=\"dishui-kanban__drop-zone\"\n data-kanban-drop=\"true\"\n data-column-id={String(columnId)}\n data-lane-id={laneId === undefined ? \"\" : String(laneId)}\n data-index={index}\n data-active={active || undefined}\n aria-hidden=\"true\"\n ><span /></div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Swimlanes.js","names":[],"sources":["../../../../src/components/pro/Kanban/Swimlanes.tsx"],"sourcesContent":["import React, { useCallback, useState } from \"react\";\nimport type { KanbanId, KanbanLane, SwimlanesProps } from \"./types\";\nimport { idsEqual } from \"./utils\";\nimport \"./styles.css\";\n\nconst EMPTY_IDS: KanbanId[] = [];\n\nexport default function Swimlanes<TLane extends KanbanLane = KanbanLane>({\n lanes,\n children,\n renderLaneHeader,\n collapsedLaneIds,\n defaultCollapsedLaneIds = EMPTY_IDS,\n onCollapsedLaneIdsChange,\n collapsible = true,\n empty = \"No lanes\",\n className = \"\",\n laneClassName = \"\",\n ...rest\n}: SwimlanesProps<TLane>) {\n const controlled = collapsedLaneIds !== undefined;\n const [internalIds, setInternalIds] = useState<KanbanId[]>(defaultCollapsedLaneIds);\n const sourceIds = controlled ? collapsedLaneIds : internalIds;\n const collapsedIds = sourceIds.filter(id => lanes.some(lane => idsEqual(lane.id, id)));\n\n const toggleLane = useCallback((id: KanbanId) => {\n const next = collapsedIds.some(item => idsEqual(item, id))\n ? collapsedIds.filter(item => !idsEqual(item, id))\n : [...collapsedIds, id];\n if (!controlled) setInternalIds(next);\n onCollapsedLaneIdsChange?.(next);\n }, [collapsedIds, controlled, onCollapsedLaneIdsChange]);\n\n return (\n <div {...rest} className={`dishui-swimlanes ${className}`.trim()}>\n {lanes.length === 0 ? <div className=\"dishui-swimlanes__empty\">{empty}</div> : lanes.map(lane => {\n const collapsed = collapsedIds.some(id => idsEqual(id, lane.id));\n const context = { lane, collapsed, toggle: () => toggleLane(lane.id) };\n return (\n <section\n className={`dishui-swimlane ${laneClassName}`.trim()}\n key={String(lane.id)}\n data-lane-id={String(lane.id)}\n data-collapsed={collapsed || undefined}\n >\n <header className=\"dishui-swimlane__header\">\n {renderLaneHeader ? renderLaneHeader(lane, context) : (\n <button\n className=\"dishui-swimlane__toggle\"\n type=\"button\"\n disabled={!collapsible}\n aria-expanded={!collapsed}\n aria-controls={`dishui-swimlane-${String(lane.id)}`}\n onClick={context.toggle}\n >\n <span className=\"dishui-swimlane__chevron\" aria-hidden=\"true\">▾</span>\n <span>{lane.title}</span>\n </button>\n )}\n </header>\n <div id={`dishui-swimlane-${String(lane.id)}`} className=\"dishui-swimlane__content\" hidden={collapsed}>\n {typeof children === \"function\" ? children(context) : children}\n </div>\n </section>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AAKA,
|
|
1
|
+
{"version":3,"file":"Swimlanes.js","names":["EMPTY_IDS","Swimlanes","rest","controlled","collapsedLaneIds","internalIds","setInternalIds","useState","defaultCollapsedLaneIds","collapsedIds","lanes","idsEqual","lane","id","toggleLane","useCallback","next","item","onCollapsedLaneIdsChange","className","empty","collapsed","context","laneClassName","renderLaneHeader","collapsible","children"],"sources":["../../../../src/components/pro/Kanban/Swimlanes.tsx"],"sourcesContent":["import React, { useCallback, useState } from \"react\";\nimport type { KanbanId, KanbanLane, SwimlanesProps } from \"./types\";\nimport { idsEqual } from \"./utils\";\nimport \"./styles.css\";\n\nconst EMPTY_IDS: KanbanId[] = [];\n\nexport default function Swimlanes<TLane extends KanbanLane = KanbanLane>({\n lanes,\n children,\n renderLaneHeader,\n collapsedLaneIds,\n defaultCollapsedLaneIds = EMPTY_IDS,\n onCollapsedLaneIdsChange,\n collapsible = true,\n empty = \"No lanes\",\n className = \"\",\n laneClassName = \"\",\n ...rest\n}: SwimlanesProps<TLane>) {\n const controlled = collapsedLaneIds !== undefined;\n const [internalIds, setInternalIds] = useState<KanbanId[]>(defaultCollapsedLaneIds);\n const sourceIds = controlled ? collapsedLaneIds : internalIds;\n const collapsedIds = sourceIds.filter(id => lanes.some(lane => idsEqual(lane.id, id)));\n\n const toggleLane = useCallback((id: KanbanId) => {\n const next = collapsedIds.some(item => idsEqual(item, id))\n ? collapsedIds.filter(item => !idsEqual(item, id))\n : [...collapsedIds, id];\n if (!controlled) setInternalIds(next);\n onCollapsedLaneIdsChange?.(next);\n }, [collapsedIds, controlled, onCollapsedLaneIdsChange]);\n\n return (\n <div {...rest} className={`dishui-swimlanes ${className}`.trim()}>\n {lanes.length === 0 ? <div className=\"dishui-swimlanes__empty\">{empty}</div> : lanes.map(lane => {\n const collapsed = collapsedIds.some(id => idsEqual(id, lane.id));\n const context = { lane, collapsed, toggle: () => toggleLane(lane.id) };\n return (\n <section\n className={`dishui-swimlane ${laneClassName}`.trim()}\n key={String(lane.id)}\n data-lane-id={String(lane.id)}\n data-collapsed={collapsed || undefined}\n >\n <header className=\"dishui-swimlane__header\">\n {renderLaneHeader ? renderLaneHeader(lane, context) : (\n <button\n className=\"dishui-swimlane__toggle\"\n type=\"button\"\n disabled={!collapsible}\n aria-expanded={!collapsed}\n aria-controls={`dishui-swimlane-${String(lane.id)}`}\n onClick={context.toggle}\n >\n <span className=\"dishui-swimlane__chevron\" aria-hidden=\"true\">▾</span>\n <span>{lane.title}</span>\n </button>\n )}\n </header>\n <div id={`dishui-swimlane-${String(lane.id)}`} className=\"dishui-swimlane__content\" hidden={collapsed}>\n {typeof children === \"function\" ? children(context) : children}\n </div>\n </section>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AAKA,IAAMA,IAAwB,CAAC;AAE/B,SAAwBC,EAAiD,EACvE,UACA,aACA,qBACA,qBACA,6BAA0BD,GAC1B,6BACA,iBAAc,IACd,WAAQ,YACR,eAAY,IACZ,mBAAgB,IAChB,GAAGE,KACqB;CACxB,IAAMC,IAAaC,MAAqB,KAAA,GAClC,CAACC,GAAaC,KAAkBC,EAAqBC,CAAuB,GAE5EC,KADYN,IAAaC,IAAmBC,EAAA,CACnB,QAAO,MAAMK,EAAM,MAAK,MAAQC,EAASC,EAAK,IAAIC,CAAE,CAAC,CAAC,GAE/EC,IAAaC,GAAa,MAAiB;EAC/C,IAAMC,IAAOP,EAAa,MAAK,MAAQE,EAASM,GAAMJ,CAAE,CAAC,IACrDJ,EAAa,QAAO,MAAQ,CAACE,EAASM,GAAMJ,CAAE,CAAC,IAC/C,CAAC,GAAGJ,GAAcI,CAAE;EAExB,AADKV,KAAYG,EAAeU,CAAI,GACpCE,IAA2BF,CAAI;CACjC,GAAG;EAACP;EAAcN;EAAYe;CAAwB,CAAC;CAEvD,OACE,kBAAC,OAAD;EAAK,GAAIhB;EAAM,WAAW,oBAAoBiB,IAAY,KAAK;EAC5D,UAAAT,EAAM,WAAW,IAAI,kBAAC,OAAD;GAAK,WAAU;GAA2B,UAAAU;EAAW,CAAA,IAAIV,EAAM,KAAI,MAAQ;GAC/F,IAAMW,IAAYZ,EAAa,MAAK,MAAME,EAASE,GAAID,EAAK,EAAE,CAAC,GACzDU,IAAU;IAAE;IAAM;IAAW,cAAcR,EAAWF,EAAK,EAAE;GAAE;GACrE,OACE,kBAAC,WAAD;IACE,WAAW,mBAAmBW,IAAgB,KAAK;IAEnD,gBAAc,OAAOX,EAAK,EAAE;IAC5B,kBAAgBS,KAAa,KAAA;IAJ/B,UAAA,CAME,kBAAC,UAAD;KAAQ,WAAU;KACf,UAAAG,IAAmBA,EAAiBZ,GAAMU,CAAO,IAChD,kBAAC,UAAD;MACE,WAAU;MACV,MAAK;MACL,UAAU,CAACG;MACX,iBAAe,CAACJ;MAChB,iBAAe,mBAAmB,OAAOT,EAAK,EAAE;MAChD,SAASU,EAAQ;MANnB,UAAA,CAQE,kBAAC,QAAD;OAAM,WAAU;OAA2B,eAAY;OAAO,UAAA;MAAO,CAAA,GACrE,kBAAC,QAAD,EAAA,UAAOV,EAAK,MAAY,CAAA,CAClB;;IAEJ,CAAA,GACR,kBAAC,OAAD;KAAK,IAAI,mBAAmB,OAAOA,EAAK,EAAE;KAAK,WAAU;KAA2B,QAAQS;KACzF,UAAA,OAAOK,KAAa,aAAaA,EAASJ,CAAO,IAAII;IACnD,CAAA,CACE;GAtBF,GAAA,OAAOd,EAAK,EAAE,CAsBZ;EAEb,CAAC;CACE,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useKanbanDrag.js","names":[],"sources":["../../../../src/components/pro/Kanban/useKanbanDrag.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type React from \"react\";\nimport type { KanbanDragTarget, KanbanId } from \"./types\";\n\nexport interface UseKanbanDragOptions {\n threshold?: number;\n disabled?: boolean;\n onDrop: (cardId: KanbanId, target: KanbanDragTarget) => void;\n}\n\ntype PendingDrag = {\n cardId: KanbanId;\n pointerId: number;\n startX: number;\n startY: number;\n element: HTMLElement;\n};\n\nfunction targetFromPoint(x: number, y: number): KanbanDragTarget | null {\n const hit = document.elementFromPoint(x, y) as HTMLElement | null;\n const board = hit?.closest<HTMLElement>(\".dishui-kanban\");\n if (!board) return null;\n\n const direct = hit?.closest<HTMLElement>(\"[data-kanban-drop]\");\n let indicator = direct?.closest<HTMLElement>(\"[data-disabled='true']\") ? null : direct;\n if (!indicator) {\n let bestDistance = Number.POSITIVE_INFINITY;\n board.querySelectorAll<HTMLElement>(\"[data-kanban-drop]\").forEach(candidate => {\n if (candidate.closest(\"[data-disabled='true']\")) return;\n const rect = candidate.getBoundingClientRect();\n const dx = x < rect.left ? rect.left - x : x > rect.right ? x - rect.right : 0;\n const dy = Math.abs(y - (rect.top + rect.bottom) / 2);\n const distance = dx * dx + dy * dy;\n if (distance < bestDistance) {\n bestDistance = distance;\n indicator = candidate;\n }\n });\n }\n\n const columnId = indicator?.dataset.columnId;\n const laneId = indicator?.dataset.laneId;\n const index = Number(indicator?.dataset.index);\n if (columnId === undefined || !Number.isFinite(index)) return null;\n return { columnId, laneId: laneId || undefined, index };\n}\n\nexport function useKanbanDrag({ threshold = 5, disabled = false, onDrop }: UseKanbanDragOptions) {\n const [draggingId, setDraggingId] = useState<KanbanId | null>(null);\n const [target, setTarget] = useState<KanbanDragTarget | null>(null);\n const pendingRef = useRef<PendingDrag | null>(null);\n const activeRef = useRef(false);\n const targetRef = useRef<KanbanDragTarget | null>(null);\n\n const cleanup = useCallback(() => {\n const pending = pendingRef.current;\n pendingRef.current = null;\n activeRef.current = false;\n targetRef.current = null;\n setDraggingId(null);\n setTarget(null);\n if (pending?.element.hasPointerCapture(pending.pointerId)) {\n pending.element.releasePointerCapture(pending.pointerId);\n }\n }, []);\n\n const onPointerDown = useCallback((event: React.PointerEvent<HTMLElement>, cardId: KanbanId) => {\n if (disabled || event.button !== 0 || event.currentTarget.closest(\"[data-kanban-disabled='true']\")) return;\n const element = event.currentTarget;\n pendingRef.current = { cardId, pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, element };\n element.setPointerCapture(event.pointerId);\n }, [disabled]);\n\n const onPointerMove = useCallback((event: React.PointerEvent<HTMLElement>) => {\n const pending = pendingRef.current;\n if (!pending || pending.pointerId !== event.pointerId) return;\n const distance = Math.hypot(event.clientX - pending.startX, event.clientY - pending.startY);\n if (!activeRef.current && distance < Math.max(4, Math.min(6, threshold))) return;\n event.preventDefault();\n if (!activeRef.current) {\n activeRef.current = true;\n setDraggingId(pending.cardId);\n }\n const next = targetFromPoint(event.clientX, event.clientY);\n targetRef.current = next;\n setTarget(next);\n }, [threshold]);\n\n const onPointerUp = useCallback((event: React.PointerEvent<HTMLElement>) => {\n const pending = pendingRef.current;\n if (!pending || pending.pointerId !== event.pointerId) return;\n if (activeRef.current && targetRef.current) onDrop(pending.cardId, targetRef.current);\n cleanup();\n }, [cleanup, onDrop]);\n\n useEffect(() => {\n const cancel = () => cleanup();\n const onKey = (event: KeyboardEvent) => { if (event.key === \"Escape\") cleanup(); };\n window.addEventListener(\"blur\", cancel);\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"blur\", cancel);\n window.removeEventListener(\"keydown\", onKey);\n cleanup();\n };\n }, [cleanup]);\n\n return {\n draggingId,\n target,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel: cleanup,\n onLostPointerCapture: cleanup,\n cancelDrag: cleanup,\n };\n}\n"],"mappings":";;AAkBA,
|
|
1
|
+
{"version":3,"file":"useKanbanDrag.js","names":["targetFromPoint","hit","x","y","board","direct","indicator","bestDistance","candidate","rect","dx","dy","distance","columnId","laneId","index","useKanbanDrag","draggingId","setDraggingId","useState","target","setTarget","pendingRef","useRef","activeRef","targetRef","cleanup","useCallback","pending","onPointerDown","disabled","event","element","onPointerMove","threshold","next","onPointerUp","onDrop","useEffect","cancel","onKey"],"sources":["../../../../src/components/pro/Kanban/useKanbanDrag.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type React from \"react\";\nimport type { KanbanDragTarget, KanbanId } from \"./types\";\n\nexport interface UseKanbanDragOptions {\n threshold?: number;\n disabled?: boolean;\n onDrop: (cardId: KanbanId, target: KanbanDragTarget) => void;\n}\n\ntype PendingDrag = {\n cardId: KanbanId;\n pointerId: number;\n startX: number;\n startY: number;\n element: HTMLElement;\n};\n\nfunction targetFromPoint(x: number, y: number): KanbanDragTarget | null {\n const hit = document.elementFromPoint(x, y) as HTMLElement | null;\n const board = hit?.closest<HTMLElement>(\".dishui-kanban\");\n if (!board) return null;\n\n const direct = hit?.closest<HTMLElement>(\"[data-kanban-drop]\");\n let indicator = direct?.closest<HTMLElement>(\"[data-disabled='true']\") ? null : direct;\n if (!indicator) {\n let bestDistance = Number.POSITIVE_INFINITY;\n board.querySelectorAll<HTMLElement>(\"[data-kanban-drop]\").forEach(candidate => {\n if (candidate.closest(\"[data-disabled='true']\")) return;\n const rect = candidate.getBoundingClientRect();\n const dx = x < rect.left ? rect.left - x : x > rect.right ? x - rect.right : 0;\n const dy = Math.abs(y - (rect.top + rect.bottom) / 2);\n const distance = dx * dx + dy * dy;\n if (distance < bestDistance) {\n bestDistance = distance;\n indicator = candidate;\n }\n });\n }\n\n const columnId = indicator?.dataset.columnId;\n const laneId = indicator?.dataset.laneId;\n const index = Number(indicator?.dataset.index);\n if (columnId === undefined || !Number.isFinite(index)) return null;\n return { columnId, laneId: laneId || undefined, index };\n}\n\nexport function useKanbanDrag({ threshold = 5, disabled = false, onDrop }: UseKanbanDragOptions) {\n const [draggingId, setDraggingId] = useState<KanbanId | null>(null);\n const [target, setTarget] = useState<KanbanDragTarget | null>(null);\n const pendingRef = useRef<PendingDrag | null>(null);\n const activeRef = useRef(false);\n const targetRef = useRef<KanbanDragTarget | null>(null);\n\n const cleanup = useCallback(() => {\n const pending = pendingRef.current;\n pendingRef.current = null;\n activeRef.current = false;\n targetRef.current = null;\n setDraggingId(null);\n setTarget(null);\n if (pending?.element.hasPointerCapture(pending.pointerId)) {\n pending.element.releasePointerCapture(pending.pointerId);\n }\n }, []);\n\n const onPointerDown = useCallback((event: React.PointerEvent<HTMLElement>, cardId: KanbanId) => {\n if (disabled || event.button !== 0 || event.currentTarget.closest(\"[data-kanban-disabled='true']\")) return;\n const element = event.currentTarget;\n pendingRef.current = { cardId, pointerId: event.pointerId, startX: event.clientX, startY: event.clientY, element };\n element.setPointerCapture(event.pointerId);\n }, [disabled]);\n\n const onPointerMove = useCallback((event: React.PointerEvent<HTMLElement>) => {\n const pending = pendingRef.current;\n if (!pending || pending.pointerId !== event.pointerId) return;\n const distance = Math.hypot(event.clientX - pending.startX, event.clientY - pending.startY);\n if (!activeRef.current && distance < Math.max(4, Math.min(6, threshold))) return;\n event.preventDefault();\n if (!activeRef.current) {\n activeRef.current = true;\n setDraggingId(pending.cardId);\n }\n const next = targetFromPoint(event.clientX, event.clientY);\n targetRef.current = next;\n setTarget(next);\n }, [threshold]);\n\n const onPointerUp = useCallback((event: React.PointerEvent<HTMLElement>) => {\n const pending = pendingRef.current;\n if (!pending || pending.pointerId !== event.pointerId) return;\n if (activeRef.current && targetRef.current) onDrop(pending.cardId, targetRef.current);\n cleanup();\n }, [cleanup, onDrop]);\n\n useEffect(() => {\n const cancel = () => cleanup();\n const onKey = (event: KeyboardEvent) => { if (event.key === \"Escape\") cleanup(); };\n window.addEventListener(\"blur\", cancel);\n window.addEventListener(\"keydown\", onKey);\n return () => {\n window.removeEventListener(\"blur\", cancel);\n window.removeEventListener(\"keydown\", onKey);\n cleanup();\n };\n }, [cleanup]);\n\n return {\n draggingId,\n target,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel: cleanup,\n onLostPointerCapture: cleanup,\n cancelDrag: cleanup,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../../../src/components/pro/Kanban/utils.ts"],"sourcesContent":["import type { KanbanCard, KanbanCardMove, KanbanId, KanbanLocation } from \"./types\";\n\nexport function idsEqual(a: KanbanId | undefined, b: KanbanId | undefined): boolean {\n return a === b;\n}\n\nexport function cardsAt(\n cards: readonly KanbanCard[],\n columnId: KanbanId,\n laneId?: KanbanId,\n): KanbanCard[] {\n return cards.filter(card => idsEqual(card.columnId, columnId) && idsEqual(card.laneId, laneId));\n}\n\nexport function getCardLocation(cards: readonly KanbanCard[], cardId: KanbanId): KanbanLocation | null {\n const card = cards.find(item => idsEqual(item.id, cardId));\n if (!card) return null;\n return {\n columnId: card.columnId,\n laneId: card.laneId,\n index: cardsAt(cards, card.columnId, card.laneId).findIndex(item => idsEqual(item.id, cardId)),\n };\n}\n\n/**\n * Pure immutable card move. `to.index` is the insertion index in the target\n * cell after the moving card has been removed, which makes same-cell sorting\n * and cross-column/lane moves follow one rule.\n */\nexport function moveKanbanCard(\n cards: readonly KanbanCard[],\n cardId: KanbanId,\n to: KanbanLocation,\n): KanbanCard[] {\n const moving = cards.find(card => idsEqual(card.id, cardId));\n if (!moving) return [...cards];\n\n const without = cards.filter(card => !idsEqual(card.id, cardId));\n const targetCards = cardsAt(without, to.columnId, to.laneId);\n const index = Math.max(0, Math.min(to.index, targetCards.length));\n const nextCard: KanbanCard = { ...moving, columnId: to.columnId };\n const originalGlobalIndex = cards.findIndex(card => idsEqual(card.id, cardId));\n if (to.laneId === undefined) delete nextCard.laneId;\n else nextCard.laneId = to.laneId;\n\n if (index === targetCards.length) {\n const lastTarget = targetCards[targetCards.length - 1];\n const globalIndex = lastTarget\n ? without.findIndex(card => idsEqual(card.id, lastTarget.id)) + 1\n : Math.min(originalGlobalIndex, without.length);\n const result = [...without];\n result.splice(globalIndex, 0, nextCard);\n return result;\n }\n\n const beforeId = targetCards[index].id;\n const globalIndex = without.findIndex(card => idsEqual(card.id, beforeId));\n const result = [...without];\n result.splice(globalIndex, 0, nextCard);\n return result;\n}\n\nexport function createCardMove(\n cards: readonly KanbanCard[],\n cardId: KanbanId,\n to: KanbanLocation,\n): KanbanCardMove | null {\n const card = cards.find(item => idsEqual(item.id, cardId));\n const from = getCardLocation(cards, cardId);\n if (!card || !from) return null;\n return { card, from, to, cards: moveKanbanCard(cards, cardId, to) };\n}\n\nexport function locationEquals(a: KanbanLocation | null, b: KanbanLocation | null): boolean {\n return !!a && !!b && idsEqual(a.columnId, b.columnId) && idsEqual(a.laneId, b.laneId) && a.index === b.index;\n}\n\nexport function idText(id: KanbanId | undefined): string {\n return id === undefined ? \"\" : String(id);\n}\n"],"mappings":";AAEA,
|
|
1
|
+
{"version":3,"file":"utils.js","names":["idsEqual","a","b","cardsAt","cards","card","columnId","laneId","getCardLocation","item","cardId","moveKanbanCard","moving","without","targetCards","to","index","nextCard","originalGlobalIndex","lastTarget","globalIndex","result","beforeId","createCardMove","from","locationEquals","idText","id"],"sources":["../../../../src/components/pro/Kanban/utils.ts"],"sourcesContent":["import type { KanbanCard, KanbanCardMove, KanbanId, KanbanLocation } from \"./types\";\n\nexport function idsEqual(a: KanbanId | undefined, b: KanbanId | undefined): boolean {\n return a === b;\n}\n\nexport function cardsAt(\n cards: readonly KanbanCard[],\n columnId: KanbanId,\n laneId?: KanbanId,\n): KanbanCard[] {\n return cards.filter(card => idsEqual(card.columnId, columnId) && idsEqual(card.laneId, laneId));\n}\n\nexport function getCardLocation(cards: readonly KanbanCard[], cardId: KanbanId): KanbanLocation | null {\n const card = cards.find(item => idsEqual(item.id, cardId));\n if (!card) return null;\n return {\n columnId: card.columnId,\n laneId: card.laneId,\n index: cardsAt(cards, card.columnId, card.laneId).findIndex(item => idsEqual(item.id, cardId)),\n };\n}\n\n/**\n * Pure immutable card move. `to.index` is the insertion index in the target\n * cell after the moving card has been removed, which makes same-cell sorting\n * and cross-column/lane moves follow one rule.\n */\nexport function moveKanbanCard(\n cards: readonly KanbanCard[],\n cardId: KanbanId,\n to: KanbanLocation,\n): KanbanCard[] {\n const moving = cards.find(card => idsEqual(card.id, cardId));\n if (!moving) return [...cards];\n\n const without = cards.filter(card => !idsEqual(card.id, cardId));\n const targetCards = cardsAt(without, to.columnId, to.laneId);\n const index = Math.max(0, Math.min(to.index, targetCards.length));\n const nextCard: KanbanCard = { ...moving, columnId: to.columnId };\n const originalGlobalIndex = cards.findIndex(card => idsEqual(card.id, cardId));\n if (to.laneId === undefined) delete nextCard.laneId;\n else nextCard.laneId = to.laneId;\n\n if (index === targetCards.length) {\n const lastTarget = targetCards[targetCards.length - 1];\n const globalIndex = lastTarget\n ? without.findIndex(card => idsEqual(card.id, lastTarget.id)) + 1\n : Math.min(originalGlobalIndex, without.length);\n const result = [...without];\n result.splice(globalIndex, 0, nextCard);\n return result;\n }\n\n const beforeId = targetCards[index].id;\n const globalIndex = without.findIndex(card => idsEqual(card.id, beforeId));\n const result = [...without];\n result.splice(globalIndex, 0, nextCard);\n return result;\n}\n\nexport function createCardMove(\n cards: readonly KanbanCard[],\n cardId: KanbanId,\n to: KanbanLocation,\n): KanbanCardMove | null {\n const card = cards.find(item => idsEqual(item.id, cardId));\n const from = getCardLocation(cards, cardId);\n if (!card || !from) return null;\n return { card, from, to, cards: moveKanbanCard(cards, cardId, to) };\n}\n\nexport function locationEquals(a: KanbanLocation | null, b: KanbanLocation | null): boolean {\n return !!a && !!b && idsEqual(a.columnId, b.columnId) && idsEqual(a.laneId, b.laneId) && a.index === b.index;\n}\n\nexport function idText(id: KanbanId | undefined): string {\n return id === undefined ? \"\" : String(id);\n}\n"],"mappings":";AAEA,SAAgBA,EAAS,GAAyB,GAAkC;CAClF,OAAOC,MAAMC;AACf;AAEA,SAAgBC,EACd,GACA,GACA,GACc;CACd,OAAOC,EAAM,QAAO,MAAQJ,EAASK,EAAK,UAAUC,CAAQ,KAAKN,EAASK,EAAK,QAAQE,CAAM,CAAC;AAChG;AAEA,SAAgBC,EAAgB,GAA8B,GAAyC;CACrG,IAAMH,IAAOD,EAAM,MAAK,MAAQJ,EAASS,EAAK,IAAIC,CAAM,CAAC;CAEzD,OADKL,IACE;EACL,UAAUA,EAAK;EACf,QAAQA,EAAK;EACb,OAAOF,EAAQC,GAAOC,EAAK,UAAUA,EAAK,MAAM,CAAC,CAAC,WAAU,MAAQL,EAASS,EAAK,IAAIC,CAAM,CAAC;CAC/F,IALkB;AAMpB;AAOA,SAAgBC,EACd,GACA,GACA,GACc;CACd,IAAMC,IAASR,EAAM,MAAK,MAAQJ,EAASK,EAAK,IAAIK,CAAM,CAAC;CAC3D,IAAI,CAACE,GAAQ,OAAO,CAAC,GAAGR,CAAK;CAE7B,IAAMS,IAAUT,EAAM,QAAO,MAAQ,CAACJ,EAASK,EAAK,IAAIK,CAAM,CAAC,GACzDI,IAAcX,EAAQU,GAASE,EAAG,UAAUA,EAAG,MAAM,GACrDC,IAAQ,KAAK,IAAI,GAAG,KAAK,IAAID,EAAG,OAAOD,EAAY,MAAM,CAAC,GAC1DG,IAAuB;EAAE,GAAGL;EAAQ,UAAUG,EAAG;CAAS,GAC1DG,IAAsBd,EAAM,WAAU,MAAQJ,EAASK,EAAK,IAAIK,CAAM,CAAC;CAI7E,IAHIK,EAAG,WAAW,KAAA,IAAW,OAAOE,EAAS,SACxC,EAAS,SAASF,EAAG,QAEtBC,MAAUF,EAAY,QAAQ;EAChC,IAAMK,IAAaL,EAAYA,EAAY,SAAS,IAC9CM,IAAcD,IAChBN,EAAQ,WAAU,MAAQb,EAASK,EAAK,IAAIc,EAAW,EAAE,CAAC,IAAI,IAC9D,KAAK,IAAID,GAAqBL,EAAQ,MAAM,GAC1CQ,IAAS,CAAC,GAAGR,CAAO;EAE1B,OADAQ,EAAO,OAAOD,GAAa,GAAGH,CAAQ,GAC/BI;CACT;CAEA,IAAMC,IAAWR,EAAYE,EAAM,CAAC,IAC9BI,IAAcP,EAAQ,WAAU,MAAQb,EAASK,EAAK,IAAIiB,CAAQ,CAAC,GACnED,IAAS,CAAC,GAAGR,CAAO;CAE1B,OADAQ,EAAO,OAAOD,GAAa,GAAGH,CAAQ,GAC/BI;AACT;AAEA,SAAgBE,EACd,GACA,GACA,GACuB;CACvB,IAAMlB,IAAOD,EAAM,MAAK,MAAQJ,EAASS,EAAK,IAAIC,CAAM,CAAC,GACnDc,IAAOhB,EAAgBJ,GAAOM,CAAM;CAE1C,OADI,CAACL,KAAQ,CAACmB,IAAa,OACpB;EAAE;EAAM;EAAM;EAAI,OAAOb,EAAeP,GAAOM,GAAQK,CAAE;CAAE;AACpE;AAEA,SAAgBU,EAAe,GAA0B,GAAmC;CAC1F,OAAO,CAAC,CAACxB,KAAK,CAAC,CAACC,KAAKF,EAASC,EAAE,UAAUC,EAAE,QAAQ,KAAKF,EAASC,EAAE,QAAQC,EAAE,MAAM,KAAKD,EAAE,UAAUC,EAAE;AACzG;AAEA,SAAgBwB,EAAO,GAAkC;CACvD,OAAOC,MAAO,KAAA,IAAY,KAAK,OAAOA,CAAE;AAC1C"}
|