@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":"schema.js","names":[],"sources":["../../../src/features/media/schema.ts"],"sourcesContent":["import { type Attributes, type AnyExtension, mergeAttributes, Node } from '@tiptap/core'\nimport { Image } from '@tiptap/extension-image'\nimport { TEXT_ABILITIES } from '../../core/schema'\n\nexport * from './assets'\n\n// Vue-free and server-importable (`@ecsplico/editor/media/schema`): the upload API validates against these types, the\n// schema has the nodes. The client adds the node views in node-views.ts.\n\n/** The media nodes (image, audio, video, file) of the document schema. */\nexport const mediaSchemaExtensions = (): AnyExtension[] => [Image, AudioNode, VideoNode, FileNode]\n\nexport type MediaKind = 'image' | 'audio' | 'video' | 'file'\n\n/** Uploadable MIME types → file extension on disk and media kind. `<uuid>.<ext>` asset names derive from this. */\nexport const MEDIA_TYPES: Readonly<Record<string, { ext: string, kind: MediaKind }>> = {\n 'image/png': { ext: 'png', kind: 'image' },\n 'image/jpeg': { ext: 'jpg', kind: 'image' },\n 'image/gif': { ext: 'gif', kind: 'image' },\n 'image/webp': { ext: 'webp', kind: 'image' },\n 'audio/webm': { ext: 'weba', kind: 'audio' },\n 'audio/mp4': { ext: 'm4a', kind: 'audio' },\n // What Chrome on macOS reports for `.m4a` files picked from disk.\n 'audio/x-m4a': { ext: 'm4a', kind: 'audio' },\n 'audio/mpeg': { ext: 'mp3', kind: 'audio' },\n 'audio/wav': { ext: 'wav', kind: 'audio' },\n 'audio/x-wav': { ext: 'wav', kind: 'audio' },\n 'audio/ogg': { ext: 'ogg', kind: 'audio' },\n 'video/mp4': { ext: 'mp4', kind: 'video' },\n 'video/webm': { ext: 'webm', kind: 'video' },\n 'video/quicktime': { ext: 'mov', kind: 'video' },\n}\n\n/** Upload size limit per kind. */\nexport const MAX_MEDIA_BYTES: Readonly<Record<MediaKind, number>> = {\n image: 5 * 1024 * 1024,\n audio: 50 * 1024 * 1024,\n video: 200 * 1024 * 1024,\n // Generic files (PDF, office documents, …): anything the media kinds do not cover.\n file: 50 * 1024 * 1024,\n}\n\n/** `type` without parameters, lowercased (`audio/webm;codecs=opus` → `audio/webm`): the key into `MEDIA_TYPES`. */\nexport const mediaMime = (type: string): string => (type.split(';')[0] ?? '').trim().toLowerCase()\n\n/** Kind of an uploadable MIME type (parameters such as `;codecs=…` ignored); null when uploads do not accept it. */\nexport function mediaKindOf(mime: string): MediaKind | null {\n return MEDIA_TYPES[mediaMime(mime)]?.kind ?? null\n}\n\n/** `accept` value of a file input for one kind: its MIME types, comma-joined. */\nexport function acceptFor(kind: MediaKind): string {\n return Object.keys(MEDIA_TYPES).filter(mime => MEDIA_TYPES[mime]?.kind === kind).join(',')\n}\n\n/** Attributes of an audio/video node; `title` is the editable caption, `mimeType` the uploaded file's base type. */\nexport interface MediaAttrs {\n src: string\n title?: string\n mimeType?: string\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n audio: {\n /** Inserts an audio block at the selection. */\n insertAudio: (attrs: MediaAttrs) => ReturnType\n }\n video: {\n /** Inserts a video block at the selection. */\n insertVideo: (attrs: MediaAttrs) => ReturnType\n }\n }\n}\n\nconst mediaAttributes: Attributes = {\n src: { default: '' },\n title: {\n default: '',\n parseHTML: el => el.getAttribute('data-title') ?? '',\n renderHTML: attrs => ({ 'data-title': attrs.title }),\n },\n mimeType: {\n default: '',\n parseHTML: el => el.getAttribute('data-mime') ?? '',\n renderHTML: attrs => ({ 'data-mime': attrs.mimeType }),\n },\n}\n\n/** Markdown export (AI context, `getMarkdown()`): a link labelled with the kind and, when there is one, the title. */\nfunction mediaMarkdown(label: string, title: unknown, src: unknown): string {\n const text = title ? `${label}: ${String(title).replace(/[[\\]\\\\]/g, '\\\\$&')}` : label\n return `[${text}](${String(src ?? '')})`\n}\n\nexport const AudioNode = Node.create({\n name: 'audio',\n group: 'block',\n atom: true,\n draggable: true,\n // A player block holds no text: nothing text-related applies inside it.\n abilities: { revokes: TEXT_ABILITIES },\n addAttributes: () => mediaAttributes,\n parseHTML: () => [{ tag: 'audio[src]' }],\n renderHTML: ({ HTMLAttributes }) => ['audio', mergeAttributes(HTMLAttributes, { controls: 'true', preload: 'metadata' })],\n renderMarkdown: node => mediaMarkdown('Audio', node.attrs?.title || 'Aufnahme', node.attrs?.src),\n addCommands() {\n return {\n insertAudio: attrs => ({ commands }) => commands.insertContent({ type: this.name, attrs }),\n }\n },\n})\n\nexport const VideoNode = Node.create({\n name: 'video',\n group: 'block',\n atom: true,\n draggable: true,\n abilities: { revokes: TEXT_ABILITIES },\n addAttributes: () => mediaAttributes,\n parseHTML: () => [{ tag: 'video[src]' }],\n renderHTML: ({ HTMLAttributes }) => ['video', mergeAttributes(HTMLAttributes, { controls: 'true', preload: 'metadata' })],\n renderMarkdown: node => mediaMarkdown('Video', node.attrs?.title, node.attrs?.src),\n addCommands() {\n return {\n insertVideo: attrs => ({ commands }) => commands.insertContent({ type: this.name, attrs }),\n }\n },\n})\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n file: {\n /** Inserts a file block (download link, PDF preview) at the selection. */\n insertFile: (attrs: FileAttrs) => ReturnType\n }\n }\n}\n\n/** Attributes of a file block; `title` is the editable file name, `size` the byte count. */\nexport interface FileAttrs {\n src: string\n title?: string\n mimeType?: string\n size?: number\n}\n\n/** A generic uploaded file (PDF, office document, …) that has no player: shown as a card with an open button. */\nexport const FileNode = Node.create({\n name: 'file',\n group: 'block',\n atom: true,\n draggable: true,\n abilities: { revokes: TEXT_ABILITIES },\n addAttributes: () => ({\n src: { default: '', parseHTML: el => el.getAttribute('href') ?? '' },\n title: { default: '', parseHTML: el => el.getAttribute('download') ?? '' },\n mimeType: { default: '', parseHTML: el => el.getAttribute('data-mime') ?? '' },\n size: { default: 0, parseHTML: el => Number(el.getAttribute('data-size')) || 0 },\n }),\n parseHTML: () => [{ tag: 'a[data-type=\"file\"]' }],\n renderHTML: ({ node }) => ['a', {\n 'data-type': 'file',\n 'href': node.attrs.src,\n 'download': node.attrs.title,\n 'data-mime': node.attrs.mimeType,\n 'data-size': String(node.attrs.size),\n }, node.attrs.title || 'Datei'],\n renderMarkdown: node => `[Datei: ${String(node.attrs?.title || 'Datei').replace(/[[\\]\\\\]/g, '\\\\$&')}](${String(node.attrs?.src ?? '')})`,\n addCommands() {\n return {\n insertFile: attrs => ({ commands }) => commands.insertContent({ type: this.name, attrs }),\n }\n },\n})\n"],"mappings":";;;;;;AAUA,MAAa,8BAA8C;CAAC;CAAO;CAAW;CAAW;AAAQ;;AAKjG,MAAa,cAA0E;CACrF,aAAa;EAAE,KAAK;EAAO,MAAM;CAAQ;CACzC,cAAc;EAAE,KAAK;EAAO,MAAM;CAAQ;CAC1C,aAAa;EAAE,KAAK;EAAO,MAAM;CAAQ;CACzC,cAAc;EAAE,KAAK;EAAQ,MAAM;CAAQ;CAC3C,cAAc;EAAE,KAAK;EAAQ,MAAM;CAAQ;CAC3C,aAAa;EAAE,KAAK;EAAO,MAAM;CAAQ;CAEzC,eAAe;EAAE,KAAK;EAAO,MAAM;CAAQ;CAC3C,cAAc;EAAE,KAAK;EAAO,MAAM;CAAQ;CAC1C,aAAa;EAAE,KAAK;EAAO,MAAM;CAAQ;CACzC,eAAe;EAAE,KAAK;EAAO,MAAM;CAAQ;CAC3C,aAAa;EAAE,KAAK;EAAO,MAAM;CAAQ;CACzC,aAAa;EAAE,KAAK;EAAO,MAAM;CAAQ;CACzC,cAAc;EAAE,KAAK;EAAQ,MAAM;CAAQ;CAC3C,mBAAmB;EAAE,KAAK;EAAO,MAAM;CAAQ;AACjD;;AAGA,MAAa,kBAAuD;CAClE,OAAO;CACP,OAAO;CACP,OAAO;CAEP,MAAM;AACR;;AAGA,MAAa,aAAa,UAA0B,KAAK,MAAM,GAAG,CAAC,CAAC,MAAM,GAAA,CAAI,KAAK,CAAC,CAAC,YAAY;;AAGjG,SAAgB,YAAY,MAAgC;CAC1D,OAAO,YAAY,UAAU,IAAI,EAAE,EAAE,QAAQ;AAC/C;;AAGA,SAAgB,UAAU,MAAyB;CACjD,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,QAAO,SAAQ,YAAY,KAAK,EAAE,SAAS,IAAI,CAAC,CAAC,KAAK,GAAG;AAC3F;AAsBA,MAAM,kBAA8B;CAClC,KAAK,EAAE,SAAS,GAAG;CACnB,OAAO;EACL,SAAS;EACT,YAAW,OAAM,GAAG,aAAa,YAAY,KAAK;EAClD,aAAY,WAAU,EAAE,cAAc,MAAM,MAAM;CACpD;CACA,UAAU;EACR,SAAS;EACT,YAAW,OAAM,GAAG,aAAa,WAAW,KAAK;EACjD,aAAY,WAAU,EAAE,aAAa,MAAM,SAAS;CACtD;AACF;;AAGA,SAAS,cAAc,OAAe,OAAgB,KAAsB;CAE1E,OAAO,IADM,QAAQ,GAAG,MAAM,IAAI,OAAO,KAAK,CAAC,CAAC,QAAQ,YAAY,MAAM,MAAM,MAChE,IAAI,OAAO,OAAO,EAAE,EAAE;AACxC;AAEA,MAAa,YAAY,KAAK,OAAO;CACnC,MAAM;CACN,OAAO;CACP,MAAM;CACN,WAAW;CAEX,WAAW,EAAE,SAAS,eAAe;CACrC,qBAAqB;CACrB,iBAAiB,CAAC,EAAE,KAAK,aAAa,CAAC;CACvC,aAAa,EAAE,qBAAqB,CAAC,SAAS,gBAAgB,gBAAgB;EAAE,UAAU;EAAQ,SAAS;CAAW,CAAC,CAAC;CACxH,iBAAgB,SAAQ,cAAc,SAAS,KAAK,OAAO,SAAS,YAAY,KAAK,OAAO,GAAG;CAC/F,cAAc;EACZ,OAAO,EACL,cAAa,WAAU,EAAE,eAAe,SAAS,cAAc;GAAE,MAAM,KAAK;GAAM;EAAM,CAAC,EAC3F;CACF;AACF,CAAC;AAED,MAAa,YAAY,KAAK,OAAO;CACnC,MAAM;CACN,OAAO;CACP,MAAM;CACN,WAAW;CACX,WAAW,EAAE,SAAS,eAAe;CACrC,qBAAqB;CACrB,iBAAiB,CAAC,EAAE,KAAK,aAAa,CAAC;CACvC,aAAa,EAAE,qBAAqB,CAAC,SAAS,gBAAgB,gBAAgB;EAAE,UAAU;EAAQ,SAAS;CAAW,CAAC,CAAC;CACxH,iBAAgB,SAAQ,cAAc,SAAS,KAAK,OAAO,OAAO,KAAK,OAAO,GAAG;CACjF,cAAc;EACZ,OAAO,EACL,cAAa,WAAU,EAAE,eAAe,SAAS,cAAc;GAAE,MAAM,KAAK;GAAM;EAAM,CAAC,EAC3F;CACF;AACF,CAAC;;AAoBD,MAAa,WAAW,KAAK,OAAO;CAClC,MAAM;CACN,OAAO;CACP,MAAM;CACN,WAAW;CACX,WAAW,EAAE,SAAS,eAAe;CACrC,sBAAsB;EACpB,KAAK;GAAE,SAAS;GAAI,YAAW,OAAM,GAAG,aAAa,MAAM,KAAK;EAAG;EACnE,OAAO;GAAE,SAAS;GAAI,YAAW,OAAM,GAAG,aAAa,UAAU,KAAK;EAAG;EACzE,UAAU;GAAE,SAAS;GAAI,YAAW,OAAM,GAAG,aAAa,WAAW,KAAK;EAAG;EAC7E,MAAM;GAAE,SAAS;GAAG,YAAW,OAAM,OAAO,GAAG,aAAa,WAAW,CAAC,KAAK;EAAE;CACjF;CACA,iBAAiB,CAAC,EAAE,KAAK,wBAAsB,CAAC;CAChD,aAAa,EAAE,WAAW;EAAC;EAAK;GAC9B,aAAa;GACb,QAAQ,KAAK,MAAM;GACnB,YAAY,KAAK,MAAM;GACvB,aAAa,KAAK,MAAM;GACxB,aAAa,OAAO,KAAK,MAAM,IAAI;EACrC;EAAG,KAAK,MAAM,SAAS;CAAO;CAC9B,iBAAgB,SAAQ,WAAW,OAAO,KAAK,OAAO,SAAS,OAAO,CAAC,CAAC,QAAQ,YAAY,MAAM,EAAE,IAAI,OAAO,KAAK,OAAO,OAAO,EAAE,EAAE;CACtI,cAAc;EACZ,OAAO,EACL,aAAY,WAAU,EAAE,eAAe,SAAS,cAAc;GAAE,MAAM,KAAK;GAAM;EAAM,CAAC,EAC1F;CACF;AACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/media/schema.ts"],"sourcesContent":["import { type Attributes, type AnyExtension, type MarkdownToken, type MarkdownTokenizer, mergeAttributes, Node } from '@tiptap/core'\nimport { Image } from '@tiptap/extension-image'\nimport { TEXT_ABILITIES } from '../../core/schema'\n\nexport * from './assets'\n\n// Vue-free and server-importable (`@ecsplico/editor/media/schema`): the upload API validates against these types, the\n// schema has the nodes. The client adds the node views in node-views.ts.\n\n/** SHA-256 (hex) of the uploaded bytes, kept on media blocks so derived content can tell when its source changed; null when unknown (memory backend, older documents). */\nconst hashAttribute: Attributes[string] = {\n default: null,\n parseHTML: el => el.getAttribute('data-hash'),\n renderHTML: attrs => (attrs.hash ? { 'data-hash': attrs.hash } : {}),\n}\n\n/** The media nodes (image, audio, video, file) of the document schema. */\nexport const mediaSchemaExtensions = (): AnyExtension[] => [ImageNode, AudioNode, VideoNode, FileNode]\n\n/**\n * The image node with a `hash` attribute. Markdown: ``, followed by ` <!-- {\"hash\":\"…\"} -->` when the\n * block has a hash; only that form is claimed by `imageBlockTokenizer` (a block-level token that still yields an `image`\n * token), a plain image keeps the stock inline parse.\n */\nexport const ImageNode = Image.extend({\n addAttributes() {\n return { ...this.parent?.(), hash: hashAttribute }\n },\n markdownTokenizer: {\n name: 'imageBlock',\n level: 'block',\n start: src => src.search(new RegExp(IMAGE_BLOCK_PATTERN, 'm')),\n tokenize: (src) => {\n const match = new RegExp(IMAGE_BLOCK_PATTERN).exec(src)\n if (!match) return undefined\n return { type: 'image', raw: match[0], text: match[1] ?? '', href: match[2] ?? '', title: match[3], attrs: parseAttrComment(match[4]) }\n },\n },\n parseMarkdown: (token, helpers) => helpers.createNode('image', {\n src: token.href,\n title: token.title,\n alt: token.text,\n hash: typeof token.attrs?.hash === 'string' ? token.attrs.hash : null,\n }),\n renderMarkdown: (node) => {\n const { src = '', alt = '', title = '' } = node.attrs ?? {}\n return `${attrComment({ hash: node.attrs?.hash })}`\n },\n})\n\n// Markdown form of the text-less media blocks. Audio, video and file are a paragraph of nothing but a link\n// (`[Audio: name](url)`), optionally followed by an HTML comment holding the attributes the link cannot carry\n// (`hash`, `mimeType`, `size`) as JSON, the way composite fences hold their meta. The block-level tokenizers below parse\n// that line back into the node; labels of every UI language are accepted, the export always writes the German one.\nconst ATTR_COMMENT_PATTERN = '(?: <!-- (\\\\{.*?\\\\}) -->)?[ \\\\t]*(?:\\\\n|$)'\nconst IMAGE_BLOCK_PATTERN = `^!\\\\[([^\\\\]\\\\n]*)\\\\]\\\\(([^)\\\\s]*)(?: \"([^\"\\\\n]*)\")?\\\\) <!-- (\\\\{.*?\\\\}) -->[ \\\\t]*(?:\\\\n|$)`\n\n/** ` <!-- {\"hash\":\"…\"} -->` for the attributes that are set (empty string when none); `>` is escaped so the JSON cannot end the comment. */\nfunction attrComment(attrs: Record<string, unknown>): string {\n const set = Object.fromEntries(Object.entries(attrs).filter(([, value]) => value !== null && value !== undefined && value !== '' && value !== 0))\n return Object.keys(set).length ? ` <!-- ${JSON.stringify(set).replace(/>/g, '\\\\u003e')} -->` : ''\n}\n\n/** The attributes of an `attrComment`; empty for a missing or malformed one. */\nfunction parseAttrComment(json: string | undefined): Record<string, unknown> {\n if (!json) return {}\n try {\n const value: unknown = JSON.parse(json)\n return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : {}\n }\n catch {\n return {}\n }\n}\n\n/** Block tokenizer for `[<label>: title](src)` lines of one media node; `labels` are the accepted labels (regex alternatives). */\nfunction mediaTokenizer(name: string, labels: string): MarkdownTokenizer {\n const pattern = `^\\\\[(?:${labels})(?:: ((?:\\\\\\\\.|[^\\\\]\\\\\\\\\\\\n])*))?\\\\]\\\\(([^)\\\\s]*)\\\\)${ATTR_COMMENT_PATTERN}`\n return {\n name,\n level: 'block',\n start: src => src.search(new RegExp(pattern, 'm')),\n tokenize: (src) => {\n const match = new RegExp(pattern).exec(src)\n if (!match) return undefined\n return { type: name, raw: match[0], title: (match[1] ?? '').replace(/\\\\(.)/g, '$1'), href: match[2] ?? '', attrs: parseAttrComment(match[3]) }\n },\n }\n}\n\nconst stringAttr = (value: unknown): string => typeof value === 'string' ? value : ''\n\nexport type MediaKind = 'image' | 'audio' | 'video' | 'file'\n\n/** Uploadable MIME types → file extension on disk and media kind. `<uuid>.<ext>` asset names derive from this. */\nexport const MEDIA_TYPES: Readonly<Record<string, { ext: string, kind: MediaKind }>> = {\n 'image/png': { ext: 'png', kind: 'image' },\n 'image/jpeg': { ext: 'jpg', kind: 'image' },\n 'image/gif': { ext: 'gif', kind: 'image' },\n 'image/webp': { ext: 'webp', kind: 'image' },\n 'audio/webm': { ext: 'weba', kind: 'audio' },\n 'audio/mp4': { ext: 'm4a', kind: 'audio' },\n // What Chrome on macOS reports for `.m4a` files picked from disk.\n 'audio/x-m4a': { ext: 'm4a', kind: 'audio' },\n 'audio/mpeg': { ext: 'mp3', kind: 'audio' },\n 'audio/wav': { ext: 'wav', kind: 'audio' },\n 'audio/x-wav': { ext: 'wav', kind: 'audio' },\n 'audio/ogg': { ext: 'ogg', kind: 'audio' },\n 'video/mp4': { ext: 'mp4', kind: 'video' },\n 'video/webm': { ext: 'webm', kind: 'video' },\n 'video/quicktime': { ext: 'mov', kind: 'video' },\n}\n\n/** Upload size limit per kind. */\nexport const MAX_MEDIA_BYTES: Readonly<Record<MediaKind, number>> = {\n image: 5 * 1024 * 1024,\n audio: 50 * 1024 * 1024,\n video: 200 * 1024 * 1024,\n // Generic files (PDF, office documents, …): anything the media kinds do not cover.\n file: 50 * 1024 * 1024,\n}\n\n/** `type` without parameters, lowercased (`audio/webm;codecs=opus` → `audio/webm`): the key into `MEDIA_TYPES`. */\nexport const mediaMime = (type: string): string => (type.split(';')[0] ?? '').trim().toLowerCase()\n\n/** Kind of an uploadable MIME type (parameters such as `;codecs=…` ignored); null when uploads do not accept it. */\nexport function mediaKindOf(mime: string): MediaKind | null {\n return MEDIA_TYPES[mediaMime(mime)]?.kind ?? null\n}\n\n/** `accept` value of a file input for one kind: its MIME types, comma-joined. */\nexport function acceptFor(kind: MediaKind): string {\n return Object.keys(MEDIA_TYPES).filter(mime => MEDIA_TYPES[mime]?.kind === kind).join(',')\n}\n\n/** Attributes of an audio/video node; `title` is the editable caption, `mimeType` the uploaded file's base type. */\nexport interface MediaAttrs {\n src: string\n title?: string\n mimeType?: string\n hash?: string | null\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n audio: {\n /** Inserts an audio block at the selection. */\n insertAudio: (attrs: MediaAttrs) => ReturnType\n }\n video: {\n /** Inserts a video block at the selection. */\n insertVideo: (attrs: MediaAttrs) => ReturnType\n }\n }\n}\n\nconst mediaAttributes: Attributes = {\n src: { default: '' },\n title: {\n default: '',\n parseHTML: el => el.getAttribute('data-title') ?? '',\n renderHTML: attrs => ({ 'data-title': attrs.title }),\n },\n mimeType: {\n default: '',\n parseHTML: el => el.getAttribute('data-mime') ?? '',\n renderHTML: attrs => ({ 'data-mime': attrs.mimeType }),\n },\n hash: hashAttribute,\n}\n\n/** Markdown export (AI context, `getMarkdown()`, source mode): a link labelled with the kind and, when there is one, the title; `extra` and the hash go into the trailing attribute comment. */\nfunction mediaMarkdown(label: string, attrs: Record<string, unknown> | undefined, extra: Record<string, unknown>): string {\n const title = attrs?.title\n const text = title ? `${label}: ${String(title).replace(/[[\\]\\\\]/g, '\\\\$&')}` : label\n return `[${text}](${String(attrs?.src ?? '')})${attrComment({ ...extra, hash: attrs?.hash })}`\n}\n\n/** Node attributes of an audio/video Markdown token. */\nfunction mediaAttrsOfToken(token: MarkdownToken) {\n return { src: token.href, title: token.title, mimeType: stringAttr(token.attrs?.mimeType), hash: stringAttr(token.attrs?.hash) || null }\n}\n\nexport const AudioNode = Node.create({\n name: 'audio',\n group: 'block',\n atom: true,\n draggable: true,\n // A player block holds no text: nothing text-related applies inside it.\n abilities: { revokes: TEXT_ABILITIES },\n addAttributes: () => mediaAttributes,\n parseHTML: () => [{ tag: 'audio[src]' }],\n renderHTML: ({ HTMLAttributes }) => ['audio', mergeAttributes(HTMLAttributes, { controls: 'true', preload: 'metadata' })],\n markdownTokenizer: mediaTokenizer('audio', 'Audio'),\n parseMarkdown: (token, helpers) => helpers.createNode('audio', mediaAttrsOfToken(token)),\n renderMarkdown: node => mediaMarkdown('Audio', node.attrs, { mimeType: node.attrs?.mimeType }),\n addCommands() {\n return {\n insertAudio: attrs => ({ commands }) => commands.insertContent({ type: this.name, attrs }),\n }\n },\n})\n\nexport const VideoNode = Node.create({\n name: 'video',\n group: 'block',\n atom: true,\n draggable: true,\n abilities: { revokes: TEXT_ABILITIES },\n addAttributes: () => mediaAttributes,\n parseHTML: () => [{ tag: 'video[src]' }],\n renderHTML: ({ HTMLAttributes }) => ['video', mergeAttributes(HTMLAttributes, { controls: 'true', preload: 'metadata' })],\n markdownTokenizer: mediaTokenizer('video', 'Video'),\n parseMarkdown: (token, helpers) => helpers.createNode('video', mediaAttrsOfToken(token)),\n renderMarkdown: node => mediaMarkdown('Video', node.attrs, { mimeType: node.attrs?.mimeType }),\n addCommands() {\n return {\n insertVideo: attrs => ({ commands }) => commands.insertContent({ type: this.name, attrs }),\n }\n },\n})\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n file: {\n /** Inserts a file block (download link, PDF preview) at the selection. */\n insertFile: (attrs: FileAttrs) => ReturnType\n }\n }\n}\n\n/** Attributes of a file block; `title` is the editable file name, `size` the byte count. */\nexport interface FileAttrs {\n src: string\n title?: string\n mimeType?: string\n size?: number\n hash?: string | null\n}\n\n/** A generic uploaded file (PDF, office document, …) that has no player: shown as a card with an open button. */\nexport const FileNode = Node.create({\n name: 'file',\n group: 'block',\n atom: true,\n draggable: true,\n abilities: { revokes: TEXT_ABILITIES },\n addAttributes: () => ({\n src: { default: '', parseHTML: el => el.getAttribute('href') ?? '' },\n title: { default: '', parseHTML: el => el.getAttribute('download') ?? '' },\n mimeType: { default: '', parseHTML: el => el.getAttribute('data-mime') ?? '' },\n size: { default: 0, parseHTML: el => Number(el.getAttribute('data-size')) || 0 },\n hash: hashAttribute,\n }),\n parseHTML: () => [{ tag: 'a[data-type=\"file\"]' }],\n renderHTML: ({ node }) => ['a', {\n 'data-type': 'file',\n 'href': node.attrs.src,\n 'download': node.attrs.title,\n 'data-mime': node.attrs.mimeType,\n 'data-size': String(node.attrs.size),\n ...(node.attrs.hash ? { 'data-hash': node.attrs.hash } : {}),\n }, node.attrs.title || 'Datei'],\n markdownTokenizer: mediaTokenizer('file', 'Datei|File'),\n parseMarkdown: (token, helpers) => helpers.createNode('file', {\n src: token.href,\n title: token.title,\n mimeType: stringAttr(token.attrs?.mimeType),\n size: typeof token.attrs?.size === 'number' ? token.attrs.size : 0,\n hash: stringAttr(token.attrs?.hash) || null,\n }),\n renderMarkdown: node => mediaMarkdown('Datei', node.attrs, { mimeType: node.attrs?.mimeType, size: node.attrs?.size }),\n addCommands() {\n return {\n insertFile: attrs => ({ commands }) => commands.insertContent({ type: this.name, attrs }),\n }\n },\n})\n"],"mappings":"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"}
|
|
@@ -1,35 +1,36 @@
|
|
|
1
|
-
import { FeatureContext
|
|
1
|
+
import { FeatureContext } from "../../core/feature.js";
|
|
2
2
|
import "../../core/index.js";
|
|
3
3
|
import { Editor, Extension, JSONContent } from "@tiptap/core";
|
|
4
4
|
//#region src/features/media/upload.d.ts
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
/** Default upload: POSTs `file` to the asset endpoint of document `documentId` through the context's HTTP client (size limits per kind, see schema.ts). */
|
|
8
|
-
export declare function postUpload(fetch: FeatureContext['fetch'], documentId: string, file: File): Promise<{
|
|
5
|
+
/** Stores a file and resolves with the URL it is addressed by. */
|
|
6
|
+
type UploadFile = (file: File) => Promise<{
|
|
9
7
|
url: string;
|
|
8
|
+
sha256?: string;
|
|
10
9
|
}>;
|
|
11
|
-
/**
|
|
12
|
-
export
|
|
10
|
+
/** `importFiles` of the media feature: imports `files` at `pos` (default: the selection), toasting failures; resolves whether every file was imported. */
|
|
11
|
+
export type ImportFilesFn = (editor: Editor, files: File[] | FileList, pos?: number) => Promise<boolean>;
|
|
12
|
+
/** The upload of a surface: the backend's asset store for its `documentId` (default: the shared `scratch` owner; size limits per kind, see schema.ts). */
|
|
13
|
+
export declare const uploadOf: (ctx: FeatureContext) => UploadFile;
|
|
13
14
|
/** Makes the upload and the file import reachable as `editor.storage.media` (drop/paste, toolbar, slash menu, recorder). */
|
|
14
15
|
export declare const Media: Extension<{
|
|
15
|
-
upload:
|
|
16
|
+
upload: UploadFile;
|
|
16
17
|
importFiles: ImportFilesFn;
|
|
17
18
|
}, {
|
|
18
|
-
upload:
|
|
19
|
+
upload: UploadFile;
|
|
19
20
|
importFiles: ImportFilesFn;
|
|
20
21
|
}>;
|
|
21
22
|
declare module '@tiptap/core' {
|
|
22
23
|
interface Storage {
|
|
23
24
|
media: {
|
|
24
|
-
upload:
|
|
25
|
+
upload: UploadFile;
|
|
25
26
|
importFiles: ImportFilesFn;
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
/** The node that embeds uploaded `file` from `url
|
|
30
|
-
export declare function mediaNodeFor(file: File, url: string): JSONContent | null;
|
|
31
|
-
/** The file block for an uploaded `file` that has no player or image node (PDF, office documents, …)
|
|
32
|
-
export declare function fileNodeFor(file: File, url: string): JSONContent;
|
|
30
|
+
/** The node that embeds uploaded `file` from `url`, remembering the upload's `hash` (SHA-256 hex; none when the backend did not report one); null for files uploads do not accept. */
|
|
31
|
+
export declare function mediaNodeFor(file: File, url: string, hash?: string): JSONContent | null;
|
|
32
|
+
/** The file block for an uploaded `file` that has no player or image node (PDF, office documents, …); `hash` as in `mediaNodeFor`. */
|
|
33
|
+
export declare function fileNodeFor(file: File, url: string, hash?: string): JSONContent;
|
|
33
34
|
/** Human-readable byte count: 1024-based, one decimal (`1536` → `1.5 KB`), units B/KB/MB/GB. */
|
|
34
35
|
export declare function formatBytes(bytes: number): string;
|
|
35
36
|
/** Transaction meta the recorder modal (AudioRecorderModal) listens for: open it, inserting at the current caret. */
|
|
@@ -38,4 +39,5 @@ export declare function openAudioRecorder(editor: Editor): void;
|
|
|
38
39
|
/** Opens the browser's file picker; resolves the chosen files, `[]` when the picker is cancelled. */
|
|
39
40
|
export declare function pickFiles(accept: string, multiple?: boolean): Promise<File[]>;
|
|
40
41
|
//#endregion
|
|
42
|
+
export {};
|
|
41
43
|
//# sourceMappingURL=upload.d.ts.map
|
|
@@ -2,17 +2,8 @@ import "./assets.js";
|
|
|
2
2
|
import { mediaKindOf, mediaMime } from "./schema.js";
|
|
3
3
|
import { Extension } from "@tiptap/core";
|
|
4
4
|
//#region src/features/media/upload.ts
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
const body = new FormData();
|
|
8
|
-
body.append("file", file);
|
|
9
|
-
return await fetch(`/api/editor/assets/${documentId}`, {
|
|
10
|
-
method: "POST",
|
|
11
|
-
body
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
/** The upload of a surface: the host's `upload` prop, else the asset endpoint of its `documentId` (default: the shared `scratch` owner). */
|
|
15
|
-
const uploadOf = (ctx) => ctx.upload ?? ((file) => postUpload(ctx.fetch, ctx.documentId ?? "scratch", file));
|
|
5
|
+
/** The upload of a surface: the backend's asset store for its `documentId` (default: the shared `scratch` owner; size limits per kind, see schema.ts). */
|
|
6
|
+
const uploadOf = (ctx) => (file) => ctx.backend.assets ? ctx.backend.assets.upload(ctx.documentId ?? "scratch", file) : Promise.reject(/* @__PURE__ */ new Error(`@ecsplico/editor: backend "${ctx.backend.name}" has no assets capability`));
|
|
16
7
|
/** Makes the upload and the file import reachable as `editor.storage.media` (drop/paste, toolbar, slash menu, recorder). */
|
|
17
8
|
const Media = Extension.create({
|
|
18
9
|
name: "media",
|
|
@@ -29,15 +20,16 @@ const Media = Extension.create({
|
|
|
29
20
|
};
|
|
30
21
|
}
|
|
31
22
|
});
|
|
32
|
-
/** The node that embeds uploaded `file` from `url
|
|
33
|
-
function mediaNodeFor(file, url) {
|
|
23
|
+
/** The node that embeds uploaded `file` from `url`, remembering the upload's `hash` (SHA-256 hex; none when the backend did not report one); null for files uploads do not accept. */
|
|
24
|
+
function mediaNodeFor(file, url, hash) {
|
|
34
25
|
const kind = mediaKindOf(file.type);
|
|
35
26
|
if (!kind) return null;
|
|
36
27
|
if (kind === "image") return {
|
|
37
28
|
type: "image",
|
|
38
29
|
attrs: {
|
|
39
30
|
src: url,
|
|
40
|
-
alt: file.name
|
|
31
|
+
alt: file.name,
|
|
32
|
+
hash: hash ?? null
|
|
41
33
|
}
|
|
42
34
|
};
|
|
43
35
|
return {
|
|
@@ -45,19 +37,21 @@ function mediaNodeFor(file, url) {
|
|
|
45
37
|
attrs: {
|
|
46
38
|
src: url,
|
|
47
39
|
title: file.name,
|
|
48
|
-
mimeType: mediaMime(file.type)
|
|
40
|
+
mimeType: mediaMime(file.type),
|
|
41
|
+
hash: hash ?? null
|
|
49
42
|
}
|
|
50
43
|
};
|
|
51
44
|
}
|
|
52
|
-
/** The file block for an uploaded `file` that has no player or image node (PDF, office documents, …)
|
|
53
|
-
function fileNodeFor(file, url) {
|
|
45
|
+
/** The file block for an uploaded `file` that has no player or image node (PDF, office documents, …); `hash` as in `mediaNodeFor`. */
|
|
46
|
+
function fileNodeFor(file, url, hash) {
|
|
54
47
|
return {
|
|
55
48
|
type: "file",
|
|
56
49
|
attrs: {
|
|
57
50
|
src: url,
|
|
58
51
|
title: file.name,
|
|
59
52
|
mimeType: mediaMime(file.type) || "application/octet-stream",
|
|
60
|
-
size: file.size
|
|
53
|
+
size: file.size,
|
|
54
|
+
hash: hash ?? null
|
|
61
55
|
}
|
|
62
56
|
};
|
|
63
57
|
}
|
|
@@ -101,6 +95,6 @@ function pickFiles(accept, multiple = true) {
|
|
|
101
95
|
return promise;
|
|
102
96
|
}
|
|
103
97
|
//#endregion
|
|
104
|
-
export { AUDIO_RECORDER_OPEN, Media, fileNodeFor, formatBytes, mediaNodeFor, openAudioRecorder, pickFiles,
|
|
98
|
+
export { AUDIO_RECORDER_OPEN, Media, fileNodeFor, formatBytes, mediaNodeFor, openAudioRecorder, pickFiles, uploadOf };
|
|
105
99
|
|
|
106
100
|
//# sourceMappingURL=upload.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","names":[],"sources":["../../../src/features/media/upload.ts"],"sourcesContent":["import { type Editor, Extension, type JSONContent } from '@tiptap/core'\nimport type { FeatureContext
|
|
1
|
+
{"version":3,"file":"upload.js","names":[],"sources":["../../../src/features/media/upload.ts"],"sourcesContent":["import { type Editor, Extension, type JSONContent } from '@tiptap/core'\nimport type { FeatureContext } from '../../core'\nimport { SCRATCH_DOCUMENT_ID } from './assets'\nimport { mediaKindOf, mediaMime } from './schema'\n\n/** Stores a file and resolves with the URL it is addressed by. */\ntype UploadFile = (file: File) => Promise<{ url: string, sha256?: string }>\n\n/** `importFiles` of the media feature: imports `files` at `pos` (default: the selection), toasting failures; resolves whether every file was imported. */\nexport type ImportFilesFn = (editor: Editor, files: File[] | FileList, pos?: number) => Promise<boolean>\n\n/** The upload of a surface: the backend's asset store for its `documentId` (default: the shared `scratch` owner; size limits per kind, see schema.ts). */\nexport const uploadOf = (ctx: FeatureContext): UploadFile =>\n file => ctx.backend.assets\n ? ctx.backend.assets.upload(ctx.documentId ?? SCRATCH_DOCUMENT_ID, file)\n : Promise.reject(new Error(`@ecsplico/editor: backend \"${ctx.backend.name}\" has no assets capability`))\n\n/** Makes the upload and the file import reachable as `editor.storage.media` (drop/paste, toolbar, slash menu, recorder). */\nexport const Media = Extension.create<{ upload: UploadFile, importFiles: ImportFilesFn }, { upload: UploadFile, importFiles: ImportFilesFn }>({\n name: 'media',\n\n addOptions() {\n return {\n upload: () => Promise.reject(new Error('@ecsplico/editor: Media.configure({ upload }) fehlt')),\n importFiles: () => Promise.reject(new Error('@ecsplico/editor: Media.configure({ importFiles }) fehlt')),\n }\n },\n\n addStorage() {\n return { upload: this.options.upload, importFiles: this.options.importFiles }\n },\n})\n\ndeclare module '@tiptap/core' {\n interface Storage {\n media: { upload: UploadFile, importFiles: ImportFilesFn }\n }\n}\n\n/** The node that embeds uploaded `file` from `url`, remembering the upload's `hash` (SHA-256 hex; none when the backend did not report one); null for files uploads do not accept. */\nexport function mediaNodeFor(file: File, url: string, hash?: string): JSONContent | null {\n const kind = mediaKindOf(file.type)\n if (!kind) return null\n if (kind === 'image') return { type: 'image', attrs: { src: url, alt: file.name, hash: hash ?? null } }\n return { type: kind, attrs: { src: url, title: file.name, mimeType: mediaMime(file.type), hash: hash ?? null } }\n}\n\n/** The file block for an uploaded `file` that has no player or image node (PDF, office documents, …); `hash` as in `mediaNodeFor`. */\nexport function fileNodeFor(file: File, url: string, hash?: string): JSONContent {\n return {\n type: 'file',\n attrs: { src: url, title: file.name, mimeType: mediaMime(file.type) || 'application/octet-stream', size: file.size, hash: hash ?? null },\n }\n}\n\n/** Human-readable byte count: 1024-based, one decimal (`1536` → `1.5 KB`), units B/KB/MB/GB. */\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB']\n let value = Math.max(0, bytes)\n let unit = 0\n while (value >= 1024 && unit < units.length - 1) {\n value /= 1024\n unit++\n }\n return unit === 0 ? `${value} B` : `${value.toFixed(1)} ${units[unit]}`\n}\n\n/** Transaction meta the recorder modal (AudioRecorderModal) listens for: open it, inserting at the current caret. */\nexport const AUDIO_RECORDER_OPEN = 'audioRecorderOpen'\n\nexport function openAudioRecorder(editor: Editor): void {\n editor.view.dispatch(editor.state.tr.setMeta(AUDIO_RECORDER_OPEN, true).setMeta('addToHistory', false))\n}\n\n/** Opens the browser's file picker; resolves the chosen files, `[]` when the picker is cancelled. */\nexport function pickFiles(accept: string, multiple = true): Promise<File[]> {\n const { promise, resolve } = Promise.withResolvers<File[]>()\n const input = document.createElement('input')\n input.type = 'file'\n input.accept = accept\n input.multiple = multiple\n input.hidden = true\n // Attached while open: some Safari versions fire no `change` for detached inputs.\n document.body.append(input)\n const done = (files: File[]) => {\n input.remove()\n resolve(files)\n }\n input.addEventListener('change', () => done(Array.from(input.files ?? [])), { once: true })\n input.addEventListener('cancel', () => done([]), { once: true })\n input.click()\n return promise\n}\n"],"mappings":";;;;;AAYA,MAAa,YAAY,SACvB,SAAQ,IAAI,QAAQ,SAChB,IAAI,QAAQ,OAAO,OAAO,IAAI,cAAA,WAAmC,IAAI,IACrE,QAAQ,uBAAO,IAAI,MAAM,8BAA8B,IAAI,QAAQ,KAAK,2BAA2B,CAAC;;AAG1G,MAAa,QAAQ,UAAU,OAA+G;CAC5I,MAAM;CAEN,aAAa;EACX,OAAO;GACL,cAAc,QAAQ,uBAAO,IAAI,MAAM,qDAAqD,CAAC;GAC7F,mBAAmB,QAAQ,uBAAO,IAAI,MAAM,0DAA0D,CAAC;EACzG;CACF;CAEA,aAAa;EACX,OAAO;GAAE,QAAQ,KAAK,QAAQ;GAAQ,aAAa,KAAK,QAAQ;EAAY;CAC9E;AACF,CAAC;;AASD,SAAgB,aAAa,MAAY,KAAa,MAAmC;CACvF,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,SAAS,SAAS,OAAO;EAAE,MAAM;EAAS,OAAO;GAAE,KAAK;GAAK,KAAK,KAAK;GAAM,MAAM,QAAQ;EAAK;CAAE;CACtG,OAAO;EAAE,MAAM;EAAM,OAAO;GAAE,KAAK;GAAK,OAAO,KAAK;GAAM,UAAU,UAAU,KAAK,IAAI;GAAG,MAAM,QAAQ;EAAK;CAAE;AACjH;;AAGA,SAAgB,YAAY,MAAY,KAAa,MAA4B;CAC/E,OAAO;EACL,MAAM;EACN,OAAO;GAAE,KAAK;GAAK,OAAO,KAAK;GAAM,UAAU,UAAU,KAAK,IAAI,KAAK;GAA4B,MAAM,KAAK;GAAM,MAAM,QAAQ;EAAK;CACzI;AACF;;AAGA,SAAgB,YAAY,OAAuB;CACjD,MAAM,QAAQ;EAAC;EAAK;EAAM;EAAM;CAAI;CACpC,IAAI,QAAQ,KAAK,IAAI,GAAG,KAAK;CAC7B,IAAI,OAAO;CACX,OAAO,SAAS,QAAQ,OAAO,MAAM,SAAS,GAAG;EAC/C,SAAS;EACT;CACF;CACA,OAAO,SAAS,IAAI,GAAG,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,EAAE,GAAG,MAAM;AAClE;;AAGA,MAAa,sBAAsB;AAEnC,SAAgB,kBAAkB,QAAsB;CACtD,OAAO,KAAK,SAAS,OAAO,MAAM,GAAG,QAAQ,qBAAqB,IAAI,CAAC,CAAC,QAAQ,gBAAgB,KAAK,CAAC;AACxG;;AAGA,SAAgB,UAAU,QAAgB,WAAW,MAAuB;CAC1E,MAAM,EAAE,SAAS,YAAY,QAAQ,cAAsB;CAC3D,MAAM,QAAQ,SAAS,cAAc,OAAO;CAC5C,MAAM,OAAO;CACb,MAAM,SAAS;CACf,MAAM,WAAW;CACjB,MAAM,SAAS;CAEf,SAAS,KAAK,OAAO,KAAK;CAC1B,MAAM,QAAQ,UAAkB;EAC9B,MAAM,OAAO;EACb,QAAQ,KAAK;CACf;CACA,MAAM,iBAAiB,gBAAgB,KAAK,MAAM,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC;CAC1F,MAAM,iBAAiB,gBAAgB,KAAK,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC;CAC/D,MAAM,MAAM;CACZ,OAAO;AACT"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { EditorFeature } from "../../core/feature.js";
|
|
2
|
-
import "../../core/
|
|
3
|
-
import { MentionAttrs, MentionNode
|
|
2
|
+
import { MentionUser } from "../../core/backend-types.js";
|
|
3
|
+
import { MentionAttrs, MentionNode } from "./mention.js";
|
|
4
4
|
import { MentionTarget, mentionUsersIn, mentionsFromText } from "./mention-text.js";
|
|
5
5
|
import { TAG_NODE, TagAttrs, TagNode, TagOptions, TagSuggestionItem, TagSuggestionPluginKey, collectTagNames, normalizeTagName, tagsFromText } from "./tag.js";
|
|
6
6
|
import "./schema.js";
|
|
7
|
+
import "../../core/index.js";
|
|
7
8
|
import { mentionSuggestion } from "./mention-suggestion.js";
|
|
8
9
|
import { mentionsMetadata } from "./metadata-defaults.js";
|
|
9
10
|
import { normalizeMentions } from "./normalize.js";
|
|
@@ -11,7 +12,7 @@ import { tagSuggestion } from "./tag-suggestion.js";
|
|
|
11
12
|
//#region src/features/mentions/index.d.ts
|
|
12
13
|
/**
|
|
13
14
|
* `@user` mention chips and `#tag` chips with their suggestion popups. Without a host list, `mentions` and `hashtags`
|
|
14
|
-
* come from `/api/editor/users` and `/api/editor/tags`
|
|
15
|
+
* come from the context's backend (`users` and `tags`; the HTTP backend asks `/api/editor/users` and `/api/editor/tags`), and only once a popup is used.
|
|
15
16
|
* Contributes the `normalize` stage: `@name` / `#tag` text of imported or AI-written Markdown becomes chips when it
|
|
16
17
|
* matches a known user or an existing tag. Contributes no components (`EditorFeature<never>`), so it fits a preset of
|
|
17
18
|
* any framework layer.
|
|
@@ -2,6 +2,7 @@ import { metadataOf } from "../../core/metadata.js";
|
|
|
2
2
|
import { MentionNode } from "./mention.js";
|
|
3
3
|
import { TAG_NODE, TagNode, TagSuggestionPluginKey, collectTagNames, normalizeTagName, tagsFromText } from "./tag.js";
|
|
4
4
|
import { mentionUsersIn, mentionsFromText } from "./mention-text.js";
|
|
5
|
+
import { mentionsSchemaExtensions } from "./schema.js";
|
|
5
6
|
import { mentionSuggestion } from "./mention-suggestion.js";
|
|
6
7
|
import { mentionsMetadata } from "./metadata-defaults.js";
|
|
7
8
|
import { normalizeMentions } from "./normalize.js";
|
|
@@ -9,7 +10,7 @@ import { tagSuggestion } from "./tag-suggestion.js";
|
|
|
9
10
|
//#region src/features/mentions/index.ts
|
|
10
11
|
/**
|
|
11
12
|
* `@user` mention chips and `#tag` chips with their suggestion popups. Without a host list, `mentions` and `hashtags`
|
|
12
|
-
* come from `/api/editor/users` and `/api/editor/tags`
|
|
13
|
+
* come from the context's backend (`users` and `tags`; the HTTP backend asks `/api/editor/users` and `/api/editor/tags`), and only once a popup is used.
|
|
13
14
|
* Contributes the `normalize` stage: `@name` / `#tag` text of imported or AI-written Markdown becomes chips when it
|
|
14
15
|
* matches a known user or an existing tag. Contributes no components (`EditorFeature<never>`), so it fits a preset of
|
|
15
16
|
* any framework layer.
|
|
@@ -17,6 +18,8 @@ import { tagSuggestion } from "./tag-suggestion.js";
|
|
|
17
18
|
function mentionsFeature() {
|
|
18
19
|
return {
|
|
19
20
|
id: "mentions",
|
|
21
|
+
dimension: "content",
|
|
22
|
+
schemaExtensions: mentionsSchemaExtensions,
|
|
20
23
|
extensions: (ctx) => [MentionNode.configure({ suggestion: mentionSuggestion(ctx.t) }), TagNode.configure({
|
|
21
24
|
suggestion: tagSuggestion(ctx.t),
|
|
22
25
|
onCreate: (editor, name) => metadataOf(editor).create("hashtags", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/features/mentions/index.ts"],"sourcesContent":["import type { EditorFeature } from '../../core'\nimport { metadataOf } from '../../core'\nimport { mentionSuggestion } from './mention-suggestion'\nimport { mentionsMetadata } from './metadata-defaults'\nimport { MentionNode } from './mention'\nimport { normalizeMentions } from './normalize'\nimport { tagSuggestion } from './tag-suggestion'\nimport { TagNode } from './tag'\n\nexport { mentionSuggestion } from './mention-suggestion'\nexport { mentionsMetadata } from './metadata-defaults'\nexport { normalizeMentions } from './normalize'\nexport { tagSuggestion } from './tag-suggestion'\nexport {\n collectTagNames,\n type MentionAttrs,\n MentionNode,\n type MentionTarget,\n mentionsFromText,\n mentionUsersIn,\n type MentionUser,\n normalizeTagName,\n TAG_NODE,\n TagNode,\n type TagAttrs,\n type TagOptions,\n type TagSuggestionItem,\n tagsFromText,\n TagSuggestionPluginKey,\n} from './schema'\n\n/**\n * `@user` mention chips and `#tag` chips with their suggestion popups. Without a host list, `mentions` and `hashtags`\n * come from `/api/editor/users` and `/api/editor/tags`
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/features/mentions/index.ts"],"sourcesContent":["import type { EditorFeature } from '../../core'\nimport { metadataOf } from '../../core'\nimport { mentionSuggestion } from './mention-suggestion'\nimport { mentionsMetadata } from './metadata-defaults'\nimport { MentionNode } from './mention'\nimport { mentionsSchemaExtensions } from './schema'\nimport { normalizeMentions } from './normalize'\nimport { tagSuggestion } from './tag-suggestion'\nimport { TagNode } from './tag'\n\nexport { mentionSuggestion } from './mention-suggestion'\nexport { mentionsMetadata } from './metadata-defaults'\nexport { normalizeMentions } from './normalize'\nexport { tagSuggestion } from './tag-suggestion'\nexport {\n collectTagNames,\n type MentionAttrs,\n MentionNode,\n type MentionTarget,\n mentionsFromText,\n mentionUsersIn,\n type MentionUser,\n normalizeTagName,\n TAG_NODE,\n TagNode,\n type TagAttrs,\n type TagOptions,\n type TagSuggestionItem,\n tagsFromText,\n TagSuggestionPluginKey,\n} from './schema'\n\n/**\n * `@user` mention chips and `#tag` chips with their suggestion popups. Without a host list, `mentions` and `hashtags`\n * come from the context's backend (`users` and `tags`; the HTTP backend asks `/api/editor/users` and `/api/editor/tags`), and only once a popup is used.\n * Contributes the `normalize` stage: `@name` / `#tag` text of imported or AI-written Markdown becomes chips when it\n * matches a known user or an existing tag. Contributes no components (`EditorFeature<never>`), so it fits a preset of\n * any framework layer.\n */\nexport function mentionsFeature(): EditorFeature<never> {\n return {\n id: 'mentions',\n dimension: 'content',\n schemaExtensions: mentionsSchemaExtensions,\n extensions: ctx => [\n MentionNode.configure({ suggestion: mentionSuggestion(ctx.t) }),\n TagNode.configure({\n suggestion: tagSuggestion(ctx.t),\n onCreate: (editor, name) => metadataOf(editor).create('hashtags', { id: name, label: name }),\n }),\n ],\n metadataDefaults: ctx => mentionsMetadata(ctx),\n blocks: { normalize: normalizeMentions },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAuCA,SAAgB,kBAAwC;CACtD,OAAO;EACL,IAAI;EACJ,WAAW;EACX,kBAAkB;EAClB,aAAY,QAAO,CACjB,YAAY,UAAU,EAAE,YAAY,kBAAkB,IAAI,CAAC,EAAE,CAAC,GAC9D,QAAQ,UAAU;GAChB,YAAY,cAAc,IAAI,CAAC;GAC/B,WAAW,QAAQ,SAAS,WAAW,MAAM,CAAC,CAAC,OAAO,YAAY;IAAE,IAAI;IAAM,OAAO;GAAK,CAAC;EAC7F,CAAC,CACH;EACA,mBAAkB,QAAO,iBAAiB,GAAG;EAC7C,QAAQ,EAAE,WAAW,kBAAkB;CACzC;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MentionUser } from "
|
|
1
|
+
import { MentionUser } from "../../core/backend-types.js";
|
|
2
2
|
import { JSONContent } from "@tiptap/core";
|
|
3
3
|
//#region src/features/mentions/mention-text.d.ts
|
|
4
4
|
/** A user `@username` may resolve to: a registered user, or the attrs of an existing chip (colour possibly unset). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mention-text.js","names":[],"sources":["../../../src/features/mentions/mention-text.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport type { MentionUser } from '
|
|
1
|
+
{"version":3,"file":"mention-text.js","names":[],"sources":["../../../src/features/mentions/mention-text.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core'\nimport type { MentionUser } from '../../core/backend-types'\n\n/** A user `@username` may resolve to: a registered user, or the attrs of an existing chip (colour possibly unset). */\nexport type MentionTarget = Pick<MentionUser, 'id' | 'username'> & { color: string | null }\n\n/**\n * Turns `@username` tokens in text nodes into `mention` nodes (attrs id, label = username, color) — for\n * AI-generated Markdown, whose parser only knows the `[@ …]` shortcode. Matches known users only,\n * case-insensitively; unknown `@foo`, e-mail addresses and text in code blocks, inline code or links stay plain.\n * Returns the input unchanged when nothing matched.\n */\nexport function mentionsFromText(json: JSONContent, users: readonly MentionTarget[]): JSONContent {\n const byName = new Map(users.filter(u => u.username).map(u => [u.username.toLowerCase(), u]))\n if (!byName.size) return json\n const names = [...byName.keys()].sort((a, b) => b.length - a.length).map(n => n.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n // Not preceded by a word char, `@` or `.` (e-mail), not followed by a word char or `-`; a trailing `.` ends the sentence.\n const token = new RegExp(`(?<![\\\\p{L}\\\\p{N}_@.])@(${names.join('|')})(?![\\\\p{L}\\\\p{N}_-]|\\\\.[\\\\p{L}\\\\p{N}_])`, 'giu')\n\n const splitText = (node: JSONContent): JSONContent[] => {\n const text = node.text ?? ''\n // Text in inline code or a link stays literal.\n if (!text.includes('@') || node.marks?.some(m => m.type === 'code' || m.type === 'link')) return [node]\n const out: JSONContent[] = []\n let last = 0\n for (const match of text.matchAll(token)) {\n const at = match.index ?? 0\n const user = byName.get(match[1]!.toLowerCase())!\n if (at > last) out.push({ ...node, text: text.slice(last, at) })\n out.push({\n type: 'mention',\n attrs: { id: user.id, label: user.username, color: user.color },\n ...(node.marks?.length ? { marks: node.marks } : {}),\n })\n last = at + match[0].length\n }\n if (!out.length) return [node]\n if (last < text.length) out.push({ ...node, text: text.slice(last) })\n return out\n }\n\n const walk = (node: JSONContent): JSONContent => {\n if (!node.content || node.type === 'codeBlock') return node\n let changed = false\n const content = node.content.flatMap((child) => {\n const next = child.type === 'text' ? splitText(child) : [walk(child)]\n if (next.length !== 1 || next[0] !== child) changed = true\n return next\n })\n return changed ? { ...node, content } : node\n }\n return walk(json)\n}\n\n/** Users of the mention chips inside a JSON tree, e.g. the range an AI result replaces (so echoed `@name`s stay chips). */\nexport function mentionUsersIn(json: JSONContent | JSONContent[]): MentionTarget[] {\n const found = new Map<string, MentionTarget>()\n const visit = (node: JSONContent) => {\n if (node.type === 'mention' && node.attrs?.id && node.attrs.label) {\n found.set(String(node.attrs.id), { id: String(node.attrs.id), username: String(node.attrs.label), color: node.attrs.color ?? null })\n }\n node.content?.forEach(visit)\n }\n ;(Array.isArray(json) ? json : [json]).forEach(visit)\n return [...found.values()]\n}\n"],"mappings":";;;;;;;AAYA,SAAgB,iBAAiB,MAAmB,OAA8C;CAChG,MAAM,SAAS,IAAI,IAAI,MAAM,QAAO,MAAK,EAAE,QAAQ,CAAC,CAAC,KAAI,MAAK,CAAC,EAAE,SAAS,YAAY,GAAG,CAAC,CAAC,CAAC;CAC5F,IAAI,CAAC,OAAO,MAAM,OAAO;CACzB,MAAM,QAAQ,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,KAAI,MAAK,EAAE,QAAQ,uBAAuB,MAAM,CAAC;CAEtH,MAAM,QAAQ,IAAI,OAAO,2BAA2B,MAAM,KAAK,GAAG,EAAE,2CAA2C,KAAK;CAEpH,MAAM,aAAa,SAAqC;EACtD,MAAM,OAAO,KAAK,QAAQ;EAE1B,IAAI,CAAC,KAAK,SAAS,GAAG,KAAK,KAAK,OAAO,MAAK,MAAK,EAAE,SAAS,UAAU,EAAE,SAAS,MAAM,GAAG,OAAO,CAAC,IAAI;EACtG,MAAM,MAAqB,CAAC;EAC5B,IAAI,OAAO;EACX,KAAK,MAAM,SAAS,KAAK,SAAS,KAAK,GAAG;GACxC,MAAM,KAAK,MAAM,SAAS;GAC1B,MAAM,OAAO,OAAO,IAAI,MAAM,EAAE,CAAE,YAAY,CAAC;GAC/C,IAAI,KAAK,MAAM,IAAI,KAAK;IAAE,GAAG;IAAM,MAAM,KAAK,MAAM,MAAM,EAAE;GAAE,CAAC;GAC/D,IAAI,KAAK;IACP,MAAM;IACN,OAAO;KAAE,IAAI,KAAK;KAAI,OAAO,KAAK;KAAU,OAAO,KAAK;IAAM;IAC9D,GAAI,KAAK,OAAO,SAAS,EAAE,OAAO,KAAK,MAAM,IAAI,CAAC;GACpD,CAAC;GACD,OAAO,KAAK,MAAM,EAAE,CAAC;EACvB;EACA,IAAI,CAAC,IAAI,QAAQ,OAAO,CAAC,IAAI;EAC7B,IAAI,OAAO,KAAK,QAAQ,IAAI,KAAK;GAAE,GAAG;GAAM,MAAM,KAAK,MAAM,IAAI;EAAE,CAAC;EACpE,OAAO;CACT;CAEA,MAAM,QAAQ,SAAmC;EAC/C,IAAI,CAAC,KAAK,WAAW,KAAK,SAAS,aAAa,OAAO;EACvD,IAAI,UAAU;EACd,MAAM,UAAU,KAAK,QAAQ,SAAS,UAAU;GAC9C,MAAM,OAAO,MAAM,SAAS,SAAS,UAAU,KAAK,IAAI,CAAC,KAAK,KAAK,CAAC;GACpE,IAAI,KAAK,WAAW,KAAK,KAAK,OAAO,OAAO,UAAU;GACtD,OAAO;EACT,CAAC;EACD,OAAO,UAAU;GAAE,GAAG;GAAM;EAAQ,IAAI;CAC1C;CACA,OAAO,KAAK,IAAI;AAClB;;AAGA,SAAgB,eAAe,MAAoD;CACjF,MAAM,wBAAQ,IAAI,IAA2B;CAC7C,MAAM,SAAS,SAAsB;EACnC,IAAI,KAAK,SAAS,aAAa,KAAK,OAAO,MAAM,KAAK,MAAM,OAC1D,MAAM,IAAI,OAAO,KAAK,MAAM,EAAE,GAAG;GAAE,IAAI,OAAO,KAAK,MAAM,EAAE;GAAG,UAAU,OAAO,KAAK,MAAM,KAAK;GAAG,OAAO,KAAK,MAAM,SAAS;EAAK,CAAC;EAErI,KAAK,SAAS,QAAQ,KAAK;CAC7B;CACC,CAAC,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,EAAA,CAAG,QAAQ,KAAK;CACpD,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC;AAC3B"}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
//#region src/features/mentions/mention.d.ts
|
|
2
|
-
/** A user as offered for `@` mentions (`GET /api/editor/users`); never carries credentials. */
|
|
3
|
-
export interface MentionUser {
|
|
4
|
-
id: string;
|
|
5
|
-
username: string;
|
|
6
|
-
color: string;
|
|
7
|
-
}
|
|
8
2
|
/** Attributes of a mention chip: `label` is the username, `color` the user's colour, both copied in at insert time. */
|
|
9
3
|
export type MentionAttrs = {
|
|
10
4
|
id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mention.js","names":[],"sources":["../../../src/features/mentions/mention.ts"],"sourcesContent":["import { Mention } from '@tiptap/extension-mention'\nimport { HEX_COLOR } from '../../core/schema/hex-color'\n\n/**
|
|
1
|
+
{"version":3,"file":"mention.js","names":[],"sources":["../../../src/features/mentions/mention.ts"],"sourcesContent":["import { Mention } from '@tiptap/extension-mention'\nimport { HEX_COLOR } from '../../core/schema/hex-color'\n\n/** Attributes of a mention chip: `label` is the username, `color` the user's colour, both copied in at insert time. */\nexport type MentionAttrs = {\n id: string\n label: string\n color: string | null\n}\n\n/**\n * Schema part of the `@username` chip, shared by the client editor and the server (collab schema, Markdown).\n * The client adds the suggestion popup via `.configure({ suggestion })` in the mentions feature.\n */\nexport const MentionNode = Mention.extend({\n addOptions() {\n return { ...this.parent!(), HTMLAttributes: { class: 'mention' } }\n },\n addAttributes() {\n return {\n ...this.parent?.(),\n color: {\n default: null,\n parseHTML: el => el.getAttribute('data-color'),\n renderHTML: attrs => HEX_COLOR.test(String(attrs.color ?? ''))\n ? { 'data-color': attrs.color, 'style': `--mention-color: ${attrs.color}` }\n : {},\n },\n }\n },\n // Markdown export (editor.getMarkdown(), AI context/selection) shows the chip as plain `@username`.\n renderMarkdown: node => `@${node.attrs?.label ?? node.attrs?.id ?? ''}`,\n})\n"],"mappings":";;;;;;;AAcA,MAAa,cAAc,QAAQ,OAAO;CACxC,aAAa;EACX,OAAO;GAAE,GAAG,KAAK,OAAQ;GAAG,gBAAgB,EAAE,OAAO,UAAU;EAAE;CACnE;CACA,gBAAgB;EACd,OAAO;GACL,GAAG,KAAK,SAAS;GACjB,OAAO;IACL,SAAS;IACT,YAAW,OAAM,GAAG,aAAa,YAAY;IAC7C,aAAY,UAAS,UAAU,KAAK,OAAO,MAAM,SAAS,EAAE,CAAC,IACzD;KAAE,cAAc,MAAM;KAAO,SAAS,oBAAoB,MAAM;IAAQ,IACxE,CAAC;GACP;EACF;CACF;CAEA,iBAAgB,SAAQ,IAAI,KAAK,OAAO,SAAS,KAAK,OAAO,MAAM;AACrE,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { EditorMetadata } from "../../core/metadata-types.js";
|
|
|
2
2
|
import { FeatureContext } from "../../core/feature.js";
|
|
3
3
|
import "../../core/index.js";
|
|
4
4
|
//#region src/features/mentions/metadata-defaults.d.ts
|
|
5
|
-
/** Built-in `mentions` and `hashtags` lists when the host supplies none: users and tags from the
|
|
6
|
-
export declare function mentionsMetadata(ctx: Pick<FeatureContext, '
|
|
5
|
+
/** Built-in `mentions` and `hashtags` lists when the host supplies none: users and tags from the context's backend (`users`, `tags`); a backend without the capability offers none. */
|
|
6
|
+
export declare function mentionsMetadata(ctx: Pick<FeatureContext, 'backend'>): EditorMetadata;
|
|
7
7
|
//#endregion
|
|
8
8
|
//# sourceMappingURL=metadata-defaults.d.ts.map
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
import { normalizeTagName } from "./tag.js";
|
|
2
2
|
//#region src/features/mentions/metadata-defaults.ts
|
|
3
|
-
/** Built-in `mentions` and `hashtags` lists when the host supplies none: users and tags from the
|
|
3
|
+
/** Built-in `mentions` and `hashtags` lists when the host supplies none: users and tags from the context's backend (`users`, `tags`); a backend without the capability offers none. */
|
|
4
4
|
function mentionsMetadata(ctx) {
|
|
5
5
|
return {
|
|
6
6
|
mentions: async ({ query, signal }) => {
|
|
7
|
-
return (await ctx.
|
|
8
|
-
query: { q: query },
|
|
9
|
-
signal
|
|
10
|
-
})).map(({ id, username, color }) => ({
|
|
7
|
+
return (await ctx.backend.users?.search(query, signal) ?? []).map(({ id, username, color }) => ({
|
|
11
8
|
id,
|
|
12
9
|
label: username,
|
|
13
10
|
color
|
|
14
11
|
}));
|
|
15
12
|
},
|
|
16
13
|
hashtags: async ({ query, signal }) => {
|
|
17
|
-
return (await ctx.
|
|
18
|
-
query: { q: normalizeTagName(query) },
|
|
19
|
-
signal
|
|
20
|
-
})).map((tag) => ({
|
|
14
|
+
return (await ctx.backend.tags?.search(normalizeTagName(query), signal) ?? []).map((tag) => ({
|
|
21
15
|
id: tag,
|
|
22
16
|
label: tag
|
|
23
17
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-defaults.js","names":[],"sources":["../../../src/features/mentions/metadata-defaults.ts"],"sourcesContent":["import type { EditorMetadata, FeatureContext } from '../../core'\nimport { normalizeTagName } from './tag'\n\n/** Built-in `mentions` and `hashtags` lists when the host supplies none: users and tags from the
|
|
1
|
+
{"version":3,"file":"metadata-defaults.js","names":[],"sources":["../../../src/features/mentions/metadata-defaults.ts"],"sourcesContent":["import type { EditorMetadata, FeatureContext } from '../../core'\nimport { normalizeTagName } from './tag'\n\n/** Built-in `mentions` and `hashtags` lists when the host supplies none: users and tags from the context's backend (`users`, `tags`); a backend without the capability offers none. */\nexport function mentionsMetadata(ctx: Pick<FeatureContext, 'backend'>): EditorMetadata {\n return {\n mentions: async ({ query, signal }) => {\n const users = await ctx.backend.users?.search(query, signal) ?? []\n return users.map(({ id, username, color }) => ({ id, label: username, color }))\n },\n hashtags: async ({ query, signal }) => {\n const tags = await ctx.backend.tags?.search(normalizeTagName(query), signal) ?? []\n return tags.map(tag => ({ id: tag, label: tag }))\n },\n }\n}\n"],"mappings":";;;AAIA,SAAgB,iBAAiB,KAAsD;CACrF,OAAO;EACL,UAAU,OAAO,EAAE,OAAO,aAAa;GAErC,QADc,MAAM,IAAI,QAAQ,OAAO,OAAO,OAAO,MAAM,KAAK,CAAC,EAAA,CACpD,KAAK,EAAE,IAAI,UAAU,aAAa;IAAE;IAAI,OAAO;IAAU;GAAM,EAAE;EAChF;EACA,UAAU,OAAO,EAAE,OAAO,aAAa;GAErC,QADa,MAAM,IAAI,QAAQ,MAAM,OAAO,iBAAiB,KAAK,GAAG,MAAM,KAAK,CAAC,EAAA,CACrE,KAAI,SAAQ;IAAE,IAAI;IAAK,OAAO;GAAI,EAAE;EAClD;CACF;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MentionUser } from "../../core/backend-types.js";
|
|
2
|
+
import { MentionAttrs, MentionNode } from "./mention.js";
|
|
2
3
|
import { MentionTarget, mentionUsersIn, mentionsFromText } from "./mention-text.js";
|
|
3
4
|
import { TAG_NODE, TagAttrs, TagNode, TagOptions, TagSuggestionItem, TagSuggestionPluginKey, collectTagNames, normalizeTagName, tagsFromText } from "./tag.js";
|
|
4
5
|
import { AnyExtension } from "@tiptap/core";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/mentions/schema.ts"],"sourcesContent":["import type { AnyExtension } from '@tiptap/core'\nimport { MentionNode } from './mention'\nimport { TagNode } from './tag'\n\n// Vue-free and server-importable (`@ecsplico/editor/mentions/schema`): the mention and tag nodes, their Markdown\n// forms and the text helpers that turn `@name` / `#tag` back into chips. The suggestion popups live in the feature.\n\nexport { type MentionAttrs, MentionNode
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/mentions/schema.ts"],"sourcesContent":["import type { AnyExtension } from '@tiptap/core'\nimport { MentionNode } from './mention'\nimport { TagNode } from './tag'\n\n// Vue-free and server-importable (`@ecsplico/editor/mentions/schema`): the mention and tag nodes, their Markdown\n// forms and the text helpers that turn `@name` / `#tag` back into chips. The suggestion popups live in the feature.\n\nexport type { MentionUser } from '../../core/backend-types'\nexport { type MentionAttrs, MentionNode } from './mention'\nexport { type MentionTarget, mentionsFromText, mentionUsersIn } from './mention-text'\nexport { collectTagNames, normalizeTagName, TAG_NODE, TagNode, type TagAttrs, type TagOptions, type TagSuggestionItem, tagsFromText, TagSuggestionPluginKey } from './tag'\n\n/** The mention and tag nodes of the document schema. */\nexport const mentionsSchemaExtensions = (): AnyExtension[] => [MentionNode, TagNode]\n"],"mappings":";;;;;AAaA,MAAa,iCAAiD,CAAC,aAAa,OAAO"}
|
|
@@ -6,7 +6,8 @@ export declare const TABLE_TOOLBAR_GROUP = "table";
|
|
|
6
6
|
/**
|
|
7
7
|
* GFM tables and task lists: the table and task-list nodes (Markdown round-trips through `@tiptap/markdown`, tables as
|
|
8
8
|
* pipe tables, tasks as `- [ ]`/`- [x]`), the toolbar group `table` (insert 3×3, add row, add column, delete row, delete
|
|
9
|
-
* column, delete table) and the slash entries `table.insert` and `task.insert
|
|
9
|
+
* column, delete table) and the slash entries `table.insert` and `task.insert`: one command each, the table commands
|
|
10
|
+
* on the toolbar, `insertTable` and `task.insert` also in the `/` menu. All are offered where the caret has
|
|
10
11
|
* `block.content`. Contributes no components (`EditorFeature<never>`), so it fits a preset of any framework layer.
|
|
11
12
|
*/
|
|
12
13
|
export declare function tablesFeature(): EditorFeature<never>;
|