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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/LayoutSuite/index.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport Page, {\n type PageProps,\n type PageBodyProps,\n type PageMainProps,\n type PageAsideProps,\n type PagePanelProps,\n type PageFooterProps,\n type PageFloatProps,\n} from '../Page';\nimport type { PageHeaderProps } from '../PageHeader';\nimport Sidebar from '../../layouts/Sidebar';\nimport { cn } from '../../utils/cn';\nimport './style.css';\nimport { DashboardSuite } from './DashboardSuite';\nexport { DashboardSuite } from './DashboardSuite';\nexport type { DashboardSuiteProps } from './DashboardSuite';\n\n/** Sidebar 保持原有 API;panel 仅配置外层 Page.Left / Page.Right。 */\nexport type LayoutSuiteSidebarProps = Omit<React.ComponentProps<typeof Sidebar>, 'language' | 'isCollapsed' | 'side'> & {\n language?: 'zh' | 'en';\n isCollapsed?: boolean;\n /** 独立启用区域边缘调宽,不要求 onToggle 或 onWidthChange。 */\n resizable?: boolean;\n panel?: Omit<PageAsideProps, 'children'>;\n};\n\nexport type LayoutSuiteHeaderProps = PageHeaderProps & PagePanelProps;\n\nexport type LayoutSuiteBaseProps = PageProps & {\n /** 可选三段式页头;Admin / Blog 仍要求配置 header。 */\n header?: LayoutSuiteHeaderProps;\n footer?: PageFooterProps;\n /** body 不接收 children;主内容支持顶层 children 或 main.children。 */\n body?: Omit<PageBodyProps, 'children'>;\n main?: PageMainProps;\n};\n\nexport type AdminSuiteProps = LayoutSuiteBaseProps & {\n header: LayoutSuiteHeaderProps;\n left: LayoutSuiteSidebarProps;\n};\n\n/** 邮件工作台:文件夹、邮件列表、邮件正文三栏。 */\nexport type MailSuiteProps = LayoutSuiteBaseProps & {\n left: LayoutSuiteSidebarProps;\n /** 第二栏为 Page.Left,承载邮件列表;open 控制收起/展开,resizable 启用调宽。\n * children / main.children 承载选中的邮件正文。 */\n list: PageAsideProps;\n};\n\nexport type WikiSuiteProps = LayoutSuiteBaseProps & {\n left?: LayoutSuiteSidebarProps;\n right?: LayoutSuiteSidebarProps;\n float?: PageFloatProps;\n};\n\nexport type BlogSuiteProps = LayoutSuiteBaseProps & {\n header: LayoutSuiteHeaderProps;\n footer?: PageFooterProps;\n};\n\nexport type BlankSuiteProps = LayoutSuiteBaseProps & {\n float?: PageFloatProps;\n};\n\nconst SidebarPanel = ({\n side,\n panel,\n resizable = false,\n language = 'zh',\n isCollapsed = false,\n ...sidebar\n}: LayoutSuiteSidebarProps & { side: 'left' | 'right' }) => {\n const { initialWidth = 280, collapsedWidth = 64, onWidthChange } = sidebar;\n const requestedMin = panel?.minWidth ?? sidebar.minWidth ?? 160;\n const requestedMax = panel?.maxWidth ?? sidebar.maxWidth ?? 400;\n const minWidth = Number.isFinite(requestedMin) ? Math.max(0, requestedMin) : 160;\n const maxWidth = Math.max(minWidth, Number.isFinite(requestedMax) ? requestedMax : 400);\n const panelWidth = panel?.style?.width ?? panel?.width;\n const sourceWidth = panelWidth ?? initialWidth;\n const clamp = (width: number) => Math.max(minWidth, Math.min(Number.isFinite(width) ? width : 280, maxWidth));\n const [widthState, setWidthState] = useState(() => ({\n initialWidth, sourceWidth, minWidth, maxWidth,\n width: typeof sourceWidth === 'number' ? clamp(sourceWidth) : sourceWidth,\n }));\n\n // 与 Sidebar 的配置同步规则一致;折叠不重置用户拖动后的展开宽度。\n const configChanged = !Object.is(widthState.initialWidth, initialWidth)\n || !Object.is(widthState.sourceWidth, sourceWidth)\n || !Object.is(widthState.minWidth, minWidth) || !Object.is(widthState.maxWidth, maxWidth);\n const expandedWidth = configChanged\n ? (typeof sourceWidth === 'number' ? clamp(sourceWidth) : sourceWidth)\n : widthState.width;\n if (configChanged) {\n setWidthState({ initialWidth, sourceWidth, minWidth, maxWidth, width: expandedWidth });\n }\n\n const handleWidthChange = (width: number) => {\n const next = clamp(width);\n setWidthState({ initialWidth, sourceWidth, minWidth, maxWidth, width: next });\n onWidthChange?.(next);\n };\n const handlePanelWidthChange = (width: number) => {\n handleWidthChange(width);\n if (panel?.onWidthChange !== onWidthChange) panel?.onWidthChange?.(clamp(width));\n };\n const sidebarWidth = typeof expandedWidth === 'number' ? expandedWidth : clamp(initialWidth);\n const Aside = side === 'left' ? Page.Left : Page.Right;\n return (\n <Aside\n bordered={false}\n scroll={false}\n {...panel}\n width={isCollapsed ? collapsedWidth : expandedWidth}\n style={panel?.style ? { ...panel.style, width: undefined } : undefined}\n minWidth={minWidth}\n maxWidth={maxWidth}\n resizable={!isCollapsed && (panel?.resizable ?? resizable)}\n resizeVariant={sidebar.onToggle ? 'line' : panel?.resizeVariant}\n onWidthChange={handlePanelWidthChange}\n className={cn('dishui-layout-suite-sidebar',\n !isCollapsed && typeof expandedWidth === 'string' && 'dishui-layout-suite-sidebar-css-width', panel?.className)}\n >\n <Sidebar {...sidebar} side={side} language={language} isCollapsed={isCollapsed}\n initialWidth={sidebarWidth} minWidth={minWidth} maxWidth={maxWidth}\n onWidthChange={onWidthChange || (sidebar.onToggle && (panel?.resizable ?? resizable)) ? handlePanelWidthChange : undefined} />\n </Aside>\n );\n};\n\ntype SuiteFrameProps = LayoutSuiteBaseProps & {\n header?: LayoutSuiteHeaderProps;\n left?: LayoutSuiteSidebarProps;\n list?: PageAsideProps;\n right?: LayoutSuiteSidebarProps;\n footer?: PageFooterProps;\n float?: PageFloatProps;\n};\n\nconst SuiteFrame = ({\n header,\n left,\n list,\n right,\n footer,\n float,\n body,\n main,\n fullHeight = false,\n children,\n className,\n ...page\n}: SuiteFrameProps) => (\n <Page fullHeight={fullHeight} {...page} className={cn('dishui-layout-suite', className)}>\n {header && <Page.Header {...header} />}\n <Page.Body gap={0} scroll={fullHeight} {...body}>\n {left && <SidebarPanel side=\"left\" {...left} />}\n {list && <Page.Left width={320} scroll {...list} />}\n <Page.Main scroll={fullHeight} {...main}>{children !== undefined ? children : main?.children}</Page.Main>\n {right && <SidebarPanel side=\"right\" {...right} />}\n </Page.Body>\n {footer && <Page.Footer {...footer} />}\n {float && <Page.Float {...float} />}\n </Page>\n);\n\n/** 后台:必填页头和内置导航侧栏。Sidebar 需置于 TanStack Router 上下文中。 */\nexport const AdminSuite = (props: AdminSuiteProps) => <SuiteFrame {...props} />;\n\n/** 邮件:全宽三栏;省略 header 或设置 header.open=false 可隐藏页头。 */\nexport const MailSuite = ({ className, ...props }: MailSuiteProps) => (\n <SuiteFrame {...props} className={cn('dishui-mail-suite', className)} />\n);\n\n/** 文档:可选双侧导航与浮窗。 */\nexport const WikiSuite = (props: WikiSuiteProps) => <SuiteFrame {...props} />;\n\n/** 博客:必填页头,可选页脚。 */\nexport const BlogSuite = (props: BlogSuiteProps) => <SuiteFrame {...props} />;\n\n/** 空白页:主内容与可选浮窗。 */\nexport const BlankSuite = (props: BlankSuiteProps) => <SuiteFrame {...props} />;\n\nexport const LayoutSuite = { AdminSuite, MailSuite, WikiSuite, BlogSuite, BlankSuite, DashboardSuite };\n\nexport default LayoutSuite;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["Page","PageWithCompounds","Sidebar","SidebarPanel","sidebar","requestedMin","panel","requestedMax","minWidth","maxWidth","sourceWidth","initialWidth","clamp","width","widthState","setWidthState","useState","configChanged","expandedWidth","handleWidthChange","next","onWidthChange","handlePanelWidthChange","sidebarWidth","Aside","side","isCollapsed","collapsedWidth","resizable","cn","SuiteFrame","page","className","header","fullHeight","body","left","list","main","children","right","footer","float","AdminSuite","props","MailSuite","WikiSuite","BlogSuite","BlankSuite","LayoutSuite","DashboardSuite"],"sources":["../../../src/components/LayoutSuite/index.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport Page, {\n type PageProps,\n type PageBodyProps,\n type PageMainProps,\n type PageAsideProps,\n type PagePanelProps,\n type PageFooterProps,\n type PageFloatProps,\n} from '../Page';\nimport type { PageHeaderProps } from '../PageHeader';\nimport Sidebar from '../../layouts/Sidebar';\nimport { cn } from '../../utils/cn';\nimport './style.css';\nimport { DashboardSuite } from './DashboardSuite';\nexport { DashboardSuite } from './DashboardSuite';\nexport type { DashboardSuiteProps } from './DashboardSuite';\n\n/** Sidebar 保持原有 API;panel 仅配置外层 Page.Left / Page.Right。 */\nexport type LayoutSuiteSidebarProps = Omit<React.ComponentProps<typeof Sidebar>, 'language' | 'isCollapsed' | 'side'> & {\n language?: 'zh' | 'en';\n isCollapsed?: boolean;\n /** 独立启用区域边缘调宽,不要求 onToggle 或 onWidthChange。 */\n resizable?: boolean;\n panel?: Omit<PageAsideProps, 'children'>;\n};\n\nexport type LayoutSuiteHeaderProps = PageHeaderProps & PagePanelProps;\n\nexport type LayoutSuiteBaseProps = PageProps & {\n /** 可选三段式页头;Admin / Blog 仍要求配置 header。 */\n header?: LayoutSuiteHeaderProps;\n footer?: PageFooterProps;\n /** body 不接收 children;主内容支持顶层 children 或 main.children。 */\n body?: Omit<PageBodyProps, 'children'>;\n main?: PageMainProps;\n};\n\nexport type AdminSuiteProps = LayoutSuiteBaseProps & {\n header: LayoutSuiteHeaderProps;\n left: LayoutSuiteSidebarProps;\n};\n\n/** 邮件工作台:文件夹、邮件列表、邮件正文三栏。 */\nexport type MailSuiteProps = LayoutSuiteBaseProps & {\n left: LayoutSuiteSidebarProps;\n /** 第二栏为 Page.Left,承载邮件列表;open 控制收起/展开,resizable 启用调宽。\n * children / main.children 承载选中的邮件正文。 */\n list: PageAsideProps;\n};\n\nexport type WikiSuiteProps = LayoutSuiteBaseProps & {\n left?: LayoutSuiteSidebarProps;\n right?: LayoutSuiteSidebarProps;\n float?: PageFloatProps;\n};\n\nexport type BlogSuiteProps = LayoutSuiteBaseProps & {\n header: LayoutSuiteHeaderProps;\n footer?: PageFooterProps;\n};\n\nexport type BlankSuiteProps = LayoutSuiteBaseProps & {\n float?: PageFloatProps;\n};\n\nconst SidebarPanel = ({\n side,\n panel,\n resizable = false,\n language = 'zh',\n isCollapsed = false,\n ...sidebar\n}: LayoutSuiteSidebarProps & { side: 'left' | 'right' }) => {\n const { initialWidth = 280, collapsedWidth = 64, onWidthChange } = sidebar;\n const requestedMin = panel?.minWidth ?? sidebar.minWidth ?? 160;\n const requestedMax = panel?.maxWidth ?? sidebar.maxWidth ?? 400;\n const minWidth = Number.isFinite(requestedMin) ? Math.max(0, requestedMin) : 160;\n const maxWidth = Math.max(minWidth, Number.isFinite(requestedMax) ? requestedMax : 400);\n const panelWidth = panel?.style?.width ?? panel?.width;\n const sourceWidth = panelWidth ?? initialWidth;\n const clamp = (width: number) => Math.max(minWidth, Math.min(Number.isFinite(width) ? width : 280, maxWidth));\n const [widthState, setWidthState] = useState(() => ({\n initialWidth, sourceWidth, minWidth, maxWidth,\n width: typeof sourceWidth === 'number' ? clamp(sourceWidth) : sourceWidth,\n }));\n\n // 与 Sidebar 的配置同步规则一致;折叠不重置用户拖动后的展开宽度。\n const configChanged = !Object.is(widthState.initialWidth, initialWidth)\n || !Object.is(widthState.sourceWidth, sourceWidth)\n || !Object.is(widthState.minWidth, minWidth) || !Object.is(widthState.maxWidth, maxWidth);\n const expandedWidth = configChanged\n ? (typeof sourceWidth === 'number' ? clamp(sourceWidth) : sourceWidth)\n : widthState.width;\n if (configChanged) {\n setWidthState({ initialWidth, sourceWidth, minWidth, maxWidth, width: expandedWidth });\n }\n\n const handleWidthChange = (width: number) => {\n const next = clamp(width);\n setWidthState({ initialWidth, sourceWidth, minWidth, maxWidth, width: next });\n onWidthChange?.(next);\n };\n const handlePanelWidthChange = (width: number) => {\n handleWidthChange(width);\n if (panel?.onWidthChange !== onWidthChange) panel?.onWidthChange?.(clamp(width));\n };\n const sidebarWidth = typeof expandedWidth === 'number' ? expandedWidth : clamp(initialWidth);\n const Aside = side === 'left' ? Page.Left : Page.Right;\n return (\n <Aside\n bordered={false}\n scroll={false}\n {...panel}\n width={isCollapsed ? collapsedWidth : expandedWidth}\n style={panel?.style ? { ...panel.style, width: undefined } : undefined}\n minWidth={minWidth}\n maxWidth={maxWidth}\n resizable={!isCollapsed && (panel?.resizable ?? resizable)}\n resizeVariant={sidebar.onToggle ? 'line' : panel?.resizeVariant}\n onWidthChange={handlePanelWidthChange}\n className={cn('dishui-layout-suite-sidebar',\n !isCollapsed && typeof expandedWidth === 'string' && 'dishui-layout-suite-sidebar-css-width', panel?.className)}\n >\n <Sidebar {...sidebar} side={side} language={language} isCollapsed={isCollapsed}\n initialWidth={sidebarWidth} minWidth={minWidth} maxWidth={maxWidth}\n onWidthChange={onWidthChange || (sidebar.onToggle && (panel?.resizable ?? resizable)) ? handlePanelWidthChange : undefined} />\n </Aside>\n );\n};\n\ntype SuiteFrameProps = LayoutSuiteBaseProps & {\n header?: LayoutSuiteHeaderProps;\n left?: LayoutSuiteSidebarProps;\n list?: PageAsideProps;\n right?: LayoutSuiteSidebarProps;\n footer?: PageFooterProps;\n float?: PageFloatProps;\n};\n\nconst SuiteFrame = ({\n header,\n left,\n list,\n right,\n footer,\n float,\n body,\n main,\n fullHeight = false,\n children,\n className,\n ...page\n}: SuiteFrameProps) => (\n <Page fullHeight={fullHeight} {...page} className={cn('dishui-layout-suite', className)}>\n {header && <Page.Header {...header} />}\n <Page.Body gap={0} scroll={fullHeight} {...body}>\n {left && <SidebarPanel side=\"left\" {...left} />}\n {list && <Page.Left width={320} scroll {...list} />}\n <Page.Main scroll={fullHeight} {...main}>{children !== undefined ? children : main?.children}</Page.Main>\n {right && <SidebarPanel side=\"right\" {...right} />}\n </Page.Body>\n {footer && <Page.Footer {...footer} />}\n {float && <Page.Float {...float} />}\n </Page>\n);\n\n/** 后台:必填页头和内置导航侧栏。Sidebar 需置于 TanStack Router 上下文中。 */\nexport const AdminSuite = (props: AdminSuiteProps) => <SuiteFrame {...props} />;\n\n/** 邮件:全宽三栏;省略 header 或设置 header.open=false 可隐藏页头。 */\nexport const MailSuite = ({ className, ...props }: MailSuiteProps) => (\n <SuiteFrame {...props} className={cn('dishui-mail-suite', className)} />\n);\n\n/** 文档:可选双侧导航与浮窗。 */\nexport const WikiSuite = (props: WikiSuiteProps) => <SuiteFrame {...props} />;\n\n/** 博客:必填页头,可选页脚。 */\nexport const BlogSuite = (props: BlogSuiteProps) => <SuiteFrame {...props} />;\n\n/** 空白页:主内容与可选浮窗。 */\nexport const BlankSuite = (props: BlankSuiteProps) => <SuiteFrame {...props} />;\n\nexport const LayoutSuite = { AdminSuite, MailSuite, WikiSuite, BlogSuite, BlankSuite, DashboardSuite };\n\nexport default LayoutSuite;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/List/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../utils/cn';\n\nexport type ListProps = {\n children: React.ReactNode;\n className?: string;\n onClick?: (e: React.MouseEvent) => void;\n onMouseEnter?: (e: React.MouseEvent) => void;\n onMouseLeave?: (e: React.MouseEvent) => void;\n};\n\nconst List = ({\n children,\n className = '',\n onClick,\n onMouseEnter,\n onMouseLeave,\n}: ListProps) => {\n const baseClass = 'dishui-list list text-body leading-5 text-base-content';\n \n const listClasses = cn(baseClass, className);\n\n return (\n <ul \n className={listClasses}\n onClick={onClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {children}\n </ul>\n );\n};\n\n// List.Row 组件\nexport type ListRowProps = {\n children: React.ReactNode;\n className?: string;\n selected?: boolean;\n onClick?: (e: React.MouseEvent) => void;\n onDoubleClick?: (e: React.MouseEvent) => void;\n onMouseEnter?: (e: React.MouseEvent) => void;\n onMouseLeave?: (e: React.MouseEvent) => void;\n onContextMenu?: (e: React.MouseEvent) => void;\n};\n\nconst ListRow = ({\n children,\n className = '',\n selected = false,\n onClick,\n onDoubleClick,\n onMouseEnter,\n onMouseLeave,\n onContextMenu,\n}: ListRowProps) => {\n const baseClass = 'dishui-list-row list-row min-h-10 gap-3 rounded-none px-3 py-2 text-body transition-colors duration-150 motion-reduce:transition-none';\n \n const rowClasses = cn(baseClass, selected && 'bg-base-200', className);\n\n return (\n <li \n className={rowClasses}\n onClick={onClick}\n onDoubleClick={onDoubleClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onContextMenu={onContextMenu}\n >\n {children}\n </li>\n );\n};\n\n// List.ColWrap 组件\nexport type ListColWrapProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ListColWrap = ({\n children,\n className = '',\n}: ListColWrapProps) => {\n const baseClass = 'list-col-wrap min-w-0 break-words';\n \n const colWrapClasses = cn(baseClass, className);\n\n return (\n <div className={colWrapClasses}>\n {children}\n </div>\n );\n};\n\n// List.ColGrow 组件\nexport type ListColGrowProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ListColGrow = ({\n children,\n className = '',\n}: ListColGrowProps) => {\n const baseClass = 'list-col-grow min-w-0 break-words';\n \n const colGrowClasses = cn(baseClass, className);\n\n return (\n <div className={colGrowClasses}>\n {children}\n </div>\n );\n};\n\n// List.Header 组件\nexport type ListHeaderProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ListHeader = ({\n children,\n className = '',\n}: ListHeaderProps) => {\n const headerClasses = cn(\n 'dishui-list-header px-3 py-2',\n 'text-body-sm font-medium leading-5',\n 'text-base-content/70',\n className\n );\n\n return (\n <li className={headerClasses}>\n {children}\n </li>\n );\n};\n\n// 扩展List组件,添加Row、ColWrap和ColGrow子组件\ninterface ListCompound extends React.FC<ListProps> {\n Row: React.FC<ListRowProps>;\n ColWrap: React.FC<ListColWrapProps>;\n ColGrow: React.FC<ListColGrowProps>;\n Header: React.FC<ListHeaderProps>;\n}\n\nconst ListWithCompounds = List as ListCompound;\nListWithCompounds.Row = ListRow;\nListWithCompounds.ColWrap = ListColWrap;\nListWithCompounds.ColGrow = ListColGrow;\nListWithCompounds.Header = ListHeader;\n\nexport default ListWithCompounds; "],"mappings":";;;;AAWA,
|
|
1
|
+
{"version":3,"file":"index.js","names":["List","listClasses","cn","className","ListRow","rowClasses","selected","ListColWrap","colWrapClasses","ListColGrow","colGrowClasses","ListHeader","headerClasses","ListWithCompounds"],"sources":["../../../src/components/List/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../utils/cn';\n\nexport type ListProps = {\n children: React.ReactNode;\n className?: string;\n onClick?: (e: React.MouseEvent) => void;\n onMouseEnter?: (e: React.MouseEvent) => void;\n onMouseLeave?: (e: React.MouseEvent) => void;\n};\n\nconst List = ({\n children,\n className = '',\n onClick,\n onMouseEnter,\n onMouseLeave,\n}: ListProps) => {\n const baseClass = 'dishui-list list text-body leading-5 text-base-content';\n \n const listClasses = cn(baseClass, className);\n\n return (\n <ul \n className={listClasses}\n onClick={onClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n >\n {children}\n </ul>\n );\n};\n\n// List.Row 组件\nexport type ListRowProps = {\n children: React.ReactNode;\n className?: string;\n selected?: boolean;\n onClick?: (e: React.MouseEvent) => void;\n onDoubleClick?: (e: React.MouseEvent) => void;\n onMouseEnter?: (e: React.MouseEvent) => void;\n onMouseLeave?: (e: React.MouseEvent) => void;\n onContextMenu?: (e: React.MouseEvent) => void;\n};\n\nconst ListRow = ({\n children,\n className = '',\n selected = false,\n onClick,\n onDoubleClick,\n onMouseEnter,\n onMouseLeave,\n onContextMenu,\n}: ListRowProps) => {\n const baseClass = 'dishui-list-row list-row min-h-10 gap-3 rounded-none px-3 py-2 text-body transition-colors duration-150 motion-reduce:transition-none';\n \n const rowClasses = cn(baseClass, selected && 'bg-base-200', className);\n\n return (\n <li \n className={rowClasses}\n onClick={onClick}\n onDoubleClick={onDoubleClick}\n onMouseEnter={onMouseEnter}\n onMouseLeave={onMouseLeave}\n onContextMenu={onContextMenu}\n >\n {children}\n </li>\n );\n};\n\n// List.ColWrap 组件\nexport type ListColWrapProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ListColWrap = ({\n children,\n className = '',\n}: ListColWrapProps) => {\n const baseClass = 'list-col-wrap min-w-0 break-words';\n \n const colWrapClasses = cn(baseClass, className);\n\n return (\n <div className={colWrapClasses}>\n {children}\n </div>\n );\n};\n\n// List.ColGrow 组件\nexport type ListColGrowProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ListColGrow = ({\n children,\n className = '',\n}: ListColGrowProps) => {\n const baseClass = 'list-col-grow min-w-0 break-words';\n \n const colGrowClasses = cn(baseClass, className);\n\n return (\n <div className={colGrowClasses}>\n {children}\n </div>\n );\n};\n\n// List.Header 组件\nexport type ListHeaderProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ListHeader = ({\n children,\n className = '',\n}: ListHeaderProps) => {\n const headerClasses = cn(\n 'dishui-list-header px-3 py-2',\n 'text-body-sm font-medium leading-5',\n 'text-base-content/70',\n className\n );\n\n return (\n <li className={headerClasses}>\n {children}\n </li>\n );\n};\n\n// 扩展List组件,添加Row、ColWrap和ColGrow子组件\ninterface ListCompound extends React.FC<ListProps> {\n Row: React.FC<ListRowProps>;\n ColWrap: React.FC<ListColWrapProps>;\n ColGrow: React.FC<ListColGrowProps>;\n Header: React.FC<ListHeaderProps>;\n}\n\nconst ListWithCompounds = List as ListCompound;\nListWithCompounds.Row = ListRow;\nListWithCompounds.ColWrap = ListColWrap;\nListWithCompounds.ColGrow = ListColGrow;\nListWithCompounds.Header = ListHeader;\n\nexport default ListWithCompounds; "],"mappings":";;;;AAWA,IAAMA,KAAQ,EACZ,aACA,eAAY,IACZ,YACA,iBACA,sBACe;CAGf,IAAMC,IAAcC,EAAG,0DAAWC,CAAS;CAE3C,OACE,kBAAC,MAAD;EACE,WAAWF;EACF;EACK;EACA;EAEb;CACC,CAAA;AAER,GAcMG,KAAW,EACf,aACA,eAAY,IACZ,cAAW,IACX,YACA,kBACA,iBACA,iBACA,uBACkB;CAGlB,IAAMC,IAAaH,EAAG,yIAAWI,KAAY,eAAeH,CAAS;CAErE,OACE,kBAAC,MAAD;EACE,WAAWE;EACF;EACM;EACD;EACA;EACC;EAEd;CACC,CAAA;AAER,GAQME,KAAe,EACnB,aACA,eAAY,SACU;CAGtB,IAAMC,IAAiBN,EAAG,qCAAWC,CAAS;CAE9C,OACE,kBAAC,OAAD;EAAK,WAAWK;EACb;CACE,CAAA;AAET,GAQMC,KAAe,EACnB,aACA,eAAY,SACU;CAGtB,IAAMC,IAAiBR,EAAG,qCAAWC,CAAS;CAE9C,OACE,kBAAC,OAAD;EAAK,WAAWO;EACb;CACE,CAAA;AAET,GAQMC,KAAc,EAClB,aACA,eAAY,SACS;CACrB,IAAMC,IAAgBV,EACpB,gCACA,sCACA,wBACAC,CACF;CAEA,OACE,kBAAC,MAAD;EAAI,WAAWS;EACZ;CACC,CAAA;AAER,GAUMC,IAAoBb;AAC1B,EAAkB,MAAMI,GACxB,EAAkB,UAAUG,GAC5B,EAAkB,UAAUE,GAC5B,EAAkB,SAASE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.js","names":[],"sources":["../../../src/components/Markdown/Markdown.tsx"],"sourcesContent":["import React, { useRef, useMemo } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkEmoji from 'remark-emoji';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport rehypeSlug from 'rehype-slug';\nimport remarkMath from 'remark-math';\nimport { remarkCodeMeta } from '../../utils/remark-code-meta';\nimport { rehypeCodeMeta } from '../../utils/rehype-code-meta';\nimport ArticleControl, { ArticleAction } from '../pro/ArticleControl';\nimport ArticleContextMenu, { ContextMenuItem } from '../pro/ArticleContextMenu';\nimport { useMarkdownSource } from './useMarkdownSource';\nimport { useMermaidRenderer } from './useMermaidRenderer';\nimport { useMarkmapRenderer } from './useMarkmapRenderer';\nimport { getCodeStyle } from './codeThemes';\nimport type { CodeThemeName } from './codeThemes';\nimport { createMarkdownComponents } from './markdownComponents';\nimport 'katex/dist/katex.min.css';\n\nexport type MarkdownSource = 'url' | 's3' | 'text';\n\nexport interface MarkdownProps {\n source?: MarkdownSource;\n content: string;\n showLoading?: boolean;\n loadingText?: string;\n showError?: boolean;\n errorRenderer?: (error: Error) => React.ReactNode;\n codeTheme?: CodeThemeName;\n showLineNumbers?: boolean;\n enableGfm?: boolean;\n enableEmoji?: boolean;\n enableKatex?: boolean;\n enableMermaid?: boolean;\n enableMarkmap?: boolean;\n enableMdx?: boolean;\n enableSlug?: boolean;\n slugPrefix?: string;\n showArticleControl?: boolean;\n articleControlProps?: {\n initialPosition?: { x: number; y: number };\n initialExpanded?: boolean;\n ballSize?: number;\n panelWidth?: number;\n panelMaxHeight?: number;\n actions?: ArticleAction[];\n };\n containerId?: string;\n showContextMenu?: boolean;\n contextMenuItems?: ContextMenuItem[];\n className?: string;\n s3Config?: {\n accessKeyId?: string;\n secretAccessKey?: string;\n region?: string;\n endpoint?: string;\n };\n onLoad?: (content: string) => void;\n onError?: (error: Error) => void;\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n source = 'text',\n content,\n showLoading = true,\n loadingText = 'Loading...',\n showError = true,\n errorRenderer,\n codeTheme = 'vscDarkPlus',\n showLineNumbers = false,\n enableGfm = true,\n enableEmoji = true,\n enableKatex = true,\n enableMermaid = true,\n enableMarkmap = true,\n enableMdx = true,\n enableSlug = true,\n slugPrefix = '',\n showArticleControl = false,\n articleControlProps,\n showContextMenu = false,\n contextMenuItems = [],\n containerId,\n className = '',\n s3Config,\n onLoad,\n onError,\n}) => {\n const mermaidRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const generatedContainerId = useRef(`markdown-${Math.random().toString(36).substr(2, 9)}`);\n\n const { markdown, loading, error } = useMarkdownSource(source, content, s3Config, onLoad, onError);\n\n useMermaidRenderer(mermaidRef, markdown, enableMermaid);\n useMarkmapRenderer(mermaidRef, markdown, enableMarkmap);\n\n const remarkPlugins: any[] = useMemo(() => {\n const plugins: any[] = [remarkCodeMeta];\n if (enableGfm) plugins.push(remarkGfm);\n if (enableEmoji) plugins.push(remarkEmoji);\n if (enableKatex) plugins.push(remarkMath);\n return plugins;\n }, [enableGfm, enableEmoji, enableKatex]);\n\n const rehypePlugins: any[] = useMemo(() => {\n const plugins: any[] = [rehypeCodeMeta];\n if (enableSlug) plugins.push([rehypeSlug, { prefix: slugPrefix }]);\n if (enableMdx) plugins.push(rehypeRaw);\n if (enableKatex) plugins.push(rehypeKatex);\n return plugins;\n }, [enableSlug, slugPrefix, enableMdx, enableKatex]);\n\n const codeStyle = useMemo(() => getCodeStyle(codeTheme), [codeTheme]);\n\n const components = useMemo(\n () => createMarkdownComponents({ enableMermaid, enableMarkmap, showLineNumbers, codeStyle }),\n [enableMermaid, enableMarkmap, showLineNumbers, codeStyle],\n );\n\n if (loading && showLoading) {\n return (\n <div className={`flex items-center justify-center p-8 ${className}`}>\n <div className=\"flex flex-col items-center gap-4\">\n <span className=\"loading loading-spinner loading-lg\"></span>\n <p className=\"text-base-content/70\">{loadingText}</p>\n </div>\n </div>\n );\n }\n\n if (error && showError) {\n if (errorRenderer) {\n return <>{errorRenderer(error)}</>;\n }\n return (\n <div className={`alert alert-error ${className}`}>\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div>\n <h3 className=\"font-bold\">加载失败</h3>\n <div className=\"text-xs\">{error.message}</div>\n </div>\n </div>\n );\n }\n\n const finalContainerId = containerId || generatedContainerId.current;\n\n return (\n <>\n <div\n ref={containerRef}\n id={finalContainerId}\n className={`prose prose-sm md:prose-base lg:prose-lg max-w-none ${className}`}\n >\n <div ref={mermaidRef}>\n <ReactMarkdown\n remarkPlugins={remarkPlugins}\n rehypePlugins={rehypePlugins}\n components={components}\n >\n {markdown}\n </ReactMarkdown>\n </div>\n </div>\n\n {showArticleControl && (\n <ArticleControl\n targetRef={containerRef}\n {...articleControlProps}\n />\n )}\n\n {showContextMenu && contextMenuItems.length > 0 && (\n <ArticleContextMenu\n targetRef={containerRef}\n menuItems={contextMenuItems}\n />\n )}\n </>\n );\n};\n\nexport default Markdown;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA8DA,
|
|
1
|
+
{"version":3,"file":"Markdown.js","names":["_Fragment","ArticleControl","ArticleContextMenu","ReactMarkdown","remarkGfm","remarkEmoji","rehypeKatex","rehypeRaw","rehypeSlug","remarkMath","Markdown","mermaidRef","useRef","containerRef","generatedContainerId","useMarkdownSource","source","content","s3Config","onLoad","onError","useMermaidRenderer","markdown","enableMermaid","useMarkmapRenderer","enableMarkmap","remarkPlugins","useMemo","plugins","remarkCodeMeta","enableGfm","enableEmoji","enableKatex","rehypePlugins","rehypeCodeMeta","enableSlug","slugPrefix","enableMdx","codeStyle","getCodeStyle","codeTheme","components","createMarkdownComponents","showLineNumbers","loading","showLoading","className","loadingText","error","showError","errorRenderer","Fragment","finalContainerId","containerId","showArticleControl","articleControlProps","showContextMenu","contextMenuItems"],"sources":["../../../src/components/Markdown/Markdown.tsx"],"sourcesContent":["import React, { useRef, useMemo } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkEmoji from 'remark-emoji';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport rehypeSlug from 'rehype-slug';\nimport remarkMath from 'remark-math';\nimport { remarkCodeMeta } from '../../utils/remark-code-meta';\nimport { rehypeCodeMeta } from '../../utils/rehype-code-meta';\nimport ArticleControl, { ArticleAction } from '../pro/ArticleControl';\nimport ArticleContextMenu, { ContextMenuItem } from '../pro/ArticleContextMenu';\nimport { useMarkdownSource } from './useMarkdownSource';\nimport { useMermaidRenderer } from './useMermaidRenderer';\nimport { useMarkmapRenderer } from './useMarkmapRenderer';\nimport { getCodeStyle } from './codeThemes';\nimport type { CodeThemeName } from './codeThemes';\nimport { createMarkdownComponents } from './markdownComponents';\nimport 'katex/dist/katex.min.css';\n\nexport type MarkdownSource = 'url' | 's3' | 'text';\n\nexport interface MarkdownProps {\n source?: MarkdownSource;\n content: string;\n showLoading?: boolean;\n loadingText?: string;\n showError?: boolean;\n errorRenderer?: (error: Error) => React.ReactNode;\n codeTheme?: CodeThemeName;\n showLineNumbers?: boolean;\n enableGfm?: boolean;\n enableEmoji?: boolean;\n enableKatex?: boolean;\n enableMermaid?: boolean;\n enableMarkmap?: boolean;\n enableMdx?: boolean;\n enableSlug?: boolean;\n slugPrefix?: string;\n showArticleControl?: boolean;\n articleControlProps?: {\n initialPosition?: { x: number; y: number };\n initialExpanded?: boolean;\n ballSize?: number;\n panelWidth?: number;\n panelMaxHeight?: number;\n actions?: ArticleAction[];\n };\n containerId?: string;\n showContextMenu?: boolean;\n contextMenuItems?: ContextMenuItem[];\n className?: string;\n s3Config?: {\n accessKeyId?: string;\n secretAccessKey?: string;\n region?: string;\n endpoint?: string;\n };\n onLoad?: (content: string) => void;\n onError?: (error: Error) => void;\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n source = 'text',\n content,\n showLoading = true,\n loadingText = 'Loading...',\n showError = true,\n errorRenderer,\n codeTheme = 'vscDarkPlus',\n showLineNumbers = false,\n enableGfm = true,\n enableEmoji = true,\n enableKatex = true,\n enableMermaid = true,\n enableMarkmap = true,\n enableMdx = true,\n enableSlug = true,\n slugPrefix = '',\n showArticleControl = false,\n articleControlProps,\n showContextMenu = false,\n contextMenuItems = [],\n containerId,\n className = '',\n s3Config,\n onLoad,\n onError,\n}) => {\n const mermaidRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const generatedContainerId = useRef(`markdown-${Math.random().toString(36).substr(2, 9)}`);\n\n const { markdown, loading, error } = useMarkdownSource(source, content, s3Config, onLoad, onError);\n\n useMermaidRenderer(mermaidRef, markdown, enableMermaid);\n useMarkmapRenderer(mermaidRef, markdown, enableMarkmap);\n\n const remarkPlugins: any[] = useMemo(() => {\n const plugins: any[] = [remarkCodeMeta];\n if (enableGfm) plugins.push(remarkGfm);\n if (enableEmoji) plugins.push(remarkEmoji);\n if (enableKatex) plugins.push(remarkMath);\n return plugins;\n }, [enableGfm, enableEmoji, enableKatex]);\n\n const rehypePlugins: any[] = useMemo(() => {\n const plugins: any[] = [rehypeCodeMeta];\n if (enableSlug) plugins.push([rehypeSlug, { prefix: slugPrefix }]);\n if (enableMdx) plugins.push(rehypeRaw);\n if (enableKatex) plugins.push(rehypeKatex);\n return plugins;\n }, [enableSlug, slugPrefix, enableMdx, enableKatex]);\n\n const codeStyle = useMemo(() => getCodeStyle(codeTheme), [codeTheme]);\n\n const components = useMemo(\n () => createMarkdownComponents({ enableMermaid, enableMarkmap, showLineNumbers, codeStyle }),\n [enableMermaid, enableMarkmap, showLineNumbers, codeStyle],\n );\n\n if (loading && showLoading) {\n return (\n <div className={`flex items-center justify-center p-8 ${className}`}>\n <div className=\"flex flex-col items-center gap-4\">\n <span className=\"loading loading-spinner loading-lg\"></span>\n <p className=\"text-base-content/70\">{loadingText}</p>\n </div>\n </div>\n );\n }\n\n if (error && showError) {\n if (errorRenderer) {\n return <>{errorRenderer(error)}</>;\n }\n return (\n <div className={`alert alert-error ${className}`}>\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"stroke-current shrink-0 h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div>\n <h3 className=\"font-bold\">加载失败</h3>\n <div className=\"text-xs\">{error.message}</div>\n </div>\n </div>\n );\n }\n\n const finalContainerId = containerId || generatedContainerId.current;\n\n return (\n <>\n <div\n ref={containerRef}\n id={finalContainerId}\n className={`prose prose-sm md:prose-base lg:prose-lg max-w-none ${className}`}\n >\n <div ref={mermaidRef}>\n <ReactMarkdown\n remarkPlugins={remarkPlugins}\n rehypePlugins={rehypePlugins}\n components={components}\n >\n {markdown}\n </ReactMarkdown>\n </div>\n </div>\n\n {showArticleControl && (\n <ArticleControl\n targetRef={containerRef}\n {...articleControlProps}\n />\n )}\n\n {showContextMenu && contextMenuItems.length > 0 && (\n <ArticleContextMenu\n targetRef={containerRef}\n menuItems={contextMenuItems}\n />\n )}\n </>\n );\n};\n\nexport default Markdown;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codeThemes.js","names":[],"sources":["../../../src/components/Markdown/codeThemes.ts"],"sourcesContent":["import {\n dracula,\n prism,\n vscDarkPlus,\n oneDark,\n atomDark,\n tomorrow,\n vs,\n oneLight,\n} from 'react-syntax-highlighter/dist/esm/styles/prism';\n\nexport type CodeThemeName = 'dracula' | 'prism' | 'vscDarkPlus' | 'oneDark' | 'atomDark' | 'tomorrow' | 'vs' | 'oneLight';\n\nconst CODE_THEMES: Record<string, any> = {\n dracula,\n prism,\n vscDarkPlus,\n oneDark,\n atomDark,\n tomorrow,\n vs,\n oneLight,\n 'vscode-dark': vscDarkPlus,\n 'vsc-dark-plus': vscDarkPlus,\n 'github-dark': vscDarkPlus,\n 'one-dark': oneDark,\n 'atom-dark': atomDark,\n 'github-light': oneLight,\n 'one-light': oneLight,\n};\n\nexport function getCodeStyle(theme: CodeThemeName): any {\n return CODE_THEMES[theme] || vscDarkPlus;\n}\n\nexport function resolveMetaTheme(metaTheme: string | undefined, fallback: any): any {\n if (!metaTheme) return fallback;\n return CODE_THEMES[metaTheme.toLowerCase()] || fallback;\n}\n\nexport { dracula, prism, vscDarkPlus, oneDark, atomDark, tomorrow, vs, oneLight };\n"],"mappings":";;AAaA,
|
|
1
|
+
{"version":3,"file":"codeThemes.js","names":["oneLight","oneLight$1","CODE_THEMES","vscDarkPlus","oneDark","atomDark","getCodeStyle","theme","resolveMetaTheme","metaTheme","fallback","dracula","prism","tomorrow","vs"],"sources":["../../../src/components/Markdown/codeThemes.ts"],"sourcesContent":["import {\n dracula,\n prism,\n vscDarkPlus,\n oneDark,\n atomDark,\n tomorrow,\n vs,\n oneLight,\n} from 'react-syntax-highlighter/dist/esm/styles/prism';\n\nexport type CodeThemeName = 'dracula' | 'prism' | 'vscDarkPlus' | 'oneDark' | 'atomDark' | 'tomorrow' | 'vs' | 'oneLight';\n\nconst CODE_THEMES: Record<string, any> = {\n dracula,\n prism,\n vscDarkPlus,\n oneDark,\n atomDark,\n tomorrow,\n vs,\n oneLight,\n 'vscode-dark': vscDarkPlus,\n 'vsc-dark-plus': vscDarkPlus,\n 'github-dark': vscDarkPlus,\n 'one-dark': oneDark,\n 'atom-dark': atomDark,\n 'github-light': oneLight,\n 'one-light': oneLight,\n};\n\nexport function getCodeStyle(theme: CodeThemeName): any {\n return CODE_THEMES[theme] || vscDarkPlus;\n}\n\nexport function resolveMetaTheme(metaTheme: string | undefined, fallback: any): any {\n if (!metaTheme) return fallback;\n return CODE_THEMES[metaTheme.toLowerCase()] || fallback;\n}\n\nexport { dracula, prism, vscDarkPlus, oneDark, atomDark, tomorrow, vs, oneLight };\n"],"mappings":";;AAaA,IAAME,IAAmC;CACvC;CACA;CACA;CACA;CACA;CACA;CACA;CACA,UAAAD;CACA,eAAeE;CACf,iBAAiBA;CACjB,eAAeA;CACf,YAAYC;CACZ,aAAaC;CACb,gBAAgBL;CAChB,aAAaA;AACf;AAEA,SAAgBM,EAAa,GAA2B;CACtD,OAAOJ,EAAYK,MAAUJ;AAC/B;AAEA,SAAgBK,EAAiB,GAA+B,GAAoB;CAElF,OADKC,KACEP,EAAYO,EAAU,YAAY,MADlBC;AAEzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdownComponents.js","names":[],"sources":["../../../src/components/Markdown/markdownComponents.tsx"],"sourcesContent":["import React from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { parseCodeBlockMeta } from './parseCodeBlockMeta';\nimport { resolveMetaTheme } from './codeThemes';\n\nfunction highlightMarkdown(text: string) {\n const lines = text.split('\\n');\n return lines.map((line, index) => {\n if (/^#{1,6}\\s/.test(line)) {\n const match = line.match(/^(#{1,6})(\\s+.*)$/);\n if (match) {\n return (\n <div key={index}>\n <span style={{ color: '#569cd6' }}>{match[1]}</span>\n <span style={{ color: '#dcdcaa' }}>{match[2]}</span>\n </div>\n );\n }\n }\n\n if (/^(\\s*)([-*+]|\\d+\\.)\\s/.test(line)) {\n const match = line.match(/^(\\s*)([-*+]|\\d+\\.)(\\s+.*)$/);\n if (match) {\n return (\n <div key={index}>\n <span>{match[1]}</span>\n <span style={{ color: '#c586c0' }}>{match[2]}</span>\n <span>{match[3]}</span>\n </div>\n );\n }\n }\n\n if (line.startsWith('```')) {\n return (\n <div key={index}>\n <span style={{ color: '#4ec9b0' }}>{line}</span>\n </div>\n );\n }\n\n if (/^>\\s/.test(line)) {\n return (\n <div key={index}>\n <span style={{ color: '#608b4e' }}>{line}</span>\n </div>\n );\n }\n\n const processInlineStyles = (text: string) => {\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n const regex = /(\\*\\*[^*]+\\*\\*|\\*[^*]+\\*|`[^`]+`|\\[([^\\]]+)\\]\\(([^)]+)\\))/g;\n let match;\n\n while ((match = regex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n parts.push(text.substring(lastIndex, match.index));\n }\n const matched = match[1];\n if (matched.startsWith('**')) {\n parts.push(<span key={match.index} style={{ color: '#ce9178', fontWeight: 'bold' }}>{matched}</span>);\n } else if (matched.startsWith('*')) {\n parts.push(<span key={match.index} style={{ color: '#ce9178', fontStyle: 'italic' }}>{matched}</span>);\n } else if (matched.startsWith('`')) {\n parts.push(<span key={match.index} style={{ color: '#d16969' }}>{matched}</span>);\n } else if (matched.startsWith('[')) {\n parts.push(<span key={match.index} style={{ color: '#4ec9b0' }}>{matched}</span>);\n }\n lastIndex = regex.lastIndex;\n }\n\n if (lastIndex < text.length) {\n parts.push(text.substring(lastIndex));\n }\n\n return parts.length > 0 ? parts : text;\n };\n\n return (\n <div key={index}>\n {processInlineStyles(line)}\n </div>\n );\n }).filter(Boolean);\n}\n\nconst MONO_FONT = 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace';\n\ninterface CreateMarkdownComponentsOpts {\n enableMermaid: boolean;\n enableMarkmap: boolean;\n showLineNumbers: boolean;\n codeStyle: any;\n}\n\nexport function createMarkdownComponents(opts: CreateMarkdownComponentsOpts) {\n const { enableMermaid, enableMarkmap, showLineNumbers, codeStyle } = opts;\n\n return {\n code({ node, className, children, ...props }: any) {\n const fullClassName = className || '';\n const match = /language-(\\w+)/.exec(fullClassName);\n const inline = props.inline;\n const language = match ? match[1] : '';\n\n const metaString = (props as any).dataMeta ||\n (props as any)['data-meta'] || '';\n\n const codeMeta = parseCodeBlockMeta(metaString, fullClassName);\n\n if (!inline && language === 'mermaid' && enableMermaid) {\n return (\n <div\n className=\"mermaid-diagram my-4\"\n data-mermaid-content={String(children).replace(/\\n$/, '')}\n >\n {String(children).replace(/\\n$/, '')}\n </div>\n );\n }\n\n if (!inline && language === 'markmap' && enableMarkmap) {\n return (\n <div\n className=\"markmap-diagram my-4 border border-base-300 rounded-lg overflow-hidden\"\n data-markmap-content={String(children).replace(/\\n$/, '')}\n />\n );\n }\n\n if (!inline && match && language === 'markdown') {\n const code = String(children).replace(/\\n$/, '');\n return (\n <pre\n style={{\n fontFamily: MONO_FONT,\n fontSize: '0.875em',\n borderRadius: '0.5rem',\n padding: '1em',\n margin: 0,\n backgroundColor: 'rgb(30, 30, 30)',\n color: 'rgb(212, 212, 212)',\n overflow: 'auto',\n lineHeight: '1.5',\n }}\n >\n <code style={{ fontFamily: MONO_FONT }}>\n {highlightMarkdown(code)}\n </code>\n </pre>\n );\n }\n\n if (!inline && match) {\n const selectedStyle = resolveMetaTheme(codeMeta.theme, codeStyle);\n\n let shouldShowLineNumbers: boolean | undefined;\n let lineNumbersToShow: number[] | undefined;\n\n if (Array.isArray(codeMeta.showLineNumbers)) {\n shouldShowLineNumbers = true;\n lineNumbersToShow = codeMeta.showLineNumbers;\n } else if (codeMeta.showLineNumbers !== undefined) {\n shouldShowLineNumbers = codeMeta.showLineNumbers as boolean;\n } else {\n shouldShowLineNumbers = showLineNumbers;\n }\n\n const startingLineNumber = codeMeta.startLineNumber || 1;\n const wrapLines = (codeMeta.highlightLines && codeMeta.highlightLines.length > 0) ||\n (lineNumbersToShow && lineNumbersToShow.length > 0);\n\n const codeBlock = (\n <SyntaxHighlighter\n style={selectedStyle as any}\n language={language}\n PreTag=\"div\"\n showLineNumbers={shouldShowLineNumbers}\n startingLineNumber={startingLineNumber}\n customStyle={{\n fontFamily: MONO_FONT,\n fontSize: '0.875em',\n borderRadius: codeMeta.title ? '0 0 0.5rem 0.5rem' : '0.5rem',\n borderTop: codeMeta.title ? 'none' : undefined,\n padding: '1em',\n margin: 0,\n border: 'none',\n boxShadow: 'none',\n lineHeight: '1.5',\n }}\n codeTagProps={{\n style: { fontFamily: MONO_FONT }\n }}\n lineNumberStyle={(lineNumber: number) => {\n const baseStyle: React.CSSProperties = {\n minWidth: '3em',\n paddingRight: '1em',\n userSelect: 'none',\n border: 'none',\n };\n if (lineNumbersToShow) {\n if (lineNumbersToShow.includes(lineNumber)) {\n baseStyle.opacity = 0.5;\n } else {\n baseStyle.opacity = 0;\n baseStyle.visibility = 'hidden';\n }\n } else {\n baseStyle.opacity = 0.5;\n }\n return baseStyle;\n }}\n wrapLines={wrapLines}\n lineProps={(lineNumber: number) => {\n const style: React.CSSProperties = {\n display: 'block',\n border: 'none',\n boxShadow: 'none',\n outline: 'none',\n margin: 0,\n padding: 0,\n };\n if (codeMeta.highlightLines && codeMeta.highlightLines.includes(lineNumber)) {\n style.backgroundColor = 'rgba(255, 255, 0, 0.1)';\n style.display = 'block';\n style.width = '100%';\n }\n return { style };\n }}\n {...props}\n >\n {String(children).replace(/\\n$/, '')}\n </SyntaxHighlighter>\n );\n\n if (codeMeta.title) {\n return (\n <div className=\"my-4\">\n <div\n className=\"px-4 py-2 text-sm font-mono text-base-content bg-base-200 rounded-t-lg border-b border-base-300\"\n style={{ fontFamily: MONO_FONT }}\n >\n {codeMeta.title}\n </div>\n {codeBlock}\n </div>\n );\n }\n\n return codeBlock;\n }\n\n return (\n <code className={className} {...props}>\n {children}\n </code>\n );\n },\n\n table({ node, children, ...props }: any) {\n return (\n <div className=\"overflow-x-auto my-6\">\n <table className=\"table-auto border-collapse w-full\" {...props}>\n {children}\n </table>\n </div>\n );\n },\n thead({ node, children, ...props }: any) {\n return <thead className=\"bg-base-200\" {...props}>{children}</thead>;\n },\n tbody({ node, children, ...props }: any) {\n return <tbody {...props}>{children}</tbody>;\n },\n tr({ node, children, ...props }: any) {\n return <tr className=\"border-b border-base-300 hover:bg-base-100 transition-colors\" {...props}>{children}</tr>;\n },\n th({ node, children, ...props }: any) {\n return <th className=\"px-4 py-3 text-left font-semibold text-base-content border-b-2 border-base-300\" {...props}>{children}</th>;\n },\n td({ node, children, ...props }: any) {\n return <td className=\"px-4 py-3 text-base-content\" {...props}>{children}</td>;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"markdownComponents.js","names":["SyntaxHighlighter","highlightMarkdown","text","line","match","index","parts","lastIndex","regex","matched","MONO_FONT","createMarkdownComponents","opts","props","fullClassName","className","inline","language","metaString","codeMeta","parseCodeBlockMeta","enableMermaid","children","enableMarkmap","code","selectedStyle","resolveMetaTheme","codeStyle","shouldShowLineNumbers","lineNumbersToShow","showLineNumbers","startingLineNumber","wrapLines","codeBlock","Prism","baseStyle","lineNumber","style"],"sources":["../../../src/components/Markdown/markdownComponents.tsx"],"sourcesContent":["import React from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { parseCodeBlockMeta } from './parseCodeBlockMeta';\nimport { resolveMetaTheme } from './codeThemes';\n\nfunction highlightMarkdown(text: string) {\n const lines = text.split('\\n');\n return lines.map((line, index) => {\n if (/^#{1,6}\\s/.test(line)) {\n const match = line.match(/^(#{1,6})(\\s+.*)$/);\n if (match) {\n return (\n <div key={index}>\n <span style={{ color: '#569cd6' }}>{match[1]}</span>\n <span style={{ color: '#dcdcaa' }}>{match[2]}</span>\n </div>\n );\n }\n }\n\n if (/^(\\s*)([-*+]|\\d+\\.)\\s/.test(line)) {\n const match = line.match(/^(\\s*)([-*+]|\\d+\\.)(\\s+.*)$/);\n if (match) {\n return (\n <div key={index}>\n <span>{match[1]}</span>\n <span style={{ color: '#c586c0' }}>{match[2]}</span>\n <span>{match[3]}</span>\n </div>\n );\n }\n }\n\n if (line.startsWith('```')) {\n return (\n <div key={index}>\n <span style={{ color: '#4ec9b0' }}>{line}</span>\n </div>\n );\n }\n\n if (/^>\\s/.test(line)) {\n return (\n <div key={index}>\n <span style={{ color: '#608b4e' }}>{line}</span>\n </div>\n );\n }\n\n const processInlineStyles = (text: string) => {\n const parts: React.ReactNode[] = [];\n let lastIndex = 0;\n const regex = /(\\*\\*[^*]+\\*\\*|\\*[^*]+\\*|`[^`]+`|\\[([^\\]]+)\\]\\(([^)]+)\\))/g;\n let match;\n\n while ((match = regex.exec(text)) !== null) {\n if (match.index > lastIndex) {\n parts.push(text.substring(lastIndex, match.index));\n }\n const matched = match[1];\n if (matched.startsWith('**')) {\n parts.push(<span key={match.index} style={{ color: '#ce9178', fontWeight: 'bold' }}>{matched}</span>);\n } else if (matched.startsWith('*')) {\n parts.push(<span key={match.index} style={{ color: '#ce9178', fontStyle: 'italic' }}>{matched}</span>);\n } else if (matched.startsWith('`')) {\n parts.push(<span key={match.index} style={{ color: '#d16969' }}>{matched}</span>);\n } else if (matched.startsWith('[')) {\n parts.push(<span key={match.index} style={{ color: '#4ec9b0' }}>{matched}</span>);\n }\n lastIndex = regex.lastIndex;\n }\n\n if (lastIndex < text.length) {\n parts.push(text.substring(lastIndex));\n }\n\n return parts.length > 0 ? parts : text;\n };\n\n return (\n <div key={index}>\n {processInlineStyles(line)}\n </div>\n );\n }).filter(Boolean);\n}\n\nconst MONO_FONT = 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace';\n\ninterface CreateMarkdownComponentsOpts {\n enableMermaid: boolean;\n enableMarkmap: boolean;\n showLineNumbers: boolean;\n codeStyle: any;\n}\n\nexport function createMarkdownComponents(opts: CreateMarkdownComponentsOpts) {\n const { enableMermaid, enableMarkmap, showLineNumbers, codeStyle } = opts;\n\n return {\n code({ node, className, children, ...props }: any) {\n const fullClassName = className || '';\n const match = /language-(\\w+)/.exec(fullClassName);\n const inline = props.inline;\n const language = match ? match[1] : '';\n\n const metaString = (props as any).dataMeta ||\n (props as any)['data-meta'] || '';\n\n const codeMeta = parseCodeBlockMeta(metaString, fullClassName);\n\n if (!inline && language === 'mermaid' && enableMermaid) {\n return (\n <div\n className=\"mermaid-diagram my-4\"\n data-mermaid-content={String(children).replace(/\\n$/, '')}\n >\n {String(children).replace(/\\n$/, '')}\n </div>\n );\n }\n\n if (!inline && language === 'markmap' && enableMarkmap) {\n return (\n <div\n className=\"markmap-diagram my-4 border border-base-300 rounded-lg overflow-hidden\"\n data-markmap-content={String(children).replace(/\\n$/, '')}\n />\n );\n }\n\n if (!inline && match && language === 'markdown') {\n const code = String(children).replace(/\\n$/, '');\n return (\n <pre\n style={{\n fontFamily: MONO_FONT,\n fontSize: '0.875em',\n borderRadius: '0.5rem',\n padding: '1em',\n margin: 0,\n backgroundColor: 'rgb(30, 30, 30)',\n color: 'rgb(212, 212, 212)',\n overflow: 'auto',\n lineHeight: '1.5',\n }}\n >\n <code style={{ fontFamily: MONO_FONT }}>\n {highlightMarkdown(code)}\n </code>\n </pre>\n );\n }\n\n if (!inline && match) {\n const selectedStyle = resolveMetaTheme(codeMeta.theme, codeStyle);\n\n let shouldShowLineNumbers: boolean | undefined;\n let lineNumbersToShow: number[] | undefined;\n\n if (Array.isArray(codeMeta.showLineNumbers)) {\n shouldShowLineNumbers = true;\n lineNumbersToShow = codeMeta.showLineNumbers;\n } else if (codeMeta.showLineNumbers !== undefined) {\n shouldShowLineNumbers = codeMeta.showLineNumbers as boolean;\n } else {\n shouldShowLineNumbers = showLineNumbers;\n }\n\n const startingLineNumber = codeMeta.startLineNumber || 1;\n const wrapLines = (codeMeta.highlightLines && codeMeta.highlightLines.length > 0) ||\n (lineNumbersToShow && lineNumbersToShow.length > 0);\n\n const codeBlock = (\n <SyntaxHighlighter\n style={selectedStyle as any}\n language={language}\n PreTag=\"div\"\n showLineNumbers={shouldShowLineNumbers}\n startingLineNumber={startingLineNumber}\n customStyle={{\n fontFamily: MONO_FONT,\n fontSize: '0.875em',\n borderRadius: codeMeta.title ? '0 0 0.5rem 0.5rem' : '0.5rem',\n borderTop: codeMeta.title ? 'none' : undefined,\n padding: '1em',\n margin: 0,\n border: 'none',\n boxShadow: 'none',\n lineHeight: '1.5',\n }}\n codeTagProps={{\n style: { fontFamily: MONO_FONT }\n }}\n lineNumberStyle={(lineNumber: number) => {\n const baseStyle: React.CSSProperties = {\n minWidth: '3em',\n paddingRight: '1em',\n userSelect: 'none',\n border: 'none',\n };\n if (lineNumbersToShow) {\n if (lineNumbersToShow.includes(lineNumber)) {\n baseStyle.opacity = 0.5;\n } else {\n baseStyle.opacity = 0;\n baseStyle.visibility = 'hidden';\n }\n } else {\n baseStyle.opacity = 0.5;\n }\n return baseStyle;\n }}\n wrapLines={wrapLines}\n lineProps={(lineNumber: number) => {\n const style: React.CSSProperties = {\n display: 'block',\n border: 'none',\n boxShadow: 'none',\n outline: 'none',\n margin: 0,\n padding: 0,\n };\n if (codeMeta.highlightLines && codeMeta.highlightLines.includes(lineNumber)) {\n style.backgroundColor = 'rgba(255, 255, 0, 0.1)';\n style.display = 'block';\n style.width = '100%';\n }\n return { style };\n }}\n {...props}\n >\n {String(children).replace(/\\n$/, '')}\n </SyntaxHighlighter>\n );\n\n if (codeMeta.title) {\n return (\n <div className=\"my-4\">\n <div\n className=\"px-4 py-2 text-sm font-mono text-base-content bg-base-200 rounded-t-lg border-b border-base-300\"\n style={{ fontFamily: MONO_FONT }}\n >\n {codeMeta.title}\n </div>\n {codeBlock}\n </div>\n );\n }\n\n return codeBlock;\n }\n\n return (\n <code className={className} {...props}>\n {children}\n </code>\n );\n },\n\n table({ node, children, ...props }: any) {\n return (\n <div className=\"overflow-x-auto my-6\">\n <table className=\"table-auto border-collapse w-full\" {...props}>\n {children}\n </table>\n </div>\n );\n },\n thead({ node, children, ...props }: any) {\n return <thead className=\"bg-base-200\" {...props}>{children}</thead>;\n },\n tbody({ node, children, ...props }: any) {\n return <tbody {...props}>{children}</tbody>;\n },\n tr({ node, children, ...props }: any) {\n return <tr className=\"border-b border-base-300 hover:bg-base-100 transition-colors\" {...props}>{children}</tr>;\n },\n th({ node, children, ...props }: any) {\n return <th className=\"px-4 py-3 text-left font-semibold text-base-content border-b-2 border-base-300\" {...props}>{children}</th>;\n },\n td({ node, children, ...props }: any) {\n return <td className=\"px-4 py-3 text-base-content\" {...props}>{children}</td>;\n },\n };\n}\n"],"mappings":";;;;;;AAKA,SAASC,EAAkB,GAAc;CAEvC,OADcC,EAAK,MAAM,IAClB,CAAA,CAAM,KAAK,GAAM,MAAU;EAChC,IAAI,YAAY,KAAKC,CAAI,GAAG;GAC1B,IAAMC,IAAQD,EAAK,MAAM,mBAAmB;GAC5C,IAAIC,GACF,OACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,QAAD;IAAM,OAAO,EAAE,OAAO,UAAU;IAAI,UAAAA,EAAM;GAAS,CAAA,GACnD,kBAAC,QAAD;IAAM,OAAO,EAAE,OAAO,UAAU;IAAI,UAAAA,EAAM;GAAS,CAAA,CAChD,EAAA,GAHKC,CAGL;EAGX;EAEA,IAAI,wBAAwB,KAAKF,CAAI,GAAG;GACtC,IAAMC,IAAQD,EAAK,MAAM,6BAA6B;GACtD,IAAIC,GACF,OACE,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,QAAD,EAAA,UAAOA,EAAM,GAAS,CAAA;IACtB,kBAAC,QAAD;KAAM,OAAO,EAAE,OAAO,UAAU;KAAI,UAAAA,EAAM;IAAS,CAAA;IACnD,kBAAC,QAAD,EAAA,UAAOA,EAAM,GAAS,CAAA;GACnB,EAAA,GAJKC,CAIL;EAGX;EAgDA,OA9CIF,EAAK,WAAW,KAAK,IAErB,kBAAC,OAAD,EAAA,UACE,kBAAC,QAAD;GAAM,OAAO,EAAE,OAAO,UAAU;GAAI,UAAAA;EAAW,CAAA,EAC5C,GAFKE,CAEL,IAIL,OAAO,KAAKF,CAAI,IAEhB,kBAAC,OAAD,EAAA,UACE,kBAAC,QAAD;GAAM,OAAO,EAAE,OAAO,UAAU;GAAI,UAAAA;EAAW,CAAA,EAC5C,GAFKE,CAEL,IAmCP,kBAAC,OAAD,EAAA,YA/B2B,MAAiB;GAC5C,IAAMC,IAA2B,CAAC,GAC9BC,IAAY,GACVC,IAAQ,8DACVJ;GAEJ,QAAQ,IAAQI,EAAM,KAAKN,CAAI,OAAO,OAAM;IAC1C,AAAIE,EAAM,QAAQG,KAChBD,EAAM,KAAKJ,EAAK,UAAUK,GAAWH,EAAM,KAAK,CAAC;IAEnD,IAAMK,IAAUL,EAAM;IAUtB,AATIK,EAAQ,WAAW,IAAI,IACzBH,EAAM,KAAK,kBAAC,QAAD;KAAwB,OAAO;MAAE,OAAO;MAAW,YAAY;KAAO;KAAI,UAAAG;IAAc,GAA7EL,EAAM,KAAuE,CAAC,IAC3FK,EAAQ,WAAW,GAAG,IAC/BH,EAAM,KAAK,kBAAC,QAAD;KAAwB,OAAO;MAAE,OAAO;MAAW,WAAW;KAAS;KAAI,UAAAG;IAAc,GAA9EL,EAAM,KAAwE,CAAC,IAC5FK,EAAQ,WAAW,GAAG,IAC/BH,EAAM,KAAK,kBAAC,QAAD;KAAwB,OAAO,EAAE,OAAO,UAAU;KAAI,UAAAG;IAAc,GAAzDL,EAAM,KAAmD,CAAC,IACvEK,EAAQ,WAAW,GAAG,KAC/BH,EAAM,KAAK,kBAAC,QAAD;KAAwB,OAAO,EAAE,OAAO,UAAU;KAAI,UAAAG;IAAc,GAAzDL,EAAM,KAAmD,CAAC,GAElF,IAAYI,EAAM;GACpB;GAMA,OAJID,IAAYL,EAAK,UACnBI,EAAM,KAAKJ,EAAK,UAAUK,CAAS,CAAC,GAG/BD,EAAM,SAAS,IAAIA,IAAQJ;EACpC,EAIK,CAAoBC,CAAI,EACtB,GAFKE,CAEL;CAET,CAAC,CAAC,CAAC,OAAO,OAAO;AACnB;AAEA,IAAMK,IAAY;AASlB,SAAgBC,EAAyB,GAAoC;CAC3E,IAAM,EAAE,kBAAe,kBAAe,oBAAiB,iBAAcC;CAErE,OAAO;EACL,KAAK,EAAE,SAAM,cAAW,aAAU,GAAGC,KAAc;GACjD,IAAMC,IAAgBC,KAAa,IAC7BX,IAAQ,iBAAiB,KAAKU,CAAa,GAC3CE,IAASH,EAAM,QACfI,IAAWb,IAAQA,EAAM,KAAK,IAE9Bc,IAAcL,EAAc,YAC/BA,EAAc,gBAAgB,IAE3BM,IAAWC,EAAmBF,GAAYJ,CAAa;GAE7D,IAAI,CAACE,KAAUC,MAAa,aAAaI,GACvC,OACE,kBAAC,OAAD;IACE,WAAU;IACV,wBAAsB,OAAOC,CAAQ,CAAC,CAAC,QAAQ,OAAO,EAAE;IAEvD,UAAA,OAAOA,CAAQ,CAAC,CAAC,QAAQ,OAAO,EAAE;GAChC,CAAA;GAIT,IAAI,CAACN,KAAUC,MAAa,aAAaM,GACvC,OACE,kBAAC,OAAD;IACE,WAAU;IACV,wBAAsB,OAAOD,CAAQ,CAAC,CAAC,QAAQ,OAAO,EAAE;GACzD,CAAA;GAIL,IAAI,CAACN,KAAUZ,KAASa,MAAa,YAAY;IAC/C,IAAMO,IAAO,OAAOF,CAAQ,CAAC,CAAC,QAAQ,OAAO,EAAE;IAC/C,OACE,kBAAC,OAAD;KACE,OAAO;MACL,YAAYZ;MACZ,UAAU;MACV,cAAc;MACd,SAAS;MACT,QAAQ;MACR,iBAAiB;MACjB,OAAO;MACP,UAAU;MACV,YAAY;KACd;KAEA,UAAA,kBAAC,QAAD;MAAM,OAAO,EAAE,YAAYA,EAAU;MAClC,UAAAT,EAAkBuB,CAAI;KACnB,CAAA;IACH,CAAA;GAET;GAEA,IAAI,CAACR,KAAUZ,GAAO;IACpB,IAAMqB,IAAgBC,EAAiBP,EAAS,OAAOQ,CAAS,GAE5DC,GACAC;IAEJ,AAAI,MAAM,QAAQV,EAAS,eAAe,KACxC,IAAwB,IACxB,IAAoBA,EAAS,mBACxB,AACLS,IADST,EAAS,oBAAoB,KAAA,IAGdW,IAFAX,EAAS;IAKnC,IAAMY,IAAqBZ,EAAS,mBAAmB,GACjDa,IAAab,EAAS,kBAAkBA,EAAS,eAAe,SAAS,KAC5EU,KAAqBA,EAAkB,SAAS,GAE7CI,IACJ,kBAACjC,GAAD;KACE,OAAOyB;KACG;KACV,QAAO;KACP,iBAAiBG;KACG;KACpB,aAAa;MACX,YAAYlB;MACZ,UAAU;MACV,cAAcS,EAAS,QAAQ,sBAAsB;MACrD,WAAWA,EAAS,QAAQ,SAAS,KAAA;MACrC,SAAS;MACT,QAAQ;MACR,QAAQ;MACR,WAAW;MACX,YAAY;KACd;KACA,cAAc,EACZ,OAAO,EAAE,YAAYT,EAAU,EACjC;KACA,kBAAkB,MAAuB;MACvC,IAAMyB,IAAiC;OACrC,UAAU;OACV,cAAc;OACd,YAAY;OACZ,QAAQ;MACV;MAWA,OAVIN,IACEA,EAAkB,SAASO,CAAU,IACvC,EAAU,UAAU,MAEpB,EAAU,UAAU,GACpB,EAAU,aAAa,YAGzB,EAAU,UAAU,IAEfD;KACT;KACW;KACX,YAAY,MAAuB;MACjC,IAAME,IAA6B;OACjC,SAAS;OACT,QAAQ;OACR,WAAW;OACX,SAAS;OACT,QAAQ;OACR,SAAS;MACX;MAMA,OALIlB,EAAS,kBAAkBA,EAAS,eAAe,SAASiB,CAAU,MACxE,EAAM,kBAAkB,0BACxB,EAAM,UAAU,SAChB,EAAM,QAAQ,SAET,EAAE,SAAM;KACjB;KACA,GAAIvB;KAEH,UAAA,OAAOS,CAAQ,CAAC,CAAC,QAAQ,OAAO,EAAE;IAClB,CAAA;IAiBrB,OAdIH,EAAS,QAET,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,OAAD;MACE,WAAU;MACV,OAAO,EAAE,YAAYT,EAAU;MAE9B,UAAAS,EAAS;KACP,CAAA,GACJc,CACE;SAIFA;GACT;GAEA,OACE,kBAAC,QAAD;IAAiB;IAAW,GAAIpB;IAC7B;GACG,CAAA;EAEV;EAEA,MAAM,EAAE,SAAM,aAAU,GAAGA,KAAc;GACvC,OACE,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,SAAD;KAAO,WAAU;KAAoC,GAAIA;KACtD;IACI,CAAA;GACJ,CAAA;EAET;EACA,MAAM,EAAE,SAAM,aAAU,GAAGA,KAAc;GACvC,OAAO,kBAAC,SAAD;IAAO,WAAU;IAAc,GAAIA;IAAQ;GAAgB,CAAA;EACpE;EACA,MAAM,EAAE,SAAM,aAAU,GAAGA,KAAc;GACvC,OAAO,kBAAC,SAAD;IAAO,GAAIA;IAAQ;GAAgB,CAAA;EAC5C;EACA,GAAG,EAAE,SAAM,aAAU,GAAGA,KAAc;GACpC,OAAO,kBAAC,MAAD;IAAI,WAAU;IAA+D,GAAIA;IAAQ;GAAa,CAAA;EAC/G;EACA,GAAG,EAAE,SAAM,aAAU,GAAGA,KAAc;GACpC,OAAO,kBAAC,MAAD;IAAI,WAAU;IAAiF,GAAIA;IAAQ;GAAa,CAAA;EACjI;EACA,GAAG,EAAE,SAAM,aAAU,GAAGA,KAAc;GACpC,OAAO,kBAAC,MAAD;IAAI,WAAU;IAA8B,GAAIA;IAAQ;GAAa,CAAA;EAC9E;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseCodeBlockMeta.js","names":[],"sources":["../../../src/components/Markdown/parseCodeBlockMeta.ts"],"sourcesContent":["export interface CodeBlockMeta {\n showLineNumbers?: boolean | number[];\n startLineNumber?: number;\n highlightLines?: number[];\n theme?: string;\n title?: string;\n}\n\nfunction parseLineRanges(rangeStr: string): number[] {\n const ranges = rangeStr.split(',').map(s => s.trim());\n const lines: number[] = [];\n ranges.forEach(range => {\n if (range.includes('-')) {\n const [start, end] = range.split('-').map(n => parseInt(n.trim(), 10));\n for (let i = start; i <= end; i++) {\n lines.push(i);\n }\n } else {\n lines.push(parseInt(range, 10));\n }\n });\n return lines;\n}\n\nexport function parseCodeBlockMeta(metaStr: string, classStr: string): CodeBlockMeta {\n const meta: CodeBlockMeta = {};\n const fullMeta = `${metaStr} ${classStr}`;\n\n const titleMatch = fullMeta.match(/title[=:][\"']([^\"']+)[\"']/);\n if (titleMatch) {\n meta.title = titleMatch[1];\n }\n\n const themeMatch = fullMeta.match(/theme[=:][\"']?([^\"'\\s]+)[\"']?/);\n if (themeMatch) {\n meta.theme = themeMatch[1];\n }\n\n const startLineMatch = fullMeta.match(/startLineNumber[=:](\\d+)/);\n if (startLineMatch) {\n meta.startLineNumber = parseInt(startLineMatch[1], 10);\n }\n\n const highlightMatch = fullMeta.match(/\\{([\\d,\\-\\s]+)\\}/);\n if (highlightMatch) {\n meta.highlightLines = parseLineRanges(highlightMatch[1]);\n }\n\n const showLineNumbersMatch = fullMeta.match(/showLineNumbers\\s*\\{([\\d,\\-\\s]+)\\}/);\n if (showLineNumbersMatch) {\n meta.showLineNumbers = parseLineRanges(showLineNumbersMatch[1]);\n } else if (/showLineNumbers/.test(fullMeta)) {\n meta.showLineNumbers = true;\n }\n\n return meta;\n}\n"],"mappings":";AAQA,
|
|
1
|
+
{"version":3,"file":"parseCodeBlockMeta.js","names":["parseLineRanges","ranges","rangeStr","s","lines","range","start","end","n","i","parseCodeBlockMeta","meta","fullMeta","metaStr","classStr","titleMatch","themeMatch","startLineMatch","highlightMatch","showLineNumbersMatch"],"sources":["../../../src/components/Markdown/parseCodeBlockMeta.ts"],"sourcesContent":["export interface CodeBlockMeta {\n showLineNumbers?: boolean | number[];\n startLineNumber?: number;\n highlightLines?: number[];\n theme?: string;\n title?: string;\n}\n\nfunction parseLineRanges(rangeStr: string): number[] {\n const ranges = rangeStr.split(',').map(s => s.trim());\n const lines: number[] = [];\n ranges.forEach(range => {\n if (range.includes('-')) {\n const [start, end] = range.split('-').map(n => parseInt(n.trim(), 10));\n for (let i = start; i <= end; i++) {\n lines.push(i);\n }\n } else {\n lines.push(parseInt(range, 10));\n }\n });\n return lines;\n}\n\nexport function parseCodeBlockMeta(metaStr: string, classStr: string): CodeBlockMeta {\n const meta: CodeBlockMeta = {};\n const fullMeta = `${metaStr} ${classStr}`;\n\n const titleMatch = fullMeta.match(/title[=:][\"']([^\"']+)[\"']/);\n if (titleMatch) {\n meta.title = titleMatch[1];\n }\n\n const themeMatch = fullMeta.match(/theme[=:][\"']?([^\"'\\s]+)[\"']?/);\n if (themeMatch) {\n meta.theme = themeMatch[1];\n }\n\n const startLineMatch = fullMeta.match(/startLineNumber[=:](\\d+)/);\n if (startLineMatch) {\n meta.startLineNumber = parseInt(startLineMatch[1], 10);\n }\n\n const highlightMatch = fullMeta.match(/\\{([\\d,\\-\\s]+)\\}/);\n if (highlightMatch) {\n meta.highlightLines = parseLineRanges(highlightMatch[1]);\n }\n\n const showLineNumbersMatch = fullMeta.match(/showLineNumbers\\s*\\{([\\d,\\-\\s]+)\\}/);\n if (showLineNumbersMatch) {\n meta.showLineNumbers = parseLineRanges(showLineNumbersMatch[1]);\n } else if (/showLineNumbers/.test(fullMeta)) {\n meta.showLineNumbers = true;\n }\n\n return meta;\n}\n"],"mappings":";AAQA,SAASA,EAAgB,GAA4B;CACnD,IAAMC,IAASC,EAAS,MAAM,GAAG,CAAC,CAAC,KAAI,MAAKC,EAAE,KAAK,CAAC,GAC9CC,IAAkB,CAAC;CAWzB,OAVAH,EAAO,SAAQ,MAAS;EACtB,IAAII,EAAM,SAAS,GAAG,GAAG;GACvB,IAAM,CAACC,GAAOC,KAAOF,EAAM,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,SAASG,EAAE,KAAK,GAAG,EAAE,CAAC;GACrE,KAAK,IAAIC,IAAIH,GAAOG,KAAKF,GAAK,KAC5B,EAAM,KAAKE,CAAC;EAEhB,OACE,EAAM,KAAK,SAASJ,GAAO,EAAE,CAAC;CAElC,CAAC,GACMD;AACT;AAEA,SAAgBM,EAAmB,GAAiB,GAAiC;CACnF,IAAMC,IAAsB,CAAC,GACvBC,IAAW,GAAGC,EAAQ,GAAGC,KAEzBC,IAAaH,EAAS,MAAM,2BAA2B;CAC7D,AAAIG,MACF,EAAK,QAAQA,EAAW;CAG1B,IAAMC,IAAaJ,EAAS,MAAM,+BAA+B;CACjE,AAAII,MACF,EAAK,QAAQA,EAAW;CAG1B,IAAMC,IAAiBL,EAAS,MAAM,0BAA0B;CAChE,AAAIK,MACF,EAAK,kBAAkB,SAASA,EAAe,IAAI,EAAE;CAGvD,IAAMC,IAAiBN,EAAS,MAAM,kBAAkB;CACxD,AAAIM,MACF,EAAK,iBAAiBlB,EAAgBkB,EAAe,EAAE;CAGzD,IAAMC,IAAuBP,EAAS,MAAM,oCAAoC;CAOhF,OANIO,IACF,EAAK,kBAAkBnB,EAAgBmB,EAAqB,EAAE,IACrD,kBAAkB,KAAKP,CAAQ,MACxC,EAAK,kBAAkB,KAGlBD;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMarkdownSource.js","names":[],"sources":["../../../src/components/Markdown/useMarkdownSource.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport type { MarkdownSource, MarkdownProps } from './Markdown';\n\nasync function fetchFromS3(\n s3Url: string,\n config?: MarkdownProps['s3Config'],\n signal?: AbortSignal,\n): Promise<string> {\n const match = /^s3:\\/\\/([^/]+)\\/(.+)$/.exec(s3Url);\n if (!match) {\n throw new Error('Invalid S3 URL format. Expected: s3://bucket/key');\n }\n\n const [, bucket, key] = match;\n const region = config?.region || 'us-east-1';\n const endpoint = config?.endpoint || `https://${bucket}.s3.${region}.amazonaws.com`;\n const url = `${endpoint}/${key}`;\n\n const response = await fetch(url, { signal });\n if (!response.ok) {\n throw new Error(`S3 fetch failed: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n}\n\nexport function useMarkdownSource(\n source: MarkdownSource,\n content: string,\n s3Config?: MarkdownProps['s3Config'],\n onLoad?: (content: string) => void,\n onError?: (error: Error) => void,\n) {\n const [markdown, setMarkdown] = useState<string>('');\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Callback identity is not a source change; notify the latest committed callbacks.\n const callbacks = useRef({ onLoad, onError });\n useEffect(() => {\n callbacks.current = { onLoad, onError };\n }, [onLoad, onError]);\n\n const region = s3Config?.region;\n const endpoint = s3Config?.endpoint;\n\n useEffect(() => {\n const controller = new AbortController();\n const { signal } = controller;\n\n const fetchContent = async () => {\n setError(null);\n if (source === 'text') {\n setMarkdown(content);\n setLoading(false);\n callbacks.current.onLoad?.(content);\n return;\n }\n\n setLoading(true);\n setMarkdown('');\n\n try {\n let text: string;\n\n if (source === 'url') {\n const response = await fetch(content, { signal });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n text = await response.text();\n } else if (source === 's3') {\n text = await fetchFromS3(content, { region, endpoint }, signal);\n } else {\n throw new Error(`Unsupported source type: ${source}`);\n }\n\n if (signal.aborted) return;\n setMarkdown(text);\n callbacks.current.onLoad?.(text);\n } catch (err) {\n if (signal.aborted) return;\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n callbacks.current.onError?.(error);\n } finally {\n if (!signal.aborted) setLoading(false);\n }\n };\n\n fetchContent();\n return () => controller.abort();\n }, [source, content, region, endpoint]);\n\n return { markdown, loading, error };\n}\n"],"mappings":";;AAGA,
|
|
1
|
+
{"version":3,"file":"useMarkdownSource.js","names":["fetchFromS3","match","s3Url","bucket","key","region","config","url","response","useMarkdownSource","markdown","setMarkdown","useState","loading","setLoading","error","setError","callbacks","useRef","onLoad","onError","s3Config","endpoint","useEffect","controller","source","content","text","signal","err"],"sources":["../../../src/components/Markdown/useMarkdownSource.ts"],"sourcesContent":["import { useState, useEffect, useRef } from 'react';\nimport type { MarkdownSource, MarkdownProps } from './Markdown';\n\nasync function fetchFromS3(\n s3Url: string,\n config?: MarkdownProps['s3Config'],\n signal?: AbortSignal,\n): Promise<string> {\n const match = /^s3:\\/\\/([^/]+)\\/(.+)$/.exec(s3Url);\n if (!match) {\n throw new Error('Invalid S3 URL format. Expected: s3://bucket/key');\n }\n\n const [, bucket, key] = match;\n const region = config?.region || 'us-east-1';\n const endpoint = config?.endpoint || `https://${bucket}.s3.${region}.amazonaws.com`;\n const url = `${endpoint}/${key}`;\n\n const response = await fetch(url, { signal });\n if (!response.ok) {\n throw new Error(`S3 fetch failed: ${response.status} ${response.statusText}`);\n }\n\n return response.text();\n}\n\nexport function useMarkdownSource(\n source: MarkdownSource,\n content: string,\n s3Config?: MarkdownProps['s3Config'],\n onLoad?: (content: string) => void,\n onError?: (error: Error) => void,\n) {\n const [markdown, setMarkdown] = useState<string>('');\n const [loading, setLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Callback identity is not a source change; notify the latest committed callbacks.\n const callbacks = useRef({ onLoad, onError });\n useEffect(() => {\n callbacks.current = { onLoad, onError };\n }, [onLoad, onError]);\n\n const region = s3Config?.region;\n const endpoint = s3Config?.endpoint;\n\n useEffect(() => {\n const controller = new AbortController();\n const { signal } = controller;\n\n const fetchContent = async () => {\n setError(null);\n if (source === 'text') {\n setMarkdown(content);\n setLoading(false);\n callbacks.current.onLoad?.(content);\n return;\n }\n\n setLoading(true);\n setMarkdown('');\n\n try {\n let text: string;\n\n if (source === 'url') {\n const response = await fetch(content, { signal });\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n text = await response.text();\n } else if (source === 's3') {\n text = await fetchFromS3(content, { region, endpoint }, signal);\n } else {\n throw new Error(`Unsupported source type: ${source}`);\n }\n\n if (signal.aborted) return;\n setMarkdown(text);\n callbacks.current.onLoad?.(text);\n } catch (err) {\n if (signal.aborted) return;\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n callbacks.current.onError?.(error);\n } finally {\n if (!signal.aborted) setLoading(false);\n }\n };\n\n fetchContent();\n return () => controller.abort();\n }, [source, content, region, endpoint]);\n\n return { markdown, loading, error };\n}\n"],"mappings":";;AAGA,eAAeA,EACb,GACA,GACA,GACiB;CACjB,IAAMC,IAAQ,yBAAyB,KAAKC,CAAK;CACjD,IAAI,CAACD,GACH,MAAU,MAAM,kDAAkD;CAGpE,IAAM,GAAGE,GAAQC,KAAOH,GAClBI,IAASC,GAAQ,UAAU,aAE3BC,IAAM,GADKD,GAAQ,YAAY,WAAWH,EAAO,MAAME,EAAO,gBAC5C,GAAGD,KAErBI,IAAW,MAAM,MAAMD,GAAK,EAAE,UAAO,CAAC;CAC5C,IAAI,CAACC,EAAS,IACZ,MAAU,MAAM,oBAAoBA,EAAS,OAAO,GAAGA,EAAS,YAAY;CAG9E,OAAOA,EAAS,KAAK;AACvB;AAEA,SAAgBC,EACd,GACA,GACA,GACA,GACA,GACA;CACA,IAAM,CAACC,GAAUC,KAAeC,EAAiB,EAAE,GAC7C,CAACC,GAASC,KAAcF,EAAkB,EAAK,GAC/C,CAACG,GAAOC,KAAYJ,EAAuB,IAAI,GAG/CK,IAAYC,EAAO;EAAE;EAAQ;CAAQ,CAAC;CAC5C,QAAgB;EACd,EAAU,UAAU;GAAE;GAAQ;EAAQ;CACxC,GAAG,CAACC,GAAQC,CAAO,CAAC;CAEpB,IAAMf,IAASgB,GAAU,QACnBC,IAAWD,GAAU;CAkD3B,OAhDAE,QAAgB;EACd,IAAMC,IAAa,IAAI,gBAAgB,GACjC,EAAE,cAAWA;EA2CnB,QADA,YAxCiC;GAE/B,IADAR,EAAS,IAAI,GACTS,MAAW,QAAQ;IAGrB,AAFAd,EAAYe,CAAO,GACnBZ,EAAW,EAAK,GAChBG,EAAU,QAAQ,SAASS,CAAO;IAClC;GACF;GAGA,AADAZ,EAAW,EAAI,GACfH,EAAY,EAAE;GAEd,IAAI;IACF,IAAIgB;IAEJ,IAAIF,MAAW,OAAO;KACpB,IAAMjB,IAAW,MAAM,MAAMkB,GAAS,EAAE,UAAO,CAAC;KAChD,IAAI,CAAClB,EAAS,IACZ,MAAU,MAAM,uBAAuBA,EAAS,QAAQ;KAE1D,IAAO,MAAMA,EAAS,KAAK;IAC7B,OAAO,IAAIiB,MAAW,MACpB,IAAO,MAAMzB,EAAY0B,GAAS;KAAE;KAAQ;IAAS,GAAGE,CAAM;SAE9D,MAAU,MAAM,4BAA4BH,GAAQ;IAGtD,IAAIG,EAAO,SAAS;IAEpB,AADAjB,EAAYgB,CAAI,GAChBV,EAAU,QAAQ,SAASU,CAAI;GACjC,SAASE,GAAK;IACZ,IAAID,EAAO,SAAS;IACpB,IAAMb,IAAQc,aAAe,QAAQA,IAAU,MAAM,OAAOA,CAAG,CAAC;IAEhE,AADAb,EAASD,CAAK,GACdE,EAAU,QAAQ,UAAUF,CAAK;GACnC,UAAU;IACR,AAAKa,EAAO,WAASd,EAAW,EAAK;GACvC;EACF,EAEA,CAAa,SACAU,EAAW,MAAM;CAChC,GAAG;EAACC;EAAQC;EAASrB;EAAQiB;CAAQ,CAAC,GAE/B;EAAE;EAAU;EAAS;CAAM;AACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMarkmapRenderer.js","names":[],"sources":["../../../src/components/Markdown/useMarkmapRenderer.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { Transformer } from 'markmap-lib';\nimport { Markmap } from 'markmap-view';\n\ninterface Diagram {\n code: string;\n output: ChildNode | null;\n instance?: Markmap;\n timer?: ReturnType<typeof setTimeout>;\n}\n\nfunction dispose(element: HTMLElement, diagram: Diagram) {\n clearTimeout(diagram.timer);\n const instance = diagram.instance;\n diagram.instance = undefined;\n if (instance) {\n // destroy disconnects Markmap's observer/refresh subscription. Stop D3's\n // transitions and pan listener too, before removing the owned SVG.\n instance.svg.interrupt();\n instance.svg.selectAll('*').interrupt();\n instance.svg.on('wheel', null);\n instance.destroy();\n }\n if (diagram.output && element.firstChild === diagram.output) {\n element.replaceChildren();\n }\n}\n\nexport function useMarkmapRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n const diagrams = useRef(new Map<HTMLElement, Diagram>());\n const transformer = useRef<Transformer | null>(null);\n\n useEffect(() => {\n const entries = diagrams.current;\n return () => {\n entries.forEach((diagram, element) => dispose(element, diagram));\n entries.clear();\n };\n }, []);\n\n useEffect(() => {\n const entries = diagrams.current;\n const container = containerRef.current;\n const elements = new Set(enabled && markdown && container\n ? container.querySelectorAll<HTMLElement>('.markmap-diagram') : []);\n\n entries.forEach((diagram, element) => {\n if (!elements.has(element) || element.getAttribute('data-markmap-content') !== diagram.code ||\n (diagram.output && element.firstChild !== diagram.output)) {\n entries.delete(element);\n dispose(element, diagram);\n }\n });\n\n elements.forEach(element => {\n if (entries.has(element)) return;\n const code = element.getAttribute('data-markmap-content') || '';\n if (!code.trim()) return;\n const diagram: Diagram = { code, output: null };\n entries.set(element, diagram);\n const canCommit = () => entries.get(element) === diagram &&\n containerRef.current === container && container?.contains(element) &&\n element.getAttribute('data-markmap-content') === code &&\n (!diagram.output || element.firstChild === diagram.output);\n\n diagram.timer = setTimeout(async () => {\n if (!canCommit()) return;\n try {\n transformer.current ??= new Transformer();\n const { root } = transformer.current.transform(code);\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.style.width = '100%';\n svg.style.height = '500px';\n element.replaceChildren(svg);\n diagram.output = svg;\n // Keep the instance before starting asynchronous layout, so cleanup\n // can destroy it and a superseded layout never starts a late fit.\n const instance = Markmap.create(svg, {});\n diagram.instance = instance;\n await instance.setData(root);\n if (canCommit()) await instance.fit();\n } catch (err) {\n if (!canCommit()) return;\n dispose(element, diagram);\n console.error('Markmap render error:', err);\n const fallback = document.createElement('pre');\n fallback.className = 'text-error';\n fallback.textContent = `Markmap 渲染失败: ${err}`;\n element.replaceChildren(fallback);\n diagram.output = fallback;\n }\n }, 100);\n });\n });\n}\n"],"mappings":";;;;AAWA,
|
|
1
|
+
{"version":3,"file":"useMarkmapRenderer.js","names":["dispose","diagram","instance","element","useMarkmapRenderer","diagrams","useRef","transformer","useEffect","entries","container","containerRef","elements","enabled","markdown","code","canCommit","Transformer","svg","Markmap","root","err","fallback"],"sources":["../../../src/components/Markdown/useMarkmapRenderer.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { Transformer } from 'markmap-lib';\nimport { Markmap } from 'markmap-view';\n\ninterface Diagram {\n code: string;\n output: ChildNode | null;\n instance?: Markmap;\n timer?: ReturnType<typeof setTimeout>;\n}\n\nfunction dispose(element: HTMLElement, diagram: Diagram) {\n clearTimeout(diagram.timer);\n const instance = diagram.instance;\n diagram.instance = undefined;\n if (instance) {\n // destroy disconnects Markmap's observer/refresh subscription. Stop D3's\n // transitions and pan listener too, before removing the owned SVG.\n instance.svg.interrupt();\n instance.svg.selectAll('*').interrupt();\n instance.svg.on('wheel', null);\n instance.destroy();\n }\n if (diagram.output && element.firstChild === diagram.output) {\n element.replaceChildren();\n }\n}\n\nexport function useMarkmapRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n const diagrams = useRef(new Map<HTMLElement, Diagram>());\n const transformer = useRef<Transformer | null>(null);\n\n useEffect(() => {\n const entries = diagrams.current;\n return () => {\n entries.forEach((diagram, element) => dispose(element, diagram));\n entries.clear();\n };\n }, []);\n\n useEffect(() => {\n const entries = diagrams.current;\n const container = containerRef.current;\n const elements = new Set(enabled && markdown && container\n ? container.querySelectorAll<HTMLElement>('.markmap-diagram') : []);\n\n entries.forEach((diagram, element) => {\n if (!elements.has(element) || element.getAttribute('data-markmap-content') !== diagram.code ||\n (diagram.output && element.firstChild !== diagram.output)) {\n entries.delete(element);\n dispose(element, diagram);\n }\n });\n\n elements.forEach(element => {\n if (entries.has(element)) return;\n const code = element.getAttribute('data-markmap-content') || '';\n if (!code.trim()) return;\n const diagram: Diagram = { code, output: null };\n entries.set(element, diagram);\n const canCommit = () => entries.get(element) === diagram &&\n containerRef.current === container && container?.contains(element) &&\n element.getAttribute('data-markmap-content') === code &&\n (!diagram.output || element.firstChild === diagram.output);\n\n diagram.timer = setTimeout(async () => {\n if (!canCommit()) return;\n try {\n transformer.current ??= new Transformer();\n const { root } = transformer.current.transform(code);\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.style.width = '100%';\n svg.style.height = '500px';\n element.replaceChildren(svg);\n diagram.output = svg;\n // Keep the instance before starting asynchronous layout, so cleanup\n // can destroy it and a superseded layout never starts a late fit.\n const instance = Markmap.create(svg, {});\n diagram.instance = instance;\n await instance.setData(root);\n if (canCommit()) await instance.fit();\n } catch (err) {\n if (!canCommit()) return;\n dispose(element, diagram);\n console.error('Markmap render error:', err);\n const fallback = document.createElement('pre');\n fallback.className = 'text-error';\n fallback.textContent = `Markmap 渲染失败: ${err}`;\n element.replaceChildren(fallback);\n diagram.output = fallback;\n }\n }, 100);\n });\n });\n}\n"],"mappings":";;;;AAWA,SAASA,EAAQ,GAAsB,GAAkB;CACvD,aAAaC,EAAQ,KAAK;CAC1B,IAAMC,IAAWD,EAAQ;CAUzB,AATA,EAAQ,WAAW,KAAA,GACfC,MAGFA,EAAS,IAAI,UAAU,GACvBA,EAAS,IAAI,UAAU,GAAG,CAAC,CAAC,UAAU,GACtCA,EAAS,IAAI,GAAG,SAAS,IAAI,GAC7BA,EAAS,QAAQ,IAEfD,EAAQ,UAAUE,EAAQ,eAAeF,EAAQ,UACnDE,EAAQ,gBAAgB;AAE5B;AAEA,SAAgBC,EACd,GACA,GACA,GACA;CACA,IAAMC,IAAWC,kBAAO,IAAI,IAA0B,CAAC,GACjDC,IAAcD,EAA2B,IAAI;CAUnD,AARAE,QAAgB;EACd,IAAMC,IAAUJ,EAAS;EACzB,aAAa;GAEX,AADAI,EAAQ,SAAS,GAAS,MAAYT,EAAQG,GAASF,CAAO,CAAC,GAC/DQ,EAAQ,MAAM;EAChB;CACF,GAAG,CAAC,CAAC,GAELD,QAAgB;EACd,IAAMC,IAAUJ,EAAS,SACnBK,IAAYC,EAAa,SACzBC,IAAW,IAAI,IAAIC,KAAWC,KAAYJ,IAC5CA,EAAU,iBAA8B,kBAAkB,IAAI,CAAC,CAAC;EAUpE,AARAD,EAAQ,SAAS,GAAS,MAAY;GACpC,CAAI,CAACG,EAAS,IAAIT,CAAO,KAAKA,EAAQ,aAAa,sBAAsB,MAAMF,EAAQ,QAClFA,EAAQ,UAAUE,EAAQ,eAAeF,EAAQ,YACpDQ,EAAQ,OAAON,CAAO,GACtBH,EAAQG,GAASF,CAAO;EAE5B,CAAC,GAEDW,EAAS,SAAQ,MAAW;GAC1B,IAAIH,EAAQ,IAAIN,CAAO,GAAG;GAC1B,IAAMY,IAAOZ,EAAQ,aAAa,sBAAsB,KAAK;GAC7D,IAAI,CAACY,EAAK,KAAK,GAAG;GAClB,IAAMd,IAAmB;IAAE;IAAM,QAAQ;GAAK;GAC9C,EAAQ,IAAIE,GAASF,CAAO;GAC5B,IAAMe,UAAkBP,EAAQ,IAAIN,CAAO,MAAMF,KAC/CU,EAAa,YAAYD,KAAaA,GAAW,SAASP,CAAO,KACjEA,EAAQ,aAAa,sBAAsB,MAAMY,MAChD,CAACd,EAAQ,UAAUE,EAAQ,eAAeF,EAAQ;GAErD,EAAQ,QAAQ,WAAW,YAAY;IACrC,IAAKe,EAAU,GACf,IAAI;KACF,EAAY,YAAY,IAAIC,EAAY;KACxC,IAAM,EAAE,YAASV,EAAY,QAAQ,UAAUQ,CAAI,GAC7CG,IAAM,SAAS,gBAAgB,8BAA8B,KAAK;KAIxE,AAHA,EAAI,MAAM,QAAQ,QAClB,EAAI,MAAM,SAAS,SACnBf,EAAQ,gBAAgBe,CAAG,GAC3B,EAAQ,SAASA;KAGjB,IAAMhB,IAAWiB,EAAQ,OAAOD,GAAK,CAAC,CAAC;KAGvC,AAFA,EAAQ,WAAWhB,GACnB,MAAMA,EAAS,QAAQkB,CAAI,GACvBJ,EAAU,KAAG,MAAMd,EAAS,IAAI;IACtC,SAASmB,GAAK;KACZ,IAAI,CAACL,EAAU,GAAG;KAElB,AADAhB,EAAQG,GAASF,CAAO,GACxB,QAAQ,MAAM,yBAAyBoB,CAAG;KAC1C,IAAMC,IAAW,SAAS,cAAc,KAAK;KAI7C,AAHA,EAAS,YAAY,cACrB,EAAS,cAAc,iBAAiBD,KACxClB,EAAQ,gBAAgBmB,CAAQ,GAChC,EAAQ,SAASA;IACnB;GACF,GAAG,GAAG;EACR,CAAC;CACH,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMermaidRenderer.js","names":[],"sources":["../../../src/components/Markdown/useMermaidRenderer.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport mermaid from 'mermaid';\n\ninterface Diagram {\n code: string;\n output: ChildNode | null;\n timer?: ReturnType<typeof setTimeout>;\n}\n\n// Shared across hook instances, including renders started in the same millisecond.\nlet nextRenderId = 0;\n\nfunction readSource(element: HTMLElement, diagram?: Diagram): string {\n const source = element.getAttribute('data-mermaid-content');\n if (source !== null) return source;\n // Retain compatibility with text-only hook consumers without parsing our SVG.\n if (diagram?.output && element.firstChild === diagram.output) return diagram.code;\n return element.querySelector('svg') ? '' : element.textContent || '';\n}\n\nfunction dispose(element: HTMLElement, diagram: Diagram) {\n clearTimeout(diagram.timer);\n if (diagram.output && element.firstChild === diagram.output) {\n // An attribute-only consumer may already have supplied a new (or empty) source.\n element.textContent = readSource(element, diagram);\n }\n}\n\nexport function useMermaidRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n const initialized = useRef(false);\n const diagrams = useRef(new Map<HTMLElement, Diagram>());\n\n useEffect(() => {\n const entries = diagrams.current;\n return () => {\n entries.forEach((diagram, element) => dispose(element, diagram));\n entries.clear();\n };\n }, []);\n\n // Reconcile every commit: loading/visibility may replace the container even\n // when the markdown string is unchanged. Only changed blocks schedule work.\n useEffect(() => {\n if (enabled && !initialized.current) {\n mermaid.initialize({\n startOnLoad: false,\n theme: 'default',\n securityLevel: 'strict',\n htmlLabels: false,\n fontFamily: 'inherit',\n flowchart: { useMaxWidth: true, htmlLabels: false },\n });\n initialized.current = true;\n }\n\n const entries = diagrams.current;\n const container = containerRef.current;\n const elements = new Set(enabled && markdown && container\n ? container.querySelectorAll<HTMLElement>('.mermaid-diagram') : []);\n\n entries.forEach((diagram, element) => {\n if (!elements.has(element) || readSource(element, diagram) !== diagram.code ||\n (diagram.output && element.firstChild !== diagram.output)) {\n entries.delete(element);\n dispose(element, diagram);\n }\n });\n\n elements.forEach(element => {\n if (entries.has(element)) return;\n const code = readSource(element);\n if (!code.trim()) return;\n const diagram: Diagram = { code, output: null };\n entries.set(element, diagram);\n const canCommit = () => entries.get(element) === diagram &&\n containerRef.current === container && container?.contains(element) &&\n readSource(element, diagram) === code;\n\n diagram.timer = setTimeout(async () => {\n if (!canCommit()) return;\n try {\n const { svg } = await mermaid.render(`dishui-mermaid-${++nextRenderId}`, code);\n if (!canCommit()) return;\n element.innerHTML = svg;\n diagram.output = element.firstChild;\n } catch (err) {\n if (!canCommit()) return;\n console.error('Mermaid render error:', err);\n const fallback = document.createElement('pre');\n fallback.className = 'text-error';\n fallback.textContent = code;\n element.replaceChildren(fallback);\n diagram.output = fallback;\n }\n }, 100);\n });\n });\n}\n"],"mappings":";;;AAUA,
|
|
1
|
+
{"version":3,"file":"useMermaidRenderer.js","names":["mermaid","nextRenderId","readSource","source","element","diagram","dispose","useMermaidRenderer","initialized","useRef","diagrams","useEffect","entries","enabled","container","containerRef","elements","markdown","code","canCommit","svg","err","fallback"],"sources":["../../../src/components/Markdown/useMermaidRenderer.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport mermaid from 'mermaid';\n\ninterface Diagram {\n code: string;\n output: ChildNode | null;\n timer?: ReturnType<typeof setTimeout>;\n}\n\n// Shared across hook instances, including renders started in the same millisecond.\nlet nextRenderId = 0;\n\nfunction readSource(element: HTMLElement, diagram?: Diagram): string {\n const source = element.getAttribute('data-mermaid-content');\n if (source !== null) return source;\n // Retain compatibility with text-only hook consumers without parsing our SVG.\n if (diagram?.output && element.firstChild === diagram.output) return diagram.code;\n return element.querySelector('svg') ? '' : element.textContent || '';\n}\n\nfunction dispose(element: HTMLElement, diagram: Diagram) {\n clearTimeout(diagram.timer);\n if (diagram.output && element.firstChild === diagram.output) {\n // An attribute-only consumer may already have supplied a new (or empty) source.\n element.textContent = readSource(element, diagram);\n }\n}\n\nexport function useMermaidRenderer(\n containerRef: React.RefObject<HTMLDivElement | null>,\n markdown: string,\n enabled: boolean,\n) {\n const initialized = useRef(false);\n const diagrams = useRef(new Map<HTMLElement, Diagram>());\n\n useEffect(() => {\n const entries = diagrams.current;\n return () => {\n entries.forEach((diagram, element) => dispose(element, diagram));\n entries.clear();\n };\n }, []);\n\n // Reconcile every commit: loading/visibility may replace the container even\n // when the markdown string is unchanged. Only changed blocks schedule work.\n useEffect(() => {\n if (enabled && !initialized.current) {\n mermaid.initialize({\n startOnLoad: false,\n theme: 'default',\n securityLevel: 'strict',\n htmlLabels: false,\n fontFamily: 'inherit',\n flowchart: { useMaxWidth: true, htmlLabels: false },\n });\n initialized.current = true;\n }\n\n const entries = diagrams.current;\n const container = containerRef.current;\n const elements = new Set(enabled && markdown && container\n ? container.querySelectorAll<HTMLElement>('.mermaid-diagram') : []);\n\n entries.forEach((diagram, element) => {\n if (!elements.has(element) || readSource(element, diagram) !== diagram.code ||\n (diagram.output && element.firstChild !== diagram.output)) {\n entries.delete(element);\n dispose(element, diagram);\n }\n });\n\n elements.forEach(element => {\n if (entries.has(element)) return;\n const code = readSource(element);\n if (!code.trim()) return;\n const diagram: Diagram = { code, output: null };\n entries.set(element, diagram);\n const canCommit = () => entries.get(element) === diagram &&\n containerRef.current === container && container?.contains(element) &&\n readSource(element, diagram) === code;\n\n diagram.timer = setTimeout(async () => {\n if (!canCommit()) return;\n try {\n const { svg } = await mermaid.render(`dishui-mermaid-${++nextRenderId}`, code);\n if (!canCommit()) return;\n element.innerHTML = svg;\n diagram.output = element.firstChild;\n } catch (err) {\n if (!canCommit()) return;\n console.error('Mermaid render error:', err);\n const fallback = document.createElement('pre');\n fallback.className = 'text-error';\n fallback.textContent = code;\n element.replaceChildren(fallback);\n diagram.output = fallback;\n }\n }, 100);\n });\n });\n}\n"],"mappings":";;;AAUA,IAAIC,IAAe;AAEnB,SAASC,EAAW,GAAsB,GAA2B;CACnE,IAAMC,IAASC,EAAQ,aAAa,sBAAsB;CAI1D,OAHID,MAAW,OAEXE,GAAS,UAAUD,EAAQ,eAAeC,EAAQ,SAAeA,EAAQ,OACtED,EAAQ,cAAc,KAAK,IAAI,KAAKA,EAAQ,eAAe,KAHtCD;AAI9B;AAEA,SAASG,EAAQ,GAAsB,GAAkB;CAEvD,AADA,aAAaD,EAAQ,KAAK,GACtBA,EAAQ,UAAUD,EAAQ,eAAeC,EAAQ,WAEnD,EAAQ,cAAcH,EAAWE,GAASC,CAAO;AAErD;AAEA,SAAgBE,EACd,GACA,GACA,GACA;CACA,IAAMC,IAAcC,EAAO,EAAK,GAC1BC,IAAWD,kBAAO,IAAI,IAA0B,CAAC;CAYvD,AAVAE,QAAgB;EACd,IAAMC,IAAUF,EAAS;EACzB,aAAa;GAEX,AADAE,EAAQ,SAAS,GAAS,MAAYN,EAAQF,GAASC,CAAO,CAAC,GAC/DO,EAAQ,MAAM;EAChB;CACF,GAAG,CAAC,CAAC,GAILD,QAAgB;EACd,AAAIE,KAAW,CAACL,EAAY,YAC1BR,EAAQ,WAAW;GACjB,aAAa;GACb,OAAO;GACP,eAAe;GACf,YAAY;GACZ,YAAY;GACZ,WAAW;IAAE,aAAa;IAAM,YAAY;GAAM;EACpD,CAAC,GACD,EAAY,UAAU;EAGxB,IAAMY,IAAUF,EAAS,SACnBI,IAAYC,EAAa,SACzBC,IAAW,IAAI,IAAIH,KAAWI,KAAYH,IAC5CA,EAAU,iBAA8B,kBAAkB,IAAI,CAAC,CAAC;EAUpE,AARAF,EAAQ,SAAS,GAAS,MAAY;GACpC,CAAI,CAACI,EAAS,IAAIZ,CAAO,KAAKF,EAAWE,GAASC,CAAO,MAAMA,EAAQ,QAClEA,EAAQ,UAAUD,EAAQ,eAAeC,EAAQ,YACpDO,EAAQ,OAAOR,CAAO,GACtBE,EAAQF,GAASC,CAAO;EAE5B,CAAC,GAEDW,EAAS,SAAQ,MAAW;GAC1B,IAAIJ,EAAQ,IAAIR,CAAO,GAAG;GAC1B,IAAMc,IAAOhB,EAAWE,CAAO;GAC/B,IAAI,CAACc,EAAK,KAAK,GAAG;GAClB,IAAMb,IAAmB;IAAE;IAAM,QAAQ;GAAK;GAC9C,EAAQ,IAAID,GAASC,CAAO;GAC5B,IAAMc,UAAkBP,EAAQ,IAAIR,CAAO,MAAMC,KAC/CU,EAAa,YAAYD,KAAaA,GAAW,SAASV,CAAO,KACjEF,EAAWE,GAASC,CAAO,MAAMa;GAEnC,EAAQ,QAAQ,WAAW,YAAY;IACrC,IAAKC,EAAU,GACf,IAAI;KACF,IAAM,EAAE,WAAQ,MAAMnB,EAAQ,OAAO,kBAAkB,EAAEC,KAAgBiB,CAAI;KAC7E,IAAI,CAACC,EAAU,GAAG;KAElB,AADA,EAAQ,YAAYC,GACpB,EAAQ,SAAShB,EAAQ;IAC3B,SAASiB,GAAK;KACZ,IAAI,CAACF,EAAU,GAAG;KAClB,QAAQ,MAAM,yBAAyBE,CAAG;KAC1C,IAAMC,IAAW,SAAS,cAAc,KAAK;KAI7C,AAHA,EAAS,YAAY,cACrB,EAAS,cAAcJ,GACvBd,EAAQ,gBAAgBkB,CAAQ,GAChC,EAAQ,SAASA;IACnB;GACF,GAAG,GAAG;EACR,CAAC;CACH,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focusScope.js","names":[],"sources":["../../../src/components/Modal/focusScope.ts"],"sourcesContent":["// Only the top Modal owns focus and background isolation. Keep original attributes\n// so nested modals and pre-existing inert/aria-hidden regions restore correctly.\ntype Scope = { panel: HTMLElement; overlay: HTMLElement; trigger: HTMLElement | null; close: () => void; existing: Set<Element> };\nconst scopes: Scope[] = [];\nconst locked = new Map<HTMLElement, { inert: boolean; hidden: string | null }>();\nlet overflow = '';\nlet observer: MutationObserver | undefined;\nconst focusable = 'button, a[href], input, select, textarea, [tabindex], [contenteditable=\"true\"]';\nconst top = () => scopes[scopes.length - 1];\nconst expanded = (scope: Scope) => !!scope.panel.querySelector('[role=\"combobox\"][aria-expanded=\"true\"]');\nconst linkedMenus = (scope: Scope): HTMLElement[] => {\n const menus = new Set<HTMLElement>();\n for (const trigger of scope.panel.querySelectorAll('[aria-haspopup=\"menu\"][aria-expanded=\"true\"][aria-controls]')) {\n for (const id of trigger.getAttribute('aria-controls')!.split(/\\s+/)) {\n const menu = document.getElementById(id);\n if (menu?.parentElement === document.body && menu.getAttribute('role') === 'menu') menus.add(menu);\n }\n }\n return [...menus];\n};\nconst roots = (scope: Scope): HTMLElement[] => {\n // Select currently portals an unlinked listbox directly to body. Only admit\n // new listboxes while a combobox in this modal is expanded, not arbitrary portals.\n const portals = expanded(scope) ? Array.from(document.body.children).filter(element =>\n !scope.existing.has(element) && element.matches('[role=\"listbox\"]')) as HTMLElement[] : [];\n return [scope.panel, ...portals, ...linkedMenus(scope)];\n};\nconst contains = (scope: Scope, node: Node) => roots(scope).some(root => root.contains(node));\nconst candidates = (scope: Scope, includeMenus = true) => roots(scope)\n .filter(root => includeMenus || root === scope.panel || root.getAttribute('role') !== 'menu')\n .flatMap(root => Array.from(root.querySelectorAll<HTMLElement>(focusable)))\n .filter(element => element.tabIndex >= 0 && !element.matches(':disabled') && !element.closest('[inert]') && element.getClientRects().length > 0 && getComputedStyle(element).visibility !== 'hidden');\nconst restoreBackground = () => {\n locked.forEach((value, element) => {\n element.inert = value.inert;\n if (value.hidden === null) element.removeAttribute('aria-hidden');\n else element.setAttribute('aria-hidden', value.hidden);\n });\n locked.clear();\n};\nconst isolate = () => {\n restoreBackground();\n const scope = top();\n if (!scope) return;\n const allowed = [scope.overlay, ...roots(scope)];\n for (const child of Array.from(document.body.children)) {\n if (!(child instanceof HTMLElement) || allowed.includes(child)) continue;\n locked.set(child, { inert: child.inert, hidden: child.getAttribute('aria-hidden') });\n child.inert = true;\n child.setAttribute('aria-hidden', 'true');\n }\n};\nconst focusInside = (scope: Scope) => (candidates(scope)[0] || scope.panel).focus({ preventScroll: true });\nconst onFocus = (event: FocusEvent) => {\n const scope = top();\n if (scope && event.target instanceof Node && !contains(scope, event.target)) focusInside(scope);\n};\nconst selectEscapes = new WeakSet<KeyboardEvent>();\nconst menuTabs = new WeakSet<KeyboardEvent>();\nconst trapTab = (scope: Scope, event: KeyboardEvent) => {\n // Menu items use roving focus, not the dialog's sequential tab order.\n const items = candidates(scope, false);\n const index = items.indexOf(document.activeElement as HTMLElement);\n if (!items.length || index < 0 || (event.shiftKey ? index === 0 : index === items.length - 1)) {\n event.preventDefault();\n (event.shiftKey ? items.at(-1) || scope.panel : items[0] || scope.panel).focus();\n }\n};\nconst onKeyCapture = (event: KeyboardEvent) => {\n const scope = top();\n if (!scope) return;\n if (event.key === 'Escape' && expanded(scope)) selectEscapes.add(event);\n if (event.key !== 'Tab') return;\n if (event.target instanceof Node && linkedMenus(scope).some(menu => menu.contains(event.target as Node))) {\n // ButtonMenu closes and returns focus to its trigger during bubbling.\n // Only then can the dialog decide whether native Tab needs to wrap.\n menuTabs.add(event);\n return;\n }\n trapTab(scope, event);\n};\nconst onKey = (event: KeyboardEvent) => {\n if (event.key === 'Tab' && menuTabs.has(event) && !event.defaultPrevented) {\n const scope = top();\n if (scope) trapTab(scope, event);\n return;\n }\n if (event.key !== 'Escape' || event.defaultPrevented || selectEscapes.has(event)) return;\n const scope = top();\n if (scope) { event.preventDefault(); scope.close(); }\n};\nexport function mountFocusScope(panel: HTMLElement, overlay: HTMLElement, trigger: HTMLElement | null, close: () => void) {\n const scope: Scope = { panel, overlay, trigger, close, existing: new Set(document.body.children) };\n if (!scopes.length) {\n overflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n document.addEventListener('focusin', onFocus);\n document.addEventListener('keydown', onKeyCapture, true);\n window.addEventListener('keydown', onKey);\n observer = new MutationObserver(isolate);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['aria-expanded', 'aria-controls', 'aria-haspopup', 'role', 'id'] });\n }\n scopes.push(scope);\n // React autoFocus has already run during commit; don't replace the safe action.\n if (!contains(scope, document.activeElement!)) focusInside(scope);\n isolate();\n return () => {\n const wasTop = top() === scope;\n scopes.splice(scopes.indexOf(scope), 1);\n isolate();\n if (!scopes.length) {\n observer?.disconnect();\n document.body.style.overflow = overflow;\n document.removeEventListener('focusin', onFocus);\n document.removeEventListener('keydown', onKeyCapture, true);\n window.removeEventListener('keydown', onKey);\n }\n if (wasTop) {\n if (trigger?.isConnected && !trigger.closest('[inert]')) trigger.focus({ preventScroll: true });\n else if (top()) focusInside(top());\n }\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"focusScope.js","names":["scopes","locked","overflow","observer","focusable","top","expanded","scope","linkedMenus","menus","trigger","id","menu","roots","portals","element","contains","root","node","candidates","includeMenus","restoreBackground","value","isolate","allowed","child","focusInside","onFocus","event","selectEscapes","menuTabs","trapTab","items","index","onKeyCapture","onKey","mountFocusScope","wasTop"],"sources":["../../../src/components/Modal/focusScope.ts"],"sourcesContent":["// Only the top Modal owns focus and background isolation. Keep original attributes\n// so nested modals and pre-existing inert/aria-hidden regions restore correctly.\ntype Scope = { panel: HTMLElement; overlay: HTMLElement; trigger: HTMLElement | null; close: () => void; existing: Set<Element> };\nconst scopes: Scope[] = [];\nconst locked = new Map<HTMLElement, { inert: boolean; hidden: string | null }>();\nlet overflow = '';\nlet observer: MutationObserver | undefined;\nconst focusable = 'button, a[href], input, select, textarea, [tabindex], [contenteditable=\"true\"]';\nconst top = () => scopes[scopes.length - 1];\nconst expanded = (scope: Scope) => !!scope.panel.querySelector('[role=\"combobox\"][aria-expanded=\"true\"]');\nconst linkedMenus = (scope: Scope): HTMLElement[] => {\n const menus = new Set<HTMLElement>();\n for (const trigger of scope.panel.querySelectorAll('[aria-haspopup=\"menu\"][aria-expanded=\"true\"][aria-controls]')) {\n for (const id of trigger.getAttribute('aria-controls')!.split(/\\s+/)) {\n const menu = document.getElementById(id);\n if (menu?.parentElement === document.body && menu.getAttribute('role') === 'menu') menus.add(menu);\n }\n }\n return [...menus];\n};\nconst roots = (scope: Scope): HTMLElement[] => {\n // Select currently portals an unlinked listbox directly to body. Only admit\n // new listboxes while a combobox in this modal is expanded, not arbitrary portals.\n const portals = expanded(scope) ? Array.from(document.body.children).filter(element =>\n !scope.existing.has(element) && element.matches('[role=\"listbox\"]')) as HTMLElement[] : [];\n return [scope.panel, ...portals, ...linkedMenus(scope)];\n};\nconst contains = (scope: Scope, node: Node) => roots(scope).some(root => root.contains(node));\nconst candidates = (scope: Scope, includeMenus = true) => roots(scope)\n .filter(root => includeMenus || root === scope.panel || root.getAttribute('role') !== 'menu')\n .flatMap(root => Array.from(root.querySelectorAll<HTMLElement>(focusable)))\n .filter(element => element.tabIndex >= 0 && !element.matches(':disabled') && !element.closest('[inert]') && element.getClientRects().length > 0 && getComputedStyle(element).visibility !== 'hidden');\nconst restoreBackground = () => {\n locked.forEach((value, element) => {\n element.inert = value.inert;\n if (value.hidden === null) element.removeAttribute('aria-hidden');\n else element.setAttribute('aria-hidden', value.hidden);\n });\n locked.clear();\n};\nconst isolate = () => {\n restoreBackground();\n const scope = top();\n if (!scope) return;\n const allowed = [scope.overlay, ...roots(scope)];\n for (const child of Array.from(document.body.children)) {\n if (!(child instanceof HTMLElement) || allowed.includes(child)) continue;\n locked.set(child, { inert: child.inert, hidden: child.getAttribute('aria-hidden') });\n child.inert = true;\n child.setAttribute('aria-hidden', 'true');\n }\n};\nconst focusInside = (scope: Scope) => (candidates(scope)[0] || scope.panel).focus({ preventScroll: true });\nconst onFocus = (event: FocusEvent) => {\n const scope = top();\n if (scope && event.target instanceof Node && !contains(scope, event.target)) focusInside(scope);\n};\nconst selectEscapes = new WeakSet<KeyboardEvent>();\nconst menuTabs = new WeakSet<KeyboardEvent>();\nconst trapTab = (scope: Scope, event: KeyboardEvent) => {\n // Menu items use roving focus, not the dialog's sequential tab order.\n const items = candidates(scope, false);\n const index = items.indexOf(document.activeElement as HTMLElement);\n if (!items.length || index < 0 || (event.shiftKey ? index === 0 : index === items.length - 1)) {\n event.preventDefault();\n (event.shiftKey ? items.at(-1) || scope.panel : items[0] || scope.panel).focus();\n }\n};\nconst onKeyCapture = (event: KeyboardEvent) => {\n const scope = top();\n if (!scope) return;\n if (event.key === 'Escape' && expanded(scope)) selectEscapes.add(event);\n if (event.key !== 'Tab') return;\n if (event.target instanceof Node && linkedMenus(scope).some(menu => menu.contains(event.target as Node))) {\n // ButtonMenu closes and returns focus to its trigger during bubbling.\n // Only then can the dialog decide whether native Tab needs to wrap.\n menuTabs.add(event);\n return;\n }\n trapTab(scope, event);\n};\nconst onKey = (event: KeyboardEvent) => {\n if (event.key === 'Tab' && menuTabs.has(event) && !event.defaultPrevented) {\n const scope = top();\n if (scope) trapTab(scope, event);\n return;\n }\n if (event.key !== 'Escape' || event.defaultPrevented || selectEscapes.has(event)) return;\n const scope = top();\n if (scope) { event.preventDefault(); scope.close(); }\n};\nexport function mountFocusScope(panel: HTMLElement, overlay: HTMLElement, trigger: HTMLElement | null, close: () => void) {\n const scope: Scope = { panel, overlay, trigger, close, existing: new Set(document.body.children) };\n if (!scopes.length) {\n overflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n document.addEventListener('focusin', onFocus);\n document.addEventListener('keydown', onKeyCapture, true);\n window.addEventListener('keydown', onKey);\n observer = new MutationObserver(isolate);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['aria-expanded', 'aria-controls', 'aria-haspopup', 'role', 'id'] });\n }\n scopes.push(scope);\n // React autoFocus has already run during commit; don't replace the safe action.\n if (!contains(scope, document.activeElement!)) focusInside(scope);\n isolate();\n return () => {\n const wasTop = top() === scope;\n scopes.splice(scopes.indexOf(scope), 1);\n isolate();\n if (!scopes.length) {\n observer?.disconnect();\n document.body.style.overflow = overflow;\n document.removeEventListener('focusin', onFocus);\n document.removeEventListener('keydown', onKeyCapture, true);\n window.removeEventListener('keydown', onKey);\n }\n if (wasTop) {\n if (trigger?.isConnected && !trigger.closest('[inert]')) trigger.focus({ preventScroll: true });\n else if (top()) focusInside(top());\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import React, { useId, useLayoutEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { mountFocusScope } from './focusScope';\n\nexport type ModalProps = {\n /** 是否打开 */\n open: boolean;\n /** 关闭回调(遮罩点击 / Esc / 关闭按钮触发) */\n onClose: () => void;\n /** 标题 */\n title?: React.ReactNode;\n /** 标题下的说明文字 */\n description?: React.ReactNode;\n /** 正文内容 */\n children?: React.ReactNode;\n /** 底部操作区(默认右对齐) */\n footer?: React.ReactNode;\n /** 尺寸(预设):sm / md / lg / xl / full */\n size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';\n /** 自定义宽度:支持百分比/像素等 CSS 长度(如 \"80%\"、640)。优先于 size。 */\n width?: number | string;\n /** 自定义高度:支持百分比/像素等 CSS 长度(如 \"80%\"、480)。 */\n height?: number | string;\n /** 点击遮罩是否关闭(默认 true) */\n closeOnOverlay?: boolean;\n /** 是否显示右上角关闭按钮(默认 true) */\n showClose?: boolean;\n className?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n};\n\nconst SIZE_CLASS: Record<NonNullable<ModalProps['size']>, string> = {\n sm: 'max-w-sm',\n md: 'max-w-lg',\n lg: 'max-w-2xl',\n xl: 'max-w-5xl',\n full: 'max-w-[95vw]',\n};\n\nconst toCssSize = (value: number | string | undefined): string | undefined =>\n typeof value === 'number' ? `${value}px` : value;\n\n/**\n * 轻量模态框:遮罩 + 居中面板,支持 Esc 关闭、遮罩点击关闭与滚动锁定。\n */\nconst Modal = ({\n open,\n onClose,\n title,\n description,\n children,\n footer,\n size = 'md',\n width,\n height,\n closeOnOverlay = true,\n showClose = true,\n className = '',\n 'aria-label': ariaLabel,\n 'aria-labelledby': labelledBy,\n 'aria-describedby': describedBy,\n}: ModalProps) => {\n const titleId = useId();\n const descriptionId = useId();\n const panel = useRef<HTMLDivElement>(null);\n const overlay = useRef<HTMLDivElement>(null);\n const trigger = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n const close = useRef(onClose);\n // Capture before React commits autoFocus inside the newly opened portal.\n if (open && !wasOpen.current && typeof document !== 'undefined') trigger.current = document.activeElement as HTMLElement | null;\n wasOpen.current = open;\n useLayoutEffect(() => { close.current = onClose; });\n useLayoutEffect(() => {\n if (!open || !panel.current || !overlay.current) return;\n return mountFocusScope(panel.current, overlay.current, trigger.current, () => close.current());\n }, [open]);\n\n if (!open || typeof document === 'undefined') return null;\n\n // 自定义宽高:传入时优先于 size 预设;支持百分比。\n const hasCustomWidth = width !== undefined;\n const panelStyle: React.CSSProperties = {\n width: hasCustomWidth ? toCssSize(width) : undefined,\n maxWidth: hasCustomWidth ? '95vw' : undefined,\n height: toCssSize(height),\n maxHeight: '92vh',\n };\n // 面板尺寸类:未自定义宽度时才应用 max-w-* 预设。\n const sizeClass = hasCustomWidth ? '' : SIZE_CLASS[size];\n // 正文区:固定高度时自适应充满并内部滚动;否则限制最大高度。\n const bodyClass = height !== undefined\n ? 'min-h-0 flex-1 overflow-y-auto px-5 py-4'\n : 'max-h-[70vh] overflow-y-auto px-5 py-4';\n\n return createPortal(\n <div ref={overlay} className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div\n className=\"absolute inset-0\"\n onClick={closeOnOverlay ? onClose : undefined}\n aria-hidden\n />\n <div\n ref={panel}\n role=\"dialog\"\n tabIndex={-1}\n aria-modal=\"true\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy ?? (title && !ariaLabel ? titleId : undefined)}\n aria-describedby={describedBy ?? (description ? descriptionId : undefined)}\n className={`dishui-modal card relative flex w-full min-w-0 flex-col rounded-xl border border-base-300 bg-base-100 text-body leading-5 text-base-content shadow-md ${sizeClass} ${className}`.trim()}\n style={panelStyle}\n >\n {(title || description || showClose) && (\n <div className=\"flex shrink-0 items-start justify-between gap-3 border-b border-base-300 px-5 py-3\">\n <div className=\"min-w-0\">\n {title && (\n <h3 id={titleId} className=\"break-words text-body font-semibold text-base-content\">\n {title}\n </h3>\n )}\n {description && (\n <p id={descriptionId} className=\"mt-1 text-body-sm leading-5 text-base-content/70\">{description}</p>\n )}\n </div>\n {showClose && (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"shrink-0 rounded-md p-1 text-base-content/70 transition-colors duration-150 motion-reduce:transition-none hover:bg-base-200 hover:text-base-content focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current\"\n >\n <svg\n className=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n )}\n <div className={bodyClass}>{children}</div>\n {footer && (\n <div className=\"flex shrink-0 flex-wrap justify-end gap-2 border-t border-base-300 px-5 py-3\">\n {footer}\n </div>\n )}\n </div>\n </div>,\n document.body,\n );\n};\n\nexport default Modal;\n"],"mappings":";;;;;AAiCA,
|
|
1
|
+
{"version":3,"file":"index.js","names":["SIZE_CLASS","toCssSize","value","Modal","ariaLabel","labelledBy","describedBy","titleId","useId","descriptionId","panel","useRef","overlay","trigger","wasOpen","close","onClose","open","useLayoutEffect","mountFocusScope","hasCustomWidth","width","panelStyle","height","sizeClass","size","bodyClass","createPortal","closeOnOverlay","title","description","className","showClose","footer"],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import React, { useId, useLayoutEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { mountFocusScope } from './focusScope';\n\nexport type ModalProps = {\n /** 是否打开 */\n open: boolean;\n /** 关闭回调(遮罩点击 / Esc / 关闭按钮触发) */\n onClose: () => void;\n /** 标题 */\n title?: React.ReactNode;\n /** 标题下的说明文字 */\n description?: React.ReactNode;\n /** 正文内容 */\n children?: React.ReactNode;\n /** 底部操作区(默认右对齐) */\n footer?: React.ReactNode;\n /** 尺寸(预设):sm / md / lg / xl / full */\n size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';\n /** 自定义宽度:支持百分比/像素等 CSS 长度(如 \"80%\"、640)。优先于 size。 */\n width?: number | string;\n /** 自定义高度:支持百分比/像素等 CSS 长度(如 \"80%\"、480)。 */\n height?: number | string;\n /** 点击遮罩是否关闭(默认 true) */\n closeOnOverlay?: boolean;\n /** 是否显示右上角关闭按钮(默认 true) */\n showClose?: boolean;\n className?: string;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n};\n\nconst SIZE_CLASS: Record<NonNullable<ModalProps['size']>, string> = {\n sm: 'max-w-sm',\n md: 'max-w-lg',\n lg: 'max-w-2xl',\n xl: 'max-w-5xl',\n full: 'max-w-[95vw]',\n};\n\nconst toCssSize = (value: number | string | undefined): string | undefined =>\n typeof value === 'number' ? `${value}px` : value;\n\n/**\n * 轻量模态框:遮罩 + 居中面板,支持 Esc 关闭、遮罩点击关闭与滚动锁定。\n */\nconst Modal = ({\n open,\n onClose,\n title,\n description,\n children,\n footer,\n size = 'md',\n width,\n height,\n closeOnOverlay = true,\n showClose = true,\n className = '',\n 'aria-label': ariaLabel,\n 'aria-labelledby': labelledBy,\n 'aria-describedby': describedBy,\n}: ModalProps) => {\n const titleId = useId();\n const descriptionId = useId();\n const panel = useRef<HTMLDivElement>(null);\n const overlay = useRef<HTMLDivElement>(null);\n const trigger = useRef<HTMLElement | null>(null);\n const wasOpen = useRef(false);\n const close = useRef(onClose);\n // Capture before React commits autoFocus inside the newly opened portal.\n if (open && !wasOpen.current && typeof document !== 'undefined') trigger.current = document.activeElement as HTMLElement | null;\n wasOpen.current = open;\n useLayoutEffect(() => { close.current = onClose; });\n useLayoutEffect(() => {\n if (!open || !panel.current || !overlay.current) return;\n return mountFocusScope(panel.current, overlay.current, trigger.current, () => close.current());\n }, [open]);\n\n if (!open || typeof document === 'undefined') return null;\n\n // 自定义宽高:传入时优先于 size 预设;支持百分比。\n const hasCustomWidth = width !== undefined;\n const panelStyle: React.CSSProperties = {\n width: hasCustomWidth ? toCssSize(width) : undefined,\n maxWidth: hasCustomWidth ? '95vw' : undefined,\n height: toCssSize(height),\n maxHeight: '92vh',\n };\n // 面板尺寸类:未自定义宽度时才应用 max-w-* 预设。\n const sizeClass = hasCustomWidth ? '' : SIZE_CLASS[size];\n // 正文区:固定高度时自适应充满并内部滚动;否则限制最大高度。\n const bodyClass = height !== undefined\n ? 'min-h-0 flex-1 overflow-y-auto px-5 py-4'\n : 'max-h-[70vh] overflow-y-auto px-5 py-4';\n\n return createPortal(\n <div ref={overlay} className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div\n className=\"absolute inset-0\"\n onClick={closeOnOverlay ? onClose : undefined}\n aria-hidden\n />\n <div\n ref={panel}\n role=\"dialog\"\n tabIndex={-1}\n aria-modal=\"true\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy ?? (title && !ariaLabel ? titleId : undefined)}\n aria-describedby={describedBy ?? (description ? descriptionId : undefined)}\n className={`dishui-modal card relative flex w-full min-w-0 flex-col rounded-xl border border-base-300 bg-base-100 text-body leading-5 text-base-content shadow-md ${sizeClass} ${className}`.trim()}\n style={panelStyle}\n >\n {(title || description || showClose) && (\n <div className=\"flex shrink-0 items-start justify-between gap-3 border-b border-base-300 px-5 py-3\">\n <div className=\"min-w-0\">\n {title && (\n <h3 id={titleId} className=\"break-words text-body font-semibold text-base-content\">\n {title}\n </h3>\n )}\n {description && (\n <p id={descriptionId} className=\"mt-1 text-body-sm leading-5 text-base-content/70\">{description}</p>\n )}\n </div>\n {showClose && (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"shrink-0 rounded-md p-1 text-base-content/70 transition-colors duration-150 motion-reduce:transition-none hover:bg-base-200 hover:text-base-content focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-current\"\n >\n <svg\n className=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n )}\n <div className={bodyClass}>{children}</div>\n {footer && (\n <div className=\"flex shrink-0 flex-wrap justify-end gap-2 border-t border-base-300 px-5 py-3\">\n {footer}\n </div>\n )}\n </div>\n </div>,\n document.body,\n );\n};\n\nexport default Modal;\n"],"mappings":";;;;;AAiCA,IAAMA,IAA8D;CAChE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM;AACV,GAEMC,KAAa,MACf,OAAOC,KAAU,WAAW,GAAGA,EAAM,MAAMA,GAKzCC,KAAS,EACX,SACA,YACA,UACA,gBACA,aACA,WACA,UAAO,MACP,UACA,WACA,oBAAiB,IACjB,eAAY,IACZ,eAAY,IACZ,cAAcC,GACd,mBAAmBC,GACnB,oBAAoBC,QACN;CACd,IAAMC,IAAUC,EAAM,GAChBC,IAAgBD,EAAM,GACtBE,IAAQC,EAAuB,IAAI,GACnCC,IAAUD,EAAuB,IAAI,GACrCE,IAAUF,EAA2B,IAAI,GACzCG,IAAUH,EAAO,EAAK,GACtBI,IAAQJ,EAAOK,CAAO;CAU5B,IARIC,KAAQ,CAACH,EAAQ,WAAW,OAAO,WAAa,QAAa,EAAQ,UAAU,SAAS,gBAC5F,EAAQ,UAAUG,GAClBC,QAAsB;EAAE,EAAM,UAAUF;CAAS,CAAC,GAClDE,QAAsB;EAClB,IAAKD,KAASP,EAAM,WAAYE,EAAQ,SACxC,OAAOO,EAAgBT,EAAM,SAASE,EAAQ,SAASC,EAAQ,eAAeE,EAAM,QAAQ,CAAC;CACjG,GAAG,CAACE,CAAI,CAAC,GAEL,CAACA,KAAQ,OAAO,WAAa,KAAa,OAAO;CAGrD,IAAMG,IAAiBC,MAAU,KAAA,GAC3BC,IAAkC;EACpC,OAAOF,IAAiBnB,EAAUoB,CAAK,IAAI,KAAA;EAC3C,UAAUD,IAAiB,SAAS,KAAA;EACpC,QAAQnB,EAAUsB,CAAM;EACxB,WAAW;CACf,GAEMC,IAAYJ,IAAiB,KAAKpB,EAAWyB,IAE7CC,IAAYH,MAAW,KAAA,IAEvB,2CADA;CAGN,OAAOI,EACH,kBAAC,OAAD;EAAK,KAAKf;EAAS,WAAU;EAA7B,UAAA,CACI,kBAAC,OAAD;GACI,WAAU;GACV,SAASgB,IAAiBZ,IAAU,KAAA;GACpC,eAAA;EACH,CAAA,GACD,kBAAC,OAAD;GACI,KAAKN;GACL,MAAK;GACL,UAAU;GACV,cAAW;GACX,cAAYN;GACZ,mBAAiBC,MAAewB,KAAS,CAACzB,IAAYG,IAAU,KAAA;GAChE,oBAAkBD,MAAgBwB,IAAcrB,IAAgB,KAAA;GAChE,WAAW,yJAAyJe,EAAU,GAAGO,IAAY,KAAK;GAClM,OAAOT;GATX,UAAA;KAWMO,KAASC,KAAeE,MACtB,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACI,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACKH,KACG,kBAAC,MAAD;OAAI,IAAItB;OAAS,WAAU;OACtB,UAAAsB;MACD,CAAA,GAEPC,KACG,kBAAC,KAAD;OAAG,IAAIrB;OAAe,WAAU;OAAoD,UAAAqB;MAAe,CAAA,CAEtG;KACJ,CAAA,GAAAE,KACG,kBAAC,UAAD;MACI,MAAK;MACL,SAAShB;MACT,cAAW;MACX,WAAU;MAEV,UAAA,kBAAC,OAAD;OACI,WAAU;OACV,MAAK;OACL,SAAQ;OACR,QAAO;OACP,aAAa;OAEb,UAAA,kBAAC,QAAD;QACI,eAAc;QACd,gBAAe;QACf,GAAE;OACL,CAAA;MACA,CAAA;KACD,CAAA,CAEX;;IAET,kBAAC,OAAD;KAAK,WAAWU;KAAY;IAAc,CAAA;IACzCO,KACG,kBAAC,OAAD;KAAK,WAAU;KACV,UAAAA;IACA,CAAA;GAER;EACJ,CAAA,CAAA;CACL,CAAA,GAAA,SAAS,IACb;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/MultipleChoice/index.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport Checkbox from '../Checkbox';\n\nexport type MultipleChoiceOption = {\n /** Value submitted for this option. */\n value: string | number;\n /** Display label. */\n label: React.ReactNode;\n /** Disable this option only. */\n disabled?: boolean;\n};\n\nexport type MultipleChoiceVariant =\n | 'default'\n | 'primary'\n | 'secondary'\n | 'accent'\n | 'info'\n | 'success'\n | 'warning'\n | 'error';\n\nexport type MultipleChoiceProps = {\n /** Available options. */\n options: MultipleChoiceOption[];\n /** Controlled selected values. */\n value?: Array<string | number>;\n /** Uncontrolled initial selection. */\n defaultValue?: Array<string | number>;\n /** Change handler with the full selected-value array. */\n onChange?: (values: Array<string | number>) => void;\n /** Layout of the options. */\n orientation?: 'vertical' | 'horizontal';\n /** Color variant forwarded to each checkbox. */\n variant?: MultipleChoiceVariant;\n /** Size forwarded to each checkbox. */\n size?: 'xs' | 'sm' | 'md' | 'lg';\n /** Disable the whole group. */\n disabled?: boolean;\n /** Limit the number of selectable options. */\n maxSelected?: number;\n /** Optional group label rendered above the options. */\n label?: React.ReactNode;\n /** Native name attribute for each checkbox. */\n name?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n /** Inline styles on the wrapper. */\n style?: React.CSSProperties;\n};\n\n/**\n * MultipleChoice —— A2UI 交互组件(v0.8):多选项组。\n * 基于 dishui Checkbox 的受控 / 非受控多选组,支持横竖排与最大选择数限制。\n */\nconst MultipleChoice: React.FC<MultipleChoiceProps> = ({\n options,\n value,\n defaultValue = [],\n onChange,\n orientation = 'vertical',\n variant = 'default',\n size = 'sm',\n disabled = false,\n maxSelected,\n label,\n name,\n className = '',\n style,\n}) => {\n const [internal, setInternal] = useState<Array<string | number>>(defaultValue);\n const isControlled = value !== undefined;\n const selected = useMemo(\n () => new Set<string | number>(isControlled ? (value as Array<string | number>) : internal),\n [isControlled, value, internal],\n );\n\n const toggle = useCallback(\n (optionValue: string | number, next: boolean) => {\n const base = Array.from(selected);\n const result = next ? [...base, optionValue] : base.filter((v) => v !== optionValue);\n if (!isControlled) setInternal(result);\n onChange?.(result);\n },\n [selected, isControlled, onChange],\n );\n\n const handleToggle = useCallback(\n (optionValue: string | number, next: boolean) => {\n // Enforce maxSelected only when turning a new option ON.\n if (next && maxSelected !== undefined && selected.size >= maxSelected) return;\n toggle(optionValue, next);\n },\n [toggle, maxSelected, selected],\n );\n\n return (\n <div className={cn('w-full', className)} style={style}>\n {label !== undefined && (\n <div className=\"mb-1.5 text-sm font-medium text-base-content/80\">{label}</div>\n )}\n <div\n className={cn(\n 'gap-2',\n orientation === 'horizontal' ? 'flex flex-wrap items-center' : 'flex flex-col',\n )}\n role=\"group\"\n >\n {options.map((option) => {\n const checked = selected.has(option.value);\n const optionDisabled = disabled || option.disabled;\n return (\n <Checkbox\n key={String(option.value)}\n label={option.label}\n checked={checked}\n onChange={(next) => handleToggle(option.value, next)}\n variant={variant === 'default' ? 'default' : variant}\n size={size}\n disabled={optionDisabled}\n name={name}\n value={String(option.value)}\n />\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default MultipleChoice;\n"],"mappings":";;;;;AAwDA,
|
|
1
|
+
{"version":3,"file":"index.js","names":["Checkbox","MultipleChoice","internal","setInternal","useState","defaultValue","isControlled","value","selected","useMemo","toggle","useCallback","base","result","next","optionValue","v","onChange","handleToggle","maxSelected","cn","className","label","orientation","options","checked","option","optionDisabled","disabled","variant"],"sources":["../../../src/components/MultipleChoice/index.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport Checkbox from '../Checkbox';\n\nexport type MultipleChoiceOption = {\n /** Value submitted for this option. */\n value: string | number;\n /** Display label. */\n label: React.ReactNode;\n /** Disable this option only. */\n disabled?: boolean;\n};\n\nexport type MultipleChoiceVariant =\n | 'default'\n | 'primary'\n | 'secondary'\n | 'accent'\n | 'info'\n | 'success'\n | 'warning'\n | 'error';\n\nexport type MultipleChoiceProps = {\n /** Available options. */\n options: MultipleChoiceOption[];\n /** Controlled selected values. */\n value?: Array<string | number>;\n /** Uncontrolled initial selection. */\n defaultValue?: Array<string | number>;\n /** Change handler with the full selected-value array. */\n onChange?: (values: Array<string | number>) => void;\n /** Layout of the options. */\n orientation?: 'vertical' | 'horizontal';\n /** Color variant forwarded to each checkbox. */\n variant?: MultipleChoiceVariant;\n /** Size forwarded to each checkbox. */\n size?: 'xs' | 'sm' | 'md' | 'lg';\n /** Disable the whole group. */\n disabled?: boolean;\n /** Limit the number of selectable options. */\n maxSelected?: number;\n /** Optional group label rendered above the options. */\n label?: React.ReactNode;\n /** Native name attribute for each checkbox. */\n name?: string;\n /** Extra class names on the wrapper. */\n className?: string;\n /** Inline styles on the wrapper. */\n style?: React.CSSProperties;\n};\n\n/**\n * MultipleChoice —— A2UI 交互组件(v0.8):多选项组。\n * 基于 dishui Checkbox 的受控 / 非受控多选组,支持横竖排与最大选择数限制。\n */\nconst MultipleChoice: React.FC<MultipleChoiceProps> = ({\n options,\n value,\n defaultValue = [],\n onChange,\n orientation = 'vertical',\n variant = 'default',\n size = 'sm',\n disabled = false,\n maxSelected,\n label,\n name,\n className = '',\n style,\n}) => {\n const [internal, setInternal] = useState<Array<string | number>>(defaultValue);\n const isControlled = value !== undefined;\n const selected = useMemo(\n () => new Set<string | number>(isControlled ? (value as Array<string | number>) : internal),\n [isControlled, value, internal],\n );\n\n const toggle = useCallback(\n (optionValue: string | number, next: boolean) => {\n const base = Array.from(selected);\n const result = next ? [...base, optionValue] : base.filter((v) => v !== optionValue);\n if (!isControlled) setInternal(result);\n onChange?.(result);\n },\n [selected, isControlled, onChange],\n );\n\n const handleToggle = useCallback(\n (optionValue: string | number, next: boolean) => {\n // Enforce maxSelected only when turning a new option ON.\n if (next && maxSelected !== undefined && selected.size >= maxSelected) return;\n toggle(optionValue, next);\n },\n [toggle, maxSelected, selected],\n );\n\n return (\n <div className={cn('w-full', className)} style={style}>\n {label !== undefined && (\n <div className=\"mb-1.5 text-sm font-medium text-base-content/80\">{label}</div>\n )}\n <div\n className={cn(\n 'gap-2',\n orientation === 'horizontal' ? 'flex flex-wrap items-center' : 'flex flex-col',\n )}\n role=\"group\"\n >\n {options.map((option) => {\n const checked = selected.has(option.value);\n const optionDisabled = disabled || option.disabled;\n return (\n <Checkbox\n key={String(option.value)}\n label={option.label}\n checked={checked}\n onChange={(next) => handleToggle(option.value, next)}\n variant={variant === 'default' ? 'default' : variant}\n size={size}\n disabled={optionDisabled}\n name={name}\n value={String(option.value)}\n />\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default MultipleChoice;\n"],"mappings":";;;;;AAwDA,IAAMC,KAAiD,EACrD,YACA,UACA,kBAAe,CAAC,GAChB,aACA,iBAAc,YACd,aAAU,WACV,UAAO,MACP,cAAW,IACX,gBACA,UACA,SACA,eAAY,IACZ,eACI;CACJ,IAAM,CAACC,GAAUC,KAAeC,EAAiCC,CAAY,GACvEC,IAAeC,MAAU,KAAA,GACzBC,IAAWC,QACT,IAAI,IAAqBH,IAAgBC,IAAmCL,CAAQ,GAC1F;EAACI;EAAcC;EAAOL;CAAQ,CAChC,GAEMQ,IAASC,GACZ,GAA8B,MAAkB;EAC/C,IAAMC,IAAO,MAAM,KAAKJ,CAAQ,GAC1BK,IAASC,IAAO,CAAC,GAAGF,GAAMG,CAAW,IAAIH,EAAK,QAAQ,MAAMI,MAAMD,CAAW;EAEnF,AADKT,KAAcH,EAAYU,CAAM,GACrCI,IAAWJ,CAAM;CACnB,GACA;EAACL;EAAUF;EAAcW;CAAQ,CACnC,GAEMC,IAAeP,GAClB,GAA8B,MAAkB;EAE/C,AAAIG,KAAQK,MAAgB,KAAA,KAAaX,EAAS,QAAQW,KAC1DT,EAAOK,GAAaD,CAAI;CAC1B,GACA;EAACJ;EAAQS;EAAaX;CAAQ,CAChC;CAEA,OACE,kBAAC,OAAD;EAAK,WAAWY,EAAG,UAAUC,CAAS;EAAU;EAAhD,UAAA,CACGC,MAAU,KAAA,KACT,kBAAC,OAAD;GAAK,WAAU;GAAmD,UAAAA;EAAW,CAAA,GAE/E,kBAAC,OAAD;GACE,WAAWF,EACT,SACAG,MAAgB,eAAe,gCAAgC,eACjE;GACA,MAAK;GAEJ,UAAAC,EAAQ,KAAK,MAAW;IACvB,IAAMC,IAAUjB,EAAS,IAAIkB,EAAO,KAAK,GACnCC,IAAiBC,KAAYF,EAAO;IAC1C,OACE,kBAAC1B,GAAD;KAEE,OAAO0B,EAAO;KACL;KACT,WAAW,MAASR,EAAaQ,EAAO,OAAOZ,CAAI;KACnD,SAASe,MAAY,YAAY,YAAYA;KACvC;KACN,UAAUF;KACJ;KACN,OAAO,OAAOD,EAAO,KAAK;IAC3B,GATM,OAAOA,EAAO,KAAK,CASzB;GAEL,CAAC;EACE,CAAA,CACF;;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/NavigationList/index.tsx"],"sourcesContent":["import React, { useId, useLayoutEffect, useRef, useState } from 'react';\nimport Button from '../Button';\nimport './NavigationList.css';\n\nexport type NavigationListItem = {\n value: string;\n label: React.ReactNode;\n count?: React.ReactNode;\n};\n\nexport type NavigationListProps = {\n 'aria-label': string;\n items: readonly NavigationListItem[];\n value: string;\n onValueChange: (value: string) => void;\n /** Optional selectable parent with a separate disclosure control. */\n root?: NavigationListItem;\n defaultExpanded?: boolean;\n};\n\n/** A single-level navigation/filter list with native keyboard-operable controls. */\nexport default function NavigationList({ items, value, onValueChange, root, defaultExpanded = true, 'aria-label': label }: NavigationListProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n const id = useId();\n const panelRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const initialized = useRef(false);\n const open = !root || expanded;\n\n useLayoutEffect(() => {\n const panel = panelRef.current;\n const list = listRef.current;\n if (!panel || !list) return;\n if (!open && panel.contains(document.activeElement)) {\n rootRef.current?.querySelector<HTMLButtonElement>('[aria-expanded]')?.focus();\n }\n const updateHeight = () => {\n panel.style.height = `${open ? list.getBoundingClientRect().height : 0}px`;\n };\n // Initialize without an entrance animation, including defaultExpanded=false.\n if (!initialized.current) {\n panel.style.transition = 'none';\n updateHeight();\n void panel.offsetHeight;\n panel.style.removeProperty('transition');\n initialized.current = true;\n } else {\n updateHeight();\n }\n // Observe the natural content, not the animated wrapper, to avoid feedback loops.\n const observer = new ResizeObserver(updateHeight);\n observer.observe(list);\n return () => observer.disconnect();\n }, [open]);\n const itemButton = (item: NavigationListItem) => <Button type=\"button\" variant=\"ghost\" className=\"dishui-navigation-list__item\" aria-pressed={value === item.value} onClick={() => onValueChange(item.value)}>\n <span className=\"dishui-navigation-list__label\">{item.label}</span>\n {item.count !== undefined && <span className=\"dishui-navigation-list__count\">{item.count}</span>}\n </Button>;\n return <div className=\"dishui-navigation-list\" role=\"group\" aria-label={label}>\n {root && <div ref={rootRef} className=\"dishui-navigation-list__root\">\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" className=\"dishui-navigation-list__disclosure\" aria-label={`${expanded ? '折叠' : '展开'}${label}`} aria-expanded={expanded} aria-controls={id} onClick={() => setExpanded(current => !current)}><svg className=\"dishui-navigation-list__chevron\" data-expanded={expanded} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" aria-hidden=\"true\"><path d=\"m6 3 5 5-5 5\" /></svg></Button>\n {itemButton(root)}\n </div>}\n <div id={id} ref={panelRef} className=\"dishui-navigation-list__panel\" inert={!open} aria-hidden={!open || undefined}>\n <ul ref={listRef} className={root ? 'dishui-navigation-list__children' : undefined}>\n {items.map(item => <li key={item.value}>{itemButton(item)}</li>)}\n </ul>\n </div>\n </div>;\n}\n"],"mappings":";;;;;AAqBA,
|
|
1
|
+
{"version":3,"file":"index.js","names":["Button","ButtonWithCompounds","NavigationList","label","expanded","setExpanded","useState","defaultExpanded","id","useId","panelRef","useRef","listRef","rootRef","initialized","open","root","panel","list","updateHeight","observer","itemButton","value","item","onValueChange","current","items"],"sources":["../../../src/components/NavigationList/index.tsx"],"sourcesContent":["import React, { useId, useLayoutEffect, useRef, useState } from 'react';\nimport Button from '../Button';\nimport './NavigationList.css';\n\nexport type NavigationListItem = {\n value: string;\n label: React.ReactNode;\n count?: React.ReactNode;\n};\n\nexport type NavigationListProps = {\n 'aria-label': string;\n items: readonly NavigationListItem[];\n value: string;\n onValueChange: (value: string) => void;\n /** Optional selectable parent with a separate disclosure control. */\n root?: NavigationListItem;\n defaultExpanded?: boolean;\n};\n\n/** A single-level navigation/filter list with native keyboard-operable controls. */\nexport default function NavigationList({ items, value, onValueChange, root, defaultExpanded = true, 'aria-label': label }: NavigationListProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n const id = useId();\n const panelRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const initialized = useRef(false);\n const open = !root || expanded;\n\n useLayoutEffect(() => {\n const panel = panelRef.current;\n const list = listRef.current;\n if (!panel || !list) return;\n if (!open && panel.contains(document.activeElement)) {\n rootRef.current?.querySelector<HTMLButtonElement>('[aria-expanded]')?.focus();\n }\n const updateHeight = () => {\n panel.style.height = `${open ? list.getBoundingClientRect().height : 0}px`;\n };\n // Initialize without an entrance animation, including defaultExpanded=false.\n if (!initialized.current) {\n panel.style.transition = 'none';\n updateHeight();\n void panel.offsetHeight;\n panel.style.removeProperty('transition');\n initialized.current = true;\n } else {\n updateHeight();\n }\n // Observe the natural content, not the animated wrapper, to avoid feedback loops.\n const observer = new ResizeObserver(updateHeight);\n observer.observe(list);\n return () => observer.disconnect();\n }, [open]);\n const itemButton = (item: NavigationListItem) => <Button type=\"button\" variant=\"ghost\" className=\"dishui-navigation-list__item\" aria-pressed={value === item.value} onClick={() => onValueChange(item.value)}>\n <span className=\"dishui-navigation-list__label\">{item.label}</span>\n {item.count !== undefined && <span className=\"dishui-navigation-list__count\">{item.count}</span>}\n </Button>;\n return <div className=\"dishui-navigation-list\" role=\"group\" aria-label={label}>\n {root && <div ref={rootRef} className=\"dishui-navigation-list__root\">\n <Button type=\"button\" variant=\"ghost\" size=\"xs\" className=\"dishui-navigation-list__disclosure\" aria-label={`${expanded ? '折叠' : '展开'}${label}`} aria-expanded={expanded} aria-controls={id} onClick={() => setExpanded(current => !current)}><svg className=\"dishui-navigation-list__chevron\" data-expanded={expanded} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" aria-hidden=\"true\"><path d=\"m6 3 5 5-5 5\" /></svg></Button>\n {itemButton(root)}\n </div>}\n <div id={id} ref={panelRef} className=\"dishui-navigation-list__panel\" inert={!open} aria-hidden={!open || undefined}>\n <ul ref={listRef} className={root ? 'dishui-navigation-list__children' : undefined}>\n {items.map(item => <li key={item.value}>{itemButton(item)}</li>)}\n </ul>\n </div>\n </div>;\n}\n"],"mappings":";;;;;AAqBA,SAAwBE,EAAe,EAAE,UAAO,UAAO,kBAAe,SAAM,qBAAkB,IAAM,cAAcC,KAA8B;CAC5I,IAAM,CAACC,GAAUC,KAAeC,EAASC,CAAe,GAClDC,IAAKC,EAAM,GACXC,IAAWC,EAAuB,IAAI,GACtCC,IAAUD,EAAyB,IAAI,GACvCE,IAAUF,EAAuB,IAAI,GACrCG,IAAcH,EAAO,EAAK,GAC1BI,IAAO,CAACC,KAAQZ;CAEtB,QAAsB;EAClB,IAAMa,IAAQP,EAAS,SACjBQ,IAAON,EAAQ;EACrB,IAAI,CAACK,KAAS,CAACC,GAAM;EACrB,AAAI,CAACH,KAAQE,EAAM,SAAS,SAAS,aAAa,KAC9CJ,EAAQ,SAAS,cAAiC,iBAAiB,CAAC,EAAE,MAAM;EAEhF,IAAMM,UAAqB;GACvB,EAAM,MAAM,SAAS,GAAGJ,IAAOG,EAAK,sBAAsB,CAAC,CAAC,SAAS,EAAE;EAC3E;EAEA,AAAKJ,EAAY,UAObK,EAAa,KANb,EAAM,MAAM,aAAa,QACzBA,EAAa,GACbF,EAAW,cACXA,EAAM,MAAM,eAAe,YAAY,GACvC,EAAY,UAAU;EAK1B,IAAMG,IAAW,IAAI,eAAeD,CAAY;EAEhD,OADAC,EAAS,QAAQF,CAAI,SACRE,EAAS,WAAW;CACrC,GAAG,CAACL,CAAI,CAAC;CACT,IAAMM,KAAc,MAA6B,kBAACrB,GAAD;EAAQ,MAAK;EAAS,SAAQ;EAAQ,WAAU;EAA+B,gBAAcsB,MAAUC,EAAK;EAAO,eAAeC,EAAcD,EAAK,KAAK;EAA1J,UAAA,CAC7C,kBAAC,QAAD;GAAM,WAAU;GAAiC,UAAAA,EAAK;EAAY,CAAA,GACjEA,EAAK,UAAU,KAAA,KAAa,kBAAC,QAAD;GAAM,WAAU;GAAiC,UAAAA,EAAK;EAAY,CAAA,CAC3F;;CACR,OAAO,kBAAC,OAAD;EAAK,WAAU;EAAyB,MAAK;EAAQ,cAAYpB;EAAjE,UAAA,CACFa,KAAQ,kBAAC,OAAD;GAAK,KAAKH;GAAS,WAAU;GAA7B,UAAA,CACL,kBAACb,GAAD;IAAQ,MAAK;IAAS,SAAQ;IAAQ,MAAK;IAAK,WAAU;IAAqC,cAAY,GAAGI,IAAW,OAAO,OAAOD;IAAS,iBAAeC;IAAU,iBAAeI;IAAI,eAAeH,GAAY,MAAW,CAACoB,CAAO;IAAG,UAAA,kBAAC,OAAD;KAAK,WAAU;KAAkC,iBAAerB;KAAU,OAAM;KAAK,QAAO;KAAK,SAAQ;KAAY,MAAK;KAAO,QAAO;KAAe,aAAY;KAAM,eAAY;KAAO,UAAA,kBAAC,QAAD,EAAM,GAAE,eAAgB,CAAA;IAAM,CAAA;GAAS,CAAA,GAC/ciB,EAAWL,CAAI,CACf;EACL,CAAA,GAAA,kBAAC,OAAD;GAAS;GAAI,KAAKN;GAAU,WAAU;GAAgC,OAAO,CAACK;GAAM,eAAa,CAACA,KAAQ,KAAA;GACtG,UAAA,kBAAC,MAAD;IAAI,KAAKH;IAAS,WAAWI,IAAO,qCAAqC,KAAA;IACpE,UAAAU,EAAM,KAAI,MAAQ,kBAAC,MAAD,EAAA,UAAsBL,EAAWE,CAAI,EAAM,GAAlCA,EAAK,KAA6B,CAAC;GAC/D,CAAA;EACH,CAAA,CACJ;;AACT"}
|