@formicoidea/labre-core 0.31.0 → 0.33.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/dist/_pkgs/affine-block-attachment/attachment-block.js +1 -1
- package/dist/_pkgs/affine-block-callout/callout-block.d.ts +6 -0
- package/dist/_pkgs/affine-block-callout/callout-block.js +26 -4
- package/dist/_pkgs/affine-block-callout/callout-keymap.js +59 -19
- package/dist/_pkgs/affine-block-callout/commands/callout-to-paragraph.d.ts +20 -0
- package/dist/_pkgs/affine-block-callout/commands/callout-to-paragraph.js +60 -0
- package/dist/_pkgs/affine-block-callout/commands/split-callout.d.ts +17 -0
- package/dist/_pkgs/affine-block-callout/commands/split-callout.js +42 -0
- package/dist/_pkgs/affine-block-callout/configs/slash-menu.js +9 -6
- package/dist/_pkgs/affine-block-callout/emoji-margin.d.ts +9 -0
- package/dist/_pkgs/affine-block-callout/emoji-margin.js +36 -0
- package/dist/_pkgs/affine-block-callout/emoji-menu.d.ts +5 -1
- package/dist/_pkgs/affine-block-callout/emoji-menu.js +5 -0
- package/dist/_pkgs/affine-block-code/code-block-inline.js +1 -1
- package/dist/_pkgs/affine-block-code/code-block.d.ts +14 -0
- package/dist/_pkgs/affine-block-code/code-block.js +44 -6
- package/dist/_pkgs/affine-block-code/code-toolbar/components/code-toolbar.d.ts +2 -0
- package/dist/_pkgs/affine-block-code/code-toolbar/components/code-toolbar.js +23 -14
- package/dist/_pkgs/affine-block-code/code-toolbar/components/more-menu.d.ts +16 -0
- package/dist/_pkgs/affine-block-code/code-toolbar/components/more-menu.js +93 -0
- package/dist/_pkgs/affine-block-code/code-toolbar/config.js +54 -5
- package/dist/_pkgs/affine-block-code/code-toolbar/index.js +1 -1
- package/dist/_pkgs/affine-block-code/effects.d.ts +2 -0
- package/dist/_pkgs/affine-block-code/effects.js +2 -0
- package/dist/_pkgs/affine-block-code/highlight/affine-code-unit.js +6 -1
- package/dist/_pkgs/affine-block-code/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-code/index.js +1 -0
- package/dist/_pkgs/affine-block-code/line-numbers.d.ts +25 -0
- package/dist/_pkgs/affine-block-code/line-numbers.js +27 -0
- package/dist/_pkgs/affine-block-code/styles.js +31 -0
- package/dist/_pkgs/affine-block-data-view/data-view-block.js +1 -0
- package/dist/_pkgs/affine-block-database/components/title/index.js +4 -1
- package/dist/_pkgs/affine-block-database/configs/slash-menu.js +28 -1
- package/dist/_pkgs/affine-block-database/data-source.js +1 -2
- package/dist/_pkgs/affine-block-database/database-block.js +13 -0
- package/dist/_pkgs/affine-block-database/external-data-source.js +1 -1
- package/dist/_pkgs/affine-block-database/properties/paste-url.d.ts +24 -0
- package/dist/_pkgs/affine-block-database/properties/paste-url.js +98 -0
- package/dist/_pkgs/affine-block-database/properties/rich-text/cell-renderer.js +9 -19
- package/dist/_pkgs/affine-block-database/properties/title/text.js +20 -25
- package/dist/_pkgs/affine-block-database/views/index.js +1 -0
- package/dist/_pkgs/affine-block-edgeless-text/edgeless-text-block.js +11 -1
- package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.d.ts +3 -0
- package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.js +48 -1
- package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/font-size.d.ts +17 -0
- package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/font-size.js +24 -0
- package/dist/_pkgs/affine-block-embed/embed-figma-block/embed-figma-service.js +1 -1
- package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.js +2 -2
- package/dist/_pkgs/affine-block-embed-doc/common/doc-trashed.d.ts +9 -0
- package/dist/_pkgs/affine-block-embed-doc/common/doc-trashed.js +10 -0
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/configs/toolbar.js +1 -1
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-linked-doc-block.js +8 -4
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/utils.js +1 -1
- package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/configs/toolbar.js +1 -1
- package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.d.ts +4 -0
- package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-synced-doc-block.js +23 -4
- package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +13 -0
- package/dist/_pkgs/affine-block-frame/frame-manager.js +34 -2
- package/dist/_pkgs/affine-block-frame/frame-tool.js +1 -1
- package/dist/_pkgs/affine-block-image/components/page-image-block.js +1 -1
- package/dist/_pkgs/affine-block-image/image-edgeless-block.js +1 -1
- package/dist/_pkgs/affine-block-latex/styles.js +6 -1
- package/dist/_pkgs/affine-block-list/utils/forward-delete.js +1 -1
- package/dist/_pkgs/affine-block-note/commands/select-block.js +1 -1
- package/dist/_pkgs/affine-block-note/commands/select-blocks-between.js +1 -1
- package/dist/_pkgs/affine-block-note/move-block.js +1 -1
- package/dist/_pkgs/affine-block-note/note-edgeless-block.d.ts +9 -0
- package/dist/_pkgs/affine-block-note/note-edgeless-block.js +29 -1
- package/dist/_pkgs/affine-block-paragraph/utils/forward-delete.js +2 -2
- package/dist/_pkgs/affine-block-paragraph/utils/merge-with-prev.js +1 -1
- package/dist/_pkgs/affine-block-root/commands/pivot-commands.d.ts +37 -0
- package/dist/_pkgs/affine-block-root/commands/pivot-commands.js +168 -0
- package/dist/_pkgs/affine-block-root/commands/reading-commands.d.ts +23 -0
- package/dist/_pkgs/affine-block-root/commands/reading-commands.js +107 -0
- package/dist/_pkgs/affine-block-root/commands/tag-commands.d.ts +47 -0
- package/dist/_pkgs/affine-block-root/commands/tag-commands.js +159 -0
- package/dist/_pkgs/affine-block-root/configs/toolbar.d.ts +1 -0
- package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/more.js +10 -3
- package/dist/_pkgs/affine-block-root/edgeless/configs/toolbar/render-linked-doc.js +1 -1
- package/dist/_pkgs/affine-block-root/edgeless/edgeless-keyboard.js +27 -2
- package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +11 -2
- package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-service.js +14 -0
- package/dist/_pkgs/affine-block-root/edgeless/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-root/edgeless/index.js +1 -0
- package/dist/_pkgs/affine-block-root/edgeless/reserved-keys.d.ts +21 -0
- package/dist/_pkgs/affine-block-root/edgeless/reserved-keys.js +34 -0
- package/dist/_pkgs/affine-block-root/edgeless/utils/clipboard-utils.js +1 -1
- package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.d.ts +7 -1
- package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.js +11 -2
- package/dist/_pkgs/affine-block-root/index.d.ts +4 -1
- package/dist/_pkgs/affine-block-root/index.js +4 -1
- package/dist/_pkgs/affine-block-root/keyboard/commands.d.ts +2 -0
- package/dist/_pkgs/affine-block-root/keyboard/commands.js +147 -0
- package/dist/_pkgs/affine-block-root/view.js +13 -4
- package/dist/_pkgs/affine-block-surface/adapters/markdown/element-adapter/type.js +1 -1
- package/dist/_pkgs/affine-block-surface/adapters/plain-text/element-adapter/type.js +1 -1
- package/dist/_pkgs/affine-block-surface/commands/reassociate-connectors.js +0 -1
- package/dist/_pkgs/affine-block-surface/effects.js +6 -0
- package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +21 -3
- package/dist/_pkgs/affine-block-surface/element-model/index.js +14 -2
- package/dist/_pkgs/affine-block-surface/extensions/audit.d.ts +107 -0
- package/dist/_pkgs/affine-block-surface/extensions/audit.js +489 -0
- package/dist/_pkgs/affine-block-surface/extensions/crud-extension.d.ts +14 -0
- package/dist/_pkgs/affine-block-surface/extensions/crud-extension.js +37 -5
- package/dist/_pkgs/affine-block-surface/extensions/editor-anchored-panel.d.ts +133 -0
- package/dist/_pkgs/affine-block-surface/extensions/editor-anchored-panel.js +327 -0
- package/dist/_pkgs/affine-block-surface/extensions/element-renderer.js +1 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +1 -1
- package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +17 -0
- package/dist/_pkgs/affine-block-surface/extensions/index.js +17 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-import.d.ts +172 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +393 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +306 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange.js +64 -0
- package/dist/_pkgs/affine-block-surface/extensions/map-quality-widget.d.ts +146 -0
- package/dist/_pkgs/affine-block-surface/extensions/map-quality-widget.js +528 -0
- package/dist/_pkgs/affine-block-surface/extensions/map-quality.d.ts +109 -0
- package/dist/_pkgs/affine-block-surface/extensions/map-quality.js +84 -0
- package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.d.ts +248 -0
- package/dist/_pkgs/affine-block-surface/extensions/morph-toolbar.js +248 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading-toolbar.d.ts +15 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading-toolbar.js +158 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +145 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +588 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +494 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading.js +767 -0
- package/dist/_pkgs/affine-block-surface/extensions/spotlight.d.ts +45 -0
- package/dist/_pkgs/affine-block-surface/extensions/spotlight.js +177 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +107 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +958 -0
- package/dist/_pkgs/affine-block-surface/extensions/tags-toolbar.d.ts +10 -0
- package/dist/_pkgs/affine-block-surface/extensions/tags-toolbar.js +295 -0
- package/dist/_pkgs/affine-block-surface/extensions/validation-toolbar.d.ts +27 -0
- package/dist/_pkgs/affine-block-surface/extensions/validation-toolbar.js +361 -0
- package/dist/_pkgs/affine-block-surface/extensions/validation.d.ts +2129 -0
- package/dist/_pkgs/affine-block-surface/extensions/validation.js +4620 -0
- package/dist/_pkgs/affine-block-surface/extensions/violation-detail-widget.d.ts +330 -0
- package/dist/_pkgs/affine-block-surface/extensions/violation-detail-widget.js +1004 -0
- package/dist/_pkgs/affine-block-surface/extensions/violation-timeline.d.ts +80 -0
- package/dist/_pkgs/affine-block-surface/extensions/violation-timeline.js +123 -0
- package/dist/_pkgs/affine-block-surface/framework-background/def.d.ts +610 -0
- package/dist/_pkgs/affine-block-surface/framework-background/def.js +206 -0
- package/dist/_pkgs/affine-block-surface/framework-background/facts.d.ts +188 -0
- package/dist/_pkgs/affine-block-surface/framework-background/facts.js +284 -0
- package/dist/_pkgs/affine-block-surface/framework-background/index.d.ts +5 -0
- package/dist/_pkgs/affine-block-surface/framework-background/index.js +5 -0
- package/dist/_pkgs/affine-block-surface/framework-background/interaction.d.ts +12 -0
- package/dist/_pkgs/affine-block-surface/framework-background/interaction.js +24 -0
- package/dist/_pkgs/affine-block-surface/framework-background/labels.d.ts +99 -0
- package/dist/_pkgs/affine-block-surface/framework-background/labels.js +193 -0
- package/dist/_pkgs/affine-block-surface/framework-background/renderer.d.ts +8 -0
- package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +399 -0
- package/dist/_pkgs/affine-block-surface/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/index.js +1 -0
- package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.d.ts +69 -3
- package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +333 -44
- package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.js +18 -2
- package/dist/_pkgs/affine-block-surface/renderer/overlay.js +1 -1
- package/dist/_pkgs/affine-block-surface/tool/default-tool.js +8 -0
- package/dist/_pkgs/affine-block-surface/utils/font.js +9 -3
- package/dist/_pkgs/affine-block-surface/view.d.ts +17 -0
- package/dist/_pkgs/affine-block-surface/view.js +57 -2
- package/dist/_pkgs/affine-block-surface-ref/portal/note.js +2 -2
- package/dist/_pkgs/affine-block-table/commands.js +1 -1
- package/dist/_pkgs/affine-block-table/selection-controller.d.ts +6 -0
- package/dist/_pkgs/affine-block-table/selection-controller.js +24 -1
- package/dist/_pkgs/affine-block-table/table-block.js +8 -2
- package/dist/_pkgs/affine-block-table/table-cell.js +5 -6
- package/dist/_pkgs/affine-block-table/table-keymap.d.ts +18 -0
- package/dist/_pkgs/affine-block-table/table-keymap.js +41 -0
- package/dist/_pkgs/affine-block-table/utils.d.ts +7 -0
- package/dist/_pkgs/affine-block-table/utils.js +12 -0
- package/dist/_pkgs/affine-block-table/view.js +2 -0
- package/dist/_pkgs/affine-components/caption/captioned-block-component.js +2 -1
- package/dist/_pkgs/affine-components/context-menu/button.d.ts +7 -0
- package/dist/_pkgs/affine-components/context-menu/button.js +7 -2
- package/dist/_pkgs/affine-components/context-menu/input.d.ts +4 -0
- package/dist/_pkgs/affine-components/context-menu/input.js +12 -0
- package/dist/_pkgs/affine-components/context-menu/menu-all.d.ts +2 -0
- package/dist/_pkgs/affine-components/context-menu/menu-renderer.js +8 -1
- package/dist/_pkgs/affine-components/context-menu/sub-menu.js +3 -0
- package/dist/_pkgs/affine-components/edgeless-shape-color-picker/color-picker.js +1 -1
- package/dist/_pkgs/affine-components/embed-card-modal/embed-card-edit-modal.js +1 -1
- package/dist/_pkgs/affine-components/filterable-list/styles.js +1 -1
- package/dist/_pkgs/affine-components/highlight-dropdown-menu/highlight-duotone-icon.js +8 -8
- package/dist/_pkgs/affine-components/highlight-dropdown-menu/text-duotone-icon.js +11 -11
- package/dist/_pkgs/affine-components/icon-picker/affine-icon-picker-panel.d.ts +28 -0
- package/dist/_pkgs/affine-components/icon-picker/affine-icon-picker-panel.js +231 -0
- package/dist/_pkgs/affine-components/icon-picker/emoji-data.d.ts +40 -0
- package/dist/_pkgs/affine-components/icon-picker/emoji-data.js +99 -0
- package/dist/_pkgs/affine-components/icon-picker/emoji-picker-panel.d.ts +32 -0
- package/dist/_pkgs/affine-components/icon-picker/emoji-picker-panel.js +276 -0
- package/dist/_pkgs/affine-components/icon-picker/icon-data.d.ts +34 -0
- package/dist/_pkgs/affine-components/icon-picker/icon-data.js +83 -0
- package/dist/_pkgs/affine-components/icon-picker/icon-picker.d.ts +39 -0
- package/dist/_pkgs/affine-components/icon-picker/icon-picker.js +233 -0
- package/dist/_pkgs/affine-components/icon-picker/index.d.ts +8 -0
- package/dist/_pkgs/affine-components/icon-picker/index.js +15 -0
- package/dist/_pkgs/affine-components/icon-picker/recent-store.d.ts +8 -0
- package/dist/_pkgs/affine-components/icon-picker/recent-store.js +41 -0
- package/dist/_pkgs/affine-components/icon-picker/styles.d.ts +5 -0
- package/dist/_pkgs/affine-components/icon-picker/styles.js +166 -0
- package/dist/_pkgs/affine-components/icon-picker/types.d.ts +22 -0
- package/dist/_pkgs/affine-components/icon-picker/types.js +10 -0
- package/dist/_pkgs/affine-components/icons/text.js +426 -426
- package/dist/_pkgs/affine-components/open-doc-dropdown-menu/dropdown-menu.d.ts +1 -0
- package/dist/_pkgs/affine-components/peek/peekable.js +1 -1
- package/dist/_pkgs/affine-components/portal/portal.d.ts +1 -1
- package/dist/_pkgs/affine-components/toolbar/index.d.ts +1 -0
- package/dist/_pkgs/affine-components/toolbar/index.js +1 -0
- package/dist/_pkgs/affine-components/toolbar/menu-button.js +2 -1
- package/dist/_pkgs/affine-components/toolbar/picker-menu.d.ts +55 -0
- package/dist/_pkgs/affine-components/toolbar/picker-menu.js +47 -0
- package/dist/_pkgs/affine-components/toolbar/toolbar.js +11 -10
- package/dist/_pkgs/affine-foundation/view.js +11 -2
- package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +2 -2
- package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.js +2 -2
- package/dist/_pkgs/affine-fragment-frame-panel/header/frames-setting-menu.js +1 -1
- package/dist/_pkgs/affine-fragment-outline/mobile-outline-panel.js +1 -1
- package/dist/_pkgs/affine-gfx-brush/index.d.ts +1 -0
- package/dist/_pkgs/affine-gfx-brush/index.js +1 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/brush.d.ts +1 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/brush.js +11 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/highlighter.d.ts +1 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/highlighter.js +11 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/index.d.ts +2 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/index.js +2 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/shared.d.ts +14 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/dom/shared.js +54 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/index.d.ts +1 -0
- package/dist/_pkgs/affine-gfx-brush/renderer/index.js +4 -0
- package/dist/_pkgs/affine-gfx-brush/toolbar/components/pen/pen-tool-button.js +1 -1
- package/dist/_pkgs/affine-gfx-brush/view.d.ts +14 -0
- package/dist/_pkgs/affine-gfx-brush/view.js +29 -3
- package/dist/_pkgs/affine-gfx-connector/connector-manager.js +39 -16
- package/dist/_pkgs/affine-gfx-connector/connector-tool.d.ts +26 -1
- package/dist/_pkgs/affine-gfx-connector/connector-tool.js +12 -3
- package/dist/_pkgs/affine-gfx-connector/connector-watcher.js +1 -4
- package/dist/_pkgs/affine-gfx-connector/direction/direction-reveal.d.ts +123 -0
- package/dist/_pkgs/affine-gfx-connector/direction/direction-reveal.js +282 -0
- package/dist/_pkgs/affine-gfx-connector/direction/direction-widget.d.ts +65 -0
- package/dist/_pkgs/affine-gfx-connector/direction/direction-widget.js +395 -0
- package/dist/_pkgs/affine-gfx-connector/direction/index.d.ts +4 -0
- package/dist/_pkgs/affine-gfx-connector/direction/index.js +4 -0
- package/dist/_pkgs/affine-gfx-connector/direction/invert-direction.d.ts +72 -0
- package/dist/_pkgs/affine-gfx-connector/direction/invert-direction.js +185 -0
- package/dist/_pkgs/affine-gfx-connector/direction/typed-edge.d.ts +69 -0
- package/dist/_pkgs/affine-gfx-connector/direction/typed-edge.js +66 -0
- package/dist/_pkgs/affine-gfx-connector/effects.d.ts +2 -0
- package/dist/_pkgs/affine-gfx-connector/effects.js +2 -0
- package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +78 -41
- package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +1 -1
- package/dist/_pkgs/affine-gfx-connector/element-renderer/utils.js +1 -1
- package/dist/_pkgs/affine-gfx-connector/index.d.ts +1 -0
- package/dist/_pkgs/affine-gfx-connector/index.js +1 -0
- package/dist/_pkgs/affine-gfx-connector/toolbar/config.d.ts +50 -0
- package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +68 -2
- package/dist/_pkgs/affine-gfx-connector/view.js +16 -0
- package/dist/_pkgs/affine-gfx-group/command/group-api.js +150 -62
- package/dist/_pkgs/affine-gfx-group/text/edgeless-group-title-editor.js +4 -1
- package/dist/_pkgs/affine-gfx-mindmap/adapter/markdown/index.js +1 -1
- package/dist/_pkgs/affine-gfx-mindmap/adapter/utils.js +1 -1
- package/dist/_pkgs/affine-gfx-mindmap/templates/index.js +583 -4
- package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-menu.js +23 -23
- package/dist/_pkgs/affine-gfx-mindmap/toolbar/mindmap-tool-button.js +5 -1
- package/dist/_pkgs/affine-gfx-mindmap/view/utils.js +1 -1
- package/dist/_pkgs/affine-gfx-note/overlay/overlay.js +1 -1
- package/dist/_pkgs/affine-gfx-note/toolbar/note-senior-button.js +1 -1
- package/dist/_pkgs/affine-gfx-pointer/tools/pan-tool.d.ts +16 -0
- package/dist/_pkgs/affine-gfx-pointer/tools/pan-tool.js +102 -32
- package/dist/_pkgs/affine-gfx-shape/commands.d.ts +2 -0
- package/dist/_pkgs/affine-gfx-shape/commands.js +33 -0
- package/dist/_pkgs/affine-gfx-shape/consts.js +1 -1
- package/dist/_pkgs/affine-gfx-shape/draggable/shape-draggable.js +1 -1
- package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/polygon.js +17 -9
- package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/utils.js +8 -3
- package/dist/_pkgs/affine-gfx-shape/element-renderer/shape-dom/index.js +48 -19
- package/dist/_pkgs/affine-gfx-shape/element-view.js +19 -12
- package/dist/_pkgs/affine-gfx-shape/index.d.ts +1 -1
- package/dist/_pkgs/affine-gfx-shape/index.js +1 -1
- package/dist/_pkgs/affine-gfx-shape/overlay/polygon-drawing-overlay.js +1 -1
- package/dist/_pkgs/affine-gfx-shape/overlay/polygon-vertex-editing-overlay.js +12 -7
- package/dist/_pkgs/affine-gfx-shape/overlay/shape-overlay.js +1 -1
- package/dist/_pkgs/affine-gfx-shape/polygon-tool.js +4 -2
- package/dist/_pkgs/affine-gfx-shape/shape-tool.js +1 -1
- package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.d.ts +26 -0
- package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.js +124 -15
- package/dist/_pkgs/affine-gfx-shape/view.js +3 -3
- package/dist/_pkgs/affine-gfx-template/builtin/other.js +66 -17
- package/dist/_pkgs/affine-gfx-template/toolbar/overlay-scrollbar.js +1 -1
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +1 -1
- package/dist/_pkgs/affine-gfx-template/toolbar/template-tool-button.d.ts +2 -0
- package/dist/_pkgs/affine-gfx-template/toolbar/template-tool-button.js +18 -1
- package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +9 -5
- package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +1 -1
- package/dist/_pkgs/affine-inline-latex/command.js +46 -26
- package/dist/_pkgs/affine-inline-latex/latex-node/latex-node.d.ts +10 -0
- package/dist/_pkgs/affine-inline-latex/latex-node/latex-node.js +23 -0
- package/dist/_pkgs/affine-inline-link/command.js +1 -1
- package/dist/_pkgs/affine-inline-link/link-node/affine-link.js +4 -1
- package/dist/_pkgs/affine-inline-preset/adapters/html/html-inline.d.ts +3 -0
- package/dist/_pkgs/affine-inline-preset/adapters/html/html-inline.js +29 -1
- package/dist/_pkgs/affine-inline-preset/command/format-block.js +1 -1
- package/dist/_pkgs/affine-inline-preset/command/format-native.js +2 -2
- package/dist/_pkgs/affine-inline-preset/command/format-text.js +1 -1
- package/dist/_pkgs/affine-inline-preset/inline-spec.js +1 -1
- package/dist/_pkgs/affine-inline-reference/reference-node/reference-node.js +1 -1
- package/dist/_pkgs/affine-model/blocks/code/code-model.d.ts +1 -0
- package/dist/_pkgs/affine-model/blocks/code/code-model.js +1 -0
- package/dist/_pkgs/affine-model/elements/bpmn/node.d.ts +40 -7
- package/dist/_pkgs/affine-model/elements/bpmn/node.js +4 -2
- package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +74 -17
- package/dist/_pkgs/affine-model/elements/bpmn/pool.js +55 -26
- package/dist/_pkgs/affine-model/elements/c4/board.d.ts +88 -0
- package/dist/_pkgs/affine-model/elements/c4/board.js +128 -0
- package/dist/_pkgs/affine-model/elements/c4/boundary.d.ts +63 -0
- package/dist/_pkgs/affine-model/elements/c4/boundary.js +134 -0
- package/dist/_pkgs/affine-model/elements/c4/index.d.ts +3 -0
- package/dist/_pkgs/affine-model/elements/c4/index.js +3 -0
- package/dist/_pkgs/affine-model/elements/c4/node.d.ts +97 -0
- package/dist/_pkgs/affine-model/elements/c4/node.js +130 -0
- package/dist/_pkgs/affine-model/elements/connector/connector.js +25 -1
- package/dist/_pkgs/affine-model/elements/context-map/context-map.d.ts +27 -0
- package/dist/_pkgs/affine-model/elements/context-map/context-map.js +94 -0
- package/dist/_pkgs/affine-model/elements/context-map/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/context-map/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/core-domain/core-domain.d.ts +34 -17
- package/dist/_pkgs/affine-model/elements/core-domain/core-domain.js +28 -26
- package/dist/_pkgs/affine-model/elements/edgy/board.d.ts +32 -0
- package/dist/_pkgs/affine-model/elements/edgy/board.js +112 -0
- package/dist/_pkgs/affine-model/elements/edgy/facets.d.ts +12 -0
- package/dist/_pkgs/affine-model/elements/edgy/facets.js +25 -1
- package/dist/_pkgs/affine-model/elements/edgy/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/edgy/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/event-storming/event-storming.d.ts +36 -0
- package/dist/_pkgs/affine-model/elements/event-storming/event-storming.js +103 -0
- package/dist/_pkgs/affine-model/elements/event-storming/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/event-storming/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/framework-background/background.d.ts +42 -0
- package/dist/_pkgs/affine-model/elements/framework-background/background.js +42 -0
- package/dist/_pkgs/affine-model/elements/framework-background/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/framework-background/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/index.d.ts +14 -1
- package/dist/_pkgs/affine-model/elements/index.js +4 -0
- package/dist/_pkgs/affine-model/elements/mindmap/mindmap.js +8 -3
- package/dist/_pkgs/affine-model/elements/mindmap/style.d.ts +10 -0
- package/dist/_pkgs/affine-model/elements/mindmap/style.js +8 -0
- package/dist/_pkgs/affine-model/elements/shape/api/polygon.js +2 -8
- package/dist/_pkgs/affine-model/elements/wardley/wardley.d.ts +21 -29
- package/dist/_pkgs/affine-model/elements/wardley/wardley.js +41 -48
- package/dist/_pkgs/affine-shared/adapters/html/block-adapter.js +1 -1
- package/dist/_pkgs/affine-shared/adapters/markdown/block-adapter.js +1 -1
- package/dist/_pkgs/affine-shared/adapters/markdown/delta-converter.d.ts +6 -1
- package/dist/_pkgs/affine-shared/adapters/markdown/delta-converter.js +161 -3
- package/dist/_pkgs/affine-shared/adapters/markdown/markdown.js +5 -1
- package/dist/_pkgs/affine-shared/adapters/notion-html/block-adapter.js +1 -1
- package/dist/_pkgs/affine-shared/adapters/notion-html/delta-converter.js +1 -1
- package/dist/_pkgs/affine-shared/adapters/plain-text/block-adapter.js +1 -1
- package/dist/_pkgs/affine-shared/adapters/plain-text/delta-converter.js +1 -1
- package/dist/_pkgs/affine-shared/adapters/types/delta-converter.d.ts +1 -0
- package/dist/_pkgs/affine-shared/adapters/utils/color.d.ts +24 -0
- package/dist/_pkgs/affine-shared/adapters/utils/color.js +283 -0
- package/dist/_pkgs/affine-shared/adapters/utils/index.d.ts +1 -0
- package/dist/_pkgs/affine-shared/adapters/utils/index.js +1 -0
- package/dist/_pkgs/affine-shared/commands/block-crud/get-selected-blocks.js +10 -2
- package/dist/_pkgs/affine-shared/commands/model-crud/draft-selected-models.js +1 -1
- package/dist/_pkgs/affine-shared/commands/selection/focus-block-end.js +1 -1
- package/dist/_pkgs/affine-shared/commands/selection/focus-block-start.js +1 -1
- package/dist/_pkgs/affine-shared/consts/index.d.ts +10 -0
- package/dist/_pkgs/affine-shared/consts/index.js +10 -0
- package/dist/_pkgs/affine-shared/services/artefact-catalogue-service.d.ts +55 -0
- package/dist/_pkgs/affine-shared/services/artefact-catalogue-service.js +35 -0
- package/dist/_pkgs/affine-shared/services/audit-service.d.ts +311 -0
- package/dist/_pkgs/affine-shared/services/audit-service.js +228 -0
- package/dist/_pkgs/affine-shared/services/command-usage-service.d.ts +31 -0
- package/dist/_pkgs/affine-shared/services/command-usage-service.js +109 -0
- package/dist/_pkgs/affine-shared/services/comment-service/block-comment-manager.js +1 -1
- package/dist/_pkgs/affine-shared/services/doc-display-meta-service.js +1 -1
- package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +7 -0
- package/dist/_pkgs/affine-shared/services/edit-props-store.js +11 -0
- package/dist/_pkgs/affine-shared/services/embed-iframe/embed-iframe-config.js +1 -1
- package/dist/_pkgs/affine-shared/services/font-loader/font-loader-service.d.ts +26 -1
- package/dist/_pkgs/affine-shared/services/font-loader/font-loader-service.js +124 -7
- package/dist/_pkgs/affine-shared/services/index.d.ts +7 -0
- package/dist/_pkgs/affine-shared/services/index.js +7 -0
- package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.d.ts +129 -0
- package/dist/_pkgs/affine-shared/services/pivot-materiality-publisher.js +312 -0
- package/dist/_pkgs/affine-shared/services/pivot-properties-service.d.ts +217 -0
- package/dist/_pkgs/affine-shared/services/pivot-properties-service.js +114 -0
- package/dist/_pkgs/affine-shared/services/telemetry-service/code-block.d.ts +1 -1
- package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +255 -1
- package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
- package/dist/_pkgs/affine-shared/services/telemetry-service/types.d.ts +6 -1
- package/dist/_pkgs/affine-shared/services/toolbar-service/action.d.ts +10 -0
- package/dist/_pkgs/affine-shared/services/toolbar-service/index.d.ts +1 -0
- package/dist/_pkgs/affine-shared/services/toolbar-service/index.js +1 -0
- package/dist/_pkgs/affine-shared/services/toolbar-service/layout.d.ts +134 -0
- package/dist/_pkgs/affine-shared/services/toolbar-service/layout.js +146 -0
- package/dist/_pkgs/affine-shared/services/toolbar-service/registry.d.ts +44 -0
- package/dist/_pkgs/affine-shared/services/toolbar-service/registry.js +161 -3
- package/dist/_pkgs/affine-shared/services/translation-service/index.d.ts +68 -0
- package/dist/_pkgs/affine-shared/services/translation-service/index.js +39 -0
- package/dist/_pkgs/affine-shared/services/universe-tag-defs-service.d.ts +155 -0
- package/dist/_pkgs/affine-shared/services/universe-tag-defs-service.js +256 -0
- package/dist/_pkgs/affine-shared/test-utils/affine-template.js +1 -1
- package/dist/_pkgs/affine-shared/utils/dom/point-to-range.d.ts +4 -0
- package/dist/_pkgs/affine-shared/utils/dom/point-to-range.js +58 -2
- package/dist/_pkgs/affine-shared/utils/dom/viewport.d.ts +60 -0
- package/dist/_pkgs/affine-shared/utils/dom/viewport.js +58 -0
- package/dist/_pkgs/affine-shared/utils/edgeless.js +1 -1
- package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +34 -0
- package/dist/_pkgs/affine-shared/utils/file/filesys.js +48 -7
- package/dist/_pkgs/affine-shared/utils/print-to-pdf.d.ts +21 -0
- package/dist/_pkgs/affine-shared/utils/print-to-pdf.js +166 -32
- package/dist/_pkgs/affine-shared/utils/zod-schema.d.ts +7 -0
- package/dist/_pkgs/affine-shared/utils/zod-schema.js +25 -1
- package/dist/_pkgs/affine-widget-drag-handle/utils.js +1 -1
- package/dist/_pkgs/affine-widget-drag-handle/watchers/edgeless-watcher.d.ts +19 -10
- package/dist/_pkgs/affine-widget-drag-handle/watchers/edgeless-watcher.js +122 -23
- package/dist/_pkgs/affine-widget-drag-handle/watchers/pointer-event-watcher.d.ts +2 -0
- package/dist/_pkgs/affine-widget-drag-handle/watchers/pointer-event-watcher.js +25 -4
- package/dist/_pkgs/affine-widget-edgeless-auto-connect/index.js +1 -1
- package/dist/_pkgs/affine-widget-edgeless-dragging-area/edgeless-dragging-area-rect.js +1 -1
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/auto-complete-panel.js +10 -5
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/edgeless-auto-complete.d.ts +15 -1
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/edgeless-auto-complete.js +37 -32
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/edgeless-element-link.js +5 -4
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/edgeless-selected-rect.js +19 -9
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/utils.d.ts +16 -2
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/utils.js +19 -2
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-default.d.ts +14 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-default.js +40 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.d.ts +158 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +572 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/catalogue-groups.d.ts +46 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/catalogue-groups.js +66 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/chord-format.d.ts +13 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/chord-format.js +50 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/edgeless-toolbar.d.ts +6 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/edgeless-toolbar.js +15 -5
- package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.d.ts +2 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.js +2 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/extension/index.d.ts +7 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +5 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +5 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.d.ts +57 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/menu/command-menu.js +140 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +9 -0
- package/dist/_pkgs/affine-widget-frame-title/edgeless-frame-title-editor.js +4 -1
- package/dist/_pkgs/affine-widget-keyboard-toolbar/icons.js +98 -98
- package/dist/_pkgs/affine-widget-keyboard-toolbar/keyboard-tool-panel.js +1 -1
- package/dist/_pkgs/affine-widget-linked-doc/import-doc/import-doc.js +1 -1
- package/dist/_pkgs/affine-widget-linked-doc/linked-doc-popover.js +2 -15
- package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.d.ts +10 -1
- package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.js +133 -6
- package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.d.ts +10 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.js +120 -3
- package/dist/_pkgs/affine-widget-linked-doc/utils.d.ts +12 -0
- package/dist/_pkgs/affine-widget-linked-doc/utils.js +33 -0
- package/dist/_pkgs/affine-widget-page-dragging-area/index.js +1 -1
- package/dist/_pkgs/affine-widget-remote-selection/doc/doc-remote-selection.js +1 -1
- package/dist/_pkgs/affine-widget-remote-selection/edgeless/index.js +6 -4
- package/dist/_pkgs/affine-widget-slash-menu/slash-menu-popover.js +8 -4
- package/dist/_pkgs/affine-widget-slash-menu/utils.d.ts +9 -0
- package/dist/_pkgs/affine-widget-slash-menu/utils.js +24 -0
- package/dist/_pkgs/affine-widget-toolbar/toolbar.d.ts +6 -0
- package/dist/_pkgs/affine-widget-toolbar/toolbar.js +40 -8
- package/dist/_pkgs/affine-widget-toolbar/utils.d.ts +146 -3
- package/dist/_pkgs/affine-widget-toolbar/utils.js +744 -58
- package/dist/_pkgs/data-view/core/common/property-menu.js +3 -16
- package/dist/_pkgs/data-view/core/component/tags/multi-tag-select.d.ts +4 -0
- package/dist/_pkgs/data-view/core/component/tags/multi-tag-select.js +28 -1
- package/dist/_pkgs/data-view/core/data-view.d.ts +3 -1
- package/dist/_pkgs/data-view/core/data-view.js +25 -3
- package/dist/_pkgs/data-view/core/detail/field.js +2 -2
- package/dist/_pkgs/data-view/core/detail/selection.d.ts +4 -2
- package/dist/_pkgs/data-view/core/detail/selection.js +23 -7
- package/dist/_pkgs/data-view/core/effect.js +2 -0
- package/dist/_pkgs/data-view/core/filter/eval.js +36 -23
- package/dist/_pkgs/data-view/core/filter/filter-fn/matcher.d.ts +7 -0
- package/dist/_pkgs/data-view/core/filter/filter-fn/matcher.js +12 -0
- package/dist/_pkgs/data-view/core/group-by/compare-date-keys.d.ts +11 -0
- package/dist/_pkgs/data-view/core/group-by/compare-date-keys.js +55 -0
- package/dist/_pkgs/data-view/core/group-by/define.d.ts +6 -0
- package/dist/_pkgs/data-view/core/group-by/define.js +114 -0
- package/dist/_pkgs/data-view/core/group-by/matcher.d.ts +7 -0
- package/dist/_pkgs/data-view/core/group-by/matcher.js +13 -0
- package/dist/_pkgs/data-view/core/group-by/renderer/boolean-group.js +11 -11
- package/dist/_pkgs/data-view/core/group-by/renderer/date-group.d.ts +9 -0
- package/dist/_pkgs/data-view/core/group-by/renderer/date-group.js +97 -0
- package/dist/_pkgs/data-view/core/group-by/setting.js +86 -7
- package/dist/_pkgs/data-view/core/group-by/trait.d.ts +34 -0
- package/dist/_pkgs/data-view/core/group-by/trait.js +106 -10
- package/dist/_pkgs/data-view/core/utils/menu-title.js +17 -17
- package/dist/_pkgs/data-view/property-presets/multi-select/cell-renderer.js +3 -1
- package/dist/_pkgs/data-view/property-presets/number/define.js +2 -1
- package/dist/_pkgs/data-view/property-presets/select/cell-renderer.js +3 -1
- package/dist/_pkgs/data-view/view-presets/calendar/calendar-view-manager.d.ts +70 -0
- package/dist/_pkgs/data-view/view-presets/calendar/calendar-view-manager.js +449 -0
- package/dist/_pkgs/data-view/view-presets/calendar/define.d.ts +10 -0
- package/dist/_pkgs/data-view/view-presets/calendar/define.js +27 -0
- package/dist/_pkgs/data-view/view-presets/calendar/effect.d.ts +1 -0
- package/dist/_pkgs/data-view/view-presets/calendar/effect.js +4 -0
- package/dist/_pkgs/data-view/view-presets/calendar/index.d.ts +6 -0
- package/dist/_pkgs/data-view/view-presets/calendar/index.js +6 -0
- package/dist/_pkgs/data-view/view-presets/calendar/layout.d.ts +37 -0
- package/dist/_pkgs/data-view/view-presets/calendar/layout.js +138 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/actions.d.ts +7 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/actions.js +64 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/dnd.d.ts +32 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/dnd.js +159 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/effect.d.ts +1 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/effect.js +7 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/hit-test.d.ts +1 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/hit-test.js +28 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/styles.d.ts +1 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/styles.js +707 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/view.d.ts +89 -0
- package/dist/_pkgs/data-view/view-presets/calendar/pc/view.js +849 -0
- package/dist/_pkgs/data-view/view-presets/calendar/renderer.d.ts +2 -0
- package/dist/_pkgs/data-view/view-presets/calendar/renderer.js +8 -0
- package/dist/_pkgs/data-view/view-presets/calendar/source.d.ts +8 -0
- package/dist/_pkgs/data-view/view-presets/calendar/source.js +3 -0
- package/dist/_pkgs/data-view/view-presets/calendar/types.d.ts +79 -0
- package/dist/_pkgs/data-view/view-presets/calendar/types.js +1 -0
- package/dist/_pkgs/data-view/view-presets/convert.js +28 -0
- package/dist/_pkgs/data-view/view-presets/effect.js +2 -0
- package/dist/_pkgs/data-view/view-presets/index.d.ts +2 -0
- package/dist/_pkgs/data-view/view-presets/index.js +3 -0
- package/dist/_pkgs/data-view/view-presets/kanban/kanban-view-manager.js +3 -1
- package/dist/_pkgs/data-view/view-presets/kanban/mobile/cell.js +2 -2
- package/dist/_pkgs/data-view/view-presets/table/collapsed-state.d.ts +18 -0
- package/dist/_pkgs/data-view/view-presets/table/collapsed-state.js +36 -0
- package/dist/_pkgs/data-view/view-presets/table/mobile/cell.js +2 -2
- package/dist/_pkgs/data-view/view-presets/table/mobile/group.d.ts +11 -0
- package/dist/_pkgs/data-view/view-presets/table/mobile/group.js +89 -4
- package/dist/_pkgs/data-view/view-presets/table/pc/cell.d.ts +3 -0
- package/dist/_pkgs/data-view/view-presets/table/pc/cell.js +11 -2
- package/dist/_pkgs/data-view/view-presets/table/pc/controller/hotkeys.d.ts +1 -0
- package/dist/_pkgs/data-view/view-presets/table/pc/controller/hotkeys.js +39 -33
- package/dist/_pkgs/data-view/view-presets/table/pc/group.d.ts +10 -0
- package/dist/_pkgs/data-view/view-presets/table/pc/group.js +86 -5
- package/dist/_pkgs/data-view/view-presets/table/pc-virtual/controller/hotkeys.d.ts +1 -0
- package/dist/_pkgs/data-view/view-presets/table/pc-virtual/controller/hotkeys.js +39 -33
- package/dist/_pkgs/data-view/view-presets/table/pc-virtual/group/top/group-title.js +18 -18
- package/dist/_pkgs/data-view/view-presets/table/pc-virtual/row/cell.d.ts +3 -0
- package/dist/_pkgs/data-view/view-presets/table/pc-virtual/row/cell.js +8 -0
- package/dist/_pkgs/data-view/view-presets/table/table-view-manager.js +3 -1
- package/dist/_pkgs/data-view/view-presets/table/utils.d.ts +3 -0
- package/dist/_pkgs/data-view/view-presets/table/utils.js +16 -1
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-options.js +3 -1
- package/dist/_pkgs/global/gfx/curve.js +4 -3
- package/dist/_pkgs/std/clipboard/clipboard.js +13 -3
- package/dist/_pkgs/std/clipboard/utils.d.ts +5 -0
- package/dist/_pkgs/std/clipboard/utils.js +10 -0
- package/dist/_pkgs/std/event/dispatcher.js +27 -1
- package/dist/_pkgs/std/event/keymap.js +16 -6
- package/dist/_pkgs/std/extension/command-registry.d.ts +475 -0
- package/dist/_pkgs/std/extension/command-registry.js +431 -0
- package/dist/_pkgs/std/extension/dnd/index.d.ts +1 -1
- package/dist/_pkgs/std/extension/index.d.ts +2 -0
- package/dist/_pkgs/std/extension/index.js +2 -0
- package/dist/_pkgs/std/extension/shortcut.js +2 -1
- package/dist/_pkgs/std/extension/translation-manifest.d.ts +49 -0
- package/dist/_pkgs/std/extension/translation-manifest.js +71 -0
- package/dist/_pkgs/std/gfx/grid.js +1 -1
- package/dist/_pkgs/std/gfx/index.d.ts +7 -3
- package/dist/_pkgs/std/gfx/index.js +6 -2
- package/dist/_pkgs/std/gfx/interactivity/gfx-view-event-handler.js +6 -1
- package/dist/_pkgs/std/gfx/interactivity/manager.d.ts +8 -0
- package/dist/_pkgs/std/gfx/interactivity/manager.js +18 -0
- package/dist/_pkgs/std/gfx/layer.d.ts +1 -1
- package/dist/_pkgs/std/gfx/layer.js +1 -2
- package/dist/_pkgs/std/gfx/model/surface/decorators/field.js +9 -0
- package/dist/_pkgs/std/gfx/model/surface/decorators/index.d.ts +2 -2
- package/dist/_pkgs/std/gfx/model/surface/decorators/index.js +2 -2
- package/dist/_pkgs/std/gfx/model/surface/decorators/local.d.ts +14 -0
- package/dist/_pkgs/std/gfx/model/surface/decorators/local.js +22 -0
- package/dist/_pkgs/std/gfx/model/surface/decorators/observer.d.ts +2 -0
- package/dist/_pkgs/std/gfx/model/surface/decorators/observer.js +40 -1
- package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +442 -0
- package/dist/_pkgs/std/gfx/model/surface/element-model.js +510 -25
- package/dist/_pkgs/std/gfx/model/surface/pivot.d.ts +48 -0
- package/dist/_pkgs/std/gfx/model/surface/pivot.js +34 -0
- package/dist/_pkgs/std/gfx/model/surface/role.d.ts +153 -0
- package/dist/_pkgs/std/gfx/model/surface/role.js +117 -0
- package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +70 -0
- package/dist/_pkgs/std/gfx/model/surface/surface-model.js +305 -17
- package/dist/_pkgs/std/gfx/model/surface/tags.d.ts +77 -0
- package/dist/_pkgs/std/gfx/model/surface/tags.js +246 -0
- package/dist/_pkgs/std/gfx/perf.d.ts +10 -0
- package/dist/_pkgs/std/gfx/perf.js +30 -0
- package/dist/_pkgs/std/gfx/selection.js +1 -1
- package/dist/_pkgs/std/gfx/tool/tool-controller.d.ts +13 -0
- package/dist/_pkgs/std/gfx/tool/tool-controller.js +26 -0
- package/dist/_pkgs/std/gfx/viewport.d.ts +12 -0
- package/dist/_pkgs/std/gfx/viewport.js +20 -2
- package/dist/_pkgs/std/inline/extensions/inline-manager.js +1 -1
- package/dist/_pkgs/std/inline/extensions/markdown-matcher.js +1 -1
- package/dist/_pkgs/std/inline/services/event.d.ts +2 -0
- package/dist/_pkgs/std/inline/services/event.js +96 -21
- package/dist/_pkgs/std/utils/layer.js +2 -6
- package/dist/_pkgs/std/utils/tree.d.ts +14 -0
- package/dist/_pkgs/std/utils/tree.js +59 -8
- package/dist/_pkgs/std/view/element/gfx-block-component.js +23 -13
- package/dist/_pkgs/store/extension/workspace/workspace-meta.d.ts +10 -0
- package/dist/_pkgs/store/model/block/flat-sync-controller.js +2 -12
- package/dist/_pkgs/store/model/store/crud.js +10 -4
- package/dist/_pkgs/store/reactive/flat-native-y/index.d.ts +1 -1
- package/dist/_pkgs/store/reactive/flat-native-y/index.js +24 -2
- package/dist/commands.d.ts +58 -0
- package/dist/commands.js +66 -0
- package/dist/extensions/command-telemetry.d.ts +21 -0
- package/dist/extensions/command-telemetry.js +89 -0
- package/dist/extensions/command-usage.d.ts +23 -0
- package/dist/extensions/command-usage.js +37 -0
- package/dist/extensions/store.d.ts +9 -4
- package/dist/extensions/store.js +27 -24
- package/dist/extensions/view.d.ts +9 -4
- package/dist/extensions/view.js +35 -8
- package/dist/flags.d.ts +98 -21
- package/dist/flags.js +103 -22
- package/dist/frameworks.d.ts +45 -0
- package/dist/frameworks.js +186 -0
- package/dist/schemas.d.ts +8 -5
- package/dist/schemas.js +28 -32
- package/dist/shortcuts.d.ts +16 -16
- package/dist/shortcuts.js +8 -36
- package/dist/translations.d.ts +56 -0
- package/dist/translations.js +200 -0
- package/package.json +16 -4
- package/dist/_pkgs/affine-block-root/keyboard/shortcuts.d.ts +0 -8
- package/dist/_pkgs/affine-block-root/keyboard/shortcuts.js +0 -48
- package/dist/_pkgs/affine-gfx-shape/shortcuts.d.ts +0 -6
- package/dist/_pkgs/affine-gfx-shape/shortcuts.js +0 -28
- package/dist/_pkgs/data-view/core/utils/cache.d.ts +0 -5
- package/dist/_pkgs/data-view/core/utils/cache.js +0 -28
|
@@ -0,0 +1,958 @@
|
|
|
1
|
+
import { ShapeStyle, ShapeType, StrokeStyle, TextAlign, } from '../../affine-model/index.js';
|
|
2
|
+
import DOMPurify from 'dompurify';
|
|
3
|
+
/**
|
|
4
|
+
* **SVG → a canvas sketch.** The platform's VISUAL-tier importer, shared by
|
|
5
|
+
* every framework that declares it (`docs/adr/0012`, P2).
|
|
6
|
+
*
|
|
7
|
+
* ## The heuristics statement, and its known failure modes
|
|
8
|
+
*
|
|
9
|
+
* _This paragraph is ADR 0012's open question 2 — "each visual capability owes
|
|
10
|
+
* a one-paragraph statement of its heuristics and its known failure modes" —
|
|
11
|
+
* answered ONCE, here, because every framework that declares `…:svg:import`
|
|
12
|
+
* wraps this one function and therefore owes the same statement. It is
|
|
13
|
+
* referenced by `bpmn:svg:import` and by `wardley:svg:import`; a framework that
|
|
14
|
+
* ever wants a narrower or wider guess writes its own parser and its own
|
|
15
|
+
* paragraph beside it._
|
|
16
|
+
*
|
|
17
|
+
* **What it guesses.** An SVG carries a rendering, not a model, so this reader
|
|
18
|
+
* recognises GEOMETRY and nothing else: `<rect>` becomes a rectangle,
|
|
19
|
+
* `<circle>` and `<ellipse>` an ellipse, `<polygon>` a polygon, `<line>`,
|
|
20
|
+
* `<polyline>` and `<path>` a brush stroke sampled at its vertices, and
|
|
21
|
+
* `<text>` an editable free-text element. Fill, stroke, stroke width, font size
|
|
22
|
+
* and text anchor are carried across where the shape model has a direct
|
|
23
|
+
* equivalent, with CSS inheritance down `<g>` honoured and colours passed
|
|
24
|
+
* through verbatim. Coordinates are user units placed by the outermost
|
|
25
|
+
* viewport: the `viewBox` origin is subtracted and the `viewBox`-to-`width`
|
|
26
|
+
* scale is applied uniformly (`min(width / viewBox width, height / viewBox
|
|
27
|
+
* height)`, which is what the default `preserveAspectRatio` means), then every
|
|
28
|
+
* `translate(…)` on the way down. Everything it emits is an ADR 0007 **level 1**
|
|
29
|
+
* element — a plain shape on the free surface, which the author then PROMOTES.
|
|
30
|
+
* It recognises no role, no relation and no framework vocabulary, and it never
|
|
31
|
+
* claims to: a Wardley component and a text box are both `<rect>` plus
|
|
32
|
+
* `<text>`, and deciding which is which is the one question only the author can
|
|
33
|
+
* answer.
|
|
34
|
+
*
|
|
35
|
+
* **Where it is known to be wrong, and the list is meant to be complete.** A
|
|
36
|
+
* `scale`, `rotate`, `matrix` or `skew` transform is IGNORED rather than
|
|
37
|
+
* applied, so anything under one lands at its untransformed position and size.
|
|
38
|
+
* Curves (`C`, `S`, `Q`, `T`, `A`) are flattened to their endpoints, so a
|
|
39
|
+
* rounded connector arrives as a polyline through its anchor points and an arc
|
|
40
|
+
* that doubles back arrives as a straight line. A `<path>` that outlines a
|
|
41
|
+
* filled region (an arrowhead, an icon glyph) arrives as an open stroke, not as
|
|
42
|
+
* a filled shape. `<image>`, `<defs>`, `<marker>`, gradients, filters,
|
|
43
|
+
* `<clipPath>` and `<mask>` are skipped by the reader, and `<use>` and
|
|
44
|
+
* `<foreignObject>` never reach it at all — the SANITIZER removes them, because
|
|
45
|
+
* they are two of the constructs an SVG can carry code in. A `<style>` sheet is
|
|
46
|
+
* skipped, and that one is worth naming twice: mermaid paints almost entirely
|
|
47
|
+
* through CSS classes, so a mermaid SVG arrives in the initial colours — mostly
|
|
48
|
+
* black — with only the note to say why. `<title>`, `<desc>` and `<metadata>`
|
|
49
|
+
* are dropped in silence, deliberately and as the only exception to the rule
|
|
50
|
+
* below: they render nothing, so there is nothing to have lost.
|
|
51
|
+
*
|
|
52
|
+
* **What this reader alters without a note, because a note could not help.**
|
|
53
|
+
* Text width and height are ESTIMATED from the font size and the character
|
|
54
|
+
* count, because measuring text needs a font a pure function of a string is not
|
|
55
|
+
* allowed to have, so a label box is approximately and not exactly the size it
|
|
56
|
+
* was. Whitespace inside a label is collapsed to single spaces and trimmed
|
|
57
|
+
* (`xml:space="preserve"` is not honoured). A `<tspan>`'s own `x`/`y`, its `dx`
|
|
58
|
+
* / `dy` offsets and `dominant-baseline` are ignored, so a label laid out span
|
|
59
|
+
* by span arrives as plain stacked lines in document order. `stroke-dasharray`
|
|
60
|
+
* is not read, so a dashed line arrives solid. `em` font sizes are resolved
|
|
61
|
+
* against the inherited size only, with no font-relative refinement.
|
|
62
|
+
*
|
|
63
|
+
* **Everything else is reported.** Every OTHER construct this reader ignores,
|
|
64
|
+
* alters or cannot resolve produces exactly one `warning` note per KIND — never
|
|
65
|
+
* one per instance — so a result that looks empty always says why.
|
|
66
|
+
*
|
|
67
|
+
* ## What it never does
|
|
68
|
+
*
|
|
69
|
+
* **It writes no `interchange` payload, on any element, ever** — P2's hard
|
|
70
|
+
* rule, pinned by an anti-decay test in this package's own spec. There is
|
|
71
|
+
* nothing to preserve that the elements do not already carry: an SVG round-trip
|
|
72
|
+
* would be a re-render rather than a round-trip, and a payload would advertise
|
|
73
|
+
* a promise this tier deliberately does not make. `carried` and `quarantined`
|
|
74
|
+
* are therefore `0` in every report it returns, and the surface that offers the
|
|
75
|
+
* import must say all of this BEFORE the file is read.
|
|
76
|
+
*
|
|
77
|
+
* ## Pure, and framework-agnostic
|
|
78
|
+
*
|
|
79
|
+
* Text in, serialized element props out (P3): no `std`, no surface, no DI, so
|
|
80
|
+
* labre-mcp calls the very same function the editor commands call. It produces
|
|
81
|
+
* only generic `shape` / `text` / `brush` props and knows the name of no
|
|
82
|
+
* framework — which is exactly why several frameworks can declare it. ADR 0012
|
|
83
|
+
* explicitly rejects inferring one framework from a `.svg`, so the capability
|
|
84
|
+
* is declared per framework and this parser is what each of them wraps.
|
|
85
|
+
*/
|
|
86
|
+
/* ── The format, as far as it is shared ───────────────────────────────── */
|
|
87
|
+
/**
|
|
88
|
+
* The format id. Never used as a payload key, unlike every semantic format's —
|
|
89
|
+
* a visual import writes no payload at all — but it is what the report's
|
|
90
|
+
* headline calls itself ("SVG imported"), and what the registry's triple is
|
|
91
|
+
* built from.
|
|
92
|
+
*/
|
|
93
|
+
export const SVG_SKETCH_FORMAT_ID = 'svg';
|
|
94
|
+
export const SVG_SKETCH_EXTENSION = '.svg';
|
|
95
|
+
export const SVG_SKETCH_MIME = 'image/svg+xml';
|
|
96
|
+
/* ── Small readers ────────────────────────────────────────────────────── */
|
|
97
|
+
/**
|
|
98
|
+
* happy-dom (the vitest environment two of the three packages that test this
|
|
99
|
+
* run in) does not implement namespace-aware lookups, so this file walks
|
|
100
|
+
* children by hand and compares `localName`, exactly as the BPMN reader does.
|
|
101
|
+
* `children` is also skipped in favour of `childNodes`, because the former is
|
|
102
|
+
* an `HTMLCollection` whose behaviour on a foreign-namespaced document is one
|
|
103
|
+
* more thing that differs between the two environments.
|
|
104
|
+
*/
|
|
105
|
+
const ELEMENT_NODE = 1;
|
|
106
|
+
const TEXT_NODE = 3;
|
|
107
|
+
const CDATA_NODE = 4;
|
|
108
|
+
// `Node` and not `Element`, because only `childNodes` is ever read and one
|
|
109
|
+
// caller is DOMPurify's `RETURN_DOM` answer — which its own typed overload
|
|
110
|
+
// declares as a `Node`. Widening the parameter is more honest than casting the
|
|
111
|
+
// argument at that one call site.
|
|
112
|
+
function childElements(parent) {
|
|
113
|
+
const found = [];
|
|
114
|
+
for (const node of Array.from(parent.childNodes)) {
|
|
115
|
+
if (node.nodeType === ELEMENT_NODE)
|
|
116
|
+
found.push(node);
|
|
117
|
+
}
|
|
118
|
+
return found;
|
|
119
|
+
}
|
|
120
|
+
const nameOf = (element) => element.localName?.toLowerCase() ?? '';
|
|
121
|
+
/** One attribute as a finite number, or the caller's default. */
|
|
122
|
+
function num(element, name, fallback = 0) {
|
|
123
|
+
const raw = element.getAttribute(name);
|
|
124
|
+
if (raw === null)
|
|
125
|
+
return fallback;
|
|
126
|
+
// `parseFloat` and not `Number`, because a length is allowed to carry a unit
|
|
127
|
+
// (`12px`, `2em`). Only user units are honoured — anything else is read as
|
|
128
|
+
// its number, which is right for `px` and an approximation for the rest. A
|
|
129
|
+
// sketch is what this reader promises.
|
|
130
|
+
const value = Number.parseFloat(raw);
|
|
131
|
+
return Number.isFinite(value) ? value : fallback;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* A length that must be an absolute number of user units, or `0`.
|
|
135
|
+
*
|
|
136
|
+
* `width="100%"` is the case this exists for: `parseFloat` reads it as `100`,
|
|
137
|
+
* and a viewport 100 units wide against a 1000-unit `viewBox` would scale the
|
|
138
|
+
* whole drawing to a tenth of its size. A percentage is a length this reader
|
|
139
|
+
* cannot resolve — it depends on a containing block there is none of — so it
|
|
140
|
+
* answers "no length declared" and the caller falls back to 1:1.
|
|
141
|
+
*/
|
|
142
|
+
function absoluteLength(element, name) {
|
|
143
|
+
const raw = element.getAttribute(name);
|
|
144
|
+
if (raw === null || raw.includes('%'))
|
|
145
|
+
return 0;
|
|
146
|
+
const value = Number.parseFloat(raw);
|
|
147
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
148
|
+
}
|
|
149
|
+
/** Every number in a string, in order — `points`, `viewBox`, a transform's args. */
|
|
150
|
+
function numbers(raw) {
|
|
151
|
+
const found = raw.match(/-?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/g);
|
|
152
|
+
return found ? found.map(Number).filter(Number.isFinite) : [];
|
|
153
|
+
}
|
|
154
|
+
/* ── Notes: one per KIND, never one per instance ──────────────────────── */
|
|
155
|
+
/**
|
|
156
|
+
* The note channel, deduplicated on a key.
|
|
157
|
+
*
|
|
158
|
+
* D1's discipline, carried across to a tier that has no D1: nothing is dropped
|
|
159
|
+
* silently. What changes is the GRANULARITY — a file with four hundred
|
|
160
|
+
* `<use>` instances is one fact about the file, not four hundred, and a report
|
|
161
|
+
* nobody reads to the end is a report that was not written.
|
|
162
|
+
*
|
|
163
|
+
* Every note is a `warning`. The other four kinds would be lies here:
|
|
164
|
+
* `carried` and `quarantined` describe a payload this tier does not write, and
|
|
165
|
+
* `substituted-id` and `invented-layout` describe promises it does not make.
|
|
166
|
+
*/
|
|
167
|
+
class Notebook {
|
|
168
|
+
constructor() {
|
|
169
|
+
this.seen = new Set();
|
|
170
|
+
this.notes = [];
|
|
171
|
+
}
|
|
172
|
+
once(key, message, element) {
|
|
173
|
+
if (this.seen.has(key))
|
|
174
|
+
return;
|
|
175
|
+
this.seen.add(key);
|
|
176
|
+
this.notes.push({
|
|
177
|
+
kind: 'warning',
|
|
178
|
+
message,
|
|
179
|
+
...(element ? { element } : {}),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** `style="fill:#fff;stroke:none"`, as a map. Wins over the attribute. */
|
|
184
|
+
function styleMap(element) {
|
|
185
|
+
const map = new Map();
|
|
186
|
+
const raw = element.getAttribute('style');
|
|
187
|
+
if (!raw)
|
|
188
|
+
return map;
|
|
189
|
+
for (const declaration of raw.split(';')) {
|
|
190
|
+
const colon = declaration.indexOf(':');
|
|
191
|
+
if (colon < 0)
|
|
192
|
+
continue;
|
|
193
|
+
const property = declaration.slice(0, colon).trim().toLowerCase();
|
|
194
|
+
const value = declaration.slice(colon + 1).trim();
|
|
195
|
+
if (property && value)
|
|
196
|
+
map.set(property, value);
|
|
197
|
+
}
|
|
198
|
+
return map;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* `12`, `12px`, `12pt`, `1.5em` as a number of user units, or `undefined` for
|
|
202
|
+
* "this reader cannot resolve it, and has said so".
|
|
203
|
+
*
|
|
204
|
+
* Three units and no more. `px` and a bare number are user units already, `pt`
|
|
205
|
+
* is 4/3 of one by CSS's own definition, and `em` is the INHERITED size — which
|
|
206
|
+
* this reader has, and which is the only font-relative context a pure function
|
|
207
|
+
* of a string can honestly claim. Everything else (`%`, `ex`, `ch`, `rem`, the
|
|
208
|
+
* viewport units) needs a containing block or a loaded font, so it is refused
|
|
209
|
+
* with a note rather than silently read as its number: `font-size="200%"` read
|
|
210
|
+
* as 200 would draw a label fourteen times too big.
|
|
211
|
+
*/
|
|
212
|
+
function fontSizeOf(raw, inherited, notes) {
|
|
213
|
+
const value = Number.parseFloat(raw);
|
|
214
|
+
if (!Number.isFinite(value) || value <= 0)
|
|
215
|
+
return undefined;
|
|
216
|
+
// The tail after the number as WRITTEN, not after `String(value)` — `12.0px`
|
|
217
|
+
// and `12px` are the same length and `String(12)` is two characters.
|
|
218
|
+
const unit = raw
|
|
219
|
+
.trim()
|
|
220
|
+
.replace(/^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/, '')
|
|
221
|
+
.trim()
|
|
222
|
+
.toLowerCase();
|
|
223
|
+
if (unit === '' || unit === 'px')
|
|
224
|
+
return value;
|
|
225
|
+
if (unit === 'pt')
|
|
226
|
+
return (value * 4) / 3;
|
|
227
|
+
if (unit === 'em')
|
|
228
|
+
return value * inherited;
|
|
229
|
+
notes.once(`font-unit:${unit}`, `Font sizes in \`${unit}\` cannot be resolved without a page to measure against; those labels use the inherited size.`);
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* This element's paint, on top of what it inherited.
|
|
234
|
+
*
|
|
235
|
+
* Inheritance is not a nicety: real files — bpmn.io's, mermaid's, Illustrator's
|
|
236
|
+
* — set `fill` and `stroke` once on a `<g>` and never again, so a reader that
|
|
237
|
+
* only looked at the leaf would import every shape in the SVG's initial colours
|
|
238
|
+
* and get the picture visibly wrong.
|
|
239
|
+
*/
|
|
240
|
+
function paintOf(element, inherited, notes) {
|
|
241
|
+
const style = styleMap(element);
|
|
242
|
+
// `inherit` is resolved HERE, where the inherited value is in hand, rather
|
|
243
|
+
// than downstream where the only honest answer would be a neutral: the
|
|
244
|
+
// keyword means "whatever my parent had", and this function is the one place
|
|
245
|
+
// that knows.
|
|
246
|
+
const read = (property) => {
|
|
247
|
+
const raw = style.get(property) ?? element.getAttribute(property);
|
|
248
|
+
return raw === null || raw === undefined || raw.trim() === 'inherit'
|
|
249
|
+
? undefined
|
|
250
|
+
: raw;
|
|
251
|
+
};
|
|
252
|
+
const strokeWidth = read('stroke-width');
|
|
253
|
+
const parsedWidth = strokeWidth === undefined ? undefined : Number.parseFloat(strokeWidth);
|
|
254
|
+
const fontSize = read('font-size');
|
|
255
|
+
return {
|
|
256
|
+
fill: read('fill') ?? inherited.fill,
|
|
257
|
+
stroke: read('stroke') ?? inherited.stroke,
|
|
258
|
+
strokeWidth: parsedWidth !== undefined && Number.isFinite(parsedWidth)
|
|
259
|
+
? parsedWidth
|
|
260
|
+
: inherited.strokeWidth,
|
|
261
|
+
fontSize: (fontSize === undefined
|
|
262
|
+
? undefined
|
|
263
|
+
: fontSizeOf(fontSize, inherited.fontSize ?? DEFAULT_FONT_SIZE, notes)) ?? inherited.fontSize,
|
|
264
|
+
textAnchor: read('text-anchor') ?? inherited.textAnchor,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Whether this element renders at all, with a note for each reason it does not.
|
|
269
|
+
*
|
|
270
|
+
* `display:none` removes the element AND its subtree from the rendering;
|
|
271
|
+
* `visibility:hidden` hides the element but not necessarily its children — this
|
|
272
|
+
* reader treats both as "skip the subtree", which is the coarser of the two and
|
|
273
|
+
* the one that keeps an invisible frame from arriving as a black rectangle over
|
|
274
|
+
* the drawing. Both are common: bpmn.io hides its own measurement layers this
|
|
275
|
+
* way, and an exporter's off-canvas scaffolding is the usual source of a
|
|
276
|
+
* "why is there a huge black box on my board" report.
|
|
277
|
+
*/
|
|
278
|
+
function isHidden(element, notes) {
|
|
279
|
+
const style = styleMap(element);
|
|
280
|
+
const display = style.get('display') ?? element.getAttribute('display');
|
|
281
|
+
if (display?.trim() === 'none') {
|
|
282
|
+
notes.once('hidden:display', 'Parts of the file marked `display:none` were not imported — they draw nothing where the file came from either.');
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
const visibility = style.get('visibility') ?? element.getAttribute('visibility');
|
|
286
|
+
const hidden = visibility?.trim();
|
|
287
|
+
if (hidden === 'hidden' || hidden === 'collapse') {
|
|
288
|
+
notes.once('hidden:visibility', 'Parts of the file marked `visibility:hidden` were not imported — they draw nothing where the file came from either.');
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Opacity is not carried, and that is a note rather than a drop.
|
|
295
|
+
*
|
|
296
|
+
* The shape model has no opacity of its own — a colour is a colour — so a
|
|
297
|
+
* half-transparent shade would have to be baked into the colour, which needs
|
|
298
|
+
* the backdrop it sits on. It is imported at full strength, which is visible
|
|
299
|
+
* and editable, and the note says the strength changed.
|
|
300
|
+
*/
|
|
301
|
+
function noteOpacity(element, notes) {
|
|
302
|
+
const style = styleMap(element);
|
|
303
|
+
for (const property of ['opacity', 'fill-opacity', 'stroke-opacity']) {
|
|
304
|
+
const raw = style.get(property) ?? element.getAttribute(property);
|
|
305
|
+
if (raw === null || raw === undefined)
|
|
306
|
+
continue;
|
|
307
|
+
const value = Number.parseFloat(raw);
|
|
308
|
+
if (Number.isFinite(value) && value < 1) {
|
|
309
|
+
notes.once('opacity', 'Transparency is not carried: partly transparent shapes arrive at full strength.');
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* The SVG initial values, which is what an unpainted element actually is.
|
|
316
|
+
*
|
|
317
|
+
* `fill: black` is the SPEC's initial value, not a choice — an attribute-free
|
|
318
|
+
* `<rect>` renders as a solid black box in every browser, and importing it
|
|
319
|
+
* hollow would be this reader redrawing the file rather than reading it.
|
|
320
|
+
*/
|
|
321
|
+
const INITIAL_PAINT = { fill: 'black', stroke: 'none', strokeWidth: 1 };
|
|
322
|
+
/** The font size a `<text>` with none declared is drawn at. */
|
|
323
|
+
const DEFAULT_FONT_SIZE = 16;
|
|
324
|
+
/** What a paint served by `url(#…)` or `currentColor` falls back to. */
|
|
325
|
+
const NEUTRAL_STROKE = '#000000';
|
|
326
|
+
const NEUTRAL_FILL = '#cccccc';
|
|
327
|
+
/**
|
|
328
|
+
* A paint value as a colour the shape model will accept, or `undefined` for
|
|
329
|
+
* "nothing is painted here".
|
|
330
|
+
*
|
|
331
|
+
* The model takes a raw CSS colour string (`Color` is `string | {normal} |
|
|
332
|
+
* {dark, light}`), so a hex or an `rgb()` from the file is passed through
|
|
333
|
+
* verbatim and the picture keeps its colours. Two values cannot be: a paint
|
|
334
|
+
* server (`url(#gradient)`) needs a `<defs>` this reader skips, and
|
|
335
|
+
* `currentColor` needs an inherited CSS colour there is nobody to ask for.
|
|
336
|
+
* Both fall back to a neutral, and both say so.
|
|
337
|
+
*/
|
|
338
|
+
function colorOf(raw, fallback, notes) {
|
|
339
|
+
const value = raw?.trim();
|
|
340
|
+
if (!value || value === 'none' || value === 'transparent')
|
|
341
|
+
return undefined;
|
|
342
|
+
if (value.startsWith('url(')) {
|
|
343
|
+
notes.once('paint-server', 'Gradients and patterns are not read; the shapes that used one are a flat neutral.');
|
|
344
|
+
return fallback;
|
|
345
|
+
}
|
|
346
|
+
if (value === 'currentColor') {
|
|
347
|
+
notes.once('current-color', '`currentColor` has no page to inherit from here; the shapes that used it are a flat neutral.');
|
|
348
|
+
return fallback;
|
|
349
|
+
}
|
|
350
|
+
return value;
|
|
351
|
+
}
|
|
352
|
+
const IDENTITY = { ox: 0, oy: 0, s: 1 };
|
|
353
|
+
const px = (frame, x) => x * frame.s + frame.ox;
|
|
354
|
+
const py = (frame, y) => y * frame.s + frame.oy;
|
|
355
|
+
/** A LENGTH is scaled and never offset — a width, a radius, a font size. */
|
|
356
|
+
const len = (frame, value) => value * frame.s;
|
|
357
|
+
const xywh = (x, y, w, h) => `[${x},${y},${w},${h}]`;
|
|
358
|
+
/**
|
|
359
|
+
* The frame a `<svg>` element establishes inside its parent's.
|
|
360
|
+
*
|
|
361
|
+
* The same arithmetic for the outermost one (whose parent frame is the
|
|
362
|
+
* identity) and for a nested one, which is why there is one function: a nested
|
|
363
|
+
* `<svg>` is a new viewport, its `x`/`y` place it in the parent's user space,
|
|
364
|
+
* and its own `viewBox` re-origins and re-scales what is inside it.
|
|
365
|
+
*/
|
|
366
|
+
function viewportFrame(element, parent) {
|
|
367
|
+
const placed = {
|
|
368
|
+
ox: px(parent, num(element, 'x')),
|
|
369
|
+
oy: py(parent, num(element, 'y')),
|
|
370
|
+
s: parent.s,
|
|
371
|
+
};
|
|
372
|
+
const box = numbers(element.getAttribute('viewBox') ?? '');
|
|
373
|
+
if (box.length < 4)
|
|
374
|
+
return placed;
|
|
375
|
+
const [minX, minY, boxW, boxH] = box;
|
|
376
|
+
if (boxW <= 0 || boxH <= 0)
|
|
377
|
+
return placed;
|
|
378
|
+
const width = absoluteLength(element, 'width');
|
|
379
|
+
const height = absoluteLength(element, 'height');
|
|
380
|
+
// No declared size is not a broken file — it is the usual `<svg viewBox=…>`
|
|
381
|
+
// that fills whatever it is put in. There is no containing block here, so the
|
|
382
|
+
// viewBox IS the size and the scale stays the parent's.
|
|
383
|
+
const scale = width > 0 && height > 0
|
|
384
|
+
? placed.s * Math.min(width / boxW, height / boxH)
|
|
385
|
+
: placed.s;
|
|
386
|
+
return {
|
|
387
|
+
ox: placed.ox - minX * scale,
|
|
388
|
+
oy: placed.oy - minY * scale,
|
|
389
|
+
s: scale,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* The `translate(…)` this element contributes, and a note for every other kind
|
|
394
|
+
* of transform on it.
|
|
395
|
+
*
|
|
396
|
+
* v1 accumulates translations and IGNORES the rest — a scaled or rotated
|
|
397
|
+
* element is imported at its untransformed position rather than dropped,
|
|
398
|
+
* because a sketch missing a shape is worse than a sketch with a shape in the
|
|
399
|
+
* wrong place, and the author is about to move things anyway. What is not
|
|
400
|
+
* acceptable is doing it quietly, so each ignored KIND is named once.
|
|
401
|
+
*/
|
|
402
|
+
function translated(element, frame, notes) {
|
|
403
|
+
const raw = element.getAttribute('transform');
|
|
404
|
+
if (!raw)
|
|
405
|
+
return frame;
|
|
406
|
+
let tx = 0;
|
|
407
|
+
let ty = 0;
|
|
408
|
+
for (const [, kind, args] of raw.matchAll(/([a-zA-Z]+)\s*\(([^)]*)\)/g)) {
|
|
409
|
+
const values = numbers(args);
|
|
410
|
+
if (kind === 'translate') {
|
|
411
|
+
tx += values[0] ?? 0;
|
|
412
|
+
ty += values[1] ?? 0;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
notes.once(`transform:${kind}`, `\`${kind}\` transforms are ignored (best effort): what carried one is placed as if it did not.`);
|
|
416
|
+
}
|
|
417
|
+
// A translate is expressed in the PARENT's user units, so it is scaled by the
|
|
418
|
+
// frame it was written in and never by the one it creates.
|
|
419
|
+
return {
|
|
420
|
+
ox: frame.ox + tx * frame.s,
|
|
421
|
+
oy: frame.oy + ty * frame.s,
|
|
422
|
+
s: frame.s,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
/* ── Path data ────────────────────────────────────────────────────────── */
|
|
426
|
+
/** How many numbers each path command takes, and where its ENDPOINT sits. */
|
|
427
|
+
const PATH_ARITY = {
|
|
428
|
+
m: 2,
|
|
429
|
+
l: 2,
|
|
430
|
+
h: 1,
|
|
431
|
+
v: 1,
|
|
432
|
+
c: 6,
|
|
433
|
+
s: 4,
|
|
434
|
+
q: 4,
|
|
435
|
+
t: 2,
|
|
436
|
+
a: 7,
|
|
437
|
+
z: 0,
|
|
438
|
+
};
|
|
439
|
+
/** The index, inside one command's arguments, of the x of its endpoint. */
|
|
440
|
+
const PATH_ENDPOINT = { c: 4, s: 2, q: 2, a: 5 };
|
|
441
|
+
/** The commands whose shape is thrown away when only the endpoint is kept. */
|
|
442
|
+
const CURVE_COMMANDS = new Set(['c', 's', 'q', 't', 'a']);
|
|
443
|
+
/**
|
|
444
|
+
* A `d` attribute as one polyline per subpath, in the element's own user space.
|
|
445
|
+
*
|
|
446
|
+
* `M/L/H/V/Z` are exact. Curves are flattened to their ENDPOINTS — coarse, and
|
|
447
|
+
* deliberately so: this is a sketch, the author is going to redraw whatever
|
|
448
|
+
* matters, and a proper flattener is a de Casteljau subdivision plus an arc
|
|
449
|
+
* parameterization for a fidelity nobody is promised. The first curve in the
|
|
450
|
+
* file says so in a note.
|
|
451
|
+
*
|
|
452
|
+
* A subpath per stroke, rather than one stroke through the whole `d`: a brush
|
|
453
|
+
* element is a single connected path, so joining two subpaths would draw a line
|
|
454
|
+
* across the drawing that the file never had.
|
|
455
|
+
*/
|
|
456
|
+
function samplePath(d, notes) {
|
|
457
|
+
const subpaths = [];
|
|
458
|
+
let current = [];
|
|
459
|
+
let start = null;
|
|
460
|
+
let x = 0;
|
|
461
|
+
let y = 0;
|
|
462
|
+
const push = () => {
|
|
463
|
+
if (current.length >= 2)
|
|
464
|
+
subpaths.push(current);
|
|
465
|
+
else if (current.length === 1) {
|
|
466
|
+
notes.once('lone-point', 'A path that never moved anywhere draws nothing and was skipped.');
|
|
467
|
+
}
|
|
468
|
+
current = [];
|
|
469
|
+
};
|
|
470
|
+
for (const [, letter, rawArgs] of d.matchAll(/([MmLlHhVvCcSsQqTtAaZz])([^MmLlHhVvCcSsQqTtAaZz]*)/g)) {
|
|
471
|
+
const kind = letter.toLowerCase();
|
|
472
|
+
const relative = letter !== letter.toUpperCase();
|
|
473
|
+
const arity = PATH_ARITY[kind];
|
|
474
|
+
const args = numbers(rawArgs);
|
|
475
|
+
if (kind === 'z') {
|
|
476
|
+
if (start && current.length > 0)
|
|
477
|
+
current.push([start[0], start[1]]);
|
|
478
|
+
[x, y] = start ?? [x, y];
|
|
479
|
+
push();
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
if (CURVE_COMMANDS.has(kind)) {
|
|
483
|
+
notes.once('curve', 'Curves are approximated by their endpoints (best effort), so a curved path arrives as straight segments.');
|
|
484
|
+
}
|
|
485
|
+
// One command letter may carry SEVERAL argument groups (`L 1 2 3 4`), and
|
|
486
|
+
// a repeated `M` group is an implicit lineto — the spec's own rule, and the
|
|
487
|
+
// one every hand-written path generator relies on.
|
|
488
|
+
let group = 0;
|
|
489
|
+
for (let i = 0; i + arity <= args.length; i += arity, group += 1) {
|
|
490
|
+
const chunk = args.slice(i, i + arity);
|
|
491
|
+
if (kind === 'h') {
|
|
492
|
+
x = relative ? x + chunk[0] : chunk[0];
|
|
493
|
+
}
|
|
494
|
+
else if (kind === 'v') {
|
|
495
|
+
y = relative ? y + chunk[0] : chunk[0];
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
const at = PATH_ENDPOINT[kind] ?? 0;
|
|
499
|
+
const [ex, ey] = [chunk[at], chunk[at + 1]];
|
|
500
|
+
x = relative ? x + ex : ex;
|
|
501
|
+
y = relative ? y + ey : ey;
|
|
502
|
+
}
|
|
503
|
+
if (kind === 'm' && group === 0) {
|
|
504
|
+
push();
|
|
505
|
+
start = [x, y];
|
|
506
|
+
}
|
|
507
|
+
current.push([x, y]);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
push();
|
|
511
|
+
return subpaths;
|
|
512
|
+
}
|
|
513
|
+
/** The generic shape props every recognised outline lands with. */
|
|
514
|
+
function shapeProps(paint, frame, sketch) {
|
|
515
|
+
const fill = colorOf(paint.fill, NEUTRAL_FILL, sketch.notes);
|
|
516
|
+
const stroke = colorOf(paint.stroke, NEUTRAL_STROKE, sketch.notes);
|
|
517
|
+
return {
|
|
518
|
+
type: 'shape',
|
|
519
|
+
// `General`, never `Scribbled`: the file is a rendering somebody produced
|
|
520
|
+
// deliberately, and re-drawing it hand-sketched would be this reader
|
|
521
|
+
// inventing a style the source never had.
|
|
522
|
+
shapeStyle: ShapeStyle.General,
|
|
523
|
+
filled: fill !== undefined,
|
|
524
|
+
fillColor: fill ?? 'transparent',
|
|
525
|
+
strokeColor: stroke ?? 'transparent',
|
|
526
|
+
strokeStyle: stroke === undefined ? StrokeStyle.None : StrokeStyle.Solid,
|
|
527
|
+
strokeWidth: len(frame, paint.strokeWidth ?? 1),
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
const EMPTY_BOX_NOTE = 'Shapes with no width or height were skipped.';
|
|
531
|
+
function readRect(element, frame, paint, sketch) {
|
|
532
|
+
const w = num(element, 'width');
|
|
533
|
+
const h = num(element, 'height');
|
|
534
|
+
if (w <= 0 || h <= 0) {
|
|
535
|
+
sketch.notes.once('empty-box', EMPTY_BOX_NOTE);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
// `rx` is an absolute corner radius in user units, and the shape model reads
|
|
539
|
+
// a `radius` of 1 or more as absolute pixels (below 1 it is a RATIO of the
|
|
540
|
+
// shorter side). Sub-pixel radii are visually zero, so they are dropped
|
|
541
|
+
// rather than reinterpreted as a 40 % round-over — and a PERCENTAGE radius is
|
|
542
|
+
// refused outright for the same reason it would otherwise be read as its
|
|
543
|
+
// number: `rx="50%"` would round a box over by fifty pixels rather than into
|
|
544
|
+
// a pill.
|
|
545
|
+
const rawRadius = element.getAttribute('rx') ?? element.getAttribute('ry');
|
|
546
|
+
let radius = 0;
|
|
547
|
+
if (rawRadius?.includes('%')) {
|
|
548
|
+
sketch.notes.once('percent-radius', 'Corner radii given as a percentage were not read; those corners arrive square.');
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
const scaled = len(frame, num(element, 'rx', num(element, 'ry')));
|
|
552
|
+
radius = scaled >= 1 ? scaled : 0;
|
|
553
|
+
}
|
|
554
|
+
sketch.elements.push({
|
|
555
|
+
...shapeProps(paint, frame, sketch),
|
|
556
|
+
shapeType: ShapeType.Rect,
|
|
557
|
+
radius,
|
|
558
|
+
xywh: xywh(px(frame, num(element, 'x')), py(frame, num(element, 'y')), len(frame, w), len(frame, h)),
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
function readEllipse(element, frame, paint, sketch) {
|
|
562
|
+
const circle = nameOf(element) === 'circle';
|
|
563
|
+
const r = num(element, 'r');
|
|
564
|
+
const rx = circle ? r : num(element, 'rx');
|
|
565
|
+
const ry = circle ? r : num(element, 'ry');
|
|
566
|
+
if (rx <= 0 || ry <= 0) {
|
|
567
|
+
sketch.notes.once('empty-box', EMPTY_BOX_NOTE);
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const cx = num(element, 'cx');
|
|
571
|
+
const cy = num(element, 'cy');
|
|
572
|
+
sketch.elements.push({
|
|
573
|
+
...shapeProps(paint, frame, sketch),
|
|
574
|
+
shapeType: ShapeType.Ellipse,
|
|
575
|
+
radius: 0,
|
|
576
|
+
xywh: xywh(px(frame, cx - rx), py(frame, cy - ry), len(frame, rx * 2), len(frame, ry * 2)),
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* A `<polygon>` as a polygon shape, with its outline kept.
|
|
581
|
+
*
|
|
582
|
+
* The shape model stores polygon `vertices` NORMALIZED into its bounding box
|
|
583
|
+
* (`[0, 1]` on each axis), which is what lets the shape be resized afterwards
|
|
584
|
+
* and is how EDGY's activity chevron is already declared. Two cases cannot be
|
|
585
|
+
* normalized and fall back to the bounding box as a plain rectangle, each with
|
|
586
|
+
* a note: fewer than three points is not an outline, and a polygon flat on one
|
|
587
|
+
* axis has a zero-width box to divide by.
|
|
588
|
+
*/
|
|
589
|
+
function readPolygon(element, frame, paint, sketch) {
|
|
590
|
+
const flat = numbers(element.getAttribute('points') ?? '');
|
|
591
|
+
const points = [];
|
|
592
|
+
for (let i = 0; i + 1 < flat.length; i += 2) {
|
|
593
|
+
points.push([px(frame, flat[i]), py(frame, flat[i + 1])]);
|
|
594
|
+
}
|
|
595
|
+
const xs = points.map(p => p[0]);
|
|
596
|
+
const ys = points.map(p => p[1]);
|
|
597
|
+
const minX = Math.min(...xs);
|
|
598
|
+
const minY = Math.min(...ys);
|
|
599
|
+
const w = Math.max(...xs) - minX;
|
|
600
|
+
const h = Math.max(...ys) - minY;
|
|
601
|
+
if (points.length < 3 || w <= 0 || h <= 0) {
|
|
602
|
+
if (points.length === 0 || w < 0 || h < 0) {
|
|
603
|
+
sketch.notes.once('empty-box', EMPTY_BOX_NOTE);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
sketch.notes.once('flat-polygon', 'A polygon with fewer than three corners, or flat on one axis, arrives as its bounding rectangle.');
|
|
607
|
+
sketch.elements.push({
|
|
608
|
+
...shapeProps(paint, frame, sketch),
|
|
609
|
+
shapeType: ShapeType.Rect,
|
|
610
|
+
radius: 0,
|
|
611
|
+
xywh: xywh(minX, minY, Math.max(w, 1), Math.max(h, 1)),
|
|
612
|
+
});
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
sketch.elements.push({
|
|
616
|
+
...shapeProps(paint, frame, sketch),
|
|
617
|
+
shapeType: ShapeType.Polygon,
|
|
618
|
+
radius: 0,
|
|
619
|
+
vertices: points.map(([x, y]) => [(x - minX) / w, (y - minY) / h]),
|
|
620
|
+
isClosed: true,
|
|
621
|
+
xywh: xywh(minX, minY, w, h),
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* A stroke — `<line>`, `<polyline>`, `<path>` — as one brush element per
|
|
626
|
+
* connected run of points, in CANVAS coordinates.
|
|
627
|
+
*
|
|
628
|
+
* ## Key order is load-bearing here, and it is not a style choice
|
|
629
|
+
*
|
|
630
|
+
* `BrushElementModel` declares `points` with a `@convert` that re-bases them
|
|
631
|
+
* onto the bound it derives, INFLATED BY `lineWidth`, and a `@derive` that
|
|
632
|
+
* writes `xywh` from the same arithmetic. `surface.addElement` copies props
|
|
633
|
+
* onto the model in `Object.keys` order, so `lineWidth` must be assigned BEFORE
|
|
634
|
+
* `points` or the conversion runs against the model's default width of 4 and
|
|
635
|
+
* the stroke lands with a box that is up to three pixels off on every side.
|
|
636
|
+
* **Do not reorder the literal below**; the integration spec
|
|
637
|
+
* (`integration-test/…/svg-sketch.spec.ts`) pins the resulting `xywh` on a live
|
|
638
|
+
* surface precisely because a unit test over plain props cannot see this.
|
|
639
|
+
*
|
|
640
|
+
* The points handed over are ABSOLUTE, which is what the brush tool itself
|
|
641
|
+
* passes: the model derives the box, so an importer that pre-computed `xywh`
|
|
642
|
+
* would be doing that arithmetic twice and disagreeing with the model about the
|
|
643
|
+
* line-width inflation.
|
|
644
|
+
*/
|
|
645
|
+
function pushStroke(points, paint, frame, sketch) {
|
|
646
|
+
if (points.length < 2)
|
|
647
|
+
return;
|
|
648
|
+
const color = colorOf(paint.stroke, NEUTRAL_STROKE, sketch.notes) ??
|
|
649
|
+
// A path with no stroke and a fill is an outlined REGION — an arrowhead, a
|
|
650
|
+
// glyph. It is drawn as a stroke anyway (a brush is the only thing this
|
|
651
|
+
// reader has for an open path), so it takes the fill's colour rather than
|
|
652
|
+
// arriving invisible. And a shape with neither is still drawn, in the
|
|
653
|
+
// initial black, because that is what the file renders as.
|
|
654
|
+
colorOf(paint.fill, NEUTRAL_STROKE, sketch.notes) ??
|
|
655
|
+
NEUTRAL_STROKE;
|
|
656
|
+
sketch.elements.push({
|
|
657
|
+
type: 'brush',
|
|
658
|
+
color,
|
|
659
|
+
// BEFORE `points` — see this function's own documentation.
|
|
660
|
+
lineWidth: Math.max(len(frame, paint.strokeWidth ?? 1), 1),
|
|
661
|
+
points,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* `<text>` and its children as an EDITABLE free-text element.
|
|
666
|
+
*
|
|
667
|
+
* The PO-critical path, and the one thing this tier promises without
|
|
668
|
+
* qualification: a label that arrives as a picture of a word is a label nobody
|
|
669
|
+
* can correct. `text` is handed over as a plain string and
|
|
670
|
+
* `TextElementModel.propsToY` turns it into the `Y.Text` the editor binds to,
|
|
671
|
+
* so the first double-click puts a caret in it.
|
|
672
|
+
*
|
|
673
|
+
* ## Children in DOCUMENT ORDER, text nodes included
|
|
674
|
+
*
|
|
675
|
+
* `<text>Hello <tspan>World</tspan></text>` is one label reading "Hello World",
|
|
676
|
+
* and a reader that collected only the `<tspan>`s would import "World" and
|
|
677
|
+
* lose the rest without noticing — the worst kind of loss, because the result
|
|
678
|
+
* still looks like a label. So the children are walked in order and every
|
|
679
|
+
* non-empty run, span or bare text node alike, becomes a line.
|
|
680
|
+
*
|
|
681
|
+
* Two approximations are unavoidable and are stated in this module's own
|
|
682
|
+
* failure-modes paragraph rather than in a note, because no note could help:
|
|
683
|
+
* SVG's `y` is a BASELINE and the model's box is a top edge, so the box is
|
|
684
|
+
* lifted by one font size; and the box's width is estimated from the character
|
|
685
|
+
* count, because measuring text needs a loaded font — which is exactly the
|
|
686
|
+
* thing a pure function of a string is not allowed to have. Whitespace inside
|
|
687
|
+
* a run is collapsed to single spaces and trimmed, so `xml:space="preserve"`
|
|
688
|
+
* is not honoured.
|
|
689
|
+
*/
|
|
690
|
+
const CHARACTER_WIDTH_RATIO = 0.55;
|
|
691
|
+
const LINE_HEIGHT_RATIO = 1.2;
|
|
692
|
+
function readText(element, frame, paint, sketch) {
|
|
693
|
+
const lines = [];
|
|
694
|
+
const collapse = (raw) => raw.replace(/\s+/g, ' ').trim();
|
|
695
|
+
for (const node of Array.from(element.childNodes)) {
|
|
696
|
+
if (node.nodeType === TEXT_NODE || node.nodeType === CDATA_NODE) {
|
|
697
|
+
const line = collapse(node.nodeValue ?? '');
|
|
698
|
+
if (line)
|
|
699
|
+
lines.push(line);
|
|
700
|
+
}
|
|
701
|
+
else if (node.nodeType === ELEMENT_NODE) {
|
|
702
|
+
const child = node;
|
|
703
|
+
if (nameOf(child) !== 'tspan')
|
|
704
|
+
continue;
|
|
705
|
+
if (isHidden(child, sketch.notes))
|
|
706
|
+
continue;
|
|
707
|
+
const line = collapse(child.textContent ?? '');
|
|
708
|
+
if (line)
|
|
709
|
+
lines.push(line);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (lines.length === 0) {
|
|
713
|
+
sketch.notes.once('empty-text', 'Empty text elements were skipped.');
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
const fontSize = len(frame, paint.fontSize ?? DEFAULT_FONT_SIZE);
|
|
717
|
+
const widest = Math.max(...lines.map(line => line.length));
|
|
718
|
+
const w = Math.max(widest * fontSize * CHARACTER_WIDTH_RATIO, fontSize);
|
|
719
|
+
const h = lines.length * fontSize * LINE_HEIGHT_RATIO;
|
|
720
|
+
// `text-anchor` says which end of the box `x` names, and it INHERITS — a
|
|
721
|
+
// `<g text-anchor="middle">` around a whole diagram is how bpmn.io centres
|
|
722
|
+
// every label it writes, so reading it off the leaf alone would offset every
|
|
723
|
+
// one of them by half its width.
|
|
724
|
+
const anchor = (paint.textAnchor ?? 'start').trim();
|
|
725
|
+
const align = anchor === 'middle'
|
|
726
|
+
? TextAlign.Center
|
|
727
|
+
: anchor === 'end'
|
|
728
|
+
? TextAlign.Right
|
|
729
|
+
: TextAlign.Left;
|
|
730
|
+
const shift = anchor === 'middle' ? w / 2 : anchor === 'end' ? w : 0;
|
|
731
|
+
sketch.elements.push({
|
|
732
|
+
type: 'text',
|
|
733
|
+
text: lines.join('\n'),
|
|
734
|
+
fontSize,
|
|
735
|
+
textAlign: align,
|
|
736
|
+
color: colorOf(paint.fill, NEUTRAL_STROKE, sketch.notes) ?? NEUTRAL_STROKE,
|
|
737
|
+
xywh: xywh(px(frame, num(element, 'x')) - shift, py(frame, num(element, 'y')) - fontSize, w, h),
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
/** The names that are containers rather than drawings. */
|
|
741
|
+
const CONTAINERS = new Set(['g', 'a']);
|
|
742
|
+
/**
|
|
743
|
+
* What renders nothing and is therefore dropped in SILENCE — the one exception
|
|
744
|
+
* to "every ignored kind gets a note".
|
|
745
|
+
*
|
|
746
|
+
* A `<title>` is an accessible name, a `<desc>` a long description, a
|
|
747
|
+
* `<metadata>` block a machine-readable annotation. None of them paints a
|
|
748
|
+
* pixel, so there is no loss to report and a note about each would be three
|
|
749
|
+
* lines of noise on the first import of every file a real tool ever wrote.
|
|
750
|
+
* `<style>` is deliberately NOT here: it paints, and losing it is the single
|
|
751
|
+
* most visible thing this reader does to a mermaid diagram.
|
|
752
|
+
*/
|
|
753
|
+
const NON_RENDERING = new Set(['title', 'desc', 'metadata']);
|
|
754
|
+
/** The sanitizer's own HTML wrapper, which no `.svg` on a disk ever contained. */
|
|
755
|
+
const PARSER_SCAFFOLDING = new Set(['html', 'head', 'body']);
|
|
756
|
+
function walk(parent, frame, inherited, sketch) {
|
|
757
|
+
for (const element of childElements(parent)) {
|
|
758
|
+
visit(element, frame, inherited, sketch);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
/** One element and whatever it contains, placed in its parent's frame. */
|
|
762
|
+
function visit(element, frame, inherited, sketch) {
|
|
763
|
+
const name = nameOf(element);
|
|
764
|
+
if (NON_RENDERING.has(name))
|
|
765
|
+
return;
|
|
766
|
+
if (isHidden(element, sketch.notes))
|
|
767
|
+
return;
|
|
768
|
+
const here = translated(element, frame, sketch.notes);
|
|
769
|
+
const paint = paintOf(element, inherited, sketch.notes);
|
|
770
|
+
noteOpacity(element, sketch.notes);
|
|
771
|
+
if (CONTAINERS.has(name)) {
|
|
772
|
+
walk(element, here, paint, sketch);
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (name === 'switch') {
|
|
776
|
+
// §5.10: a `<switch>` renders the FIRST child whose requirement attributes
|
|
777
|
+
// pass, and this reader evaluates none of them — so it takes the first,
|
|
778
|
+
// which is what a viewer that supports everything does, and says the
|
|
779
|
+
// alternatives went. Rendering all of them would stack every localisation
|
|
780
|
+
// of a label on top of itself.
|
|
781
|
+
const [first, ...rest] = childElements(element).filter(child => !NON_RENDERING.has(nameOf(child)));
|
|
782
|
+
if (rest.length > 0) {
|
|
783
|
+
sketch.notes.once('switch', 'A `<switch>` offers alternative renderings; the first was imported and the others were not.');
|
|
784
|
+
}
|
|
785
|
+
if (first)
|
|
786
|
+
visit(first, here, paint, sketch);
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
if (name === 'svg') {
|
|
790
|
+
walk(element, viewportFrame(element, here), paint, sketch);
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
emit(element, name, here, paint, sketch);
|
|
794
|
+
}
|
|
795
|
+
/** One recognised element, as props. Split out so `<switch>` can reuse it. */
|
|
796
|
+
function emit(element, name, frame, paint, sketch) {
|
|
797
|
+
switch (name) {
|
|
798
|
+
case 'rect':
|
|
799
|
+
readRect(element, frame, paint, sketch);
|
|
800
|
+
break;
|
|
801
|
+
case 'circle':
|
|
802
|
+
case 'ellipse':
|
|
803
|
+
readEllipse(element, frame, paint, sketch);
|
|
804
|
+
break;
|
|
805
|
+
case 'polygon':
|
|
806
|
+
readPolygon(element, frame, paint, sketch);
|
|
807
|
+
break;
|
|
808
|
+
case 'line':
|
|
809
|
+
pushStroke([
|
|
810
|
+
[px(frame, num(element, 'x1')), py(frame, num(element, 'y1'))],
|
|
811
|
+
[px(frame, num(element, 'x2')), py(frame, num(element, 'y2'))],
|
|
812
|
+
], paint, frame, sketch);
|
|
813
|
+
break;
|
|
814
|
+
case 'polyline': {
|
|
815
|
+
const flat = numbers(element.getAttribute('points') ?? '');
|
|
816
|
+
const points = [];
|
|
817
|
+
for (let i = 0; i + 1 < flat.length; i += 2) {
|
|
818
|
+
points.push([px(frame, flat[i]), py(frame, flat[i + 1])]);
|
|
819
|
+
}
|
|
820
|
+
pushStroke(points, paint, frame, sketch);
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
case 'path':
|
|
824
|
+
for (const subpath of samplePath(element.getAttribute('d') ?? '', sketch.notes)) {
|
|
825
|
+
pushStroke(subpath.map(([x, y]) => [px(frame, x), py(frame, y)]), paint, frame, sketch);
|
|
826
|
+
}
|
|
827
|
+
break;
|
|
828
|
+
case 'text':
|
|
829
|
+
readText(element, frame, paint, sketch);
|
|
830
|
+
break;
|
|
831
|
+
default:
|
|
832
|
+
// Everything this reader has no artefact for, named ONCE per kind:
|
|
833
|
+
// `<image>`, `<defs>`, `<marker>`, the gradients, the filters, `<style>`,
|
|
834
|
+
// and whatever SVG grows next. A drawing built out of symbol instances
|
|
835
|
+
// arrives nearly empty, and this is the line that tells its author why
|
|
836
|
+
// instead of leaving them to guess.
|
|
837
|
+
sketch.notes.once(`skipped:${name}`, `\`<${name}>\` is not recognised and was skipped.`, name);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
/* ── The capability's function ────────────────────────────────────────── */
|
|
841
|
+
/**
|
|
842
|
+
* The document, sanitized, or an exception naming what is wrong with it.
|
|
843
|
+
*
|
|
844
|
+
* Well-formedness FIRST, because `DOMParser` reports a malformed document as a
|
|
845
|
+
* `parsererror` element rather than by throwing — a verdict in the shape of a
|
|
846
|
+
* document — and because DOMPurify's parser is the forgiving HTML one, which
|
|
847
|
+
* would quietly repair the very thing the caller needs to be told about. So:
|
|
848
|
+
* parse for the verdict, reading nothing out of the result but that; sanitize
|
|
849
|
+
* the SOURCE; and walk only what came back from the sanitizer.
|
|
850
|
+
*
|
|
851
|
+
* The sanitizer is not optional and it is not defensive programming. An `.svg`
|
|
852
|
+
* is an executable document — `<script>`, `<foreignObject>` with markup, event
|
|
853
|
+
* handler attributes — handed over by whoever sent the file. The same
|
|
854
|
+
* `USE_PROFILES: { svg: true }` guard is what the edgeless clipboard already
|
|
855
|
+
* puts in front of a pasted SVG.
|
|
856
|
+
*/
|
|
857
|
+
function parseSvgRoot(source, notes) {
|
|
858
|
+
const doc = new DOMParser().parseFromString(source, 'image/svg+xml');
|
|
859
|
+
const error = doc.querySelector('parsererror');
|
|
860
|
+
if (error) {
|
|
861
|
+
// The FIRST line only. Chromium's `parsererror` is a whole rendered
|
|
862
|
+
// document — a heading, the message, then the offending source line with a
|
|
863
|
+
// caret under it — and pouring that into a toast makes the one sentence
|
|
864
|
+
// that matters unreadable.
|
|
865
|
+
const [summary = ''] = (error.textContent ?? '')
|
|
866
|
+
.split('\n')
|
|
867
|
+
.map(line => line.trim())
|
|
868
|
+
.filter(line => line.length > 0);
|
|
869
|
+
throw new Error(`This file is not well-formed XML, so no drawing can be read out of it: ${summary.slice(0, 200)}`);
|
|
870
|
+
}
|
|
871
|
+
if (nameOf(doc.documentElement) !== 'svg') {
|
|
872
|
+
throw new Error(`An SVG opens on <svg>; this one opens on <${doc.documentElement?.localName ?? 'nothing'}>.`);
|
|
873
|
+
}
|
|
874
|
+
const clean = DOMPurify.sanitize(source, {
|
|
875
|
+
USE_PROFILES: { svg: true },
|
|
876
|
+
RETURN_DOM: true,
|
|
877
|
+
});
|
|
878
|
+
// …and then say what the sanitizer took, which is NOT the same list as what
|
|
879
|
+
// the walk below skips. `<use>` and `<foreignObject>` never reach the walk at
|
|
880
|
+
// all — they are two of the SVG format's genuine attack surfaces and DOMPurify
|
|
881
|
+
// removes them outright — so a drawing built out of symbol instances arrives
|
|
882
|
+
// empty. Without this the only remark would be "nothing was recognised",
|
|
883
|
+
// which is true and useless. `DOMPurify.removed` is repopulated by each call
|
|
884
|
+
// and is read here immediately, before anything else can sanitize.
|
|
885
|
+
for (const entry of DOMPurify.removed) {
|
|
886
|
+
const removed = entry;
|
|
887
|
+
if (removed.element) {
|
|
888
|
+
// The node's OWN spelling, because `foreignObject` is camel-cased in the
|
|
889
|
+
// format and a remark that called it `foreignobject` would send its
|
|
890
|
+
// reader looking for something the spec does not have. The dedup key is
|
|
891
|
+
// folded; the sentence is not.
|
|
892
|
+
const name = removed.element.nodeName ?? '';
|
|
893
|
+
// The sanitizer parses into an HTML document and reports unwinding its
|
|
894
|
+
// own wrapper as a removal. Nobody wrote a `<body>` into an `.svg`, and a
|
|
895
|
+
// remark about one would be this reader telling the user about its own
|
|
896
|
+
// plumbing.
|
|
897
|
+
if (PARSER_SCAFFOLDING.has(name.toLowerCase()))
|
|
898
|
+
continue;
|
|
899
|
+
notes.once(`removed:${name.toLowerCase()}`, `\`<${name}>\` was removed while sanitizing the file — it is one of the constructs an SVG can carry code in — so nothing it drew was imported.`, name);
|
|
900
|
+
}
|
|
901
|
+
else if (removed.attribute) {
|
|
902
|
+
// Worded for what this actually is, which is broader than "unsafe": the
|
|
903
|
+
// sanitizer's allow-list drops an event handler AND a `requiredFeatures`,
|
|
904
|
+
// and calling the second one dangerous would be this reader accusing a
|
|
905
|
+
// perfectly ordinary file of something.
|
|
906
|
+
notes.once('removed-attribute', 'Attributes outside the safe SVG drawing vocabulary — event handlers, script URLs, and anything else the sanitizer does not know — were removed before the file was read.');
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
// No cast: `RETURN_DOM: true` in the literal selects DOMPurify's typed
|
|
910
|
+
// overload, which answers an `HTMLElement` — the sanitized body wrapper.
|
|
911
|
+
const root = childElements(clean).find(child => nameOf(child) === 'svg');
|
|
912
|
+
if (!root) {
|
|
913
|
+
throw new Error('Nothing survived sanitizing this SVG, so there is no drawing to read.');
|
|
914
|
+
}
|
|
915
|
+
return root;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* An SVG file as a canvas sketch — the shared VISUAL-tier importer.
|
|
919
|
+
*
|
|
920
|
+
* See this module's own documentation for the heuristics statement and the
|
|
921
|
+
* known failure modes (ADR 0012, open question 2). The contract in one
|
|
922
|
+
* sentence: the picture arrives as editable elements, and nothing else is
|
|
923
|
+
* promised.
|
|
924
|
+
*
|
|
925
|
+
* A blank or unrecognisable drawing is `0` elements and a note, NOT an
|
|
926
|
+
* exception: the file was read, it simply held nothing this reader draws, and a
|
|
927
|
+
* throw would show the user an error toast where the truth is a remark.
|
|
928
|
+
* Malformed XML is the exception, because then the file was not read at all.
|
|
929
|
+
*/
|
|
930
|
+
export function parseSvgSketch(source, context = {}) {
|
|
931
|
+
// A sketch has no document-level name to take: what a board is CALLED is the
|
|
932
|
+
// document's business, not any element's. Same answer the BPMN reader gives.
|
|
933
|
+
void context;
|
|
934
|
+
const sketch = { elements: [], notes: new Notebook() };
|
|
935
|
+
const root = parseSvgRoot(source, sketch.notes);
|
|
936
|
+
// The root `<svg>` paints like any other element — a `fill` on it is what
|
|
937
|
+
// every shape under it inherits — and it establishes the outermost viewport.
|
|
938
|
+
walk(root, viewportFrame(root, IDENTITY), paintOf(root, INITIAL_PAINT, sketch.notes), sketch);
|
|
939
|
+
if (sketch.elements.length === 0) {
|
|
940
|
+
sketch.notes.once('empty', 'No shape or text was recognised in this SVG, so nothing was drawn.');
|
|
941
|
+
}
|
|
942
|
+
return {
|
|
943
|
+
elements: sketch.elements,
|
|
944
|
+
report: {
|
|
945
|
+
mapped: sketch.elements.length,
|
|
946
|
+
// Always zero, and it is the tier's whole contract rather than an
|
|
947
|
+
// accident of this file: a visual import carries nothing and quarantines
|
|
948
|
+
// nothing, because it writes no `interchange` payload to carry anything
|
|
949
|
+
// IN (ADR 0012, P2). Pinned by an anti-decay test.
|
|
950
|
+
carried: 0,
|
|
951
|
+
quarantined: 0,
|
|
952
|
+
notes: sketch.notes.notes,
|
|
953
|
+
// …and no `sourceVersion`. An SVG declares a version of the SVG spec, not
|
|
954
|
+
// a version of a vocabulary this reader translates, so claiming one would
|
|
955
|
+
// be a fact about the file dressed up as a fact about the import.
|
|
956
|
+
},
|
|
957
|
+
};
|
|
958
|
+
}
|