@flanksource/clicky-ui 0.3.44 → 0.3.46
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/README.md +24 -0
- package/dist/ai.cjs +4 -2
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.js +3 -1
- package/dist/components/MdxEditorField.cjs +40 -22
- package/dist/components/MdxEditorField.cjs.map +1 -1
- package/dist/components/MdxEditorField.d.ts.map +1 -1
- package/dist/components/MdxEditorField.js +41 -23
- package/dist/components/MdxEditorField.js.map +1 -1
- package/dist/components/json-schema-form-item-summary.cjs +6 -1
- package/dist/components/json-schema-form-item-summary.cjs.map +1 -1
- package/dist/components/json-schema-form-item-summary.d.ts.map +1 -1
- package/dist/components/json-schema-form-item-summary.js +6 -1
- package/dist/components/json-schema-form-item-summary.js.map +1 -1
- package/dist/data/AccessMark.cjs +23 -0
- package/dist/data/AccessMark.cjs.map +1 -0
- package/dist/data/AccessMark.d.ts +11 -0
- package/dist/data/AccessMark.d.ts.map +1 -0
- package/dist/data/AccessMark.js +23 -0
- package/dist/data/AccessMark.js.map +1 -0
- package/dist/data/CodeBlock.cjs +3 -2
- package/dist/data/CodeBlock.cjs.map +1 -1
- package/dist/data/CodeBlock.d.ts +3 -1
- package/dist/data/CodeBlock.d.ts.map +1 -1
- package/dist/data/CodeBlock.js +3 -2
- package/dist/data/CodeBlock.js.map +1 -1
- package/dist/data/CodeDiff.cjs +116 -23
- package/dist/data/CodeDiff.cjs.map +1 -1
- package/dist/data/CodeDiff.d.ts +26 -0
- package/dist/data/CodeDiff.d.ts.map +1 -1
- package/dist/data/CodeDiff.js +116 -23
- package/dist/data/CodeDiff.js.map +1 -1
- package/dist/data/GraphDiagram.cjs +75 -11
- package/dist/data/GraphDiagram.cjs.map +1 -1
- package/dist/data/GraphDiagram.d.ts +17 -2
- package/dist/data/GraphDiagram.d.ts.map +1 -1
- package/dist/data/GraphDiagram.js +76 -12
- package/dist/data/GraphDiagram.js.map +1 -1
- package/dist/data/GraphDiagramGroups.cjs +100 -0
- package/dist/data/GraphDiagramGroups.cjs.map +1 -0
- package/dist/data/GraphDiagramGroups.d.ts +24 -0
- package/dist/data/GraphDiagramGroups.d.ts.map +1 -0
- package/dist/data/GraphDiagramGroups.js +100 -0
- package/dist/data/GraphDiagramGroups.js.map +1 -0
- package/dist/data/GraphDiagramNodes.cjs +46 -51
- package/dist/data/GraphDiagramNodes.cjs.map +1 -1
- package/dist/data/GraphDiagramNodes.d.ts +8 -9
- package/dist/data/GraphDiagramNodes.d.ts.map +1 -1
- package/dist/data/GraphDiagramNodes.js +46 -51
- package/dist/data/GraphDiagramNodes.js.map +1 -1
- package/dist/data/JsonView.cjs +118 -49
- package/dist/data/JsonView.cjs.map +1 -1
- package/dist/data/JsonView.d.ts +13 -10
- package/dist/data/JsonView.d.ts.map +1 -1
- package/dist/data/JsonView.js +118 -49
- package/dist/data/JsonView.js.map +1 -1
- package/dist/data/MarkdownEditor.cjs +2 -2
- package/dist/data/MarkdownEditor.cjs.map +1 -1
- package/dist/data/MarkdownEditor.js +2 -2
- package/dist/data/MarkdownEditor.js.map +1 -1
- package/dist/data/TreeNode.cjs +1 -1
- package/dist/data/TreeNode.cjs.map +1 -1
- package/dist/data/TreeNode.d.ts.map +1 -1
- package/dist/data/TreeNode.js +1 -1
- package/dist/data/TreeNode.js.map +1 -1
- package/dist/data/ai/AdvancedChatConfig.cjs +90 -249
- package/dist/data/ai/AdvancedChatConfig.cjs.map +1 -1
- package/dist/data/ai/AdvancedChatConfig.d.ts +2 -5
- package/dist/data/ai/AdvancedChatConfig.d.ts.map +1 -1
- package/dist/data/ai/AdvancedChatConfig.js +91 -250
- package/dist/data/ai/AdvancedChatConfig.js.map +1 -1
- package/dist/data/ai/ChatButton.cjs +2 -0
- package/dist/data/ai/ChatButton.cjs.map +1 -1
- package/dist/data/ai/ChatButton.d.ts +1 -1
- package/dist/data/ai/ChatButton.d.ts.map +1 -1
- package/dist/data/ai/ChatButton.js +2 -0
- package/dist/data/ai/ChatButton.js.map +1 -1
- package/dist/data/ai/ChatFab.cjs +5 -1
- package/dist/data/ai/ChatFab.cjs.map +1 -1
- package/dist/data/ai/ChatFab.d.ts +5 -1
- package/dist/data/ai/ChatFab.d.ts.map +1 -1
- package/dist/data/ai/ChatFab.js +5 -1
- package/dist/data/ai/ChatFab.js.map +1 -1
- package/dist/data/ai/ChatWindow.cjs +2 -8
- package/dist/data/ai/ChatWindow.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.js +2 -8
- package/dist/data/ai/ChatWindow.js.map +1 -1
- package/dist/data/ai/ChatWindow.runtime.cjs +0 -5
- package/dist/data/ai/ChatWindow.runtime.cjs.map +1 -1
- package/dist/data/ai/ChatWindow.runtime.d.ts +0 -2
- package/dist/data/ai/ChatWindow.runtime.d.ts.map +1 -1
- package/dist/data/ai/ChatWindow.runtime.js +0 -5
- package/dist/data/ai/ChatWindow.runtime.js.map +1 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.cjs +2 -2
- package/dist/data/ai/PromptRunEditor/runtimeActions.cjs.map +1 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.d.ts.map +1 -1
- package/dist/data/ai/PromptRunEditor/runtimeActions.js +2 -2
- package/dist/data/ai/PromptRunEditor/runtimeActions.js.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.cjs +3 -6
- package/dist/data/ai/SessionInspector.approvals.cjs.map +1 -1
- package/dist/data/ai/SessionInspector.approvals.js +3 -6
- package/dist/data/ai/SessionInspector.approvals.js.map +1 -1
- package/dist/data/ai/SessionViewer.cjs +13 -4
- package/dist/data/ai/SessionViewer.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.d.ts +5 -1
- package/dist/data/ai/SessionViewer.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.header.cjs +1 -1
- package/dist/data/ai/SessionViewer.header.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.header.js +1 -1
- package/dist/data/ai/SessionViewer.header.js.map +1 -1
- package/dist/data/ai/SessionViewer.js +13 -4
- package/dist/data/ai/SessionViewer.js.map +1 -1
- package/dist/data/ai/SessionViewer.model.cjs +2 -0
- package/dist/data/ai/SessionViewer.model.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.model.d.ts +1 -0
- package/dist/data/ai/SessionViewer.model.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.model.js +2 -0
- package/dist/data/ai/SessionViewer.model.js.map +1 -1
- package/dist/data/ai/SessionViewer.rows.cjs +41 -27
- package/dist/data/ai/SessionViewer.rows.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.rows.d.ts +4 -2
- package/dist/data/ai/SessionViewer.rows.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.rows.js +41 -27
- package/dist/data/ai/SessionViewer.rows.js.map +1 -1
- package/dist/data/ai/SessionViewer.tokens.cjs +35 -0
- package/dist/data/ai/SessionViewer.tokens.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.tokens.d.ts +5 -0
- package/dist/data/ai/SessionViewer.tokens.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.tokens.js +35 -0
- package/dist/data/ai/SessionViewer.tokens.js.map +1 -0
- package/dist/data/ai/SessionViewer.tool-cost.cjs +128 -0
- package/dist/data/ai/SessionViewer.tool-cost.cjs.map +1 -0
- package/dist/data/ai/SessionViewer.tool-cost.d.ts +6 -0
- package/dist/data/ai/SessionViewer.tool-cost.d.ts.map +1 -0
- package/dist/data/ai/SessionViewer.tool-cost.js +128 -0
- package/dist/data/ai/SessionViewer.tool-cost.js.map +1 -0
- package/dist/data/ai/SessionViewer.tool-details.cjs +3 -1
- package/dist/data/ai/SessionViewer.tool-details.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.tool-details.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.tool-details.js +3 -1
- package/dist/data/ai/SessionViewer.tool-details.js.map +1 -1
- package/dist/data/ai/SessionViewer.tool-row.cjs +55 -35
- package/dist/data/ai/SessionViewer.tool-row.cjs.map +1 -1
- package/dist/data/ai/SessionViewer.tool-row.d.ts +2 -1
- package/dist/data/ai/SessionViewer.tool-row.d.ts.map +1 -1
- package/dist/data/ai/SessionViewer.tool-row.js +55 -35
- package/dist/data/ai/SessionViewer.tool-row.js.map +1 -1
- package/dist/data/ai/SessionViewer.unified.d.ts +4 -0
- package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
- package/dist/data/ai/SessionViewerMenu.cjs +18 -1
- package/dist/data/ai/SessionViewerMenu.cjs.map +1 -1
- package/dist/data/ai/SessionViewerMenu.d.ts +6 -1
- package/dist/data/ai/SessionViewerMenu.d.ts.map +1 -1
- package/dist/data/ai/SessionViewerMenu.js +18 -1
- package/dist/data/ai/SessionViewerMenu.js.map +1 -1
- package/dist/data/ai/ToolPreferences.cjs +149 -143
- package/dist/data/ai/ToolPreferences.cjs.map +1 -1
- package/dist/data/ai/ToolPreferences.d.ts +20 -6
- package/dist/data/ai/ToolPreferences.d.ts.map +1 -1
- package/dist/data/ai/ToolPreferences.js +151 -146
- package/dist/data/ai/ToolPreferences.js.map +1 -1
- package/dist/data/ai/ToolPreferences.model.cjs +14 -10
- package/dist/data/ai/ToolPreferences.model.cjs.map +1 -1
- package/dist/data/ai/ToolPreferences.model.d.ts +1 -0
- package/dist/data/ai/ToolPreferences.model.d.ts.map +1 -1
- package/dist/data/ai/ToolPreferences.model.js +15 -11
- package/dist/data/ai/ToolPreferences.model.js.map +1 -1
- package/dist/data/ai/ToolPreferencesList.cjs +1 -0
- package/dist/data/ai/ToolPreferencesList.cjs.map +1 -1
- package/dist/data/ai/ToolPreferencesList.d.ts +4 -1
- package/dist/data/ai/ToolPreferencesList.d.ts.map +1 -1
- package/dist/data/ai/ToolPreferencesList.js +2 -1
- package/dist/data/ai/ToolPreferencesList.js.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.cjs +52 -53
- package/dist/data/ai/ToolSchemaBrowser.cjs.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.d.ts +6 -3
- package/dist/data/ai/ToolSchemaBrowser.d.ts.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs +9 -13
- package/dist/data/ai/ToolSchemaBrowser.directory-header.cjs.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts +5 -2
- package/dist/data/ai/ToolSchemaBrowser.directory-header.d.ts.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.directory-header.js +9 -13
- package/dist/data/ai/ToolSchemaBrowser.directory-header.js.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.js +53 -54
- package/dist/data/ai/ToolSchemaBrowser.js.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.model.cjs +19 -27
- package/dist/data/ai/ToolSchemaBrowser.model.cjs.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.model.d.ts +9 -6
- package/dist/data/ai/ToolSchemaBrowser.model.d.ts.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.model.js +20 -28
- package/dist/data/ai/ToolSchemaBrowser.model.js.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs +12 -213
- package/dist/data/ai/ToolSchemaBrowser.sidebar.cjs.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts +1 -3
- package/dist/data/ai/ToolSchemaBrowser.sidebar.d.ts.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.sidebar.js +13 -214
- package/dist/data/ai/ToolSchemaBrowser.sidebar.js.map +1 -1
- package/dist/data/ai/ToolSchemaBrowser.strategies.cjs +54 -0
- package/dist/data/ai/ToolSchemaBrowser.strategies.cjs.map +1 -0
- package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts +9 -0
- package/dist/data/ai/ToolSchemaBrowser.strategies.d.ts.map +1 -0
- package/dist/data/ai/ToolSchemaBrowser.strategies.js +54 -0
- package/dist/data/ai/ToolSchemaBrowser.strategies.js.map +1 -0
- package/dist/data/ai/ToolSchemaBrowser.tree.cjs +179 -0
- package/dist/data/ai/ToolSchemaBrowser.tree.cjs.map +1 -0
- package/dist/data/ai/ToolSchemaBrowser.tree.d.ts +20 -0
- package/dist/data/ai/ToolSchemaBrowser.tree.d.ts.map +1 -0
- package/dist/data/ai/ToolSchemaBrowser.tree.js +179 -0
- package/dist/data/ai/ToolSchemaBrowser.tree.js.map +1 -0
- package/dist/data/ai/index.d.ts +2 -2
- package/dist/data/ai/index.d.ts.map +1 -1
- package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs +8 -28
- package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.cjs.map +1 -1
- package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.d.ts.map +1 -1
- package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js +9 -29
- package/dist/data/ai/runtime-profiles/PermissionStrategiesEditor.js.map +1 -1
- package/dist/data/ai/session-token-sizing.d.ts +32 -0
- package/dist/data/ai/session-token-sizing.d.ts.map +1 -0
- package/dist/data/ai/use-session-token-sizing.cjs +73 -0
- package/dist/data/ai/use-session-token-sizing.cjs.map +1 -0
- package/dist/data/ai/use-session-token-sizing.d.ts +21 -0
- package/dist/data/ai/use-session-token-sizing.d.ts.map +1 -0
- package/dist/data/ai/use-session-token-sizing.js +73 -0
- package/dist/data/ai/use-session-token-sizing.js.map +1 -0
- package/dist/data/call-graph/CallGraph.cjs +269 -0
- package/dist/data/call-graph/CallGraph.cjs.map +1 -0
- package/dist/data/call-graph/CallGraph.d.ts +78 -0
- package/dist/data/call-graph/CallGraph.d.ts.map +1 -0
- package/dist/data/call-graph/CallGraph.js +269 -0
- package/dist/data/call-graph/CallGraph.js.map +1 -0
- package/dist/data/call-graph/CallGraphGlyphs.cjs +39 -0
- package/dist/data/call-graph/CallGraphGlyphs.cjs.map +1 -0
- package/dist/data/call-graph/CallGraphGlyphs.d.ts +19 -0
- package/dist/data/call-graph/CallGraphGlyphs.d.ts.map +1 -0
- package/dist/data/call-graph/CallGraphGlyphs.js +39 -0
- package/dist/data/call-graph/CallGraphGlyphs.js.map +1 -0
- package/dist/data/call-graph/CallGraphMembers.cjs +51 -0
- package/dist/data/call-graph/CallGraphMembers.cjs.map +1 -0
- package/dist/data/call-graph/CallGraphMembers.d.ts +22 -0
- package/dist/data/call-graph/CallGraphMembers.d.ts.map +1 -0
- package/dist/data/call-graph/CallGraphMembers.js +51 -0
- package/dist/data/call-graph/CallGraphMembers.js.map +1 -0
- package/dist/data/call-graph/CallGraphParts.cjs +204 -0
- package/dist/data/call-graph/CallGraphParts.cjs.map +1 -0
- package/dist/data/call-graph/CallGraphParts.d.ts +44 -0
- package/dist/data/call-graph/CallGraphParts.d.ts.map +1 -0
- package/dist/data/call-graph/CallGraphParts.js +204 -0
- package/dist/data/call-graph/CallGraphParts.js.map +1 -0
- package/dist/data/call-graph/CallGraphToolbar.cjs +198 -0
- package/dist/data/call-graph/CallGraphToolbar.cjs.map +1 -0
- package/dist/data/call-graph/CallGraphToolbar.d.ts +55 -0
- package/dist/data/call-graph/CallGraphToolbar.d.ts.map +1 -0
- package/dist/data/call-graph/CallGraphToolbar.js +198 -0
- package/dist/data/call-graph/CallGraphToolbar.js.map +1 -0
- package/dist/data/call-graph/call-graph-exclude.cjs +75 -0
- package/dist/data/call-graph/call-graph-exclude.cjs.map +1 -0
- package/dist/data/call-graph/call-graph-exclude.d.ts +31 -0
- package/dist/data/call-graph/call-graph-exclude.d.ts.map +1 -0
- package/dist/data/call-graph/call-graph-exclude.js +75 -0
- package/dist/data/call-graph/call-graph-exclude.js.map +1 -0
- package/dist/data/call-graph/call-graph-labels.cjs +96 -0
- package/dist/data/call-graph/call-graph-labels.cjs.map +1 -0
- package/dist/data/call-graph/call-graph-labels.d.ts +53 -0
- package/dist/data/call-graph/call-graph-labels.d.ts.map +1 -0
- package/dist/data/call-graph/call-graph-labels.js +96 -0
- package/dist/data/call-graph/call-graph-labels.js.map +1 -0
- package/dist/data/call-graph/call-graph-model.cjs +312 -0
- package/dist/data/call-graph/call-graph-model.cjs.map +1 -0
- package/dist/data/call-graph/call-graph-model.d.ts +138 -0
- package/dist/data/call-graph/call-graph-model.d.ts.map +1 -0
- package/dist/data/call-graph/call-graph-model.js +312 -0
- package/dist/data/call-graph/call-graph-model.js.map +1 -0
- package/dist/data/call-graph/call-graph-vocabulary.cjs +195 -0
- package/dist/data/call-graph/call-graph-vocabulary.cjs.map +1 -0
- package/dist/data/call-graph/call-graph-vocabulary.d.ts +76 -0
- package/dist/data/call-graph/call-graph-vocabulary.d.ts.map +1 -0
- package/dist/data/call-graph/call-graph-vocabulary.js +195 -0
- package/dist/data/call-graph/call-graph-vocabulary.js.map +1 -0
- package/dist/data/call-graph/call-graph.fixtures.d.ts +63 -0
- package/dist/data/call-graph/call-graph.fixtures.d.ts.map +1 -0
- package/dist/data/call-graph/index.d.ts +7 -0
- package/dist/data/call-graph/index.d.ts.map +1 -0
- package/dist/data/call-graph/types.cjs +5 -0
- package/dist/data/call-graph/types.cjs.map +1 -0
- package/dist/data/call-graph/types.d.ts +140 -0
- package/dist/data/call-graph/types.d.ts.map +1 -0
- package/dist/data/call-graph/types.js +5 -0
- package/dist/data/call-graph/types.js.map +1 -0
- package/dist/data/call-graph/use-call-graph.cjs +93 -0
- package/dist/data/call-graph/use-call-graph.cjs.map +1 -0
- package/dist/data/call-graph/use-call-graph.d.ts +24 -0
- package/dist/data/call-graph/use-call-graph.d.ts.map +1 -0
- package/dist/data/call-graph/use-call-graph.js +93 -0
- package/dist/data/call-graph/use-call-graph.js.map +1 -0
- package/dist/data/chat/Chat.cjs +39 -15
- package/dist/data/chat/Chat.cjs.map +1 -1
- package/dist/data/chat/Chat.d.ts.map +1 -1
- package/dist/data/chat/Chat.fixtures.cjs +2 -2
- package/dist/data/chat/Chat.fixtures.cjs.map +1 -1
- package/dist/data/chat/Chat.fixtures.js +2 -2
- package/dist/data/chat/Chat.fixtures.js.map +1 -1
- package/dist/data/chat/Chat.js +40 -16
- package/dist/data/chat/Chat.js.map +1 -1
- package/dist/data/chat/ChatRuntimeToolbar.cjs +3 -6
- package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
- package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
- package/dist/data/chat/ChatRuntimeToolbar.js +3 -6
- package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
- package/dist/data/chat/ContextMeter.bar.cjs +5 -8
- package/dist/data/chat/ContextMeter.bar.cjs.map +1 -1
- package/dist/data/chat/ContextMeter.bar.d.ts +1 -1
- package/dist/data/chat/ContextMeter.bar.d.ts.map +1 -1
- package/dist/data/chat/ContextMeter.bar.js +5 -8
- package/dist/data/chat/ContextMeter.bar.js.map +1 -1
- package/dist/data/chat/ContextMeter.cjs +18 -19
- package/dist/data/chat/ContextMeter.cjs.map +1 -1
- package/dist/data/chat/ContextMeter.d.ts +1 -1
- package/dist/data/chat/ContextMeter.d.ts.map +1 -1
- package/dist/data/chat/ContextMeter.js +18 -19
- package/dist/data/chat/ContextMeter.js.map +1 -1
- package/dist/data/chat/Conversation.cjs +2 -1
- package/dist/data/chat/Conversation.cjs.map +1 -1
- package/dist/data/chat/Conversation.d.ts +4 -1
- package/dist/data/chat/Conversation.d.ts.map +1 -1
- package/dist/data/chat/Conversation.js +2 -1
- package/dist/data/chat/Conversation.js.map +1 -1
- package/dist/data/chat/Message.cjs +39 -12
- package/dist/data/chat/Message.cjs.map +1 -1
- package/dist/data/chat/Message.d.ts +1 -1
- package/dist/data/chat/Message.d.ts.map +1 -1
- package/dist/data/chat/Message.js +40 -13
- package/dist/data/chat/Message.js.map +1 -1
- package/dist/data/chat/ToolCall.cjs +60 -5
- package/dist/data/chat/ToolCall.cjs.map +1 -1
- package/dist/data/chat/ToolCall.d.ts +7 -2
- package/dist/data/chat/ToolCall.d.ts.map +1 -1
- package/dist/data/chat/ToolCall.js +60 -5
- package/dist/data/chat/ToolCall.js.map +1 -1
- package/dist/data/chat/approval.cjs.map +1 -1
- package/dist/data/chat/approval.d.ts +2 -2
- package/dist/data/chat/approval.d.ts.map +1 -1
- package/dist/data/chat/approval.js.map +1 -1
- package/dist/data/chat/tool-policy.cjs +59 -2
- package/dist/data/chat/tool-policy.cjs.map +1 -1
- package/dist/data/chat/tool-policy.d.ts +9 -0
- package/dist/data/chat/tool-policy.d.ts.map +1 -1
- package/dist/data/chat/tool-policy.js +59 -2
- package/dist/data/chat/tool-policy.js.map +1 -1
- package/dist/data/chat/types.cjs +6 -0
- package/dist/data/chat/types.cjs.map +1 -1
- package/dist/data/chat/types.d.ts +13 -4
- package/dist/data/chat/types.d.ts.map +1 -1
- package/dist/data/chat/types.js +7 -1
- package/dist/data/chat/types.js.map +1 -1
- package/dist/data/chat/usage-snapshot.cjs +11 -6
- package/dist/data/chat/usage-snapshot.cjs.map +1 -1
- package/dist/data/chat/usage-snapshot.d.ts +0 -1
- package/dist/data/chat/usage-snapshot.d.ts.map +1 -1
- package/dist/data/chat/usage-snapshot.js +11 -6
- package/dist/data/chat/usage-snapshot.js.map +1 -1
- package/dist/data/data-access.cjs +8 -0
- package/dist/data/data-access.cjs.map +1 -0
- package/dist/data/data-access.d.ts +5 -0
- package/dist/data/data-access.d.ts.map +1 -0
- package/dist/data/data-access.js +8 -0
- package/dist/data/data-access.js.map +1 -0
- package/dist/data/diagnostics/StackFrameRow.cjs +3 -3
- package/dist/data/diagnostics/StackFrameRow.cjs.map +1 -1
- package/dist/data/diagnostics/StackFrameRow.js +3 -3
- package/dist/data/diagnostics/StackFrameRow.js.map +1 -1
- package/dist/data/git/GitChangeList.cjs +6 -2
- package/dist/data/git/GitChangeList.cjs.map +1 -1
- package/dist/data/git/GitChangeList.d.ts +6 -1
- package/dist/data/git/GitChangeList.d.ts.map +1 -1
- package/dist/data/git/GitChangeList.js +6 -2
- package/dist/data/git/GitChangeList.js.map +1 -1
- package/dist/data/graph-columns-layout.cjs +61 -14
- package/dist/data/graph-columns-layout.cjs.map +1 -1
- package/dist/data/graph-columns-layout.d.ts +42 -0
- package/dist/data/graph-columns-layout.d.ts.map +1 -1
- package/dist/data/graph-columns-layout.js +61 -14
- package/dist/data/graph-columns-layout.js.map +1 -1
- package/dist/data/graph-diagram-model.cjs +5 -0
- package/dist/data/graph-diagram-model.cjs.map +1 -1
- package/dist/data/graph-diagram-model.d.ts +24 -0
- package/dist/data/graph-diagram-model.d.ts.map +1 -1
- package/dist/data/graph-diagram-model.js +5 -0
- package/dist/data/graph-diagram-model.js.map +1 -1
- package/dist/data/graph-edge-routing.cjs +9 -3
- package/dist/data/graph-edge-routing.cjs.map +1 -1
- package/dist/data/graph-edge-routing.d.ts +2 -0
- package/dist/data/graph-edge-routing.d.ts.map +1 -1
- package/dist/data/graph-edge-routing.js +9 -3
- package/dist/data/graph-edge-routing.js.map +1 -1
- package/dist/data/graph-group-window.cjs +60 -0
- package/dist/data/graph-group-window.cjs.map +1 -0
- package/dist/data/graph-group-window.d.ts +33 -0
- package/dist/data/graph-group-window.d.ts.map +1 -0
- package/dist/data/graph-group-window.js +60 -0
- package/dist/data/graph-group-window.js.map +1 -0
- package/dist/data/json-view/JsonSource.cjs +84 -0
- package/dist/data/json-view/JsonSource.cjs.map +1 -0
- package/dist/data/json-view/JsonSource.d.ts +7 -0
- package/dist/data/json-view/JsonSource.d.ts.map +1 -0
- package/dist/data/json-view/JsonSource.js +84 -0
- package/dist/data/json-view/JsonSource.js.map +1 -0
- package/dist/data/json-view/parse-prefix.cjs +132 -0
- package/dist/data/json-view/parse-prefix.cjs.map +1 -0
- package/dist/data/json-view/parse-prefix.d.ts +11 -0
- package/dist/data/json-view/parse-prefix.d.ts.map +1 -0
- package/dist/data/json-view/parse-prefix.js +132 -0
- package/dist/data/json-view/parse-prefix.js.map +1 -0
- package/dist/data/json-view/parse-source.cjs +62 -0
- package/dist/data/json-view/parse-source.cjs.map +1 -0
- package/dist/data/json-view/parse-source.d.ts +16 -0
- package/dist/data/json-view/parse-source.d.ts.map +1 -0
- package/dist/data/json-view/parse-source.js +62 -0
- package/dist/data/json-view/parse-source.js.map +1 -0
- package/dist/data/json-view/story-fixtures.d.ts +6 -0
- package/dist/data/json-view/story-fixtures.d.ts.map +1 -0
- package/dist/data/json-view/types.d.ts +14 -0
- package/dist/data/json-view/types.d.ts.map +1 -0
- package/dist/data/runtime/RuntimeBar.cjs +2 -5
- package/dist/data/runtime/RuntimeBar.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBar.d.ts +2 -4
- package/dist/data/runtime/RuntimeBar.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBar.fields.cjs +2 -2
- package/dist/data/runtime/RuntimeBar.fields.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBar.fields.js +2 -2
- package/dist/data/runtime/RuntimeBar.fields.js.map +1 -1
- package/dist/data/runtime/RuntimeBar.js +2 -5
- package/dist/data/runtime/RuntimeBar.js.map +1 -1
- package/dist/data/runtime/RuntimeBar.selection.cjs +4 -1
- package/dist/data/runtime/RuntimeBar.selection.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBar.selection.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBar.selection.js +5 -2
- package/dist/data/runtime/RuntimeBar.selection.js.map +1 -1
- package/dist/data/runtime/RuntimeBarActions.cjs +1 -5
- package/dist/data/runtime/RuntimeBarActions.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBarActions.d.ts +1 -1
- package/dist/data/runtime/RuntimeBarActions.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBarActions.js +1 -5
- package/dist/data/runtime/RuntimeBarActions.js.map +1 -1
- package/dist/data/runtime/RuntimeBarIdentity.cjs +6 -14
- package/dist/data/runtime/RuntimeBarIdentity.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBarIdentity.d.ts +0 -1
- package/dist/data/runtime/RuntimeBarIdentity.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBarIdentity.js +6 -14
- package/dist/data/runtime/RuntimeBarIdentity.js.map +1 -1
- package/dist/data/runtime/RuntimeBarLayout.cjs +8 -27
- package/dist/data/runtime/RuntimeBarLayout.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBarLayout.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBarLayout.js +8 -27
- package/dist/data/runtime/RuntimeBarLayout.js.map +1 -1
- package/dist/data/runtime/RuntimeBarSegment.cjs +1 -5
- package/dist/data/runtime/RuntimeBarSegment.cjs.map +1 -1
- package/dist/data/runtime/RuntimeBarSegment.d.ts.map +1 -1
- package/dist/data/runtime/RuntimeBarSegment.js +1 -5
- package/dist/data/runtime/RuntimeBarSegment.js.map +1 -1
- package/dist/data/runtime/use-runtime-bar-overflow.cjs +4 -10
- package/dist/data/runtime/use-runtime-bar-overflow.cjs.map +1 -1
- package/dist/data/runtime/use-runtime-bar-overflow.d.ts +1 -2
- package/dist/data/runtime/use-runtime-bar-overflow.d.ts.map +1 -1
- package/dist/data/runtime/use-runtime-bar-overflow.js +4 -10
- package/dist/data/runtime/use-runtime-bar-overflow.js.map +1 -1
- package/dist/data/test-runner/TestRunner.fixtures.d.ts +0 -20
- package/dist/data/test-runner/TestRunner.fixtures.d.ts.map +1 -1
- package/dist/data/test-runner/TestRunner.large-fixtures.d.ts +22 -0
- package/dist/data/test-runner/TestRunner.large-fixtures.d.ts.map +1 -0
- package/dist/data/use-group-windows.cjs +50 -0
- package/dist/data/use-group-windows.cjs.map +1 -0
- package/dist/data/use-group-windows.d.ts +27 -0
- package/dist/data/use-group-windows.d.ts.map +1 -0
- package/dist/data/use-group-windows.js +50 -0
- package/dist/data/use-group-windows.js.map +1 -0
- package/dist/data/use-pan-zoom.cjs +23 -10
- package/dist/data/use-pan-zoom.cjs.map +1 -1
- package/dist/data/use-pan-zoom.d.ts +16 -2
- package/dist/data/use-pan-zoom.d.ts.map +1 -1
- package/dist/data/use-pan-zoom.js +23 -10
- package/dist/data/use-pan-zoom.js.map +1 -1
- package/dist/data/version-info.cjs +3 -3
- package/dist/data/version-info.js +3 -3
- package/dist/data.cjs +36 -2
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +5 -2
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +35 -1
- package/dist/data.js.map +1 -1
- package/dist/hooks/event-hub.cjs +229 -0
- package/dist/hooks/event-hub.cjs.map +1 -0
- package/dist/hooks/event-hub.d.ts +26 -0
- package/dist/hooks/event-hub.d.ts.map +1 -0
- package/dist/hooks/event-hub.js +229 -0
- package/dist/hooks/event-hub.js.map +1 -0
- package/dist/hooks.cjs +2 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +2 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +40 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +37 -1
- package/dist/index.js.map +1 -1
- package/dist/layout/Workspace.cjs +13 -4
- package/dist/layout/Workspace.cjs.map +1 -1
- package/dist/layout/Workspace.d.ts +7 -2
- package/dist/layout/Workspace.d.ts.map +1 -1
- package/dist/layout/Workspace.js +13 -4
- package/dist/layout/Workspace.js.map +1 -1
- package/dist/lib/permission-strategies.cjs +71 -11
- package/dist/lib/permission-strategies.cjs.map +1 -1
- package/dist/lib/permission-strategies.d.ts +3 -0
- package/dist/lib/permission-strategies.d.ts.map +1 -1
- package/dist/lib/permission-strategies.js +71 -11
- package/dist/lib/permission-strategies.js.map +1 -1
- package/dist/overlay/modalStack.cjs +13 -6
- package/dist/overlay/modalStack.cjs.map +1 -1
- package/dist/overlay/modalStack.d.ts.map +1 -1
- package/dist/overlay/modalStack.js +13 -6
- package/dist/overlay/modalStack.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -3
- package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs +0 -57
- package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.cjs.map +0 -1
- package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts +0 -7
- package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.d.ts.map +0 -1
- package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js +0 -57
- package/dist/data/ai/ToolSchemaBrowser.selection-toolbar.js.map +0 -1
- package/dist/data/runtime/RuntimeBar.context.cjs +0 -8
- package/dist/data/runtime/RuntimeBar.context.cjs.map +0 -1
- package/dist/data/runtime/RuntimeBar.context.d.ts +0 -2
- package/dist/data/runtime/RuntimeBar.context.d.ts.map +0 -1
- package/dist/data/runtime/RuntimeBar.context.js +0 -8
- package/dist/data/runtime/RuntimeBar.context.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkdownEditor.cjs","sources":["../../src/data/MarkdownEditor.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useMemo,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { Button } from \"../components/button\";\nimport { IconButton } from \"../components/IconButton\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../components/SegmentedControl\";\nimport { cn } from \"../lib/utils\";\nimport {\n UiCopy,\n UiEdit,\n UiEye,\n UiFileCode,\n UiFileSpreadsheet,\n UiFileText,\n UiJson,\n UiMarkdown,\n UiRefresh,\n} from \"../icons\";\nimport { Clicky, type ClickyProps } from \"./Clicky\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { JsonView } from \"./JsonView\";\nimport { Markdown } from \"./Markdown\";\nimport {\n buildMarkdownPreviewUrl,\n MARKDOWN_EDITOR_PREVIEW_FORMATS,\n type MarkdownEditorPreviewFormat,\n type MarkdownEditorPreviewHeaders,\n type MarkdownEditorPreviewRequest,\n type MarkdownEditorPreviewResult,\n} from \"./MarkdownEditor.model\";\n\nexport type MarkdownEditorProps = {\n /** Controlled markdown source. */\n value?: string;\n /** Initial markdown source for uncontrolled usage. */\n defaultValue?: string;\n /** Called whenever the editor source changes. */\n onChange?: (value: string) => void;\n /** Editor label. */\n label?: ReactNode;\n /** Textarea placeholder. */\n placeholder?: string;\n /** Preview formats to expose in the toolbar. */\n previewFormats?: readonly MarkdownEditorPreviewFormat[];\n /** Controlled active preview format. */\n previewFormat?: MarkdownEditorPreviewFormat;\n /** Initial active preview format for uncontrolled usage. */\n defaultPreviewFormat?: MarkdownEditorPreviewFormat;\n /** Called when the active preview format changes. */\n onPreviewFormatChange?: (format: MarkdownEditorPreviewFormat) => void;\n /** Clicky endpoint that accepts markdown and a `format=` query parameter. */\n previewEndpoint?: string;\n /** HTTP method for `previewEndpoint`; POST sends the markdown body. */\n previewMethod?: \"GET\" | \"POST\" | \"PUT\";\n /** Extra headers for remote previews. */\n previewHeaders?: MarkdownEditorPreviewHeaders;\n /** Build a URL for remote preview requests instead of `previewEndpoint`. */\n buildPreviewUrl?: (request: {\n markdown: string;\n format: MarkdownEditorPreviewFormat;\n }) => string | undefined;\n /**\n * Custom loader for host-specific markdown conversion. Return `undefined` for\n * a format to leave it on the local preview — Clicky's `format=` contract has\n * no `react`, so hosts commonly convert every other format remotely.\n */\n loadPreview?: (\n request: MarkdownEditorPreviewRequest,\n ) =>\n | Promise<MarkdownEditorPreviewResult | undefined>\n | MarkdownEditorPreviewResult\n | undefined;\n /** Local Clicky document for the React preview, or a mapper from markdown. */\n clickyData?: ClickyProps[\"data\"] | ((markdown: string) => ClickyProps[\"data\"] | undefined);\n /** Debounce interval for remote preview requests. */\n previewDebounceMs?: number;\n /** Minimum height for both editor and preview panes. */\n minHeight?: number | string;\n /** Disable editing and preview refresh. */\n disabled?: boolean;\n /** Render the source as read-only. */\n readOnly?: boolean;\n /** Classes applied to the component root. */\n className?: string;\n /** Classes applied to the textarea. */\n editorClassName?: string;\n /** Classes applied to the preview body. */\n previewClassName?: string;\n /** Extra toolbar content rendered after the built-in actions. */\n toolbar?: ReactNode;\n};\n\ntype PreviewState =\n | { status: \"idle\" }\n | { status: \"loading\"; result?: MarkdownEditorPreviewResult }\n | { status: \"success\"; result: MarkdownEditorPreviewResult }\n | { status: \"error\"; error: string; result?: MarkdownEditorPreviewResult };\n\ntype FormatMeta = {\n label: string;\n icon: StaticIconComponent;\n iconClassName?: string;\n};\n\nconst FORMAT_META: Record<MarkdownEditorPreviewFormat, FormatMeta> = {\n react: {\n label: \"React\",\n icon: UiEye,\n },\n html: {\n label: \"HTML\",\n icon: UiFileCode,\n },\n markdown: {\n label: \"Markdown\",\n icon: UiMarkdown,\n },\n pdf: {\n label: \"PDF\",\n icon: UiFileText,\n iconClassName: \"text-rose-600 dark:text-rose-400\",\n },\n json: {\n label: \"JSON\",\n icon: UiJson,\n },\n csv: {\n label: \"CSV\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-600 dark:text-emerald-400\",\n },\n excel: {\n label: \"Excel\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-700 dark:text-emerald-300\",\n },\n};\n\n/**\n * Split-pane markdown editor with local Markdown/React preview and optional\n * Clicky-backed format previews. Hosts can pass `previewEndpoint` for the\n * standard Clicky `format=` contract or `loadPreview` for custom conversion.\n */\nexport function MarkdownEditor({\n value,\n defaultValue = \"\",\n onChange,\n label = \"Markdown\",\n placeholder = \"Write markdown...\",\n previewFormats,\n previewFormat,\n defaultPreviewFormat,\n onPreviewFormatChange,\n previewEndpoint,\n previewMethod = \"POST\",\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n clickyData,\n previewDebounceMs = 350,\n minHeight = 420,\n disabled = false,\n readOnly = false,\n className,\n editorClassName,\n previewClassName,\n toolbar,\n}: MarkdownEditorProps) {\n const editorId = useId();\n const formats = useMemo(\n () => normalizePreviewFormats(previewFormats),\n [previewFormats],\n );\n const firstFormat = formats[0] ?? \"react\";\n const [draft, setDraft] = useState(defaultValue);\n const markdown = value ?? draft;\n const [internalFormat, setInternalFormat] = useState<MarkdownEditorPreviewFormat>(\n () =>\n normalizeInitialFormat(defaultPreviewFormat, formats) ??\n firstFormat,\n );\n const activeFormat = formats.includes(previewFormat ?? internalFormat)\n ? previewFormat ?? internalFormat\n : firstFormat;\n const [refreshKey, setRefreshKey] = useState(0);\n const [previewState, setPreviewState] = useState<PreviewState>({\n status: \"idle\",\n });\n const contentStyle = useMemo<CSSProperties>(\n () => ({ minHeight: cssSize(minHeight) }),\n [minHeight],\n );\n const remoteEnabled = Boolean(loadPreview || previewEndpoint || buildPreviewUrl);\n const currentMeta = FORMAT_META[activeFormat];\n const segmentOptions = useMemo<SegmentedOption<MarkdownEditorPreviewFormat>[]>(\n () =>\n formats.map((format) => {\n const meta = FORMAT_META[format];\n return {\n id: format,\n label: meta.label,\n icon: meta.icon,\n title: `${meta.label} preview`,\n };\n }),\n [formats],\n );\n\n useEffect(() => {\n if (formats.includes(activeFormat)) return;\n setInternalFormat(firstFormat);\n }, [activeFormat, firstFormat, formats]);\n\n useEffect(() => {\n if (!remoteEnabled) {\n setPreviewState({ status: \"idle\" });\n return;\n }\n\n const controller = new AbortController();\n const timeout = window.setTimeout(() => {\n setPreviewState((current) =>\n current.status === \"success\"\n ? { status: \"loading\", result: current.result }\n : { status: \"loading\" },\n );\n\n resolvePreview({\n markdown,\n format: activeFormat,\n signal: controller.signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n })\n .then((result) => {\n if (controller.signal.aborted) return;\n setPreviewState(\n result ? { status: \"success\", result } : { status: \"idle\" },\n );\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) return;\n setPreviewState((current) => ({\n status: \"error\",\n error: error instanceof Error ? error.message : \"Preview failed\",\n ...(current.status === \"loading\" && current.result\n ? { result: current.result }\n : {}),\n }));\n });\n }, Math.max(0, previewDebounceMs));\n\n return () => {\n window.clearTimeout(timeout);\n controller.abort();\n };\n }, [\n activeFormat,\n buildPreviewUrl,\n loadPreview,\n markdown,\n previewDebounceMs,\n previewEndpoint,\n previewHeaders,\n previewMethod,\n refreshKey,\n remoteEnabled,\n ]);\n\n const updateMarkdown = (next: string) => {\n if (value === undefined) setDraft(next);\n onChange?.(next);\n };\n\n const updateFormat = (next: MarkdownEditorPreviewFormat) => {\n if (previewFormat === undefined) setInternalFormat(next);\n onPreviewFormatChange?.(next);\n };\n\n const copySource = () => {\n const clipboard = globalThis.navigator?.clipboard;\n if (clipboard?.writeText) {\n void clipboard.writeText(markdown).catch(() => undefined);\n }\n };\n\n return (\n <div className={cn(\"rounded-md border border-border bg-card\", className)}>\n <div className=\"flex flex-wrap items-center gap-density-2 border-b border-border px-density-3 py-density-2\">\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Icon icon={UiEdit} className=\"text-base text-muted-foreground\" />\n <label\n htmlFor={editorId}\n className=\"truncate text-sm font-medium text-card-foreground\"\n >\n {label}\n </label>\n {previewState.status === \"loading\" && (\n <span className=\"text-xs text-muted-foreground\">Refreshing...</span>\n )}\n </div>\n <div className=\"flex min-w-0 flex-wrap items-center justify-end gap-2\">\n <SegmentedControl\n value={activeFormat}\n options={segmentOptions}\n onChange={updateFormat}\n size=\"sm\"\n aria-label=\"Markdown preview format\"\n className=\"max-w-full flex-wrap\"\n />\n {remoteEnabled && (\n <IconButton\n icon={UiRefresh}\n label=\"Refresh preview\"\n disabled={disabled}\n onClick={() => setRefreshKey((current) => current + 1)}\n />\n )}\n <IconButton icon={UiCopy} label=\"Copy markdown\" onClick={copySource} />\n {toolbar}\n </div>\n </div>\n\n <div className=\"grid gap-density-3 p-density-3 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]\">\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n Source\n </div>\n <textarea\n id={editorId}\n value={markdown}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n spellCheck\n onChange={(event) => updateMarkdown(event.currentTarget.value)}\n className={cn(\n \"block w-full resize-y border-0 bg-transparent px-density-3 py-density-3 font-mono text-sm leading-6 text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:opacity-60\",\n editorClassName,\n )}\n style={contentStyle}\n />\n </div>\n\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n <Icon\n icon={currentMeta.icon}\n className={cn(\"text-sm\", currentMeta.iconClassName)}\n />\n <span>{currentMeta.label}</span>\n </div>\n <div\n className={cn(\n \"overflow-auto px-density-3 py-density-3\",\n previewClassName,\n )}\n style={contentStyle}\n >\n <MarkdownEditorPreview\n format={activeFormat}\n markdown={markdown}\n state={previewState}\n clickyData={clickyData}\n />\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction MarkdownEditorPreview({\n format,\n markdown,\n state,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n state: PreviewState;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n const result =\n state.status === \"success\" || state.status === \"loading\" || state.status === \"error\"\n ? state.result\n : undefined;\n\n return (\n <div className=\"space-y-density-3\">\n {state.status === \"error\" && (\n <PreviewNotice title=\"Preview failed\" message={state.error} tone=\"danger\" />\n )}\n {result ? (\n <PreviewResult format={format} result={result} />\n ) : (\n <LocalPreview\n format={format}\n markdown={markdown}\n clickyData={clickyData}\n />\n )}\n </div>\n );\n}\n\nfunction LocalPreview({\n format,\n markdown,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n if (format === \"react\") {\n const data =\n typeof clickyData === \"function\" ? clickyData(markdown) : clickyData;\n return data === undefined ? <Markdown text={markdown} /> : <Clicky data={data} />;\n }\n\n if (format === \"markdown\") {\n return <TextPreview label=\"Markdown source\" text={markdown} />;\n }\n\n return (\n <PreviewNotice\n title={`${FORMAT_META[format].label} preview not configured`}\n message=\"Pass previewEndpoint or loadPreview to render this format from Clicky.\"\n />\n );\n}\n\nfunction PreviewResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: MarkdownEditorPreviewResult;\n}) {\n switch (result.kind) {\n case \"clicky\":\n return <Clicky data={result.data} />;\n case \"html\":\n return <HtmlPreview html={result.html} />;\n case \"json\":\n return <JsonView data={result.data} />;\n case \"url\":\n return <UrlPreview format={format} url={result.url} />;\n case \"blob\":\n return <BlobPreview format={format} result={result} />;\n case \"text\":\n return <TextResult format={format} result={result} />;\n }\n}\n\nfunction TextResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"text\" }>;\n}) {\n if (format === \"react\") {\n return <Clicky data={result.text} />;\n }\n\n if (format === \"html\" || isHtmlContent(result.contentType)) {\n return <HtmlPreview html={result.text} />;\n }\n\n if (format === \"json\" || isJsonContent(result.contentType)) {\n const parsed = parseJson(result.text);\n return parsed.ok ? (\n <JsonView data={parsed.value} />\n ) : (\n <TextPreview label=\"JSON output\" text={result.text} />\n );\n }\n\n return (\n <TextPreview\n label={`${FORMAT_META[format].label} output`}\n text={result.text}\n />\n );\n}\n\nfunction UrlPreview({\n format,\n url,\n}: {\n format: MarkdownEditorPreviewFormat;\n url: string;\n}) {\n if (format === \"react\") {\n return <Clicky url={url} view={[\"clicky\"]} download={{ all: false }} />;\n }\n\n if (format === \"html\") {\n return <HtmlPreview src={url} />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n if (format === \"excel\") {\n return <DownloadPreview label=\"Open Excel workbook\" href={url} />;\n }\n\n return <TextPreview label={`${FORMAT_META[format].label} URL`} text={url} />;\n}\n\nfunction BlobPreview({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"blob\" }>;\n}) {\n const [url, setUrl] = useState<string>();\n\n useEffect(() => {\n const next = URL.createObjectURL(result.blob);\n setUrl(next);\n return () => URL.revokeObjectURL(next);\n }, [result.blob]);\n\n if (!url) {\n return <PreviewNotice title=\"Preparing preview\" message=\"Creating object URL.\" />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n return (\n <DownloadPreview\n label={`Open ${FORMAT_META[format].label}`}\n href={url}\n {...(result.filename ? { download: result.filename } : {})}\n />\n );\n}\n\nfunction HtmlPreview({\n html,\n src,\n}: {\n html?: string;\n src?: string;\n}) {\n return (\n <FramePreview\n title=\"HTML preview\"\n {...(src ? { src } : {})}\n {...(html ? { srcDoc: html } : {})}\n sandbox=\"allow-same-origin\"\n />\n );\n}\n\nfunction FramePreview({\n title,\n src,\n srcDoc,\n sandbox,\n}: {\n title: string;\n src?: string;\n srcDoc?: string;\n sandbox?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-md border border-border bg-background\">\n <iframe\n title={title}\n {...(src ? { src } : {})}\n {...(srcDoc ? { srcDoc } : {})}\n {...(sandbox ? { sandbox } : {})}\n className=\"h-[720px] w-full bg-background\"\n />\n </div>\n );\n}\n\nfunction DownloadPreview({\n label,\n href,\n download,\n}: {\n label: string;\n href: string;\n download?: string;\n}) {\n return (\n <PreviewNotice\n title=\"Inline preview unavailable\"\n message={\n <Button asChild variant=\"outline\" size=\"sm\">\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n {...(download ? { download } : {})}\n >\n {label}\n </a>\n </Button>\n }\n />\n );\n}\n\nfunction TextPreview({ label, text }: { label: string; text: string }) {\n return (\n <pre\n aria-label={label}\n className=\"overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-muted/30 px-density-3 py-density-3 font-mono text-xs text-foreground\"\n >\n {text || \"No content\"}\n </pre>\n );\n}\n\nfunction PreviewNotice({\n title,\n message,\n tone = \"default\",\n}: {\n title: string;\n message: ReactNode;\n tone?: \"default\" | \"danger\";\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border p-density-3\",\n tone === \"danger\"\n ? \"border-destructive/30 bg-destructive/5\"\n : \"border-border bg-muted/30\",\n )}\n >\n <div\n className={cn(\n \"text-sm font-medium\",\n tone === \"danger\" && \"text-destructive\",\n )}\n >\n {title}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">{message}</div>\n </div>\n );\n}\n\nfunction normalizePreviewFormats(\n formats: readonly MarkdownEditorPreviewFormat[] | undefined,\n): MarkdownEditorPreviewFormat[] {\n const seen = new Set<MarkdownEditorPreviewFormat>();\n const source = formats && formats.length > 0 ? formats : MARKDOWN_EDITOR_PREVIEW_FORMATS;\n for (const format of source) {\n seen.add(format);\n }\n return [...seen];\n}\n\nfunction normalizeInitialFormat(\n format: MarkdownEditorPreviewFormat | undefined,\n formats: readonly MarkdownEditorPreviewFormat[],\n) {\n return format && formats.includes(format) ? format : undefined;\n}\n\nfunction cssSize(size: number | string) {\n return typeof size === \"number\" ? `${size}px` : size;\n}\n\nasync function resolvePreview({\n markdown,\n format,\n signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n}: MarkdownEditorPreviewRequest & {\n previewEndpoint: string | undefined;\n previewMethod: \"GET\" | \"POST\" | \"PUT\";\n previewHeaders: MarkdownEditorPreviewHeaders | undefined;\n buildPreviewUrl: MarkdownEditorProps[\"buildPreviewUrl\"] | undefined;\n loadPreview: MarkdownEditorProps[\"loadPreview\"] | undefined;\n}): Promise<MarkdownEditorPreviewResult | undefined> {\n if (loadPreview) {\n return loadPreview({ markdown, format, signal });\n }\n\n const url =\n buildPreviewUrl?.({ markdown, format }) ??\n (previewEndpoint\n ? buildMarkdownPreviewUrl(previewEndpoint, format)\n : undefined);\n\n if (!url) {\n throw new Error(\"No preview endpoint configured\");\n }\n\n const headers = new Headers(\n typeof previewHeaders === \"function\"\n ? previewHeaders({ markdown, format })\n : previewHeaders,\n );\n headers.set(\"Accept\", previewAccept(format));\n\n const init: RequestInit = {\n method: previewMethod,\n headers,\n signal,\n };\n\n if (previewMethod !== \"GET\") {\n headers.set(\"Content-Type\", \"text/markdown; charset=utf-8\");\n init.body = markdown;\n }\n\n const response = await fetch(url, init);\n if (!response.ok) {\n throw new Error(\n `Preview failed with ${response.status} ${response.statusText}`.trim(),\n );\n }\n\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n if (format === \"pdf\" || format === \"excel\" || isBinaryContent(contentType)) {\n return {\n kind: \"blob\",\n blob: await response.blob(),\n contentType,\n filename: previewFilename(format),\n };\n }\n\n const text = await response.text();\n if (format === \"react\") {\n return { kind: \"clicky\", data: text };\n }\n if (format === \"html\" || isHtmlContent(contentType)) {\n return { kind: \"html\", html: text };\n }\n if (format === \"json\" || isJsonContent(contentType)) {\n const parsed = parseJson(text);\n return parsed.ok\n ? { kind: \"json\", data: parsed.value }\n : { kind: \"text\", text, contentType };\n }\n return { kind: \"text\", text, contentType };\n}\n\nfunction previewAccept(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"application/json+clicky, application/clicky+json;q=0.9, application/json;q=0.8,*/*;q=0.7\";\n case \"html\":\n return \"text/html, */*;q=0.7\";\n case \"markdown\":\n return \"text/markdown, text/plain;q=0.8,*/*;q=0.7\";\n case \"pdf\":\n return \"application/pdf, */*;q=0.7\";\n case \"json\":\n return \"application/json, text/plain;q=0.8,*/*;q=0.7\";\n case \"csv\":\n return \"text/csv, text/plain;q=0.8,*/*;q=0.7\";\n case \"excel\":\n return \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, */*;q=0.7\";\n }\n}\n\nfunction previewFilename(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"preview.clicky.json\";\n case \"html\":\n return \"preview.html\";\n case \"markdown\":\n return \"preview.md\";\n case \"pdf\":\n return \"preview.pdf\";\n case \"json\":\n return \"preview.json\";\n case \"csv\":\n return \"preview.csv\";\n case \"excel\":\n return \"preview.xlsx\";\n }\n}\n\nfunction parseJson(text: string): { ok: true; value: unknown } | { ok: false } {\n try {\n return { ok: true, value: JSON.parse(text) as unknown };\n } catch {\n return { ok: false };\n }\n}\n\nfunction isJsonContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"json\") ?? false;\n}\n\nfunction isHtmlContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"html\") ?? false;\n}\n\nfunction isBinaryContent(contentType: string | undefined) {\n const normalized = contentType?.toLowerCase() ?? \"\";\n return (\n normalized.includes(\"application/pdf\") ||\n normalized.includes(\"spreadsheetml\") ||\n normalized.includes(\"application/vnd.ms-excel\")\n );\n}\n"],"names":["UiEye","UiFileCode","UiMarkdown","UiFileText","UiJson","UiFileSpreadsheet","useId","useMemo","useState","useEffect","cn","jsxs","jsx","Icon","UiEdit","SegmentedControl","IconButton","UiRefresh","UiCopy","Markdown","Clicky","JsonView","Button","MARKDOWN_EDITOR_PREVIEW_FORMATS","buildMarkdownPreviewUrl"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarkdownEditor.cjs","sources":["../../src/data/MarkdownEditor.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useMemo,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { Button } from \"../components/button\";\nimport { IconButton } from \"../components/IconButton\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../components/SegmentedControl\";\nimport { cn } from \"../lib/utils\";\nimport {\n UiCopy,\n UiEdit,\n UiEye,\n UiFileCode,\n UiFileSpreadsheet,\n UiFileText,\n UiJson,\n UiMarkdown,\n UiRefresh,\n} from \"../icons\";\nimport { Clicky, type ClickyProps } from \"./Clicky\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { JsonView } from \"./JsonView\";\nimport { Markdown } from \"./Markdown\";\nimport {\n buildMarkdownPreviewUrl,\n MARKDOWN_EDITOR_PREVIEW_FORMATS,\n type MarkdownEditorPreviewFormat,\n type MarkdownEditorPreviewHeaders,\n type MarkdownEditorPreviewRequest,\n type MarkdownEditorPreviewResult,\n} from \"./MarkdownEditor.model\";\n\nexport type MarkdownEditorProps = {\n /** Controlled markdown source. */\n value?: string;\n /** Initial markdown source for uncontrolled usage. */\n defaultValue?: string;\n /** Called whenever the editor source changes. */\n onChange?: (value: string) => void;\n /** Editor label. */\n label?: ReactNode;\n /** Textarea placeholder. */\n placeholder?: string;\n /** Preview formats to expose in the toolbar. */\n previewFormats?: readonly MarkdownEditorPreviewFormat[];\n /** Controlled active preview format. */\n previewFormat?: MarkdownEditorPreviewFormat;\n /** Initial active preview format for uncontrolled usage. */\n defaultPreviewFormat?: MarkdownEditorPreviewFormat;\n /** Called when the active preview format changes. */\n onPreviewFormatChange?: (format: MarkdownEditorPreviewFormat) => void;\n /** Clicky endpoint that accepts markdown and a `format=` query parameter. */\n previewEndpoint?: string;\n /** HTTP method for `previewEndpoint`; POST sends the markdown body. */\n previewMethod?: \"GET\" | \"POST\" | \"PUT\";\n /** Extra headers for remote previews. */\n previewHeaders?: MarkdownEditorPreviewHeaders;\n /** Build a URL for remote preview requests instead of `previewEndpoint`. */\n buildPreviewUrl?: (request: {\n markdown: string;\n format: MarkdownEditorPreviewFormat;\n }) => string | undefined;\n /**\n * Custom loader for host-specific markdown conversion. Return `undefined` for\n * a format to leave it on the local preview — Clicky's `format=` contract has\n * no `react`, so hosts commonly convert every other format remotely.\n */\n loadPreview?: (\n request: MarkdownEditorPreviewRequest,\n ) =>\n | Promise<MarkdownEditorPreviewResult | undefined>\n | MarkdownEditorPreviewResult\n | undefined;\n /** Local Clicky document for the React preview, or a mapper from markdown. */\n clickyData?: ClickyProps[\"data\"] | ((markdown: string) => ClickyProps[\"data\"] | undefined);\n /** Debounce interval for remote preview requests. */\n previewDebounceMs?: number;\n /** Minimum height for both editor and preview panes. */\n minHeight?: number | string;\n /** Disable editing and preview refresh. */\n disabled?: boolean;\n /** Render the source as read-only. */\n readOnly?: boolean;\n /** Classes applied to the component root. */\n className?: string;\n /** Classes applied to the textarea. */\n editorClassName?: string;\n /** Classes applied to the preview body. */\n previewClassName?: string;\n /** Extra toolbar content rendered after the built-in actions. */\n toolbar?: ReactNode;\n};\n\ntype PreviewState =\n | { status: \"idle\" }\n | { status: \"loading\"; result?: MarkdownEditorPreviewResult }\n | { status: \"success\"; result: MarkdownEditorPreviewResult }\n | { status: \"error\"; error: string; result?: MarkdownEditorPreviewResult };\n\ntype FormatMeta = {\n label: string;\n icon: StaticIconComponent;\n iconClassName?: string;\n};\n\nconst FORMAT_META: Record<MarkdownEditorPreviewFormat, FormatMeta> = {\n react: {\n label: \"React\",\n icon: UiEye,\n },\n html: {\n label: \"HTML\",\n icon: UiFileCode,\n },\n markdown: {\n label: \"Markdown\",\n icon: UiMarkdown,\n },\n pdf: {\n label: \"PDF\",\n icon: UiFileText,\n iconClassName: \"text-rose-600 dark:text-rose-400\",\n },\n json: {\n label: \"JSON\",\n icon: UiJson,\n },\n csv: {\n label: \"CSV\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-600 dark:text-emerald-400\",\n },\n excel: {\n label: \"Excel\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-700 dark:text-emerald-300\",\n },\n};\n\n/**\n * Split-pane markdown editor with local Markdown/React preview and optional\n * Clicky-backed format previews. Hosts can pass `previewEndpoint` for the\n * standard Clicky `format=` contract or `loadPreview` for custom conversion.\n */\nexport function MarkdownEditor({\n value,\n defaultValue = \"\",\n onChange,\n label = \"Markdown\",\n placeholder = \"Write markdown...\",\n previewFormats,\n previewFormat,\n defaultPreviewFormat,\n onPreviewFormatChange,\n previewEndpoint,\n previewMethod = \"POST\",\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n clickyData,\n previewDebounceMs = 350,\n minHeight = 420,\n disabled = false,\n readOnly = false,\n className,\n editorClassName,\n previewClassName,\n toolbar,\n}: MarkdownEditorProps) {\n const editorId = useId();\n const formats = useMemo(\n () => normalizePreviewFormats(previewFormats),\n [previewFormats],\n );\n const firstFormat = formats[0] ?? \"react\";\n const [draft, setDraft] = useState(defaultValue);\n const markdown = value ?? draft;\n const [internalFormat, setInternalFormat] = useState<MarkdownEditorPreviewFormat>(\n () =>\n normalizeInitialFormat(defaultPreviewFormat, formats) ??\n firstFormat,\n );\n const activeFormat = formats.includes(previewFormat ?? internalFormat)\n ? previewFormat ?? internalFormat\n : firstFormat;\n const [refreshKey, setRefreshKey] = useState(0);\n const [previewState, setPreviewState] = useState<PreviewState>({\n status: \"idle\",\n });\n const contentStyle = useMemo<CSSProperties>(\n () => ({ minHeight: cssSize(minHeight) }),\n [minHeight],\n );\n const remoteEnabled = Boolean(loadPreview || previewEndpoint || buildPreviewUrl);\n const currentMeta = FORMAT_META[activeFormat];\n const segmentOptions = useMemo<SegmentedOption<MarkdownEditorPreviewFormat>[]>(\n () =>\n formats.map((format) => {\n const meta = FORMAT_META[format];\n return {\n id: format,\n label: meta.label,\n icon: meta.icon,\n title: `${meta.label} preview`,\n };\n }),\n [formats],\n );\n\n useEffect(() => {\n if (formats.includes(activeFormat)) return;\n setInternalFormat(firstFormat);\n }, [activeFormat, firstFormat, formats]);\n\n useEffect(() => {\n if (!remoteEnabled) {\n setPreviewState({ status: \"idle\" });\n return;\n }\n\n const controller = new AbortController();\n const timeout = window.setTimeout(() => {\n setPreviewState((current) =>\n current.status === \"success\"\n ? { status: \"loading\", result: current.result }\n : { status: \"loading\" },\n );\n\n resolvePreview({\n markdown,\n format: activeFormat,\n signal: controller.signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n })\n .then((result) => {\n if (controller.signal.aborted) return;\n setPreviewState(\n result ? { status: \"success\", result } : { status: \"idle\" },\n );\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) return;\n setPreviewState((current) => ({\n status: \"error\",\n error: error instanceof Error ? error.message : \"Preview failed\",\n ...(current.status === \"loading\" && current.result\n ? { result: current.result }\n : {}),\n }));\n });\n }, Math.max(0, previewDebounceMs));\n\n return () => {\n window.clearTimeout(timeout);\n controller.abort();\n };\n }, [\n activeFormat,\n buildPreviewUrl,\n loadPreview,\n markdown,\n previewDebounceMs,\n previewEndpoint,\n previewHeaders,\n previewMethod,\n refreshKey,\n remoteEnabled,\n ]);\n\n const updateMarkdown = (next: string) => {\n if (value === undefined) setDraft(next);\n onChange?.(next);\n };\n\n const updateFormat = (next: MarkdownEditorPreviewFormat) => {\n if (previewFormat === undefined) setInternalFormat(next);\n onPreviewFormatChange?.(next);\n };\n\n const copySource = () => {\n const clipboard = globalThis.navigator?.clipboard;\n if (clipboard?.writeText) {\n void clipboard.writeText(markdown).catch(() => undefined);\n }\n };\n\n return (\n <div className={cn(\"rounded-md border border-border bg-card\", className)}>\n <div className=\"flex flex-wrap items-center gap-density-2 border-b border-border px-density-3 py-density-2\">\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Icon icon={UiEdit} className=\"text-base text-muted-foreground\" />\n <label\n htmlFor={editorId}\n className=\"truncate text-sm font-medium text-card-foreground\"\n >\n {label}\n </label>\n {previewState.status === \"loading\" && (\n <span className=\"text-xs text-muted-foreground\">Refreshing...</span>\n )}\n </div>\n <div className=\"flex min-w-0 flex-wrap items-center justify-end gap-2\">\n <SegmentedControl\n value={activeFormat}\n options={segmentOptions}\n onChange={updateFormat}\n size=\"sm\"\n aria-label=\"Markdown preview format\"\n className=\"max-w-full flex-wrap\"\n />\n {remoteEnabled && (\n <IconButton\n icon={UiRefresh}\n label=\"Refresh preview\"\n disabled={disabled}\n onClick={() => setRefreshKey((current) => current + 1)}\n />\n )}\n <IconButton icon={UiCopy} label=\"Copy markdown\" onClick={copySource} />\n {toolbar}\n </div>\n </div>\n\n <div className=\"grid gap-density-3 p-density-3 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]\">\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n Source\n </div>\n <textarea\n id={editorId}\n value={markdown}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n spellCheck\n onChange={(event) => updateMarkdown(event.currentTarget.value)}\n className={cn(\n \"block w-full resize-y border-0 bg-transparent px-density-3 py-density-3 font-mono text-sm leading-6 text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:opacity-60\",\n editorClassName,\n )}\n style={contentStyle}\n />\n </div>\n\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n <Icon\n icon={currentMeta.icon}\n className={cn(\"text-sm\", currentMeta.iconClassName)}\n />\n <span>{currentMeta.label}</span>\n </div>\n <div\n className={cn(\n \"overflow-auto px-density-3 py-density-3\",\n previewClassName,\n )}\n style={contentStyle}\n >\n <MarkdownEditorPreview\n format={activeFormat}\n markdown={markdown}\n state={previewState}\n clickyData={clickyData}\n />\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction MarkdownEditorPreview({\n format,\n markdown,\n state,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n state: PreviewState;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n const result =\n state.status === \"success\" || state.status === \"loading\" || state.status === \"error\"\n ? state.result\n : undefined;\n\n return (\n <div className=\"space-y-density-3\">\n {state.status === \"error\" && (\n <PreviewNotice title=\"Preview failed\" message={state.error} tone=\"danger\" />\n )}\n {result ? (\n <PreviewResult format={format} result={result} />\n ) : (\n <LocalPreview\n format={format}\n markdown={markdown}\n clickyData={clickyData}\n />\n )}\n </div>\n );\n}\n\nfunction LocalPreview({\n format,\n markdown,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n if (format === \"react\") {\n const data =\n typeof clickyData === \"function\" ? clickyData(markdown) : clickyData;\n return data === undefined ? <Markdown text={markdown} /> : <Clicky data={data} />;\n }\n\n if (format === \"markdown\") {\n return <TextPreview label=\"Markdown source\" text={markdown} />;\n }\n\n return (\n <PreviewNotice\n title={`${FORMAT_META[format].label} preview not configured`}\n message=\"Pass previewEndpoint or loadPreview to render this format from Clicky.\"\n />\n );\n}\n\nfunction PreviewResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: MarkdownEditorPreviewResult;\n}) {\n switch (result.kind) {\n case \"clicky\":\n return <Clicky data={result.data} />;\n case \"html\":\n return <HtmlPreview html={result.html} />;\n case \"json\":\n return <JsonView data={result.data} format=\"json\" />;\n case \"url\":\n return <UrlPreview format={format} url={result.url} />;\n case \"blob\":\n return <BlobPreview format={format} result={result} />;\n case \"text\":\n return <TextResult format={format} result={result} />;\n }\n}\n\nfunction TextResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"text\" }>;\n}) {\n if (format === \"react\") {\n return <Clicky data={result.text} />;\n }\n\n if (format === \"html\" || isHtmlContent(result.contentType)) {\n return <HtmlPreview html={result.text} />;\n }\n\n if (format === \"json\" || isJsonContent(result.contentType)) {\n const parsed = parseJson(result.text);\n return parsed.ok ? (\n <JsonView data={parsed.value} format=\"json\" />\n ) : (\n <TextPreview label=\"JSON output\" text={result.text} />\n );\n }\n\n return (\n <TextPreview\n label={`${FORMAT_META[format].label} output`}\n text={result.text}\n />\n );\n}\n\nfunction UrlPreview({\n format,\n url,\n}: {\n format: MarkdownEditorPreviewFormat;\n url: string;\n}) {\n if (format === \"react\") {\n return <Clicky url={url} view={[\"clicky\"]} download={{ all: false }} />;\n }\n\n if (format === \"html\") {\n return <HtmlPreview src={url} />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n if (format === \"excel\") {\n return <DownloadPreview label=\"Open Excel workbook\" href={url} />;\n }\n\n return <TextPreview label={`${FORMAT_META[format].label} URL`} text={url} />;\n}\n\nfunction BlobPreview({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"blob\" }>;\n}) {\n const [url, setUrl] = useState<string>();\n\n useEffect(() => {\n const next = URL.createObjectURL(result.blob);\n setUrl(next);\n return () => URL.revokeObjectURL(next);\n }, [result.blob]);\n\n if (!url) {\n return <PreviewNotice title=\"Preparing preview\" message=\"Creating object URL.\" />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n return (\n <DownloadPreview\n label={`Open ${FORMAT_META[format].label}`}\n href={url}\n {...(result.filename ? { download: result.filename } : {})}\n />\n );\n}\n\nfunction HtmlPreview({\n html,\n src,\n}: {\n html?: string;\n src?: string;\n}) {\n return (\n <FramePreview\n title=\"HTML preview\"\n {...(src ? { src } : {})}\n {...(html ? { srcDoc: html } : {})}\n sandbox=\"allow-same-origin\"\n />\n );\n}\n\nfunction FramePreview({\n title,\n src,\n srcDoc,\n sandbox,\n}: {\n title: string;\n src?: string;\n srcDoc?: string;\n sandbox?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-md border border-border bg-background\">\n <iframe\n title={title}\n {...(src ? { src } : {})}\n {...(srcDoc ? { srcDoc } : {})}\n {...(sandbox ? { sandbox } : {})}\n className=\"h-[720px] w-full bg-background\"\n />\n </div>\n );\n}\n\nfunction DownloadPreview({\n label,\n href,\n download,\n}: {\n label: string;\n href: string;\n download?: string;\n}) {\n return (\n <PreviewNotice\n title=\"Inline preview unavailable\"\n message={\n <Button asChild variant=\"outline\" size=\"sm\">\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n {...(download ? { download } : {})}\n >\n {label}\n </a>\n </Button>\n }\n />\n );\n}\n\nfunction TextPreview({ label, text }: { label: string; text: string }) {\n return (\n <pre\n aria-label={label}\n className=\"overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-muted/30 px-density-3 py-density-3 font-mono text-xs text-foreground\"\n >\n {text || \"No content\"}\n </pre>\n );\n}\n\nfunction PreviewNotice({\n title,\n message,\n tone = \"default\",\n}: {\n title: string;\n message: ReactNode;\n tone?: \"default\" | \"danger\";\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border p-density-3\",\n tone === \"danger\"\n ? \"border-destructive/30 bg-destructive/5\"\n : \"border-border bg-muted/30\",\n )}\n >\n <div\n className={cn(\n \"text-sm font-medium\",\n tone === \"danger\" && \"text-destructive\",\n )}\n >\n {title}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">{message}</div>\n </div>\n );\n}\n\nfunction normalizePreviewFormats(\n formats: readonly MarkdownEditorPreviewFormat[] | undefined,\n): MarkdownEditorPreviewFormat[] {\n const seen = new Set<MarkdownEditorPreviewFormat>();\n const source = formats && formats.length > 0 ? formats : MARKDOWN_EDITOR_PREVIEW_FORMATS;\n for (const format of source) {\n seen.add(format);\n }\n return [...seen];\n}\n\nfunction normalizeInitialFormat(\n format: MarkdownEditorPreviewFormat | undefined,\n formats: readonly MarkdownEditorPreviewFormat[],\n) {\n return format && formats.includes(format) ? format : undefined;\n}\n\nfunction cssSize(size: number | string) {\n return typeof size === \"number\" ? `${size}px` : size;\n}\n\nasync function resolvePreview({\n markdown,\n format,\n signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n}: MarkdownEditorPreviewRequest & {\n previewEndpoint: string | undefined;\n previewMethod: \"GET\" | \"POST\" | \"PUT\";\n previewHeaders: MarkdownEditorPreviewHeaders | undefined;\n buildPreviewUrl: MarkdownEditorProps[\"buildPreviewUrl\"] | undefined;\n loadPreview: MarkdownEditorProps[\"loadPreview\"] | undefined;\n}): Promise<MarkdownEditorPreviewResult | undefined> {\n if (loadPreview) {\n return loadPreview({ markdown, format, signal });\n }\n\n const url =\n buildPreviewUrl?.({ markdown, format }) ??\n (previewEndpoint\n ? buildMarkdownPreviewUrl(previewEndpoint, format)\n : undefined);\n\n if (!url) {\n throw new Error(\"No preview endpoint configured\");\n }\n\n const headers = new Headers(\n typeof previewHeaders === \"function\"\n ? previewHeaders({ markdown, format })\n : previewHeaders,\n );\n headers.set(\"Accept\", previewAccept(format));\n\n const init: RequestInit = {\n method: previewMethod,\n headers,\n signal,\n };\n\n if (previewMethod !== \"GET\") {\n headers.set(\"Content-Type\", \"text/markdown; charset=utf-8\");\n init.body = markdown;\n }\n\n const response = await fetch(url, init);\n if (!response.ok) {\n throw new Error(\n `Preview failed with ${response.status} ${response.statusText}`.trim(),\n );\n }\n\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n if (format === \"pdf\" || format === \"excel\" || isBinaryContent(contentType)) {\n return {\n kind: \"blob\",\n blob: await response.blob(),\n contentType,\n filename: previewFilename(format),\n };\n }\n\n const text = await response.text();\n if (format === \"react\") {\n return { kind: \"clicky\", data: text };\n }\n if (format === \"html\" || isHtmlContent(contentType)) {\n return { kind: \"html\", html: text };\n }\n if (format === \"json\" || isJsonContent(contentType)) {\n const parsed = parseJson(text);\n return parsed.ok\n ? { kind: \"json\", data: parsed.value }\n : { kind: \"text\", text, contentType };\n }\n return { kind: \"text\", text, contentType };\n}\n\nfunction previewAccept(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"application/json+clicky, application/clicky+json;q=0.9, application/json;q=0.8,*/*;q=0.7\";\n case \"html\":\n return \"text/html, */*;q=0.7\";\n case \"markdown\":\n return \"text/markdown, text/plain;q=0.8,*/*;q=0.7\";\n case \"pdf\":\n return \"application/pdf, */*;q=0.7\";\n case \"json\":\n return \"application/json, text/plain;q=0.8,*/*;q=0.7\";\n case \"csv\":\n return \"text/csv, text/plain;q=0.8,*/*;q=0.7\";\n case \"excel\":\n return \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, */*;q=0.7\";\n }\n}\n\nfunction previewFilename(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"preview.clicky.json\";\n case \"html\":\n return \"preview.html\";\n case \"markdown\":\n return \"preview.md\";\n case \"pdf\":\n return \"preview.pdf\";\n case \"json\":\n return \"preview.json\";\n case \"csv\":\n return \"preview.csv\";\n case \"excel\":\n return \"preview.xlsx\";\n }\n}\n\nfunction parseJson(text: string): { ok: true; value: unknown } | { ok: false } {\n try {\n return { ok: true, value: JSON.parse(text) as unknown };\n } catch {\n return { ok: false };\n }\n}\n\nfunction isJsonContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"json\") ?? false;\n}\n\nfunction isHtmlContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"html\") ?? false;\n}\n\nfunction isBinaryContent(contentType: string | undefined) {\n const normalized = contentType?.toLowerCase() ?? \"\";\n return (\n normalized.includes(\"application/pdf\") ||\n normalized.includes(\"spreadsheetml\") ||\n normalized.includes(\"application/vnd.ms-excel\")\n );\n}\n"],"names":["UiEye","UiFileCode","UiMarkdown","UiFileText","UiJson","UiFileSpreadsheet","useId","useMemo","useState","useEffect","cn","jsxs","jsx","Icon","UiEdit","SegmentedControl","IconButton","UiRefresh","UiCopy","Markdown","Clicky","JsonView","Button","MARKDOWN_EDITOR_PREVIEW_FORMATS","buildMarkdownPreviewUrl"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgHA,MAAM,cAA+D;AAAA,EACnE,OAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAMA,MAAAA;AAAAA,EAAA;AAAA,EAER,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,MAAMC,WAAAA;AAAAA,EAAA;AAAA,EAER,UAAU;AAAA,IACR,OAAO;AAAA,IACP,MAAMC,WAAAA;AAAAA,EAAA;AAAA,EAER,KAAK;AAAA,IACH,OAAO;AAAA,IACP,MAAMC,WAAAA;AAAAA,IACN,eAAe;AAAA,EAAA;AAAA,EAEjB,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,MAAMC,OAAAA;AAAAA,EAAA;AAAA,EAER,KAAK;AAAA,IACH,OAAO;AAAA,IACP,MAAMC,kBAAAA;AAAAA,IACN,eAAe;AAAA,EAAA;AAAA,EAEjB,OAAO;AAAA,IACL,OAAO;AAAA,IACP,MAAMA,kBAAAA;AAAAA,IACN,eAAe;AAAA,EAAA;AAEnB;AAOO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,eAAe;AAAA,EACf;AAAA,EACA,QAAQ;AAAA,EACR,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,WAAWC,MAAAA,MAAA;AACjB,QAAM,UAAUC,MAAAA;AAAAA,IACd,MAAM,wBAAwB,cAAc;AAAA,IAC5C,CAAC,cAAc;AAAA,EAAA;AAEjB,QAAM,cAAc,QAAQ,CAAC,KAAK;AAClC,QAAM,CAAC,OAAO,QAAQ,IAAIC,MAAAA,SAAS,YAAY;AAC/C,QAAM,WAAW,SAAS;AAC1B,QAAM,CAAC,gBAAgB,iBAAiB,IAAIA,MAAAA;AAAAA,IAC1C,MACE,uBAAuB,sBAAsB,OAAO,KACpD;AAAA,EAAA;AAEJ,QAAM,eAAe,QAAQ,SAAS,iBAAiB,cAAc,IACjE,iBAAiB,iBACjB;AACJ,QAAM,CAAC,YAAY,aAAa,IAAIA,MAAAA,SAAS,CAAC;AAC9C,QAAM,CAAC,cAAc,eAAe,IAAIA,eAAuB;AAAA,IAC7D,QAAQ;AAAA,EAAA,CACT;AACD,QAAM,eAAeD,MAAAA;AAAAA,IACnB,OAAO,EAAE,WAAW,QAAQ,SAAS,EAAA;AAAA,IACrC,CAAC,SAAS;AAAA,EAAA;AAEZ,QAAM,gBAAgB,QAAQ,eAAe,mBAAmB,eAAe;AAC/E,QAAM,cAAc,YAAY,YAAY;AAC5C,QAAM,iBAAiBA,MAAAA;AAAAA,IACrB,MACE,QAAQ,IAAI,CAAC,WAAW;AACtB,YAAM,OAAO,YAAY,MAAM;AAC/B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,OAAO,GAAG,KAAK,KAAK;AAAA,MAAA;AAAA,IAExB,CAAC;AAAA,IACH,CAAC,OAAO;AAAA,EAAA;AAGVE,QAAAA,UAAU,MAAM;AACd,QAAI,QAAQ,SAAS,YAAY,EAAG;AACpC,sBAAkB,WAAW;AAAA,EAC/B,GAAG,CAAC,cAAc,aAAa,OAAO,CAAC;AAEvCA,QAAAA,UAAU,MAAM;AACd,QAAI,CAAC,eAAe;AAClB,sBAAgB,EAAE,QAAQ,QAAQ;AAClC;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,gBAAA;AACvB,UAAM,UAAU,OAAO,WAAW,MAAM;AACtC;AAAA,QAAgB,CAAC,YACf,QAAQ,WAAW,YACf,EAAE,QAAQ,WAAW,QAAQ,QAAQ,WACrC,EAAE,QAAQ,UAAA;AAAA,MAAU;AAG1B,qBAAe;AAAA,QACb;AAAA,QACA,QAAQ;AAAA,QACR,QAAQ,WAAW;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA,CACD,EACE,KAAK,CAAC,WAAW;AAChB,YAAI,WAAW,OAAO,QAAS;AAC/B;AAAA,UACE,SAAS,EAAE,QAAQ,WAAW,WAAW,EAAE,QAAQ,OAAA;AAAA,QAAO;AAAA,MAE9D,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,YAAI,WAAW,OAAO,QAAS;AAC/B,wBAAgB,CAAC,aAAa;AAAA,UAC5B,QAAQ;AAAA,UACR,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,UAChD,GAAI,QAAQ,WAAW,aAAa,QAAQ,SACxC,EAAE,QAAQ,QAAQ,WAClB,CAAA;AAAA,QAAC,EACL;AAAA,MACJ,CAAC;AAAA,IACL,GAAG,KAAK,IAAI,GAAG,iBAAiB,CAAC;AAEjC,WAAO,MAAM;AACX,aAAO,aAAa,OAAO;AAC3B,iBAAW,MAAA;AAAA,IACb;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAED,QAAM,iBAAiB,CAAC,SAAiB;AACvC,QAAI,UAAU,OAAW,UAAS,IAAI;AACtC,yCAAW;AAAA,EACb;AAEA,QAAM,eAAe,CAAC,SAAsC;AAC1D,QAAI,kBAAkB,OAAW,mBAAkB,IAAI;AACvD,mEAAwB;AAAA,EAC1B;AAEA,QAAM,aAAa,MAAM;;AACvB,UAAM,aAAY,gBAAW,cAAX,mBAAsB;AACxC,QAAI,uCAAW,WAAW;AACxB,WAAK,UAAU,UAAU,QAAQ,EAAE,MAAM,MAAM,MAAS;AAAA,IAC1D;AAAA,EACF;AAEA,yCACG,OAAA,EAAI,WAAWC,MAAAA,GAAG,2CAA2C,SAAS,GACrE,UAAA;AAAA,IAAAC,2BAAAA,KAAC,OAAA,EAAI,WAAU,8FACb,UAAA;AAAA,MAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,0CACb,UAAA;AAAA,QAAAC,2BAAAA,IAACC,KAAAA,MAAA,EAAK,MAAMC,OAAAA,QAAQ,WAAU,mCAAkC;AAAA,QAChEF,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAU;AAAA,YAET,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEF,aAAa,WAAW,4CACtB,QAAA,EAAK,WAAU,iCAAgC,UAAA,gBAAA,CAAa;AAAA,MAAA,GAEjE;AAAA,MACAD,2BAAAA,KAAC,OAAA,EAAI,WAAU,yDACb,UAAA;AAAA,QAAAC,2BAAAA;AAAAA,UAACG,iBAAAA;AAAAA,UAAA;AAAA,YACC,OAAO;AAAA,YACP,SAAS;AAAA,YACT,UAAU;AAAA,YACV,MAAK;AAAA,YACL,cAAW;AAAA,YACX,WAAU;AAAA,UAAA;AAAA,QAAA;AAAA,QAEX,iBACCH,2BAAAA;AAAAA,UAACI,WAAAA;AAAAA,UAAA;AAAA,YACC,MAAMC,UAAAA;AAAAA,YACN,OAAM;AAAA,YACN;AAAA,YACA,SAAS,MAAM,cAAc,CAAC,YAAY,UAAU,CAAC;AAAA,UAAA;AAAA,QAAA;AAAA,uCAGxDD,WAAAA,YAAA,EAAW,MAAME,OAAAA,QAAQ,OAAM,iBAAgB,SAAS,YAAY;AAAA,QACpE;AAAA,MAAA,EAAA,CACH;AAAA,IAAA,GACF;AAAA,IAEAP,2BAAAA,KAAC,OAAA,EAAI,WAAU,6EACb,UAAA;AAAA,MAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,yEACb,UAAA;AAAA,QAAAC,2BAAAA,IAAC,OAAA,EAAI,WAAU,8FAA6F,UAAA,UAE5G;AAAA,QACAA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,YACJ,OAAO;AAAA,YACP;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAU;AAAA,YACV,UAAU,CAAC,UAAU,eAAe,MAAM,cAAc,KAAK;AAAA,YAC7D,WAAWF,MAAAA;AAAAA,cACT;AAAA,cACA;AAAA,YAAA;AAAA,YAEF,OAAO;AAAA,UAAA;AAAA,QAAA;AAAA,MACT,GACF;AAAA,MAEAC,2BAAAA,KAAC,OAAA,EAAI,WAAU,yEACb,UAAA;AAAA,QAAAA,2BAAAA,KAAC,OAAA,EAAI,WAAU,sHACb,UAAA;AAAA,UAAAC,2BAAAA;AAAAA,YAACC,KAAAA;AAAAA,YAAA;AAAA,cACC,MAAM,YAAY;AAAA,cAClB,WAAWH,MAAAA,GAAG,WAAW,YAAY,aAAa;AAAA,YAAA;AAAA,UAAA;AAAA,UAEpDE,2BAAAA,IAAC,QAAA,EAAM,UAAA,YAAY,MAAA,CAAM;AAAA,QAAA,GAC3B;AAAA,QACAA,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWF,MAAAA;AAAAA,cACT;AAAA,cACA;AAAA,YAAA;AAAA,YAEF,OAAO;AAAA,YAEP,UAAAE,2BAAAA;AAAAA,cAAC;AAAA,cAAA;AAAA,gBACC,QAAQ;AAAA,gBACR;AAAA,gBACA,OAAO;AAAA,gBACP;AAAA,cAAA;AAAA,YAAA;AAAA,UACF;AAAA,QAAA;AAAA,MACF,EAAA,CACF;AAAA,IAAA,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,SAAS,sBAAsB;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,SACJ,MAAM,WAAW,aAAa,MAAM,WAAW,aAAa,MAAM,WAAW,UACzE,MAAM,SACN;AAEN,SACED,2BAAAA,KAAC,OAAA,EAAI,WAAU,qBACZ,UAAA;AAAA,IAAA,MAAM,WAAW,WAChBC,2BAAAA,IAAC,eAAA,EAAc,OAAM,kBAAiB,SAAS,MAAM,OAAO,MAAK,SAAA,CAAS;AAAA,IAE3E,SACCA,2BAAAA,IAAC,eAAA,EAAc,QAAgB,QAAgB,IAE/CA,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAAA,IAAA;AAAA,EACF,GAEJ;AAEJ;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,WAAW,SAAS;AACtB,UAAM,OACJ,OAAO,eAAe,aAAa,WAAW,QAAQ,IAAI;AAC5D,WAAO,SAAS,SAAYA,2BAAAA,IAACO,SAAAA,UAAA,EAAS,MAAM,SAAA,CAAU,IAAKP,2BAAAA,IAACQ,eAAA,EAAO,KAAA,CAAY;AAAA,EACjF;AAEA,MAAI,WAAW,YAAY;AACzB,WAAOR,2BAAAA,IAAC,aAAA,EAAY,OAAM,mBAAkB,MAAM,UAAU;AAAA,EAC9D;AAEA,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,GAAG,YAAY,MAAM,EAAE,KAAK;AAAA,MACnC,SAAQ;AAAA,IAAA;AAAA,EAAA;AAGd;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AACF,GAGG;AACD,UAAQ,OAAO,MAAA;AAAA,IACb,KAAK;AACH,aAAOA,2BAAAA,IAACQ,OAAAA,QAAA,EAAO,MAAM,OAAO,KAAA,CAAM;AAAA,IACpC,KAAK;AACH,aAAOR,2BAAAA,IAAC,aAAA,EAAY,MAAM,OAAO,KAAA,CAAM;AAAA,IACzC,KAAK;AACH,4CAAQS,SAAAA,UAAA,EAAS,MAAM,OAAO,MAAM,QAAO,QAAO;AAAA,IACpD,KAAK;AACH,aAAOT,2BAAAA,IAAC,YAAA,EAAW,QAAgB,KAAK,OAAO,KAAK;AAAA,IACtD,KAAK;AACH,aAAOA,2BAAAA,IAAC,aAAA,EAAY,QAAgB,OAAA,CAAgB;AAAA,IACtD,KAAK;AACH,aAAOA,2BAAAA,IAAC,YAAA,EAAW,QAAgB,OAAA,CAAgB;AAAA,EAAA;AAEzD;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AACF,GAGG;AACD,MAAI,WAAW,SAAS;AACtB,WAAOA,2BAAAA,IAACQ,OAAAA,QAAA,EAAO,MAAM,OAAO,KAAA,CAAM;AAAA,EACpC;AAEA,MAAI,WAAW,UAAU,cAAc,OAAO,WAAW,GAAG;AAC1D,WAAOR,2BAAAA,IAAC,aAAA,EAAY,MAAM,OAAO,KAAA,CAAM;AAAA,EACzC;AAEA,MAAI,WAAW,UAAU,cAAc,OAAO,WAAW,GAAG;AAC1D,UAAM,SAAS,UAAU,OAAO,IAAI;AACpC,WAAO,OAAO,KACZA,+BAACS,SAAAA,UAAA,EAAS,MAAM,OAAO,OAAO,QAAO,OAAA,CAAO,mCAE3C,aAAA,EAAY,OAAM,eAAc,MAAM,OAAO,MAAM;AAAA,EAExD;AAEA,SACET,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,GAAG,YAAY,MAAM,EAAE,KAAK;AAAA,MACnC,MAAM,OAAO;AAAA,IAAA;AAAA,EAAA;AAGnB;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AACF,GAGG;AACD,MAAI,WAAW,SAAS;AACtB,WAAOA,+BAACQ,OAAAA,QAAA,EAAO,KAAU,MAAM,CAAC,QAAQ,GAAG,UAAU,EAAE,KAAK,MAAA,EAAM,CAAG;AAAA,EACvE;AAEA,MAAI,WAAW,QAAQ;AACrB,WAAOR,2BAAAA,IAAC,aAAA,EAAY,KAAK,IAAA,CAAK;AAAA,EAChC;AAEA,MAAI,WAAW,OAAO;AACpB,WAAOA,2BAAAA,IAAC,cAAA,EAAa,OAAM,eAAc,KAAK,KAAK;AAAA,EACrD;AAEA,MAAI,WAAW,SAAS;AACtB,WAAOA,2BAAAA,IAAC,iBAAA,EAAgB,OAAM,uBAAsB,MAAM,KAAK;AAAA,EACjE;AAEA,SAAOA,2BAAAA,IAAC,aAAA,EAAY,OAAO,GAAG,YAAY,MAAM,EAAE,KAAK,QAAQ,MAAM,IAAA,CAAK;AAC5E;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,KAAK,MAAM,IAAIJ,eAAA;AAEtBC,QAAAA,UAAU,MAAM;AACd,UAAM,OAAO,IAAI,gBAAgB,OAAO,IAAI;AAC5C,WAAO,IAAI;AACX,WAAO,MAAM,IAAI,gBAAgB,IAAI;AAAA,EACvC,GAAG,CAAC,OAAO,IAAI,CAAC;AAEhB,MAAI,CAAC,KAAK;AACR,WAAOG,2BAAAA,IAAC,eAAA,EAAc,OAAM,qBAAoB,SAAQ,wBAAuB;AAAA,EACjF;AAEA,MAAI,WAAW,OAAO;AACpB,WAAOA,2BAAAA,IAAC,cAAA,EAAa,OAAM,eAAc,KAAK,KAAK;AAAA,EACrD;AAEA,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,QAAQ,YAAY,MAAM,EAAE,KAAK;AAAA,MACxC,MAAM;AAAA,MACL,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAA,IAAa,CAAA;AAAA,IAAC;AAAA,EAAA;AAG9D;AAEA,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACL,GAAI,MAAM,EAAE,IAAA,IAAQ,CAAA;AAAA,MACpB,GAAI,OAAO,EAAE,QAAQ,KAAA,IAAS,CAAA;AAAA,MAC/B,SAAQ;AAAA,IAAA;AAAA,EAAA;AAGd;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACEA,2BAAAA,IAAC,OAAA,EAAI,WAAU,iEACb,UAAAA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACC,GAAI,MAAM,EAAE,IAAA,IAAQ,CAAA;AAAA,MACpB,GAAI,SAAS,EAAE,OAAA,IAAW,CAAA;AAAA,MAC1B,GAAI,UAAU,EAAE,QAAA,IAAY,CAAA;AAAA,MAC7B,WAAU;AAAA,IAAA;AAAA,EAAA,GAEd;AAEJ;AAEA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN,wCACGU,eAAA,EAAO,SAAO,MAAC,SAAQ,WAAU,MAAK,MACrC,UAAAV,2BAAAA;AAAAA,QAAC;AAAA,QAAA;AAAA,UACC;AAAA,UACA,QAAO;AAAA,UACP,KAAI;AAAA,UACH,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,UAE9B,UAAA;AAAA,QAAA;AAAA,MAAA,EACH,CACF;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,YAAY,EAAE,OAAO,QAAyC;AACrE,SACEA,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,cAAY;AAAA,MACZ,WAAU;AAAA,MAET,UAAA,QAAQ;AAAA,IAAA;AAAA,EAAA;AAGf;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA,OAAO;AACT,GAIG;AACD,SACED,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWD,MAAAA;AAAAA,QACT;AAAA,QACA,SAAS,WACL,2CACA;AAAA,MAAA;AAAA,MAGN,UAAA;AAAA,QAAAE,2BAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWF,MAAAA;AAAAA,cACT;AAAA,cACA,SAAS,YAAY;AAAA,YAAA;AAAA,YAGtB,UAAA;AAAA,UAAA;AAAA,QAAA;AAAA,QAEHE,2BAAAA,IAAC,OAAA,EAAI,WAAU,sCAAsC,UAAA,QAAA,CAAQ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGnE;AAEA,SAAS,wBACP,SAC+B;AAC/B,QAAM,2BAAW,IAAA;AACjB,QAAM,SAAS,WAAW,QAAQ,SAAS,IAAI,UAAUW,qBAAAA;AACzD,aAAW,UAAU,QAAQ;AAC3B,SAAK,IAAI,MAAM;AAAA,EACjB;AACA,SAAO,CAAC,GAAG,IAAI;AACjB;AAEA,SAAS,uBACP,QACA,SACA;AACA,SAAO,UAAU,QAAQ,SAAS,MAAM,IAAI,SAAS;AACvD;AAEA,SAAS,QAAQ,MAAuB;AACtC,SAAO,OAAO,SAAS,WAAW,GAAG,IAAI,OAAO;AAClD;AAEA,eAAe,eAAe;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMqD;AACnD,MAAI,aAAa;AACf,WAAO,YAAY,EAAE,UAAU,QAAQ,QAAQ;AAAA,EACjD;AAEA,QAAM,OACJ,mDAAkB,EAAE,UAAU,OAAA,QAC7B,kBACGC,6CAAwB,iBAAiB,MAAM,IAC/C;AAEN,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,QAAM,UAAU,IAAI;AAAA,IAClB,OAAO,mBAAmB,aACtB,eAAe,EAAE,UAAU,OAAA,CAAQ,IACnC;AAAA,EAAA;AAEN,UAAQ,IAAI,UAAU,cAAc,MAAM,CAAC;AAE3C,QAAM,OAAoB;AAAA,IACxB,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EAAA;AAGF,MAAI,kBAAkB,OAAO;AAC3B,YAAQ,IAAI,gBAAgB,8BAA8B;AAC1D,SAAK,OAAO;AAAA,EACd;AAEA,QAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AACtC,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI;AAAA,MACR,uBAAuB,SAAS,MAAM,IAAI,SAAS,UAAU,GAAG,KAAA;AAAA,IAAK;AAAA,EAEzE;AAEA,QAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAC5D,MAAI,WAAW,SAAS,WAAW,WAAW,gBAAgB,WAAW,GAAG;AAC1E,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,MAAM,SAAS,KAAA;AAAA,MACrB;AAAA,MACA,UAAU,gBAAgB,MAAM;AAAA,IAAA;AAAA,EAEpC;AAEA,QAAM,OAAO,MAAM,SAAS,KAAA;AAC5B,MAAI,WAAW,SAAS;AACtB,WAAO,EAAE,MAAM,UAAU,MAAM,KAAA;AAAA,EACjC;AACA,MAAI,WAAW,UAAU,cAAc,WAAW,GAAG;AACnD,WAAO,EAAE,MAAM,QAAQ,MAAM,KAAA;AAAA,EAC/B;AACA,MAAI,WAAW,UAAU,cAAc,WAAW,GAAG;AACnD,UAAM,SAAS,UAAU,IAAI;AAC7B,WAAO,OAAO,KACV,EAAE,MAAM,QAAQ,MAAM,OAAO,MAAA,IAC7B,EAAE,MAAM,QAAQ,MAAM,YAAA;AAAA,EAC5B;AACA,SAAO,EAAE,MAAM,QAAQ,MAAM,YAAA;AAC/B;AAEA,SAAS,cAAc,QAAqC;AAC1D,UAAQ,QAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EAAA;AAEb;AAEA,SAAS,gBAAgB,QAAqC;AAC5D,UAAQ,QAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EAAA;AAEb;AAEA,SAAS,UAAU,MAA4D;AAC7E,MAAI;AACF,WAAO,EAAE,IAAI,MAAM,OAAO,KAAK,MAAM,IAAI,EAAA;AAAA,EAC3C,QAAQ;AACN,WAAO,EAAE,IAAI,MAAA;AAAA,EACf;AACF;AAEA,SAAS,cAAc,aAAiC;AACtD,UAAO,2CAAa,cAAc,SAAS,YAAW;AACxD;AAEA,SAAS,cAAc,aAAiC;AACtD,UAAO,2CAAa,cAAc,SAAS,YAAW;AACxD;AAEA,SAAS,gBAAgB,aAAiC;AACxD,QAAM,cAAa,2CAAa,kBAAiB;AACjD,SACE,WAAW,SAAS,iBAAiB,KACrC,WAAW,SAAS,eAAe,KACnC,WAAW,SAAS,0BAA0B;AAElD;;"}
|
|
@@ -321,7 +321,7 @@ function PreviewResult({
|
|
|
321
321
|
case "html":
|
|
322
322
|
return /* @__PURE__ */ jsx(HtmlPreview, { html: result.html });
|
|
323
323
|
case "json":
|
|
324
|
-
return /* @__PURE__ */ jsx(JsonView, { data: result.data });
|
|
324
|
+
return /* @__PURE__ */ jsx(JsonView, { data: result.data, format: "json" });
|
|
325
325
|
case "url":
|
|
326
326
|
return /* @__PURE__ */ jsx(UrlPreview, { format, url: result.url });
|
|
327
327
|
case "blob":
|
|
@@ -342,7 +342,7 @@ function TextResult({
|
|
|
342
342
|
}
|
|
343
343
|
if (format === "json" || isJsonContent(result.contentType)) {
|
|
344
344
|
const parsed = parseJson(result.text);
|
|
345
|
-
return parsed.ok ? /* @__PURE__ */ jsx(JsonView, { data: parsed.value }) : /* @__PURE__ */ jsx(TextPreview, { label: "JSON output", text: result.text });
|
|
345
|
+
return parsed.ok ? /* @__PURE__ */ jsx(JsonView, { data: parsed.value, format: "json" }) : /* @__PURE__ */ jsx(TextPreview, { label: "JSON output", text: result.text });
|
|
346
346
|
}
|
|
347
347
|
return /* @__PURE__ */ jsx(
|
|
348
348
|
TextPreview,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkdownEditor.js","sources":["../../src/data/MarkdownEditor.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useMemo,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { Button } from \"../components/button\";\nimport { IconButton } from \"../components/IconButton\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../components/SegmentedControl\";\nimport { cn } from \"../lib/utils\";\nimport {\n UiCopy,\n UiEdit,\n UiEye,\n UiFileCode,\n UiFileSpreadsheet,\n UiFileText,\n UiJson,\n UiMarkdown,\n UiRefresh,\n} from \"../icons\";\nimport { Clicky, type ClickyProps } from \"./Clicky\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { JsonView } from \"./JsonView\";\nimport { Markdown } from \"./Markdown\";\nimport {\n buildMarkdownPreviewUrl,\n MARKDOWN_EDITOR_PREVIEW_FORMATS,\n type MarkdownEditorPreviewFormat,\n type MarkdownEditorPreviewHeaders,\n type MarkdownEditorPreviewRequest,\n type MarkdownEditorPreviewResult,\n} from \"./MarkdownEditor.model\";\n\nexport type MarkdownEditorProps = {\n /** Controlled markdown source. */\n value?: string;\n /** Initial markdown source for uncontrolled usage. */\n defaultValue?: string;\n /** Called whenever the editor source changes. */\n onChange?: (value: string) => void;\n /** Editor label. */\n label?: ReactNode;\n /** Textarea placeholder. */\n placeholder?: string;\n /** Preview formats to expose in the toolbar. */\n previewFormats?: readonly MarkdownEditorPreviewFormat[];\n /** Controlled active preview format. */\n previewFormat?: MarkdownEditorPreviewFormat;\n /** Initial active preview format for uncontrolled usage. */\n defaultPreviewFormat?: MarkdownEditorPreviewFormat;\n /** Called when the active preview format changes. */\n onPreviewFormatChange?: (format: MarkdownEditorPreviewFormat) => void;\n /** Clicky endpoint that accepts markdown and a `format=` query parameter. */\n previewEndpoint?: string;\n /** HTTP method for `previewEndpoint`; POST sends the markdown body. */\n previewMethod?: \"GET\" | \"POST\" | \"PUT\";\n /** Extra headers for remote previews. */\n previewHeaders?: MarkdownEditorPreviewHeaders;\n /** Build a URL for remote preview requests instead of `previewEndpoint`. */\n buildPreviewUrl?: (request: {\n markdown: string;\n format: MarkdownEditorPreviewFormat;\n }) => string | undefined;\n /**\n * Custom loader for host-specific markdown conversion. Return `undefined` for\n * a format to leave it on the local preview — Clicky's `format=` contract has\n * no `react`, so hosts commonly convert every other format remotely.\n */\n loadPreview?: (\n request: MarkdownEditorPreviewRequest,\n ) =>\n | Promise<MarkdownEditorPreviewResult | undefined>\n | MarkdownEditorPreviewResult\n | undefined;\n /** Local Clicky document for the React preview, or a mapper from markdown. */\n clickyData?: ClickyProps[\"data\"] | ((markdown: string) => ClickyProps[\"data\"] | undefined);\n /** Debounce interval for remote preview requests. */\n previewDebounceMs?: number;\n /** Minimum height for both editor and preview panes. */\n minHeight?: number | string;\n /** Disable editing and preview refresh. */\n disabled?: boolean;\n /** Render the source as read-only. */\n readOnly?: boolean;\n /** Classes applied to the component root. */\n className?: string;\n /** Classes applied to the textarea. */\n editorClassName?: string;\n /** Classes applied to the preview body. */\n previewClassName?: string;\n /** Extra toolbar content rendered after the built-in actions. */\n toolbar?: ReactNode;\n};\n\ntype PreviewState =\n | { status: \"idle\" }\n | { status: \"loading\"; result?: MarkdownEditorPreviewResult }\n | { status: \"success\"; result: MarkdownEditorPreviewResult }\n | { status: \"error\"; error: string; result?: MarkdownEditorPreviewResult };\n\ntype FormatMeta = {\n label: string;\n icon: StaticIconComponent;\n iconClassName?: string;\n};\n\nconst FORMAT_META: Record<MarkdownEditorPreviewFormat, FormatMeta> = {\n react: {\n label: \"React\",\n icon: UiEye,\n },\n html: {\n label: \"HTML\",\n icon: UiFileCode,\n },\n markdown: {\n label: \"Markdown\",\n icon: UiMarkdown,\n },\n pdf: {\n label: \"PDF\",\n icon: UiFileText,\n iconClassName: \"text-rose-600 dark:text-rose-400\",\n },\n json: {\n label: \"JSON\",\n icon: UiJson,\n },\n csv: {\n label: \"CSV\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-600 dark:text-emerald-400\",\n },\n excel: {\n label: \"Excel\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-700 dark:text-emerald-300\",\n },\n};\n\n/**\n * Split-pane markdown editor with local Markdown/React preview and optional\n * Clicky-backed format previews. Hosts can pass `previewEndpoint` for the\n * standard Clicky `format=` contract or `loadPreview` for custom conversion.\n */\nexport function MarkdownEditor({\n value,\n defaultValue = \"\",\n onChange,\n label = \"Markdown\",\n placeholder = \"Write markdown...\",\n previewFormats,\n previewFormat,\n defaultPreviewFormat,\n onPreviewFormatChange,\n previewEndpoint,\n previewMethod = \"POST\",\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n clickyData,\n previewDebounceMs = 350,\n minHeight = 420,\n disabled = false,\n readOnly = false,\n className,\n editorClassName,\n previewClassName,\n toolbar,\n}: MarkdownEditorProps) {\n const editorId = useId();\n const formats = useMemo(\n () => normalizePreviewFormats(previewFormats),\n [previewFormats],\n );\n const firstFormat = formats[0] ?? \"react\";\n const [draft, setDraft] = useState(defaultValue);\n const markdown = value ?? draft;\n const [internalFormat, setInternalFormat] = useState<MarkdownEditorPreviewFormat>(\n () =>\n normalizeInitialFormat(defaultPreviewFormat, formats) ??\n firstFormat,\n );\n const activeFormat = formats.includes(previewFormat ?? internalFormat)\n ? previewFormat ?? internalFormat\n : firstFormat;\n const [refreshKey, setRefreshKey] = useState(0);\n const [previewState, setPreviewState] = useState<PreviewState>({\n status: \"idle\",\n });\n const contentStyle = useMemo<CSSProperties>(\n () => ({ minHeight: cssSize(minHeight) }),\n [minHeight],\n );\n const remoteEnabled = Boolean(loadPreview || previewEndpoint || buildPreviewUrl);\n const currentMeta = FORMAT_META[activeFormat];\n const segmentOptions = useMemo<SegmentedOption<MarkdownEditorPreviewFormat>[]>(\n () =>\n formats.map((format) => {\n const meta = FORMAT_META[format];\n return {\n id: format,\n label: meta.label,\n icon: meta.icon,\n title: `${meta.label} preview`,\n };\n }),\n [formats],\n );\n\n useEffect(() => {\n if (formats.includes(activeFormat)) return;\n setInternalFormat(firstFormat);\n }, [activeFormat, firstFormat, formats]);\n\n useEffect(() => {\n if (!remoteEnabled) {\n setPreviewState({ status: \"idle\" });\n return;\n }\n\n const controller = new AbortController();\n const timeout = window.setTimeout(() => {\n setPreviewState((current) =>\n current.status === \"success\"\n ? { status: \"loading\", result: current.result }\n : { status: \"loading\" },\n );\n\n resolvePreview({\n markdown,\n format: activeFormat,\n signal: controller.signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n })\n .then((result) => {\n if (controller.signal.aborted) return;\n setPreviewState(\n result ? { status: \"success\", result } : { status: \"idle\" },\n );\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) return;\n setPreviewState((current) => ({\n status: \"error\",\n error: error instanceof Error ? error.message : \"Preview failed\",\n ...(current.status === \"loading\" && current.result\n ? { result: current.result }\n : {}),\n }));\n });\n }, Math.max(0, previewDebounceMs));\n\n return () => {\n window.clearTimeout(timeout);\n controller.abort();\n };\n }, [\n activeFormat,\n buildPreviewUrl,\n loadPreview,\n markdown,\n previewDebounceMs,\n previewEndpoint,\n previewHeaders,\n previewMethod,\n refreshKey,\n remoteEnabled,\n ]);\n\n const updateMarkdown = (next: string) => {\n if (value === undefined) setDraft(next);\n onChange?.(next);\n };\n\n const updateFormat = (next: MarkdownEditorPreviewFormat) => {\n if (previewFormat === undefined) setInternalFormat(next);\n onPreviewFormatChange?.(next);\n };\n\n const copySource = () => {\n const clipboard = globalThis.navigator?.clipboard;\n if (clipboard?.writeText) {\n void clipboard.writeText(markdown).catch(() => undefined);\n }\n };\n\n return (\n <div className={cn(\"rounded-md border border-border bg-card\", className)}>\n <div className=\"flex flex-wrap items-center gap-density-2 border-b border-border px-density-3 py-density-2\">\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Icon icon={UiEdit} className=\"text-base text-muted-foreground\" />\n <label\n htmlFor={editorId}\n className=\"truncate text-sm font-medium text-card-foreground\"\n >\n {label}\n </label>\n {previewState.status === \"loading\" && (\n <span className=\"text-xs text-muted-foreground\">Refreshing...</span>\n )}\n </div>\n <div className=\"flex min-w-0 flex-wrap items-center justify-end gap-2\">\n <SegmentedControl\n value={activeFormat}\n options={segmentOptions}\n onChange={updateFormat}\n size=\"sm\"\n aria-label=\"Markdown preview format\"\n className=\"max-w-full flex-wrap\"\n />\n {remoteEnabled && (\n <IconButton\n icon={UiRefresh}\n label=\"Refresh preview\"\n disabled={disabled}\n onClick={() => setRefreshKey((current) => current + 1)}\n />\n )}\n <IconButton icon={UiCopy} label=\"Copy markdown\" onClick={copySource} />\n {toolbar}\n </div>\n </div>\n\n <div className=\"grid gap-density-3 p-density-3 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]\">\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n Source\n </div>\n <textarea\n id={editorId}\n value={markdown}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n spellCheck\n onChange={(event) => updateMarkdown(event.currentTarget.value)}\n className={cn(\n \"block w-full resize-y border-0 bg-transparent px-density-3 py-density-3 font-mono text-sm leading-6 text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:opacity-60\",\n editorClassName,\n )}\n style={contentStyle}\n />\n </div>\n\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n <Icon\n icon={currentMeta.icon}\n className={cn(\"text-sm\", currentMeta.iconClassName)}\n />\n <span>{currentMeta.label}</span>\n </div>\n <div\n className={cn(\n \"overflow-auto px-density-3 py-density-3\",\n previewClassName,\n )}\n style={contentStyle}\n >\n <MarkdownEditorPreview\n format={activeFormat}\n markdown={markdown}\n state={previewState}\n clickyData={clickyData}\n />\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction MarkdownEditorPreview({\n format,\n markdown,\n state,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n state: PreviewState;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n const result =\n state.status === \"success\" || state.status === \"loading\" || state.status === \"error\"\n ? state.result\n : undefined;\n\n return (\n <div className=\"space-y-density-3\">\n {state.status === \"error\" && (\n <PreviewNotice title=\"Preview failed\" message={state.error} tone=\"danger\" />\n )}\n {result ? (\n <PreviewResult format={format} result={result} />\n ) : (\n <LocalPreview\n format={format}\n markdown={markdown}\n clickyData={clickyData}\n />\n )}\n </div>\n );\n}\n\nfunction LocalPreview({\n format,\n markdown,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n if (format === \"react\") {\n const data =\n typeof clickyData === \"function\" ? clickyData(markdown) : clickyData;\n return data === undefined ? <Markdown text={markdown} /> : <Clicky data={data} />;\n }\n\n if (format === \"markdown\") {\n return <TextPreview label=\"Markdown source\" text={markdown} />;\n }\n\n return (\n <PreviewNotice\n title={`${FORMAT_META[format].label} preview not configured`}\n message=\"Pass previewEndpoint or loadPreview to render this format from Clicky.\"\n />\n );\n}\n\nfunction PreviewResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: MarkdownEditorPreviewResult;\n}) {\n switch (result.kind) {\n case \"clicky\":\n return <Clicky data={result.data} />;\n case \"html\":\n return <HtmlPreview html={result.html} />;\n case \"json\":\n return <JsonView data={result.data} />;\n case \"url\":\n return <UrlPreview format={format} url={result.url} />;\n case \"blob\":\n return <BlobPreview format={format} result={result} />;\n case \"text\":\n return <TextResult format={format} result={result} />;\n }\n}\n\nfunction TextResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"text\" }>;\n}) {\n if (format === \"react\") {\n return <Clicky data={result.text} />;\n }\n\n if (format === \"html\" || isHtmlContent(result.contentType)) {\n return <HtmlPreview html={result.text} />;\n }\n\n if (format === \"json\" || isJsonContent(result.contentType)) {\n const parsed = parseJson(result.text);\n return parsed.ok ? (\n <JsonView data={parsed.value} />\n ) : (\n <TextPreview label=\"JSON output\" text={result.text} />\n );\n }\n\n return (\n <TextPreview\n label={`${FORMAT_META[format].label} output`}\n text={result.text}\n />\n );\n}\n\nfunction UrlPreview({\n format,\n url,\n}: {\n format: MarkdownEditorPreviewFormat;\n url: string;\n}) {\n if (format === \"react\") {\n return <Clicky url={url} view={[\"clicky\"]} download={{ all: false }} />;\n }\n\n if (format === \"html\") {\n return <HtmlPreview src={url} />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n if (format === \"excel\") {\n return <DownloadPreview label=\"Open Excel workbook\" href={url} />;\n }\n\n return <TextPreview label={`${FORMAT_META[format].label} URL`} text={url} />;\n}\n\nfunction BlobPreview({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"blob\" }>;\n}) {\n const [url, setUrl] = useState<string>();\n\n useEffect(() => {\n const next = URL.createObjectURL(result.blob);\n setUrl(next);\n return () => URL.revokeObjectURL(next);\n }, [result.blob]);\n\n if (!url) {\n return <PreviewNotice title=\"Preparing preview\" message=\"Creating object URL.\" />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n return (\n <DownloadPreview\n label={`Open ${FORMAT_META[format].label}`}\n href={url}\n {...(result.filename ? { download: result.filename } : {})}\n />\n );\n}\n\nfunction HtmlPreview({\n html,\n src,\n}: {\n html?: string;\n src?: string;\n}) {\n return (\n <FramePreview\n title=\"HTML preview\"\n {...(src ? { src } : {})}\n {...(html ? { srcDoc: html } : {})}\n sandbox=\"allow-same-origin\"\n />\n );\n}\n\nfunction FramePreview({\n title,\n src,\n srcDoc,\n sandbox,\n}: {\n title: string;\n src?: string;\n srcDoc?: string;\n sandbox?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-md border border-border bg-background\">\n <iframe\n title={title}\n {...(src ? { src } : {})}\n {...(srcDoc ? { srcDoc } : {})}\n {...(sandbox ? { sandbox } : {})}\n className=\"h-[720px] w-full bg-background\"\n />\n </div>\n );\n}\n\nfunction DownloadPreview({\n label,\n href,\n download,\n}: {\n label: string;\n href: string;\n download?: string;\n}) {\n return (\n <PreviewNotice\n title=\"Inline preview unavailable\"\n message={\n <Button asChild variant=\"outline\" size=\"sm\">\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n {...(download ? { download } : {})}\n >\n {label}\n </a>\n </Button>\n }\n />\n );\n}\n\nfunction TextPreview({ label, text }: { label: string; text: string }) {\n return (\n <pre\n aria-label={label}\n className=\"overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-muted/30 px-density-3 py-density-3 font-mono text-xs text-foreground\"\n >\n {text || \"No content\"}\n </pre>\n );\n}\n\nfunction PreviewNotice({\n title,\n message,\n tone = \"default\",\n}: {\n title: string;\n message: ReactNode;\n tone?: \"default\" | \"danger\";\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border p-density-3\",\n tone === \"danger\"\n ? \"border-destructive/30 bg-destructive/5\"\n : \"border-border bg-muted/30\",\n )}\n >\n <div\n className={cn(\n \"text-sm font-medium\",\n tone === \"danger\" && \"text-destructive\",\n )}\n >\n {title}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">{message}</div>\n </div>\n );\n}\n\nfunction normalizePreviewFormats(\n formats: readonly MarkdownEditorPreviewFormat[] | undefined,\n): MarkdownEditorPreviewFormat[] {\n const seen = new Set<MarkdownEditorPreviewFormat>();\n const source = formats && formats.length > 0 ? formats : MARKDOWN_EDITOR_PREVIEW_FORMATS;\n for (const format of source) {\n seen.add(format);\n }\n return [...seen];\n}\n\nfunction normalizeInitialFormat(\n format: MarkdownEditorPreviewFormat | undefined,\n formats: readonly MarkdownEditorPreviewFormat[],\n) {\n return format && formats.includes(format) ? format : undefined;\n}\n\nfunction cssSize(size: number | string) {\n return typeof size === \"number\" ? `${size}px` : size;\n}\n\nasync function resolvePreview({\n markdown,\n format,\n signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n}: MarkdownEditorPreviewRequest & {\n previewEndpoint: string | undefined;\n previewMethod: \"GET\" | \"POST\" | \"PUT\";\n previewHeaders: MarkdownEditorPreviewHeaders | undefined;\n buildPreviewUrl: MarkdownEditorProps[\"buildPreviewUrl\"] | undefined;\n loadPreview: MarkdownEditorProps[\"loadPreview\"] | undefined;\n}): Promise<MarkdownEditorPreviewResult | undefined> {\n if (loadPreview) {\n return loadPreview({ markdown, format, signal });\n }\n\n const url =\n buildPreviewUrl?.({ markdown, format }) ??\n (previewEndpoint\n ? buildMarkdownPreviewUrl(previewEndpoint, format)\n : undefined);\n\n if (!url) {\n throw new Error(\"No preview endpoint configured\");\n }\n\n const headers = new Headers(\n typeof previewHeaders === \"function\"\n ? previewHeaders({ markdown, format })\n : previewHeaders,\n );\n headers.set(\"Accept\", previewAccept(format));\n\n const init: RequestInit = {\n method: previewMethod,\n headers,\n signal,\n };\n\n if (previewMethod !== \"GET\") {\n headers.set(\"Content-Type\", \"text/markdown; charset=utf-8\");\n init.body = markdown;\n }\n\n const response = await fetch(url, init);\n if (!response.ok) {\n throw new Error(\n `Preview failed with ${response.status} ${response.statusText}`.trim(),\n );\n }\n\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n if (format === \"pdf\" || format === \"excel\" || isBinaryContent(contentType)) {\n return {\n kind: \"blob\",\n blob: await response.blob(),\n contentType,\n filename: previewFilename(format),\n };\n }\n\n const text = await response.text();\n if (format === \"react\") {\n return { kind: \"clicky\", data: text };\n }\n if (format === \"html\" || isHtmlContent(contentType)) {\n return { kind: \"html\", html: text };\n }\n if (format === \"json\" || isJsonContent(contentType)) {\n const parsed = parseJson(text);\n return parsed.ok\n ? { kind: \"json\", data: parsed.value }\n : { kind: \"text\", text, contentType };\n }\n return { kind: \"text\", text, contentType };\n}\n\nfunction previewAccept(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"application/json+clicky, application/clicky+json;q=0.9, application/json;q=0.8,*/*;q=0.7\";\n case \"html\":\n return \"text/html, */*;q=0.7\";\n case \"markdown\":\n return \"text/markdown, text/plain;q=0.8,*/*;q=0.7\";\n case \"pdf\":\n return \"application/pdf, */*;q=0.7\";\n case \"json\":\n return \"application/json, text/plain;q=0.8,*/*;q=0.7\";\n case \"csv\":\n return \"text/csv, text/plain;q=0.8,*/*;q=0.7\";\n case \"excel\":\n return \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, */*;q=0.7\";\n }\n}\n\nfunction previewFilename(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"preview.clicky.json\";\n case \"html\":\n return \"preview.html\";\n case \"markdown\":\n return \"preview.md\";\n case \"pdf\":\n return \"preview.pdf\";\n case \"json\":\n return \"preview.json\";\n case \"csv\":\n return \"preview.csv\";\n case \"excel\":\n return \"preview.xlsx\";\n }\n}\n\nfunction parseJson(text: string): { ok: true; value: unknown } | { ok: false } {\n try {\n return { ok: true, value: JSON.parse(text) as unknown };\n } catch {\n return { ok: false };\n }\n}\n\nfunction isJsonContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"json\") ?? false;\n}\n\nfunction isHtmlContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"html\") ?? false;\n}\n\nfunction isBinaryContent(contentType: string | undefined) {\n const normalized = contentType?.toLowerCase() ?? \"\";\n return (\n normalized.includes(\"application/pdf\") ||\n normalized.includes(\"spreadsheetml\") ||\n normalized.includes(\"application/vnd.ms-excel\")\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MarkdownEditor.js","sources":["../../src/data/MarkdownEditor.tsx"],"sourcesContent":["import {\n useEffect,\n useId,\n useMemo,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { Button } from \"../components/button\";\nimport { IconButton } from \"../components/IconButton\";\nimport {\n SegmentedControl,\n type SegmentedOption,\n} from \"../components/SegmentedControl\";\nimport { cn } from \"../lib/utils\";\nimport {\n UiCopy,\n UiEdit,\n UiEye,\n UiFileCode,\n UiFileSpreadsheet,\n UiFileText,\n UiJson,\n UiMarkdown,\n UiRefresh,\n} from \"../icons\";\nimport { Clicky, type ClickyProps } from \"./Clicky\";\nimport { Icon, type StaticIconComponent } from \"./Icon\";\nimport { JsonView } from \"./JsonView\";\nimport { Markdown } from \"./Markdown\";\nimport {\n buildMarkdownPreviewUrl,\n MARKDOWN_EDITOR_PREVIEW_FORMATS,\n type MarkdownEditorPreviewFormat,\n type MarkdownEditorPreviewHeaders,\n type MarkdownEditorPreviewRequest,\n type MarkdownEditorPreviewResult,\n} from \"./MarkdownEditor.model\";\n\nexport type MarkdownEditorProps = {\n /** Controlled markdown source. */\n value?: string;\n /** Initial markdown source for uncontrolled usage. */\n defaultValue?: string;\n /** Called whenever the editor source changes. */\n onChange?: (value: string) => void;\n /** Editor label. */\n label?: ReactNode;\n /** Textarea placeholder. */\n placeholder?: string;\n /** Preview formats to expose in the toolbar. */\n previewFormats?: readonly MarkdownEditorPreviewFormat[];\n /** Controlled active preview format. */\n previewFormat?: MarkdownEditorPreviewFormat;\n /** Initial active preview format for uncontrolled usage. */\n defaultPreviewFormat?: MarkdownEditorPreviewFormat;\n /** Called when the active preview format changes. */\n onPreviewFormatChange?: (format: MarkdownEditorPreviewFormat) => void;\n /** Clicky endpoint that accepts markdown and a `format=` query parameter. */\n previewEndpoint?: string;\n /** HTTP method for `previewEndpoint`; POST sends the markdown body. */\n previewMethod?: \"GET\" | \"POST\" | \"PUT\";\n /** Extra headers for remote previews. */\n previewHeaders?: MarkdownEditorPreviewHeaders;\n /** Build a URL for remote preview requests instead of `previewEndpoint`. */\n buildPreviewUrl?: (request: {\n markdown: string;\n format: MarkdownEditorPreviewFormat;\n }) => string | undefined;\n /**\n * Custom loader for host-specific markdown conversion. Return `undefined` for\n * a format to leave it on the local preview — Clicky's `format=` contract has\n * no `react`, so hosts commonly convert every other format remotely.\n */\n loadPreview?: (\n request: MarkdownEditorPreviewRequest,\n ) =>\n | Promise<MarkdownEditorPreviewResult | undefined>\n | MarkdownEditorPreviewResult\n | undefined;\n /** Local Clicky document for the React preview, or a mapper from markdown. */\n clickyData?: ClickyProps[\"data\"] | ((markdown: string) => ClickyProps[\"data\"] | undefined);\n /** Debounce interval for remote preview requests. */\n previewDebounceMs?: number;\n /** Minimum height for both editor and preview panes. */\n minHeight?: number | string;\n /** Disable editing and preview refresh. */\n disabled?: boolean;\n /** Render the source as read-only. */\n readOnly?: boolean;\n /** Classes applied to the component root. */\n className?: string;\n /** Classes applied to the textarea. */\n editorClassName?: string;\n /** Classes applied to the preview body. */\n previewClassName?: string;\n /** Extra toolbar content rendered after the built-in actions. */\n toolbar?: ReactNode;\n};\n\ntype PreviewState =\n | { status: \"idle\" }\n | { status: \"loading\"; result?: MarkdownEditorPreviewResult }\n | { status: \"success\"; result: MarkdownEditorPreviewResult }\n | { status: \"error\"; error: string; result?: MarkdownEditorPreviewResult };\n\ntype FormatMeta = {\n label: string;\n icon: StaticIconComponent;\n iconClassName?: string;\n};\n\nconst FORMAT_META: Record<MarkdownEditorPreviewFormat, FormatMeta> = {\n react: {\n label: \"React\",\n icon: UiEye,\n },\n html: {\n label: \"HTML\",\n icon: UiFileCode,\n },\n markdown: {\n label: \"Markdown\",\n icon: UiMarkdown,\n },\n pdf: {\n label: \"PDF\",\n icon: UiFileText,\n iconClassName: \"text-rose-600 dark:text-rose-400\",\n },\n json: {\n label: \"JSON\",\n icon: UiJson,\n },\n csv: {\n label: \"CSV\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-600 dark:text-emerald-400\",\n },\n excel: {\n label: \"Excel\",\n icon: UiFileSpreadsheet,\n iconClassName: \"text-emerald-700 dark:text-emerald-300\",\n },\n};\n\n/**\n * Split-pane markdown editor with local Markdown/React preview and optional\n * Clicky-backed format previews. Hosts can pass `previewEndpoint` for the\n * standard Clicky `format=` contract or `loadPreview` for custom conversion.\n */\nexport function MarkdownEditor({\n value,\n defaultValue = \"\",\n onChange,\n label = \"Markdown\",\n placeholder = \"Write markdown...\",\n previewFormats,\n previewFormat,\n defaultPreviewFormat,\n onPreviewFormatChange,\n previewEndpoint,\n previewMethod = \"POST\",\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n clickyData,\n previewDebounceMs = 350,\n minHeight = 420,\n disabled = false,\n readOnly = false,\n className,\n editorClassName,\n previewClassName,\n toolbar,\n}: MarkdownEditorProps) {\n const editorId = useId();\n const formats = useMemo(\n () => normalizePreviewFormats(previewFormats),\n [previewFormats],\n );\n const firstFormat = formats[0] ?? \"react\";\n const [draft, setDraft] = useState(defaultValue);\n const markdown = value ?? draft;\n const [internalFormat, setInternalFormat] = useState<MarkdownEditorPreviewFormat>(\n () =>\n normalizeInitialFormat(defaultPreviewFormat, formats) ??\n firstFormat,\n );\n const activeFormat = formats.includes(previewFormat ?? internalFormat)\n ? previewFormat ?? internalFormat\n : firstFormat;\n const [refreshKey, setRefreshKey] = useState(0);\n const [previewState, setPreviewState] = useState<PreviewState>({\n status: \"idle\",\n });\n const contentStyle = useMemo<CSSProperties>(\n () => ({ minHeight: cssSize(minHeight) }),\n [minHeight],\n );\n const remoteEnabled = Boolean(loadPreview || previewEndpoint || buildPreviewUrl);\n const currentMeta = FORMAT_META[activeFormat];\n const segmentOptions = useMemo<SegmentedOption<MarkdownEditorPreviewFormat>[]>(\n () =>\n formats.map((format) => {\n const meta = FORMAT_META[format];\n return {\n id: format,\n label: meta.label,\n icon: meta.icon,\n title: `${meta.label} preview`,\n };\n }),\n [formats],\n );\n\n useEffect(() => {\n if (formats.includes(activeFormat)) return;\n setInternalFormat(firstFormat);\n }, [activeFormat, firstFormat, formats]);\n\n useEffect(() => {\n if (!remoteEnabled) {\n setPreviewState({ status: \"idle\" });\n return;\n }\n\n const controller = new AbortController();\n const timeout = window.setTimeout(() => {\n setPreviewState((current) =>\n current.status === \"success\"\n ? { status: \"loading\", result: current.result }\n : { status: \"loading\" },\n );\n\n resolvePreview({\n markdown,\n format: activeFormat,\n signal: controller.signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n })\n .then((result) => {\n if (controller.signal.aborted) return;\n setPreviewState(\n result ? { status: \"success\", result } : { status: \"idle\" },\n );\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) return;\n setPreviewState((current) => ({\n status: \"error\",\n error: error instanceof Error ? error.message : \"Preview failed\",\n ...(current.status === \"loading\" && current.result\n ? { result: current.result }\n : {}),\n }));\n });\n }, Math.max(0, previewDebounceMs));\n\n return () => {\n window.clearTimeout(timeout);\n controller.abort();\n };\n }, [\n activeFormat,\n buildPreviewUrl,\n loadPreview,\n markdown,\n previewDebounceMs,\n previewEndpoint,\n previewHeaders,\n previewMethod,\n refreshKey,\n remoteEnabled,\n ]);\n\n const updateMarkdown = (next: string) => {\n if (value === undefined) setDraft(next);\n onChange?.(next);\n };\n\n const updateFormat = (next: MarkdownEditorPreviewFormat) => {\n if (previewFormat === undefined) setInternalFormat(next);\n onPreviewFormatChange?.(next);\n };\n\n const copySource = () => {\n const clipboard = globalThis.navigator?.clipboard;\n if (clipboard?.writeText) {\n void clipboard.writeText(markdown).catch(() => undefined);\n }\n };\n\n return (\n <div className={cn(\"rounded-md border border-border bg-card\", className)}>\n <div className=\"flex flex-wrap items-center gap-density-2 border-b border-border px-density-3 py-density-2\">\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n <Icon icon={UiEdit} className=\"text-base text-muted-foreground\" />\n <label\n htmlFor={editorId}\n className=\"truncate text-sm font-medium text-card-foreground\"\n >\n {label}\n </label>\n {previewState.status === \"loading\" && (\n <span className=\"text-xs text-muted-foreground\">Refreshing...</span>\n )}\n </div>\n <div className=\"flex min-w-0 flex-wrap items-center justify-end gap-2\">\n <SegmentedControl\n value={activeFormat}\n options={segmentOptions}\n onChange={updateFormat}\n size=\"sm\"\n aria-label=\"Markdown preview format\"\n className=\"max-w-full flex-wrap\"\n />\n {remoteEnabled && (\n <IconButton\n icon={UiRefresh}\n label=\"Refresh preview\"\n disabled={disabled}\n onClick={() => setRefreshKey((current) => current + 1)}\n />\n )}\n <IconButton icon={UiCopy} label=\"Copy markdown\" onClick={copySource} />\n {toolbar}\n </div>\n </div>\n\n <div className=\"grid gap-density-3 p-density-3 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]\">\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n Source\n </div>\n <textarea\n id={editorId}\n value={markdown}\n placeholder={placeholder}\n disabled={disabled}\n readOnly={readOnly}\n spellCheck\n onChange={(event) => updateMarkdown(event.currentTarget.value)}\n className={cn(\n \"block w-full resize-y border-0 bg-transparent px-density-3 py-density-3 font-mono text-sm leading-6 text-foreground outline-none placeholder:text-placeholder disabled:cursor-not-allowed disabled:opacity-60\",\n editorClassName,\n )}\n style={contentStyle}\n />\n </div>\n\n <div className=\"min-w-0 overflow-hidden rounded-md border border-border bg-background\">\n <div className=\"flex items-center gap-2 border-b border-border px-density-3 py-density-2 text-xs font-medium text-muted-foreground\">\n <Icon\n icon={currentMeta.icon}\n className={cn(\"text-sm\", currentMeta.iconClassName)}\n />\n <span>{currentMeta.label}</span>\n </div>\n <div\n className={cn(\n \"overflow-auto px-density-3 py-density-3\",\n previewClassName,\n )}\n style={contentStyle}\n >\n <MarkdownEditorPreview\n format={activeFormat}\n markdown={markdown}\n state={previewState}\n clickyData={clickyData}\n />\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction MarkdownEditorPreview({\n format,\n markdown,\n state,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n state: PreviewState;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n const result =\n state.status === \"success\" || state.status === \"loading\" || state.status === \"error\"\n ? state.result\n : undefined;\n\n return (\n <div className=\"space-y-density-3\">\n {state.status === \"error\" && (\n <PreviewNotice title=\"Preview failed\" message={state.error} tone=\"danger\" />\n )}\n {result ? (\n <PreviewResult format={format} result={result} />\n ) : (\n <LocalPreview\n format={format}\n markdown={markdown}\n clickyData={clickyData}\n />\n )}\n </div>\n );\n}\n\nfunction LocalPreview({\n format,\n markdown,\n clickyData,\n}: {\n format: MarkdownEditorPreviewFormat;\n markdown: string;\n clickyData?: MarkdownEditorProps[\"clickyData\"];\n}) {\n if (format === \"react\") {\n const data =\n typeof clickyData === \"function\" ? clickyData(markdown) : clickyData;\n return data === undefined ? <Markdown text={markdown} /> : <Clicky data={data} />;\n }\n\n if (format === \"markdown\") {\n return <TextPreview label=\"Markdown source\" text={markdown} />;\n }\n\n return (\n <PreviewNotice\n title={`${FORMAT_META[format].label} preview not configured`}\n message=\"Pass previewEndpoint or loadPreview to render this format from Clicky.\"\n />\n );\n}\n\nfunction PreviewResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: MarkdownEditorPreviewResult;\n}) {\n switch (result.kind) {\n case \"clicky\":\n return <Clicky data={result.data} />;\n case \"html\":\n return <HtmlPreview html={result.html} />;\n case \"json\":\n return <JsonView data={result.data} format=\"json\" />;\n case \"url\":\n return <UrlPreview format={format} url={result.url} />;\n case \"blob\":\n return <BlobPreview format={format} result={result} />;\n case \"text\":\n return <TextResult format={format} result={result} />;\n }\n}\n\nfunction TextResult({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"text\" }>;\n}) {\n if (format === \"react\") {\n return <Clicky data={result.text} />;\n }\n\n if (format === \"html\" || isHtmlContent(result.contentType)) {\n return <HtmlPreview html={result.text} />;\n }\n\n if (format === \"json\" || isJsonContent(result.contentType)) {\n const parsed = parseJson(result.text);\n return parsed.ok ? (\n <JsonView data={parsed.value} format=\"json\" />\n ) : (\n <TextPreview label=\"JSON output\" text={result.text} />\n );\n }\n\n return (\n <TextPreview\n label={`${FORMAT_META[format].label} output`}\n text={result.text}\n />\n );\n}\n\nfunction UrlPreview({\n format,\n url,\n}: {\n format: MarkdownEditorPreviewFormat;\n url: string;\n}) {\n if (format === \"react\") {\n return <Clicky url={url} view={[\"clicky\"]} download={{ all: false }} />;\n }\n\n if (format === \"html\") {\n return <HtmlPreview src={url} />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n if (format === \"excel\") {\n return <DownloadPreview label=\"Open Excel workbook\" href={url} />;\n }\n\n return <TextPreview label={`${FORMAT_META[format].label} URL`} text={url} />;\n}\n\nfunction BlobPreview({\n format,\n result,\n}: {\n format: MarkdownEditorPreviewFormat;\n result: Extract<MarkdownEditorPreviewResult, { kind: \"blob\" }>;\n}) {\n const [url, setUrl] = useState<string>();\n\n useEffect(() => {\n const next = URL.createObjectURL(result.blob);\n setUrl(next);\n return () => URL.revokeObjectURL(next);\n }, [result.blob]);\n\n if (!url) {\n return <PreviewNotice title=\"Preparing preview\" message=\"Creating object URL.\" />;\n }\n\n if (format === \"pdf\") {\n return <FramePreview title=\"PDF preview\" src={url} />;\n }\n\n return (\n <DownloadPreview\n label={`Open ${FORMAT_META[format].label}`}\n href={url}\n {...(result.filename ? { download: result.filename } : {})}\n />\n );\n}\n\nfunction HtmlPreview({\n html,\n src,\n}: {\n html?: string;\n src?: string;\n}) {\n return (\n <FramePreview\n title=\"HTML preview\"\n {...(src ? { src } : {})}\n {...(html ? { srcDoc: html } : {})}\n sandbox=\"allow-same-origin\"\n />\n );\n}\n\nfunction FramePreview({\n title,\n src,\n srcDoc,\n sandbox,\n}: {\n title: string;\n src?: string;\n srcDoc?: string;\n sandbox?: string;\n}) {\n return (\n <div className=\"overflow-hidden rounded-md border border-border bg-background\">\n <iframe\n title={title}\n {...(src ? { src } : {})}\n {...(srcDoc ? { srcDoc } : {})}\n {...(sandbox ? { sandbox } : {})}\n className=\"h-[720px] w-full bg-background\"\n />\n </div>\n );\n}\n\nfunction DownloadPreview({\n label,\n href,\n download,\n}: {\n label: string;\n href: string;\n download?: string;\n}) {\n return (\n <PreviewNotice\n title=\"Inline preview unavailable\"\n message={\n <Button asChild variant=\"outline\" size=\"sm\">\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n {...(download ? { download } : {})}\n >\n {label}\n </a>\n </Button>\n }\n />\n );\n}\n\nfunction TextPreview({ label, text }: { label: string; text: string }) {\n return (\n <pre\n aria-label={label}\n className=\"overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-muted/30 px-density-3 py-density-3 font-mono text-xs text-foreground\"\n >\n {text || \"No content\"}\n </pre>\n );\n}\n\nfunction PreviewNotice({\n title,\n message,\n tone = \"default\",\n}: {\n title: string;\n message: ReactNode;\n tone?: \"default\" | \"danger\";\n}) {\n return (\n <div\n className={cn(\n \"rounded-md border p-density-3\",\n tone === \"danger\"\n ? \"border-destructive/30 bg-destructive/5\"\n : \"border-border bg-muted/30\",\n )}\n >\n <div\n className={cn(\n \"text-sm font-medium\",\n tone === \"danger\" && \"text-destructive\",\n )}\n >\n {title}\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">{message}</div>\n </div>\n );\n}\n\nfunction normalizePreviewFormats(\n formats: readonly MarkdownEditorPreviewFormat[] | undefined,\n): MarkdownEditorPreviewFormat[] {\n const seen = new Set<MarkdownEditorPreviewFormat>();\n const source = formats && formats.length > 0 ? formats : MARKDOWN_EDITOR_PREVIEW_FORMATS;\n for (const format of source) {\n seen.add(format);\n }\n return [...seen];\n}\n\nfunction normalizeInitialFormat(\n format: MarkdownEditorPreviewFormat | undefined,\n formats: readonly MarkdownEditorPreviewFormat[],\n) {\n return format && formats.includes(format) ? format : undefined;\n}\n\nfunction cssSize(size: number | string) {\n return typeof size === \"number\" ? `${size}px` : size;\n}\n\nasync function resolvePreview({\n markdown,\n format,\n signal,\n previewEndpoint,\n previewMethod,\n previewHeaders,\n buildPreviewUrl,\n loadPreview,\n}: MarkdownEditorPreviewRequest & {\n previewEndpoint: string | undefined;\n previewMethod: \"GET\" | \"POST\" | \"PUT\";\n previewHeaders: MarkdownEditorPreviewHeaders | undefined;\n buildPreviewUrl: MarkdownEditorProps[\"buildPreviewUrl\"] | undefined;\n loadPreview: MarkdownEditorProps[\"loadPreview\"] | undefined;\n}): Promise<MarkdownEditorPreviewResult | undefined> {\n if (loadPreview) {\n return loadPreview({ markdown, format, signal });\n }\n\n const url =\n buildPreviewUrl?.({ markdown, format }) ??\n (previewEndpoint\n ? buildMarkdownPreviewUrl(previewEndpoint, format)\n : undefined);\n\n if (!url) {\n throw new Error(\"No preview endpoint configured\");\n }\n\n const headers = new Headers(\n typeof previewHeaders === \"function\"\n ? previewHeaders({ markdown, format })\n : previewHeaders,\n );\n headers.set(\"Accept\", previewAccept(format));\n\n const init: RequestInit = {\n method: previewMethod,\n headers,\n signal,\n };\n\n if (previewMethod !== \"GET\") {\n headers.set(\"Content-Type\", \"text/markdown; charset=utf-8\");\n init.body = markdown;\n }\n\n const response = await fetch(url, init);\n if (!response.ok) {\n throw new Error(\n `Preview failed with ${response.status} ${response.statusText}`.trim(),\n );\n }\n\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n if (format === \"pdf\" || format === \"excel\" || isBinaryContent(contentType)) {\n return {\n kind: \"blob\",\n blob: await response.blob(),\n contentType,\n filename: previewFilename(format),\n };\n }\n\n const text = await response.text();\n if (format === \"react\") {\n return { kind: \"clicky\", data: text };\n }\n if (format === \"html\" || isHtmlContent(contentType)) {\n return { kind: \"html\", html: text };\n }\n if (format === \"json\" || isJsonContent(contentType)) {\n const parsed = parseJson(text);\n return parsed.ok\n ? { kind: \"json\", data: parsed.value }\n : { kind: \"text\", text, contentType };\n }\n return { kind: \"text\", text, contentType };\n}\n\nfunction previewAccept(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"application/json+clicky, application/clicky+json;q=0.9, application/json;q=0.8,*/*;q=0.7\";\n case \"html\":\n return \"text/html, */*;q=0.7\";\n case \"markdown\":\n return \"text/markdown, text/plain;q=0.8,*/*;q=0.7\";\n case \"pdf\":\n return \"application/pdf, */*;q=0.7\";\n case \"json\":\n return \"application/json, text/plain;q=0.8,*/*;q=0.7\";\n case \"csv\":\n return \"text/csv, text/plain;q=0.8,*/*;q=0.7\";\n case \"excel\":\n return \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, */*;q=0.7\";\n }\n}\n\nfunction previewFilename(format: MarkdownEditorPreviewFormat) {\n switch (format) {\n case \"react\":\n return \"preview.clicky.json\";\n case \"html\":\n return \"preview.html\";\n case \"markdown\":\n return \"preview.md\";\n case \"pdf\":\n return \"preview.pdf\";\n case \"json\":\n return \"preview.json\";\n case \"csv\":\n return \"preview.csv\";\n case \"excel\":\n return \"preview.xlsx\";\n }\n}\n\nfunction parseJson(text: string): { ok: true; value: unknown } | { ok: false } {\n try {\n return { ok: true, value: JSON.parse(text) as unknown };\n } catch {\n return { ok: false };\n }\n}\n\nfunction isJsonContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"json\") ?? false;\n}\n\nfunction isHtmlContent(contentType: string | undefined) {\n return contentType?.toLowerCase().includes(\"html\") ?? false;\n}\n\nfunction isBinaryContent(contentType: string | undefined) {\n const normalized = contentType?.toLowerCase() ?? \"\";\n return (\n normalized.includes(\"application/pdf\") ||\n normalized.includes(\"spreadsheetml\") ||\n normalized.includes(\"application/vnd.ms-excel\")\n );\n}\n"],"names":[],"mappings":"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"}
|
package/dist/data/TreeNode.cjs
CHANGED
|
@@ -38,7 +38,7 @@ function TreeNode({
|
|
|
38
38
|
const expandable = hasChildren || lazyUnloaded;
|
|
39
39
|
const secondaryNode = (isSecondary == null ? void 0 : isSecondary(node)) ?? false;
|
|
40
40
|
const childrenAllSecondary = hasChildren && isSecondary != null && children.every((c) => isSecondary(c));
|
|
41
|
-
const skipExpandAll = secondaryNode || childrenAllSecondary;
|
|
41
|
+
const skipExpandAll = secondaryNode || childrenAllSecondary || expandAll === true && lazyUnloaded;
|
|
42
42
|
const initialOpen = expandAll !== null && !skipExpandAll ? expandAll : defaultOpen ? defaultOpen(node, depth) : depth < 1;
|
|
43
43
|
const [open, setOpen] = react.useState(initialOpen);
|
|
44
44
|
const prevExpandAll = react.useRef(expandAll);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNode.cjs","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\n// A row's content column starts after the chevron (`w-3`, 12px) plus the row's\n// `gap-1.5` (6px) — fixed regardless of indentPx/basePaddingPx, since the\n// chevron/spacer width and gap are not configurable. renderDetail's wrapper\n// adds this on top of the row's own paddingLeft so it lines up under the label.\nconst ROW_CONTENT_OFFSET_PX = 18;\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n /**\n * Render extra content beneath a node's row and above its children (e.g. the\n * decompiled source line a call was made from). Rendered for leaf and parent\n * nodes alike, regardless of open/collapsed state, and left-aligned with the\n * row's content column (after the depth indent and chevron). Returning\n * `null`/`undefined`/`false` renders nothing — no wrapper, no extra spacing.\n * A click or keydown inside it is stopped from propagating, so it can never\n * toggle the row's expand/collapse state.\n */\n renderDetail?: (node: T) => ReactNode;\n /** Render a node's result after its children, including when the children are collapsed. */\n renderAfterChildren?: (node: T) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n renderDetail,\n renderAfterChildren,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n const skipExpandAll = secondaryNode || childrenAllSecondary;\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n // A lazy node can be open without ever having been clicked — defaultOpen said\n // so, expand-all did, or the filter forced it open to reveal a match. Loading\n // only on the open transition would leave every one of those showing a caret\n // over nothing.\n //\n // A node that already failed is skipped: loadLazyChildren clears its own retry\n // guard on failure so a re-toggle can try again, and re-running here would\n // turn that into an unbounded retry loop instead.\n useEffect(() => {\n if (isOpen && lazyUnloaded && error === null) loadLazyChildren();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, lazyUnloaded, error]);\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n const detail = renderDetail?.(node);\n const afterChildren = renderAfterChildren?.(node);\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {detail != null && detail !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {detail}\n </div>\n )}\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(renderDetail ? { renderDetail } : {})}\n {...(renderAfterChildren ? { renderAfterChildren } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n {afterChildren != null && afterChildren !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {afterChildren}\n </div>\n )}\n </div>\n );\n}\n"],"names":["useState","useRef","useEffect","jsxs","cn","jsx","Icon","UiChevronDown","UiChevronRight"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TreeNode.cjs","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\n// A row's content column starts after the chevron (`w-3`, 12px) plus the row's\n// `gap-1.5` (6px) — fixed regardless of indentPx/basePaddingPx, since the\n// chevron/spacer width and gap are not configurable. renderDetail's wrapper\n// adds this on top of the row's own paddingLeft so it lines up under the label.\nconst ROW_CONTENT_OFFSET_PX = 18;\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n /**\n * Render extra content beneath a node's row and above its children (e.g. the\n * decompiled source line a call was made from). Rendered for leaf and parent\n * nodes alike, regardless of open/collapsed state, and left-aligned with the\n * row's content column (after the depth indent and chevron). Returning\n * `null`/`undefined`/`false` renders nothing — no wrapper, no extra spacing.\n * A click or keydown inside it is stopped from propagating, so it can never\n * toggle the row's expand/collapse state.\n */\n renderDetail?: (node: T) => ReactNode;\n /** Render a node's result after its children, including when the children are collapsed. */\n renderAfterChildren?: (node: T) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n renderDetail,\n renderAfterChildren,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n // An unloaded lazy node never opens in bulk either: opening it would fetch,\n // and bulk operations never trigger loads. Collapse-all still closes it.\n const skipExpandAll = secondaryNode || childrenAllSecondary || (expandAll === true && lazyUnloaded);\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n // A lazy node can be open without ever having been clicked — defaultOpen said\n // so, expand-all did, or the filter forced it open to reveal a match. Loading\n // only on the open transition would leave every one of those showing a caret\n // over nothing.\n //\n // A node that already failed is skipped: loadLazyChildren clears its own retry\n // guard on failure so a re-toggle can try again, and re-running here would\n // turn that into an unbounded retry loop instead.\n useEffect(() => {\n if (isOpen && lazyUnloaded && error === null) loadLazyChildren();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, lazyUnloaded, error]);\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n const detail = renderDetail?.(node);\n const afterChildren = renderAfterChildren?.(node);\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {detail != null && detail !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {detail}\n </div>\n )}\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(renderDetail ? { renderDetail } : {})}\n {...(renderAfterChildren ? { renderAfterChildren } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n {afterChildren != null && afterChildren !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {afterChildren}\n </div>\n )}\n </div>\n );\n}\n"],"names":["useState","useRef","useEffect","jsxs","cn","jsx","Icon","UiChevronDown","UiChevronRight"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNode.d.ts","sourceRoot":"","sources":["../../src/data/TreeNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAWpE,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC;IAC1C,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;IACrC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACjD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IACtC,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACpC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAC1B,IAAI,EACJ,KAAS,EACT,SAAgB,EAChB,cAAqB,EACrB,QAAe,EACf,WAAW,EACX,WAAW,EACX,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,QAAQ,EACR,QAAa,EACb,aAAiB,EACjB,WAAW,EACX,eAAe,EACf,YAAY,GACb,EAAE,aAAa,CAAC,CAAC,CAAC,+
|
|
1
|
+
{"version":3,"file":"TreeNode.d.ts","sourceRoot":"","sources":["../../src/data/TreeNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAWpE,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,+EAA+E;IAC/E,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,CAAC;IAC1C,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAC;IACrC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,SAAS,EAAE,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC;IACjD;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IACtC,4FAA4F;IAC5F,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACzC;;;;;;;;;;;;;;;OAeG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACpC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,EAC1B,IAAI,EACJ,KAAS,EACT,SAAgB,EAChB,cAAqB,EACrB,QAAe,EACf,WAAW,EACX,WAAW,EACX,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,QAAQ,EACR,QAAa,EACb,aAAiB,EACjB,WAAW,EACX,eAAe,EACf,YAAY,GACb,EAAE,aAAa,CAAC,CAAC,CAAC,+BAkNlB"}
|
package/dist/data/TreeNode.js
CHANGED
|
@@ -36,7 +36,7 @@ function TreeNode({
|
|
|
36
36
|
const expandable = hasChildren || lazyUnloaded;
|
|
37
37
|
const secondaryNode = (isSecondary == null ? void 0 : isSecondary(node)) ?? false;
|
|
38
38
|
const childrenAllSecondary = hasChildren && isSecondary != null && children.every((c) => isSecondary(c));
|
|
39
|
-
const skipExpandAll = secondaryNode || childrenAllSecondary;
|
|
39
|
+
const skipExpandAll = secondaryNode || childrenAllSecondary || expandAll === true && lazyUnloaded;
|
|
40
40
|
const initialOpen = expandAll !== null && !skipExpandAll ? expandAll : defaultOpen ? defaultOpen(node, depth) : depth < 1;
|
|
41
41
|
const [open, setOpen] = useState(initialOpen);
|
|
42
42
|
const prevExpandAll = useRef(expandAll);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNode.js","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\n// A row's content column starts after the chevron (`w-3`, 12px) plus the row's\n// `gap-1.5` (6px) — fixed regardless of indentPx/basePaddingPx, since the\n// chevron/spacer width and gap are not configurable. renderDetail's wrapper\n// adds this on top of the row's own paddingLeft so it lines up under the label.\nconst ROW_CONTENT_OFFSET_PX = 18;\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n /**\n * Render extra content beneath a node's row and above its children (e.g. the\n * decompiled source line a call was made from). Rendered for leaf and parent\n * nodes alike, regardless of open/collapsed state, and left-aligned with the\n * row's content column (after the depth indent and chevron). Returning\n * `null`/`undefined`/`false` renders nothing — no wrapper, no extra spacing.\n * A click or keydown inside it is stopped from propagating, so it can never\n * toggle the row's expand/collapse state.\n */\n renderDetail?: (node: T) => ReactNode;\n /** Render a node's result after its children, including when the children are collapsed. */\n renderAfterChildren?: (node: T) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n renderDetail,\n renderAfterChildren,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n const skipExpandAll = secondaryNode || childrenAllSecondary;\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n // A lazy node can be open without ever having been clicked — defaultOpen said\n // so, expand-all did, or the filter forced it open to reveal a match. Loading\n // only on the open transition would leave every one of those showing a caret\n // over nothing.\n //\n // A node that already failed is skipped: loadLazyChildren clears its own retry\n // guard on failure so a re-toggle can try again, and re-running here would\n // turn that into an unbounded retry loop instead.\n useEffect(() => {\n if (isOpen && lazyUnloaded && error === null) loadLazyChildren();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, lazyUnloaded, error]);\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n const detail = renderDetail?.(node);\n const afterChildren = renderAfterChildren?.(node);\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {detail != null && detail !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {detail}\n </div>\n )}\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(renderDetail ? { renderDetail } : {})}\n {...(renderAfterChildren ? { renderAfterChildren } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n {afterChildren != null && afterChildren !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {afterChildren}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TreeNode.js","sources":["../../src/data/TreeNode.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Icon } from \"./Icon\";\nimport { UiChevronDown, UiChevronRight } from \"../icons\";\n\n// A row's content column starts after the chevron (`w-3`, 12px) plus the row's\n// `gap-1.5` (6px) — fixed regardless of indentPx/basePaddingPx, since the\n// chevron/spacer width and gap are not configurable. renderDetail's wrapper\n// adds this on top of the row's own paddingLeft so it lines up under the label.\nconst ROW_CONTENT_OFFSET_PX = 18;\n\nexport type TreeRowContext<T> = {\n node: T;\n depth: number;\n open: boolean;\n selected: boolean;\n hasChildren: boolean;\n toggle: () => void;\n /** True while this node's lazy children are being fetched via loadChildren. */\n loading: boolean;\n /** The rejection value from loadChildren, or null when there was no error. */\n error: unknown;\n};\n\nexport type TreeNodeProps<T> = {\n node: T;\n depth?: number;\n expandAll?: boolean | null;\n forcedOpenKeys?: Set<string | number> | null;\n selected?: T | null;\n defaultOpen?: (node: T, depth: number) => boolean;\n getChildren: (node: T) => T[] | undefined;\n getKey: (node: T) => string | number;\n getAriaLabel?: (node: T) => string;\n onSelect?: (node: T) => void;\n renderRow: (ctx: TreeRowContext<T>) => ReactNode;\n /**\n * Render extra content beneath a node's row and above its children (e.g. the\n * decompiled source line a call was made from). Rendered for leaf and parent\n * nodes alike, regardless of open/collapsed state, and left-aligned with the\n * row's content column (after the depth indent and chevron). Returning\n * `null`/`undefined`/`false` renders nothing — no wrapper, no extra spacing.\n * A click or keydown inside it is stopped from propagating, so it can never\n * toggle the row's expand/collapse state.\n */\n renderDetail?: (node: T) => ReactNode;\n /** Render a node's result after its children, including when the children are collapsed. */\n renderAfterChildren?: (node: T) => ReactNode;\n rowClass?: (node: T, selected: boolean) => string;\n indentPx?: number;\n basePaddingPx?: number;\n /**\n * Reports that a node has children that are not yet loaded — it renders an\n * expand chevron even when `getChildren` returns nothing. On the first open\n * the node fetches them via `loadChildren`. Without this (the default), a\n * node is expandable only when `getChildren` already returns children.\n */\n hasMoreChildren?: (node: T) => boolean;\n /**\n * Lazily fetch a node's children the first time it is opened. Resolves to the\n * child nodes (which may themselves be lazy). A rejection is surfaced to\n * `renderRow` via `ctx.error` and is not retried until the node is collapsed\n * and reopened. Required for any node `hasMoreChildren` returns true for.\n */\n loadChildren?: (node: T) => Promise<T[]>;\n /**\n * Marks a node as a **secondary child** of its parent. Secondary\n * children keep the full tree structure (they render, they can be\n * opened manually) but opt out of the bulk behaviours a caller\n * typically wants when they click the toolbar:\n *\n * - Tree-wide filter: their text is skipped during match detection\n * so typing in the search box never surfaces a row because one\n * of its secondary children happened to match.\n * - Expand all: secondary nodes stay at their default-open state\n * instead of being forced open, preventing 28k field rows from\n * flooding the viewport when an operator hits the button on a\n * schema with hundreds of tables.\n *\n * Default: every node is primary (returns false).\n */\n isSecondary?: (node: T) => boolean;\n};\n\nexport function TreeNode<T>({\n node,\n depth = 0,\n expandAll = null,\n forcedOpenKeys = null,\n selected = null,\n defaultOpen,\n getChildren,\n getKey,\n getAriaLabel,\n onSelect,\n renderRow,\n renderDetail,\n renderAfterChildren,\n rowClass,\n indentPx = 16,\n basePaddingPx = 8,\n isSecondary,\n hasMoreChildren,\n loadChildren,\n}: TreeNodeProps<T>) {\n // Lazily-fetched children take precedence over the synchronous ones once a\n // load has resolved; until then `loadedChildren` is null and we fall back to\n // getChildren. A node can be \"lazy\" (hasMoreChildren) with no sync children.\n const [loadedChildren, setLoadedChildren] = useState<T[] | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<unknown>(null);\n const syncChildren = getChildren(node);\n const children = loadedChildren ?? syncChildren;\n const hasChildren = (children?.length ?? 0) > 0;\n const lazyUnloaded = (hasMoreChildren?.(node) ?? false) && loadedChildren === null;\n // The chevron shows when there is something to reveal: either real children\n // are present, or the node is lazy and has not been loaded yet.\n const expandable = hasChildren || lazyUnloaded;\n // A node opts out of bulk expand-all in two distinct cases:\n //\n // 1. The node itself is secondary (its edge from the parent is\n // secondary) — rare at the root, but the rule is symmetric.\n // 2. All of the node's children are secondary — the common case.\n // This is what keeps an \"Expand all\" on a schema tree from\n // flooding the viewport with every table's field rows: the\n // table opens to nothing structural worth seeing in bulk, so\n // we leave it closed until the operator clicks it manually.\n //\n // In both cases the manual toggle still works, and filter matches\n // still force the row open via forcedOpenKeys, so users never\n // lose access — they just don't get auto-flooded.\n const secondaryNode = isSecondary?.(node) ?? false;\n const childrenAllSecondary =\n hasChildren && isSecondary != null && children!.every((c) => isSecondary(c));\n // An unloaded lazy node never opens in bulk either: opening it would fetch,\n // and bulk operations never trigger loads. Collapse-all still closes it.\n const skipExpandAll = secondaryNode || childrenAllSecondary || (expandAll === true && lazyUnloaded);\n // A non-null `expandAll` is a live bulk state, not just a one-off change\n // signal: a node mounted *while* expand-all is active (because an ancestor\n // just opened) inherits it as its initial open state, so opening a parent\n // cascades all the way down — expand/collapse-all are recursive. The\n // skipExpandAll guard keeps secondary subtrees from auto-flooding. When\n // expandAll is null (before any toolbar click) we fall back to defaultOpen.\n const initialOpen =\n expandAll !== null && !skipExpandAll\n ? expandAll\n : defaultOpen\n ? defaultOpen(node, depth)\n : depth < 1;\n const [open, setOpen] = useState(initialOpen);\n const prevExpandAll = useRef(expandAll);\n const isSelected = selected === node;\n const key = getKey(node);\n const isForcedOpen = forcedOpenKeys?.has(key) ?? false;\n const isOpen = isForcedOpen || open;\n\n useEffect(() => {\n if (expandAll !== null && expandAll !== prevExpandAll.current && !skipExpandAll) {\n setOpen(expandAll);\n }\n prevExpandAll.current = expandAll;\n }, [expandAll, skipExpandAll]);\n\n // Guards a lazy fetch so a node loads its children at most once per mount and\n // a resolution arriving after the node was reused (key changed) is ignored.\n const loadRequested = useRef(false);\n const nodeKey = getKey(node);\n const loadKeyRef = useRef(nodeKey);\n\n function loadLazyChildren() {\n if (!loadChildren || loadRequested.current) return;\n loadRequested.current = true;\n loadKeyRef.current = nodeKey;\n setLoading(true);\n setError(null);\n loadChildren(node)\n .then((kids) => {\n if (loadKeyRef.current !== nodeKey) return;\n setLoadedChildren(kids);\n setLoading(false);\n })\n .catch((err) => {\n if (loadKeyRef.current !== nodeKey) return;\n // Surfaced to renderRow via ctx.error; allow a retry on re-toggle.\n loadRequested.current = false;\n setError(err);\n setLoading(false);\n });\n }\n\n // A lazy node can be open without ever having been clicked — defaultOpen said\n // so, expand-all did, or the filter forced it open to reveal a match. Loading\n // only on the open transition would leave every one of those showing a caret\n // over nothing.\n //\n // A node that already failed is skipped: loadLazyChildren clears its own retry\n // guard on failure so a re-toggle can try again, and re-running here would\n // turn that into an unbounded retry loop instead.\n useEffect(() => {\n if (isOpen && lazyUnloaded && error === null) loadLazyChildren();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, lazyUnloaded, error]);\n\n function toggle() {\n if (!expandable) return;\n setOpen((o) => {\n const next = !o;\n // Only fetch when transitioning into the open state, so collapsing a\n // not-yet-loaded (e.g. previously-failed) lazy node never triggers a load.\n if (next && lazyUnloaded) loadLazyChildren();\n return next;\n });\n }\n\n const defaultRowBg = isSelected ? \"bg-primary/10 border-l-2 border-primary\" : \"hover:bg-accent\";\n const rowClassName = rowClass ? rowClass(node, isSelected) : defaultRowBg;\n const detail = renderDetail?.(node);\n const afterChildren = renderAfterChildren?.(node);\n\n return (\n <div\n role=\"treeitem\"\n aria-label={getAriaLabel?.(node)}\n aria-expanded={expandable ? isOpen : undefined}\n aria-selected={isSelected}\n >\n <div\n className={cn(\"flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm\", rowClassName)}\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx}px` }}\n onClick={(e) => {\n e.stopPropagation();\n onSelect?.(node);\n toggle();\n }}\n >\n {expandable ? (\n <button\n type=\"button\"\n aria-label={isOpen ? \"Collapse\" : \"Expand\"}\n // The caret only toggles expansion — stopPropagation keeps the row's\n // onClick (which selects) from firing, so expanding a node never\n // selects it.\n onClick={(e) => {\n e.stopPropagation();\n toggle();\n }}\n className=\"flex shrink-0 items-center text-muted-foreground\"\n >\n <Icon icon={isOpen ? UiChevronDown : UiChevronRight} className=\"text-xs w-3\" />\n </button>\n ) : (\n <span className=\"w-3 shrink-0\" aria-hidden />\n )}\n {renderRow({\n node,\n depth,\n open: isOpen,\n selected: isSelected,\n hasChildren,\n toggle,\n loading,\n error,\n })}\n </div>\n {detail != null && detail !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {detail}\n </div>\n )}\n {isOpen && hasChildren && (\n <div role=\"group\">\n {children!.map((child) => (\n <TreeNode\n key={getKey(child)}\n node={child}\n depth={depth + 1}\n expandAll={expandAll}\n forcedOpenKeys={forcedOpenKeys}\n selected={selected}\n getChildren={getChildren}\n getKey={getKey}\n renderRow={renderRow}\n indentPx={indentPx}\n basePaddingPx={basePaddingPx}\n {...(defaultOpen ? { defaultOpen } : {})}\n {...(renderDetail ? { renderDetail } : {})}\n {...(renderAfterChildren ? { renderAfterChildren } : {})}\n {...(getAriaLabel ? { getAriaLabel } : {})}\n {...(onSelect ? { onSelect } : {})}\n {...(rowClass ? { rowClass } : {})}\n {...(isSecondary ? { isSecondary } : {})}\n {...(hasMoreChildren ? { hasMoreChildren } : {})}\n {...(loadChildren ? { loadChildren } : {})}\n />\n ))}\n </div>\n )}\n {afterChildren != null && afterChildren !== false && (\n <div\n className=\"pb-1 pr-2\"\n style={{ paddingLeft: `${depth * indentPx + basePaddingPx + ROW_CONTENT_OFFSET_PX}px` }}\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n {afterChildren}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|