@ecsplico/editor 2.1.1 → 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 +74 -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/code/CodeSurface.vue.d.ts +3 -3
- 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/document/DocumentSurface.vue.d.ts +3 -3
- 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 +22 -1
- package/dist/features/block-ui/block-actions.js +26 -2
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/components/BlockActionsOverlay.js +33 -4
- package/dist/features/block-ui/components/BlockActionsOverlay.js.map +1 -1
- package/dist/features/block-ui/components/BlockActionsOverlay.vue.d.ts +4 -0
- 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/index.d.ts +2 -2
- package/dist/features/block-ui/index.js +2 -2
- package/dist/features/block-ui/react/BlockActionsOverlay.d.ts +4 -0
- package/dist/features/block-ui/react/BlockActionsOverlay.js +38 -12
- package/dist/features/block-ui/react/BlockActionsOverlay.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 +10 -9
- 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 +1 -1
- package/dist/vue/AdvancedEditor.js +30 -9
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
- 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 +11 -11
- 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 -630
- package/docs/llms.md +0 -383
- package/docs/usage.md +0 -1076
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/composites/feature.ts"],"sourcesContent":["import type { ChainedCommands, Editor } from '@tiptap/core'\nimport type { EditorFeature, FeatureContext, MenuItem, SlashCommandItem, ToolbarItem } from '../../core'\nimport { abilitiesAtSelection, downloadText, editorEntryOf, settingsTabsOf } from '../../core'\nimport type { Translate } from '../../i18n'\nimport { ABILITY } from '../../core/schema'\nimport { AcceptedChildren } from './accepted-children'\nimport { compositeConversions } from './convert'\nimport { blocksFromMarkdown } from './fences'\nimport { structureBlocks } from './heading-composites'\nimport { type CompositeKind, compositeKind, defaultCompositeKinds } from './kinds'\nimport { migrateLegacyContent } from './legacy'\nimport { documentCompositeMarkdown, markdownFileName } from './markdown-export'\nimport { type CompositeNodeViews, compositeNodes } from './node-views'\nimport { CompositeDescriptionNode, CompositeTitleNode, compositeKindsOf } from './nodes'\nimport { Structure, structureOf } from './structure'\nimport { STRUCTURE_MODE_KEYS } from './structure-mode'\n\n/** What a framework binding supplies to the composites feature. */\nexport interface CompositesUi<C> {\n /** The chips on each title line and the details popover on the kind icon; mounted as an overlay. */\n chrome: C\n /** The „Bearbeiten“ settings tab; receives `{ kinds }` as props. */\n settingsTab: C\n /** The composite block view of the framework. */\n nodeViews: CompositeNodeViews\n}\n\n/** Options of `compositeFeature`. */\nexport interface CompositeFeatureOptions {\n /** The composite kinds („Bausteine“) offered in the editor, with their own labels (default: `defaultCompositeKinds(t)`, the built-in kinds in the editor's language); read once. */\n kinds?: readonly CompositeKind[]\n}\n\n/** Heading level the structure stage starts at when it turns composites into headings (below the document title). */\nconst STRUCTURE_STAGE_LEVEL = 2\n\n/**\n * Composites („Bausteine“): the node family with its node views, the toolbar group (insert, „In Baustein umwandeln“,\n * „Gliederung umwandeln“), `/` commands, the conversion providers (wrap into / switch kind of / unwrap composites),\n * Markdown `:::` fences, legacy `section` migration, the preferred-structure setting and its `editing` settings tab,\n * the chips on each title line (status, tags) and the details popover on the kind icon (the binding's `chrome` overlay), and\n * the AI view of kinds and structure, and the kinds' accepted children (`AcceptedChildren`: an edit that nests a Baustein\n * into one that does not accept its kind is refused with a notice). Contributes the `parseMarkdown`,\n * `structure` and `migrateContent` stages. Imports no AI, media or transcript code.\n */\nexport function compositeFeatureCore<C>(ui: CompositesUi<C>, options: CompositeFeatureOptions = {}): EditorFeature<C> {\n // Host kinds keep their labels; the built-in ones are produced from the context's translator (memoized per `t`).\n const kindsOf = (ctx: { t: Translate }) => options.kinds ?? defaultCompositeKinds(ctx.t)\n const { Composite, CompositeTags } = compositeNodes(ui.nodeViews)\n return {\n id: 'composites',\n extensions: ctx => [\n Composite.configure({ kinds: kindsOf(ctx) }),\n CompositeTitleNode,\n CompositeDescriptionNode,\n CompositeTags,\n Structure.configure({ mode: () => ctx.settings.get().blocks.structure }),\n AcceptedChildren.configure({ notify: ctx.notify, t: ctx.t }),\n ],\n toolbar: ctx => [{\n id: 'composites',\n order: 60,\n items: compositeToolbarItems(ctx, kindsOf(ctx)),\n }],\n slashCommands: ctx => compositeSlashCommands(ctx, kindsOf(ctx)),\n blockActions: ctx => [{\n id: 'document-export',\n label: ctx.t('composites.blockAction.export'),\n icon: 'i-lucide-download',\n ability: ABILITY.compositeExport,\n order: 400,\n isVisible: ({ node }) => node.attrs.kind === 'document',\n run: ({ editor, node }) => downloadText(markdownFileName(node), documentCompositeMarkdown(editor, node)),\n }],\n overlays: [ui.chrome],\n settingsTabs: ctx => [{ id: 'editing', label: ctx.t('composites.tab'), icon: 'i-lucide-pencil', component: ui.settingsTab, props: { kinds: kindsOf(ctx) } }],\n blocks: {\n parseMarkdown: (editor, markdown) => blocksFromMarkdown(md => editor.markdown!.parse(md), markdown, compositeKindsOf(editor)),\n structure: (editor, blocks) => {\n const { schema } = editor\n return structureBlocks(schema, blocks.map(block => schema.nodeFromJSON(block)), structureOf(editor), STRUCTURE_STAGE_LEVEL, compositeKindsOf(editor)).map(node => node.toJSON())\n },\n migrateContent: migrateLegacyContent,\n },\n conversions: compositeConversions(options.kinds),\n aiContext: editor => ({\n kinds: compositeKindsOf(editor).map(({ id, label, fields, ai }) => ({ id, label, fields, ...(ai?.purpose && { purpose: ai.purpose }) })),\n structure: structureOf(editor),\n }),\n }\n}\n\nfunction compositeSlashCommands({ settings, t }: FeatureContext, kinds: readonly CompositeKind[]): SlashCommandItem[] {\n const insert = (kind: string) => (editor: Editor) => editor.commands.insertComposite(kind)\n const group = (recursive: boolean) => (editor: Editor) => {\n const { editing, blocks } = settings.get()\n return editor.commands.convertHeadingsToComposites({ recursive, scope: editing.headingConversionScope, kind: blocks.defaultKind })\n }\n const flatten = (recursive: boolean) => (editor: Editor) => editor.commands.convertCompositesToHeadings({ recursive, scope: settings.get().editing.headingConversionScope })\n return [\n { id: 'abschnitt', label: t('composites.slash.section'), icon: 'i-lucide-layers', ability: ABILITY.composite, run: insert('section') },\n ...kinds.filter(kind => kind.id !== 'section').map((kind): SlashCommandItem => (\n { id: kind.id, label: kind.label, icon: kind.icon, ability: ABILITY.composite, run: insert(kind.id) }\n )),\n { id: 'gliedern', label: t('composites.slash.group'), icon: 'i-lucide-layers', ability: ABILITY.composite, run: group(false) },\n { id: 'gliedern-alle', label: t('composites.slash.groupAll'), icon: 'i-lucide-list-tree', ability: ABILITY.composite, run: group(true) },\n { id: 'aufloesen', label: t('composites.slash.flatten'), icon: 'i-lucide-heading', ability: ABILITY.headings, run: flatten(false) },\n { id: 'aufloesen-alle', label: t('composites.slash.flattenAll'), icon: 'i-lucide-align-left', ability: ABILITY.headings, run: flatten(true) },\n ]\n}\n\n/**\n * The toolbar group beside the inserts: the default kind's insert button (it follows the setting, so label/icon/shortcut\n * are getters read at render time), „In Baustein umwandeln“ (one entry per kind for the caret's block) and „Gliederung\n * umwandeln“ (headings <-> composites in both directions, the preferred structure's direction first).\n */\nfunction compositeToolbarItems<C>({ settings, t }: FeatureContext, kinds: readonly CompositeKind[]): ToolbarItem<C>[] {\n const defaultKind = () => compositeKind(kinds, settings.get().blocks.defaultKind)\n const insert = (chain: ChainedCommands) => chain.insertComposite(defaultKind().id)\n const scope = () => settings.get().editing.headingConversionScope\n\n const canGroup = (editor: Editor, recursive: boolean) => editor.can().convertHeadingsToComposites({ recursive, scope: scope(), kind: settings.get().blocks.defaultKind })\n const canFlatten = (editor: Editor, recursive: boolean) => editor.can().convertCompositesToHeadings({ recursive, scope: scope() })\n\n function kindItems(editor: Editor): MenuItem[] {\n return [\n { type: 'label', label: t('composites.menu.kindHeading') },\n ...compositeKindsOf(editor).map((kind): MenuItem => {\n const target = { type: 'composite', kind: kind.id } as const\n return { label: kind.label, icon: kind.icon, disabled: !editor.can().convertBlockTo(target), onSelect: () => editor.chain().focus().convertBlockTo(target).run() }\n }),\n ]\n }\n\n function structureItems(editor: Editor): MenuItem[] {\n const structure = settings.get().blocks.structure\n const abilities = abilitiesAtSelection(editor)\n const composite = abilities.has(ABILITY.composite)\n const headings = abilities.has(ABILITY.headings)\n const run = (command: () => boolean) => () => void command()\n const sep: MenuItem = { type: 'separator' }\n const toComposites: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toComposites') },\n { label: t('composites.menu.toComposites.top'), description: t('composites.menu.toComposites.top.description'), icon: 'i-lucide-layers', disabled: !composite || !canGroup(editor, false), onSelect: run(() => editor.chain().focus().convertHeadingsToComposites({ recursive: false, scope: scope(), kind: settings.get().blocks.defaultKind }).run()) },\n { label: t('composites.menu.toComposites.all'), description: t('composites.menu.toComposites.all.description'), icon: 'i-lucide-list-tree', disabled: !composite || !canGroup(editor, true), onSelect: run(() => editor.chain().focus().convertHeadingsToComposites({ recursive: true, scope: scope(), kind: settings.get().blocks.defaultKind }).run()) },\n ]\n const toHeadings: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toHeadings') },\n { label: t('composites.menu.toHeadings.top'), description: t('composites.menu.toHeadings.top.description'), icon: 'i-lucide-heading', disabled: !headings || !canFlatten(editor, false), onSelect: run(() => editor.chain().focus().convertCompositesToHeadings({ recursive: false, scope: scope() }).run()) },\n { label: t('composites.menu.toHeadings.all'), description: t('composites.menu.toHeadings.all.description'), icon: 'i-lucide-align-left', disabled: !headings || !canFlatten(editor, true), onSelect: run(() => editor.chain().focus().convertCompositesToHeadings({ recursive: true, scope: scope() }).run()) },\n ]\n const entry = editorEntryOf(editor)\n // The settings entry exists only while some feature contributes a tab to open.\n const settingsEntry: MenuItem[] = entry && settingsTabsOf(entry.preset, entry.ctx.app).length\n ? [sep, { label: t('composites.menu.settings'), icon: 'i-lucide-settings-2', onSelect: () => entry.ui.openSettings('editing') }]\n : []\n return [\n { type: 'label', label: t('composites.menu.preferred', { mode: t(STRUCTURE_MODE_KEYS[structure].labelKey) }) },\n ...(structure === 'composite' ? [...toComposites, sep, ...toHeadings] : [...toHeadings, sep, ...toComposites]),\n ...settingsEntry,\n ]\n }\n\n return [\n {\n id: 'insert',\n order: 10,\n // Getters: the default kind arrives with the server settings; the toolbar reads them at render time.\n get icon() { return defaultKind().icon },\n get label() { return defaultKind().label },\n // Mod-Shift-a (CompositeNode) always inserts a `section`, so only then is it shown as the shortcut.\n get kbds() { return defaultKind().id === 'section' ? ['meta', 'shift', 'a'] : undefined },\n ability: ABILITY.composite,\n disabled: editor => !insert(editor.can().chain()).run(),\n run: (editor) => { insert(editor.chain().focus()).run() },\n },\n {\n id: 'to-kind',\n order: 20,\n icon: 'i-lucide-replace',\n label: t('composites.toolbar.toKind'),\n ability: ABILITY.composite,\n disabled: editor => kindItems(editor).every(item => item.type === 'label' || item.disabled),\n menu: kindItems,\n },\n {\n id: 'structure',\n order: 30,\n icon: 'i-lucide-list-tree',\n label: t('composites.toolbar.structure'),\n disabled: editor => !canGroup(editor, true) && !canFlatten(editor, true),\n menu: structureItems,\n },\n ]\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/composites/feature.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { CommandDef, EditorFeature, FeatureContext, MenuItem, ToolbarGroupDef } from '../../core'\nimport { abilitiesAtSelection, downloadText, editorEntryOf, settingsTabsOf } from '../../core'\nimport type { Translate } from '../../i18n'\nimport { ABILITY, findBlockById } from '../../core/schema'\nimport { AcceptedChildren, compositeInsertGuard } from './accepted-children'\nimport { bibOf, bibtexOf, cslOf } from './bibliography'\nimport { compositeConversions } from './convert'\nimport { bodyMarkdown, derivationOf } from './derivation'\nimport { blocksFromMarkdown } from './fences'\nimport { structureBlocks } from './heading-composites'\nimport { type CompositeKind, compositeKind, defaultCompositeKinds } from './kinds'\nimport { migrateLegacyContent } from './legacy'\nimport { compositeSchemaExtensions } from './schema'\nimport { documentCompositeMarkdown, markdownFileName } from './markdown-export'\nimport { type CompositeNodeViews, compositeNodes } from './node-views'\nimport { CompositeDescriptionNode, CompositeTitleNode, compositeKindsOf } from './nodes'\nimport { REFERENCE_TRIGGER } from './reference'\nimport { REFERENCE_AI_BLOCK } from './reference-ai'\nimport { referenceSuggestion } from './reference-suggestion'\nimport { compositeIdsOf, normalizeReferences } from './reference-text'\nimport { SourceReveal } from './reveal-source'\nimport { Structure, structureOf } from './structure'\nimport { STRUCTURE_MODE_KEYS } from './structure-mode'\n\n/** What a framework binding supplies to the composites feature. */\nexport interface CompositesUi<C> {\n /** The chips on each title line and the details popover on the kind icon; mounted as an overlay. */\n chrome: C\n /** The „Bearbeiten“ settings tab; receives `{ kinds }` as props. */\n settingsTab: C\n /** The composite block view of the framework. */\n nodeViews: CompositeNodeViews\n}\n\n/** Options of `compositeFeature`. */\nexport interface CompositeFeatureOptions {\n /** The composite kinds („Bausteine“) offered in the editor, with their own labels (default: `defaultCompositeKinds(t)`, the built-in kinds in the editor's language); read once. */\n kinds?: readonly CompositeKind[]\n}\n\n/** Heading level the structure stage starts at when it turns composites into headings (below the document title). */\nconst STRUCTURE_STAGE_LEVEL = 2\n\n/**\n * Composites („Bausteine“): the node family with its node views, the toolbar group (insert, „In Baustein umwandeln“,\n * „Gliederung umwandeln“), `/` commands, the conversion providers (wrap into / switch kind of / unwrap composites),\n * Markdown `:::` fences, legacy `section` migration, the preferred-structure setting and its `editing` settings tab,\n * the chips on each title line (status, tags) and the details popover on the kind icon (the binding's `chrome` overlay), and\n * the AI view of kinds and structure, and the kinds' accepted children (`AcceptedChildren`: an edit that nests a Baustein\n * into one that does not accept its kind is refused with a notice). Contributes the `parseMarkdown`,\n * `structure` and `migrateContent` stages. Imports no AI, media or transcript code.\n */\nexport function compositeFeatureCore<C>(ui: CompositesUi<C>, options: CompositeFeatureOptions = {}): EditorFeature<C> {\n // Host kinds keep their labels; the built-in ones are produced from the context's translator (memoized per `t`).\n const kindsOf = (ctx: { t: Translate }) => options.kinds ?? defaultCompositeKinds(ctx.t)\n const { Composite, CompositeTags, Reference } = compositeNodes(ui.nodeViews)\n return {\n id: 'composites',\n dimension: 'content',\n schemaExtensions: () => compositeSchemaExtensions(options.kinds ? { kinds: options.kinds } : {}),\n extensions: ctx => [\n Composite.configure({ kinds: kindsOf(ctx) }),\n CompositeTitleNode,\n CompositeDescriptionNode,\n CompositeTags,\n Structure.configure({ mode: () => ctx.settings.get().blocks.structure }),\n AcceptedChildren.configure({ notify: ctx.notify, t: ctx.t }),\n SourceReveal,\n Reference.configure({ suggestion: referenceSuggestion(ctx.t) }),\n ],\n toolbarGroups: COMPOSITE_TOOLBAR_GROUPS,\n commands: ctx => compositeCommands(ctx, kindsOf(ctx)),\n insertGuards: () => [compositeInsertGuard],\n blockActions: ctx => [{\n id: 'document-export',\n label: ctx.t('composites.blockAction.export'),\n icon: 'i-lucide-download',\n ability: ABILITY.compositeExport,\n order: 400,\n isVisible: ({ node }) => node.attrs.kind === 'document',\n run: ({ editor, node }) => downloadText(markdownFileName(node), documentCompositeMarkdown(editor, node)),\n }, {\n id: 'bibliography-export',\n label: ctx.t('composites.blockAction.bibtex'),\n icon: 'i-lucide-book-marked',\n ability: ABILITY.compositeExport,\n order: 410,\n isVisible: ({ node }) => bibOf(node) !== null,\n run: ({ node }) => downloadText(`${markdownFileName(node).replace(/\\.md$/, '')}.bib`, bibtexOf(cslOf(node)!), 'text/x-bibtex;charset=utf-8'),\n }],\n overlays: [ui.chrome],\n settingsTabs: ctx => [{ id: 'editing', label: ctx.t('composites.tab'), icon: 'i-lucide-pencil', component: ui.settingsTab, props: { kinds: kindsOf(ctx) } }],\n blocks: {\n parseMarkdown: (editor, markdown) => blocksFromMarkdown(md => editor.markdown!.parse(md), markdown, compositeKindsOf(editor)),\n structure: (editor, blocks) => {\n const { schema } = editor\n return structureBlocks(schema, blocks.map(block => schema.nodeFromJSON(block)), structureOf(editor), STRUCTURE_STAGE_LEVEL, compositeKindsOf(editor)).map(node => node.toJSON())\n },\n migrateContent: migrateLegacyContent,\n normalize: (editor, blocks) => normalizeReferences(blocks, compositeIdsOf(editor.state.doc)),\n },\n conversions: compositeConversions(options.kinds),\n aiContext: editor => ({\n kinds: compositeKindsOf(editor).map(({ id, label, fields, ai }) => ({ id, label, fields, ...(ai?.purpose && { purpose: ai.purpose }) })),\n structure: structureOf(editor),\n blocks: [REFERENCE_AI_BLOCK],\n }),\n // A Baustein derived from another block hands the model that source block's Markdown.\n aiBlockData: ({ editor, node }) => {\n const from = derivationOf(node)?.from\n const source = from && 'block' in from ? findBlockById(editor.state.doc, from.block)?.node : undefined\n // i18n-ignore: model-facing data label (German prompt text, not UI)\n return source?.type.name === 'composite' ? [{ label: `Quelle: ${source.child(0).textContent.trim()}`, text: bodyMarkdown(editor, source) }] : []\n },\n }\n}\n\nconst COMPOSITE_TOOLBAR_GROUPS: ToolbarGroupDef[] = [{ id: 'composites', order: 60, labelKey: 'palette.group.composites' }]\n\n/**\n * Converting headings to Bausteine and back: the checks and actions the toolbar's „Gliederung umwandeln“ menu and the\n * `/gliedern*` and `/aufloesen*` commands share, so both placements gate and act identically. They read the scope and\n * default kind from the settings at call time.\n */\nfunction structureActions({ settings }: FeatureContext) {\n const groupOptions = (recursive: boolean) => ({ recursive, scope: settings.get().editing.headingConversionScope, kind: settings.get().blocks.defaultKind })\n const flattenOptions = (recursive: boolean) => ({ recursive, scope: settings.get().editing.headingConversionScope })\n return {\n canGroup: (editor: Editor, recursive: boolean) => editor.can().convertHeadingsToComposites(groupOptions(recursive)),\n canFlatten: (editor: Editor, recursive: boolean) => editor.can().convertCompositesToHeadings(flattenOptions(recursive)),\n group: (editor: Editor, recursive: boolean) => void editor.chain().focus().convertHeadingsToComposites(groupOptions(recursive)).run(),\n flatten: (editor: Editor, recursive: boolean) => void editor.chain().focus().convertCompositesToHeadings(flattenOptions(recursive)).run(),\n }\n}\n\n/**\n * The commands of the composites feature, each declared once. Toolbar group beside the inserts: the default kind's\n * insert button (it follows the setting, so label/icon/shortcut/`creates` are getters read at render time), „In\n * Baustein umwandeln“ (one entry per kind for the caret's block) and „Gliederung umwandeln“ (headings <-> composites in\n * both directions, the preferred structure's direction first). `/` menu: one command per kind (`creates` that kind, so\n * the insert guard hides kinds the surrounding Baustein does not accept) and the four heading conversions.\n */\nfunction compositeCommands<C>(ctx: FeatureContext, kinds: readonly CompositeKind[]): CommandDef<C>[] {\n const { settings, t } = ctx\n const defaultKind = () => compositeKind(kinds, settings.get().blocks.defaultKind)\n const { canGroup, canFlatten, group, flatten } = structureActions(ctx)\n\n function kindItems(editor: Editor): MenuItem[] {\n return [\n { type: 'label', label: t('composites.menu.kindHeading') },\n ...compositeKindsOf(editor).map((kind): MenuItem => {\n const target = { type: 'composite', kind: kind.id } as const\n return { label: kind.label, icon: kind.icon, disabled: !editor.can().convertBlockTo(target), onSelect: () => editor.chain().focus().convertBlockTo(target).run() }\n }),\n ]\n }\n\n function structureItems(editor: Editor): MenuItem[] {\n const structure = settings.get().blocks.structure\n const abilities = abilitiesAtSelection(editor)\n const composite = abilities.has(ABILITY.composite)\n const headings = abilities.has(ABILITY.headings)\n const sep: MenuItem = { type: 'separator' }\n const toComposites: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toComposites') },\n { label: t('composites.menu.toComposites.top'), description: t('composites.menu.toComposites.top.description'), icon: 'i-lucide-layers', disabled: !composite || !canGroup(editor, false), onSelect: () => group(editor, false) },\n { label: t('composites.menu.toComposites.all'), description: t('composites.menu.toComposites.all.description'), icon: 'i-lucide-list-tree', disabled: !composite || !canGroup(editor, true), onSelect: () => group(editor, true) },\n ]\n const toHeadings: MenuItem[] = [\n { type: 'label', label: t('composites.menu.toHeadings') },\n { label: t('composites.menu.toHeadings.top'), description: t('composites.menu.toHeadings.top.description'), icon: 'i-lucide-heading', disabled: !headings || !canFlatten(editor, false), onSelect: () => flatten(editor, false) },\n { label: t('composites.menu.toHeadings.all'), description: t('composites.menu.toHeadings.all.description'), icon: 'i-lucide-align-left', disabled: !headings || !canFlatten(editor, true), onSelect: () => flatten(editor, true) },\n ]\n const entry = editorEntryOf(editor)\n // The settings entry exists only while some feature contributes a tab to open.\n const settingsEntry: MenuItem[] = entry && settingsTabsOf(entry.preset, entry.ctx.app).length\n ? [sep, { label: t('composites.menu.settings'), icon: 'i-lucide-settings-2', onSelect: () => entry.ui.openSettings('editing') }]\n : []\n return [\n { type: 'label', label: t('composites.menu.preferred', { mode: t(STRUCTURE_MODE_KEYS[structure].labelKey) }) },\n ...(structure === 'composite' ? [...toComposites, sep, ...toHeadings] : [...toHeadings, sep, ...toComposites]),\n ...settingsEntry,\n ]\n }\n\n const insertKind = (kind: string, slashId: string, label: string, icon: string): CommandDef<C> => ({\n id: `composite.${kind}`,\n slash: { id: slashId },\n creates: { type: 'composite', attrs: { kind } },\n icon,\n label,\n ability: ABILITY.composite,\n run: (editor) => { editor.chain().focus().insertComposite(kind).run() },\n })\n\n return [\n {\n id: 'insert',\n toolbar: { group: 'composites', order: 10 },\n // Getters: the default kind arrives with the server settings; the toolbar reads them at render time.\n get icon() { return defaultKind().icon },\n get label() { return defaultKind().label },\n // Mod-Shift-a (CompositeNode) always inserts a `section`, so only then is it shown as the shortcut.\n get kbds() { return defaultKind().id === 'section' ? ['meta', 'shift', 'a'] : undefined },\n get creates() { return { type: 'composite', attrs: { kind: defaultKind().id } } },\n ability: ABILITY.composite,\n can: editor => editor.can().insertComposite(defaultKind().id),\n run: (editor) => { editor.chain().focus().insertComposite(defaultKind().id).run() },\n },\n {\n id: 'to-kind',\n toolbar: { group: 'composites', order: 20 },\n icon: 'i-lucide-replace',\n label: t('composites.toolbar.toKind'),\n ability: ABILITY.composite,\n can: editor => kindItems(editor).some(item => item.type !== 'label' && !item.disabled),\n menu: kindItems,\n },\n {\n id: 'structure',\n toolbar: { group: 'composites', order: 30 },\n icon: 'i-lucide-list-tree',\n label: t('composites.toolbar.structure'),\n can: editor => canGroup(editor, true) || canFlatten(editor, true),\n menu: structureItems,\n },\n insertKind('section', 'abschnitt', t('composites.slash.section'), 'i-lucide-layers'),\n ...kinds.filter(kind => kind.id !== 'section').map(kind => insertKind(kind.id, kind.id, kind.label, kind.icon)),\n { id: 'gliedern', slash: {}, label: t('composites.slash.group'), icon: 'i-lucide-layers', ability: ABILITY.composite, can: editor => canGroup(editor, false), run: editor => group(editor, false) },\n { id: 'gliedern-alle', slash: {}, label: t('composites.slash.groupAll'), icon: 'i-lucide-list-tree', ability: ABILITY.composite, can: editor => canGroup(editor, true), run: editor => group(editor, true) },\n { id: 'aufloesen', slash: {}, label: t('composites.slash.flatten'), icon: 'i-lucide-heading', ability: ABILITY.headings, can: editor => canFlatten(editor, false), run: editor => flatten(editor, false) },\n { id: 'aufloesen-alle', slash: {}, label: t('composites.slash.flattenAll'), icon: 'i-lucide-align-left', ability: ABILITY.headings, can: editor => canFlatten(editor, true), run: editor => flatten(editor, true) },\n { id: 'verweis', slash: {}, label: t('composites.reference.insert'), icon: 'i-lucide-link-2', ability: ABILITY.reference, run: (editor) => { editor.chain().focus().insertContent(REFERENCE_TRIGGER).run() } },\n ]\n}\n"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { CompositeKind } from "./kinds.js";
|
|
|
2
2
|
import { CompositeFence, FenceSegment, splitCompositeFences } from "../../core/fences.js";
|
|
3
3
|
import { JSONContent } from "@tiptap/core";
|
|
4
4
|
//#region src/features/composites/fences.d.ts
|
|
5
|
-
/** `inner` fenced as composite of `kind`: `::: kind {meta}` (meta JSON only when non-empty), `inner`, `:::`. */
|
|
6
|
-
export declare function compositeFence(kind: string, meta: Record<string, unknown>, inner: string): string;
|
|
5
|
+
/** `inner` fenced as composite of `kind`: `::: kind #id {meta}` (`#id` only with an `id`, meta JSON only when non-empty), `inner`, `:::`. */
|
|
6
|
+
export declare function compositeFence(kind: string, meta: Record<string, unknown>, inner: string, id?: string): string;
|
|
7
7
|
/**
|
|
8
8
|
* Markdown segments parsed, fences of a registered kind turned into composites, in order. A fence of any other kind
|
|
9
9
|
* becomes an `opaqueFence` that keeps its text verbatim.
|
|
@@ -12,7 +12,8 @@ export declare function blocksFromMarkdown(parse: (md: string) => JSONContent, m
|
|
|
12
12
|
/**
|
|
13
13
|
* JSON of a composite built from the fence body: first `#`-heading → title, first blockquote directly after →
|
|
14
14
|
* description, a `Tags:` line → tags, rest → body (recursing for nested fences). Missing title → empty title; empty
|
|
15
|
-
* body → [paragraph]. Meta of a known kind keeps only that kind's fields
|
|
15
|
+
* body → [paragraph]. Meta of a known kind keeps only that kind's fields, plus provenance (`derivation`) and the
|
|
16
|
+
* bibliographic record (`bib`), which any kind may carry.
|
|
16
17
|
*/
|
|
17
18
|
export declare function compositeFromMarkdown(parse: (md: string) => JSONContent, fence: CompositeFence, kinds: readonly CompositeKind[]): JSONContent;
|
|
18
19
|
//#endregion
|
|
@@ -1,8 +1,50 @@
|
|
|
1
1
|
import { opaqueFenceJSON, splitCompositeFences } from "../../core/fences.js";
|
|
2
|
+
import { DERIVATION_KEY, keptMeta } from "./meta-keys.js";
|
|
2
3
|
//#region src/features/composites/fences.ts
|
|
3
|
-
/** `inner` fenced as composite of `kind`: `::: kind {meta}` (meta JSON only when non-empty), `inner`, `:::`. */
|
|
4
|
-
function compositeFence(kind, meta, inner) {
|
|
5
|
-
|
|
4
|
+
/** `inner` fenced as composite of `kind`: `::: kind #id {meta}` (`#id` only with an `id`, meta JSON only when non-empty), `inner`, `:::`. */
|
|
5
|
+
function compositeFence(kind, meta, inner, id) {
|
|
6
|
+
const parts = [`::: ${kind}`];
|
|
7
|
+
if (id) parts.push(`#${id}`);
|
|
8
|
+
if (Object.keys(meta).length) parts.push(JSON.stringify(meta));
|
|
9
|
+
return `${parts.join(" ")}\n${inner}\n:::`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `json` with the `id` attr removed from every composite that nothing in `json` references: the Markdown renderer writes
|
|
13
|
+
* the id of the composites that still have one. References are `reference` nodes (`target`) and meta values of `reference`
|
|
14
|
+
* fields of the composite's kind. The input is not modified; unchanged subtrees are shared.
|
|
15
|
+
*/
|
|
16
|
+
function withReferencedFenceIds(json, kinds) {
|
|
17
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
18
|
+
let anyId = false;
|
|
19
|
+
const collect = (node) => {
|
|
20
|
+
if (node.type === "reference" && typeof node.attrs?.target === "string") referenced.add(node.attrs.target);
|
|
21
|
+
if (node.type === "composite") {
|
|
22
|
+
if (typeof node.attrs?.id === "string" && node.attrs.id) anyId = true;
|
|
23
|
+
const meta = node.attrs?.meta;
|
|
24
|
+
if (meta && typeof meta === "object") for (const field of kinds.find((kind) => kind.id === node.attrs?.kind)?.fields ?? []) {
|
|
25
|
+
const value = meta[field.key];
|
|
26
|
+
if (field.type === "reference" && typeof value === "string" && value) referenced.add(value);
|
|
27
|
+
}
|
|
28
|
+
const sourceBlock = node.attrs?.meta?.[DERIVATION_KEY]?.from?.block;
|
|
29
|
+
if (typeof sourceBlock === "string" && sourceBlock) referenced.add(sourceBlock);
|
|
30
|
+
}
|
|
31
|
+
node.content?.forEach(collect);
|
|
32
|
+
};
|
|
33
|
+
collect(json);
|
|
34
|
+
if (!anyId) return json;
|
|
35
|
+
const strip = (node) => {
|
|
36
|
+
const content = node.content?.map(strip);
|
|
37
|
+
const changed = content?.some((child, index) => child !== node.content[index]);
|
|
38
|
+
const dropId = node.type === "composite" && typeof node.attrs?.id === "string" && !referenced.has(node.attrs.id);
|
|
39
|
+
if (!dropId && !changed) return node;
|
|
40
|
+
const { id: _id, ...attrs } = node.attrs ?? {};
|
|
41
|
+
return {
|
|
42
|
+
...node,
|
|
43
|
+
...dropId ? { attrs } : {},
|
|
44
|
+
...changed ? { content } : {}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
return strip(json);
|
|
6
48
|
}
|
|
7
49
|
/**
|
|
8
50
|
* Markdown segments parsed, fences of a registered kind turned into composites, in order. A fence of any other kind
|
|
@@ -28,7 +70,8 @@ function inlineOf(parse, md) {
|
|
|
28
70
|
/**
|
|
29
71
|
* JSON of a composite built from the fence body: first `#`-heading → title, first blockquote directly after →
|
|
30
72
|
* description, a `Tags:` line → tags, rest → body (recursing for nested fences). Missing title → empty title; empty
|
|
31
|
-
* body → [paragraph]. Meta of a known kind keeps only that kind's fields
|
|
73
|
+
* body → [paragraph]. Meta of a known kind keeps only that kind's fields, plus provenance (`derivation`) and the
|
|
74
|
+
* bibliographic record (`bib`), which any kind may carry.
|
|
32
75
|
*/
|
|
33
76
|
function compositeFromMarkdown(parse, fence, kinds) {
|
|
34
77
|
const lines = fence.inner.split("\n");
|
|
@@ -55,12 +98,13 @@ function compositeFromMarkdown(parse, fence, kinds) {
|
|
|
55
98
|
i++;
|
|
56
99
|
}
|
|
57
100
|
const body = blocksFromMarkdown(parse, lines.slice(i).join("\n"), kinds);
|
|
58
|
-
const
|
|
59
|
-
const meta =
|
|
101
|
+
const kind = kinds.find((candidate) => candidate.id === fence.kind);
|
|
102
|
+
const meta = kind ? keptMeta(kind, fence.meta) : fence.meta;
|
|
60
103
|
return {
|
|
61
104
|
type: "composite",
|
|
62
105
|
attrs: {
|
|
63
106
|
kind: fence.kind,
|
|
107
|
+
...fence.id && { id: fence.id },
|
|
64
108
|
meta
|
|
65
109
|
},
|
|
66
110
|
content: [
|
|
@@ -81,6 +125,6 @@ function compositeFromMarkdown(parse, fence, kinds) {
|
|
|
81
125
|
};
|
|
82
126
|
}
|
|
83
127
|
//#endregion
|
|
84
|
-
export { blocksFromMarkdown, compositeFence, compositeFromMarkdown, splitCompositeFences };
|
|
128
|
+
export { blocksFromMarkdown, compositeFence, compositeFromMarkdown, splitCompositeFences, withReferencedFenceIds };
|
|
85
129
|
|
|
86
130
|
//# sourceMappingURL=fences.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fences.js","names":[],"sources":["../../../src/features/composites/fences.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport { type CompositeFence, opaqueFenceJSON, splitCompositeFences } from '../../core/fences'\nimport type { CompositeKind } from './kinds'\n\n// Inverse of the composite nodes' renderMarkdown: `::: kind {meta}`, `## title`, `> description`, `Tags: #a #b`, body,\n// `:::`. The fence grammar itself (`splitCompositeFences`) is shared with the Markdown entry (`core/fences`).\nexport { type CompositeFence, type FenceSegment, splitCompositeFences } from '../../core/fences'\n\n/** `inner` fenced as composite of `kind`: `::: kind {meta}` (meta JSON only when non-empty), `inner`, `:::`. */\nexport function compositeFence(kind: string, meta: Record<string, unknown>, inner: string): string {\n const opener = Object.keys(meta).length ? `::: ${kind} ${JSON.stringify(meta)}` : `::: ${kind}`\n return `${opener}\\n${inner}\\n:::`\n}\n\n/**\n * Markdown segments parsed, fences of a registered kind turned into composites, in order. A fence of any other kind\n * becomes an `opaqueFence` that keeps its text verbatim.\n */\nexport function blocksFromMarkdown(parse: (md: string) => JSONContent, markdown: string, kinds: readonly CompositeKind[]): JSONContent[] {\n return splitCompositeFences(markdown).flatMap((segment) => {\n if (!('inner' in segment)) return parse(segment.markdown).content ?? []\n return kinds.some(kind => kind.id === segment.kind) ? [compositeFromMarkdown(parse, segment, kinds)] : [opaqueFenceJSON(segment)]\n })\n}\n\n/** Inline content of the first textblock `parse` makes of `md`. */\nfunction inlineOf(parse: (md: string) => JSONContent, md: string): JSONContent[] | undefined {\n let found: JSONContent[] | undefined\n const walk = (node: JSONContent): void => {\n if (found) return\n if (node.content?.some(child => child.type === 'text')) found = node.content\n else node.content?.forEach(walk)\n }\n if (md.trim()) walk(parse(md))\n return found?.length ? found : undefined\n}\n\n/**\n * JSON of a composite built from the fence body: first `#`-heading → title, first blockquote directly after →\n * description, a `Tags:` line → tags, rest → body (recursing for nested fences). Missing title → empty title; empty\n * body → [paragraph]. Meta of a known kind keeps only that kind's fields.\n */\nexport function compositeFromMarkdown(parse: (md: string) => JSONContent, fence: CompositeFence, kinds: readonly CompositeKind[]): JSONContent {\n const lines = fence.inner.split('\\n')\n let i = 0\n const skipBlank = () => {\n while (i < lines.length && !lines[i]!.trim()) i++\n }\n skipBlank()\n let title: JSONContent[] | undefined\n const heading = /^\\s*#{1,6}(?:\\s+(.*?))?\\s*#*\\s*$/.exec(lines[i] ?? '')\n if (heading) {\n title = inlineOf(parse, heading[1] ?? '')\n i++\n skipBlank()\n }\n const quote: string[] = []\n while (i < lines.length && /^\\s*>/.test(lines[i]!)) quote.push(lines[i++]!.replace(/^\\s*>\\s?/, ''))\n const description = quote.length ? inlineOf(parse, quote.join('\\n')) : undefined\n skipBlank()\n let tags: string[] = []\n const tagLine = /^\\s*Tags:\\s*(.*)$/i.exec(lines[i] ?? '')\n if (tagLine) {\n tags = [...new Set([...tagLine[1]!.matchAll(/#?([\\p{L}\\p{N}_-]+)/gu)].map(m => m[1]!.toLowerCase()))]\n i++\n }\n const body = blocksFromMarkdown(parse, lines.slice(i).join('\\n'), kinds)\n\n // A kind outside `kinds` (only reachable when called directly; `blocksFromMarkdown` makes those fences opaque) keeps its id (the views fall back via `compositeKind()`) and its meta as given.\n const fields = kinds.find(kind => kind.id === fence.kind)?.fields.map(field => field.key)\n const meta = fields ? Object.fromEntries(Object.entries(fence.meta).filter(([key]) => fields.includes(key))) : fence.meta\n return {\n type: 'composite',\n attrs: { kind: fence.kind, meta },\n content: [\n title ? { type: 'compositeTitle', content: title } : { type: 'compositeTitle' },\n description ? { type: 'compositeDescription', content: description } : { type: 'compositeDescription' },\n { type: 'compositeTags', attrs: { tags } },\n ...(body.length ? body : [{ type: 'paragraph' }]),\n ],\n }\n}\n"],"mappings":";;;AASA,SAAgB,eAAe,MAAc,MAA+B,OAAuB;CAEjG,OAAO,GADQ,OAAO,KAAK,IAAI,CAAC,CAAC,SAAS,OAAO,KAAK,GAAG,KAAK,UAAU,IAAI,MAAM,OAAO,OACxE,IAAI,MAAM;AAC7B;;;;;AAMA,SAAgB,mBAAmB,OAAoC,UAAkB,OAAgD;CACvI,OAAO,qBAAqB,QAAQ,CAAC,CAAC,SAAS,YAAY;EACzD,IAAI,EAAE,WAAW,UAAU,OAAO,MAAM,QAAQ,QAAQ,CAAC,CAAC,WAAW,CAAC;EACtE,OAAO,MAAM,MAAK,SAAQ,KAAK,OAAO,QAAQ,IAAI,IAAI,CAAC,sBAAsB,OAAO,SAAS,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC;CAClI,CAAC;AACH;;AAGA,SAAS,SAAS,OAAoC,IAAuC;CAC3F,IAAI;CACJ,MAAM,QAAQ,SAA4B;EACxC,IAAI,OAAO;EACX,IAAI,KAAK,SAAS,MAAK,UAAS,MAAM,SAAS,MAAM,GAAG,QAAQ,KAAK;OAChE,KAAK,SAAS,QAAQ,IAAI;CACjC;CACA,IAAI,GAAG,KAAK,GAAG,KAAK,MAAM,EAAE,CAAC;CAC7B,OAAO,OAAO,SAAS,QAAQ,KAAA;AACjC;;;;;;AAOA,SAAgB,sBAAsB,OAAoC,OAAuB,OAA8C;CAC7I,MAAM,QAAQ,MAAM,MAAM,MAAM,IAAI;CACpC,IAAI,IAAI;CACR,MAAM,kBAAkB;EACtB,OAAO,IAAI,MAAM,UAAU,CAAC,MAAM,EAAE,CAAE,KAAK,GAAG;CAChD;CACA,UAAU;CACV,IAAI;CACJ,MAAM,UAAU,mCAAmC,KAAK,MAAM,MAAM,EAAE;CACtE,IAAI,SAAS;EACX,QAAQ,SAAS,OAAO,QAAQ,MAAM,EAAE;EACxC;EACA,UAAU;CACZ;CACA,MAAM,QAAkB,CAAC;CACzB,OAAO,IAAI,MAAM,UAAU,QAAQ,KAAK,MAAM,EAAG,GAAG,MAAM,KAAK,MAAM,IAAI,CAAE,QAAQ,YAAY,EAAE,CAAC;CAClG,MAAM,cAAc,MAAM,SAAS,SAAS,OAAO,MAAM,KAAK,IAAI,CAAC,IAAI,KAAA;CACvE,UAAU;CACV,IAAI,OAAiB,CAAC;CACtB,MAAM,UAAU,qBAAqB,KAAK,MAAM,MAAM,EAAE;CACxD,IAAI,SAAS;EACX,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAE,SAAS,uBAAuB,CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE,CAAE,YAAY,CAAC,CAAC,CAAC;EACpG;CACF;CACA,MAAM,OAAO,mBAAmB,OAAO,MAAM,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,KAAK;CAGvE,MAAM,SAAS,MAAM,MAAK,SAAQ,KAAK,OAAO,MAAM,IAAI,CAAC,EAAE,OAAO,KAAI,UAAS,MAAM,GAAG;CACxF,MAAM,OAAO,SAAS,OAAO,YAAY,OAAO,QAAQ,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,SAAS,OAAO,SAAS,GAAG,CAAC,CAAC,IAAI,MAAM;CACrH,OAAO;EACL,MAAM;EACN,OAAO;GAAE,MAAM,MAAM;GAAM;EAAK;EAChC,SAAS;GACP,QAAQ;IAAE,MAAM;IAAkB,SAAS;GAAM,IAAI,EAAE,MAAM,iBAAiB;GAC9E,cAAc;IAAE,MAAM;IAAwB,SAAS;GAAY,IAAI,EAAE,MAAM,uBAAuB;GACtG;IAAE,MAAM;IAAiB,OAAO,EAAE,KAAK;GAAE;GACzC,GAAI,KAAK,SAAS,OAAO,CAAC,EAAE,MAAM,YAAY,CAAC;EACjD;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"fences.js","names":[],"sources":["../../../src/features/composites/fences.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport { type CompositeFence, opaqueFenceJSON, splitCompositeFences } from '../../core/fences'\nimport { DERIVATION_KEY, keptMeta } from './meta-keys'\nimport type { CompositeKind } from './kinds'\n\n// Inverse of the composite nodes' renderMarkdown: `::: kind #id {meta}`, `## title`, `> description`, `Tags: #a #b`, body,\n// `:::`. The fence grammar itself (`splitCompositeFences`) is shared with the Markdown entry (`core/fences`).\n//\n// Block ids in fences: a Baustein written to Markdown carries its block id in the opener (`::: paper #<uuid> {meta}`,\n// Pandoc-like `#id` between kind and meta) only when something in the same serialized content points at it — a `reference`\n// chip (`[@<id>, S. 3]`) or a `reference` meta field. Every other fence stays `::: kind {meta}`. Parsing restores the id\n// as `attrs.id`, so after a Markdown round trip (source-mode commit, import) the `[@<id>]` tokens still resolve to\n// the same Bausteine. `withReferencedFenceIds` is the pre-pass that decides which ids are written.\nexport { type CompositeFence, type FenceSegment, splitCompositeFences } from '../../core/fences'\n\n/** `inner` fenced as composite of `kind`: `::: kind #id {meta}` (`#id` only with an `id`, meta JSON only when non-empty), `inner`, `:::`. */\nexport function compositeFence(kind: string, meta: Record<string, unknown>, inner: string, id?: string): string {\n const parts = [`::: ${kind}`]\n if (id) parts.push(`#${id}`)\n if (Object.keys(meta).length) parts.push(JSON.stringify(meta))\n return `${parts.join(' ')}\\n${inner}\\n:::`\n}\n\n/**\n * `json` with the `id` attr removed from every composite that nothing in `json` references: the Markdown renderer writes\n * the id of the composites that still have one. References are `reference` nodes (`target`) and meta values of `reference`\n * fields of the composite's kind. The input is not modified; unchanged subtrees are shared.\n */\nexport function withReferencedFenceIds(json: JSONContent, kinds: readonly CompositeKind[]): JSONContent {\n const referenced = new Set<string>()\n let anyId = false\n const collect = (node: JSONContent): void => {\n if (node.type === 'reference' && typeof node.attrs?.target === 'string') referenced.add(node.attrs.target)\n if (node.type === 'composite') {\n if (typeof node.attrs?.id === 'string' && node.attrs.id) anyId = true\n const meta: unknown = node.attrs?.meta\n if (meta && typeof meta === 'object') {\n for (const field of kinds.find(kind => kind.id === node.attrs?.kind)?.fields ?? []) {\n const value = (meta as Record<string, unknown>)[field.key]\n if (field.type === 'reference' && typeof value === 'string' && value) referenced.add(value)\n }\n }\n // A block-derived Baustein points at its source (`meta.derivation.from.block`): the source keeps its id across a round trip.\n const sourceBlock: unknown = node.attrs?.meta?.[DERIVATION_KEY]?.from?.block\n if (typeof sourceBlock === 'string' && sourceBlock) referenced.add(sourceBlock)\n }\n node.content?.forEach(collect)\n }\n collect(json)\n if (!anyId) return json\n const strip = (node: JSONContent): JSONContent => {\n const content = node.content?.map(strip)\n const changed = content?.some((child, index) => child !== node.content![index])\n const dropId = node.type === 'composite' && typeof node.attrs?.id === 'string' && !referenced.has(node.attrs.id)\n if (!dropId && !changed) return node\n const { id: _id, ...attrs } = node.attrs ?? {}\n return { ...node, ...(dropId ? { attrs } : {}), ...(changed ? { content } : {}) }\n }\n return strip(json)\n}\n\n/**\n * Markdown segments parsed, fences of a registered kind turned into composites, in order. A fence of any other kind\n * becomes an `opaqueFence` that keeps its text verbatim.\n */\nexport function blocksFromMarkdown(parse: (md: string) => JSONContent, markdown: string, kinds: readonly CompositeKind[]): JSONContent[] {\n return splitCompositeFences(markdown).flatMap((segment) => {\n if (!('inner' in segment)) return parse(segment.markdown).content ?? []\n return kinds.some(kind => kind.id === segment.kind) ? [compositeFromMarkdown(parse, segment, kinds)] : [opaqueFenceJSON(segment)]\n })\n}\n\n/** Inline content of the first textblock `parse` makes of `md`. */\nfunction inlineOf(parse: (md: string) => JSONContent, md: string): JSONContent[] | undefined {\n let found: JSONContent[] | undefined\n const walk = (node: JSONContent): void => {\n if (found) return\n if (node.content?.some(child => child.type === 'text')) found = node.content\n else node.content?.forEach(walk)\n }\n if (md.trim()) walk(parse(md))\n return found?.length ? found : undefined\n}\n\n/**\n * JSON of a composite built from the fence body: first `#`-heading → title, first blockquote directly after →\n * description, a `Tags:` line → tags, rest → body (recursing for nested fences). Missing title → empty title; empty\n * body → [paragraph]. Meta of a known kind keeps only that kind's fields, plus provenance (`derivation`) and the\n * bibliographic record (`bib`), which any kind may carry.\n */\nexport function compositeFromMarkdown(parse: (md: string) => JSONContent, fence: CompositeFence, kinds: readonly CompositeKind[]): JSONContent {\n const lines = fence.inner.split('\\n')\n let i = 0\n const skipBlank = () => {\n while (i < lines.length && !lines[i]!.trim()) i++\n }\n skipBlank()\n let title: JSONContent[] | undefined\n const heading = /^\\s*#{1,6}(?:\\s+(.*?))?\\s*#*\\s*$/.exec(lines[i] ?? '')\n if (heading) {\n title = inlineOf(parse, heading[1] ?? '')\n i++\n skipBlank()\n }\n const quote: string[] = []\n while (i < lines.length && /^\\s*>/.test(lines[i]!)) quote.push(lines[i++]!.replace(/^\\s*>\\s?/, ''))\n const description = quote.length ? inlineOf(parse, quote.join('\\n')) : undefined\n skipBlank()\n let tags: string[] = []\n const tagLine = /^\\s*Tags:\\s*(.*)$/i.exec(lines[i] ?? '')\n if (tagLine) {\n tags = [...new Set([...tagLine[1]!.matchAll(/#?([\\p{L}\\p{N}_-]+)/gu)].map(m => m[1]!.toLowerCase()))]\n i++\n }\n const body = blocksFromMarkdown(parse, lines.slice(i).join('\\n'), kinds)\n\n // A kind outside `kinds` (only reachable when called directly; `blocksFromMarkdown` makes those fences opaque) keeps its id (the views fall back via `compositeKind()`) and its meta as given.\n const kind = kinds.find(candidate => candidate.id === fence.kind)\n const meta = kind ? keptMeta(kind, fence.meta) : fence.meta\n return {\n type: 'composite',\n attrs: { kind: fence.kind, ...(fence.id && { id: fence.id }), meta },\n content: [\n title ? { type: 'compositeTitle', content: title } : { type: 'compositeTitle' },\n description ? { type: 'compositeDescription', content: description } : { type: 'compositeDescription' },\n { type: 'compositeTags', attrs: { tags } },\n ...(body.length ? body : [{ type: 'paragraph' }]),\n ],\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
import { CSL_TYPES, CslDate, CslItem, CslName, CslType } from "../../core/backend-types.js";
|
|
1
2
|
import { CompositeAiBrief, compositeAiBrief } from "./ai-brief.js";
|
|
2
|
-
import { CompositeKind, CompositeKindAi, CompositeMetaField, compositeKind, defaultCompositeKinds, kindAccepts } from "./kinds.js";
|
|
3
|
-
import { CompositeMention, CompositeRow, compositeDescriptionText, compositeMetaWith, compositeOfRow, compositeRowAt, compositeRows, setCompositeDescription, setCompositeMetaField, setCompositeTags } from "./rows.js";
|
|
3
|
+
import { CompositeKind, CompositeKindAi, CompositeMetaField, SOURCE_MEDIA_TYPES, compositeKind, defaultCompositeKinds, kindAccepts } from "./kinds.js";
|
|
4
|
+
import { CompositeBacklink, CompositeMention, CompositeReference, CompositeRow, compositeBacklinks, compositeDescriptionText, compositeMetaWith, compositeOfRow, compositeRowAt, compositeRows, setCompositeDescription, setCompositeMetaField, setCompositeTags } from "./rows.js";
|
|
4
5
|
import { CompositeAnchor, CompositeAnchorsHandle, CompositeFrame, compositeSectionOf, observeCompositeAnchors } from "./anchors.js";
|
|
5
6
|
import { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeNode, CompositeOptions, CompositeStorage, CompositeTagsNode, CompositeTitleNode, compositeJSON, compositeKindsOf } from "./nodes.js";
|
|
7
|
+
import { REFERENCE_NODE, ReferenceAttrs, ReferenceNode, ReferenceOptions, ReferenceSuggestionPluginKey, referenceMarkdown } from "./reference.js";
|
|
6
8
|
import { CompositeNodeViews, compositeNodes } from "./node-views.js";
|
|
7
9
|
import { CompositeFeatureOptions, CompositesUi, compositeFeatureCore } from "./feature.js";
|
|
8
10
|
import { documentCompositeMarkdown, headingsMarkdown, markdownFileName } from "./markdown-export.js";
|
|
9
11
|
import { MoveVerdict, OutlineNode, canMoveBlockInto, compositeOutline, moveBlockInto, moveIntoVerdict } from "./outline.js";
|
|
12
|
+
import { SourceLocator, SourceReveal, parseLocator, revealSource, seekSource } from "./reveal-source.js";
|
|
10
13
|
import { AcceptedChildren, AcceptedChildrenOptions } from "./accepted-children.js";
|
|
11
14
|
import { CompositeKindCount, CompositeRowsHandle, CompositeRowsState, createCompositeRows } from "./rows-model.js";
|
|
12
15
|
import { CompositeInspector, CompositeInspectorSection, CompositeInspectorState, CompositeKindOption, compositeFieldText, createCompositeInspector } from "./inspector-model.js";
|
|
16
|
+
import { ReferenceTarget, referenceLabel, referenceTarget, referenceTitle } from "./reference-label.js";
|
|
17
|
+
import { referenceSuggestion } from "./reference-suggestion.js";
|
|
13
18
|
import { Structure, StructureStorage, structureOf } from "./structure.js";
|
|
14
19
|
import { STRUCTURE_MODE_KEYS } from "./structure-mode.js";
|
|
15
20
|
import { TREE_ROOT_KEYS } from "./tree-root.js";
|
|
@@ -17,6 +22,10 @@ import { compositeConversions, convertCompositeBlocks } from "./convert.js";
|
|
|
17
22
|
import { CompositeFence, FenceSegment, splitCompositeFences } from "../../core/fences.js";
|
|
18
23
|
import { blocksFromMarkdown, compositeFence, compositeFromMarkdown } from "./fences.js";
|
|
19
24
|
import { compositeChromeBlocks, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, structureBlocks } from "./heading-composites.js";
|
|
25
|
+
import { BIB_KEY, DERIVATION_KEY } from "./meta-keys.js";
|
|
26
|
+
import { bibOf, bibtexOf, citeFull, citeShort, cslOf, cslTypeOptions, yearOf } from "./bibliography.js";
|
|
27
|
+
import { Derivation, DerivationMethod, DerivationSource, bodyMarkdown, derivationOf, derivationState, renditionsOf, sourceOf } from "./derivation.js";
|
|
20
28
|
import { LEGACY_COMPOSITE_NODE, migrateLegacyContent } from "./legacy.js";
|
|
29
|
+
import { normalizeReferences, referencesFromText } from "./reference-text.js";
|
|
21
30
|
import { compositeSchemaExtensions } from "./schema.js";
|
|
22
|
-
export { AcceptedChildren, type AcceptedChildrenOptions, COMPOSITE_CHROME_COUNT, type CompositeAiBrief, type CompositeAnchor, type CompositeAnchorsHandle, CompositeDescriptionNode, type CompositeFeatureOptions, type CompositeFence, type CompositeFrame, type CompositeInspector, type CompositeInspectorSection, type CompositeInspectorState, type CompositeKind, type CompositeKindAi, type CompositeKindCount, type CompositeKindOption, type CompositeMention, type CompositeMetaField, CompositeNode, type CompositeNodeViews, type CompositeOptions, type CompositeRow, type CompositeRowsHandle, type CompositeRowsState, type CompositeStorage, CompositeTagsNode, CompositeTitleNode, type CompositesUi, type FenceSegment, LEGACY_COMPOSITE_NODE, type MoveVerdict, type OutlineNode, STRUCTURE_MODE_KEYS, Structure, type StructureStorage, TREE_ROOT_KEYS, blocksFromMarkdown, canMoveBlockInto, compositeAiBrief, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, defaultCompositeKinds, documentCompositeMarkdown, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, migrateLegacyContent, moveBlockInto, moveIntoVerdict, observeCompositeAnchors, setCompositeDescription, setCompositeMetaField, setCompositeTags, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf };
|
|
31
|
+
export { AcceptedChildren, type AcceptedChildrenOptions, BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, type CompositeAiBrief, type CompositeAnchor, type CompositeAnchorsHandle, type CompositeBacklink, CompositeDescriptionNode, type CompositeFeatureOptions, type CompositeFence, type CompositeFrame, type CompositeInspector, type CompositeInspectorSection, type CompositeInspectorState, type CompositeKind, type CompositeKindAi, type CompositeKindCount, type CompositeKindOption, type CompositeMention, type CompositeMetaField, CompositeNode, type CompositeNodeViews, type CompositeOptions, type CompositeReference, type CompositeRow, type CompositeRowsHandle, type CompositeRowsState, type CompositeStorage, CompositeTagsNode, CompositeTitleNode, type CompositesUi, type CslDate, type CslItem, type CslName, type CslType, DERIVATION_KEY, type Derivation, type DerivationMethod, type DerivationSource, type FenceSegment, LEGACY_COMPOSITE_NODE, type MoveVerdict, type OutlineNode, REFERENCE_NODE, type ReferenceAttrs, ReferenceNode, type ReferenceOptions, ReferenceSuggestionPluginKey, type ReferenceTarget, SOURCE_MEDIA_TYPES, STRUCTURE_MODE_KEYS, type SourceLocator, SourceReveal, Structure, type StructureStorage, TREE_ROOT_KEYS, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, canMoveBlockInto, citeFull, citeShort, compositeAiBrief, compositeBacklinks, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, cslOf, cslTypeOptions, defaultCompositeKinds, derivationOf, derivationState, documentCompositeMarkdown, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, migrateLegacyContent, moveBlockInto, moveIntoVerdict, normalizeReferences, observeCompositeAnchors, parseLocator, referenceLabel, referenceMarkdown, referenceSuggestion, referenceTarget, referenceTitle, referencesFromText, renditionsOf, revealSource, seekSource, setCompositeDescription, setCompositeMetaField, setCompositeTags, sourceOf, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf, yearOf };
|
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import { splitCompositeFences } from "../../core/fences.js";
|
|
2
|
-
import { compositeKind, defaultCompositeKinds, kindAccepts } from "./kinds.js";
|
|
2
|
+
import { SOURCE_MEDIA_TYPES, compositeKind, defaultCompositeKinds, kindAccepts } from "./kinds.js";
|
|
3
|
+
import { BIB_KEY, DERIVATION_KEY } from "./meta-keys.js";
|
|
3
4
|
import { blocksFromMarkdown, compositeFence, compositeFromMarkdown } from "./fences.js";
|
|
5
|
+
import { bodyMarkdown, derivationOf, derivationState, renditionsOf, sourceOf } from "./derivation.js";
|
|
4
6
|
import { compositeChromeBlocks, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, structureBlocks } from "./heading-composites.js";
|
|
5
7
|
import { COMPOSITE_CHROME_COUNT, CompositeDescriptionNode, CompositeNode, CompositeTagsNode, CompositeTitleNode, compositeJSON, compositeKindsOf } from "./nodes.js";
|
|
8
|
+
import { REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, referenceMarkdown } from "./reference.js";
|
|
9
|
+
import { CSL_TYPES } from "../../core/backend-types.js";
|
|
10
|
+
import { bibOf, bibtexOf, citeFull, citeShort, cslOf, cslTypeOptions, yearOf } from "./bibliography.js";
|
|
6
11
|
import { compositeAiBrief } from "./ai-brief.js";
|
|
7
12
|
import { compositeConversions, convertCompositeBlocks } from "./convert.js";
|
|
8
13
|
import { LEGACY_COMPOSITE_NODE, migrateLegacyContent } from "./legacy.js";
|
|
14
|
+
import { normalizeReferences, referencesFromText } from "./reference-text.js";
|
|
9
15
|
import { compositeSchemaExtensions } from "./schema.js";
|
|
10
|
-
import { compositeDescriptionText, compositeMetaWith, compositeOfRow, compositeRowAt, compositeRows, setCompositeDescription, setCompositeMetaField, setCompositeTags } from "./rows.js";
|
|
11
|
-
import { compositeSectionOf, observeCompositeAnchors } from "./anchors.js";
|
|
12
16
|
import { AcceptedChildren } from "./accepted-children.js";
|
|
13
17
|
import { documentCompositeMarkdown, headingsMarkdown, markdownFileName } from "./markdown-export.js";
|
|
14
18
|
import { compositeNodes } from "./node-views.js";
|
|
19
|
+
import { referenceLabel, referenceTarget, referenceTitle } from "./reference-label.js";
|
|
20
|
+
import { compositeBacklinks, compositeDescriptionText, compositeMetaWith, compositeOfRow, compositeRowAt, compositeRows, setCompositeDescription, setCompositeMetaField, setCompositeTags } from "./rows.js";
|
|
21
|
+
import { referenceSuggestion } from "./reference-suggestion.js";
|
|
22
|
+
import { SourceReveal, parseLocator, revealSource, seekSource } from "./reveal-source.js";
|
|
15
23
|
import { Structure, structureOf } from "./structure.js";
|
|
16
24
|
import { STRUCTURE_MODE_KEYS } from "./structure-mode.js";
|
|
17
25
|
import { compositeFeatureCore } from "./feature.js";
|
|
18
|
-
import {
|
|
26
|
+
import { compositeSectionOf, observeCompositeAnchors } from "./anchors.js";
|
|
19
27
|
import { createCompositeRows } from "./rows-model.js";
|
|
20
|
-
import { compositeFieldText, createCompositeInspector } from "./inspector-model.js";
|
|
21
28
|
import { TREE_ROOT_KEYS } from "./tree-root.js";
|
|
22
|
-
|
|
29
|
+
import { compositeFieldText, createCompositeInspector } from "./inspector-model.js";
|
|
30
|
+
import { canMoveBlockInto, compositeOutline, moveBlockInto, moveIntoVerdict } from "./outline.js";
|
|
31
|
+
export { AcceptedChildren, BIB_KEY, COMPOSITE_CHROME_COUNT, CSL_TYPES, CompositeDescriptionNode, CompositeNode, CompositeTagsNode, CompositeTitleNode, DERIVATION_KEY, LEGACY_COMPOSITE_NODE, REFERENCE_NODE, ReferenceNode, ReferenceSuggestionPluginKey, SOURCE_MEDIA_TYPES, STRUCTURE_MODE_KEYS, SourceReveal, Structure, TREE_ROOT_KEYS, bibOf, bibtexOf, blocksFromMarkdown, bodyMarkdown, canMoveBlockInto, citeFull, citeShort, compositeAiBrief, compositeBacklinks, compositeChromeBlocks, compositeConversions, compositeDescriptionText, compositeFeatureCore, compositeFence, compositeFieldText, compositeFromMarkdown, compositeJSON, compositeKind, compositeKindsOf, compositeMetaWith, compositeNodes, compositeOfRow, compositeOutline, compositeRowAt, compositeRows, compositeSchemaExtensions, compositeSectionOf, convertCompositeBlocks, createCompositeInspector, createCompositeRows, cslOf, cslTypeOptions, defaultCompositeKinds, derivationOf, derivationState, documentCompositeMarkdown, flattenCompositesToHeadings, groupHeadingsIntoComposites, headingGroupRange, headingsMarkdown, kindAccepts, markdownFileName, migrateLegacyContent, moveBlockInto, moveIntoVerdict, normalizeReferences, observeCompositeAnchors, parseLocator, referenceLabel, referenceMarkdown, referenceSuggestion, referenceTarget, referenceTitle, referencesFromText, renditionsOf, revealSource, seekSource, setCompositeDescription, setCompositeMetaField, setCompositeTags, sourceOf, splitCompositeFences, structureBlocks as structureCompositeBlocks, structureOf, yearOf };
|
|
@@ -60,7 +60,10 @@ export interface CompositeInspector {
|
|
|
60
60
|
setSearchTerm: (term: string) => void;
|
|
61
61
|
/** Schedules a tag search for the current term (the picker opened). */
|
|
62
62
|
searchTags: () => void;
|
|
63
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Writes the text `value` to the meta `field` of the focused Baustein; ignored while the editor is not editable and
|
|
65
|
+
* for structured fields (`isStructuredField`), whose values are not text and have their own editors.
|
|
66
|
+
*/
|
|
64
67
|
setField: (field: CompositeMetaField, value: unknown) => void;
|
|
65
68
|
/** Commits a pending description draft and detaches from the editor. Idempotent; the model is inert afterwards. */
|
|
66
69
|
dispose: () => void;
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { createStore } from "../../core/store.js";
|
|
2
1
|
import { metadataOf } from "../../core/metadata.js";
|
|
2
|
+
import { createStore } from "../../core/store.js";
|
|
3
3
|
import { METADATA_LIST } from "../../core/metadata-types.js";
|
|
4
|
+
import { normalizeTagName } from "../../core/tag-name.js";
|
|
4
5
|
import { compositeKindsOf } from "./nodes.js";
|
|
5
6
|
import { compositeDescriptionText, compositeOfRow, setCompositeDescription, setCompositeMetaField, setCompositeTags } from "./rows.js";
|
|
6
|
-
import { normalizeTagName } from "../../core/tag-name.js";
|
|
7
7
|
import { createCompositeRows } from "./rows-model.js";
|
|
8
8
|
//#region src/features/composites/inspector-model.ts
|
|
9
9
|
/** Pause after the last keystroke in the description before the draft is written to the document. */
|
|
10
10
|
const COMMIT_DELAY_MS = 600;
|
|
11
11
|
/** Pause after the last change of the tag search term before the metadata source is asked. */
|
|
12
12
|
const SEARCH_DELAY_MS = 150;
|
|
13
|
+
/** Fields whose value is not text (a block ID, a CSL item, a provenance record): the inspector hands them to `CompositeFieldEditor` and never writes a string to them. */
|
|
14
|
+
function isStructuredField(field) {
|
|
15
|
+
return field.type === "reference" || field.type === "bibliography" || field.type === "derivation";
|
|
16
|
+
}
|
|
13
17
|
/** The text of `field` in `row`'s meta as an input shows it: strings and numbers, otherwise empty. */
|
|
14
18
|
function compositeFieldText(row, field) {
|
|
15
19
|
const value = row?.meta[field.key];
|
|
@@ -232,7 +236,7 @@ function createCompositeInspector(editor) {
|
|
|
232
236
|
},
|
|
233
237
|
setField(field, value) {
|
|
234
238
|
const row = focusedRow();
|
|
235
|
-
if (editor && isEditable() && row) setCompositeMetaField(editor, row, field.key, value);
|
|
239
|
+
if (editor && isEditable() && row && !isStructuredField(field)) setCompositeMetaField(editor, row, field.key, value);
|
|
236
240
|
},
|
|
237
241
|
dispose() {
|
|
238
242
|
if (disposed) return;
|
|
@@ -250,6 +254,6 @@ function createCompositeInspector(editor) {
|
|
|
250
254
|
};
|
|
251
255
|
}
|
|
252
256
|
//#endregion
|
|
253
|
-
export { compositeFieldText, createCompositeInspector };
|
|
257
|
+
export { compositeFieldText, createCompositeInspector, isStructuredField };
|
|
254
258
|
|
|
255
259
|
//# sourceMappingURL=inspector-model.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector-model.js","names":[],"sources":["../../../src/features/composites/inspector-model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { metadataOf } from '../../core/metadata'\nimport { METADATA_LIST } from '../../core/metadata-types'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport { normalizeTagName } from '../../core/tag-name'\nimport type { CompositeMetaField } from './kinds'\nimport { compositeKindsOf } from './nodes'\nimport { compositeDescriptionText, compositeOfRow, type CompositeRow, setCompositeDescription, setCompositeMetaField, setCompositeTags } from './rows'\nimport { type CompositeRowsState, createCompositeRows } from './rows-model'\n\n/** Pause after the last keystroke in the description before the draft is written to the document. */\nconst COMMIT_DELAY_MS = 600\n/** Pause after the last change of the tag search term before the metadata source is asked. */\nconst SEARCH_DELAY_MS = 150\n\n/** Which section of the inspector shows: the document's facts, or the properties of the Baustein under the caret. */\nexport type CompositeInspectorSection = 'document' | 'composite'\n\n/** A kind the Baustein can be switched to, as the kind select lists it. */\nexport interface CompositeKindOption {\n value: string\n label: string\n icon: string\n}\n\n/** Everything the inspector renders (see `createCompositeInspector`): the live rows plus the inspector's own state. */\nexport interface CompositeInspectorState extends CompositeRowsState {\n /** `'composite'` only while the caret last was in the editor and a Baustein is focused, else `'document'`. */\n section: CompositeInspectorSection\n /** Whether the editor accepts edits; follows `setEditable` (see `createCompositeInspector`). */\n editable: boolean\n /** The description text as the user sees it in the focused Baustein's textarea; may be ahead of the document until it is committed. */\n draft: string\n /** The text typed into the tag search. */\n searchTerm: string\n /** Tag names the metadata source suggested for the latest search that was not superseded. */\n tagItems: string[]\n /** The kinds the editor was configured with, in configured order; empty without an editor. */\n kindOptions: CompositeKindOption[]\n /** How many Bausteine have a description. */\n summarized: number\n /** The focused Baustein has a description. */\n hasSummary: boolean\n}\n\n/** The inspector model of an editor: observable `state`, the actions of the panel, and `dispose()`. */\nexport interface CompositeInspector {\n readonly state: ReadonlyStore<CompositeInspectorState>\n /**\n * Reports whether the host's document-level input (its title field) has the focus. Only the rising edge switches\n * the section to `'document'`; the section stays there after the input blurs, until the editor takes the focus.\n */\n setDocumentFocused: (focused: boolean) => void\n /** Switches the focused Baustein to `kind`; ignored when it already has it or no Baustein is focused. */\n setKind: (kind: string) => void\n /**\n * The user typed `text` into the description. The draft is written to the document 600 ms after the last call and\n * on `blurDescription`; the Baustein focused at the first call of a pending draft is the one that is written.\n */\n inputDescription: (text: string) => void\n /**\n * The description textarea lost focus: writes the pending draft, then shows what the document holds. The draft\n * shows the normalized text after a write; after a refused write (a peer changed the description since the draft\n * started) it shows the peer's text.\n */\n blurDescription: () => void\n /** Replaces the tags of the focused Baustein. */\n setTags: (tags: readonly string[]) => void\n /** Creates the tag `raw` (normalized) on the focused Baustein and registers it with the metadata source; clears the search term. */\n createTag: (raw: string) => void\n /** Sets the tag search term and schedules a search for it. */\n setSearchTerm: (term: string) => void\n /** Schedules a tag search for the current term (the picker opened). */\n searchTags: () => void\n /** Writes `value` to the meta `field` of the focused Baustein; ignored while the editor is not editable. */\n setField: (field: CompositeMetaField, value: unknown) => void\n /** Commits a pending description draft and detaches from the editor. Idempotent; the model is inert afterwards. */\n dispose: () => void\n}\n\n/** The text of `field` in `row`'s meta as an input shows it: strings and numbers, otherwise empty. */\nexport function compositeFieldText(row: Pick<CompositeRow, 'meta'> | null, field: Pick<CompositeMetaField, 'key'>): string {\n const value = row?.meta[field.key]\n return typeof value === 'string' || typeof value === 'number' ? String(value) : ''\n}\n\nfunction sameState(a: CompositeInspectorState, b: CompositeInspectorState): boolean {\n return (Object.keys(a) as (keyof CompositeInspectorState)[]).every(key => Object.is(a[key], b[key]))\n}\n\n/**\n * The properties panel of `editor`: which section shows, the focused Baustein's description draft, the tag search\n * and the writes. Owns its own `createCompositeRows(editor)`, so a focus change and the rows it refers to arrive in\n * one notification and the draft is committed before it is replaced. Create one model per editor (a framework hook\n * follows an editor that changes); without an editor the state is empty and every action is ignored.\n *\n * Section: the caret is either in the host's input (`setDocumentFocused`) or in the editor. Only the editor's `focus`\n * event moves it to the editor (not `selectionUpdate`: collaboration sync moves the selection while the host's input\n * has the focus). A deleted Baustein falls back to the document section.\n *\n * `isEditable` is not reactive: `editable` follows it on every editor `transaction`, so whoever calls `setEditable`\n * must dispatch a transaction afterwards (`EditorSurface` does).\n *\n * Description: edits go to a local `draft` so the asynchronous re-read of the document never overwrites the text\n * (and moves the caret) while it is typed. `base` is the document text the draft started from; the write lands only\n * while the description still holds it, so a peer's change made meanwhile is never replaced. The draft is committed\n * 600 ms after typing pauses, on blur, when another Baustein takes the focus (before the draft is replaced), when\n * the panel leaves the Baustein section, and on `dispose()`. A commit is skipped when the editor is destroyed or not\n * editable, and refused when a peer changed the description; the draft then reloads the live text. A draft that is\n * not dirty follows every change of the focused description.\n *\n * Tag search: each term change restarts a 150 ms debounce; when it fires, the previous search is aborted and the\n * source is asked with a fresh `AbortSignal`. Results of aborted searches are dropped, errors of aborted searches\n * are silent, other errors are logged and keep the old suggestions.\n */\nexport function createCompositeInspector(editor: Editor | undefined): CompositeInspector {\n const rows = createCompositeRows(editor)\n const kindOptions: CompositeKindOption[] = editor && !editor.isDestroyed\n ? compositeKindsOf(editor).map(kind => ({ value: kind.id, label: kind.label, icon: kind.icon }))\n : []\n const isEditable = () => !!editor && !editor.isDestroyed && editor.isEditable\n const focusedRow = () => rows.state.get().focused\n\n let disposed = false\n\n // --- Section ---\n let caretIn: 'document' | 'editor' = 'document'\n let documentFocused = false\n let section: CompositeInspectorSection = 'document'\n let editable = isEditable()\n\n // --- Description draft ---\n let draft = ''\n let base = ''\n let dirty = false\n let pendingRow: CompositeRow | null = null\n let commitTimer: ReturnType<typeof setTimeout> | undefined\n // What the focused Baustein looked like at the last rows notification: a change of the key is a switch, a change of the description a peer's (or our own) write.\n let focusKey = focusedRow()?.key\n let focusDescription = focusedRow()?.description\n\n // --- Tag search ---\n let searchTerm = ''\n let tagItems: string[] = []\n let searchTimer: ReturnType<typeof setTimeout> | undefined\n let pendingSearch: AbortController | undefined\n\n let summarizedRows: CompositeRowsState['rows'] | undefined\n let summarized = 0\n const store = createStore<CompositeInspectorState>(snapshot())\n\n function snapshot(): CompositeInspectorState {\n const read = rows.state.get()\n if (read.rows !== summarizedRows) {\n summarizedRows = read.rows\n summarized = read.rows.filter(row => row.description.trim()).length\n }\n return {\n ...read,\n section,\n editable,\n draft,\n searchTerm,\n tagItems,\n kindOptions,\n summarized,\n hasSummary: !!read.focused?.description.trim(),\n }\n }\n\n function publish() {\n const next = snapshot()\n if (!sameState(store.get(), next)) store.set(next)\n }\n\n function load() {\n dirty = false\n pendingRow = null\n base = focusedRow()?.description ?? ''\n draft = base\n }\n\n /** Writes the pending draft; `false` when there was nothing to write or the write was refused. Does not touch `draft`. */\n function commit(): boolean {\n clearTimeout(commitTimer)\n if (!dirty || !pendingRow) return false\n dirty = false\n const row = pendingRow\n pendingRow = null\n if (!editor || editor.isDestroyed || !editor.isEditable) return false\n if (!setCompositeDescription(editor, row, draft, base)) return false\n base = compositeDescriptionText(draft)\n return true\n }\n\n function refreshSection() {\n const next = caretIn === 'editor' && focusedRow() ? 'composite' : 'document'\n if (section === 'composite' && next !== 'composite') commit()\n section = next\n }\n\n // A switch commits the draft of the previous Baustein first (`draft` still holds its text), then loads the new one.\n // A change of the description reaches an untouched draft, also while the textarea has focus. A draft with unsaved\n // typing keeps it; if a peer changed the description meanwhile, its commit is refused and the peer's text is\n // loaded instead.\n function followRows() {\n const focused = focusedRow()\n const key = focused?.key\n const description = focused?.description\n if (key !== focusKey) {\n focusKey = key\n focusDescription = description\n commit()\n load()\n }\n else if (description !== focusDescription) {\n focusDescription = description\n if (dirty) {\n if (description !== base && !commit()) load()\n }\n else if (description !== base) {\n load()\n }\n }\n refreshSection()\n publish()\n }\n\n function scheduleSearch() {\n clearTimeout(searchTimer)\n searchTimer = setTimeout(async () => {\n if (!editor || editor.isDestroyed) return\n pendingSearch?.abort()\n const controller = pendingSearch = new AbortController()\n try {\n const found = await metadataOf(editor).search(METADATA_LIST.hashtags, { query: searchTerm, editor, signal: controller.signal })\n if (controller.signal.aborted) return\n tagItems = found.map(item => item.label)\n publish()\n }\n catch (error) {\n if (!controller.signal.aborted) console.warn('Tag-Vorschläge konnten nicht geladen werden', error)\n }\n }, SEARCH_DELAY_MS)\n }\n\n function setSearchTerm(term: string) {\n if (disposed || term === searchTerm) return\n searchTerm = term\n scheduleSearch()\n publish()\n }\n\n const syncEditable = () => {\n const next = isEditable()\n if (next === editable) return\n editable = next\n publish()\n }\n const toEditor = () => {\n caretIn = 'editor'\n refreshSection()\n publish()\n }\n\n load()\n refreshSection()\n const stopRows = rows.state.subscribe(followRows)\n if (editor && !editor.isDestroyed) {\n editor.on('transaction', syncEditable)\n // Only `focus`, not `selectionUpdate`: a collaboration sync can move the selection while the host's input has the focus.\n editor.on('focus', toEditor)\n }\n publish()\n\n return {\n state: store,\n\n setDocumentFocused(focused) {\n if (disposed) return\n const rising = focused && !documentFocused\n documentFocused = focused\n if (!rising) return\n caretIn = 'document'\n refreshSection()\n publish()\n },\n\n setKind(kind) {\n const row = focusedRow()\n const found = editor && row ? compositeOfRow(editor.state.doc, row) : null\n if (!editor || !found || kind === row?.kind) return\n editor.commands.setCompositeKind(kind, found.pos)\n },\n\n inputDescription(text) {\n if (disposed) return\n draft = text\n dirty = true\n pendingRow ??= focusedRow()\n clearTimeout(commitTimer)\n commitTimer = setTimeout(commit, COMMIT_DELAY_MS)\n publish()\n },\n\n blurDescription() {\n if (disposed) return\n if (commit()) draft = base\n else load()\n publish()\n },\n\n setTags(tags) {\n const row = focusedRow()\n if (editor && row) setCompositeTags(editor, row, tags)\n },\n\n // „Neu Tag“ → `neu-tag`. A name that normalizes to an already chosen tag is ignored; only unknown names are reported as created.\n createTag(raw) {\n const row = focusedRow()\n const name = normalizeTagName(raw)\n setSearchTerm('')\n if (!editor || !row || !name || row.tags.includes(name)) return\n setCompositeTags(editor, row, [...row.tags, name])\n if (!tagItems.includes(name)) metadataOf(editor).create(METADATA_LIST.hashtags, { id: name, label: name })\n },\n\n setSearchTerm,\n\n searchTags() {\n if (!disposed) scheduleSearch()\n },\n\n setField(field, value) {\n const row = focusedRow()\n if (editor && isEditable() && row) setCompositeMetaField(editor, row, field.key, value)\n },\n\n dispose() {\n if (disposed) return\n commit()\n disposed = true\n clearTimeout(searchTimer)\n pendingSearch?.abort()\n stopRows()\n if (editor && !editor.isDestroyed) {\n editor.off('transaction', syncEditable)\n editor.off('focus', toEditor)\n }\n rows.dispose()\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inspector-model.js","names":[],"sources":["../../../src/features/composites/inspector-model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { metadataOf } from '../../core/metadata'\nimport { METADATA_LIST } from '../../core/metadata-types'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport { normalizeTagName } from '../../core/tag-name'\nimport type { CompositeMetaField } from './kinds'\nimport { compositeKindsOf } from './nodes'\nimport { compositeDescriptionText, compositeOfRow, type CompositeRow, setCompositeDescription, setCompositeMetaField, setCompositeTags } from './rows'\nimport { type CompositeRowsState, createCompositeRows } from './rows-model'\n\n/** Pause after the last keystroke in the description before the draft is written to the document. */\nconst COMMIT_DELAY_MS = 600\n/** Pause after the last change of the tag search term before the metadata source is asked. */\nconst SEARCH_DELAY_MS = 150\n\n/** Which section of the inspector shows: the document's facts, or the properties of the Baustein under the caret. */\nexport type CompositeInspectorSection = 'document' | 'composite'\n\n/** A kind the Baustein can be switched to, as the kind select lists it. */\nexport interface CompositeKindOption {\n value: string\n label: string\n icon: string\n}\n\n/** Everything the inspector renders (see `createCompositeInspector`): the live rows plus the inspector's own state. */\nexport interface CompositeInspectorState extends CompositeRowsState {\n /** `'composite'` only while the caret last was in the editor and a Baustein is focused, else `'document'`. */\n section: CompositeInspectorSection\n /** Whether the editor accepts edits; follows `setEditable` (see `createCompositeInspector`). */\n editable: boolean\n /** The description text as the user sees it in the focused Baustein's textarea; may be ahead of the document until it is committed. */\n draft: string\n /** The text typed into the tag search. */\n searchTerm: string\n /** Tag names the metadata source suggested for the latest search that was not superseded. */\n tagItems: string[]\n /** The kinds the editor was configured with, in configured order; empty without an editor. */\n kindOptions: CompositeKindOption[]\n /** How many Bausteine have a description. */\n summarized: number\n /** The focused Baustein has a description. */\n hasSummary: boolean\n}\n\n/** The inspector model of an editor: observable `state`, the actions of the panel, and `dispose()`. */\nexport interface CompositeInspector {\n readonly state: ReadonlyStore<CompositeInspectorState>\n /**\n * Reports whether the host's document-level input (its title field) has the focus. Only the rising edge switches\n * the section to `'document'`; the section stays there after the input blurs, until the editor takes the focus.\n */\n setDocumentFocused: (focused: boolean) => void\n /** Switches the focused Baustein to `kind`; ignored when it already has it or no Baustein is focused. */\n setKind: (kind: string) => void\n /**\n * The user typed `text` into the description. The draft is written to the document 600 ms after the last call and\n * on `blurDescription`; the Baustein focused at the first call of a pending draft is the one that is written.\n */\n inputDescription: (text: string) => void\n /**\n * The description textarea lost focus: writes the pending draft, then shows what the document holds. The draft\n * shows the normalized text after a write; after a refused write (a peer changed the description since the draft\n * started) it shows the peer's text.\n */\n blurDescription: () => void\n /** Replaces the tags of the focused Baustein. */\n setTags: (tags: readonly string[]) => void\n /** Creates the tag `raw` (normalized) on the focused Baustein and registers it with the metadata source; clears the search term. */\n createTag: (raw: string) => void\n /** Sets the tag search term and schedules a search for it. */\n setSearchTerm: (term: string) => void\n /** Schedules a tag search for the current term (the picker opened). */\n searchTags: () => void\n /**\n * Writes the text `value` to the meta `field` of the focused Baustein; ignored while the editor is not editable and\n * for structured fields (`isStructuredField`), whose values are not text and have their own editors.\n */\n setField: (field: CompositeMetaField, value: unknown) => void\n /** Commits a pending description draft and detaches from the editor. Idempotent; the model is inert afterwards. */\n dispose: () => void\n}\n\n/** Fields whose value is not text (a block ID, a CSL item, a provenance record): the inspector hands them to `CompositeFieldEditor` and never writes a string to them. */\nexport function isStructuredField(field: Pick<CompositeMetaField, 'type'>): boolean {\n return field.type === 'reference' || field.type === 'bibliography' || field.type === 'derivation'\n}\n\n/** The text of `field` in `row`'s meta as an input shows it: strings and numbers, otherwise empty. */\nexport function compositeFieldText(row: Pick<CompositeRow, 'meta'> | null, field: Pick<CompositeMetaField, 'key'>): string {\n const value = row?.meta[field.key]\n return typeof value === 'string' || typeof value === 'number' ? String(value) : ''\n}\n\nfunction sameState(a: CompositeInspectorState, b: CompositeInspectorState): boolean {\n return (Object.keys(a) as (keyof CompositeInspectorState)[]).every(key => Object.is(a[key], b[key]))\n}\n\n/**\n * The properties panel of `editor`: which section shows, the focused Baustein's description draft, the tag search\n * and the writes. Owns its own `createCompositeRows(editor)`, so a focus change and the rows it refers to arrive in\n * one notification and the draft is committed before it is replaced. Create one model per editor (a framework hook\n * follows an editor that changes); without an editor the state is empty and every action is ignored.\n *\n * Section: the caret is either in the host's input (`setDocumentFocused`) or in the editor. Only the editor's `focus`\n * event moves it to the editor (not `selectionUpdate`: collaboration sync moves the selection while the host's input\n * has the focus). A deleted Baustein falls back to the document section.\n *\n * `isEditable` is not reactive: `editable` follows it on every editor `transaction`, so whoever calls `setEditable`\n * must dispatch a transaction afterwards (`EditorSurface` does).\n *\n * Description: edits go to a local `draft` so the asynchronous re-read of the document never overwrites the text\n * (and moves the caret) while it is typed. `base` is the document text the draft started from; the write lands only\n * while the description still holds it, so a peer's change made meanwhile is never replaced. The draft is committed\n * 600 ms after typing pauses, on blur, when another Baustein takes the focus (before the draft is replaced), when\n * the panel leaves the Baustein section, and on `dispose()`. A commit is skipped when the editor is destroyed or not\n * editable, and refused when a peer changed the description; the draft then reloads the live text. A draft that is\n * not dirty follows every change of the focused description.\n *\n * Tag search: each term change restarts a 150 ms debounce; when it fires, the previous search is aborted and the\n * source is asked with a fresh `AbortSignal`. Results of aborted searches are dropped, errors of aborted searches\n * are silent, other errors are logged and keep the old suggestions.\n */\nexport function createCompositeInspector(editor: Editor | undefined): CompositeInspector {\n const rows = createCompositeRows(editor)\n const kindOptions: CompositeKindOption[] = editor && !editor.isDestroyed\n ? compositeKindsOf(editor).map(kind => ({ value: kind.id, label: kind.label, icon: kind.icon }))\n : []\n const isEditable = () => !!editor && !editor.isDestroyed && editor.isEditable\n const focusedRow = () => rows.state.get().focused\n\n let disposed = false\n\n // --- Section ---\n let caretIn: 'document' | 'editor' = 'document'\n let documentFocused = false\n let section: CompositeInspectorSection = 'document'\n let editable = isEditable()\n\n // --- Description draft ---\n let draft = ''\n let base = ''\n let dirty = false\n let pendingRow: CompositeRow | null = null\n let commitTimer: ReturnType<typeof setTimeout> | undefined\n // What the focused Baustein looked like at the last rows notification: a change of the key is a switch, a change of the description a peer's (or our own) write.\n let focusKey = focusedRow()?.key\n let focusDescription = focusedRow()?.description\n\n // --- Tag search ---\n let searchTerm = ''\n let tagItems: string[] = []\n let searchTimer: ReturnType<typeof setTimeout> | undefined\n let pendingSearch: AbortController | undefined\n\n let summarizedRows: CompositeRowsState['rows'] | undefined\n let summarized = 0\n const store = createStore<CompositeInspectorState>(snapshot())\n\n function snapshot(): CompositeInspectorState {\n const read = rows.state.get()\n if (read.rows !== summarizedRows) {\n summarizedRows = read.rows\n summarized = read.rows.filter(row => row.description.trim()).length\n }\n return {\n ...read,\n section,\n editable,\n draft,\n searchTerm,\n tagItems,\n kindOptions,\n summarized,\n hasSummary: !!read.focused?.description.trim(),\n }\n }\n\n function publish() {\n const next = snapshot()\n if (!sameState(store.get(), next)) store.set(next)\n }\n\n function load() {\n dirty = false\n pendingRow = null\n base = focusedRow()?.description ?? ''\n draft = base\n }\n\n /** Writes the pending draft; `false` when there was nothing to write or the write was refused. Does not touch `draft`. */\n function commit(): boolean {\n clearTimeout(commitTimer)\n if (!dirty || !pendingRow) return false\n dirty = false\n const row = pendingRow\n pendingRow = null\n if (!editor || editor.isDestroyed || !editor.isEditable) return false\n if (!setCompositeDescription(editor, row, draft, base)) return false\n base = compositeDescriptionText(draft)\n return true\n }\n\n function refreshSection() {\n const next = caretIn === 'editor' && focusedRow() ? 'composite' : 'document'\n if (section === 'composite' && next !== 'composite') commit()\n section = next\n }\n\n // A switch commits the draft of the previous Baustein first (`draft` still holds its text), then loads the new one.\n // A change of the description reaches an untouched draft, also while the textarea has focus. A draft with unsaved\n // typing keeps it; if a peer changed the description meanwhile, its commit is refused and the peer's text is\n // loaded instead.\n function followRows() {\n const focused = focusedRow()\n const key = focused?.key\n const description = focused?.description\n if (key !== focusKey) {\n focusKey = key\n focusDescription = description\n commit()\n load()\n }\n else if (description !== focusDescription) {\n focusDescription = description\n if (dirty) {\n if (description !== base && !commit()) load()\n }\n else if (description !== base) {\n load()\n }\n }\n refreshSection()\n publish()\n }\n\n function scheduleSearch() {\n clearTimeout(searchTimer)\n searchTimer = setTimeout(async () => {\n if (!editor || editor.isDestroyed) return\n pendingSearch?.abort()\n const controller = pendingSearch = new AbortController()\n try {\n const found = await metadataOf(editor).search(METADATA_LIST.hashtags, { query: searchTerm, editor, signal: controller.signal })\n if (controller.signal.aborted) return\n tagItems = found.map(item => item.label)\n publish()\n }\n catch (error) {\n if (!controller.signal.aborted) console.warn('Tag-Vorschläge konnten nicht geladen werden', error)\n }\n }, SEARCH_DELAY_MS)\n }\n\n function setSearchTerm(term: string) {\n if (disposed || term === searchTerm) return\n searchTerm = term\n scheduleSearch()\n publish()\n }\n\n const syncEditable = () => {\n const next = isEditable()\n if (next === editable) return\n editable = next\n publish()\n }\n const toEditor = () => {\n caretIn = 'editor'\n refreshSection()\n publish()\n }\n\n load()\n refreshSection()\n const stopRows = rows.state.subscribe(followRows)\n if (editor && !editor.isDestroyed) {\n editor.on('transaction', syncEditable)\n // Only `focus`, not `selectionUpdate`: a collaboration sync can move the selection while the host's input has the focus.\n editor.on('focus', toEditor)\n }\n publish()\n\n return {\n state: store,\n\n setDocumentFocused(focused) {\n if (disposed) return\n const rising = focused && !documentFocused\n documentFocused = focused\n if (!rising) return\n caretIn = 'document'\n refreshSection()\n publish()\n },\n\n setKind(kind) {\n const row = focusedRow()\n const found = editor && row ? compositeOfRow(editor.state.doc, row) : null\n if (!editor || !found || kind === row?.kind) return\n editor.commands.setCompositeKind(kind, found.pos)\n },\n\n inputDescription(text) {\n if (disposed) return\n draft = text\n dirty = true\n pendingRow ??= focusedRow()\n clearTimeout(commitTimer)\n commitTimer = setTimeout(commit, COMMIT_DELAY_MS)\n publish()\n },\n\n blurDescription() {\n if (disposed) return\n if (commit()) draft = base\n else load()\n publish()\n },\n\n setTags(tags) {\n const row = focusedRow()\n if (editor && row) setCompositeTags(editor, row, tags)\n },\n\n // „Neu Tag“ → `neu-tag`. A name that normalizes to an already chosen tag is ignored; only unknown names are reported as created.\n createTag(raw) {\n const row = focusedRow()\n const name = normalizeTagName(raw)\n setSearchTerm('')\n if (!editor || !row || !name || row.tags.includes(name)) return\n setCompositeTags(editor, row, [...row.tags, name])\n if (!tagItems.includes(name)) metadataOf(editor).create(METADATA_LIST.hashtags, { id: name, label: name })\n },\n\n setSearchTerm,\n\n searchTags() {\n if (!disposed) scheduleSearch()\n },\n\n setField(field, value) {\n const row = focusedRow()\n if (editor && isEditable() && row && !isStructuredField(field)) setCompositeMetaField(editor, row, field.key, value)\n },\n\n dispose() {\n if (disposed) return\n commit()\n disposed = true\n clearTimeout(searchTimer)\n pendingSearch?.abort()\n stopRows()\n if (editor && !editor.isDestroyed) {\n editor.off('transaction', syncEditable)\n editor.off('focus', toEditor)\n }\n rows.dispose()\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { Translate } from "../../i18n/index.js";
|
|
2
2
|
//#region src/features/composites/kinds.d.ts
|
|
3
|
+
/** Media block types a source-holding kind's source may be (`CompositeKind.source`). */
|
|
4
|
+
export declare const SOURCE_MEDIA_TYPES: readonly ["image", "audio", "video", "file"];
|
|
3
5
|
/** One metadata field of a composite kind, stored under `key` in the composite's `meta` attribute. */
|
|
4
6
|
export interface CompositeMetaField {
|
|
5
7
|
key: string;
|
|
6
8
|
label: string;
|
|
7
|
-
|
|
9
|
+
/** `bibliography`: CSL-JSON item under `meta.bib`; `derivation`: read-only provenance of a derived Baustein; `reference`: block id of another Baustein. */
|
|
10
|
+
type: 'text' | 'textarea' | 'date' | 'number' | 'select' | 'reference' | 'bibliography' | 'derivation';
|
|
8
11
|
/** Choices of a `select` field. */
|
|
9
12
|
options?: {
|
|
10
13
|
value: string;
|
|
11
14
|
label: string;
|
|
12
15
|
}[];
|
|
16
|
+
/** `reference`: kind ids the field may point to; absent = any Baustein. */
|
|
17
|
+
targets?: readonly string[];
|
|
13
18
|
}
|
|
14
19
|
/**
|
|
15
20
|
* What a kind tells the model beyond its fields. `purpose` goes into every AI request's block model (chat, generate
|
|
@@ -41,6 +46,8 @@ export interface CompositeKind {
|
|
|
41
46
|
* Only new moves are checked; documents that already nest against it stay as they are.
|
|
42
47
|
*/
|
|
43
48
|
accepts?: readonly string[] | 'all';
|
|
49
|
+
/** Present on source-holding kinds: the media block types the kind's source may be; `sourceOf` returns the first body child of one of these. */
|
|
50
|
+
source?: readonly (typeof SOURCE_MEDIA_TYPES)[number][];
|
|
44
51
|
}
|
|
45
52
|
/**
|
|
46
53
|
* The built-in kinds in the language of `t`. The default set is produced from the translator (labels, placeholders, field
|