@formicoidea/labre-core 0.43.1 → 0.45.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/utils.js +4 -0
- package/dist/_pkgs/affine-block-bookmark/configs/toolbar.js +17 -4
- package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.d.ts +29 -0
- package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.js +81 -0
- package/dist/_pkgs/affine-block-callout/configs/slash-menu.js +6 -4
- package/dist/_pkgs/affine-block-callout/configs/turn-into.d.ts +8 -0
- package/dist/_pkgs/affine-block-callout/configs/turn-into.js +19 -0
- package/dist/_pkgs/affine-block-callout/translations.d.ts +4 -2
- package/dist/_pkgs/affine-block-callout/translations.js +4 -2
- package/dist/_pkgs/affine-block-callout/view.js +3 -0
- package/dist/_pkgs/affine-block-code/code-block-service.d.ts +13 -0
- package/dist/_pkgs/affine-block-code/code-block-service.js +26 -0
- package/dist/_pkgs/affine-block-code/code-block.d.ts +6 -0
- package/dist/_pkgs/affine-block-code/code-block.js +11 -2
- package/dist/_pkgs/affine-block-code/code-toolbar/components/lang-button.js +31 -8
- package/dist/_pkgs/affine-block-edgeless-text/edgeless-toolbar/config.d.ts +11 -0
- package/dist/_pkgs/affine-block-edgeless-text/svg-painter.d.ts +20 -0
- package/dist/_pkgs/affine-block-edgeless-text/svg-painter.js +76 -0
- package/dist/_pkgs/affine-block-edgeless-text/view.js +2 -0
- package/dist/_pkgs/affine-block-embed/configs/toolbar.js +11 -2
- package/dist/_pkgs/affine-block-embed/embed-iframe-block/configs/toolbar.js +11 -2
- package/dist/_pkgs/affine-block-embed-doc/embed-linked-doc-block/embed-edgeless-linked-doc-block.js +3 -1
- package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/configs/toolbar.js +7 -2
- package/dist/_pkgs/affine-block-embed-doc/embed-synced-doc-block/embed-edgeless-synced-doc-block.js +3 -1
- package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +5 -0
- package/dist/_pkgs/affine-block-frame/frame-manager.js +48 -17
- package/dist/_pkgs/affine-block-frame/frame-tool.js +3 -1
- package/dist/_pkgs/affine-block-image/utils.js +4 -1
- package/dist/_pkgs/affine-block-latex/adapters/markdown/preprocessor.d.ts +8 -0
- package/dist/_pkgs/affine-block-latex/adapters/markdown/preprocessor.js +9 -5
- package/dist/_pkgs/affine-block-note/translations.d.ts +0 -1
- package/dist/_pkgs/affine-block-note/translations.js +0 -5
- package/dist/_pkgs/affine-block-root/configs/toolbar.js +17 -1
- package/dist/_pkgs/affine-block-root/edgeless/clipboard/clipboard.js +2 -1
- package/dist/_pkgs/affine-block-root/edgeless/clipboard/command.js +161 -83
- package/dist/_pkgs/affine-block-root/edgeless/clipboard/paste-order.d.ts +21 -0
- package/dist/_pkgs/affine-block-root/edgeless/clipboard/paste-order.js +85 -0
- package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.d.ts +6 -0
- package/dist/_pkgs/affine-block-root/edgeless/edgeless-root-block.js +18 -1
- package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.d.ts +9 -0
- package/dist/_pkgs/affine-block-root/edgeless/utils/clone-utils.js +28 -0
- package/dist/_pkgs/affine-block-root/keyboard/commands.js +9 -6
- package/dist/_pkgs/affine-block-root/preview/edgeless-root-preview-block.js +15 -2
- package/dist/_pkgs/affine-block-surface/adapters/markdown/element-adapter/type.d.ts +1 -1
- package/dist/_pkgs/affine-block-surface/element-model/index.d.ts +1 -1
- package/dist/_pkgs/affine-block-surface/element-model/index.js +1 -1
- package/dist/_pkgs/affine-block-surface/extensions/audit.js +13 -61
- package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/commands.d.ts +2 -0
- package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/commands.js +71 -0
- package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/extensions/canvas-grid/index.js +1 -0
- package/dist/_pkgs/affine-block-surface/extensions/clipboard-config.js +4 -0
- package/dist/_pkgs/affine-block-surface/extensions/crud-extension.js +4 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.d.ts +12 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +27 -7
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +2 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +22 -3
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +6 -3
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +4 -2
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/parts.d.ts +63 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/parts.js +67 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +62 -5
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +98 -18
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +14 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +82 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.d.ts +2 -2
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/toolbar.js +112 -10
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/translations.d.ts +13 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/translations.js +33 -0
- package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/index.js +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/reading-widget.d.ts +13 -6
- package/dist/_pkgs/affine-block-surface/extensions/reading-widget.js +26 -10
- package/dist/_pkgs/affine-block-surface/extensions/reading.d.ts +82 -6
- package/dist/_pkgs/affine-block-surface/extensions/reading.js +99 -21
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.d.ts +80 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.js +248 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.d.ts +82 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.js +342 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.d.ts +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.js +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/tree.d.ts +137 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/tree.js +323 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +112 -4
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +86 -15
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/actions.d.ts +76 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/actions.js +299 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/active-layer.d.ts +20 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/active-layer.js +34 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/commands.d.ts +67 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/commands.js +172 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/creation.d.ts +40 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/creation.js +69 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/index.d.ts +5 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/index.js +5 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/translations.d.ts +10 -0
- package/dist/_pkgs/affine-block-surface/extensions/user-layers/translations.js +14 -0
- package/dist/_pkgs/affine-block-surface/framework-background/facts.d.ts +55 -2
- package/dist/_pkgs/affine-block-surface/framework-background/facts.js +63 -1
- package/dist/_pkgs/affine-block-surface/framework-background/stacking.d.ts +16 -8
- package/dist/_pkgs/affine-block-surface/framework-background/stacking.js +26 -14
- package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +17 -3
- package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.d.ts +3 -1
- package/dist/_pkgs/affine-block-surface/renderer/dom-renderer.js +22 -2
- package/dist/_pkgs/affine-block-surface/renderer/paint-predicate.d.ts +30 -0
- package/dist/_pkgs/affine-block-surface/renderer/paint-predicate.js +29 -0
- package/dist/_pkgs/affine-block-surface/surface-block.js +6 -0
- package/dist/_pkgs/affine-block-surface/surface-model.js +5 -0
- package/dist/_pkgs/affine-block-surface/surface-transformer.js +5 -0
- package/dist/_pkgs/affine-block-surface/tool/default-tool.js +28 -5
- package/dist/_pkgs/affine-block-surface/view.js +23 -1
- package/dist/_pkgs/affine-block-surface-ref/surface-ref-block.js +12 -2
- package/dist/_pkgs/affine-components/context-menu/button.js +14 -0
- package/dist/_pkgs/affine-components/filterable-list/index.js +30 -9
- package/dist/_pkgs/affine-components/icons/index.d.ts +0 -1
- package/dist/_pkgs/affine-components/icons/index.js +0 -1
- package/dist/_pkgs/affine-components/icons/text.d.ts +1 -0
- package/dist/_pkgs/affine-components/icons/text.js +11 -0
- package/dist/_pkgs/affine-fragment-adapter-panel/adapter-panel.d.ts +2 -2
- package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +2 -2
- package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.d.ts +1 -1
- package/dist/_pkgs/affine-fragment-frame-panel/header/frame-panel-header.js +8 -27
- package/dist/_pkgs/affine-fragment-frame-panel/index.d.ts +1 -0
- package/dist/_pkgs/affine-fragment-frame-panel/index.js +1 -0
- package/dist/_pkgs/affine-gfx-connector/element-renderer/connector-dom/index.js +3 -1
- package/dist/_pkgs/affine-gfx-connector/element-renderer/index.js +21 -4
- package/dist/_pkgs/affine-gfx-connector/text/edgeless-connector-label-editor.js +3 -2
- package/dist/_pkgs/affine-gfx-connector/toolbar/config.js +1 -1
- package/dist/_pkgs/affine-gfx-group/command/group-api.js +52 -1
- package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/index.js +21 -3
- package/dist/_pkgs/affine-gfx-shape/text/edgeless-shape-text-editor.js +2 -0
- package/dist/_pkgs/affine-gfx-shape/toolbar/config.js +1 -1
- package/dist/_pkgs/affine-gfx-template/services/template-middlewares.d.ts +9 -0
- package/dist/_pkgs/affine-gfx-template/services/template-middlewares.js +23 -1
- package/dist/_pkgs/affine-gfx-template/services/template.js +2 -1
- package/dist/_pkgs/affine-gfx-text/edgeless-text-editor.js +2 -1
- package/dist/_pkgs/affine-gfx-text/element-renderer/index.js +20 -3
- package/dist/_pkgs/affine-gfx-text/element-renderer/utils.d.ts +67 -1
- package/dist/_pkgs/affine-gfx-text/element-renderer/utils.js +101 -0
- package/dist/_pkgs/affine-gfx-text/toolbar/actions.d.ts +11 -0
- package/dist/_pkgs/affine-gfx-text/toolbar/actions.js +53 -2
- package/dist/_pkgs/affine-gfx-text/toolbar/config.d.ts +11 -0
- package/dist/_pkgs/affine-gfx-text/toolbar/config.js +1 -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 +31 -0
- package/dist/_pkgs/affine-inline-preset/adapters/html/inline-delta.d.ts +4 -0
- package/dist/_pkgs/affine-inline-preset/adapters/html/inline-delta.js +14 -0
- package/dist/_pkgs/affine-inline-preset/command/config.js +21 -3
- package/dist/_pkgs/affine-inline-preset/command/index.d.ts +1 -1
- package/dist/_pkgs/affine-inline-preset/command/index.js +1 -1
- package/dist/_pkgs/affine-inline-preset/command/text-style.d.ts +2 -1
- package/dist/_pkgs/affine-inline-preset/command/text-style.js +1 -0
- package/dist/_pkgs/affine-inline-preset/default-inline-manager.js +2 -1
- package/dist/_pkgs/affine-inline-preset/inline-spec.d.ts +4 -0
- package/dist/_pkgs/affine-inline-preset/inline-spec.js +14 -0
- package/dist/_pkgs/affine-inline-preset/translations.d.ts +2 -2
- package/dist/_pkgs/affine-inline-preset/translations.js +2 -2
- package/dist/_pkgs/affine-model/blocks/attachment/attachment-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/bookmark/bookmark-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/edgeless-text/edgeless-text-model.d.ts +1 -1
- package/dist/_pkgs/affine-model/blocks/edgeless-text/edgeless-text-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/embed/iframe/iframe-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/frame/frame-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/image/image-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/latex/latex-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/note/note-model.js +2 -0
- package/dist/_pkgs/affine-model/consts/text.d.ts +26 -0
- package/dist/_pkgs/affine-model/consts/text.js +25 -0
- package/dist/_pkgs/affine-model/elements/shape/shape.d.ts +6 -1
- package/dist/_pkgs/affine-model/elements/shape/shape.js +14 -1
- package/dist/_pkgs/affine-model/elements/text/text.d.ts +6 -1
- package/dist/_pkgs/affine-model/elements/text/text.js +13 -1
- package/dist/_pkgs/affine-model/utils/helper.js +2 -0
- package/dist/_pkgs/affine-rich-text/conversion.d.ts +25 -0
- package/dist/_pkgs/affine-rich-text/conversion.js +9 -0
- package/dist/_pkgs/affine-rich-text/index.d.ts +1 -1
- package/dist/_pkgs/affine-rich-text/index.js +1 -1
- package/dist/_pkgs/affine-shared/commands/model-crud/replace-selected-text-with-blocks.d.ts +1 -1
- package/dist/_pkgs/affine-shared/services/canvas-grid.d.ts +63 -0
- package/dist/_pkgs/affine-shared/services/canvas-grid.js +109 -0
- package/dist/_pkgs/affine-shared/services/canvas-local-visibility.d.ts +64 -0
- package/dist/_pkgs/affine-shared/services/canvas-local-visibility.js +192 -0
- package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +27 -0
- package/dist/_pkgs/affine-shared/services/edit-props-store.js +34 -0
- package/dist/_pkgs/affine-shared/services/editor-setting-service.d.ts +3 -0
- package/dist/_pkgs/affine-shared/services/editor-setting-service.js +7 -0
- package/dist/_pkgs/affine-shared/services/feature-flag-service.d.ts +4 -0
- package/dist/_pkgs/affine-shared/services/index.d.ts +3 -0
- package/dist/_pkgs/affine-shared/services/index.js +3 -0
- package/dist/_pkgs/affine-shared/services/selection-pane-service.d.ts +44 -0
- package/dist/_pkgs/affine-shared/services/selection-pane-service.js +28 -0
- package/dist/_pkgs/affine-shared/services/telemetry-service/lifecycle.d.ts +69 -0
- package/dist/_pkgs/affine-shared/services/telemetry-service/telemetry-service.d.ts +2 -2
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +5 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +9 -0
- package/dist/_pkgs/affine-shared/styles/index.d.ts +1 -0
- package/dist/_pkgs/affine-shared/styles/index.js +1 -0
- package/dist/_pkgs/affine-shared/styles/panel-header.d.ts +31 -0
- package/dist/_pkgs/affine-shared/styles/panel-header.js +61 -0
- package/dist/_pkgs/affine-shared/styles/text.js +7 -7
- package/dist/_pkgs/affine-shared/types/index.d.ts +6 -0
- package/dist/_pkgs/affine-shared/utils/canvas-export-colors.d.ts +26 -0
- package/dist/_pkgs/affine-shared/utils/canvas-export-colors.js +127 -0
- package/dist/_pkgs/affine-shared/utils/file/filesys.d.ts +8 -11
- package/dist/_pkgs/affine-shared/utils/file/filesys.js +8 -11
- package/dist/_pkgs/affine-shared/utils/index.d.ts +2 -0
- package/dist/_pkgs/affine-shared/utils/index.js +2 -0
- package/dist/_pkgs/affine-shared/utils/label-mode.d.ts +47 -0
- package/dist/_pkgs/affine-shared/utils/label-mode.js +55 -0
- package/dist/_pkgs/affine-shared/utils/model/merge-to-code-model.js +7 -1
- package/dist/_pkgs/affine-shared/utils/model/transform-model.js +5 -0
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/utils.js +10 -3
- package/dist/_pkgs/affine-widget-edgeless-toolbar/catalogue/artefact-catalogue-widget.js +25 -49
- package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.d.ts +4 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/effects.js +4 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/index.d.ts +4 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/index.js +4 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.d.ts +61 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.js +91 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/labels.d.ts +17 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/labels.js +95 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-default.d.ts +10 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-default.js +31 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-tool.d.ts +26 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-tool.js +82 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.d.ts +170 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.js +1381 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.d.ts +52 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/translations.js +161 -1
- package/dist/_pkgs/affine-widget-edgeless-toolbar/view.js +10 -0
- package/dist/_pkgs/affine-widget-note-slicer/note-slicer.js +7 -3
- package/dist/_pkgs/std/gfx/controller.d.ts +13 -0
- package/dist/_pkgs/std/gfx/controller.js +22 -2
- package/dist/_pkgs/std/gfx/grid.d.ts +31 -2
- package/dist/_pkgs/std/gfx/index.d.ts +3 -1
- package/dist/_pkgs/std/gfx/index.js +3 -1
- package/dist/_pkgs/std/gfx/interactivity/manager.js +7 -0
- package/dist/_pkgs/std/gfx/layer.js +73 -5
- package/dist/_pkgs/std/gfx/local-visibility.d.ts +88 -0
- package/dist/_pkgs/std/gfx/local-visibility.js +217 -0
- package/dist/_pkgs/std/gfx/model/gfx-block-model.d.ts +13 -0
- package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +34 -0
- package/dist/_pkgs/std/gfx/model/surface/element-model.js +65 -1
- package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +27 -0
- package/dist/_pkgs/std/gfx/model/surface/surface-model.js +43 -0
- package/dist/_pkgs/std/gfx/model/surface/user-layers.d.ts +68 -0
- package/dist/_pkgs/std/gfx/model/surface/user-layers.js +127 -0
- package/dist/_pkgs/std/utils/layer.d.ts +10 -0
- package/dist/_pkgs/std/utils/layer.js +64 -13
- package/dist/_pkgs/std/view/element/gfx-block-component.js +10 -2
- package/dist/commands.js +4 -1
- package/dist/translations.js +10 -6
- package/package.json +9 -2
- package/dist/_pkgs/affine-components/icons/file-icons-rc.d.ts +0 -1
- package/dist/_pkgs/affine-components/icons/file-icons-rc.js +0 -130
- package/dist/_pkgs/affine-shared/test-utils/affine-template.d.ts +0 -6
- package/dist/_pkgs/affine-shared/test-utils/affine-template.js +0 -258
- package/dist/_pkgs/affine-shared/test-utils/affine-test-utils.d.ts +0 -8
- package/dist/_pkgs/affine-shared/test-utils/affine-test-utils.js +0 -81
- package/dist/_pkgs/affine-shared/test-utils/create-test-host.d.ts +0 -23
- package/dist/_pkgs/affine-shared/test-utils/create-test-host.js +0 -187
- package/dist/_pkgs/affine-shared/test-utils/index.d.ts +0 -3
- package/dist/_pkgs/affine-shared/test-utils/index.js +0 -3
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { CanvasLocalVisibility } from '../../../affine-shared/services/index.js';
|
|
2
|
+
import { LifeCycleWatcher } from '../../../std/index.js';
|
|
3
|
+
import { GfxBlockElementModel, GfxControllerIdentifier, GfxGroupLikeElementModel, GfxPrimitiveElementModel, DEFAULT_LAYER_ID, isStoredHiddenForEveryone, } from '../../../std/gfx/index.js';
|
|
4
|
+
import { computed, effect, signal, } from '@preact/signals-core';
|
|
5
|
+
import { userLayersBottomUp } from '../user-layers/actions.js';
|
|
6
|
+
/** The default layer's reserved id (ADR 0031 §2), re-exported from std. */
|
|
7
|
+
export { DEFAULT_LAYER_ID };
|
|
8
|
+
const NOTHING_HIDDEN = new Set();
|
|
9
|
+
/**
|
|
10
|
+
* The layers of a surface with no `layers` record: the default layer alone,
|
|
11
|
+
* shown but not written (ADR 0031 §2 and amendments). Every model is in it,
|
|
12
|
+
* whatever its own key says — with no record, every id is dangling.
|
|
13
|
+
*/
|
|
14
|
+
function unrecordedDefaultLayer(hiddenLocally) {
|
|
15
|
+
return {
|
|
16
|
+
order: [DEFAULT_LAYER_ID],
|
|
17
|
+
ranks: new Map(),
|
|
18
|
+
effectiveLayerOf: () => DEFAULT_LAYER_ID,
|
|
19
|
+
hiddenLocally,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The group-like ELEMENT a model is listed under, or `null` for a top-level
|
|
24
|
+
* row.
|
|
25
|
+
*
|
|
26
|
+
* Frames are deliberately not containers here, although they are
|
|
27
|
+
* group-compatible for z-order: a frame is a slide, and the pane filters BY
|
|
28
|
+
* frame rather than nesting under one — exactly the line ADR 0031 §4 draws for
|
|
29
|
+
* layers. `group` walks the model's surface, which throws on a model that is
|
|
30
|
+
* not attached to one; such a model is simply a top-level row.
|
|
31
|
+
*/
|
|
32
|
+
export function paneContainerOf(model) {
|
|
33
|
+
return containerOf(rawGroupOf(model));
|
|
34
|
+
}
|
|
35
|
+
/** The rule {@link paneContainerOf} applies, to a `group` already read. */
|
|
36
|
+
function containerOf(group) {
|
|
37
|
+
return group instanceof GfxGroupLikeElementModel ? group : null;
|
|
38
|
+
}
|
|
39
|
+
/** `model.groups`, nearest first, or none where the getter throws. */
|
|
40
|
+
function ancestorsOf(model) {
|
|
41
|
+
try {
|
|
42
|
+
return model.groups;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** `model.group`, or `null` on a model no surface holds (the getter throws). */
|
|
49
|
+
function rawGroupOf(model) {
|
|
50
|
+
try {
|
|
51
|
+
return model.group;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The pane's rows, built from the canvas' models: one pass to bucket every
|
|
59
|
+
* model under its container, one sort per sibling list, top first.
|
|
60
|
+
*
|
|
61
|
+
* Pure, so the budget test can time exactly what a live pane pays. The order
|
|
62
|
+
* is the canvas' own comparator (`compareLayer`) reversed — the paint order,
|
|
63
|
+
* never a second opinion of it — with one shortcut that is exact: two models
|
|
64
|
+
* under the same group-like ancestor are ordered by `compareLayer` on their
|
|
65
|
+
* `index` alone (its ancestor walk finds no difference and falls through to
|
|
66
|
+
* `compareIndex`). So that case reads two cached strings instead of walking
|
|
67
|
+
* two ancestor chains per comparison, and only models stacked under different
|
|
68
|
+
* ancestors (a frame's members beside loose elements) walk their chains, read
|
|
69
|
+
* once per model rather than once per comparison.
|
|
70
|
+
*
|
|
71
|
+
* The top-level rows are the layers; with no `layers` given, the default
|
|
72
|
+
* layer alone, unrecorded — what a canvas without layers shows.
|
|
73
|
+
*/
|
|
74
|
+
export function buildSelectionPaneTree(models, hiddenLocally = NOTHING_HIDDEN, layers = unrecordedDefaultLayer()) {
|
|
75
|
+
// A frame is an ordinary row (ADR 0031, amendments), listed where it
|
|
76
|
+
// paints: a block with no container, so its members — which paint right
|
|
77
|
+
// above it — are its siblings right above it, never its children.
|
|
78
|
+
const present = new Set();
|
|
79
|
+
const groupOf = new Map();
|
|
80
|
+
const indexOf = new Map();
|
|
81
|
+
for (const model of models) {
|
|
82
|
+
present.add(model.id);
|
|
83
|
+
groupOf.set(model, rawGroupOf(model));
|
|
84
|
+
indexOf.set(model, model.index);
|
|
85
|
+
}
|
|
86
|
+
const layerOf = (model) => layers.effectiveLayerOf(model);
|
|
87
|
+
// `compareLayer`'s ancestor rule, on ancestor chains read ONCE per model:
|
|
88
|
+
// `groups` walks the surface on every read, and a frame's members — rows
|
|
89
|
+
// beside loose elements since frames are rows — compared through
|
|
90
|
+
// `compareLayer` read it on every comparison, which blew the frame budget.
|
|
91
|
+
// A chain is the model's ancestors, outermost first, then the model; the
|
|
92
|
+
// first link two chains do not share decides by `index`, and a chain that
|
|
93
|
+
// is a prefix of the other is its ancestor, stacked below it. Held to
|
|
94
|
+
// `compareLayer` by the parity case in `selection-pane.unit.spec.ts`.
|
|
95
|
+
const chainOf = new Map();
|
|
96
|
+
const chain = (model) => {
|
|
97
|
+
let found = chainOf.get(model);
|
|
98
|
+
if (!found) {
|
|
99
|
+
found = [...ancestorsOf(model)].reverse().concat(model);
|
|
100
|
+
chainOf.set(model, found);
|
|
101
|
+
}
|
|
102
|
+
return found;
|
|
103
|
+
};
|
|
104
|
+
const byAncestors = (a, b) => {
|
|
105
|
+
const ac = chain(a);
|
|
106
|
+
const bc = chain(b);
|
|
107
|
+
let i = 0;
|
|
108
|
+
while (i < ac.length && i < bc.length && ac[i] === bc[i])
|
|
109
|
+
i++;
|
|
110
|
+
if (i === ac.length && i === bc.length)
|
|
111
|
+
return 0;
|
|
112
|
+
if (i === ac.length)
|
|
113
|
+
return -1;
|
|
114
|
+
if (i === bc.length)
|
|
115
|
+
return 1;
|
|
116
|
+
const ai = ac[i].index;
|
|
117
|
+
const bi = bc[i].index;
|
|
118
|
+
return ai === bi ? 0 : ai < bi ? -1 : 1;
|
|
119
|
+
};
|
|
120
|
+
const paintOrder = (a, b) => {
|
|
121
|
+
// Rank first, as `compare` does, so the index shortcut below only ever
|
|
122
|
+
// orders two models of the same layer.
|
|
123
|
+
const al = layerOf(a);
|
|
124
|
+
const bl = layerOf(b);
|
|
125
|
+
if (al !== bl) {
|
|
126
|
+
const ar = layers.ranks.get(al) ?? '';
|
|
127
|
+
const br = layers.ranks.get(bl) ?? '';
|
|
128
|
+
if (ar !== br)
|
|
129
|
+
return ar < br ? -1 : 1;
|
|
130
|
+
}
|
|
131
|
+
if (groupOf.get(a) !== groupOf.get(b))
|
|
132
|
+
return byAncestors(a, b);
|
|
133
|
+
const ai = indexOf.get(a);
|
|
134
|
+
const bi = indexOf.get(b);
|
|
135
|
+
return ai === bi ? 0 : ai < bi ? -1 : 1;
|
|
136
|
+
};
|
|
137
|
+
const buckets = new Map();
|
|
138
|
+
for (const model of models) {
|
|
139
|
+
// The `group` read once above: `paneContainerOf` would read it again.
|
|
140
|
+
const container = containerOf(groupOf.get(model));
|
|
141
|
+
// A container that is not listed (a stale group id) cannot hold a row:
|
|
142
|
+
// the member is listed at the top level rather than vanishing.
|
|
143
|
+
const key = container && present.has(container.id) ? container.id : null;
|
|
144
|
+
let bucket = buckets.get(key);
|
|
145
|
+
if (!bucket) {
|
|
146
|
+
bucket = [];
|
|
147
|
+
buckets.set(key, bucket);
|
|
148
|
+
}
|
|
149
|
+
bucket.push(model);
|
|
150
|
+
}
|
|
151
|
+
const build = (key) => {
|
|
152
|
+
const bucket = buckets.get(key);
|
|
153
|
+
if (!bucket)
|
|
154
|
+
return [];
|
|
155
|
+
bucket.sort((a, b) => paintOrder(b, a));
|
|
156
|
+
return bucket.map(model => {
|
|
157
|
+
const block = model instanceof GfxBlockElementModel;
|
|
158
|
+
const role = model instanceof GfxPrimitiveElementModel ? model.role : undefined;
|
|
159
|
+
const node = {
|
|
160
|
+
id: model.id,
|
|
161
|
+
kind: block ? 'block' : 'element',
|
|
162
|
+
type: block ? model.flavour : model.type,
|
|
163
|
+
layerId: layerOf(model),
|
|
164
|
+
locked: model.lockedBySelf === true,
|
|
165
|
+
hiddenLocal: hiddenLocally.has(model.id),
|
|
166
|
+
hiddenForEveryone: isStoredHiddenForEveryone(model),
|
|
167
|
+
};
|
|
168
|
+
if (role !== undefined)
|
|
169
|
+
node.role = role;
|
|
170
|
+
if (key !== null)
|
|
171
|
+
node.groupId = key;
|
|
172
|
+
if (model instanceof GfxGroupLikeElementModel) {
|
|
173
|
+
node.children = build(model.id);
|
|
174
|
+
}
|
|
175
|
+
return node;
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
const top = build(null);
|
|
179
|
+
// The top-level rows are the layers, top first, each holding its members
|
|
180
|
+
// in paint order. An empty layer is still a row — it is where a drop lands.
|
|
181
|
+
return layers.order.map(id => ({
|
|
182
|
+
id,
|
|
183
|
+
kind: 'layer',
|
|
184
|
+
type: 'layer',
|
|
185
|
+
layerId: id,
|
|
186
|
+
locked: false,
|
|
187
|
+
hiddenLocal: layers.hiddenLocally?.has(id) ?? false,
|
|
188
|
+
hiddenForEveryone: layers.hiddenForEveryone?.has(id) ?? false,
|
|
189
|
+
children: top.filter(node => node.layerId === id),
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* The element props whose change can move, nest, lock or re-role a row. A
|
|
194
|
+
* drag writes `xywh` every frame and must not rebuild the tree every frame.
|
|
195
|
+
*/
|
|
196
|
+
const TREE_KEYS = new Set([
|
|
197
|
+
'index',
|
|
198
|
+
'layer',
|
|
199
|
+
'lockedBySelf',
|
|
200
|
+
'children',
|
|
201
|
+
'childIds',
|
|
202
|
+
'role',
|
|
203
|
+
]);
|
|
204
|
+
/**
|
|
205
|
+
* The surface's user layers as the tree builder takes them; while there is no
|
|
206
|
+
* record, the default layer alone, unrecorded (nothing is written to show it).
|
|
207
|
+
* Reads `layers$`, so a `computed` calling it re-derives on a create, a
|
|
208
|
+
* rename, a reorder — local or a peer's.
|
|
209
|
+
*/
|
|
210
|
+
export function paneLayersOf(surface, hiddenLocally) {
|
|
211
|
+
surface.props.layers$?.value;
|
|
212
|
+
const ranks = surface.userLayers?.ranks;
|
|
213
|
+
if (!ranks)
|
|
214
|
+
return unrecordedDefaultLayer(hiddenLocally);
|
|
215
|
+
const bottomUp = userLayersBottomUp(surface);
|
|
216
|
+
return {
|
|
217
|
+
order: bottomUp.map(layer => layer.id).reverse(),
|
|
218
|
+
ranks,
|
|
219
|
+
effectiveLayerOf: model => surface.userLayers.effectiveLayerOf(model),
|
|
220
|
+
hiddenLocally,
|
|
221
|
+
hiddenForEveryone: new Set(bottomUp
|
|
222
|
+
.filter(layer => layer.record.hidden === true)
|
|
223
|
+
.map(layer => layer.id)),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* The live tree behind {@link selectionPaneTree}, one per editor.
|
|
228
|
+
*
|
|
229
|
+
* The tree is a `computed` over a revision counter, bumped by the few events
|
|
230
|
+
* that can change a row (an element or block added or removed, a reorder, a
|
|
231
|
+
* regroup, a lock) — never by geometry. A `computed` is lazy, so an editor
|
|
232
|
+
* whose pane is closed and whose host never reads the tree pays the counter
|
|
233
|
+
* bump and nothing else; an open pane pays one rebuild per relevant change,
|
|
234
|
+
* not one per frame.
|
|
235
|
+
*
|
|
236
|
+
* It also holds whether the LIBRARY's own panel is open (`open$`), which is
|
|
237
|
+
* what the toggle command reads. A host that replaced the panel through
|
|
238
|
+
* `SelectionPaneExtension` owns its own open state; `open$` then stays false
|
|
239
|
+
* and the toggle always opens.
|
|
240
|
+
*/
|
|
241
|
+
export class SelectionPaneModel extends LifeCycleWatcher {
|
|
242
|
+
constructor() {
|
|
243
|
+
super(...arguments);
|
|
244
|
+
this._revision$ = signal(0);
|
|
245
|
+
this._disposeSurfaceEffect = null;
|
|
246
|
+
this._subscriptions = [];
|
|
247
|
+
/** Whether the library's own panel is on screen. Written by that panel. */
|
|
248
|
+
this.open$ = signal(false);
|
|
249
|
+
this.tree$ = computed(() => {
|
|
250
|
+
this._revision$.value;
|
|
251
|
+
const gfx = this.std.get(GfxControllerIdentifier);
|
|
252
|
+
const surface = gfx.surface$.value;
|
|
253
|
+
if (!surface)
|
|
254
|
+
return [];
|
|
255
|
+
// Read here, so a local hide or show re-derives the rows' marks.
|
|
256
|
+
const local = this.std.getOptional(CanvasLocalVisibility);
|
|
257
|
+
const hidden = local?.hiddenIds$.value;
|
|
258
|
+
const hiddenLayers = local?.hiddenLayerIds$.value;
|
|
259
|
+
// And here, so a hide for everyone (local or a peer's) re-derives them too.
|
|
260
|
+
gfx.hiddenForEveryone?.ids$.value;
|
|
261
|
+
return buildSelectionPaneTree(gfx.gfxElements, hidden, paneLayersOf(surface, hiddenLayers));
|
|
262
|
+
});
|
|
263
|
+
this._surfaceSubscriptions = [];
|
|
264
|
+
}
|
|
265
|
+
static { this.key = 'selection-pane-model'; }
|
|
266
|
+
/** Force a rebuild; for a change no subscribed event reports. */
|
|
267
|
+
invalidate() {
|
|
268
|
+
// `peek`, not `value`: called from inside an effect, a READ would
|
|
269
|
+
// subscribe that effect to the counter it is about to bump.
|
|
270
|
+
this._revision$.value = this._revision$.peek() + 1;
|
|
271
|
+
}
|
|
272
|
+
mounted() {
|
|
273
|
+
super.mounted();
|
|
274
|
+
const gfx = this.std.get(GfxControllerIdentifier);
|
|
275
|
+
const store = this.std.store;
|
|
276
|
+
this._subscriptions.push(gfx.layer.slots.layerUpdated.subscribe(() => this.invalidate()), store.slots.blockUpdated.subscribe(payload => {
|
|
277
|
+
if (payload.type !== 'update' || TREE_KEYS.has(payload.props.key)) {
|
|
278
|
+
this.invalidate();
|
|
279
|
+
}
|
|
280
|
+
}));
|
|
281
|
+
// The surface is a signal: it may arrive after mount, or be replaced.
|
|
282
|
+
this._disposeSurfaceEffect = effect(() => {
|
|
283
|
+
const surface = gfx.surface$.value;
|
|
284
|
+
this._watchSurface(surface);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
_watchSurface(surface) {
|
|
288
|
+
this._surfaceSubscriptions.forEach(sub => sub.unsubscribe());
|
|
289
|
+
this._surfaceSubscriptions = [];
|
|
290
|
+
if (!surface)
|
|
291
|
+
return;
|
|
292
|
+
this._surfaceSubscriptions.push(surface.elementAdded.subscribe(() => this.invalidate()), surface.elementRemoved.subscribe(() => this.invalidate()), surface.elementUpdated.subscribe(({ props }) => {
|
|
293
|
+
for (const key of Object.keys(props)) {
|
|
294
|
+
if (TREE_KEYS.has(key)) {
|
|
295
|
+
this.invalidate();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}));
|
|
300
|
+
this.invalidate();
|
|
301
|
+
}
|
|
302
|
+
unmounted() {
|
|
303
|
+
this._disposeSurfaceEffect?.();
|
|
304
|
+
this._disposeSurfaceEffect = null;
|
|
305
|
+
this._watchSurface(null);
|
|
306
|
+
this._subscriptions.forEach(sub => sub.unsubscribe());
|
|
307
|
+
this._subscriptions = [];
|
|
308
|
+
this.open$.value = false;
|
|
309
|
+
super.unmounted();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* The headless data API of the selection pane (ADR 0031 §12): a signal of
|
|
314
|
+
* rows, z-order, top first, ids only.
|
|
315
|
+
*
|
|
316
|
+
* What a host's own pane renders from, and what the library's panel renders
|
|
317
|
+
* from — one tree, so the two cannot disagree about the order of a canvas.
|
|
318
|
+
* Edgeless editors only: the model is registered by the surface's edgeless
|
|
319
|
+
* view extension.
|
|
320
|
+
*/
|
|
321
|
+
export function selectionPaneTree(std) {
|
|
322
|
+
return std.get(SelectionPaneModel).tree$;
|
|
323
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { TranslationParams } from '../../affine-shared/services/index.js';
|
|
2
|
+
import { type InterchangeImportContext, type InterchangeImportResult, type InterchangeNote, type SerializedElementProps } from './interchange.js';
|
|
2
3
|
/**
|
|
3
4
|
* **SVG → a canvas sketch.** The platform's VISUAL-tier importer, shared by
|
|
4
5
|
* every framework that declares it (`docs/adr/0012`, P2).
|
|
@@ -9,9 +10,11 @@ import { type InterchangeImportContext, type InterchangeImportResult } from './i
|
|
|
9
10
|
* a one-paragraph statement of its heuristics and its known failure modes" —
|
|
10
11
|
* answered ONCE, here, because every framework that declares `…:svg:import`
|
|
11
12
|
* wraps this one function and therefore owes the same statement. It is
|
|
12
|
-
* referenced by `bpmn:svg:import
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* referenced by `bpmn:svg:import`; a framework that ever wants a narrower or
|
|
14
|
+
* wider guess writes its own parser and its own paragraph beside it. Wardley
|
|
15
|
+
* did (ADR 0032): a framework may CLAIM nodes before the walk below
|
|
16
|
+
* ({@link sanitizeSvg}, {@link sketchSvgTree}), and then owes its own statement
|
|
17
|
+
* for what it claims — this one still covers everything it leaves here._
|
|
15
18
|
*
|
|
16
19
|
* **What it guesses.** An SVG carries a rendering, not a model, so this reader
|
|
17
20
|
* recognises GEOMETRY and nothing else: `<rect>` becomes a rectangle,
|
|
@@ -91,6 +94,110 @@ import { type InterchangeImportContext, type InterchangeImportResult } from './i
|
|
|
91
94
|
export declare const SVG_SKETCH_FORMAT_ID = "svg";
|
|
92
95
|
export declare const SVG_SKETCH_EXTENSION = ".svg";
|
|
93
96
|
export declare const SVG_SKETCH_MIME = "image/svg+xml";
|
|
97
|
+
/**
|
|
98
|
+
* The note channel, deduplicated on a key.
|
|
99
|
+
*
|
|
100
|
+
* D1's discipline, carried across to a tier that has no D1: nothing is dropped
|
|
101
|
+
* silently. What changes is the GRANULARITY — a file with four hundred
|
|
102
|
+
* `<use>` instances is one fact about the file, not four hundred, and a report
|
|
103
|
+
* nobody reads to the end is a report that was not written.
|
|
104
|
+
*
|
|
105
|
+
* Every note is a `warning`. The other four kinds would be lies here:
|
|
106
|
+
* `carried` and `quarantined` describe a payload this tier does not write, and
|
|
107
|
+
* `substituted-id` and `invented-layout` describe promises it does not make.
|
|
108
|
+
*
|
|
109
|
+
* Exported so a framework that claims part of a picture first (ADR 0032 §2)
|
|
110
|
+
* hands the SAME notebook to {@link sanitizeSvg} and {@link sketchSvgTree}: one
|
|
111
|
+
* file, one de-duplication, one list of remarks.
|
|
112
|
+
*/
|
|
113
|
+
export declare class SvgSketchNotebook {
|
|
114
|
+
private readonly seen;
|
|
115
|
+
readonly notes: InterchangeNote[];
|
|
116
|
+
/**
|
|
117
|
+
* @param dedupKey De-duplication identity — a note fires once per distinct
|
|
118
|
+
* value (`font-unit:px`, `font-unit:pt`…), independent of the i18n key
|
|
119
|
+
* below, which stays the same across all of them.
|
|
120
|
+
* @param message The English sentence, already filled in with the file's
|
|
121
|
+
* own words — shown as is with no host catalogue registered.
|
|
122
|
+
* @param wording The key/fallback pair for this sentence's SHAPE
|
|
123
|
+
* (`svg-sketch-translations.ts`), and the params that fill its
|
|
124
|
+
* `{{name}}` holes when it has any.
|
|
125
|
+
*/
|
|
126
|
+
once(dedupKey: string, message: string, wording: readonly [key: string, fallback: string], params?: TranslationParams, element?: string): void;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* How a user-space coordinate at this depth becomes a canvas coordinate:
|
|
130
|
+
* `canvas = user * s + o`.
|
|
131
|
+
*
|
|
132
|
+
* Carrying the SCALE rather than only the offset is what makes a `viewBox`
|
|
133
|
+
* honest. `width="200" viewBox="0 0 1000 1000"` is a drawing authored at 1000
|
|
134
|
+
* units and displayed at 200; reading its coordinates 1:1 imports it five times
|
|
135
|
+
* too big, and every stroke width and font size with it. The factor is uniform
|
|
136
|
+
* — `min(width / viewBox width, height / viewBox height)` — because that is
|
|
137
|
+
* what the default `preserveAspectRatio` (`xMidYMid meet`) means, and a
|
|
138
|
+
* non-uniform read would need a shape model with independent axes.
|
|
139
|
+
*
|
|
140
|
+
* Exported as {@link SvgSketchFrame}: a recogniser reads a node's coordinates
|
|
141
|
+
* through {@link svgFrameOf} so it lands them exactly where this walk would
|
|
142
|
+
* have, and places what it leaves to the walk with the `place` option of
|
|
143
|
+
* {@link sketchSvgTree}.
|
|
144
|
+
*/
|
|
145
|
+
interface Frame {
|
|
146
|
+
ox: number;
|
|
147
|
+
oy: number;
|
|
148
|
+
s: number;
|
|
149
|
+
}
|
|
150
|
+
export type SvgSketchFrame = Frame;
|
|
151
|
+
/**
|
|
152
|
+
* The second pass: a sanitised tree as sketch props, minus what a caller
|
|
153
|
+
* claimed.
|
|
154
|
+
*
|
|
155
|
+
* `skip` is the set of nodes a framework's recogniser already turned into its
|
|
156
|
+
* own artefacts; each one is left alone WITH its subtree, and everything else
|
|
157
|
+
* is read exactly as {@link parseSvgSketch} reads it. `place` composes a frame
|
|
158
|
+
* OUTSIDE the file's own viewport — `canvas = place.s · file + place.o` — so
|
|
159
|
+
* the remainder can land beside a board the recogniser laid out at another
|
|
160
|
+
* scale. Both default to nothing, which is {@link parseSvgSketch} itself.
|
|
161
|
+
*
|
|
162
|
+
* A framework that claims nodes owes its own heuristics statement for what it
|
|
163
|
+
* claims; this module's statement covers only what reaches this walk.
|
|
164
|
+
*/
|
|
165
|
+
export declare function sketchSvgTree(root: Element, notes: SvgSketchNotebook, options?: {
|
|
166
|
+
skip?: ReadonlySet<Element>;
|
|
167
|
+
place?: SvgSketchFrame;
|
|
168
|
+
}): SerializedElementProps[];
|
|
169
|
+
/**
|
|
170
|
+
* The frame a node's OWN attributes are read in — its `cx`, its `x1`, its
|
|
171
|
+
* `points` — composed exactly the way the walk composes it: the root's
|
|
172
|
+
* viewport, then every ancestor's translate and nested viewport, then the
|
|
173
|
+
* node's own `transform`. So a recogniser that reads a circle's centre through
|
|
174
|
+
* this lands it on the very point the sketch would have drawn it.
|
|
175
|
+
*
|
|
176
|
+
* The transforms the walk ignores are ignored here too, silently: the walk
|
|
177
|
+
* already says so once per kind when it meets them.
|
|
178
|
+
*/
|
|
179
|
+
export declare function svgFrameOf(element: Element): SvgSketchFrame;
|
|
180
|
+
/**
|
|
181
|
+
* The document, sanitized, or an exception naming what is wrong with it.
|
|
182
|
+
*
|
|
183
|
+
* Well-formedness FIRST, because `DOMParser` reports a malformed document as a
|
|
184
|
+
* `parsererror` element rather than by throwing — a verdict in the shape of a
|
|
185
|
+
* document — and because DOMPurify's parser is the forgiving HTML one, which
|
|
186
|
+
* would quietly repair the very thing the caller needs to be told about. So:
|
|
187
|
+
* parse for the verdict, reading nothing out of the result but that; sanitize
|
|
188
|
+
* the SOURCE; and walk only what came back from the sanitizer.
|
|
189
|
+
*
|
|
190
|
+
* The sanitizer is not optional and it is not defensive programming. An `.svg`
|
|
191
|
+
* is an executable document — `<script>`, `<foreignObject>` with markup, event
|
|
192
|
+
* handler attributes — handed over by whoever sent the file. The same
|
|
193
|
+
* `USE_PROFILES: { svg: true }` guard is what the edgeless clipboard already
|
|
194
|
+
* puts in front of a pasted SVG.
|
|
195
|
+
*
|
|
196
|
+
* The first of the two passes {@link parseSvgSketch} is made of, exported so a
|
|
197
|
+
* framework that recognises part of a picture reads the SAME sanitised tree
|
|
198
|
+
* the sketch walks (ADR 0032 §2, §7) — never the source.
|
|
199
|
+
*/
|
|
200
|
+
export declare function sanitizeSvg(source: string, notes: SvgSketchNotebook): Element;
|
|
94
201
|
/**
|
|
95
202
|
* An SVG file as a canvas sketch — the shared VISUAL-tier importer.
|
|
96
203
|
*
|
|
@@ -105,3 +212,4 @@ export declare const SVG_SKETCH_MIME = "image/svg+xml";
|
|
|
105
212
|
* Malformed XML is the exception, because then the file was not read at all.
|
|
106
213
|
*/
|
|
107
214
|
export declare function parseSvgSketch(source: string, context?: InterchangeImportContext): InterchangeImportResult;
|
|
215
|
+
export {};
|
|
@@ -12,9 +12,11 @@ import { SVG_SKETCH_CURRENT_COLOR, SVG_SKETCH_CURVE, SVG_SKETCH_EMPTY, SVG_SKETC
|
|
|
12
12
|
* a one-paragraph statement of its heuristics and its known failure modes" —
|
|
13
13
|
* answered ONCE, here, because every framework that declares `…:svg:import`
|
|
14
14
|
* wraps this one function and therefore owes the same statement. It is
|
|
15
|
-
* referenced by `bpmn:svg:import
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* referenced by `bpmn:svg:import`; a framework that ever wants a narrower or
|
|
16
|
+
* wider guess writes its own parser and its own paragraph beside it. Wardley
|
|
17
|
+
* did (ADR 0032): a framework may CLAIM nodes before the walk below
|
|
18
|
+
* ({@link sanitizeSvg}, {@link sketchSvgTree}), and then owes its own statement
|
|
19
|
+
* for what it claims — this one still covers everything it leaves here._
|
|
18
20
|
*
|
|
19
21
|
* **What it guesses.** An SVG carries a rendering, not a model, so this reader
|
|
20
22
|
* recognises GEOMETRY and nothing else: `<rect>` becomes a rectangle,
|
|
@@ -165,8 +167,12 @@ function numbers(raw) {
|
|
|
165
167
|
* Every note is a `warning`. The other four kinds would be lies here:
|
|
166
168
|
* `carried` and `quarantined` describe a payload this tier does not write, and
|
|
167
169
|
* `substituted-id` and `invented-layout` describe promises it does not make.
|
|
170
|
+
*
|
|
171
|
+
* Exported so a framework that claims part of a picture first (ADR 0032 §2)
|
|
172
|
+
* hands the SAME notebook to {@link sanitizeSvg} and {@link sketchSvgTree}: one
|
|
173
|
+
* file, one de-duplication, one list of remarks.
|
|
168
174
|
*/
|
|
169
|
-
class
|
|
175
|
+
export class SvgSketchNotebook {
|
|
170
176
|
constructor() {
|
|
171
177
|
this.seen = new Set();
|
|
172
178
|
this.notes = [];
|
|
@@ -774,6 +780,8 @@ function walk(parent, frame, inherited, sketch) {
|
|
|
774
780
|
}
|
|
775
781
|
/** One element and whatever it contains, placed in its parent's frame. */
|
|
776
782
|
function visit(element, frame, inherited, sketch) {
|
|
783
|
+
if (sketch.skip.has(element))
|
|
784
|
+
return;
|
|
777
785
|
const name = nameOf(element);
|
|
778
786
|
if (NON_RENDERING.has(name))
|
|
779
787
|
return;
|
|
@@ -851,6 +859,68 @@ function emit(element, name, frame, paint, sketch) {
|
|
|
851
859
|
sketch.notes.once(`skipped:${name}`, `\`<${name}>\` is not recognised and was skipped.`, SVG_SKETCH_SKIPPED, { name }, name);
|
|
852
860
|
}
|
|
853
861
|
}
|
|
862
|
+
/* ── The two passes, opened to a recogniser (ADR 0032 §2) ────────────── */
|
|
863
|
+
/**
|
|
864
|
+
* The second pass: a sanitised tree as sketch props, minus what a caller
|
|
865
|
+
* claimed.
|
|
866
|
+
*
|
|
867
|
+
* `skip` is the set of nodes a framework's recogniser already turned into its
|
|
868
|
+
* own artefacts; each one is left alone WITH its subtree, and everything else
|
|
869
|
+
* is read exactly as {@link parseSvgSketch} reads it. `place` composes a frame
|
|
870
|
+
* OUTSIDE the file's own viewport — `canvas = place.s · file + place.o` — so
|
|
871
|
+
* the remainder can land beside a board the recogniser laid out at another
|
|
872
|
+
* scale. Both default to nothing, which is {@link parseSvgSketch} itself.
|
|
873
|
+
*
|
|
874
|
+
* A framework that claims nodes owes its own heuristics statement for what it
|
|
875
|
+
* claims; this module's statement covers only what reaches this walk.
|
|
876
|
+
*/
|
|
877
|
+
export function sketchSvgTree(root, notes, options = {}) {
|
|
878
|
+
const sketch = {
|
|
879
|
+
elements: [],
|
|
880
|
+
notes,
|
|
881
|
+
skip: options.skip ?? new Set(),
|
|
882
|
+
};
|
|
883
|
+
const place = options.place ?? IDENTITY;
|
|
884
|
+
const own = viewportFrame(root, IDENTITY);
|
|
885
|
+
// The root `<svg>` paints like any other element — a `fill` on it is what
|
|
886
|
+
// every shape under it inherits — and it establishes the outermost viewport.
|
|
887
|
+
walk(root, {
|
|
888
|
+
ox: own.ox * place.s + place.ox,
|
|
889
|
+
oy: own.oy * place.s + place.oy,
|
|
890
|
+
s: own.s * place.s,
|
|
891
|
+
}, paintOf(root, INITIAL_PAINT, notes), sketch);
|
|
892
|
+
return sketch.elements;
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* The frame a node's OWN attributes are read in — its `cx`, its `x1`, its
|
|
896
|
+
* `points` — composed exactly the way the walk composes it: the root's
|
|
897
|
+
* viewport, then every ancestor's translate and nested viewport, then the
|
|
898
|
+
* node's own `transform`. So a recogniser that reads a circle's centre through
|
|
899
|
+
* this lands it on the very point the sketch would have drawn it.
|
|
900
|
+
*
|
|
901
|
+
* The transforms the walk ignores are ignored here too, silently: the walk
|
|
902
|
+
* already says so once per kind when it meets them.
|
|
903
|
+
*/
|
|
904
|
+
export function svgFrameOf(element) {
|
|
905
|
+
const path = [];
|
|
906
|
+
for (let at = element; at; at = at.parentElement) {
|
|
907
|
+
path.unshift(at);
|
|
908
|
+
}
|
|
909
|
+
// The outermost `<svg>` on the path is the root the walk starts from: its
|
|
910
|
+
// viewport is the identity's, and its own `transform` is never read.
|
|
911
|
+
const rootIndex = path.findIndex(node => nameOf(node) === 'svg');
|
|
912
|
+
if (rootIndex < 0)
|
|
913
|
+
return IDENTITY;
|
|
914
|
+
const quiet = new SvgSketchNotebook();
|
|
915
|
+
let frame = viewportFrame(path[rootIndex], IDENTITY);
|
|
916
|
+
for (const node of path.slice(rootIndex + 1)) {
|
|
917
|
+
frame = translated(node, frame, quiet);
|
|
918
|
+
if (node !== element && nameOf(node) === 'svg') {
|
|
919
|
+
frame = viewportFrame(node, frame);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return frame;
|
|
923
|
+
}
|
|
854
924
|
/* ── The capability's function ────────────────────────────────────────── */
|
|
855
925
|
/**
|
|
856
926
|
* The document, sanitized, or an exception naming what is wrong with it.
|
|
@@ -867,8 +937,12 @@ function emit(element, name, frame, paint, sketch) {
|
|
|
867
937
|
* handler attributes — handed over by whoever sent the file. The same
|
|
868
938
|
* `USE_PROFILES: { svg: true }` guard is what the edgeless clipboard already
|
|
869
939
|
* puts in front of a pasted SVG.
|
|
940
|
+
*
|
|
941
|
+
* The first of the two passes {@link parseSvgSketch} is made of, exported so a
|
|
942
|
+
* framework that recognises part of a picture reads the SAME sanitised tree
|
|
943
|
+
* the sketch walks (ADR 0032 §2, §7) — never the source.
|
|
870
944
|
*/
|
|
871
|
-
function
|
|
945
|
+
export function sanitizeSvg(source, notes) {
|
|
872
946
|
const doc = new DOMParser().parseFromString(source, 'image/svg+xml');
|
|
873
947
|
const error = doc.querySelector('parsererror');
|
|
874
948
|
if (error) {
|
|
@@ -952,25 +1026,22 @@ export function parseSvgSketch(source, context = {}) {
|
|
|
952
1026
|
// A sketch has no document-level name to take: what a board is CALLED is the
|
|
953
1027
|
// document's business, not any element's. Same answer the BPMN reader gives.
|
|
954
1028
|
void context;
|
|
955
|
-
const
|
|
956
|
-
const
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
walk(root, viewportFrame(root, IDENTITY), paintOf(root, INITIAL_PAINT, sketch.notes), sketch);
|
|
960
|
-
if (sketch.elements.length === 0) {
|
|
961
|
-
sketch.notes.once('empty', 'No shape or text was recognised in this SVG, so nothing was drawn.', SVG_SKETCH_EMPTY);
|
|
1029
|
+
const notes = new SvgSketchNotebook();
|
|
1030
|
+
const elements = sketchSvgTree(sanitizeSvg(source, notes), notes);
|
|
1031
|
+
if (elements.length === 0) {
|
|
1032
|
+
notes.once('empty', 'No shape or text was recognised in this SVG, so nothing was drawn.', SVG_SKETCH_EMPTY);
|
|
962
1033
|
}
|
|
963
1034
|
return {
|
|
964
|
-
elements
|
|
1035
|
+
elements,
|
|
965
1036
|
report: {
|
|
966
|
-
mapped:
|
|
1037
|
+
mapped: elements.length,
|
|
967
1038
|
// Always zero, and it is the tier's whole contract rather than an
|
|
968
1039
|
// accident of this file: a visual import carries nothing and quarantines
|
|
969
1040
|
// nothing, because it writes no `interchange` payload to carry anything
|
|
970
1041
|
// IN (ADR 0012, P2). Pinned by an anti-decay test.
|
|
971
1042
|
carried: 0,
|
|
972
1043
|
quarantined: 0,
|
|
973
|
-
notes:
|
|
1044
|
+
notes: notes.notes,
|
|
974
1045
|
// …and no `sourceVersion`. An SVG declares a version of the SVG spec, not
|
|
975
1046
|
// a version of a vocabulary this reader translates, so claiming one would
|
|
976
1047
|
// be a fact about the file dressed up as a fact about the import.
|