@ecsplico/editor 2.1.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -1
- package/README.md +39 -156
- package/dist/adapters/comments/drizzle.d.ts +1 -1
- package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
- package/dist/adapters/comments/rest-model.js.map +1 -0
- package/dist/adapters/comments/types.d.ts +2 -2
- package/dist/adapters/document-state.d.ts +23 -0
- package/dist/adapters/document-state.js +66 -0
- package/dist/adapters/document-state.js.map +1 -0
- package/dist/adapters/documents.js +14 -11
- package/dist/adapters/documents.js.map +1 -1
- package/dist/adapters/drizzle.d.ts +2 -2
- package/dist/adapters/drizzle.js +97 -88
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/forge.d.ts +12 -7
- package/dist/adapters/forge.js +38 -45
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/http.d.ts +20 -0
- package/dist/adapters/http.js +68 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/json.d.ts +3 -3
- package/dist/adapters/json.js +58 -49
- package/dist/adapters/json.js.map +1 -1
- package/dist/adapters/memory.d.ts +21 -0
- package/dist/adapters/memory.js +53 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/nitro.d.ts +23 -20
- package/dist/adapters/nitro.js +58 -163
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/react.d.ts +55 -0
- package/dist/adapters/react.js +209 -0
- package/dist/adapters/react.js.map +1 -0
- package/dist/adapters/shared.d.ts +15 -21
- package/dist/adapters/shared.js +10 -8
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/vue.d.ts +15 -30
- package/dist/adapters/vue.js +36 -87
- package/dist/adapters/vue.js.map +1 -1
- package/dist/config/index.d.ts +105 -0
- package/dist/config/index.js +95 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/abilities.js +1 -0
- package/dist/core/abilities.js.map +1 -1
- package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
- package/dist/core/api-routes.js.map +1 -0
- package/dist/core/backend-capability.d.ts +7 -0
- package/dist/core/backend-capability.js +17 -0
- package/dist/core/backend-capability.js.map +1 -0
- package/dist/core/backend-types.d.ts +245 -0
- package/dist/core/backend-types.js +17 -0
- package/dist/core/backend-types.js.map +1 -0
- package/dist/core/backend.d.ts +108 -0
- package/dist/core/backend.js +14 -0
- package/dist/core/backend.js.map +1 -0
- package/dist/core/block-convert.d.ts +7 -5
- package/dist/core/block-convert.js +28 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/command-types.d.ts +89 -0
- package/dist/core/commands.d.ts +40 -0
- package/dist/core/commands.js +151 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/context.d.ts +17 -20
- package/dist/core/context.js +24 -21
- package/dist/core/context.js.map +1 -1
- package/dist/core/core-feature.d.ts +22 -7
- package/dist/core/core-feature.js +51 -18
- package/dist/core/core-feature.js.map +1 -1
- package/dist/core/define-editor.d.ts +4 -3
- package/dist/core/define-editor.js +14 -7
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/document-markdown.js +12 -3
- package/dist/core/document-markdown.js.map +1 -1
- package/dist/core/editor-ui.d.ts +8 -1
- package/dist/core/editor-ui.js +9 -8
- package/dist/core/editor-ui.js.map +1 -1
- package/dist/core/extension-points.d.ts +3 -15
- package/dist/core/feature-context.d.ts +8 -7
- package/dist/core/feature-context.js +12 -11
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +35 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.d.ts +2 -1
- package/dist/core/fences.js +3 -2
- package/dist/core/fences.js.map +1 -1
- package/dist/core/fetch-error.d.ts +1 -1
- package/dist/core/fetch-error.js +3 -1
- package/dist/core/fetch-error.js.map +1 -1
- package/dist/core/hash.d.ts +5 -0
- package/dist/core/hash.js +11 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/http-backend.d.ts +11 -0
- package/dist/core/http-backend.js +195 -0
- package/dist/core/http-backend.js.map +1 -0
- package/dist/core/index.d.ts +14 -9
- package/dist/core/index.js +12 -9
- package/dist/core/palette.d.ts +48 -0
- package/dist/core/palette.js +95 -0
- package/dist/core/palette.js.map +1 -0
- package/dist/core/schema/abilities.d.ts +2 -1
- package/dist/core/schema/abilities.js +5 -1
- package/dist/core/schema/abilities.js.map +1 -1
- package/dist/core/schema/index.d.ts +11 -5
- package/dist/core/schema/index.js +13 -8
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/mark-flags.d.ts +8 -1
- package/dist/core/schema/of-features.d.ts +13 -0
- package/dist/core/schema/of-features.js +14 -0
- package/dist/core/schema/of-features.js.map +1 -0
- package/dist/core/slash.d.ts +8 -6
- package/dist/core/slash.js +24 -16
- package/dist/core/slash.js.map +1 -1
- package/dist/core/surface-session.js +13 -5
- package/dist/core/surface-session.js.map +1 -1
- package/dist/core/toolbar-items.d.ts +10 -4
- package/dist/core/toolbar-items.js +269 -195
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +11 -0
- package/dist/core/util.js.map +1 -0
- package/dist/document/DocumentSurface.d.ts +1 -1
- package/dist/features/ai/agent-op-review.d.ts +1 -1
- package/dist/features/ai/agent-op-review.js +1 -1
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-apply.d.ts +2 -2
- package/dist/features/ai/ai-apply.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/ai-sse.d.ts +6 -6
- package/dist/features/ai/ai-sse.js +20 -63
- package/dist/features/ai/ai-sse.js.map +1 -1
- package/dist/features/ai/assistant.d.ts +8 -7
- package/dist/features/ai/assistant.js +3 -3
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/block-actions.d.ts +3 -2
- package/dist/features/ai/block-actions.js +3 -2
- package/dist/features/ai/block-actions.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
- package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +8 -7
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +1 -1
- package/dist/features/ai/feature.js +27 -14
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
- package/dist/features/ai/ghost-autocomplete.js +6 -9
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +4 -3
- package/dist/features/ai/index.js +10 -10
- package/dist/features/ai/model-profiles.d.ts +5 -4
- package/dist/features/ai/model-profiles.js +2 -2
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.js +1 -1
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.js +4 -1
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -2
- package/dist/features/ai/protocol/models.d.ts +2 -16
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/rate-limit.d.ts +1 -1
- package/dist/features/ai/rate-limit.js +3 -1
- package/dist/features/ai/rate-limit.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js +2 -2
- package/dist/features/ai/react/AiSidebar.js +4 -4
- package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
- package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
- package/dist/features/ai/react/DocumentChatOps.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +3 -3
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-document-chat.js +2 -2
- package/dist/features/ai/react/use-document-chat.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
- package/dist/features/ai/selection-flow.d.ts +1 -1
- package/dist/features/ai/selection-flow.js +1 -1
- package/dist/features/ai/sidebar-flow.d.ts +1 -1
- package/dist/features/ai/sidebar-flow.js +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +3 -3
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-document-chat.js +2 -2
- package/dist/features/ai/use-document-chat.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +2 -1
- package/dist/features/authors/attribution.d.ts +1 -1
- package/dist/features/authors/feature.js +12 -11
- package/dist/features/authors/feature.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +1 -1
- package/dist/features/block-ui/block-actions.js +1 -1
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +1 -1
- package/dist/features/block-ui/feature.js +1 -0
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +1 -1
- package/dist/features/collab/anchor-resolver.js +1 -1
- package/dist/features/collab/feature.js +2 -0
- package/dist/features/collab/feature.js.map +1 -1
- package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
- package/dist/features/comments/feature.js +12 -11
- package/dist/features/comments/feature.js.map +1 -1
- package/dist/features/comments/index.d.ts +3 -2
- package/dist/features/comments/index.js +1 -1
- package/dist/features/comments/margin-layout.d.ts +3 -2
- package/dist/features/comments/model.d.ts +3 -67
- package/dist/features/comments/model.js +2 -2
- package/dist/features/comments/model.js.map +1 -1
- package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
- package/dist/features/comments/react/use-comments.d.ts +2 -1
- package/dist/features/comments/react.d.ts +1 -1
- package/dist/features/comments/schema.d.ts +2 -52
- package/dist/features/comments/schema.js.map +1 -1
- package/dist/features/comments/snapshot-equality.js.map +1 -1
- package/dist/features/comments/use-comments.d.ts +3 -2
- package/dist/features/comments/vue.d.ts +1 -1
- package/dist/features/composites/accepted-children.d.ts +1 -0
- package/dist/features/composites/accepted-children.js +16 -1
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.js +31 -0
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +11 -0
- package/dist/features/composites/bibliography-form.js +90 -0
- package/dist/features/composites/bibliography-form.js.map +1 -0
- package/dist/features/composites/bibliography.d.ts +33 -0
- package/dist/features/composites/bibliography.js +120 -0
- package/dist/features/composites/bibliography.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +261 -0
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
- package/dist/features/composites/components/CompositeChrome.js +75 -26
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.js +46 -11
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.js +17 -5
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeTable.js +13 -4
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeView.js +11 -1
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +103 -0
- package/dist/features/composites/components/DerivationBadge.js.map +1 -0
- package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
- package/dist/features/composites/components/ReferenceView.js +122 -0
- package/dist/features/composites/components/ReferenceView.js.map +1 -0
- package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
- package/dist/features/composites/components/SettingsEditingTab.js +1 -1
- package/dist/features/composites/convert.js +2 -2
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derivation.d.ts +61 -0
- package/dist/features/composites/derivation.js +98 -0
- package/dist/features/composites/derivation.js.map +1 -0
- package/dist/features/composites/derived-chrome.js +69 -0
- package/dist/features/composites/derived-chrome.js.map +1 -0
- package/dist/features/composites/feature.js +159 -109
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +4 -3
- package/dist/features/composites/fences.js +51 -7
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/index.d.ts +12 -3
- package/dist/features/composites/index.js +15 -6
- package/dist/features/composites/inspector-model.d.ts +4 -1
- package/dist/features/composites/inspector-model.js +8 -4
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/kinds.d.ts +8 -1
- package/dist/features/composites/kinds.js +145 -6
- package/dist/features/composites/kinds.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +4 -1
- package/dist/features/composites/legacy.js +56 -1
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/meta-display.js +40 -1
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +7 -0
- package/dist/features/composites/meta-keys.js +21 -0
- package/dist/features/composites/meta-keys.js.map +1 -0
- package/dist/features/composites/node-views.d.ts +6 -3
- package/dist/features/composites/node-views.js +7 -3
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +6 -1
- package/dist/features/composites/nodes.js +33 -7
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/react/BibliographyEditor.js +229 -0
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
- package/dist/features/composites/react/CompositeChrome.js +65 -17
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
- package/dist/features/composites/react/CompositeDetails.js +45 -6
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.js +11 -5
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeTable.js +16 -2
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
- package/dist/features/composites/react/CompositeView.js +6 -1
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +116 -0
- package/dist/features/composites/react/DerivationBadge.js.map +1 -0
- package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
- package/dist/features/composites/react/ReferenceView.d.ts +11 -0
- package/dist/features/composites/react/ReferenceView.js +115 -0
- package/dist/features/composites/react/ReferenceView.js.map +1 -0
- package/dist/features/composites/react/SettingsEditingTab.js +2 -2
- package/dist/features/composites/react.d.ts +2 -1
- package/dist/features/composites/react.js +7 -3
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +16 -0
- package/dist/features/composites/reference-ai.js.map +1 -0
- package/dist/features/composites/reference-label.d.ts +19 -0
- package/dist/features/composites/reference-label.js +58 -0
- package/dist/features/composites/reference-label.js.map +1 -0
- package/dist/features/composites/reference-suggestion.d.ts +10 -0
- package/dist/features/composites/reference-suggestion.js +41 -0
- package/dist/features/composites/reference-suggestion.js.map +1 -0
- package/dist/features/composites/reference-text.d.ts +18 -0
- package/dist/features/composites/reference-text.js +89 -0
- package/dist/features/composites/reference-text.js.map +1 -0
- package/dist/features/composites/reference.d.ts +44 -0
- package/dist/features/composites/reference.js +148 -0
- package/dist/features/composites/reference.js.map +1 -0
- package/dist/features/composites/reveal-source.d.ts +32 -0
- package/dist/features/composites/reveal-source.js +89 -0
- package/dist/features/composites/reveal-source.js.map +1 -0
- package/dist/features/composites/rows.d.ts +21 -2
- package/dist/features/composites/rows.js +63 -9
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +9 -3
- package/dist/features/composites/schema.js +11 -4
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/table-model.js +12 -21
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/vue.d.ts +3 -2
- package/dist/features/composites/vue.js +8 -4
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/media/assets.d.ts +2 -0
- package/dist/features/media/assets.js +3 -2
- package/dist/features/media/assets.js.map +1 -1
- package/dist/features/media/components/FileView.js +13 -4
- package/dist/features/media/components/FileView.js.map +1 -1
- package/dist/features/media/feature.d.ts +3 -3
- package/dist/features/media/feature.js +21 -28
- package/dist/features/media/feature.js.map +1 -1
- package/dist/features/media/file-import.js +2 -2
- package/dist/features/media/file-import.js.map +1 -1
- package/dist/features/media/index.d.ts +2 -2
- package/dist/features/media/index.js +2 -2
- package/dist/features/media/react/FileView.js +19 -2
- package/dist/features/media/react/FileView.js.map +1 -1
- package/dist/features/media/schema.d.ts +8 -0
- package/dist/features/media/schema.js +126 -11
- package/dist/features/media/schema.js.map +1 -1
- package/dist/features/media/upload.d.ts +16 -14
- package/dist/features/media/upload.js +13 -19
- package/dist/features/media/upload.js.map +1 -1
- package/dist/features/mentions/index.d.ts +4 -3
- package/dist/features/mentions/index.js +4 -1
- package/dist/features/mentions/index.js.map +1 -1
- package/dist/features/mentions/mention-text.d.ts +1 -1
- package/dist/features/mentions/mention-text.js.map +1 -1
- package/dist/features/mentions/mention.d.ts +0 -6
- package/dist/features/mentions/mention.js.map +1 -1
- package/dist/features/mentions/metadata-defaults.d.ts +2 -2
- package/dist/features/mentions/metadata-defaults.js +3 -9
- package/dist/features/mentions/metadata-defaults.js.map +1 -1
- package/dist/features/mentions/schema.d.ts +2 -1
- package/dist/features/mentions/schema.js.map +1 -1
- package/dist/features/tables/feature.d.ts +2 -1
- package/dist/features/tables/feature.js +90 -70
- package/dist/features/tables/feature.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.js +2 -0
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/index.d.ts +2 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/schema.d.ts +2 -6
- package/dist/features/themes/schema.js.map +1 -1
- package/dist/features/themes/theme-runtime.d.ts +1 -1
- package/dist/features/themes/theme-runtime.js +4 -2
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +48 -28
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/feature.js +21 -19
- package/dist/features/transcript/feature.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.d.ts +2 -0
- package/dist/features/transcript/segment-node.js +35 -7
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/i18n/de/composites.js +91 -1
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/integrations.js +49 -8
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/media.js +0 -1
- package/dist/i18n/de/media.js.map +1 -1
- package/dist/i18n/de/palette.js +22 -0
- package/dist/i18n/de/palette.js.map +1 -0
- package/dist/i18n/de/tables.js +0 -1
- package/dist/i18n/de/tables.js.map +1 -1
- package/dist/i18n/de/transcript.js +2 -1
- package/dist/i18n/de/transcript.js.map +1 -1
- package/dist/i18n/de/tree.js +3 -0
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +157 -11
- package/dist/i18n/de.js +3 -1
- package/dist/i18n/de.js.map +1 -1
- package/dist/i18n/en/composites.js +89 -1
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +49 -8
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/media.js +0 -1
- package/dist/i18n/en/media.js.map +1 -1
- package/dist/i18n/en/palette.js +22 -0
- package/dist/i18n/en/palette.js.map +1 -0
- package/dist/i18n/en/tables.js +0 -1
- package/dist/i18n/en/tables.js.map +1 -1
- package/dist/i18n/en/transcript.js +2 -1
- package/dist/i18n/en/transcript.js.map +1 -1
- package/dist/i18n/en/tree.js +3 -0
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/i18n/en.js +3 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
- package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
- package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
- package/dist/integrations/composite-ai/composite-fill.js +97 -56
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
- package/dist/integrations/composite-ai/composite-summary.js +7 -26
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +29 -0
- package/dist/integrations/composite-ai/derive.js +173 -0
- package/dist/integrations/composite-ai/derive.js.map +1 -0
- package/dist/integrations/composite-ai/index.d.ts +11 -7
- package/dist/integrations/composite-ai/index.js +72 -14
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +45 -0
- package/dist/integrations/composite-ai/rendition.js +314 -0
- package/dist/integrations/composite-ai/rendition.js.map +1 -0
- package/dist/integrations/composite-media/index.d.ts +7 -5
- package/dist/integrations/composite-media/index.js +86 -13
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/integrations/transcript-ai/index.d.ts +1 -1
- package/dist/integrations/transcript-ai/index.js +5 -2
- package/dist/integrations/transcript-ai/index.js.map +1 -1
- package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
- package/dist/integrations/transcript-ai/protocol.js +0 -2
- package/dist/integrations/transcript-ai/protocol.js.map +1 -1
- package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
- package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
- package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +6 -5
- package/dist/markdown/MarkdownSurface2.js +3 -6
- package/dist/markdown/MarkdownSurface2.js.map +1 -1
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/source-mode.d.ts +1 -1
- package/dist/nuxt/module.d.ts +1402 -54
- package/dist/nuxt/module.js +6 -49
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/install-context.d.ts +7 -3
- package/dist/nuxt/runtime/install-context.js +14 -8
- package/dist/nuxt/runtime/install-context.js.map +1 -1
- package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +94 -0
- package/dist/presets/compose.js +164 -0
- package/dist/presets/compose.js.map +1 -0
- package/dist/react/AdvancedEditor.d.ts +15 -15
- package/dist/react/AdvancedEditor.js +15 -13
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/EditorCommandPalette.d.ts +13 -0
- package/dist/react/EditorCommandPalette.js +118 -0
- package/dist/react/EditorCommandPalette.js.map +1 -0
- package/dist/react/EditorSettingsModal.d.ts +5 -5
- package/dist/react/EditorSettingsModal.js +7 -4
- package/dist/react/EditorSettingsModal.js.map +1 -1
- package/dist/react/EditorSettingsPanel.d.ts +7 -7
- package/dist/react/EditorSettingsPanel.js +8 -5
- package/dist/react/EditorSettingsPanel.js.map +1 -1
- package/dist/react/EditorSurface.d.ts +7 -7
- package/dist/react/EditorSurface.js +10 -6
- package/dist/react/EditorSurface.js.map +1 -1
- package/dist/react/EditorToolbar.d.ts +4 -6
- package/dist/react/EditorToolbar.js +29 -37
- package/dist/react/EditorToolbar.js.map +1 -1
- package/dist/react/SimpleEditor.d.ts +22 -23
- package/dist/react/SimpleEditor.js +21 -7
- package/dist/react/SimpleEditor.js.map +1 -1
- package/dist/react/advanced.d.ts +4 -3
- package/dist/react/advanced.js +2 -2
- package/dist/react/compose.d.ts +20 -0
- package/dist/react/compose.js +49 -0
- package/dist/react/compose.js.map +1 -0
- package/dist/react/composed-surface.d.ts +39 -0
- package/dist/react/composed-surface.js +71 -0
- package/dist/react/composed-surface.js.map +1 -0
- package/dist/react/context.js +6 -2
- package/dist/react/context.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/key-labels.js +15 -0
- package/dist/react/key-labels.js.map +1 -0
- package/dist/react/settings.d.ts +1 -1
- package/dist/react/simple.d.ts +2 -2
- package/dist/react/ui/command.js +36 -1
- package/dist/react/ui/command.js.map +1 -1
- package/dist/schema/advanced.d.ts +6 -6
- package/dist/schema/advanced.js +26 -29
- package/dist/schema/advanced.js.map +1 -1
- package/dist/server/ai.d.ts +5 -16
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +9 -0
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +13 -13
- package/dist/server/collab.js +34 -18
- package/dist/server/collab.js.map +1 -1
- package/dist/server/crossref.js +78 -0
- package/dist/server/crossref.js.map +1 -0
- package/dist/server/errors.d.ts +1 -1
- package/dist/server/errors.js +1 -1
- package/dist/server/errors.js.map +1 -1
- package/dist/server/extract.js +308 -0
- package/dist/server/extract.js.map +1 -0
- package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
- package/dist/server/h3.js.map +1 -0
- package/dist/server/handlers/ai.d.ts +30 -9
- package/dist/server/handlers/ai.js +170 -36
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +12 -5
- package/dist/server/handlers/context.js +10 -4
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +19 -13
- package/dist/server/handlers/editor.js +49 -38
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/index.d.ts +4 -4
- package/dist/server/handlers/index.js +4 -4
- package/dist/server/host.d.ts +16 -25
- package/dist/server/host.js +58 -41
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +6 -4
- package/dist/server/index.js +3 -2
- package/dist/server/pdf.js +97 -0
- package/dist/server/pdf.js.map +1 -0
- package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
- package/dist/server/ports.js +29 -0
- package/dist/server/ports.js.map +1 -0
- package/dist/server/routes.js +144 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js.map +1 -1
- package/dist/styles/composites.css +25 -0
- package/dist/tree/DocumentTree.js +56 -29
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +23 -0
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +2 -2
- package/dist/tree/tree-items.js +1 -1
- package/dist/vue/AdvancedEditor.js +30 -9
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +28 -8
- package/dist/vue/SimpleEditor.js +62 -16
- package/dist/vue/SimpleEditor.js.map +1 -1
- package/dist/vue/SimpleEditor.vue.d.ts +37 -7
- package/dist/vue/advanced.d.ts +3 -2
- package/dist/vue/advanced.js +2 -2
- package/dist/vue/components/EditorCommandPalette.js +91 -0
- package/dist/vue/components/EditorCommandPalette.js.map +1 -0
- package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
- package/dist/vue/components/EditorSettingsModal.js +10 -6
- package/dist/vue/components/EditorSettingsModal.js.map +1 -1
- package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
- package/dist/vue/components/EditorSettingsPanel.js +10 -6
- package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
- package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
- package/dist/vue/components/EditorSurface.js +11 -6
- package/dist/vue/components/EditorSurface.js.map +1 -1
- package/dist/vue/components/EditorSurface.vue.d.ts +7 -7
- package/dist/vue/components/EditorToolbar.js +41 -49
- package/dist/vue/components/EditorToolbar.js.map +1 -1
- package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
- package/dist/vue/compose.d.ts +17 -0
- package/dist/vue/compose.js +51 -0
- package/dist/vue/compose.js.map +1 -0
- package/dist/vue/context-key.d.ts +6 -0
- package/dist/vue/context-key.js +6 -0
- package/dist/vue/context-key.js.map +1 -0
- package/dist/vue/context.d.ts +8 -6
- package/dist/vue/context.js +6 -5
- package/dist/vue/context.js.map +1 -1
- package/dist/vue/index.d.ts +10 -8
- package/dist/vue/index.js +10 -8
- package/dist/vue/kit/index.d.ts +2 -2
- package/dist/vue/kit/nuxt-ui.js +23 -0
- package/dist/vue/kit/nuxt-ui.js.map +1 -1
- package/dist/vue/kit/types.d.ts +40 -1
- package/package.json +30 -16
- package/dist/adapters/comments/client.d.ts +0 -64
- package/dist/adapters/comments/client.js.map +0 -1
- package/dist/adapters/routes.js.map +0 -1
- package/dist/core/toolbar.d.ts +0 -74
- package/dist/core/toolbar.js +0 -45
- package/dist/core/toolbar.js.map +0 -1
- package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
- package/dist/integrations/composite-ai/document-transcribe.js +0 -89
- package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
- package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
- package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
- package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
- package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
- package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
- package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
- package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
- package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
- package/dist/presets/advanced.d.ts +0 -33
- package/dist/presets/advanced.js +0 -50
- package/dist/presets/advanced.js.map +0 -1
- package/dist/presets/simple.d.ts +0 -9
- package/dist/presets/simple.js +0 -12
- package/dist/presets/simple.js.map +0 -1
- package/dist/react/advanced-preset.d.ts +0 -11
- package/dist/react/advanced-preset.js +0 -31
- package/dist/react/advanced-preset.js.map +0 -1
- package/dist/vue/advanced-preset.d.ts +0 -13
- package/dist/vue/advanced-preset.js +0 -33
- package/dist/vue/advanced-preset.js.map +0 -1
- package/docs/extending.md +0 -538
- package/docs/integration.md +0 -632
- package/docs/llms.md +0 -383
- package/docs/usage.md +0 -1076
|
@@ -13,6 +13,6 @@ export declare function CompositeFieldEditor({ editor, row, field, disabled, siz
|
|
|
13
13
|
field: CompositeMetaField;
|
|
14
14
|
disabled?: boolean;
|
|
15
15
|
size?: 'xs' | 'sm' | 'md';
|
|
16
|
-
}): import("react").JSX.Element;
|
|
16
|
+
}): import("react").JSX.Element | null;
|
|
17
17
|
//#endregion
|
|
18
18
|
//# sourceMappingURL=CompositeFieldEditor.d.ts.map
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { useEditorI18n } from "../../../react/use-editor-i18n.js";
|
|
2
2
|
import { cn } from "../../../react/ui/utils.js";
|
|
3
|
-
import { setCompositeMetaField } from "../rows.js";
|
|
4
3
|
import { Input } from "../../../react/ui/input.js";
|
|
5
4
|
import { Textarea } from "../../../react/ui/textarea.js";
|
|
6
5
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
|
|
6
|
+
import { compositeOfRow, setCompositeMetaField } from "../rows.js";
|
|
7
7
|
import { metaText } from "../meta-display.js";
|
|
8
|
+
import { BibliographyEditor } from "./BibliographyEditor.js";
|
|
9
|
+
import { DerivationBadge } from "./DerivationBadge.js";
|
|
10
|
+
import { ReferenceFieldSelect } from "./ReferenceFieldSelect.js";
|
|
8
11
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
9
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
13
|
//#region src/features/composites/react/CompositeFieldEditor.tsx
|
|
@@ -97,6 +100,26 @@ function CompositeFieldEditor({ editor, row, field, disabled, size = "sm" }) {
|
|
|
97
100
|
children: option.label
|
|
98
101
|
}, option.value)) })]
|
|
99
102
|
});
|
|
103
|
+
if (field.type === "reference") return /* @__PURE__ */ jsx(ReferenceFieldSelect, {
|
|
104
|
+
editor,
|
|
105
|
+
row,
|
|
106
|
+
field,
|
|
107
|
+
disabled,
|
|
108
|
+
size
|
|
109
|
+
});
|
|
110
|
+
if (field.type === "bibliography") return /* @__PURE__ */ jsx(BibliographyEditor, {
|
|
111
|
+
editor,
|
|
112
|
+
row,
|
|
113
|
+
field,
|
|
114
|
+
disabled
|
|
115
|
+
});
|
|
116
|
+
if (field.type === "derivation") {
|
|
117
|
+
const derived = compositeOfRow(editor.state.doc, row)?.node;
|
|
118
|
+
return derived ? /* @__PURE__ */ jsx(DerivationBadge, {
|
|
119
|
+
editor,
|
|
120
|
+
node: derived
|
|
121
|
+
}) : null;
|
|
122
|
+
}
|
|
100
123
|
if (field.type === "textarea") return /* @__PURE__ */ jsx(Textarea, {
|
|
101
124
|
value: draft,
|
|
102
125
|
"aria-label": field.label,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositeFieldEditor.js","names":[],"sources":["../../../../src/features/composites/react/CompositeFieldEditor.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { metaText } from '../meta-display'\nimport { type CompositeRow, setCompositeMetaField } from '../rows'\n\n/** Radix Select has no empty-string value: an option with an empty value travels as this sentinel. */\nconst EMPTY = '__empty__'\n\nconst INPUT_SIZE = {\n xs: 'h-6 px-2 text-xs md:text-xs',\n sm: 'h-7 px-2.5 text-sm md:text-sm',\n md: '',\n}\nconst TEXTAREA_SIZE = {\n xs: 'px-2 py-1 text-xs md:text-xs',\n sm: 'px-2.5 py-1.5 text-sm md:text-sm',\n md: '',\n}\nconst SELECT_SIZE = {\n xs: 'data-[size=sm]:h-6 text-xs',\n sm: 'data-[size=sm]:h-7',\n md: '',\n}\n\n/**\n * One meta field of a Baustein as an input that writes through `setCompositeMetaField`. Text-like inputs keep a local\n * draft and commit after typing pauses, on blur and on unmount, so the one-frame-late re-read of the rows never\n * overwrites what is being typed.\n */\nexport function CompositeFieldEditor({ editor, row, field, disabled, size = 'sm' }: {\n editor: Editor\n row: CompositeRow\n field: CompositeMetaField\n disabled?: boolean\n size?: 'xs' | 'sm' | 'md'\n}) {\n const { t } = useEditorI18n()\n const stored = metaText(row, field)\n const [draft, setDraft] = useState(stored)\n const draftRef = useRef(draft)\n const typing = useRef(false)\n const dirty = useRef(false)\n const timer = useRef<number | undefined>(undefined)\n // The latest props for the debounced commit and the flush on unmount; updated after every render, so the cleanup of a\n // changed `row.key` still sees the previous row.\n const target = useRef({ editor, row, field })\n useEffect(() => {\n target.current = { editor, row, field }\n })\n\n useEffect(() => {\n if (!typing.current && !dirty.current) {\n draftRef.current = stored\n setDraft(stored)\n }\n }, [stored, row.key])\n\n const commit = useCallback(() => {\n clearTimeout(timer.current)\n if (!dirty.current) return\n dirty.current = false\n const current = target.current\n if (!current.editor.isDestroyed) setCompositeMetaField(current.editor, current.row, current.field.key, draftRef.current)\n }, [])\n\n // Flush on unmount and when the field is bound to another row.\n useEffect(() => commit, [commit, editor, row.key, field.key])\n\n function onInput(value: string) {\n draftRef.current = value\n setDraft(value)\n dirty.current = true\n clearTimeout(timer.current)\n timer.current = window.setTimeout(commit, 400)\n }\n\n function onBlur() {\n typing.current = false\n commit()\n }\n\n function onChoice(value: string) {\n setCompositeMetaField(editor, row, field.key, value === EMPTY ? '' : value)\n }\n\n if (field.type === 'select') {\n return (\n <Select value={stored} onValueChange={onChoice} disabled={disabled}>\n <SelectTrigger size=\"sm\" className={cn('w-full', SELECT_SIZE[size])} aria-label={field.label}>\n <SelectValue placeholder={t('composites.field.choose', { field: field.label })} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => (\n <SelectItem key={option.value} value={option.value || EMPTY}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n }\n\n if (field.type === 'textarea') {\n return (\n <Textarea\n value={draft}\n aria-label={field.label}\n disabled={disabled}\n rows={2}\n className={cn('max-h-[8.5rem] min-h-0 w-full', TEXTAREA_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onChange={event => onInput(event.target.value)}\n />\n )\n }\n\n return (\n <Input\n value={draft}\n type={field.type}\n aria-label={field.label}\n disabled={disabled}\n className={cn('w-full', INPUT_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(event.target.value)}\n />\n )\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CompositeFieldEditor.js","names":[],"sources":["../../../../src/features/composites/react/CompositeFieldEditor.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { metaText } from '../meta-display'\nimport { compositeOfRow, type CompositeRow, setCompositeMetaField } from '../rows'\nimport { BibliographyEditor } from './BibliographyEditor'\nimport { DerivationBadge } from './DerivationBadge'\nimport { ReferenceFieldSelect } from './ReferenceFieldSelect'\n\n/** Radix Select has no empty-string value: an option with an empty value travels as this sentinel. */\nconst EMPTY = '__empty__'\n\nconst INPUT_SIZE = {\n xs: 'h-6 px-2 text-xs md:text-xs',\n sm: 'h-7 px-2.5 text-sm md:text-sm',\n md: '',\n}\nconst TEXTAREA_SIZE = {\n xs: 'px-2 py-1 text-xs md:text-xs',\n sm: 'px-2.5 py-1.5 text-sm md:text-sm',\n md: '',\n}\nconst SELECT_SIZE = {\n xs: 'data-[size=sm]:h-6 text-xs',\n sm: 'data-[size=sm]:h-7',\n md: '',\n}\n\n/**\n * One meta field of a Baustein as an input that writes through `setCompositeMetaField`. Text-like inputs keep a local\n * draft and commit after typing pauses, on blur and on unmount, so the one-frame-late re-read of the rows never\n * overwrites what is being typed.\n */\nexport function CompositeFieldEditor({ editor, row, field, disabled, size = 'sm' }: {\n editor: Editor\n row: CompositeRow\n field: CompositeMetaField\n disabled?: boolean\n size?: 'xs' | 'sm' | 'md'\n}) {\n const { t } = useEditorI18n()\n const stored = metaText(row, field)\n const [draft, setDraft] = useState(stored)\n const draftRef = useRef(draft)\n const typing = useRef(false)\n const dirty = useRef(false)\n const timer = useRef<number | undefined>(undefined)\n // The latest props for the debounced commit and the flush on unmount; updated after every render, so the cleanup of a\n // changed `row.key` still sees the previous row.\n const target = useRef({ editor, row, field })\n useEffect(() => {\n target.current = { editor, row, field }\n })\n\n useEffect(() => {\n if (!typing.current && !dirty.current) {\n draftRef.current = stored\n setDraft(stored)\n }\n }, [stored, row.key])\n\n const commit = useCallback(() => {\n clearTimeout(timer.current)\n if (!dirty.current) return\n dirty.current = false\n const current = target.current\n if (!current.editor.isDestroyed) setCompositeMetaField(current.editor, current.row, current.field.key, draftRef.current)\n }, [])\n\n // Flush on unmount and when the field is bound to another row.\n useEffect(() => commit, [commit, editor, row.key, field.key])\n\n function onInput(value: string) {\n draftRef.current = value\n setDraft(value)\n dirty.current = true\n clearTimeout(timer.current)\n timer.current = window.setTimeout(commit, 400)\n }\n\n function onBlur() {\n typing.current = false\n commit()\n }\n\n function onChoice(value: string) {\n setCompositeMetaField(editor, row, field.key, value === EMPTY ? '' : value)\n }\n\n if (field.type === 'select') {\n return (\n <Select value={stored} onValueChange={onChoice} disabled={disabled}>\n <SelectTrigger size=\"sm\" className={cn('w-full', SELECT_SIZE[size])} aria-label={field.label}>\n <SelectValue placeholder={t('composites.field.choose', { field: field.label })} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => (\n <SelectItem key={option.value} value={option.value || EMPTY}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n }\n\n if (field.type === 'reference') {\n return <ReferenceFieldSelect editor={editor} row={row} field={field} disabled={disabled} size={size} />\n }\n\n if (field.type === 'bibliography') {\n return <BibliographyEditor editor={editor} row={row} field={field} disabled={disabled} />\n }\n\n if (field.type === 'derivation') {\n const derived = compositeOfRow(editor.state.doc, row)?.node\n return derived ? <DerivationBadge editor={editor} node={derived} /> : null\n }\n\n if (field.type === 'textarea') {\n return (\n <Textarea\n value={draft}\n aria-label={field.label}\n disabled={disabled}\n rows={2}\n className={cn('max-h-[8.5rem] min-h-0 w-full', TEXTAREA_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onChange={event => onInput(event.target.value)}\n />\n )\n }\n\n return (\n <Input\n value={draft}\n type={field.type}\n aria-label={field.label}\n disabled={disabled}\n className={cn('w-full', INPUT_SIZE[size])}\n onFocus={() => {\n typing.current = true\n }}\n onBlur={onBlur}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(event.target.value)}\n />\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { normalizeTagName } from "../../../core/tag-name.js";
|
|
1
2
|
import { useEditorI18n } from "../../../react/use-editor-i18n.js";
|
|
2
3
|
import { cn } from "../../../react/ui/utils.js";
|
|
3
4
|
import { Icon } from "../../../react/Icon.js";
|
|
4
|
-
import { normalizeTagName } from "../../../core/tag-name.js";
|
|
5
|
-
import { compositeFieldText } from "../inspector-model.js";
|
|
6
|
-
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../react/ui/popover.js";
|
|
7
5
|
import { Input } from "../../../react/ui/input.js";
|
|
8
6
|
import { Textarea } from "../../../react/ui/textarea.js";
|
|
7
|
+
import { Command, CommandInput, CommandItem, CommandList } from "../../../react/ui/command.js";
|
|
8
|
+
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../react/ui/popover.js";
|
|
9
9
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
|
|
10
10
|
import { Label } from "../../../react/ui/label.js";
|
|
11
11
|
import { Badge } from "../../../react/ui/badge.js";
|
|
12
|
-
import {
|
|
12
|
+
import { CompositeFieldEditor } from "./CompositeFieldEditor.js";
|
|
13
|
+
import { compositeFieldText, isStructuredField } from "../inspector-model.js";
|
|
13
14
|
import { useCompositeInspector } from "./use-composite-inspector.js";
|
|
14
15
|
import { useEffect, useId, useState } from "react";
|
|
15
16
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -299,7 +300,12 @@ function CompositeInspector({ editor, documentFocused, document, className }) {
|
|
|
299
300
|
}),
|
|
300
301
|
focused.fields.map((field) => /* @__PURE__ */ jsx(FormField, {
|
|
301
302
|
label: field.label,
|
|
302
|
-
children: field
|
|
303
|
+
children: isStructuredField(field) ? editor && /* @__PURE__ */ jsx(CompositeFieldEditor, {
|
|
304
|
+
editor,
|
|
305
|
+
row: focused,
|
|
306
|
+
field,
|
|
307
|
+
disabled: !editable
|
|
308
|
+
}) : field.type === "select" ? /* @__PURE__ */ jsxs(Select, {
|
|
303
309
|
value: compositeFieldText(focused, field),
|
|
304
310
|
onValueChange: (value) => inspector.setField(field, value),
|
|
305
311
|
disabled: !editable,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositeInspector.js","names":[],"sources":["../../../../src/features/composites/react/CompositeInspector.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type CSSProperties, type ReactNode, useEffect, useId, useState } from 'react'\nimport { normalizeTagName } from '../../../core/tag-name'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Command, CommandInput, CommandItem, CommandList } from '../../../react/ui/command'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '../../../react/ui/popover'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { compositeFieldText } from '../inspector-model'\nimport { useCompositeInspector } from './use-composite-inspector'\n\nconst HEX_COLOR = /^#[0-9a-f]{3,8}$/i\n// Same tint as the chip in the document (`--mention-color`), only invalid colors fall back to the primary color.\nconst mentionStyle = (color: string | null) => ({ '--mention-color': color && HEX_COLOR.test(color) ? color : 'var(--sk-primary)' }) as CSSProperties\n\n/** A label (+ help) above its control; the counterpart of Nuxt UI's `UFormField` (size `sm`). */\nfunction FormField({ label, help, children }: { label: string, help?: string, children: ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Label className=\"text-xs font-medium text-foreground\">{label}</Label>\n {children}\n {help && <p className=\"text-xs text-muted-foreground\">{help}</p>}\n </div>\n )\n}\n\n/**\n * A meta field input that writes through on every change like the Vue `UInput`/`UTextarea` bound to the row. The\n * document is re-read asynchronously (once per frame), so a purely controlled input would snap back while typing:\n * it keeps the typed value locally and follows the document whenever the document's value changes.\n */\nfunction MetaFieldInput({ field, value, readOnly, onChange }: {\n field: CompositeMetaField\n value: string\n readOnly: boolean\n onChange: (value: string) => void\n}) {\n const [local, setLocal] = useState(value)\n useEffect(() => setLocal(value), [value])\n const set = (next: string) => {\n setLocal(next)\n onChange(next)\n }\n return field.type === 'textarea'\n ? (\n <Textarea\n value={local}\n aria-label={field.label}\n rows={2}\n className=\"max-h-40 min-h-12 w-full resize-none overflow-y-auto text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n : (\n <Input\n value={local}\n type={field.type}\n aria-label={field.label}\n className=\"h-7 w-full text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n}\n\n/**\n * Side panel with the metadata of the document *or* of the Baustein under the caret — one at a time — connected to\n * `editor`. Fills the height of its container and scrolls on its own; the width comes from the host. Open/close is\n * the host's business. The `document` prop carries host-provided document facts (title, folder, dates, presence) at\n * the top of the „Dokument“ section: render them as a `<dl>` with the same grid as below to look native.\n *\n * The „Baustein“ section shows while the caret is in a Baustein of the editor; the „Dokument“ section shows before\n * the editor was ever focused, while the caret is in editor text outside any Baustein, and while `documentFocused`.\n * `documentFocused`: the host's document-level input (its title field) has the focus. While it is true the panel\n * shows the „Dokument“ section and keeps showing it after the input blurs, until the caret returns to the editor.\n */\nexport function CompositeInspector({ editor, documentFocused, document, className }: {\n editor?: Editor\n documentFocused?: boolean\n /** Document facts known to the host only, rendered above the facts derived from the editor. */\n document?: ReactNode\n className?: string\n}) {\n const { t } = useEditorI18n()\n const { state, inspector } = useCompositeInspector(editor, documentFocused)\n const { section, editable, draft, searchTerm: term, tagItems, kindOptions, summarized, hasSummary, rows, tags, kinds, mentions, focused } = state\n const [tagsOpen, setTagsOpen] = useState(false)\n const uid = useId()\n\n return (\n <aside className={cn('flex h-full min-h-0 flex-col overflow-y-auto text-sm', className)} aria-label={t('composites.inspector.label')}>\n {section === 'document'\n ? (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-document`}>\n <h2 id={`${uid}-document`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.document')}\n </h2>\n <div className=\"flex flex-col gap-y-2\">\n {document}\n <dl className=\"grid grid-cols-[6.5rem_minmax(0,1fr)] items-start gap-x-3 gap-y-2\">\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.composites')}\n </dt>\n {kinds.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-col gap-y-1\">\n {kinds.map(kind => (\n <span key={kind.id} className=\"flex min-h-6 min-w-0 items-center gap-2\">\n <Icon name={kind.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate text-foreground\">{kind.label}</span>\n <span className=\"text-muted-foreground tabular-nums\">{kind.count}</span>\n </span>\n ))}\n <span className=\"min-h-6 leading-6 text-muted-foreground tabular-nums\">\n {t('composites.inspector.summarized', { n: summarized, total: rows.length })}\n </span>\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.tags.label')}\n </dt>\n {tags.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {tags.map(tag => <Badge key={tag} variant=\"secondary\" className=\"max-w-full\">{`#${tag}`}</Badge>)}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.mentions')}\n </dt>\n {mentions.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {mentions.map(mention => (\n <span\n key={mention.id}\n className=\"inline-flex max-w-full items-center gap-1.5 truncate rounded-sm px-1.5 py-0.5 text-xs font-medium text-foreground\"\n style={{ ...mentionStyle(mention.color), background: 'color-mix(in oklab, var(--mention-color) 15%, transparent)' }}\n >\n <span className=\"size-1.5 shrink-0 rounded-full\" style={{ background: 'var(--mention-color)' }} />\n <span className=\"truncate\">@{mention.label}</span>\n </span>\n ))}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n </dl>\n </div>\n </section>\n )\n : focused && (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-composite`}>\n <h2 id={`${uid}-composite`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.composite')}\n </h2>\n\n <div key={focused.key} className=\"flex flex-col gap-3\">\n <FormField label={t('composites.inspector.kind')}>\n <Select value={focused.kind} onValueChange={inspector.setKind} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={t('composites.kind.select')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kindOptions.map(item => (\n <SelectItem key={item.value} value={item.value}>\n <Icon name={item.icon} />\n {item.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('composites.inspector.title')} help={editable ? t('composites.inspector.titleHelp') : undefined}>\n <p className={cn('min-h-6 truncate leading-6', focused.title ? 'text-foreground' : 'text-muted-foreground/70')} title={focused.title}>\n {focused.title || t('composites.inspector.untitled')}\n </p>\n </FormField>\n\n <FormField\n label={t('composites.inspector.description')}\n help={focused.descriptionTextOnly ? undefined : t('composites.inspector.descriptionHelp')}\n >\n <Textarea\n value={draft}\n rows={3}\n className=\"max-h-52 min-h-[4.5rem] w-full resize-none overflow-y-auto text-sm md:text-sm\"\n placeholder={t('composites.inspector.description')}\n aria-label={t('composites.inspector.description')}\n readOnly={!editable || !focused.descriptionTextOnly}\n onChange={event => inspector.inputDescription(event.target.value)}\n onBlur={inspector.blurDescription}\n />\n </FormField>\n\n <FormField label={t('composites.tags.label')}>\n <Popover\n open={tagsOpen}\n onOpenChange={(isOpen) => {\n setTagsOpen(isOpen)\n if (isOpen) inspector.searchTags()\n }}\n >\n <PopoverAnchor asChild>\n <div className={cn('flex min-h-7 w-full flex-wrap items-center gap-1 rounded-lg border border-input px-2 py-1 dark:bg-input/30', !editable && 'opacity-50')}>\n <Icon name=\"i-lucide-hash\" className=\"size-3.5 text-muted-foreground\" />\n {focused.tags.map(tag => (\n <Badge key={tag} variant=\"secondary\" className=\"max-w-full gap-0.5 pr-1\">\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"inline-flex cursor-pointer items-center rounded-full outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n aria-label={t('composites.tag.remove', { tag })}\n disabled={!editable}\n onClick={() => inspector.setTags(focused.tags.filter(item => item !== tag))}\n >\n <Icon name=\"i-lucide-x\" className=\"size-3\" />\n </button>\n </Badge>\n ))}\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n role=\"combobox\"\n aria-expanded={tagsOpen}\n aria-label={t('composites.tags.label')}\n disabled={!editable}\n className=\"min-w-12 flex-1 cursor-text self-stretch rounded text-left text-sm text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n >\n {focused.tags.length ? '' : t('composites.tags.label')}\n </button>\n </PopoverTrigger>\n </div>\n </PopoverAnchor>\n <PopoverContent align=\"start\" className=\"w-64 gap-0 p-0\">\n {/* `shouldFilter` off: the list is the metadata source's answer to the search term. */}\n <Command shouldFilter={false}>\n <CommandInput\n value={term}\n onValueChange={inspector.setSearchTerm}\n placeholder={t('composites.tags.label')}\n aria-label={t('composites.tags.label')}\n onKeyDown={(event) => {\n if (event.key === 'Backspace' && !term && focused.tags.length) inspector.setTags(focused.tags.slice(0, -1))\n }}\n />\n <CommandList>\n {tagItems.map((tag) => {\n const selected = focused.tags.includes(tag)\n return (\n <CommandItem\n key={tag}\n value={tag}\n data-checked={selected}\n onSelect={() => inspector.setTags(selected ? focused.tags.filter(item => item !== tag) : [...focused.tags, tag])}\n >\n {tag}\n </CommandItem>\n )\n })}\n {term.trim() && (\n <CommandItem value={`__create__:${term}`} onSelect={() => inspector.createTag(term)}>\n <Icon name=\"i-lucide-plus\" />\n {t('composites.tags.create', { tag: normalizeTagName(term) || term })}\n </CommandItem>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </FormField>\n\n {focused.fields.map(field => (\n <FormField key={field.key} label={field.label}>\n {field.type === 'select'\n ? (\n <Select value={compositeFieldText(focused, field)} onValueChange={value => inspector.setField(field, value)} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={field.label}>\n <SelectValue placeholder=\"–\" />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}\n </SelectContent>\n </Select>\n )\n : (\n <MetaFieldInput\n field={field}\n value={compositeFieldText(focused, field)}\n readOnly={!editable}\n onChange={value => inspector.setField(field, value)}\n />\n )}\n </FormField>\n ))}\n\n <div className=\"flex items-center gap-2 border-t border-border pt-3\">\n <Icon name=\"i-lucide-sparkles\" className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">{t('composites.inspector.aiStatus')}</span>\n <span className={cn('ml-auto inline-flex items-center gap-1.5', hasSummary ? 'text-foreground' : 'text-muted-foreground/70')}>\n <span className={cn('size-2 rounded-full', hasSummary ? 'bg-(--sk-success)' : 'bg-border')} />\n {hasSummary ? t('composites.inspector.summaryPresent') : t('composites.inspector.summaryMissing')}\n </span>\n </div>\n </div>\n </section>\n )}\n </aside>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CompositeInspector.js","names":[],"sources":["../../../../src/features/composites/react/CompositeInspector.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type CSSProperties, type ReactNode, useEffect, useId, useState } from 'react'\nimport { normalizeTagName } from '../../../core/tag-name'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Command, CommandInput, CommandItem, CommandList } from '../../../react/ui/command'\nimport { Input } from '../../../react/ui/input'\nimport { Label } from '../../../react/ui/label'\nimport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '../../../react/ui/popover'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeMetaField } from '../kinds'\nimport { compositeFieldText, isStructuredField } from '../inspector-model'\nimport { CompositeFieldEditor } from './CompositeFieldEditor'\nimport { useCompositeInspector } from './use-composite-inspector'\n\nconst HEX_COLOR = /^#[0-9a-f]{3,8}$/i\n// Same tint as the chip in the document (`--mention-color`), only invalid colors fall back to the primary color.\nconst mentionStyle = (color: string | null) => ({ '--mention-color': color && HEX_COLOR.test(color) ? color : 'var(--sk-primary)' }) as CSSProperties\n\n/** A label (+ help) above its control; the counterpart of Nuxt UI's `UFormField` (size `sm`). */\nfunction FormField({ label, help, children }: { label: string, help?: string, children: ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Label className=\"text-xs font-medium text-foreground\">{label}</Label>\n {children}\n {help && <p className=\"text-xs text-muted-foreground\">{help}</p>}\n </div>\n )\n}\n\n/**\n * A meta field input that writes through on every change like the Vue `UInput`/`UTextarea` bound to the row. The\n * document is re-read asynchronously (once per frame), so a purely controlled input would snap back while typing:\n * it keeps the typed value locally and follows the document whenever the document's value changes.\n */\nfunction MetaFieldInput({ field, value, readOnly, onChange }: {\n field: CompositeMetaField\n value: string\n readOnly: boolean\n onChange: (value: string) => void\n}) {\n const [local, setLocal] = useState(value)\n useEffect(() => setLocal(value), [value])\n const set = (next: string) => {\n setLocal(next)\n onChange(next)\n }\n return field.type === 'textarea'\n ? (\n <Textarea\n value={local}\n aria-label={field.label}\n rows={2}\n className=\"max-h-40 min-h-12 w-full resize-none overflow-y-auto text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n : (\n <Input\n value={local}\n type={field.type}\n aria-label={field.label}\n className=\"h-7 w-full text-sm md:text-sm\"\n readOnly={readOnly}\n onChange={event => set(event.target.value)}\n />\n )\n}\n\n/**\n * Side panel with the metadata of the document *or* of the Baustein under the caret — one at a time — connected to\n * `editor`. Fills the height of its container and scrolls on its own; the width comes from the host. Open/close is\n * the host's business. The `document` prop carries host-provided document facts (title, folder, dates, presence) at\n * the top of the „Dokument“ section: render them as a `<dl>` with the same grid as below to look native.\n *\n * The „Baustein“ section shows while the caret is in a Baustein of the editor; the „Dokument“ section shows before\n * the editor was ever focused, while the caret is in editor text outside any Baustein, and while `documentFocused`.\n * `documentFocused`: the host's document-level input (its title field) has the focus. While it is true the panel\n * shows the „Dokument“ section and keeps showing it after the input blurs, until the caret returns to the editor.\n */\nexport function CompositeInspector({ editor, documentFocused, document, className }: {\n editor?: Editor\n documentFocused?: boolean\n /** Document facts known to the host only, rendered above the facts derived from the editor. */\n document?: ReactNode\n className?: string\n}) {\n const { t } = useEditorI18n()\n const { state, inspector } = useCompositeInspector(editor, documentFocused)\n const { section, editable, draft, searchTerm: term, tagItems, kindOptions, summarized, hasSummary, rows, tags, kinds, mentions, focused } = state\n const [tagsOpen, setTagsOpen] = useState(false)\n const uid = useId()\n\n return (\n <aside className={cn('flex h-full min-h-0 flex-col overflow-y-auto text-sm', className)} aria-label={t('composites.inspector.label')}>\n {section === 'document'\n ? (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-document`}>\n <h2 id={`${uid}-document`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.document')}\n </h2>\n <div className=\"flex flex-col gap-y-2\">\n {document}\n <dl className=\"grid grid-cols-[6.5rem_minmax(0,1fr)] items-start gap-x-3 gap-y-2\">\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.composites')}\n </dt>\n {kinds.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-col gap-y-1\">\n {kinds.map(kind => (\n <span key={kind.id} className=\"flex min-h-6 min-w-0 items-center gap-2\">\n <Icon name={kind.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate text-foreground\">{kind.label}</span>\n <span className=\"text-muted-foreground tabular-nums\">{kind.count}</span>\n </span>\n ))}\n <span className=\"min-h-6 leading-6 text-muted-foreground tabular-nums\">\n {t('composites.inspector.summarized', { n: summarized, total: rows.length })}\n </span>\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.tags.label')}\n </dt>\n {tags.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {tags.map(tag => <Badge key={tag} variant=\"secondary\" className=\"max-w-full\">{`#${tag}`}</Badge>)}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n\n <dt className=\"min-h-6 leading-6 text-muted-foreground\">\n {t('composites.inspector.mentions')}\n </dt>\n {mentions.length\n ? (\n <dd className=\"m-0 flex min-w-0 flex-wrap items-center gap-1\">\n {mentions.map(mention => (\n <span\n key={mention.id}\n className=\"inline-flex max-w-full items-center gap-1.5 truncate rounded-sm px-1.5 py-0.5 text-xs font-medium text-foreground\"\n style={{ ...mentionStyle(mention.color), background: 'color-mix(in oklab, var(--mention-color) 15%, transparent)' }}\n >\n <span className=\"size-1.5 shrink-0 rounded-full\" style={{ background: 'var(--mention-color)' }} />\n <span className=\"truncate\">@{mention.label}</span>\n </span>\n ))}\n </dd>\n )\n : (\n <dd className=\"m-0 min-h-6 leading-6 text-muted-foreground/70\">\n {t('composites.inspector.none')}\n </dd>\n )}\n </dl>\n </div>\n </section>\n )\n : focused && (\n <section className=\"flex-1 p-4\" aria-labelledby={`${uid}-composite`}>\n <h2 id={`${uid}-composite`} className=\"mb-3 text-sm font-semibold text-foreground\">\n {t('composites.inspector.composite')}\n </h2>\n\n <div key={focused.key} className=\"flex flex-col gap-3\">\n <FormField label={t('composites.inspector.kind')}>\n <Select value={focused.kind} onValueChange={inspector.setKind} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={t('composites.kind.select')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {kindOptions.map(item => (\n <SelectItem key={item.value} value={item.value}>\n <Icon name={item.icon} />\n {item.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </FormField>\n\n <FormField label={t('composites.inspector.title')} help={editable ? t('composites.inspector.titleHelp') : undefined}>\n <p className={cn('min-h-6 truncate leading-6', focused.title ? 'text-foreground' : 'text-muted-foreground/70')} title={focused.title}>\n {focused.title || t('composites.inspector.untitled')}\n </p>\n </FormField>\n\n <FormField\n label={t('composites.inspector.description')}\n help={focused.descriptionTextOnly ? undefined : t('composites.inspector.descriptionHelp')}\n >\n <Textarea\n value={draft}\n rows={3}\n className=\"max-h-52 min-h-[4.5rem] w-full resize-none overflow-y-auto text-sm md:text-sm\"\n placeholder={t('composites.inspector.description')}\n aria-label={t('composites.inspector.description')}\n readOnly={!editable || !focused.descriptionTextOnly}\n onChange={event => inspector.inputDescription(event.target.value)}\n onBlur={inspector.blurDescription}\n />\n </FormField>\n\n <FormField label={t('composites.tags.label')}>\n <Popover\n open={tagsOpen}\n onOpenChange={(isOpen) => {\n setTagsOpen(isOpen)\n if (isOpen) inspector.searchTags()\n }}\n >\n <PopoverAnchor asChild>\n <div className={cn('flex min-h-7 w-full flex-wrap items-center gap-1 rounded-lg border border-input px-2 py-1 dark:bg-input/30', !editable && 'opacity-50')}>\n <Icon name=\"i-lucide-hash\" className=\"size-3.5 text-muted-foreground\" />\n {focused.tags.map(tag => (\n <Badge key={tag} variant=\"secondary\" className=\"max-w-full gap-0.5 pr-1\">\n <span className=\"truncate\">{tag}</span>\n <button\n type=\"button\"\n className=\"inline-flex cursor-pointer items-center rounded-full outline-none hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n aria-label={t('composites.tag.remove', { tag })}\n disabled={!editable}\n onClick={() => inspector.setTags(focused.tags.filter(item => item !== tag))}\n >\n <Icon name=\"i-lucide-x\" className=\"size-3\" />\n </button>\n </Badge>\n ))}\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n role=\"combobox\"\n aria-expanded={tagsOpen}\n aria-label={t('composites.tags.label')}\n disabled={!editable}\n className=\"min-w-12 flex-1 cursor-text self-stretch rounded text-left text-sm text-muted-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed\"\n >\n {focused.tags.length ? '' : t('composites.tags.label')}\n </button>\n </PopoverTrigger>\n </div>\n </PopoverAnchor>\n <PopoverContent align=\"start\" className=\"w-64 gap-0 p-0\">\n {/* `shouldFilter` off: the list is the metadata source's answer to the search term. */}\n <Command shouldFilter={false}>\n <CommandInput\n value={term}\n onValueChange={inspector.setSearchTerm}\n placeholder={t('composites.tags.label')}\n aria-label={t('composites.tags.label')}\n onKeyDown={(event) => {\n if (event.key === 'Backspace' && !term && focused.tags.length) inspector.setTags(focused.tags.slice(0, -1))\n }}\n />\n <CommandList>\n {tagItems.map((tag) => {\n const selected = focused.tags.includes(tag)\n return (\n <CommandItem\n key={tag}\n value={tag}\n data-checked={selected}\n onSelect={() => inspector.setTags(selected ? focused.tags.filter(item => item !== tag) : [...focused.tags, tag])}\n >\n {tag}\n </CommandItem>\n )\n })}\n {term.trim() && (\n <CommandItem value={`__create__:${term}`} onSelect={() => inspector.createTag(term)}>\n <Icon name=\"i-lucide-plus\" />\n {t('composites.tags.create', { tag: normalizeTagName(term) || term })}\n </CommandItem>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n </FormField>\n\n {focused.fields.map(field => (\n <FormField key={field.key} label={field.label}>\n {isStructuredField(field)\n ? (\n // Not text (reference, bibliography, derivation): own editors as in the details card; a text input would overwrite the stored object with a string.\n editor && <CompositeFieldEditor editor={editor} row={focused} field={field} disabled={!editable} />\n )\n : field.type === 'select'\n ? (\n <Select value={compositeFieldText(focused, field)} onValueChange={value => inspector.setField(field, value)} disabled={!editable}>\n <SelectTrigger size=\"sm\" className=\"w-full\" aria-label={field.label}>\n <SelectValue placeholder=\"–\" />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map(option => <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>)}\n </SelectContent>\n </Select>\n )\n : (\n <MetaFieldInput\n field={field}\n value={compositeFieldText(focused, field)}\n readOnly={!editable}\n onChange={value => inspector.setField(field, value)}\n />\n )}\n </FormField>\n ))}\n\n <div className=\"flex items-center gap-2 border-t border-border pt-3\">\n <Icon name=\"i-lucide-sparkles\" className=\"size-4 shrink-0 text-muted-foreground\" />\n <span className=\"text-muted-foreground\">{t('composites.inspector.aiStatus')}</span>\n <span className={cn('ml-auto inline-flex items-center gap-1.5', hasSummary ? 'text-foreground' : 'text-muted-foreground/70')}>\n <span className={cn('size-2 rounded-full', hasSummary ? 'bg-(--sk-success)' : 'bg-border')} />\n {hasSummary ? t('composites.inspector.summaryPresent') : t('composites.inspector.summaryMissing')}\n </span>\n </div>\n </div>\n </section>\n )}\n </aside>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEditorI18n } from "../../../react/use-editor-i18n.js";
|
|
2
2
|
import { Icon } from "../../../react/Icon.js";
|
|
3
|
-
import { setCompositeMetaField } from "../rows.js";
|
|
4
3
|
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger } from "../../../react/ui/dropdown-menu.js";
|
|
4
|
+
import { setCompositeMetaField } from "../rows.js";
|
|
5
5
|
import { rowStatus, statusStyle } from "../meta-display.js";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
//#region src/features/composites/react/CompositeStatusMenu.tsx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEditorI18n } from "../../../react/use-editor-i18n.js";
|
|
2
|
-
import { setCompositeDescription } from "../rows.js";
|
|
3
2
|
import { Textarea } from "../../../react/ui/textarea.js";
|
|
3
|
+
import { setCompositeDescription } from "../rows.js";
|
|
4
4
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/features/composites/react/CompositeSummaryEditor.tsx
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { compositeKindsOf } from "../nodes.js";
|
|
1
2
|
import { useEditorI18n } from "../../../react/use-editor-i18n.js";
|
|
2
3
|
import { cn } from "../../../react/ui/utils.js";
|
|
3
4
|
import { Icon } from "../../../react/Icon.js";
|
|
@@ -15,7 +16,20 @@ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
|
15
16
|
function CompositeTable({ editor, onSelect, className }) {
|
|
16
17
|
const { rows, tags, kinds } = useCompositeRows(editor);
|
|
17
18
|
const { t } = useEditorI18n();
|
|
18
|
-
const
|
|
19
|
+
const fieldContext = useMemo(() => editor ? {
|
|
20
|
+
doc: editor.state.doc,
|
|
21
|
+
kinds: compositeKindsOf(editor),
|
|
22
|
+
t
|
|
23
|
+
} : void 0, [
|
|
24
|
+
editor,
|
|
25
|
+
rows,
|
|
26
|
+
t
|
|
27
|
+
]);
|
|
28
|
+
const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds, fieldContext), [
|
|
29
|
+
rows,
|
|
30
|
+
kinds,
|
|
31
|
+
fieldContext
|
|
32
|
+
]);
|
|
19
33
|
const specs = useMemo(() => columnSpecsOf(fieldColumns, t), [fieldColumns, t]);
|
|
20
34
|
const [search, setSearch] = useState("");
|
|
21
35
|
const [pickedKinds, setPickedKinds] = useState([]);
|
|
@@ -314,7 +328,7 @@ function CompositeTable({ editor, onSelect, className }) {
|
|
|
314
328
|
}, spec.id);
|
|
315
329
|
const column = fieldColumns.find((item) => item.id === spec.id);
|
|
316
330
|
if (!column) return /* @__PURE__ */ jsx(TableCell, { className: cellClass }, spec.id);
|
|
317
|
-
const text = fieldText(row, column.field.key);
|
|
331
|
+
const text = fieldText(row, column.field.key, fieldContext);
|
|
318
332
|
return /* @__PURE__ */ jsx(TableCell, {
|
|
319
333
|
className: cellClass,
|
|
320
334
|
children: text ? /* @__PURE__ */ jsx("span", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositeTable.js","names":[],"sources":["../../../../src/features/composites/react/CompositeTable.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useMemo, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../react/ui/table'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { CompositeRow } from '../rows'\nimport { columnSpecsOf, FILTER_ALL, fieldColumnsOf, fieldOf, fieldText, hasText, isLongText, sortRows, toggled } from '../table-model'\nimport { useCompositeRows } from './use-composite-rows'\n\n// All Bausteine of an editor's document as a sortable, filterable table. Columns beyond the fixed ones derive from the\n// meta fields of the kinds present in the document, so a host kind with fields gets its columns without code changes.\n// The column specs, cell text and sorting are the framework-free `table-model`, shared with the Vue table.\n\n/** The table of an editor's Bausteine: sortable columns, filters by kind, tag and select fields, a text search; `onSelect` receives the clicked row. */\nexport function CompositeTable({ editor, onSelect, className }: {\n editor?: Editor\n onSelect?: (row: CompositeRow) => void\n className?: string\n}) {\n const { rows, tags, kinds } = useCompositeRows(editor)\n\n const { t } = useEditorI18n()\n const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds), [rows, kinds])\n const specs = useMemo(() => columnSpecsOf(fieldColumns, t), [fieldColumns, t])\n\n const [search, setSearch] = useState('')\n const [pickedKinds, setPickedKinds] = useState<string[]>([])\n const [pickedTags, setPickedTags] = useState<string[]>([])\n const [pickedOptions, setPickedOptions] = useState<Record<string, string>>({})\n\n /** One select per `select` field in use; its choices are the union of the options of all kinds that have the key. */\n const selectFilters = useMemo(() => fieldColumns.flatMap((column) => {\n if (column.field.type !== 'select') return []\n const options = new Map<string, string>()\n for (const row of rows) {\n for (const option of fieldOf(row, column.field.key)?.options ?? []) if (!options.has(option.value)) options.set(option.value, option.label)\n }\n return [{\n key: column.field.key,\n label: column.field.label,\n items: [{ label: t('composites.table.filter.all'), value: FILTER_ALL }, ...[...options].map(([value, label]) => ({ label, value }))],\n }]\n }), [fieldColumns, rows, t])\n\n // A kind, tag or option that vanished from the document can no longer be unpicked in the UI, so it must not filter either.\n const activeKinds = useMemo(() => pickedKinds.filter(id => kinds.some(kind => kind.id === id)), [pickedKinds, kinds])\n const activeTags = useMemo(() => pickedTags.filter(tag => tags.includes(tag)), [pickedTags, tags])\n const activeOptions = useMemo(() => selectFilters.flatMap((filter) => {\n const value = pickedOptions[filter.key]\n return value && filter.items.some(item => item.value === value && value !== FILTER_ALL) ? [[filter.key, value] as const] : []\n }), [selectFilters, pickedOptions])\n const needle = search.trim().toLowerCase()\n const filterActive = activeKinds.length > 0 || activeTags.length > 0 || activeOptions.length > 0 || needle !== ''\n\n function resetFilters() {\n setSearch('')\n setPickedKinds([])\n setPickedTags([])\n setPickedOptions({})\n }\n\n const filtered = useMemo(() => rows.filter((row) => {\n if (activeKinds.length && !activeKinds.includes(row.kind)) return false\n if (activeTags.length && !activeTags.every(tag => row.tags.includes(tag))) return false\n if (activeOptions.some(([key, value]) => row.meta[key] !== value)) return false\n if (needle) {\n const haystack = `${row.title}\\n${row.description}\\n${row.tags.map(tag => `#${tag}`).join(' ')}`.toLowerCase()\n if (!haystack.includes(needle)) return false\n }\n return true\n }), [rows, activeKinds, activeTags, activeOptions, needle])\n\n // --- Sorting (client side, over the filtered rows) ---\n\n const [sorting, setSorting] = useState<{ id: string, desc: boolean } | null>(null)\n const activeSort = useMemo(() => {\n const spec = sorting && specs.find(item => item.id === sorting.id)\n return sorting && spec ? { id: sorting.id, desc: sorting.desc, sort: spec.sort } : null\n }, [sorting, specs])\n\n /** Header click cycles ascending → descending → unsorted. */\n function cycleSort(id: string) {\n setSorting(current => current?.id !== id ? { id, desc: false } : current.desc ? null : { id, desc: true })\n }\n const sortIcon = (id: string) => {\n if (sorting?.id !== id) return 'i-lucide-chevrons-up-down'\n return sorting.desc ? 'i-lucide-arrow-down' : 'i-lucide-arrow-up'\n }\n\n const sorted = useMemo(() => activeSort ? sortRows(filtered, activeSort.sort, activeSort.desc) : filtered, [filtered, activeSort])\n\n const countLabel = t(rows.length === 1 ? 'composites.table.count.one' : 'composites.table.count.other', { n: sorted.length, total: rows.length })\n const columnCount = specs.length\n\n return (\n <section className={cn('flex min-h-0 flex-col gap-3', className)} aria-label={t('composites.table.label')}>\n {!rows.length\n ? (\n <div className=\"mx-auto flex max-w-sm flex-1 flex-col items-center justify-center gap-2 py-16 text-center\">\n <Icon name=\"i-lucide-table-2\" className=\"size-8 text-muted-foreground/70\" />\n <p className=\"text-sm font-medium text-foreground\">\n {t('composites.table.emptyTitle')}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.emptyText')}\n </p>\n </div>\n )\n : (\n <>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative w-64\">\n <Icon name=\"i-lucide-search\" className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={search}\n onChange={event => setSearch(event.target.value)}\n className={cn('h-7 pl-8 text-sm', search && 'pr-8')}\n placeholder={t('composites.table.search.placeholder')}\n aria-label={t('composites.table.search.label')}\n />\n {search && (\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"absolute top-1/2 right-1 -translate-y-1/2\"\n aria-label={t('composites.table.search.clear')}\n onClick={() => setSearch('')}\n >\n <Icon name=\"i-lucide-x\" />\n </Button>\n )}\n </div>\n\n {selectFilters.map(filter => (\n <div key={filter.key} className=\"flex items-center gap-1.5\">\n <span className=\"text-sm text-muted-foreground\" aria-hidden=\"true\">{filter.label}</span>\n <Select\n value={pickedOptions[filter.key] ?? FILTER_ALL}\n onValueChange={value => setPickedOptions({ ...pickedOptions, [filter.key]: String(value) })}\n >\n <SelectTrigger size=\"sm\" className=\"w-36\" aria-label={filter.label}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {filter.items.map(item => <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n ))}\n\n {filterActive && (\n <Button size=\"sm\" variant=\"ghost\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n )}\n <span className=\"ml-auto text-xs text-muted-foreground tabular-nums\" role=\"status\">{countLabel}</span>\n </div>\n\n {kinds.length > 1 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byKind')}>\n {kinds.map(kind => (\n <Button\n key={kind.id}\n size=\"xs\"\n variant={activeKinds.includes(kind.id) ? 'default' : 'outline'}\n aria-pressed={activeKinds.includes(kind.id)}\n onClick={() => setPickedKinds(toggled(pickedKinds, kind.id))}\n >\n <Icon name={kind.icon} />\n {kind.label}\n </Button>\n ))}\n </div>\n )}\n\n {tags.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byTag')}>\n {tags.map(tag => (\n <Button\n key={tag}\n size=\"xs\"\n variant={activeTags.includes(tag) ? 'default' : 'outline'}\n aria-pressed={activeTags.includes(tag)}\n onClick={() => setPickedTags(toggled(pickedTags, tag))}\n >\n {`#${tag}`}\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {/* Own scroll container instead of `<Table>`'s: the sticky header needs the element that scrolls vertically. */}\n <div className=\"min-h-0 flex-1 overflow-auto rounded-md border border-border\">\n <table data-slot=\"table\" className=\"w-full caption-bottom text-sm\">\n <TableHeader className=\"sticky top-0 z-10 bg-background\">\n <TableRow className=\"hover:bg-transparent\">\n {specs.map(spec => (\n <TableHead\n key={spec.id}\n className={cn('h-auto px-3 py-2 text-sm', spec.id === 'title' && 'min-w-56', spec.align === 'end' && 'text-right')}\n aria-sort={activeSort?.id === spec.id ? (activeSort.desc ? 'descending' : 'ascending') : 'none'}\n >\n <button\n type=\"button\"\n className=\"-mx-1.5 inline-flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 font-semibold hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary\"\n onClick={() => cycleSort(spec.id)}\n >\n {spec.label}\n <Icon name={sortIcon(spec.id)} className={cn('size-3.5', activeSort?.id === spec.id ? 'text-foreground' : 'text-muted-foreground/70')} />\n </button>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {sorted.length === 0\n ? (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell colSpan={columnCount} className=\"px-3 py-2 text-muted-foreground\">\n <div className=\"flex flex-col items-center gap-2 py-6\">\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.filter.noMatch')}\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n </div>\n </TableCell>\n </TableRow>\n )\n : sorted.map(row => (\n <TableRow key={row.key} className=\"cursor-pointer\" onClick={() => onSelect?.(row)}>\n {specs.map((spec) => {\n const cellClass = cn('px-3 py-2 text-muted-foreground', spec.align === 'end' && 'text-right')\n if (spec.id === 'title') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n <div className=\"flex min-w-0 items-center gap-1.5\" style={{ paddingLeft: `${row.depth * 1.25}rem` }}>\n <Icon name={row.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n {hasText(row.title)\n ? <span className=\"truncate font-medium text-foreground\">{row.title}</span>\n : <span className=\"truncate text-muted-foreground\">{t('composites.untitled')}</span>}\n </div>\n </TableCell>\n )\n }\n if (spec.id === 'kind') return <TableCell key={spec.id} className={cellClass}>{row.kindLabel}</TableCell>\n if (spec.id === 'tags') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {row.tags.length\n ? (\n <div className=\"flex flex-wrap gap-1\">\n {row.tags.map(tag => <Badge key={tag} variant=\"secondary\">{`#${tag}`}</Badge>)}\n </div>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noTags')}</span>\n </>\n )}\n </TableCell>\n )\n }\n if (spec.id === 'summary') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {hasText(row.description)\n ? (\n <>\n <span className=\"inline-block size-2 rounded-full bg-primary\" aria-hidden=\"true\" title={row.description} />\n <span className=\"sr-only\">{t('composites.table.summaryPresent')}</span>\n </>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.summary.none')}</span>\n </>\n )}\n </TableCell>\n )\n }\n const column = fieldColumns.find(item => item.id === spec.id)\n if (!column) return <TableCell key={spec.id} className={cellClass} />\n const text = fieldText(row, column.field.key)\n return (\n <TableCell key={spec.id} className={cellClass}>\n {text\n ? (\n <span\n className={cn('block', (column.field.type === 'number' || column.field.type === 'date') && 'tabular-nums', isLongText(column.field) && 'max-w-64 truncate')}\n title={isLongText(column.field) ? text : undefined}\n >\n {text}\n </span>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noValue')}</span>\n </>\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n </table>\n </div>\n </>\n )}\n </section>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CompositeTable.js","names":[],"sources":["../../../../src/features/composites/react/CompositeTable.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useMemo, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Badge } from '../../../react/ui/badge'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { TableBody, TableCell, TableHead, TableHeader, TableRow } from '../../../react/ui/table'\nimport { cn } from '../../../react/ui/utils'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { compositeKindsOf } from '../nodes'\nimport type { CompositeRow } from '../rows'\nimport { columnSpecsOf, type FieldContext, FILTER_ALL, fieldColumnsOf, fieldOf, fieldText, hasText, isLongText, sortRows, toggled } from '../table-model'\nimport { useCompositeRows } from './use-composite-rows'\n\n// All Bausteine of an editor's document as a sortable, filterable table. Columns beyond the fixed ones derive from the\n// meta fields of the kinds present in the document, so a host kind with fields gets its columns without code changes.\n// The column specs, cell text and sorting are the framework-free `table-model`, shared with the Vue table.\n\n/** The table of an editor's Bausteine: sortable columns, filters by kind, tag and select fields, a text search; `onSelect` receives the clicked row. */\nexport function CompositeTable({ editor, onSelect, className }: {\n editor?: Editor\n onSelect?: (row: CompositeRow) => void\n className?: string\n}) {\n const { rows, tags, kinds } = useCompositeRows(editor)\n\n const { t } = useEditorI18n()\n // `reference` cells resolve their target in the document; re-read whenever the rows change.\n const fieldContext = useMemo<FieldContext | undefined>(() => (editor ? { doc: editor.state.doc, kinds: compositeKindsOf(editor), t } : undefined), [editor, rows, t])\n const fieldColumns = useMemo(() => fieldColumnsOf(rows, kinds, fieldContext), [rows, kinds, fieldContext])\n const specs = useMemo(() => columnSpecsOf(fieldColumns, t), [fieldColumns, t])\n\n const [search, setSearch] = useState('')\n const [pickedKinds, setPickedKinds] = useState<string[]>([])\n const [pickedTags, setPickedTags] = useState<string[]>([])\n const [pickedOptions, setPickedOptions] = useState<Record<string, string>>({})\n\n /** One select per `select` field in use; its choices are the union of the options of all kinds that have the key. */\n const selectFilters = useMemo(() => fieldColumns.flatMap((column) => {\n if (column.field.type !== 'select') return []\n const options = new Map<string, string>()\n for (const row of rows) {\n for (const option of fieldOf(row, column.field.key)?.options ?? []) if (!options.has(option.value)) options.set(option.value, option.label)\n }\n return [{\n key: column.field.key,\n label: column.field.label,\n items: [{ label: t('composites.table.filter.all'), value: FILTER_ALL }, ...[...options].map(([value, label]) => ({ label, value }))],\n }]\n }), [fieldColumns, rows, t])\n\n // A kind, tag or option that vanished from the document can no longer be unpicked in the UI, so it must not filter either.\n const activeKinds = useMemo(() => pickedKinds.filter(id => kinds.some(kind => kind.id === id)), [pickedKinds, kinds])\n const activeTags = useMemo(() => pickedTags.filter(tag => tags.includes(tag)), [pickedTags, tags])\n const activeOptions = useMemo(() => selectFilters.flatMap((filter) => {\n const value = pickedOptions[filter.key]\n return value && filter.items.some(item => item.value === value && value !== FILTER_ALL) ? [[filter.key, value] as const] : []\n }), [selectFilters, pickedOptions])\n const needle = search.trim().toLowerCase()\n const filterActive = activeKinds.length > 0 || activeTags.length > 0 || activeOptions.length > 0 || needle !== ''\n\n function resetFilters() {\n setSearch('')\n setPickedKinds([])\n setPickedTags([])\n setPickedOptions({})\n }\n\n const filtered = useMemo(() => rows.filter((row) => {\n if (activeKinds.length && !activeKinds.includes(row.kind)) return false\n if (activeTags.length && !activeTags.every(tag => row.tags.includes(tag))) return false\n if (activeOptions.some(([key, value]) => row.meta[key] !== value)) return false\n if (needle) {\n const haystack = `${row.title}\\n${row.description}\\n${row.tags.map(tag => `#${tag}`).join(' ')}`.toLowerCase()\n if (!haystack.includes(needle)) return false\n }\n return true\n }), [rows, activeKinds, activeTags, activeOptions, needle])\n\n // --- Sorting (client side, over the filtered rows) ---\n\n const [sorting, setSorting] = useState<{ id: string, desc: boolean } | null>(null)\n const activeSort = useMemo(() => {\n const spec = sorting && specs.find(item => item.id === sorting.id)\n return sorting && spec ? { id: sorting.id, desc: sorting.desc, sort: spec.sort } : null\n }, [sorting, specs])\n\n /** Header click cycles ascending → descending → unsorted. */\n function cycleSort(id: string) {\n setSorting(current => current?.id !== id ? { id, desc: false } : current.desc ? null : { id, desc: true })\n }\n const sortIcon = (id: string) => {\n if (sorting?.id !== id) return 'i-lucide-chevrons-up-down'\n return sorting.desc ? 'i-lucide-arrow-down' : 'i-lucide-arrow-up'\n }\n\n const sorted = useMemo(() => activeSort ? sortRows(filtered, activeSort.sort, activeSort.desc) : filtered, [filtered, activeSort])\n\n const countLabel = t(rows.length === 1 ? 'composites.table.count.one' : 'composites.table.count.other', { n: sorted.length, total: rows.length })\n const columnCount = specs.length\n\n return (\n <section className={cn('flex min-h-0 flex-col gap-3', className)} aria-label={t('composites.table.label')}>\n {!rows.length\n ? (\n <div className=\"mx-auto flex max-w-sm flex-1 flex-col items-center justify-center gap-2 py-16 text-center\">\n <Icon name=\"i-lucide-table-2\" className=\"size-8 text-muted-foreground/70\" />\n <p className=\"text-sm font-medium text-foreground\">\n {t('composites.table.emptyTitle')}\n </p>\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.emptyText')}\n </p>\n </div>\n )\n : (\n <>\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <div className=\"relative w-64\">\n <Icon name=\"i-lucide-search\" className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={search}\n onChange={event => setSearch(event.target.value)}\n className={cn('h-7 pl-8 text-sm', search && 'pr-8')}\n placeholder={t('composites.table.search.placeholder')}\n aria-label={t('composites.table.search.label')}\n />\n {search && (\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"absolute top-1/2 right-1 -translate-y-1/2\"\n aria-label={t('composites.table.search.clear')}\n onClick={() => setSearch('')}\n >\n <Icon name=\"i-lucide-x\" />\n </Button>\n )}\n </div>\n\n {selectFilters.map(filter => (\n <div key={filter.key} className=\"flex items-center gap-1.5\">\n <span className=\"text-sm text-muted-foreground\" aria-hidden=\"true\">{filter.label}</span>\n <Select\n value={pickedOptions[filter.key] ?? FILTER_ALL}\n onValueChange={value => setPickedOptions({ ...pickedOptions, [filter.key]: String(value) })}\n >\n <SelectTrigger size=\"sm\" className=\"w-36\" aria-label={filter.label}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {filter.items.map(item => <SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n ))}\n\n {filterActive && (\n <Button size=\"sm\" variant=\"ghost\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n )}\n <span className=\"ml-auto text-xs text-muted-foreground tabular-nums\" role=\"status\">{countLabel}</span>\n </div>\n\n {kinds.length > 1 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byKind')}>\n {kinds.map(kind => (\n <Button\n key={kind.id}\n size=\"xs\"\n variant={activeKinds.includes(kind.id) ? 'default' : 'outline'}\n aria-pressed={activeKinds.includes(kind.id)}\n onClick={() => setPickedKinds(toggled(pickedKinds, kind.id))}\n >\n <Icon name={kind.icon} />\n {kind.label}\n </Button>\n ))}\n </div>\n )}\n\n {tags.length > 0 && (\n <div className=\"flex flex-wrap items-center gap-1\" role=\"group\" aria-label={t('composites.table.filter.byTag')}>\n {tags.map(tag => (\n <Button\n key={tag}\n size=\"xs\"\n variant={activeTags.includes(tag) ? 'default' : 'outline'}\n aria-pressed={activeTags.includes(tag)}\n onClick={() => setPickedTags(toggled(pickedTags, tag))}\n >\n {`#${tag}`}\n </Button>\n ))}\n </div>\n )}\n </div>\n\n {/* Own scroll container instead of `<Table>`'s: the sticky header needs the element that scrolls vertically. */}\n <div className=\"min-h-0 flex-1 overflow-auto rounded-md border border-border\">\n <table data-slot=\"table\" className=\"w-full caption-bottom text-sm\">\n <TableHeader className=\"sticky top-0 z-10 bg-background\">\n <TableRow className=\"hover:bg-transparent\">\n {specs.map(spec => (\n <TableHead\n key={spec.id}\n className={cn('h-auto px-3 py-2 text-sm', spec.id === 'title' && 'min-w-56', spec.align === 'end' && 'text-right')}\n aria-sort={activeSort?.id === spec.id ? (activeSort.desc ? 'descending' : 'ascending') : 'none'}\n >\n <button\n type=\"button\"\n className=\"-mx-1.5 inline-flex cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 font-semibold hover:bg-muted focus-visible:outline-2 focus-visible:outline-primary\"\n onClick={() => cycleSort(spec.id)}\n >\n {spec.label}\n <Icon name={sortIcon(spec.id)} className={cn('size-3.5', activeSort?.id === spec.id ? 'text-foreground' : 'text-muted-foreground/70')} />\n </button>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {sorted.length === 0\n ? (\n <TableRow className=\"hover:bg-transparent\">\n <TableCell colSpan={columnCount} className=\"px-3 py-2 text-muted-foreground\">\n <div className=\"flex flex-col items-center gap-2 py-6\">\n <p className=\"text-sm text-muted-foreground\">\n {t('composites.table.filter.noMatch')}\n </p>\n <Button size=\"sm\" variant=\"outline\" onClick={resetFilters}>\n <Icon name=\"i-lucide-filter-x\" />\n {t('composites.table.filter.reset')}\n </Button>\n </div>\n </TableCell>\n </TableRow>\n )\n : sorted.map(row => (\n <TableRow key={row.key} className=\"cursor-pointer\" onClick={() => onSelect?.(row)}>\n {specs.map((spec) => {\n const cellClass = cn('px-3 py-2 text-muted-foreground', spec.align === 'end' && 'text-right')\n if (spec.id === 'title') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n <div className=\"flex min-w-0 items-center gap-1.5\" style={{ paddingLeft: `${row.depth * 1.25}rem` }}>\n <Icon name={row.icon} className=\"size-4 shrink-0 text-muted-foreground\" />\n {hasText(row.title)\n ? <span className=\"truncate font-medium text-foreground\">{row.title}</span>\n : <span className=\"truncate text-muted-foreground\">{t('composites.untitled')}</span>}\n </div>\n </TableCell>\n )\n }\n if (spec.id === 'kind') return <TableCell key={spec.id} className={cellClass}>{row.kindLabel}</TableCell>\n if (spec.id === 'tags') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {row.tags.length\n ? (\n <div className=\"flex flex-wrap gap-1\">\n {row.tags.map(tag => <Badge key={tag} variant=\"secondary\">{`#${tag}`}</Badge>)}\n </div>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noTags')}</span>\n </>\n )}\n </TableCell>\n )\n }\n if (spec.id === 'summary') {\n return (\n <TableCell key={spec.id} className={cellClass}>\n {hasText(row.description)\n ? (\n <>\n <span className=\"inline-block size-2 rounded-full bg-primary\" aria-hidden=\"true\" title={row.description} />\n <span className=\"sr-only\">{t('composites.table.summaryPresent')}</span>\n </>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.summary.none')}</span>\n </>\n )}\n </TableCell>\n )\n }\n const column = fieldColumns.find(item => item.id === spec.id)\n if (!column) return <TableCell key={spec.id} className={cellClass} />\n const text = fieldText(row, column.field.key, fieldContext)\n return (\n <TableCell key={spec.id} className={cellClass}>\n {text\n ? (\n <span\n className={cn('block', (column.field.type === 'number' || column.field.type === 'date') && 'tabular-nums', isLongText(column.field) && 'max-w-64 truncate')}\n title={isLongText(column.field) ? text : undefined}\n >\n {text}\n </span>\n )\n : (\n <>\n <span className=\"text-muted-foreground/70\" aria-hidden=\"true\">–</span>\n <span className=\"sr-only\">{t('composites.table.noValue')}</span>\n </>\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n </table>\n </div>\n </>\n )}\n </section>\n )\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { metadataOf } from "../../../core/metadata.js";
|
|
2
2
|
import { METADATA_LIST } from "../../../core/metadata-types.js";
|
|
3
|
+
import { normalizeTagName } from "../../../core/tag-name.js";
|
|
3
4
|
import { useEditorI18n } from "../../../react/use-editor-i18n.js";
|
|
4
5
|
import { Icon } from "../../../react/Icon.js";
|
|
5
|
-
import { setCompositeTags } from "../rows.js";
|
|
6
|
-
import { normalizeTagName } from "../../../core/tag-name.js";
|
|
7
6
|
import { Command, CommandInput, CommandItem, CommandList } from "../../../react/ui/command.js";
|
|
7
|
+
import { setCompositeTags } from "../rows.js";
|
|
8
8
|
import { useEffect, useRef, useState } from "react";
|
|
9
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
//#region src/features/composites/react/CompositeTagsEditor.tsx
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { compositeKind } from "../kinds.js";
|
|
2
|
+
import { derivationOf } from "../derivation.js";
|
|
2
3
|
import { compositeKindsOf } from "../nodes.js";
|
|
3
4
|
import { cn } from "../../../react/ui/utils.js";
|
|
5
|
+
import { useStore } from "../../../react/use-store.js";
|
|
4
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
7
|
import { NodeViewContent, NodeViewWrapper } from "@tiptap/react";
|
|
6
8
|
//#region src/features/composites/react/CompositeView.tsx
|
|
@@ -9,10 +11,13 @@ const cssString = (text) => `"${text.replace(/["\\]/g, "\\$&").replace(/\n/g, "\
|
|
|
9
11
|
/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */
|
|
10
12
|
function CompositeView({ editor, node, selected }) {
|
|
11
13
|
const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind));
|
|
14
|
+
const expanded = useStore(editor.storage.composite.expanded);
|
|
15
|
+
const id = node.attrs.id;
|
|
16
|
+
const collapsed = typeof id === "string" && id !== "" && derivationOf(node) !== null && !expanded.has(id);
|
|
12
17
|
const placeholderVars = { "--composite-title-placeholder": cssString(kind.titlePlaceholder) };
|
|
13
18
|
return /* @__PURE__ */ jsxs(NodeViewWrapper, {
|
|
14
19
|
as: "section",
|
|
15
|
-
className: cn("composite", selected && "is-selected rounded-md ring-1 ring-primary"),
|
|
20
|
+
className: cn("composite", collapsed && "is-collapsed", selected && "is-selected rounded-md ring-1 ring-primary"),
|
|
16
21
|
"data-type": "composite",
|
|
17
22
|
"data-kind": node.attrs.kind,
|
|
18
23
|
"data-id": node.attrs.id || void 0,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompositeView.js","names":[],"sources":["../../../../src/features/composites/react/CompositeView.tsx"],"sourcesContent":["import { NodeViewContent, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'\nimport type { CSSProperties } from 'react'\nimport { cn } from '../../../react/ui/utils'\nimport { compositeKind } from '../kinds'\nimport { compositeKindsOf } from '../nodes'\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n\n/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */\nexport function CompositeView({ editor, node, selected }: NodeViewProps) {\n const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind))\n // Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\n const placeholderVars = { '--composite-title-placeholder': cssString(kind.titlePlaceholder) } as CSSProperties\n return (\n <NodeViewWrapper\n as=\"section\"\n className={cn('composite', selected && 'is-selected rounded-md ring-1 ring-primary')}\n data-type=\"composite\"\n data-kind={node.attrs.kind}\n data-id={node.attrs.id || undefined}\n style={placeholderVars}\n >\n {/* Anchor of the kind icon on the left border: it only takes the icon's place and size. The composite chrome overlay\n measures it and draws the icon as the button that opens the details popover and drags the composite. */}\n <span className=\"composite__toggle\" contentEditable={false} aria-hidden=\"true\" />\n <NodeViewContent className=\"composite__content\" />\n </NodeViewWrapper>\n )\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CompositeView.js","names":[],"sources":["../../../../src/features/composites/react/CompositeView.tsx"],"sourcesContent":["import { NodeViewContent, NodeViewWrapper, type NodeViewProps } from '@tiptap/react'\nimport type { CSSProperties } from 'react'\nimport { cn } from '../../../react/ui/utils'\nimport { compositeKind } from '../kinds'\nimport { useStore } from '../../../react/use-store'\nimport { derivationOf } from '../derivation'\nimport { compositeKindsOf } from '../nodes'\n\n/** `text` as a CSS string literal (for `content:`). */\nconst cssString = (text: string) => `\"${text.replace(/[\"\\\\]/g, '\\\\$&').replace(/\\n/g, '\\\\a ')}\"`\n\n/** The composite block: the section with its content. The kind icon is drawn by the composite chrome overlay. */\nexport function CompositeView({ editor, node, selected }: NodeViewProps) {\n const kind = compositeKind(compositeKindsOf(editor), String(node.attrs.kind))\n // A derived Baustein (one with a `meta.derivation`) shows collapsed to a faded preview until it is opened; the content\n // stays laid out (CSS clips it), so editing positions are unaffected. The chrome's chevron and a caret inside open it.\n const expanded = useStore(editor.storage.composite.expanded)\n const id: unknown = node.attrs.id\n const collapsed = typeof id === 'string' && id !== '' && derivationOf(node) !== null && !expanded.has(id)\n // Placeholder of the empty title (composites.css `content: var(…)`); a nested composite sets its own.\n const placeholderVars = { '--composite-title-placeholder': cssString(kind.titlePlaceholder) } as CSSProperties\n return (\n <NodeViewWrapper\n as=\"section\"\n className={cn('composite', collapsed && 'is-collapsed', selected && 'is-selected rounded-md ring-1 ring-primary')}\n data-type=\"composite\"\n data-kind={node.attrs.kind}\n data-id={node.attrs.id || undefined}\n style={placeholderVars}\n >\n {/* Anchor of the kind icon on the left border: it only takes the icon's place and size. The composite chrome overlay\n measures it and draws the icon as the button that opens the details popover and drags the composite. */}\n <span className=\"composite__toggle\" contentEditable={false} aria-hidden=\"true\" />\n <NodeViewContent className=\"composite__content\" />\n </NodeViewWrapper>\n )\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,aAAa,SAAiB,IAAI,KAAK,QAAQ,UAAU,MAAM,CAAC,CAAC,QAAQ,OAAO,MAAM,EAAE;;AAG9F,SAAgB,cAAc,EAAE,QAAQ,MAAM,YAA2B;CACvE,MAAM,OAAO,cAAc,iBAAiB,MAAM,GAAG,OAAO,KAAK,MAAM,IAAI,CAAC;CAG5E,MAAM,WAAW,SAAS,OAAO,QAAQ,UAAU,QAAQ;CAC3D,MAAM,KAAc,KAAK,MAAM;CAC/B,MAAM,YAAY,OAAO,OAAO,YAAY,OAAO,MAAM,aAAa,IAAI,MAAM,QAAQ,CAAC,SAAS,IAAI,EAAE;CAExG,MAAM,kBAAkB,EAAE,iCAAiC,UAAU,KAAK,gBAAgB,EAAE;CAC5F,OACE,qBAAC,iBAAD;EACE,IAAG;EACH,WAAW,GAAG,aAAa,aAAa,gBAAgB,YAAY,4CAA4C;EAChH,aAAU;EACV,aAAW,KAAK,MAAM;EACtB,WAAS,KAAK,MAAM,MAAM,KAAA;EAC1B,OAAO;EANT,UAAA,CAUE,oBAAC,QAAD;GAAM,WAAU;GAAoB,iBAAiB;GAAO,eAAY;EAAQ,CAAA,GAChF,oBAAC,iBAAD,EAAiB,WAAU,qBAAsB,CAAA,CAClC;;AAErB"}
|