@formicoidea/labre-core 0.43.1 → 0.46.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-callout-into.d.ts +43 -0
- package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.js +109 -0
- 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/toolbar.d.ts +65 -0
- package/dist/_pkgs/affine-block-callout/configs/toolbar.js +178 -0
- 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 +10 -1
- 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/commands.d.ts +27 -0
- package/dist/_pkgs/affine-block-frame/commands.js +49 -0
- package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +16 -6
- package/dist/_pkgs/affine-block-frame/frame-manager.js +58 -22
- package/dist/_pkgs/affine-block-frame/frame-order.d.ts +43 -0
- package/dist/_pkgs/affine-block-frame/frame-order.js +93 -0
- package/dist/_pkgs/affine-block-frame/frame-tool.js +3 -1
- package/dist/_pkgs/affine-block-frame/index.d.ts +2 -0
- package/dist/_pkgs/affine-block-frame/index.js +2 -0
- package/dist/_pkgs/affine-block-frame/present/frame-order-menu.d.ts +10 -2
- package/dist/_pkgs/affine-block-frame/present/frame-order-menu.js +32 -18
- package/dist/_pkgs/affine-block-frame/view.js +6 -0
- 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/configs/toolbar.d.ts +19 -0
- package/dist/_pkgs/affine-block-note/configs/toolbar.js +38 -23
- package/dist/_pkgs/affine-block-note/translations.d.ts +2 -1
- package/dist/_pkgs/affine-block-note/translations.js +14 -6
- package/dist/_pkgs/affine-block-root/configs/toolbar.js +48 -3
- 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-root/translations.d.ts +7 -2
- package/dist/_pkgs/affine-block-root/translations.js +10 -13
- 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 +91 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.js +285 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.d.ts +80 -0
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.js +355 -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-components/portal/portal.d.ts +1 -1
- package/dist/_pkgs/affine-foundation/view.d.ts +8 -8
- package/dist/_pkgs/affine-fragment-adapter-panel/adapter-panel.d.ts +2 -2
- package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.d.ts +34 -2
- package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +194 -81
- package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.d.ts +7 -4
- package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +9 -24
- 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 +2 -0
- package/dist/_pkgs/affine-fragment-frame-panel/index.js +2 -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-model/utils/types.d.ts +2 -2
- 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 +31 -4
- 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/font-loader/config.d.ts +2 -2
- package/dist/_pkgs/affine-shared/services/font-loader/font-loader-service.d.ts +3 -3
- package/dist/_pkgs/affine-shared/services/index.d.ts +4 -1
- package/dist/_pkgs/affine-shared/services/index.js +4 -1
- package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-storage.d.ts +4 -4
- package/dist/_pkgs/affine-shared/services/outline-panel-service.d.ts +31 -0
- package/dist/_pkgs/affine-shared/services/outline-panel-service.js +17 -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 +16 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +28 -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 +3 -0
- package/dist/_pkgs/affine-shared/utils/index.js +3 -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-shared/utils/panel-reorder-drag.d.ts +85 -0
- package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.js +162 -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 +62 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.js +94 -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 +186 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.js +1417 -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/scope/std-scope.d.ts +1 -1
- 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 +6 -1
- package/dist/host-panels.d.ts +90 -0
- package/dist/host-panels.js +111 -0
- package/dist/translations.js +10 -6
- package/package.json +13 -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-fragment-frame-panel/utils/drag.d.ts +0 -27
- package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.js +0 -96
- package/dist/_pkgs/affine-shared/services/sidebar-service.d.ts +0 -8
- package/dist/_pkgs/affine-shared/services/sidebar-service.js +0 -7
- 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,1417 @@
|
|
|
1
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
+
var _, done = false;
|
|
7
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
+
var context = {};
|
|
9
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
+
if (kind === "accessor") {
|
|
14
|
+
if (result === void 0) continue;
|
|
15
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
+
}
|
|
20
|
+
else if (_ = accept(result)) {
|
|
21
|
+
if (kind === "field") initializers.unshift(_);
|
|
22
|
+
else descriptor[key] = _;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
+
done = true;
|
|
27
|
+
};
|
|
28
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
+
var useValue = arguments.length > 2;
|
|
30
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
+
}
|
|
33
|
+
return useValue ? value : void 0;
|
|
34
|
+
};
|
|
35
|
+
import { CanvasActiveLayer, EDITOR_ANCHORED_PANEL_Z_INDEX, filterSelectionPaneTree, SelectionPaneModel, selectionPaneCommands, selectionPaneFilterMembers, selectionPaneFilterTargets, selectionPaneTree, userLayerCommands, userLayerName, } from '../../affine-block-surface/index.js';
|
|
36
|
+
import { menu, popMenu, popupTargetFromElement, } from '../../affine-components/context-menu/index.js';
|
|
37
|
+
import { FrameBlockModel, MindmapElementModel, } from '../../affine-model/index.js';
|
|
38
|
+
import { TOOLBAR_LOCK, TOOLBAR_RENAME, translateKey, } from '../../affine-shared/services/index.js';
|
|
39
|
+
import { panelHeaderStyles } from '../../affine-shared/styles/index.js';
|
|
40
|
+
import { createPanelReorderDrag, } from '../../affine-shared/utils/index.js';
|
|
41
|
+
import { runCommand, WidgetComponent, WidgetViewExtension, } from '../../std/index.js';
|
|
42
|
+
import { DEFAULT_LAYER_ID, GfxBlockElementModel, GfxControllerIdentifier, } from '../../std/gfx/index.js';
|
|
43
|
+
import { ArrowDownSmallIcon, ArrowRightSmallIcon, CloseIcon, DeleteIcon, FilterIcon, InvisibleIcon, LayerIcon, LockIcon, MoreHorizontalIcon, PlusIcon, UnlockIcon, ViewIcon, } from '@blocksuite/icons/lit';
|
|
44
|
+
import { css, html, nothing, unsafeCSS } from 'lit';
|
|
45
|
+
import { state } from 'lit/decorators.js';
|
|
46
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
47
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
48
|
+
import { literal, unsafeStatic } from 'lit/static-html.js';
|
|
49
|
+
import { SELECTION_PANE_ACTIVE_LAYER, SELECTION_PANE_CLOSE, SELECTION_PANE_COLLAPSE, SELECTION_PANE_DELETE_LAYER, SELECTION_PANE_EMPTY, SELECTION_PANE_EXPAND, SELECTION_PANE_FILTER, SELECTION_PANE_FILTER_ALL, SELECTION_PANE_FILTER_FRAME, SELECTION_PANE_LAYER_FILTERED, SELECTION_PANE_TITLE, SELECTION_PANE_HIDE, SELECTION_PANE_HIDE_FOR_EVERYONE, SELECTION_PANE_NEW_LAYER, SELECTION_PANE_ROW_MENU, SELECTION_PANE_SHOW, SELECTION_PANE_SHOW_FOR_EVERYONE, SELECTION_PANE_UNLOCK, } from '../translations.js';
|
|
50
|
+
import { paneDropAbove, paneLists, paneSlotAtGap, } from './drop.js';
|
|
51
|
+
import { selectionPaneRowIcon, selectionPaneRowLabel } from './labels.js';
|
|
52
|
+
export const EDGELESS_SELECTION_PANE_WIDGET = 'edgeless-selection-pane-widget';
|
|
53
|
+
/** The catalogue's measure: an icon, a label and a toggle, never most of a phone. */
|
|
54
|
+
const PANEL_WIDTH = 'min(320px, 85vw)';
|
|
55
|
+
/** Indent per nesting level, in px. */
|
|
56
|
+
const INDENT_PX = 16;
|
|
57
|
+
/**
|
|
58
|
+
* How the pane invokes the registry. The pane is not one of the registry's
|
|
59
|
+
* surfaces (a designed panel, not an enumeration of commands): like the
|
|
60
|
+
* contextual toolbar it acts on ONE element, the row's, and `source` says it
|
|
61
|
+
* came from the editor's chrome.
|
|
62
|
+
*/
|
|
63
|
+
const PANE_INVOCATION = {
|
|
64
|
+
surface: 'contextual-toolbar',
|
|
65
|
+
source: 'toolbar:general',
|
|
66
|
+
};
|
|
67
|
+
function paneCommand(id) {
|
|
68
|
+
const command = [...selectionPaneCommands, ...userLayerCommands].find(c => c.id === id);
|
|
69
|
+
if (!command)
|
|
70
|
+
throw new Error(`selection pane: no command ${id}`);
|
|
71
|
+
return command;
|
|
72
|
+
}
|
|
73
|
+
/** `model.group`, or `null` where the getter throws (no surface holds it). */
|
|
74
|
+
function rawGroupOf(model) {
|
|
75
|
+
try {
|
|
76
|
+
return model.group ?? null;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The **selection pane** (ADR 0031, stage 2): the canvas elements by z-order,
|
|
84
|
+
* top first, the library's own panel behind `SelectionPaneProvider`.
|
|
85
|
+
*
|
|
86
|
+
* ## Docked like the artefact catalogue
|
|
87
|
+
*
|
|
88
|
+
* A full-height column down the left edge of the editor, inside it — the
|
|
89
|
+
* geometry, layer, zero-width host and wheel capture are the catalogue's, for
|
|
90
|
+
* the catalogue's reasons (see `artefact-catalogue-widget.ts`). What differs
|
|
91
|
+
* is the dismissal: the pane is a place you WORK from, its selection mirrors
|
|
92
|
+
* the canvas both ways, so a click on the canvas does not put it away. × and
|
|
93
|
+
* Escape (with the pointer or focus in the pane) do.
|
|
94
|
+
*
|
|
95
|
+
* ## Rows
|
|
96
|
+
*
|
|
97
|
+
* Drawn from `selectionPaneTree(std)` — the same headless tree a host pane
|
|
98
|
+
* would draw — and labelled at render time ({@link selectionPaneRowLabel}).
|
|
99
|
+
* A group or a mindmap is a collapsible row; collapse is this panel's state,
|
|
100
|
+
* never stored. Hover highlights the element on the canvas, click selects it
|
|
101
|
+
* (shift / ctrl / cmd adds or removes it, like on the canvas), the padlock
|
|
102
|
+
* locks that row alone, a double-click renames a group or a frame (a frame is
|
|
103
|
+
* a row at its place in the stack, ADR 0031 amendments), and a drag moves a row
|
|
104
|
+
* — or, pressed on a selected row, the whole selection of one stack — among
|
|
105
|
+
* its siblings (the side panels' one drag, ADR 0034). Every write goes through
|
|
106
|
+
* `runCommand`, so the read-only refusal and the undo step live in one place.
|
|
107
|
+
*/
|
|
108
|
+
let EdgelessSelectionPaneWidget = (() => {
|
|
109
|
+
let _classSuper = WidgetComponent;
|
|
110
|
+
let __open_decorators;
|
|
111
|
+
let __open_initializers = [];
|
|
112
|
+
let __open_extraInitializers = [];
|
|
113
|
+
let __collapsed_decorators;
|
|
114
|
+
let __collapsed_initializers = [];
|
|
115
|
+
let __collapsed_extraInitializers = [];
|
|
116
|
+
let __filter_decorators;
|
|
117
|
+
let __filter_initializers = [];
|
|
118
|
+
let __filter_extraInitializers = [];
|
|
119
|
+
let __renaming_decorators;
|
|
120
|
+
let __renaming_initializers = [];
|
|
121
|
+
let __renaming_extraInitializers = [];
|
|
122
|
+
let __drop_decorators;
|
|
123
|
+
let __drop_initializers = [];
|
|
124
|
+
let __drop_extraInitializers = [];
|
|
125
|
+
let __ghost_decorators;
|
|
126
|
+
let __ghost_initializers = [];
|
|
127
|
+
let __ghost_extraInitializers = [];
|
|
128
|
+
let __selectionRevision_decorators;
|
|
129
|
+
let __selectionRevision_initializers = [];
|
|
130
|
+
let __selectionRevision_extraInitializers = [];
|
|
131
|
+
let __drag_decorators;
|
|
132
|
+
let __drag_initializers = [];
|
|
133
|
+
let __drag_extraInitializers = [];
|
|
134
|
+
return class EdgelessSelectionPaneWidget extends _classSuper {
|
|
135
|
+
constructor() {
|
|
136
|
+
super(...arguments);
|
|
137
|
+
this.#_open_accessor_storage = __runInitializers(this, __open_initializers, false);
|
|
138
|
+
this.#_collapsed_accessor_storage = (__runInitializers(this, __open_extraInitializers), __runInitializers(this, __collapsed_initializers, new Set()));
|
|
139
|
+
this.#_filter_accessor_storage = (__runInitializers(this, __collapsed_extraInitializers), __runInitializers(this, __filter_initializers, null));
|
|
140
|
+
this.#_renaming_accessor_storage = (__runInitializers(this, __filter_extraInitializers), __runInitializers(this, __renaming_initializers, null));
|
|
141
|
+
this.#_drop_accessor_storage = (__runInitializers(this, __renaming_extraInitializers), __runInitializers(this, __drop_initializers, null));
|
|
142
|
+
this.#_ghost_accessor_storage = (__runInitializers(this, __drop_extraInitializers), __runInitializers(this, __ghost_initializers, null));
|
|
143
|
+
this.#_selectionRevision_accessor_storage = (__runInitializers(this, __ghost_extraInitializers), __runInitializers(this, __selectionRevision_initializers, 0));
|
|
144
|
+
this.#_drag_accessor_storage = (__runInitializers(this, __selectionRevision_extraInitializers), __runInitializers(this, __drag_initializers, null));
|
|
145
|
+
/** The last row pressed: what a pick-up picks up. */
|
|
146
|
+
this._pressed = (__runInitializers(this, __drag_extraInitializers), null);
|
|
147
|
+
/** The side panels' one reorder gesture, wired in `_wire()`. */
|
|
148
|
+
this._reorder = null;
|
|
149
|
+
/** The rows of the last render, top first: what a drag hit-tests. */
|
|
150
|
+
this._visibleRows = [];
|
|
151
|
+
/** The sibling lists before the filter: what a drop is computed in. */
|
|
152
|
+
this._lists = paneLists([]);
|
|
153
|
+
/** Put the pane away. Writes nothing but its own state. */
|
|
154
|
+
this.closePanel = () => {
|
|
155
|
+
this._setOpen(false);
|
|
156
|
+
};
|
|
157
|
+
this._swallow = (event) => {
|
|
158
|
+
event.stopPropagation();
|
|
159
|
+
};
|
|
160
|
+
this._onHostKeydown = (event) => {
|
|
161
|
+
if (!this._open || event.key !== 'Escape')
|
|
162
|
+
return;
|
|
163
|
+
if (!event.composedPath().includes(this))
|
|
164
|
+
return;
|
|
165
|
+
if (this._renaming)
|
|
166
|
+
return;
|
|
167
|
+
event.stopPropagation();
|
|
168
|
+
// Escape during a drag never gets here: the drag controller cancels the
|
|
169
|
+
// drag and stops it in the capture phase, so the pane stays open.
|
|
170
|
+
this.closePanel();
|
|
171
|
+
};
|
|
172
|
+
/** Same capture as the catalogue: a wheel over the pane scrolls the pane. */
|
|
173
|
+
this._onHostWheel = (event) => {
|
|
174
|
+
if (!this._open)
|
|
175
|
+
return;
|
|
176
|
+
if (!event.composedPath().includes(this))
|
|
177
|
+
return;
|
|
178
|
+
event.stopPropagation();
|
|
179
|
+
};
|
|
180
|
+
this._onRenameKeydown = (event, id) => {
|
|
181
|
+
// The canvas behind binds Backspace, Delete and every letter: a key typed
|
|
182
|
+
// into the title must never reach it.
|
|
183
|
+
event.stopPropagation();
|
|
184
|
+
if (event.isComposing)
|
|
185
|
+
return;
|
|
186
|
+
if (event.key === 'Enter') {
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
this._commitRename(id, event.currentTarget);
|
|
189
|
+
}
|
|
190
|
+
else if (event.key === 'Escape') {
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
this._renaming = null;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
this._openFilterMenu = (event) => {
|
|
196
|
+
const targets = selectionPaneFilterTargets(this.std);
|
|
197
|
+
popMenu(popupTargetFromElement(event.currentTarget), {
|
|
198
|
+
options: {
|
|
199
|
+
items: [
|
|
200
|
+
menu.action({
|
|
201
|
+
name: translateKey(this.std, ...SELECTION_PANE_FILTER_ALL),
|
|
202
|
+
isSelected: this._filter === null,
|
|
203
|
+
select: () => {
|
|
204
|
+
this._filter = null;
|
|
205
|
+
},
|
|
206
|
+
}),
|
|
207
|
+
...targets.map(target => menu.action({
|
|
208
|
+
name: this._filterWording(target.id),
|
|
209
|
+
isSelected: this._filter === target.id,
|
|
210
|
+
select: () => {
|
|
211
|
+
this._filter = target.id;
|
|
212
|
+
},
|
|
213
|
+
})),
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* "New layer": create it, then open its name for editing — the frame
|
|
220
|
+
* panel's inline title editor, as a double-click does — so the creation is
|
|
221
|
+
* unmistakable even under a filter (ADR 0031, amendments).
|
|
222
|
+
*/
|
|
223
|
+
this._createLayer = () => {
|
|
224
|
+
const before = new Set(Object.keys(this._gfx.surface?.props.layers ?? {}));
|
|
225
|
+
this._run('canvas.layer.create', {});
|
|
226
|
+
const created = Object.keys(this._gfx.surface?.props.layers ?? {}).find(id => id !== DEFAULT_LAYER_ID && !before.has(id));
|
|
227
|
+
if (created)
|
|
228
|
+
this._renaming = created;
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
static {
|
|
232
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
233
|
+
__open_decorators = [state()];
|
|
234
|
+
__collapsed_decorators = [state()];
|
|
235
|
+
__filter_decorators = [state()];
|
|
236
|
+
__renaming_decorators = [state()];
|
|
237
|
+
__drop_decorators = [state()];
|
|
238
|
+
__ghost_decorators = [state()];
|
|
239
|
+
__selectionRevision_decorators = [state()];
|
|
240
|
+
__drag_decorators = [state()];
|
|
241
|
+
__esDecorate(this, null, __open_decorators, { kind: "accessor", name: "_open", static: false, private: false, access: { has: obj => "_open" in obj, get: obj => obj._open, set: (obj, value) => { obj._open = value; } }, metadata: _metadata }, __open_initializers, __open_extraInitializers);
|
|
242
|
+
__esDecorate(this, null, __collapsed_decorators, { kind: "accessor", name: "_collapsed", static: false, private: false, access: { has: obj => "_collapsed" in obj, get: obj => obj._collapsed, set: (obj, value) => { obj._collapsed = value; } }, metadata: _metadata }, __collapsed_initializers, __collapsed_extraInitializers);
|
|
243
|
+
__esDecorate(this, null, __filter_decorators, { kind: "accessor", name: "_filter", static: false, private: false, access: { has: obj => "_filter" in obj, get: obj => obj._filter, set: (obj, value) => { obj._filter = value; } }, metadata: _metadata }, __filter_initializers, __filter_extraInitializers);
|
|
244
|
+
__esDecorate(this, null, __renaming_decorators, { kind: "accessor", name: "_renaming", static: false, private: false, access: { has: obj => "_renaming" in obj, get: obj => obj._renaming, set: (obj, value) => { obj._renaming = value; } }, metadata: _metadata }, __renaming_initializers, __renaming_extraInitializers);
|
|
245
|
+
__esDecorate(this, null, __drop_decorators, { kind: "accessor", name: "_drop", static: false, private: false, access: { has: obj => "_drop" in obj, get: obj => obj._drop, set: (obj, value) => { obj._drop = value; } }, metadata: _metadata }, __drop_initializers, __drop_extraInitializers);
|
|
246
|
+
__esDecorate(this, null, __ghost_decorators, { kind: "accessor", name: "_ghost", static: false, private: false, access: { has: obj => "_ghost" in obj, get: obj => obj._ghost, set: (obj, value) => { obj._ghost = value; } }, metadata: _metadata }, __ghost_initializers, __ghost_extraInitializers);
|
|
247
|
+
__esDecorate(this, null, __selectionRevision_decorators, { kind: "accessor", name: "_selectionRevision", static: false, private: false, access: { has: obj => "_selectionRevision" in obj, get: obj => obj._selectionRevision, set: (obj, value) => { obj._selectionRevision = value; } }, metadata: _metadata }, __selectionRevision_initializers, __selectionRevision_extraInitializers);
|
|
248
|
+
__esDecorate(this, null, __drag_decorators, { kind: "accessor", name: "_drag", static: false, private: false, access: { has: obj => "_drag" in obj, get: obj => obj._drag, set: (obj, value) => { obj._drag = value; } }, metadata: _metadata }, __drag_initializers, __drag_extraInitializers);
|
|
249
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
250
|
+
}
|
|
251
|
+
static { this.styles = css `
|
|
252
|
+
${panelHeaderStyles}
|
|
253
|
+
|
|
254
|
+
:host {
|
|
255
|
+
position: absolute;
|
|
256
|
+
left: 0;
|
|
257
|
+
top: 0;
|
|
258
|
+
bottom: 0;
|
|
259
|
+
width: 0;
|
|
260
|
+
z-index: ${unsafeCSS(EDITOR_ANCHORED_PANEL_Z_INDEX)};
|
|
261
|
+
pointer-events: none;
|
|
262
|
+
font-family: var(--affine-font-family);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.selection-pane-panel {
|
|
266
|
+
position: absolute;
|
|
267
|
+
left: 0;
|
|
268
|
+
top: 0;
|
|
269
|
+
bottom: 0;
|
|
270
|
+
width: ${unsafeCSS(PANEL_WIDTH)};
|
|
271
|
+
box-sizing: border-box;
|
|
272
|
+
display: flex;
|
|
273
|
+
flex-direction: column;
|
|
274
|
+
background: var(--affine-background-overlay-panel-color, #fff);
|
|
275
|
+
border-right: 1px solid var(--affine-border-color);
|
|
276
|
+
box-shadow: var(--affine-shadow-2);
|
|
277
|
+
color: var(--affine-text-primary-color);
|
|
278
|
+
font-size: 14px;
|
|
279
|
+
line-height: 1.4;
|
|
280
|
+
pointer-events: auto;
|
|
281
|
+
user-select: none;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.selection-pane-panel:focus-visible {
|
|
285
|
+
outline: 2px solid var(--affine-primary-color);
|
|
286
|
+
outline-offset: -2px;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* The header row itself is the frame panel's (panelHeaderStyles). */
|
|
290
|
+
.selection-pane-actions {
|
|
291
|
+
flex: none;
|
|
292
|
+
display: flex;
|
|
293
|
+
align-items: center;
|
|
294
|
+
gap: 8px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* The pane's secondary text: the filter's name, a layer's filtered count. */
|
|
298
|
+
.selection-pane-filter-label,
|
|
299
|
+
.selection-pane-layer-note {
|
|
300
|
+
color: var(--affine-text-secondary-color);
|
|
301
|
+
font-size: 12px;
|
|
302
|
+
overflow: hidden;
|
|
303
|
+
text-overflow: ellipsis;
|
|
304
|
+
white-space: nowrap;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.selection-pane-filter-label {
|
|
308
|
+
padding: 6px 16px;
|
|
309
|
+
border-bottom: 1px solid var(--affine-border-color);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.selection-pane-layer-note {
|
|
313
|
+
padding-top: 2px;
|
|
314
|
+
padding-bottom: 4px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.selection-pane-body {
|
|
318
|
+
position: relative;
|
|
319
|
+
flex: 1;
|
|
320
|
+
min-height: 0;
|
|
321
|
+
overflow-y: auto;
|
|
322
|
+
overflow-x: hidden;
|
|
323
|
+
overscroll-behavior: contain;
|
|
324
|
+
-webkit-overflow-scrolling: touch;
|
|
325
|
+
padding: 4px 0 16px;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.selection-pane-empty {
|
|
329
|
+
padding: 16px;
|
|
330
|
+
color: var(--affine-text-secondary-color);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.selection-pane-row {
|
|
334
|
+
display: flex;
|
|
335
|
+
align-items: center;
|
|
336
|
+
gap: 4px;
|
|
337
|
+
min-height: 32px;
|
|
338
|
+
box-sizing: border-box;
|
|
339
|
+
padding-right: 8px;
|
|
340
|
+
border-top: 2px solid transparent;
|
|
341
|
+
border-bottom: 2px solid transparent;
|
|
342
|
+
cursor: pointer;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@media (hover: hover) {
|
|
346
|
+
.selection-pane-row:hover {
|
|
347
|
+
background: var(--affine-hover-color);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.selection-pane-row[data-selected] {
|
|
352
|
+
background: var(--affine-hover-color);
|
|
353
|
+
color: var(--affine-primary-color);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* The rows being dragged stay in place, dimmed, like the frame panel's
|
|
357
|
+
placeholder cards; the pressed row's ghost follows the pointer. */
|
|
358
|
+
.selection-pane-row[data-dragging] {
|
|
359
|
+
opacity: 0.5;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* While dragging, the pane says whether a drop here would land. */
|
|
363
|
+
.selection-pane-panel[data-drag='valid'] {
|
|
364
|
+
cursor: grabbing;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.selection-pane-panel[data-drag='invalid'] {
|
|
368
|
+
cursor: not-allowed;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.selection-pane-panel[data-drag] * {
|
|
372
|
+
cursor: inherit;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/* The frame panel's insert indicator: a line at the gap a drop lands in. */
|
|
376
|
+
.selection-pane-drop-indicator {
|
|
377
|
+
position: absolute;
|
|
378
|
+
right: 8px;
|
|
379
|
+
height: 2px;
|
|
380
|
+
border-radius: 1px;
|
|
381
|
+
background: var(--affine-primary-color);
|
|
382
|
+
transform: translateY(-1px);
|
|
383
|
+
pointer-events: none;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/*
|
|
387
|
+
The drag mask, created by the drag controller (createPanelReorderDrag):
|
|
388
|
+
over the whole viewport for the length of the drag, so the cursor —
|
|
389
|
+
set inline by the controller, "grabbing" or "not-allowed" — speaks
|
|
390
|
+
wherever the pointer is, and the canvas under it takes no hover.
|
|
391
|
+
*/
|
|
392
|
+
.selection-pane-drag-mask {
|
|
393
|
+
position: fixed;
|
|
394
|
+
inset: 0;
|
|
395
|
+
z-index: 1;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/* The row itself at its own width, like the frame panel's dragged card. */
|
|
399
|
+
.selection-pane-drag-ghost {
|
|
400
|
+
position: absolute;
|
|
401
|
+
top: 0;
|
|
402
|
+
left: 0;
|
|
403
|
+
z-index: 2;
|
|
404
|
+
display: flex;
|
|
405
|
+
align-items: center;
|
|
406
|
+
gap: 4px;
|
|
407
|
+
min-height: 32px;
|
|
408
|
+
box-sizing: border-box;
|
|
409
|
+
padding: 4px 8px;
|
|
410
|
+
border: 1px solid var(--affine-border-color);
|
|
411
|
+
border-radius: 4px;
|
|
412
|
+
background: var(--affine-background-overlay-panel-color);
|
|
413
|
+
box-shadow: var(--affine-shadow-2);
|
|
414
|
+
white-space: nowrap;
|
|
415
|
+
overflow: hidden;
|
|
416
|
+
pointer-events: none;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.selection-pane-drag-ghost .selection-pane-label {
|
|
420
|
+
flex: initial;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* How many rows move with the ghost: the frame panel's card count. */
|
|
424
|
+
.selection-pane-drag-count {
|
|
425
|
+
flex: none;
|
|
426
|
+
margin-left: auto;
|
|
427
|
+
display: flex;
|
|
428
|
+
align-items: center;
|
|
429
|
+
justify-content: center;
|
|
430
|
+
min-width: 20px;
|
|
431
|
+
height: 20px;
|
|
432
|
+
padding: 0 4px;
|
|
433
|
+
box-sizing: border-box;
|
|
434
|
+
border-radius: 10px;
|
|
435
|
+
background: var(--affine-black);
|
|
436
|
+
color: var(--affine-white);
|
|
437
|
+
font-size: 12px;
|
|
438
|
+
line-height: 20px;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/* A row dragged onto a layer moves into it (ADR 0031 §5). */
|
|
442
|
+
.selection-pane-row[data-drop='into'] {
|
|
443
|
+
outline: 2px solid var(--affine-primary-color);
|
|
444
|
+
outline-offset: -2px;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
.selection-pane-layer-row {
|
|
448
|
+
font-weight: 600;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* The active layer: where this viewer's new elements land. */
|
|
452
|
+
.selection-pane-layer-row[data-active] .selection-pane-label,
|
|
453
|
+
.selection-pane-layer-row[data-active] .selection-pane-icon {
|
|
454
|
+
color: var(--affine-primary-color);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.selection-pane-chevron,
|
|
458
|
+
.selection-pane-eye,
|
|
459
|
+
.selection-pane-lock,
|
|
460
|
+
.selection-pane-more {
|
|
461
|
+
flex: none;
|
|
462
|
+
display: flex;
|
|
463
|
+
align-items: center;
|
|
464
|
+
justify-content: center;
|
|
465
|
+
width: 24px;
|
|
466
|
+
height: 24px;
|
|
467
|
+
padding: 0;
|
|
468
|
+
border: none;
|
|
469
|
+
border-radius: 4px;
|
|
470
|
+
background: transparent;
|
|
471
|
+
color: var(--affine-icon-color);
|
|
472
|
+
cursor: pointer;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.selection-pane-chevron svg,
|
|
476
|
+
.selection-pane-eye svg,
|
|
477
|
+
.selection-pane-lock svg,
|
|
478
|
+
.selection-pane-more svg,
|
|
479
|
+
.selection-pane-icon svg {
|
|
480
|
+
width: 16px;
|
|
481
|
+
height: 16px;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.selection-pane-chevron:hover,
|
|
485
|
+
.selection-pane-eye:hover,
|
|
486
|
+
.selection-pane-lock:hover,
|
|
487
|
+
.selection-pane-more:hover {
|
|
488
|
+
background: var(--affine-hover-color);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.selection-pane-chevron[hidden] {
|
|
492
|
+
visibility: hidden;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/*
|
|
496
|
+
Off states show on hover only, like PowerPoint's pane: a column of open
|
|
497
|
+
eyes and open padlocks on every row would be noise. A hidden or locked
|
|
498
|
+
row keeps its mark visible, which is what makes it findable.
|
|
499
|
+
*/
|
|
500
|
+
.selection-pane-eye[aria-pressed='false'],
|
|
501
|
+
.selection-pane-lock[aria-pressed='false'],
|
|
502
|
+
.selection-pane-more {
|
|
503
|
+
opacity: 0;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.selection-pane-row:hover .selection-pane-eye,
|
|
507
|
+
.selection-pane-row:hover .selection-pane-lock,
|
|
508
|
+
.selection-pane-row:hover .selection-pane-more,
|
|
509
|
+
.selection-pane-eye:focus-visible,
|
|
510
|
+
.selection-pane-lock:focus-visible,
|
|
511
|
+
.selection-pane-more:focus-visible {
|
|
512
|
+
opacity: 1;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.selection-pane-row[data-hidden-local] .selection-pane-label,
|
|
516
|
+
.selection-pane-row[data-hidden-local] .selection-pane-icon {
|
|
517
|
+
opacity: 0.5;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.selection-pane-row[data-hidden-everyone] .selection-pane-label,
|
|
521
|
+
.selection-pane-layer-row[data-hidden-local] .selection-pane-label {
|
|
522
|
+
opacity: 0.5;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/* Hidden for everyone: the theme warning token marks what others cannot see. */
|
|
526
|
+
.selection-pane-row[data-hidden-everyone] .selection-pane-icon {
|
|
527
|
+
color: var(--affine-warning-color);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.selection-pane-lock:disabled {
|
|
531
|
+
cursor: default;
|
|
532
|
+
color: var(--affine-text-disable-color);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.selection-pane-icon {
|
|
536
|
+
flex: none;
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
color: var(--affine-icon-color);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.selection-pane-label {
|
|
543
|
+
flex: 1;
|
|
544
|
+
min-width: 0;
|
|
545
|
+
overflow: hidden;
|
|
546
|
+
text-overflow: ellipsis;
|
|
547
|
+
white-space: nowrap;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.selection-pane-rename {
|
|
551
|
+
flex: 1;
|
|
552
|
+
min-width: 0;
|
|
553
|
+
padding: 2px 6px;
|
|
554
|
+
border: 1px solid var(--affine-border-color);
|
|
555
|
+
border-radius: 4px;
|
|
556
|
+
background: var(--affine-background-primary-color);
|
|
557
|
+
color: inherit;
|
|
558
|
+
font: inherit;
|
|
559
|
+
outline: none;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.selection-pane-rename:focus {
|
|
563
|
+
box-shadow: var(--affine-active-shadow);
|
|
564
|
+
border-color: var(--affine-primary-color);
|
|
565
|
+
}
|
|
566
|
+
`; }
|
|
567
|
+
#_open_accessor_storage;
|
|
568
|
+
get _open() { return this.#_open_accessor_storage; }
|
|
569
|
+
set _open(value) { this.#_open_accessor_storage = value; }
|
|
570
|
+
#_collapsed_accessor_storage;
|
|
571
|
+
/** Group rows the user folded. UI state, never stored. */
|
|
572
|
+
get _collapsed() { return this.#_collapsed_accessor_storage; }
|
|
573
|
+
set _collapsed(value) { this.#_collapsed_accessor_storage = value; }
|
|
574
|
+
#_filter_accessor_storage;
|
|
575
|
+
/** The frame the list is narrowed to, or `null`. */
|
|
576
|
+
get _filter() { return this.#_filter_accessor_storage; }
|
|
577
|
+
set _filter(value) { this.#_filter_accessor_storage = value; }
|
|
578
|
+
#_renaming_accessor_storage;
|
|
579
|
+
/** The group row being renamed, or `null`. */
|
|
580
|
+
get _renaming() { return this.#_renaming_accessor_storage; }
|
|
581
|
+
set _renaming(value) { this.#_renaming_accessor_storage = value; }
|
|
582
|
+
#_drop_accessor_storage;
|
|
583
|
+
/** Where the dragged rows would land; `null` while refused. */
|
|
584
|
+
get _drop() { return this.#_drop_accessor_storage; }
|
|
585
|
+
set _drop(value) { this.#_drop_accessor_storage = value; }
|
|
586
|
+
#_ghost_accessor_storage;
|
|
587
|
+
/** Where the dragged row's ghost is drawn, in the panel's own box. */
|
|
588
|
+
get _ghost() { return this.#_ghost_accessor_storage; }
|
|
589
|
+
set _ghost(value) { this.#_ghost_accessor_storage = value; }
|
|
590
|
+
#_selectionRevision_accessor_storage;
|
|
591
|
+
/** Bumped when the canvas selection changes, so the rows repaint. */
|
|
592
|
+
get _selectionRevision() { return this.#_selectionRevision_accessor_storage; }
|
|
593
|
+
set _selectionRevision(value) { this.#_selectionRevision_accessor_storage = value; }
|
|
594
|
+
#_drag_accessor_storage;
|
|
595
|
+
/** The drag under way, from its pick-up to its end. */
|
|
596
|
+
get _drag() { return this.#_drag_accessor_storage; }
|
|
597
|
+
set _drag(value) { this.#_drag_accessor_storage = value; }
|
|
598
|
+
get paneOpen() {
|
|
599
|
+
return this._open;
|
|
600
|
+
}
|
|
601
|
+
get _gfx() {
|
|
602
|
+
return this.std.get(GfxControllerIdentifier);
|
|
603
|
+
}
|
|
604
|
+
_setOpen(open) {
|
|
605
|
+
this._open = open;
|
|
606
|
+
const model = this.std.getOptional(SelectionPaneModel);
|
|
607
|
+
if (model)
|
|
608
|
+
model.open$.value = open;
|
|
609
|
+
if (!open) {
|
|
610
|
+
this._renaming = null;
|
|
611
|
+
this._clearHighlight();
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
/** Show the pane. Called through `SelectionPaneProvider` only. */
|
|
615
|
+
openPanel() {
|
|
616
|
+
this._setOpen(true);
|
|
617
|
+
}
|
|
618
|
+
_wire() {
|
|
619
|
+
const host = this.std.host;
|
|
620
|
+
host.addEventListener('keydown', this._onHostKeydown, true);
|
|
621
|
+
host.addEventListener('wheel', this._onHostWheel, true);
|
|
622
|
+
const subscription = this._gfx.selection.slots.updated.subscribe(() => {
|
|
623
|
+
this._selectionRevision++;
|
|
624
|
+
});
|
|
625
|
+
const reorder = this._createReorderDrag();
|
|
626
|
+
this._reorder = reorder;
|
|
627
|
+
this._disposables.add(() => {
|
|
628
|
+
host.removeEventListener('keydown', this._onHostKeydown, true);
|
|
629
|
+
host.removeEventListener('wheel', this._onHostWheel, true);
|
|
630
|
+
subscription.unsubscribe();
|
|
631
|
+
reorder.dispose();
|
|
632
|
+
if (this._reorder === reorder)
|
|
633
|
+
this._reorder = null;
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
connectedCallback() {
|
|
637
|
+
super.connectedCallback();
|
|
638
|
+
if (this.hasUpdated)
|
|
639
|
+
this._wire();
|
|
640
|
+
}
|
|
641
|
+
firstUpdated() {
|
|
642
|
+
this._wire();
|
|
643
|
+
}
|
|
644
|
+
disconnectedCallback() {
|
|
645
|
+
super.disconnectedCallback();
|
|
646
|
+
const model = this.std.getOptional(SelectionPaneModel);
|
|
647
|
+
if (model)
|
|
648
|
+
model.open$.value = false;
|
|
649
|
+
}
|
|
650
|
+
/* ── Canvas mirrors ─────────────────────────────────────────────────── */
|
|
651
|
+
_highlight(id) {
|
|
652
|
+
this._gfx.highlightElements([id], { duration: 0 });
|
|
653
|
+
}
|
|
654
|
+
_clearHighlight() {
|
|
655
|
+
this._gfx.highlight.clear();
|
|
656
|
+
}
|
|
657
|
+
_select(event, node) {
|
|
658
|
+
const { selection } = this._gfx;
|
|
659
|
+
if (event.shiftKey || event.metaKey || event.ctrlKey) {
|
|
660
|
+
const ids = new Set(selection.selectedIds);
|
|
661
|
+
if (ids.has(node.id))
|
|
662
|
+
ids.delete(node.id);
|
|
663
|
+
else
|
|
664
|
+
ids.add(node.id);
|
|
665
|
+
selection.set({ elements: [...ids], editing: false });
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
selection.set({ elements: [node.id], editing: false });
|
|
669
|
+
}
|
|
670
|
+
_run(id, params) {
|
|
671
|
+
runCommand(this.std, paneCommand(id), PANE_INVOCATION, params);
|
|
672
|
+
}
|
|
673
|
+
/* ── Rows ───────────────────────────────────────────────────────────── */
|
|
674
|
+
/**
|
|
675
|
+
* The visible rows of `nodes` (the tree as filtered), with `full` the tree
|
|
676
|
+
* before the filter: what tells a layer emptied by the filter from an empty
|
|
677
|
+
* one.
|
|
678
|
+
*/
|
|
679
|
+
_rows(nodes, full = nodes) {
|
|
680
|
+
const membersOf = new Map(full
|
|
681
|
+
.filter(node => node.kind === 'layer')
|
|
682
|
+
.map(node => [node.id, node.children?.length ?? 0]));
|
|
683
|
+
const rows = [];
|
|
684
|
+
const walk = (list, depth, parent) => {
|
|
685
|
+
for (const node of list) {
|
|
686
|
+
const row = { node, depth, parent };
|
|
687
|
+
if (node.kind === 'layer' && node.children?.length === 0) {
|
|
688
|
+
const members = membersOf.get(node.id) ?? 0;
|
|
689
|
+
if (members > 0)
|
|
690
|
+
row.hiddenByFilter = members;
|
|
691
|
+
}
|
|
692
|
+
rows.push(row);
|
|
693
|
+
if (node.children && !this._collapsed.has(node.id)) {
|
|
694
|
+
walk(node.children, depth + 1, node.id);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
walk(nodes, 0, '');
|
|
699
|
+
return rows;
|
|
700
|
+
}
|
|
701
|
+
_toggleCollapsed(id) {
|
|
702
|
+
const next = new Set(this._collapsed);
|
|
703
|
+
if (next.has(id))
|
|
704
|
+
next.delete(id);
|
|
705
|
+
else
|
|
706
|
+
next.add(id);
|
|
707
|
+
this._collapsed = next;
|
|
708
|
+
}
|
|
709
|
+
_onRowClick(event, node) {
|
|
710
|
+
// A drag ends with a click on the row it started on; that click is not one.
|
|
711
|
+
if (this._reorder?.consumeSwallowedClick())
|
|
712
|
+
return;
|
|
713
|
+
// A layer row is not on the canvas: a click makes it the active layer,
|
|
714
|
+
// where this viewer's new elements land (session only, never stored).
|
|
715
|
+
if (node.kind === 'layer') {
|
|
716
|
+
this.std.getOptional(CanvasActiveLayer)?.choose(node.id);
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
this._select(event, node);
|
|
720
|
+
}
|
|
721
|
+
_onRowDblClick(node) {
|
|
722
|
+
if (this.std.store.readonly)
|
|
723
|
+
return;
|
|
724
|
+
if (node.type !== 'group' &&
|
|
725
|
+
node.type !== 'affine:frame' &&
|
|
726
|
+
node.kind !== 'layer') {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
this._renaming = node.id;
|
|
730
|
+
}
|
|
731
|
+
/** A layer's name — the default layer's seed while it has no record. */
|
|
732
|
+
_layerName(id) {
|
|
733
|
+
return userLayerName(this.std, id);
|
|
734
|
+
}
|
|
735
|
+
_onLockClick(event, node) {
|
|
736
|
+
event.stopPropagation();
|
|
737
|
+
this._run(node.locked ? 'canvas.element.unlock' : 'canvas.element.lock', {
|
|
738
|
+
ids: [node.id],
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Hide this row for this viewer, or show it again. Not refused on a
|
|
743
|
+
* read-only document: nothing reaches the document (ADR 0031 §8).
|
|
744
|
+
*/
|
|
745
|
+
_onEyeClick(event, node) {
|
|
746
|
+
event.stopPropagation();
|
|
747
|
+
// A layer's eye hides the whole layer for this viewer (stage 7).
|
|
748
|
+
const target = node.kind === 'layer' ? { layerIds: [node.id] } : { ids: [node.id] };
|
|
749
|
+
this._run('canvas.visibility.hideLocal', {
|
|
750
|
+
...target,
|
|
751
|
+
hidden: !node.hiddenLocal,
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* The row's menu: the actions that write to the DOCUMENT for every viewer,
|
|
756
|
+
* kept off the row's quick toggles so they are never one stray click away.
|
|
757
|
+
* "Hide for everyone" is painted with the theme warning tokens (ADR 0031,
|
|
758
|
+
* resolved at acceptance). A read-only document offers none of them, so the
|
|
759
|
+
* menu does not open there.
|
|
760
|
+
*/
|
|
761
|
+
_openRowMenu(anchor, node) {
|
|
762
|
+
if (this.std.store.readonly)
|
|
763
|
+
return;
|
|
764
|
+
if (node.kind === 'layer') {
|
|
765
|
+
this._openLayerMenu(anchor, node);
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
popMenu(popupTargetFromElement(anchor), {
|
|
769
|
+
options: { items: [this._hideForEveryoneItem(node)] },
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* "Hide for everyone" (or "Show for everyone"), in a row's or a layer's
|
|
774
|
+
* menu alike: painted with the warning tokens, and written on the element
|
|
775
|
+
* or on the layer's record (`hidden: true`) depending on the row.
|
|
776
|
+
*/
|
|
777
|
+
_hideForEveryoneItem(node) {
|
|
778
|
+
const wording = node.hiddenForEveryone
|
|
779
|
+
? SELECTION_PANE_SHOW_FOR_EVERYONE
|
|
780
|
+
: SELECTION_PANE_HIDE_FOR_EVERYONE;
|
|
781
|
+
const target = node.kind === 'layer' ? { layerIds: [node.id] } : { ids: [node.id] };
|
|
782
|
+
return menu.action({
|
|
783
|
+
name: translateKey(this.std, ...wording),
|
|
784
|
+
prefix: node.hiddenForEveryone ? ViewIcon() : InvisibleIcon(),
|
|
785
|
+
class: { 'warning-item': true },
|
|
786
|
+
testId: 'selection-pane-hide-for-everyone',
|
|
787
|
+
select: () => {
|
|
788
|
+
this._run('canvas.visibility.hideForEveryone', {
|
|
789
|
+
...target,
|
|
790
|
+
hidden: !node.hiddenForEveryone,
|
|
791
|
+
});
|
|
792
|
+
},
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* A layer's menu (ADR 0031 stage 7): "Hide for everyone" — `hidden: true`
|
|
797
|
+
* on the record, painted with the warning tokens like the element entry —
|
|
798
|
+
* and "Delete layer", which takes the members with it in one undo step.
|
|
799
|
+
* The default layer cannot be deleted, so its menu has no such entry.
|
|
800
|
+
*/
|
|
801
|
+
_openLayerMenu(anchor, node) {
|
|
802
|
+
popMenu(popupTargetFromElement(anchor), {
|
|
803
|
+
options: {
|
|
804
|
+
items: [
|
|
805
|
+
this._hideForEveryoneItem(node),
|
|
806
|
+
menu.action({
|
|
807
|
+
name: translateKey(this.std, ...SELECTION_PANE_DELETE_LAYER),
|
|
808
|
+
prefix: DeleteIcon(),
|
|
809
|
+
class: { 'delete-item': true },
|
|
810
|
+
testId: 'selection-pane-delete-layer',
|
|
811
|
+
hide: () => node.id === DEFAULT_LAYER_ID,
|
|
812
|
+
select: () => {
|
|
813
|
+
this._run('canvas.layer.delete', { id: node.id });
|
|
814
|
+
},
|
|
815
|
+
}),
|
|
816
|
+
],
|
|
817
|
+
},
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
_onRowContextMenu(event, node) {
|
|
821
|
+
event.preventDefault();
|
|
822
|
+
event.stopPropagation();
|
|
823
|
+
this._openRowMenu(event.currentTarget, node);
|
|
824
|
+
}
|
|
825
|
+
_commitRename(id, input) {
|
|
826
|
+
if (this._renaming !== id)
|
|
827
|
+
return;
|
|
828
|
+
this._renaming = null;
|
|
829
|
+
if (this._layerName(id) !== null) {
|
|
830
|
+
this._run('canvas.layer.rename', { id, name: input.value });
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
const frame = this._gfx.getElementById(id) instanceof FrameBlockModel;
|
|
834
|
+
this._run(frame ? 'canvas.frame.rename' : 'canvas.group.rename', {
|
|
835
|
+
id,
|
|
836
|
+
title: input.value,
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
/* ── Drag to reorder ────────────────────────────────────────────────── */
|
|
840
|
+
/*
|
|
841
|
+
* The gesture is the side panels' one controller (`createPanelReorderDrag`,
|
|
842
|
+
* `@labre/affine-shared/utils`, ADR 0034), shared with the frame panel:
|
|
843
|
+
* threshold, read-only refusal, mask and cursor, Escape and `pointercancel`
|
|
844
|
+
* as cancels, the swallowed click. What is the pane's own is below: which
|
|
845
|
+
* rows move (the pressed row, or the whole selection of one stack), where a
|
|
846
|
+
* gap lands them in their stack, the ghost and the line, and the write.
|
|
847
|
+
*/
|
|
848
|
+
_createReorderDrag() {
|
|
849
|
+
return createPanelReorderDrag({
|
|
850
|
+
readonly: () => this.std.store.readonly,
|
|
851
|
+
rows: () => this._shownRows().map(({ element }) => element),
|
|
852
|
+
bounds: () => this._paneBody(),
|
|
853
|
+
onPickUp: () => this._pickUp(),
|
|
854
|
+
dropAt: (gap, point) => this._dropAt(gap, point.clientY),
|
|
855
|
+
onMove: (drop, point) => {
|
|
856
|
+
this._drop = drop;
|
|
857
|
+
const panel = this._panel();
|
|
858
|
+
if (!panel)
|
|
859
|
+
return;
|
|
860
|
+
const box = panel.getBoundingClientRect();
|
|
861
|
+
this._ghost = {
|
|
862
|
+
x: point.clientX - box.left,
|
|
863
|
+
y: point.clientY - box.top,
|
|
864
|
+
};
|
|
865
|
+
},
|
|
866
|
+
onDrop: drop => this._commitDrop(drop),
|
|
867
|
+
onEnd: () => {
|
|
868
|
+
this._drag = null;
|
|
869
|
+
this._drop = null;
|
|
870
|
+
this._ghost = null;
|
|
871
|
+
},
|
|
872
|
+
mask: {
|
|
873
|
+
host: () => this._panel(),
|
|
874
|
+
className: 'selection-pane-drag-mask',
|
|
875
|
+
testId: 'selection-pane-drag-mask',
|
|
876
|
+
},
|
|
877
|
+
stateHost: () => this._panel(),
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
_panel() {
|
|
881
|
+
return (this.shadowRoot?.querySelector('[data-testid="selection-pane-panel"]') ?? null);
|
|
882
|
+
}
|
|
883
|
+
_paneBody() {
|
|
884
|
+
return (this.shadowRoot?.querySelector('[data-testid="selection-pane-body"]') ?? null);
|
|
885
|
+
}
|
|
886
|
+
/** The rows on screen, top first, with the rows they draw. */
|
|
887
|
+
_shownRows() {
|
|
888
|
+
const body = this._paneBody();
|
|
889
|
+
if (!body)
|
|
890
|
+
return [];
|
|
891
|
+
const byId = new Map(this._visibleRows.map(row => [row.node.id, row]));
|
|
892
|
+
return Array.from(body.querySelectorAll('[data-testid="selection-pane-row"], [data-testid="selection-pane-layer"]')).flatMap(element => {
|
|
893
|
+
const row = byId.get(element.dataset.id ?? '');
|
|
894
|
+
return row ? [{ element, row }] : [];
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
_onRowPointerDown(event, row) {
|
|
898
|
+
const target = event.target;
|
|
899
|
+
if (target.closest('button, input'))
|
|
900
|
+
return;
|
|
901
|
+
this._pressed = {
|
|
902
|
+
row,
|
|
903
|
+
width: event.currentTarget.getBoundingClientRect().width,
|
|
904
|
+
};
|
|
905
|
+
this._reorder?.press(event);
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* The press became a drag. A canvas row picked up is selected, as the frame
|
|
909
|
+
* panel selects a card — unless it already is, and then the whole selection
|
|
910
|
+
* moves with it, as in the frame panel: every selected row the pane lists.
|
|
911
|
+
* Rows that are not all in the pressed row's stack and list have no one
|
|
912
|
+
* place to land, so every drop of theirs is refused, honestly, with a
|
|
913
|
+
* `not-allowed` cursor rather than a line that would write nothing.
|
|
914
|
+
*/
|
|
915
|
+
_pickUp() {
|
|
916
|
+
const pressed = this._pressed;
|
|
917
|
+
if (!pressed)
|
|
918
|
+
return;
|
|
919
|
+
const { node, parent } = pressed.row;
|
|
920
|
+
const drag = {
|
|
921
|
+
id: node.id,
|
|
922
|
+
kind: node.kind,
|
|
923
|
+
parent,
|
|
924
|
+
width: pressed.width,
|
|
925
|
+
moving: new Set([node.id]),
|
|
926
|
+
refused: false,
|
|
927
|
+
};
|
|
928
|
+
if (node.kind !== 'layer') {
|
|
929
|
+
const { selection } = this._gfx;
|
|
930
|
+
if (selection.selectedIds.includes(node.id)) {
|
|
931
|
+
const listed = selection.selectedIds.filter(id => this._lists.parentOf.has(id));
|
|
932
|
+
drag.moving = new Set([node.id, ...listed]);
|
|
933
|
+
const stackOf = this._stackOf(drag);
|
|
934
|
+
drag.refused = [...drag.moving].some(id => this._lists.parentOf.get(id) !== parent || stackOf?.(id) !== id);
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
selection.set({ elements: [node.id], editing: false });
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
this._drag = drag;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Which model stands for a row in the dragged row's own stack — the stack
|
|
944
|
+
* `canvas.element.reorder` restacks it in, the models sharing its raw
|
|
945
|
+
* `group` — or `undefined` for a row outside it. A frame's members paint
|
|
946
|
+
* together right above the frame, so for a loose element they stand for
|
|
947
|
+
* their frame. `null` when the dragged row cannot be restacked at all (a
|
|
948
|
+
* mindmap node moves with its mindmap).
|
|
949
|
+
*/
|
|
950
|
+
_stackOf(drag) {
|
|
951
|
+
if (drag.kind === 'layer')
|
|
952
|
+
return id => id;
|
|
953
|
+
const gfx = this._gfx;
|
|
954
|
+
const dragged = gfx.getElementById(drag.id);
|
|
955
|
+
if (!dragged)
|
|
956
|
+
return null;
|
|
957
|
+
const stack = rawGroupOf(dragged);
|
|
958
|
+
if (stack instanceof MindmapElementModel)
|
|
959
|
+
return null;
|
|
960
|
+
return id => {
|
|
961
|
+
let model = gfx.getElementById(id);
|
|
962
|
+
for (let hops = 0; model && hops < 32; hops++) {
|
|
963
|
+
const group = rawGroupOf(model);
|
|
964
|
+
if (group === stack)
|
|
965
|
+
return model.id;
|
|
966
|
+
model = group;
|
|
967
|
+
}
|
|
968
|
+
return undefined;
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Where a release over the gap `gap` (the controller's count of rows whose
|
|
973
|
+
* middle is above the pointer, at `clientY`) would land the dragged rows,
|
|
974
|
+
* or `null` to refuse it.
|
|
975
|
+
*/
|
|
976
|
+
_dropAt(gap, clientY) {
|
|
977
|
+
const drag = this._drag;
|
|
978
|
+
if (!drag || drag.refused)
|
|
979
|
+
return null;
|
|
980
|
+
const shown = this._shownRows();
|
|
981
|
+
// A canvas row over a layer's header moves INTO that layer (§5).
|
|
982
|
+
if (drag.kind !== 'layer') {
|
|
983
|
+
const header = shown.find(({ element, row }) => {
|
|
984
|
+
if (row.node.kind !== 'layer')
|
|
985
|
+
return false;
|
|
986
|
+
const rect = element.getBoundingClientRect();
|
|
987
|
+
return clientY >= rect.top && clientY <= rect.bottom;
|
|
988
|
+
});
|
|
989
|
+
if (header)
|
|
990
|
+
return { kind: 'into', id: header.row.node.id };
|
|
991
|
+
}
|
|
992
|
+
const stackOf = this._stackOf(drag);
|
|
993
|
+
const slot = stackOf
|
|
994
|
+
? paneSlotAtGap(shown.map(({ row }) => row), gap, drag.parent, this._lists)
|
|
995
|
+
: null;
|
|
996
|
+
const list = slot ? this._lists.lists.get(slot.parent) : undefined;
|
|
997
|
+
const landing = slot && list && stackOf
|
|
998
|
+
? paneDropAbove(list, slot.index, drag.moving, stackOf)
|
|
999
|
+
: null;
|
|
1000
|
+
if (!slot || !landing)
|
|
1001
|
+
return null;
|
|
1002
|
+
const under = shown[gap]?.element;
|
|
1003
|
+
const last = shown[shown.length - 1]?.element;
|
|
1004
|
+
const top = under
|
|
1005
|
+
? under.offsetTop
|
|
1006
|
+
: last
|
|
1007
|
+
? last.offsetTop + last.offsetHeight
|
|
1008
|
+
: 0;
|
|
1009
|
+
return {
|
|
1010
|
+
kind: 'slot',
|
|
1011
|
+
above: landing.above,
|
|
1012
|
+
top,
|
|
1013
|
+
left: 8 + slot.depth * INDENT_PX,
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* One write per gesture, through the command: `layer` for a drop into a
|
|
1018
|
+
* layer, one restack for a slot. The command writes nothing when the slot
|
|
1019
|
+
* is where the rows already are, and a refused drop never reaches it.
|
|
1020
|
+
*/
|
|
1021
|
+
_commitDrop(drop) {
|
|
1022
|
+
const drag = this._drag;
|
|
1023
|
+
if (!drag)
|
|
1024
|
+
return;
|
|
1025
|
+
const ids = [...drag.moving];
|
|
1026
|
+
if (drop.kind === 'into') {
|
|
1027
|
+
this._run('canvas.layer.moveElements', { ids, layerId: drop.id });
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
if (drag.kind === 'layer') {
|
|
1031
|
+
this._run('canvas.layer.reorder', { id: drag.id, above: drop.above });
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
this._run('canvas.element.reorder', { ids, above: drop.above });
|
|
1035
|
+
}
|
|
1036
|
+
_renderGhost() {
|
|
1037
|
+
const drag = this._drag;
|
|
1038
|
+
const at = this._ghost;
|
|
1039
|
+
if (!drag || !at)
|
|
1040
|
+
return nothing;
|
|
1041
|
+
const style = styleMap({
|
|
1042
|
+
transform: `translate(${at.x - 16}px, ${at.y - 8}px)`,
|
|
1043
|
+
width: `${drag.width}px`,
|
|
1044
|
+
});
|
|
1045
|
+
if (drag.kind === 'layer') {
|
|
1046
|
+
return html `<div
|
|
1047
|
+
class="selection-pane-drag-ghost"
|
|
1048
|
+
data-testid="selection-pane-drag-ghost"
|
|
1049
|
+
style=${style}
|
|
1050
|
+
>
|
|
1051
|
+
<span class="selection-pane-icon">${LayerIcon()}</span>
|
|
1052
|
+
<span class="selection-pane-label"
|
|
1053
|
+
>${this._layerName(drag.id) ?? ''}</span
|
|
1054
|
+
>
|
|
1055
|
+
</div>`;
|
|
1056
|
+
}
|
|
1057
|
+
const model = this._gfx.getElementById(drag.id);
|
|
1058
|
+
if (!model)
|
|
1059
|
+
return nothing;
|
|
1060
|
+
const type = model instanceof GfxBlockElementModel
|
|
1061
|
+
? model.flavour
|
|
1062
|
+
: model.type;
|
|
1063
|
+
const count = drag.moving.size;
|
|
1064
|
+
return html `<div
|
|
1065
|
+
class="selection-pane-drag-ghost"
|
|
1066
|
+
data-testid="selection-pane-drag-ghost"
|
|
1067
|
+
style=${style}
|
|
1068
|
+
>
|
|
1069
|
+
<span class="selection-pane-icon">${selectionPaneRowIcon(type)}</span>
|
|
1070
|
+
<span class="selection-pane-label"
|
|
1071
|
+
>${selectionPaneRowLabel(this.std, model)}</span
|
|
1072
|
+
>
|
|
1073
|
+
${count > 1
|
|
1074
|
+
? html `<span
|
|
1075
|
+
class="selection-pane-drag-count"
|
|
1076
|
+
data-testid="selection-pane-drag-count"
|
|
1077
|
+
>${count}</span
|
|
1078
|
+
>`
|
|
1079
|
+
: nothing}
|
|
1080
|
+
</div>`;
|
|
1081
|
+
}
|
|
1082
|
+
_renderDropIndicator() {
|
|
1083
|
+
const drop = this._drop;
|
|
1084
|
+
if (!this._drag || drop?.kind !== 'slot')
|
|
1085
|
+
return nothing;
|
|
1086
|
+
return html `<div
|
|
1087
|
+
class="selection-pane-drop-indicator"
|
|
1088
|
+
data-testid="selection-pane-drop-indicator"
|
|
1089
|
+
style=${styleMap({ top: `${drop.top}px`, left: `${drop.left}px` })}
|
|
1090
|
+
></div>`;
|
|
1091
|
+
}
|
|
1092
|
+
/* ── Filter ─────────────────────────────────────────────────────────── */
|
|
1093
|
+
_filterName(id) {
|
|
1094
|
+
const model = this._gfx.getElementById(id);
|
|
1095
|
+
return model ? selectionPaneRowLabel(this.std, model) : id;
|
|
1096
|
+
}
|
|
1097
|
+
_filterWording(id) {
|
|
1098
|
+
return translateKey(this.std, ...SELECTION_PANE_FILTER_FRAME, {
|
|
1099
|
+
name: this._filterName(id),
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
/* ── Render ─────────────────────────────────────────────────────────── */
|
|
1103
|
+
/**
|
|
1104
|
+
* A user layer's row (ADR 0031 §2): its name, renamed in place with a
|
|
1105
|
+
* double-click; a click makes it the active layer; collapsible like a
|
|
1106
|
+
* group (UI state, never stored); dragged among the layers to reorder, and
|
|
1107
|
+
* the drop target of a canvas row dragged onto it. The default layer's row
|
|
1108
|
+
* is drawn the same before it has a record (ADR 0031 amendments): its
|
|
1109
|
+
* rename or "hide for everyone" is what records it.
|
|
1110
|
+
*/
|
|
1111
|
+
_renderLayerRow(row) {
|
|
1112
|
+
const { node, depth } = row;
|
|
1113
|
+
const std = this.std;
|
|
1114
|
+
const name = this._layerName(node.id) ?? '';
|
|
1115
|
+
const collapsed = this._collapsed.has(node.id);
|
|
1116
|
+
const active = (std.getOptional(CanvasActiveLayer)?.resolve() ?? null) === node.id;
|
|
1117
|
+
const drop = this._drop?.kind === 'into' && this._drop.id === node.id
|
|
1118
|
+
? 'into'
|
|
1119
|
+
: undefined;
|
|
1120
|
+
const dragging = this._drag?.moving.has(node.id) ?? false;
|
|
1121
|
+
return html `<div
|
|
1122
|
+
class="selection-pane-row selection-pane-layer-row"
|
|
1123
|
+
role="treeitem"
|
|
1124
|
+
data-testid="selection-pane-layer"
|
|
1125
|
+
data-id=${node.id}
|
|
1126
|
+
data-kind="layer"
|
|
1127
|
+
aria-level=${depth + 1}
|
|
1128
|
+
aria-expanded=${collapsed ? 'false' : 'true'}
|
|
1129
|
+
title=${active
|
|
1130
|
+
? translateKey(std, ...SELECTION_PANE_ACTIVE_LAYER)
|
|
1131
|
+
: nothing}
|
|
1132
|
+
?data-active=${active}
|
|
1133
|
+
?data-hidden-local=${node.hiddenLocal}
|
|
1134
|
+
?data-hidden-everyone=${node.hiddenForEveryone}
|
|
1135
|
+
?data-dragging=${dragging}
|
|
1136
|
+
data-drop=${drop ?? nothing}
|
|
1137
|
+
style=${styleMap({ paddingLeft: `${8 + depth * INDENT_PX}px` })}
|
|
1138
|
+
@click=${(event) => this._onRowClick(event, node)}
|
|
1139
|
+
@dblclick=${() => this._onRowDblClick(node)}
|
|
1140
|
+
@contextmenu=${(event) => this._onRowContextMenu(event, node)}
|
|
1141
|
+
@pointerdown=${(event) => this._onRowPointerDown(event, row)}
|
|
1142
|
+
>
|
|
1143
|
+
<button
|
|
1144
|
+
class="selection-pane-chevron"
|
|
1145
|
+
type="button"
|
|
1146
|
+
data-testid="selection-pane-collapse"
|
|
1147
|
+
aria-label=${translateKey(std, ...(collapsed ? SELECTION_PANE_EXPAND : SELECTION_PANE_COLLAPSE))}
|
|
1148
|
+
@click=${(event) => {
|
|
1149
|
+
event.stopPropagation();
|
|
1150
|
+
this._toggleCollapsed(node.id);
|
|
1151
|
+
}}
|
|
1152
|
+
>
|
|
1153
|
+
${collapsed ? ArrowRightSmallIcon() : ArrowDownSmallIcon()}
|
|
1154
|
+
</button>
|
|
1155
|
+
<span class="selection-pane-icon">${LayerIcon()}</span>
|
|
1156
|
+
${this._renderName(node.id, name)} ${this._renderEye(node)}
|
|
1157
|
+
${std.store.readonly
|
|
1158
|
+
? nothing
|
|
1159
|
+
: html `<button
|
|
1160
|
+
class="selection-pane-more"
|
|
1161
|
+
type="button"
|
|
1162
|
+
data-testid="selection-pane-more"
|
|
1163
|
+
aria-haspopup="menu"
|
|
1164
|
+
aria-label=${translateKey(std, ...SELECTION_PANE_ROW_MENU)}
|
|
1165
|
+
@click=${(event) => {
|
|
1166
|
+
event.stopPropagation();
|
|
1167
|
+
this._openRowMenu(event.currentTarget, node);
|
|
1168
|
+
}}
|
|
1169
|
+
>
|
|
1170
|
+
${MoreHorizontalIcon()}
|
|
1171
|
+
</button>`}
|
|
1172
|
+
</div>
|
|
1173
|
+
${row.hiddenByFilter && !collapsed
|
|
1174
|
+
? html `<div
|
|
1175
|
+
class="selection-pane-layer-note"
|
|
1176
|
+
data-testid="selection-pane-layer-filtered"
|
|
1177
|
+
data-id=${node.id}
|
|
1178
|
+
style=${styleMap({
|
|
1179
|
+
paddingLeft: `${8 + (depth + 1) * INDENT_PX + 28}px`,
|
|
1180
|
+
})}
|
|
1181
|
+
>
|
|
1182
|
+
${translateKey(std, ...SELECTION_PANE_LAYER_FILTERED, {
|
|
1183
|
+
count: row.hiddenByFilter,
|
|
1184
|
+
})}
|
|
1185
|
+
</div>`
|
|
1186
|
+
: nothing}`;
|
|
1187
|
+
}
|
|
1188
|
+
/** A row's name, or the field that renames it in place. */
|
|
1189
|
+
_renderName(id, name) {
|
|
1190
|
+
if (this._renaming !== id) {
|
|
1191
|
+
return html `<span class="selection-pane-label" title=${name}
|
|
1192
|
+
>${name}</span
|
|
1193
|
+
>`;
|
|
1194
|
+
}
|
|
1195
|
+
return html `<input
|
|
1196
|
+
class="selection-pane-rename"
|
|
1197
|
+
data-testid="selection-pane-rename"
|
|
1198
|
+
aria-label=${translateKey(this.std, ...TOOLBAR_RENAME)}
|
|
1199
|
+
.value=${name}
|
|
1200
|
+
@click=${this._swallow}
|
|
1201
|
+
@dblclick=${this._swallow}
|
|
1202
|
+
@keydown=${(event) => this._onRenameKeydown(event, id)}
|
|
1203
|
+
@blur=${(event) => this._commitRename(id, event.target)}
|
|
1204
|
+
/>`;
|
|
1205
|
+
}
|
|
1206
|
+
/** A row's eye: hide it, or the whole layer, for this viewer only. */
|
|
1207
|
+
_renderEye(node) {
|
|
1208
|
+
return html `<button
|
|
1209
|
+
class="selection-pane-eye"
|
|
1210
|
+
type="button"
|
|
1211
|
+
data-testid="selection-pane-eye"
|
|
1212
|
+
aria-pressed=${node.hiddenLocal ? 'true' : 'false'}
|
|
1213
|
+
aria-label=${translateKey(this.std, ...(node.hiddenLocal ? SELECTION_PANE_SHOW : SELECTION_PANE_HIDE))}
|
|
1214
|
+
@click=${(event) => this._onEyeClick(event, node)}
|
|
1215
|
+
>
|
|
1216
|
+
${node.hiddenLocal ? InvisibleIcon() : ViewIcon()}
|
|
1217
|
+
</button>`;
|
|
1218
|
+
}
|
|
1219
|
+
_renderRow(row) {
|
|
1220
|
+
const { node, depth } = row;
|
|
1221
|
+
if (node.kind === 'layer')
|
|
1222
|
+
return this._renderLayerRow(row);
|
|
1223
|
+
const std = this.std;
|
|
1224
|
+
const model = this._gfx.getElementById(node.id);
|
|
1225
|
+
if (!model)
|
|
1226
|
+
return nothing;
|
|
1227
|
+
const label = selectionPaneRowLabel(std, model);
|
|
1228
|
+
const selected = this._gfx.selection.has(node.id);
|
|
1229
|
+
const container = node.children !== undefined;
|
|
1230
|
+
const collapsed = this._collapsed.has(node.id);
|
|
1231
|
+
const readonly = std.store.readonly;
|
|
1232
|
+
const drop = this._drop?.kind === 'into' && this._drop.id === node.id
|
|
1233
|
+
? 'into'
|
|
1234
|
+
: undefined;
|
|
1235
|
+
const dragging = this._drag?.moving.has(node.id) ?? false;
|
|
1236
|
+
return html `<div
|
|
1237
|
+
class="selection-pane-row"
|
|
1238
|
+
role="treeitem"
|
|
1239
|
+
data-testid="selection-pane-row"
|
|
1240
|
+
data-id=${node.id}
|
|
1241
|
+
data-type=${node.type}
|
|
1242
|
+
data-kind=${node.kind}
|
|
1243
|
+
aria-level=${depth + 1}
|
|
1244
|
+
aria-selected=${selected ? 'true' : 'false'}
|
|
1245
|
+
aria-expanded=${container ? (collapsed ? 'false' : 'true') : nothing}
|
|
1246
|
+
?data-selected=${selected}
|
|
1247
|
+
?data-locked=${node.locked}
|
|
1248
|
+
?data-hidden-local=${node.hiddenLocal}
|
|
1249
|
+
?data-hidden-everyone=${node.hiddenForEveryone}
|
|
1250
|
+
?data-dragging=${dragging}
|
|
1251
|
+
data-drop=${drop ?? nothing}
|
|
1252
|
+
style=${styleMap({ paddingLeft: `${8 + depth * INDENT_PX}px` })}
|
|
1253
|
+
@click=${(event) => this._onRowClick(event, node)}
|
|
1254
|
+
@contextmenu=${(event) => this._onRowContextMenu(event, node)}
|
|
1255
|
+
@dblclick=${() => this._onRowDblClick(node)}
|
|
1256
|
+
@pointerenter=${() => this._highlight(node.id)}
|
|
1257
|
+
@pointerdown=${(event) => this._onRowPointerDown(event, row)}
|
|
1258
|
+
>
|
|
1259
|
+
<button
|
|
1260
|
+
class="selection-pane-chevron"
|
|
1261
|
+
type="button"
|
|
1262
|
+
data-testid="selection-pane-collapse"
|
|
1263
|
+
?hidden=${!container}
|
|
1264
|
+
aria-label=${translateKey(std, ...(collapsed ? SELECTION_PANE_EXPAND : SELECTION_PANE_COLLAPSE))}
|
|
1265
|
+
@click=${(event) => {
|
|
1266
|
+
event.stopPropagation();
|
|
1267
|
+
this._toggleCollapsed(node.id);
|
|
1268
|
+
}}
|
|
1269
|
+
>
|
|
1270
|
+
${collapsed ? ArrowRightSmallIcon() : ArrowDownSmallIcon()}
|
|
1271
|
+
</button>
|
|
1272
|
+
<span class="selection-pane-icon"
|
|
1273
|
+
>${selectionPaneRowIcon(node.type)}</span
|
|
1274
|
+
>
|
|
1275
|
+
${this._renderName(node.id, label)} ${this._renderEye(node)}
|
|
1276
|
+
<button
|
|
1277
|
+
class="selection-pane-lock"
|
|
1278
|
+
type="button"
|
|
1279
|
+
data-testid="selection-pane-lock"
|
|
1280
|
+
aria-pressed=${node.locked ? 'true' : 'false'}
|
|
1281
|
+
aria-label=${translateKey(std, ...(node.locked ? SELECTION_PANE_UNLOCK : TOOLBAR_LOCK))}
|
|
1282
|
+
?disabled=${readonly}
|
|
1283
|
+
@click=${(event) => this._onLockClick(event, node)}
|
|
1284
|
+
>
|
|
1285
|
+
${node.locked ? LockIcon() : UnlockIcon()}
|
|
1286
|
+
</button>
|
|
1287
|
+
${readonly
|
|
1288
|
+
? nothing
|
|
1289
|
+
: html `<button
|
|
1290
|
+
class="selection-pane-more"
|
|
1291
|
+
type="button"
|
|
1292
|
+
data-testid="selection-pane-more"
|
|
1293
|
+
aria-haspopup="menu"
|
|
1294
|
+
aria-label=${translateKey(std, ...SELECTION_PANE_ROW_MENU)}
|
|
1295
|
+
@click=${(event) => {
|
|
1296
|
+
event.stopPropagation();
|
|
1297
|
+
this._openRowMenu(event.currentTarget, node);
|
|
1298
|
+
}}
|
|
1299
|
+
>
|
|
1300
|
+
${MoreHorizontalIcon()}
|
|
1301
|
+
</button>`}
|
|
1302
|
+
</div>`;
|
|
1303
|
+
}
|
|
1304
|
+
updated() {
|
|
1305
|
+
const input = this.shadowRoot?.querySelector('[data-testid="selection-pane-rename"]');
|
|
1306
|
+
if (input && this.shadowRoot?.activeElement !== input) {
|
|
1307
|
+
input.focus();
|
|
1308
|
+
input.select();
|
|
1309
|
+
// A layer just created may sit above the scrolled-to rows: bring its
|
|
1310
|
+
// field into view, so the creation is seen where it happened.
|
|
1311
|
+
input.scrollIntoView({ block: 'nearest' });
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1315
|
+
* One header action, in the frame panel's icon button
|
|
1316
|
+
* (`header/frame-panel-header.ts`): a 20px glyph in `edgeless-tool-icon-button`,
|
|
1317
|
+
* secondary until hovered, its tooltip above it, a wash while active.
|
|
1318
|
+
*/
|
|
1319
|
+
_renderHeadButton(testId, label, icon, onClick, active = false) {
|
|
1320
|
+
return html `<edgeless-tool-icon-button
|
|
1321
|
+
class="affine-panel-header-button ${active ? 'active' : ''}"
|
|
1322
|
+
data-testid=${testId}
|
|
1323
|
+
aria-label=${label}
|
|
1324
|
+
.tooltip=${label}
|
|
1325
|
+
.tipPosition=${'top'}
|
|
1326
|
+
.active=${active}
|
|
1327
|
+
.activeMode=${'background'}
|
|
1328
|
+
@click=${onClick}
|
|
1329
|
+
>
|
|
1330
|
+
${icon({ width: '20px', height: '20px' })}
|
|
1331
|
+
</edgeless-tool-icon-button>`;
|
|
1332
|
+
}
|
|
1333
|
+
render() {
|
|
1334
|
+
if (!this._open)
|
|
1335
|
+
return nothing;
|
|
1336
|
+
// Read for its dependency: the rows repaint when the canvas selection does.
|
|
1337
|
+
this._selectionRevision;
|
|
1338
|
+
const full = selectionPaneTree(this.std).value;
|
|
1339
|
+
let tree = full;
|
|
1340
|
+
let filterLabel = null;
|
|
1341
|
+
if (this._filter !== null) {
|
|
1342
|
+
const members = selectionPaneFilterMembers(this.std, this._filter);
|
|
1343
|
+
const target = selectionPaneFilterTargets(this.std).find(candidate => candidate.id === this._filter);
|
|
1344
|
+
if (members && target) {
|
|
1345
|
+
tree = filterSelectionPaneTree(tree, members);
|
|
1346
|
+
filterLabel = this._filterWording(target.id);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
const rows = this._rows(tree, full);
|
|
1350
|
+
this._visibleRows = rows;
|
|
1351
|
+
this._lists = paneLists(full);
|
|
1352
|
+
const title = translateKey(this.std, ...SELECTION_PANE_TITLE);
|
|
1353
|
+
// `pointermove` too: the editor turns every move over the host into a
|
|
1354
|
+
// cursor selection, and a selection with nothing recoverable in it makes
|
|
1355
|
+
// the range binding focus the host — which blurred a layer's rename field
|
|
1356
|
+
// the moment the pointer moved (a group's survived only because its click
|
|
1357
|
+
// had selected it). The pane's own drag listens on the document, in the
|
|
1358
|
+
// capture phase, so it still sees every move. Its `data-drag` and its
|
|
1359
|
+
// mask are the drag controller's, set outside this template.
|
|
1360
|
+
return html `<div
|
|
1361
|
+
class="selection-pane-panel"
|
|
1362
|
+
role="dialog"
|
|
1363
|
+
tabindex="-1"
|
|
1364
|
+
aria-label=${title}
|
|
1365
|
+
data-testid="selection-pane-panel"
|
|
1366
|
+
@pointerdown=${this._swallow}
|
|
1367
|
+
@pointerup=${this._swallow}
|
|
1368
|
+
@pointermove=${this._swallow}
|
|
1369
|
+
@click=${this._swallow}
|
|
1370
|
+
@dblclick=${this._swallow}
|
|
1371
|
+
>
|
|
1372
|
+
<div
|
|
1373
|
+
class="selection-pane-head affine-panel-header"
|
|
1374
|
+
data-testid="selection-pane-header"
|
|
1375
|
+
>
|
|
1376
|
+
<span
|
|
1377
|
+
class="affine-panel-header-title"
|
|
1378
|
+
data-testid="selection-pane-title"
|
|
1379
|
+
>${title}</span
|
|
1380
|
+
>
|
|
1381
|
+
<div class="selection-pane-actions">
|
|
1382
|
+
${this.std.store.readonly
|
|
1383
|
+
? nothing
|
|
1384
|
+
: this._renderHeadButton('selection-pane-new-layer', translateKey(this.std, ...SELECTION_PANE_NEW_LAYER), PlusIcon, this._createLayer)}
|
|
1385
|
+
${this._renderHeadButton('selection-pane-filter', translateKey(this.std, ...SELECTION_PANE_FILTER), FilterIcon, this._openFilterMenu, filterLabel !== null)}
|
|
1386
|
+
${this._renderHeadButton('selection-pane-close', translateKey(this.std, ...SELECTION_PANE_CLOSE), CloseIcon, this.closePanel)}
|
|
1387
|
+
</div>
|
|
1388
|
+
</div>
|
|
1389
|
+
${filterLabel !== null
|
|
1390
|
+
? html `<div
|
|
1391
|
+
class="selection-pane-filter-label"
|
|
1392
|
+
data-testid="selection-pane-filter-label"
|
|
1393
|
+
>
|
|
1394
|
+
${filterLabel}
|
|
1395
|
+
</div>`
|
|
1396
|
+
: nothing}
|
|
1397
|
+
<div
|
|
1398
|
+
class="selection-pane-body"
|
|
1399
|
+
role="tree"
|
|
1400
|
+
aria-label=${title}
|
|
1401
|
+
data-testid="selection-pane-body"
|
|
1402
|
+
@pointerleave=${() => this._clearHighlight()}
|
|
1403
|
+
>
|
|
1404
|
+
${rows.length
|
|
1405
|
+
? repeat(rows, row => row.node.id, row => this._renderRow(row))
|
|
1406
|
+
: html `<div class="selection-pane-empty">
|
|
1407
|
+
${translateKey(this.std, ...SELECTION_PANE_EMPTY)}
|
|
1408
|
+
</div>`}
|
|
1409
|
+
${this._renderDropIndicator()}
|
|
1410
|
+
</div>
|
|
1411
|
+
${this._renderGhost()}
|
|
1412
|
+
</div>`;
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
})();
|
|
1416
|
+
export { EdgelessSelectionPaneWidget };
|
|
1417
|
+
export const edgelessSelectionPaneWidget = WidgetViewExtension('affine:page', EDGELESS_SELECTION_PANE_WIDGET, literal `${unsafeStatic(EDGELESS_SELECTION_PANE_WIDGET)}`);
|