@formicoidea/labre-core 0.49.0 → 0.51.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/asset-picker.d.ts +24 -0
- package/dist/_pkgs/affine-block-attachment/asset-picker.js +87 -0
- package/dist/_pkgs/affine-block-attachment/configs/slash-menu.js +3 -20
- package/dist/_pkgs/affine-block-attachment/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-attachment/index.js +1 -0
- package/dist/_pkgs/affine-block-attachment/utils.d.ts +9 -1
- package/dist/_pkgs/affine-block-attachment/utils.js +9 -0
- package/dist/_pkgs/affine-block-bookmark/adapters/markdown/markdown.js +14 -1
- package/dist/_pkgs/affine-block-bookmark/adapters/notion-html.js +5 -1
- package/dist/_pkgs/affine-block-database/adapters/markdown.js +5 -3
- package/dist/_pkgs/affine-block-embed/common/adapters/html.js +5 -3
- package/dist/_pkgs/affine-block-embed/common/adapters/markdown.js +11 -0
- package/dist/_pkgs/affine-block-frame/frame-template.d.ts +58 -0
- package/dist/_pkgs/affine-block-frame/frame-template.js +207 -0
- package/dist/_pkgs/affine-block-frame/frame-toolbar.js +19 -3
- package/dist/_pkgs/affine-block-frame/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-frame/index.js +1 -0
- package/dist/_pkgs/affine-block-frame/translations.d.ts +7 -0
- package/dist/_pkgs/affine-block-frame/translations.js +16 -1
- package/dist/_pkgs/affine-block-frame/view.js +6 -0
- package/dist/_pkgs/affine-block-image/asset-picker.d.ts +63 -0
- package/dist/_pkgs/affine-block-image/asset-picker.js +183 -0
- package/dist/_pkgs/affine-block-image/commands/insert-images.d.ts +5 -0
- package/dist/_pkgs/affine-block-image/commands/insert-images.js +8 -8
- package/dist/_pkgs/affine-block-image/components/page-image-block.d.ts +11 -0
- package/dist/_pkgs/affine-block-image/components/page-image-block.js +81 -12
- package/dist/_pkgs/affine-block-image/configs/replace-action.d.ts +9 -0
- package/dist/_pkgs/affine-block-image/configs/replace-action.js +27 -0
- package/dist/_pkgs/affine-block-image/configs/toolbar.js +6 -0
- package/dist/_pkgs/affine-block-image/crop/crop-controller.d.ts +46 -0
- package/dist/_pkgs/affine-block-image/crop/crop-controller.js +104 -0
- package/dist/_pkgs/affine-block-image/crop/crop-math.d.ts +70 -0
- package/dist/_pkgs/affine-block-image/crop/crop-math.js +141 -0
- package/dist/_pkgs/affine-block-image/crop/crop-overlay.d.ts +57 -0
- package/dist/_pkgs/affine-block-image/crop/crop-overlay.js +343 -0
- package/dist/_pkgs/affine-block-image/crop/crop-toolbar.d.ts +12 -0
- package/dist/_pkgs/affine-block-image/crop/crop-toolbar.js +78 -0
- package/dist/_pkgs/affine-block-image/crop/write-crop.d.ts +16 -0
- package/dist/_pkgs/affine-block-image/crop/write-crop.js +57 -0
- package/dist/_pkgs/affine-block-image/edgeless-clipboard-config.js +4 -1
- package/dist/_pkgs/affine-block-image/effects.js +2 -0
- package/dist/_pkgs/affine-block-image/image-block.d.ts +2 -0
- package/dist/_pkgs/affine-block-image/image-block.js +2 -0
- package/dist/_pkgs/affine-block-image/image-edgeless-block.d.ts +2 -0
- package/dist/_pkgs/affine-block-image/image-edgeless-block.js +36 -8
- package/dist/_pkgs/affine-block-image/image-resize-manager.js +15 -0
- package/dist/_pkgs/affine-block-image/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-image/index.js +1 -0
- package/dist/_pkgs/affine-block-image/translations.d.ts +15 -0
- package/dist/_pkgs/affine-block-image/translations.js +43 -0
- package/dist/_pkgs/affine-block-image/utils.d.ts +13 -0
- package/dist/_pkgs/affine-block-image/utils.js +10 -1
- package/dist/_pkgs/affine-block-root/clipboard/page-clipboard.js +5 -0
- package/dist/_pkgs/affine-block-root/commands/page-export-commands.d.ts +2 -0
- package/dist/_pkgs/affine-block-root/commands/page-export-commands.js +71 -0
- package/dist/_pkgs/affine-block-root/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-root/index.js +1 -0
- package/dist/_pkgs/affine-block-root/view.js +8 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/capability.d.ts +30 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/capability.js +44 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/colors.d.ts +26 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/colors.js +82 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/command.d.ts +18 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/command.js +91 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/index.d.ts +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/index.js +3 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/writer.d.ts +50 -0
- package/dist/_pkgs/affine-block-surface/extensions/drawio-export/writer.js +732 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/draw-image-block.d.ts +12 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/draw-image-block.js +15 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +7 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.d.ts +7 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/command.js +60 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.d.ts +2 -2
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/index.js +2 -2
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/marker-version.d.ts +6 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/marker-version.js +8 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.d.ts +28 -1
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +66 -6
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.d.ts +2 -7
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/svg-context.js +2 -6
- package/dist/_pkgs/affine-block-surface/extensions/index.d.ts +2 -0
- package/dist/_pkgs/affine-block-surface/extensions/index.js +2 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-export.d.ts +84 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-export.js +150 -0
- package/dist/_pkgs/affine-block-surface/extensions/interchange-import.js +24 -2
- package/dist/_pkgs/affine-block-surface/extensions/interchange.d.ts +23 -2
- package/dist/_pkgs/affine-block-surface/extensions/interchange.js +4 -1
- package/dist/_pkgs/affine-block-surface/extensions/legend-role.d.ts +18 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend-role.js +20 -0
- package/dist/_pkgs/affine-block-surface/extensions/legend.d.ts +2 -19
- package/dist/_pkgs/affine-block-surface/extensions/legend.js +2 -18
- package/dist/_pkgs/affine-block-surface/extensions/svg-sanitize.d.ts +67 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sanitize.js +235 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch-translations.js +9 -0
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.d.ts +17 -13
- package/dist/_pkgs/affine-block-surface/extensions/svg-sketch.js +52 -80
- package/dist/_pkgs/affine-block-surface/extensions/xml-element.d.ts +98 -0
- package/dist/_pkgs/affine-block-surface/extensions/xml-element.js +261 -0
- package/dist/_pkgs/affine-block-surface/extensions/xml-reader.d.ts +238 -0
- package/dist/_pkgs/affine-block-surface/extensions/xml-reader.js +570 -0
- package/dist/_pkgs/affine-block-surface/framework-background/def.js +1 -1
- package/dist/_pkgs/affine-block-surface/interchange-headless.d.ts +29 -0
- package/dist/_pkgs/affine-block-surface/interchange-headless.js +32 -0
- package/dist/_pkgs/affine-block-surface/view.js +22 -2
- package/dist/_pkgs/affine-block-table/adapters/utils.js +24 -1
- package/dist/_pkgs/affine-components/color-picker/color-panel.d.ts +11 -0
- package/dist/_pkgs/affine-components/color-picker/color-panel.js +87 -12
- package/dist/_pkgs/affine-components/color-picker/framework-palette.d.ts +8 -0
- package/dist/_pkgs/affine-components/color-picker/framework-palette.js +11 -3
- package/dist/_pkgs/affine-components/color-picker/icons.d.ts +9 -0
- package/dist/_pkgs/affine-components/color-picker/icons.js +12 -0
- package/dist/_pkgs/affine-gfx-note/toolbar/note-menu.js +5 -8
- package/dist/_pkgs/affine-gfx-template/contribute.d.ts +14 -4
- package/dist/_pkgs/affine-gfx-template/contribute.js +47 -6
- package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.d.ts +7 -2
- package/dist/_pkgs/affine-gfx-template/toolbar/builtin-templates.js +14 -40
- package/dist/_pkgs/affine-gfx-template/toolbar/resolve-name.d.ts +1 -1
- package/dist/_pkgs/affine-gfx-template/toolbar/resolve-name.js +1 -1
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.d.ts +4 -4
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +9 -9
- package/dist/_pkgs/affine-gfx-template/toolbar/template-type.d.ts +2 -4
- package/dist/_pkgs/affine-gfx-template/translations.d.ts +5 -0
- package/dist/_pkgs/affine-gfx-template/translations.js +9 -0
- package/dist/_pkgs/affine-inline-footnote/adapters/markdown/inline-delta.js +6 -0
- package/dist/_pkgs/affine-inline-footnote/adapters/markdown/markdown-inline.js +7 -0
- package/dist/_pkgs/affine-inline-link/adapters/html/html-inline.js +4 -1
- package/dist/_pkgs/affine-inline-link/adapters/html/inline-delta.js +3 -1
- package/dist/_pkgs/affine-inline-link/adapters/markdown/inline-delta.js +4 -1
- package/dist/_pkgs/affine-inline-link/adapters/notion-html/html-inline.js +2 -1
- package/dist/_pkgs/affine-inline-link/link-node/affine-link.d.ts +7 -0
- package/dist/_pkgs/affine-inline-link/link-node/affine-link.js +37 -0
- package/dist/_pkgs/affine-inline-link/link-node/index.d.ts +1 -0
- package/dist/_pkgs/affine-inline-link/link-node/index.js +1 -0
- package/dist/_pkgs/affine-inline-link/link-node/propose-views.d.ts +22 -0
- package/dist/_pkgs/affine-inline-link/link-node/propose-views.js +59 -0
- package/dist/_pkgs/affine-model/blocks/database/types.d.ts +28 -0
- package/dist/_pkgs/affine-model/blocks/image/image-crop.d.ts +48 -0
- package/dist/_pkgs/affine-model/blocks/image/image-crop.js +78 -0
- package/dist/_pkgs/affine-model/blocks/image/image-model.d.ts +6 -0
- package/dist/_pkgs/affine-model/blocks/image/image-model.js +2 -0
- package/dist/_pkgs/affine-model/blocks/image/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/blocks/image/index.js +1 -0
- package/dist/_pkgs/affine-model/consts/shape.d.ts +2 -0
- package/dist/_pkgs/affine-model/consts/shape.js +5 -0
- package/dist/_pkgs/affine-model/elements/bpmn/consts.d.ts +31 -0
- package/dist/_pkgs/affine-model/elements/bpmn/consts.js +31 -0
- package/dist/_pkgs/affine-model/elements/bpmn/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/bpmn/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/bpmn/pool.d.ts +0 -25
- package/dist/_pkgs/affine-model/elements/bpmn/pool.js +1 -25
- package/dist/_pkgs/affine-model/elements/shape/shape.d.ts +0 -2
- package/dist/_pkgs/affine-model/elements/shape/shape.js +1 -2
- package/dist/_pkgs/affine-model/elements/uml/consts.d.ts +133 -0
- package/dist/_pkgs/affine-model/elements/uml/consts.js +107 -0
- package/dist/_pkgs/affine-model/elements/uml/diagram.d.ts +1 -79
- package/dist/_pkgs/affine-model/elements/uml/diagram.js +1 -53
- package/dist/_pkgs/affine-model/elements/uml/fragment.d.ts +0 -15
- package/dist/_pkgs/affine-model/elements/uml/fragment.js +1 -15
- package/dist/_pkgs/affine-model/elements/uml/index.d.ts +1 -0
- package/dist/_pkgs/affine-model/elements/uml/index.js +1 -0
- package/dist/_pkgs/affine-model/elements/uml/partition.d.ts +0 -20
- package/dist/_pkgs/affine-model/elements/uml/partition.js +1 -20
- package/dist/_pkgs/affine-model/elements/uml/region.d.ts +0 -11
- package/dist/_pkgs/affine-model/elements/uml/region.js +1 -11
- package/dist/_pkgs/affine-model/headless.d.ts +19 -0
- package/dist/_pkgs/affine-model/headless.js +19 -0
- package/dist/_pkgs/affine-shared/headless.d.ts +10 -0
- package/dist/_pkgs/affine-shared/headless.js +10 -0
- package/dist/_pkgs/affine-shared/services/asset-picker-service.d.ts +63 -0
- package/dist/_pkgs/affine-shared/services/asset-picker-service.js +20 -0
- package/dist/_pkgs/affine-shared/services/data-source-picker-service.d.ts +6 -3
- package/dist/_pkgs/affine-shared/services/frame-template-service.d.ts +83 -0
- package/dist/_pkgs/affine-shared/services/frame-template-service.js +17 -0
- package/dist/_pkgs/affine-shared/services/index.d.ts +2 -0
- package/dist/_pkgs/affine-shared/services/index.js +2 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +6 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +10 -0
- package/dist/_pkgs/affine-widget-drag-handle/watchers/drag-event-watcher.js +8 -3
- package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +4 -16
- package/dist/_pkgs/affine-widget-linked-doc/transformers/html.d.ts +7 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/html.js +25 -24
- package/dist/_pkgs/affine-widget-linked-doc/transformers/index.d.ts +1 -1
- package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.d.ts +7 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/markdown.js +26 -25
- package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.d.ts +23 -0
- package/dist/_pkgs/affine-widget-linked-doc/transformers/utils.js +14 -0
- package/dist/_pkgs/data-view/core/common/properties.d.ts +29 -0
- package/dist/_pkgs/data-view/core/common/properties.js +110 -8
- package/dist/_pkgs/data-view/core/common/property-menu.d.ts +44 -1
- package/dist/_pkgs/data-view/core/common/property-menu.js +100 -3
- package/dist/_pkgs/data-view/core/component/tags/color-carousel.d.ts +41 -0
- package/dist/_pkgs/data-view/core/component/tags/color-carousel.js +199 -0
- package/dist/_pkgs/data-view/core/component/tags/color-menu.d.ts +49 -0
- package/dist/_pkgs/data-view/core/component/tags/color-menu.js +123 -0
- package/dist/_pkgs/data-view/core/component/tags/index.d.ts +3 -0
- package/dist/_pkgs/data-view/core/component/tags/index.js +3 -0
- package/dist/_pkgs/data-view/core/component/tags/multi-tag-select.d.ts +8 -1
- package/dist/_pkgs/data-view/core/component/tags/multi-tag-select.js +21 -20
- package/dist/_pkgs/data-view/core/component/tags/softened-colors.d.ts +42 -0
- package/dist/_pkgs/data-view/core/component/tags/softened-colors.js +79 -0
- package/dist/_pkgs/data-view/core/data-view.d.ts +8 -1
- package/dist/_pkgs/data-view/core/data-view.js +18 -2
- package/dist/_pkgs/data-view/core/effect.js +2 -1
- package/dist/_pkgs/data-view/core/filter/eval.d.ts +6 -1
- package/dist/_pkgs/data-view/core/filter/eval.js +7 -2
- package/dist/_pkgs/data-view/core/group-by/renderer/select-group.d.ts +3 -0
- package/dist/_pkgs/data-view/core/group-by/renderer/select-group.js +119 -71
- package/dist/_pkgs/data-view/core/view/color-rules.d.ts +85 -0
- package/dist/_pkgs/data-view/core/view/color-rules.js +165 -0
- package/dist/_pkgs/data-view/core/view/index.d.ts +1 -0
- package/dist/_pkgs/data-view/core/view/index.js +1 -0
- package/dist/_pkgs/data-view/property-presets/multi-select/cell-renderer.js +1 -0
- package/dist/_pkgs/data-view/property-presets/select/cell-renderer.js +1 -0
- package/dist/_pkgs/data-view/translations.d.ts +34 -0
- package/dist/_pkgs/data-view/translations.js +80 -0
- package/dist/_pkgs/data-view/view-presets/gallery/gallery-view.js +7 -1
- package/dist/_pkgs/data-view/view-presets/kanban/mobile/card.js +6 -1
- package/dist/_pkgs/data-view/view-presets/kanban/pc/card.js +6 -1
- package/dist/_pkgs/data-view/view-presets/list/list-view.js +4 -0
- package/dist/_pkgs/data-view/view-presets/table/mobile/row.js +3 -0
- package/dist/_pkgs/data-view/view-presets/table/pc/header/database-header-column.d.ts +3 -1
- package/dist/_pkgs/data-view/view-presets/table/pc/header/database-header-column.js +149 -175
- package/dist/_pkgs/data-view/view-presets/table/pc/row/row.js +6 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/color-rules-menu.d.ts +12 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/color-rules-menu.js +206 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-options.js +16 -2
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-settings.d.ts +4 -2
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-settings.js +11 -2
- package/dist/commands.js +5 -2
- package/dist/host-panels.d.ts +21 -1
- package/dist/host-panels.js +50 -10
- package/dist/interchange.d.ts +1 -0
- package/dist/interchange.js +1 -0
- package/dist/model/headless.d.ts +1 -0
- package/dist/model/headless.js +1 -0
- package/dist/shared/headless.d.ts +1 -0
- package/dist/shared/headless.js +1 -0
- package/dist/translations.js +8 -1
- package/package.json +13 -1
|
@@ -265,9 +265,10 @@ let EdgelessTemplatePanel = (() => {
|
|
|
265
265
|
}
|
|
266
266
|
`; }
|
|
267
267
|
/**
|
|
268
|
-
* The GLOBAL half of the catalogue — `Other
|
|
269
|
-
*
|
|
270
|
-
* (`TemplateCategoryExtension`) and are read
|
|
268
|
+
* The GLOBAL half of the catalogue — `Other`. Framework and host
|
|
269
|
+
* categories are not here: they live in the editor's DI container
|
|
270
|
+
* (`TemplateCategoryExtension`, `FrameTemplateProvider`) and are read
|
|
271
|
+
* through {@link catalogue}.
|
|
271
272
|
*/
|
|
272
273
|
static { this.templates = builtInTemplates; }
|
|
273
274
|
/** What THIS edgeless offers: the global half plus its std's categories. */
|
|
@@ -485,10 +486,10 @@ let EdgelessTemplatePanel = (() => {
|
|
|
485
486
|
})}
|
|
486
487
|
></affine-template-loading>`
|
|
487
488
|
: repeat(_templates,
|
|
488
|
-
// The
|
|
489
|
-
//
|
|
490
|
-
//
|
|
491
|
-
template => template
|
|
489
|
+
// The template object itself: two saved frames may share
|
|
490
|
+
// a title (`FrameTemplateProvider`), and a name key
|
|
491
|
+
// would draw one tile for both.
|
|
492
|
+
template => template, template => {
|
|
492
493
|
const preview = template.preview
|
|
493
494
|
? template.preview.startsWith('<svg')
|
|
494
495
|
? html `${unsafeSVG(template.preview)}`
|
|
@@ -498,8 +499,7 @@ let EdgelessTemplatePanel = (() => {
|
|
|
498
499
|
loading="lazy"
|
|
499
500
|
/>`
|
|
500
501
|
: defaultPreview;
|
|
501
|
-
const isBeingDragged = draggingElement &&
|
|
502
|
-
draggingElement.data.name === template.name;
|
|
502
|
+
const isBeingDragged = draggingElement && draggingElement.data === template;
|
|
503
503
|
// The one place that asks the host's catalogue for the
|
|
504
504
|
// WORDING above the identity — see `resolveTemplateName`.
|
|
505
505
|
const displayName = resolveTemplateName(this.edgeless.std, template);
|
|
@@ -70,9 +70,8 @@ export type TemplateCategory = {
|
|
|
70
70
|
* key (`com.labre.framework.<id>`, the senior button's); a generic one
|
|
71
71
|
* (`Other`) gets a key of its own. Absent for a category whose display name
|
|
72
72
|
* cannot be attributed to one owner (Cynefin and Estuarine share a single
|
|
73
|
-
* `cynefin-estuarine` framework key that names neither individually)
|
|
74
|
-
*
|
|
75
|
-
* `name` is shown as is.
|
|
73
|
+
* `cynefin-estuarine` framework key that names neither individually), in
|
|
74
|
+
* which case `name` is shown as is.
|
|
76
75
|
*/
|
|
77
76
|
nameKey?: string;
|
|
78
77
|
templates: Template[] | (() => Promise<Template[]>);
|
|
@@ -83,5 +82,4 @@ export interface TemplateManager {
|
|
|
83
82
|
search(keyword: string, category?: string): Promise<Template[]> | Template[];
|
|
84
83
|
/** {@link TemplateCategory.nameKey} of the category named `name`, if any. */
|
|
85
84
|
categoryLabel?(name: string): string | undefined;
|
|
86
|
-
extend?(manager: TemplateManager): void;
|
|
87
85
|
}
|
|
@@ -18,6 +18,11 @@ export declare const TEMPLATE_PANEL_SEARCH_PLACEHOLDER: ChromeWording;
|
|
|
18
18
|
* same word as {@link CATALOGUE_OTHER}, one key.
|
|
19
19
|
*/
|
|
20
20
|
export declare const TEMPLATE_PANEL_CATEGORY_OTHER: ChromeWording;
|
|
21
|
+
/**
|
|
22
|
+
* The tab of the frames a host keeps as templates (`FrameTemplateProvider`,
|
|
23
|
+
* `SAVED_FRAMES_CATEGORY`); there is no such tab without that host.
|
|
24
|
+
*/
|
|
25
|
+
export declare const TEMPLATE_PANEL_CATEGORY_SAVED_FRAMES: ChromeWording;
|
|
21
26
|
/** The "Template" senior tool's own button name (`SeniorTool.labelKey`). */
|
|
22
27
|
export declare const TEMPLATE_SENIOR_TOOL_NAME: ChromeWording;
|
|
23
28
|
export declare const TEMPLATE_NAME_SWOT: ChromeWording;
|
|
@@ -24,6 +24,14 @@ export const TEMPLATE_PANEL_SEARCH_PLACEHOLDER = [
|
|
|
24
24
|
* same word as {@link CATALOGUE_OTHER}, one key.
|
|
25
25
|
*/
|
|
26
26
|
export const TEMPLATE_PANEL_CATEGORY_OTHER = CATALOGUE_OTHER;
|
|
27
|
+
/**
|
|
28
|
+
* The tab of the frames a host keeps as templates (`FrameTemplateProvider`,
|
|
29
|
+
* `SAVED_FRAMES_CATEGORY`); there is no such tab without that host.
|
|
30
|
+
*/
|
|
31
|
+
export const TEMPLATE_PANEL_CATEGORY_SAVED_FRAMES = [
|
|
32
|
+
'com.labre.template.panel.category.saved-frames',
|
|
33
|
+
'Saved frames',
|
|
34
|
+
];
|
|
27
35
|
/** The "Template" senior tool's own button name (`SeniorTool.labelKey`). */
|
|
28
36
|
export const TEMPLATE_SENIOR_TOOL_NAME = [
|
|
29
37
|
'com.labre.template.senior-tool.name',
|
|
@@ -65,6 +73,7 @@ export const TEMPLATE_NAME_GANTT_CHART = [
|
|
|
65
73
|
export const TEMPLATE_PACKAGE_WORDINGS = [
|
|
66
74
|
TEMPLATE_PANEL_ADD,
|
|
67
75
|
TEMPLATE_PANEL_SEARCH_PLACEHOLDER,
|
|
76
|
+
TEMPLATE_PANEL_CATEGORY_SAVED_FRAMES,
|
|
68
77
|
TEMPLATE_SENIOR_TOOL_NAME,
|
|
69
78
|
TEMPLATE_NAME_SWOT,
|
|
70
79
|
TEMPLATE_NAME_KANBAN_BOARD,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FOOTNOTE_DEFINITION_PREFIX, InlineDeltaToMarkdownAdapterExtension, } from '../../../affine-shared/adapters/index.js';
|
|
2
|
+
import { isSafeLinkUrl } from '../../../affine-shared/utils/index.js';
|
|
2
3
|
export const footnoteReferenceDeltaToMarkdownAdapterMatcher = InlineDeltaToMarkdownAdapterExtension({
|
|
3
4
|
name: 'footnote-reference',
|
|
4
5
|
match: delta => !!delta.attributes?.footnote,
|
|
@@ -19,6 +20,11 @@ export const footnoteReferenceDeltaToMarkdownAdapterMatcher = InlineDeltaToMarkd
|
|
|
19
20
|
if (!configs.has(footnoteDefinitionKey)) {
|
|
20
21
|
// clone the footnote reference
|
|
21
22
|
const clonedFootnoteReference = { ...footnote.reference };
|
|
23
|
+
// A stored url with a refused scheme is not written back out.
|
|
24
|
+
if (clonedFootnoteReference.url &&
|
|
25
|
+
!isSafeLinkUrl(clonedFootnoteReference.url)) {
|
|
26
|
+
delete clonedFootnoteReference.url;
|
|
27
|
+
}
|
|
22
28
|
// If the footnote reference contains url, encode it
|
|
23
29
|
if (clonedFootnoteReference.url) {
|
|
24
30
|
clonedFootnoteReference.url = encodeURIComponent(clonedFootnoteReference.url);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FootNoteReferenceParamsSchema } from '../../../affine-model/index.js';
|
|
2
2
|
import { FOOTNOTE_DEFINITION_PREFIX, MarkdownASTToDeltaExtension, } from '../../../affine-shared/adapters/index.js';
|
|
3
|
+
import { isSafeLinkUrl } from '../../../affine-shared/utils/index.js';
|
|
3
4
|
export const markdownFootnoteReferenceToDeltaMatcher = MarkdownASTToDeltaExtension({
|
|
4
5
|
name: 'footnote-reference',
|
|
5
6
|
match: ast => ast.type === 'footnoteReference',
|
|
@@ -23,6 +24,12 @@ export const markdownFootnoteReferenceToDeltaMatcher = MarkdownASTToDeltaExtensi
|
|
|
23
24
|
footnoteDefinitionJson.favicon = decodeURIComponent(footnoteDefinitionJson.favicon);
|
|
24
25
|
}
|
|
25
26
|
const footnoteReference = FootNoteReferenceParamsSchema.parse(footnoteDefinitionJson);
|
|
27
|
+
// A refused scheme is not stored: the footnote keeps its label and
|
|
28
|
+
// loses the url, which the render side would refuse anyway.
|
|
29
|
+
if (footnoteReference.url !== undefined &&
|
|
30
|
+
!isSafeLinkUrl(footnoteReference.url)) {
|
|
31
|
+
delete footnoteReference.url;
|
|
32
|
+
}
|
|
26
33
|
// If the footnote reference is an attachment, and the file type is not set,
|
|
27
34
|
// Try to infer the file type from the file name.
|
|
28
35
|
const { type: referenceType, fileName, fileType } = footnoteReference;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HtmlASTToDeltaExtension, } from '../../../affine-shared/adapters/index.js';
|
|
2
|
+
import { isSafeLinkUrl } from '../../../affine-shared/utils/index.js';
|
|
2
3
|
const isElement = (ast) => {
|
|
3
4
|
return ast.type === 'element';
|
|
4
5
|
};
|
|
@@ -47,7 +48,9 @@ export const htmlLinkElementToDeltaMatcher = HtmlASTToDeltaExtension({
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
return ast.children.flatMap(child => context.toDelta(child, { trim: false }).map(delta => {
|
|
50
|
-
|
|
51
|
+
// http(s) only, and by the parsed scheme: a prefix test let
|
|
52
|
+
// `httpx:` or `http-javascript:` through.
|
|
53
|
+
if (/^https?:/i.test(href.trim()) && isSafeLinkUrl(href)) {
|
|
51
54
|
delta.attributes = {
|
|
52
55
|
...delta.attributes,
|
|
53
56
|
link: href,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InlineDeltaToHtmlAdapterExtension } from '../../../affine-shared/adapters/index.js';
|
|
2
|
+
import { isSafeLinkUrl } from '../../../affine-shared/utils/index.js';
|
|
2
3
|
export const linkDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
|
|
3
4
|
name: 'link',
|
|
4
5
|
match: delta => !!delta.attributes?.link,
|
|
@@ -8,7 +9,8 @@ export const linkDeltaToHtmlAdapterMatcher = InlineDeltaToHtmlAdapterExtension({
|
|
|
8
9
|
value: delta.insert,
|
|
9
10
|
};
|
|
10
11
|
const link = delta.attributes?.link;
|
|
11
|
-
|
|
12
|
+
// A stored link with a refused scheme is written as its text alone.
|
|
13
|
+
if (!link || !isSafeLinkUrl(link)) {
|
|
12
14
|
return hast;
|
|
13
15
|
}
|
|
14
16
|
return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { InlineDeltaToMarkdownAdapterExtension } from '../../../affine-shared/adapters/index.js';
|
|
2
|
+
import { isSafeLinkUrl } from '../../../affine-shared/utils/index.js';
|
|
2
3
|
export const linkDeltaToMarkdownAdapterMatcher = InlineDeltaToMarkdownAdapterExtension({
|
|
3
4
|
name: 'link',
|
|
4
5
|
match: delta => !!delta.attributes?.link,
|
|
@@ -8,7 +9,9 @@ export const linkDeltaToMarkdownAdapterMatcher = InlineDeltaToMarkdownAdapterExt
|
|
|
8
9
|
value: delta.insert,
|
|
9
10
|
};
|
|
10
11
|
const link = delta.attributes?.link;
|
|
11
|
-
|
|
12
|
+
// A stored link with a refused scheme (an older document, a paste) is
|
|
13
|
+
// written as its text alone, never re-emitted as a link.
|
|
14
|
+
if (!link || !isSafeLinkUrl(link)) {
|
|
12
15
|
return mdast;
|
|
13
16
|
}
|
|
14
17
|
const { current: currentMdast } = context;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NotionHtmlASTToDeltaExtension, } from '../../../affine-shared/adapters/index.js';
|
|
2
|
+
import { isSafeLinkUrl } from '../../../affine-shared/utils/index.js';
|
|
2
3
|
const isElement = (ast) => {
|
|
3
4
|
return ast.type === 'element';
|
|
4
5
|
};
|
|
@@ -29,7 +30,7 @@ export const notionHtmlLinkElementToDeltaMatcher = NotionHtmlASTToDeltaExtension
|
|
|
29
30
|
return delta;
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
if (href.
|
|
33
|
+
if (/^https?:/i.test(href.trim()) && isSafeLinkUrl(href)) {
|
|
33
34
|
delta.attributes = {
|
|
34
35
|
...delta.attributes,
|
|
35
36
|
link: href,
|
|
@@ -14,6 +14,13 @@ export declare class AffineLink extends AffineLink_base {
|
|
|
14
14
|
setFloating: (element?: Element) => void;
|
|
15
15
|
dispose: () => void;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Opens this link's toolbar without a hover, as a proposal (see
|
|
19
|
+
* `proposeLinkViews`). The toolbar keeps the hover contract once the pointer
|
|
20
|
+
* enters it; until then any key or press outside it closes it, so the
|
|
21
|
+
* proposal never outlives the next gesture.
|
|
22
|
+
*/
|
|
23
|
+
proposeViews(): void;
|
|
17
24
|
connectedCallback(): void;
|
|
18
25
|
get block(): BlockComponent<import("../../store/index.js").BlockModel<object>, import("../../std/index.js").BlockService, string> | null;
|
|
19
26
|
get inlineEditor(): import("../../std/inline/inline-editor.js").InlineEditor<AffineTextAttributes> | undefined;
|
|
@@ -65,6 +65,43 @@ let AffineLink = (() => {
|
|
|
65
65
|
text-decoration: underline;
|
|
66
66
|
}
|
|
67
67
|
`; }
|
|
68
|
+
/**
|
|
69
|
+
* Opens this link's toolbar without a hover, as a proposal (see
|
|
70
|
+
* `proposeLinkViews`). The toolbar keeps the hover contract once the pointer
|
|
71
|
+
* enters it; until then any key or press outside it closes it, so the
|
|
72
|
+
* proposal never outlives the next gesture.
|
|
73
|
+
*/
|
|
74
|
+
proposeViews() {
|
|
75
|
+
const message$ = this.std.get(ToolbarRegistryIdentifier).message$;
|
|
76
|
+
let floating;
|
|
77
|
+
const controller = new AbortController();
|
|
78
|
+
const close = (event) => {
|
|
79
|
+
if (floating && event.composedPath().includes(floating))
|
|
80
|
+
return;
|
|
81
|
+
controller.abort();
|
|
82
|
+
if (message$.peek()?.element === this)
|
|
83
|
+
message$.value = null;
|
|
84
|
+
};
|
|
85
|
+
const options = { capture: true, signal: controller.signal };
|
|
86
|
+
document.addEventListener('keydown', close, options);
|
|
87
|
+
document.addEventListener('pointerdown', close, options);
|
|
88
|
+
this._disposables.add(() => controller.abort());
|
|
89
|
+
message$.value = {
|
|
90
|
+
flavour: 'affine:link',
|
|
91
|
+
element: this,
|
|
92
|
+
setFloating: element => {
|
|
93
|
+
floating = element;
|
|
94
|
+
this._whenHover.setFloating(element);
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
// Subscribed after the write: `subscribe` calls back at once with the
|
|
98
|
+
// current value, which must already be this proposal.
|
|
99
|
+
const unsubscribe = message$.subscribe(message => {
|
|
100
|
+
if (message?.element !== this)
|
|
101
|
+
controller.abort();
|
|
102
|
+
});
|
|
103
|
+
controller.signal.addEventListener('abort', unsubscribe);
|
|
104
|
+
}
|
|
68
105
|
connectedCallback() {
|
|
69
106
|
super.connectedCallback();
|
|
70
107
|
this._whenHover.setReference(this);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type BlockStdScope } from '../../std/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The URL a paste carries when its plain text is ONE http(s) URL and nothing
|
|
4
|
+
* else, or `null`. A sentence holding a URL, two URLs, a `mailto:` or any
|
|
5
|
+
* scheme `isSafeLinkUrl` refuses is not a lone URL: it pastes as text, as it
|
|
6
|
+
* always did.
|
|
7
|
+
*/
|
|
8
|
+
export declare function lonePastedUrl(text: string | null | undefined): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* After a lone URL was pasted in a page (labre REQ-IM-1), open the link's own
|
|
11
|
+
* toolbar on the link the paste wrote, so its view switcher offers "Card view"
|
|
12
|
+
* and "Embed view" next to the current "Inline view". Nothing is written: the
|
|
13
|
+
* paste already stored a plain link, which stays the default when the viewer
|
|
14
|
+
* picks nothing. The conversions are the toolbar's, with their own gates (a
|
|
15
|
+
* registered bookmark or embed view, an embed provider for the URL).
|
|
16
|
+
*
|
|
17
|
+
* Returns whether a toolbar was opened. Nothing opens when the paste did not
|
|
18
|
+
* leave a link at the caret (a URL the host recognised as one of its own
|
|
19
|
+
* documents became a reference), on a read-only document, or inside a table
|
|
20
|
+
* or a database cell, where the toolbar offers no conversion.
|
|
21
|
+
*/
|
|
22
|
+
export declare function proposeLinkViews(std: BlockStdScope, url: string): Promise<boolean>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { isSafeLinkUrl, normalizeUrl } from '../../affine-shared/utils/index.js';
|
|
2
|
+
import { TextSelection } from '../../std/index.js';
|
|
3
|
+
import { AffineLink } from './affine-link.js';
|
|
4
|
+
/**
|
|
5
|
+
* The URL a paste carries when its plain text is ONE http(s) URL and nothing
|
|
6
|
+
* else, or `null`. A sentence holding a URL, two URLs, a `mailto:` or any
|
|
7
|
+
* scheme `isSafeLinkUrl` refuses is not a lone URL: it pastes as text, as it
|
|
8
|
+
* always did.
|
|
9
|
+
*/
|
|
10
|
+
export function lonePastedUrl(text) {
|
|
11
|
+
const candidate = text?.trim();
|
|
12
|
+
if (!candidate || /\s/.test(candidate))
|
|
13
|
+
return null;
|
|
14
|
+
if (!isSafeLinkUrl(candidate))
|
|
15
|
+
return null;
|
|
16
|
+
if (!URL.canParse(candidate))
|
|
17
|
+
return null;
|
|
18
|
+
const { protocol } = new URL(candidate);
|
|
19
|
+
return protocol === 'http:' || protocol === 'https:' ? candidate : null;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* After a lone URL was pasted in a page (labre REQ-IM-1), open the link's own
|
|
23
|
+
* toolbar on the link the paste wrote, so its view switcher offers "Card view"
|
|
24
|
+
* and "Embed view" next to the current "Inline view". Nothing is written: the
|
|
25
|
+
* paste already stored a plain link, which stays the default when the viewer
|
|
26
|
+
* picks nothing. The conversions are the toolbar's, with their own gates (a
|
|
27
|
+
* registered bookmark or embed view, an embed provider for the URL).
|
|
28
|
+
*
|
|
29
|
+
* Returns whether a toolbar was opened. Nothing opens when the paste did not
|
|
30
|
+
* leave a link at the caret (a URL the host recognised as one of its own
|
|
31
|
+
* documents became a reference), on a read-only document, or inside a table
|
|
32
|
+
* or a database cell, where the toolbar offers no conversion.
|
|
33
|
+
*/
|
|
34
|
+
export async function proposeLinkViews(std, url) {
|
|
35
|
+
if (std.store.readonly)
|
|
36
|
+
return false;
|
|
37
|
+
await std.host.updateComplete;
|
|
38
|
+
const caret = std.selection.find(TextSelection);
|
|
39
|
+
if (!caret)
|
|
40
|
+
return false;
|
|
41
|
+
const block = std.view.getBlock(caret.from.blockId);
|
|
42
|
+
if (!block)
|
|
43
|
+
return false;
|
|
44
|
+
await block.updateComplete;
|
|
45
|
+
if (block.closest('affine-database, affine-table'))
|
|
46
|
+
return false;
|
|
47
|
+
const href = normalizeUrl(url);
|
|
48
|
+
const links = Array.from(block.querySelectorAll('affine-link')).filter((node) => node instanceof AffineLink && node.link === href);
|
|
49
|
+
// The caret ends the pasted run; an equal link written earlier in the same
|
|
50
|
+
// paragraph must not be the one the toolbar points at.
|
|
51
|
+
const pasted = links.find(link => {
|
|
52
|
+
const range = link.selfInlineRange;
|
|
53
|
+
return !!range && range.index + range.length === caret.from.index;
|
|
54
|
+
}) ?? links.at(-1);
|
|
55
|
+
if (!pasted)
|
|
56
|
+
return false;
|
|
57
|
+
pasted.proposeViews();
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
@@ -16,12 +16,39 @@ export type SerializedCells = Record<string, Record<string, CellDataType>>;
|
|
|
16
16
|
*/
|
|
17
17
|
export declare const DATABASE_VIEW_OPEN_IN: readonly ["side", "center", "full"];
|
|
18
18
|
export type DatabaseViewOpenIn = (typeof DATABASE_VIEW_OPEN_IN)[number];
|
|
19
|
+
/**
|
|
20
|
+
* The condition of a colour rule: a filter group, the very shape a view
|
|
21
|
+
* stores as its `filter` (`FilterGroup` of `@labre/data-view`, which reads
|
|
22
|
+
* and evaluates it). Opaque here: the model does not know the filter
|
|
23
|
+
* functions.
|
|
24
|
+
*/
|
|
25
|
+
export type DatabaseViewColorRuleFilter = {
|
|
26
|
+
type: 'group';
|
|
27
|
+
op: 'and' | 'or';
|
|
28
|
+
conditions: unknown[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* One conditional colour of a view (ADR 0036): rows (table, list) and cards
|
|
32
|
+
* (board, gallery) that match `filter` take `color` as a light background.
|
|
33
|
+
* `color` is a colour of the select options' palette, stored as an option
|
|
34
|
+
* stores it; a value this build does not know paints nothing. `id` names
|
|
35
|
+
* the rule for the editor, so a peer's reorder never retargets an edit.
|
|
36
|
+
*/
|
|
37
|
+
export type DatabaseViewColorRule = {
|
|
38
|
+
id: string;
|
|
39
|
+
color: string;
|
|
40
|
+
filter: DatabaseViewColorRuleFilter;
|
|
41
|
+
};
|
|
19
42
|
/**
|
|
20
43
|
* The stored shape every view in `props.views` shares; each mode adds its own
|
|
21
44
|
* data on top. `sourceId` and `openIn` arrived in 0.49 (ADR 0035 §8, red
|
|
22
45
|
* zone): optional, `undefined` by default and never written on load, so a
|
|
23
46
|
* view stored by 0.48 or earlier is still a valid view and a 0.48 client
|
|
24
47
|
* ignores them. `sourceId` absent means the block's own implicit source.
|
|
48
|
+
* `colorRules` arrived in 0.50 (ADR 0036, red zone), on the same terms: absent
|
|
49
|
+
* until a gesture adds a rule, ordered (the first rule that matches a row
|
|
50
|
+
* wins), ignored by a 0.49 client, which keeps it through its own writes
|
|
51
|
+
* (`updateView` merges into the stored view).
|
|
25
52
|
* Held by `view-basic-data.unit.spec.ts`.
|
|
26
53
|
*/
|
|
27
54
|
export type ViewBasicDataType = {
|
|
@@ -30,4 +57,5 @@ export type ViewBasicDataType = {
|
|
|
30
57
|
mode: string;
|
|
31
58
|
sourceId?: string;
|
|
32
59
|
openIn?: DatabaseViewOpenIn;
|
|
60
|
+
colorRules?: DatabaseViewColorRule[];
|
|
33
61
|
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The stored crop of an image block (ADR 0037): a view on the source, never
|
|
3
|
+
* new bytes. The rectangle is normalised to the source image (0..1 on each
|
|
4
|
+
* axis), so it needs no pixel size and survives any resize.
|
|
5
|
+
*
|
|
6
|
+
* Append-only: a mask token, once shipped, is never renamed or removed. A
|
|
7
|
+
* token this build does not know reads as `free`.
|
|
8
|
+
*/
|
|
9
|
+
export declare const IMAGE_CROP_MASKS: readonly ["free", "16:9", "4:3", "1:1"];
|
|
10
|
+
export type ImageCropMask = (typeof IMAGE_CROP_MASKS)[number];
|
|
11
|
+
export interface ImageCrop {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
w: number;
|
|
15
|
+
h: number;
|
|
16
|
+
/** The preset that drew the rectangle; absent means free. */
|
|
17
|
+
mask?: ImageCropMask;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Below this a side is a sliver nobody can grab again; the crop tool never
|
|
21
|
+
* writes one, and a stored one is treated as damaged.
|
|
22
|
+
*/
|
|
23
|
+
export declare const IMAGE_CROP_MIN_SIDE = 0.02;
|
|
24
|
+
/**
|
|
25
|
+
* The crop to paint, or `undefined` for the whole image.
|
|
26
|
+
*
|
|
27
|
+
* Every reader goes through here: the value may come from a peer, an import
|
|
28
|
+
* or a damaged document, and a crop that cannot be honoured shows the whole
|
|
29
|
+
* picture rather than an empty box or an error. A rectangle covering the
|
|
30
|
+
* whole image is "no crop" too, so nothing downstream has to tell them apart.
|
|
31
|
+
*/
|
|
32
|
+
export declare function readImageCrop(value: unknown): ImageCrop | undefined;
|
|
33
|
+
export declare function isWholeImage(rect: Pick<ImageCrop, 'x' | 'y' | 'w' | 'h'>): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* The part of the source, in source pixels, a crop keeps — what a raster
|
|
36
|
+
* export hands to `drawImage(image, sx, sy, sw, sh, …)`.
|
|
37
|
+
*
|
|
38
|
+
* `null` when there is nothing to cut: no crop, or a source with no pixel
|
|
39
|
+
* size (an SVG without intrinsic dimensions loads as 0×0). The caller then
|
|
40
|
+
* draws the whole image into the box, as before ADR 0037; a source
|
|
41
|
+
* rectangle of 0×0 would draw nothing at all.
|
|
42
|
+
*/
|
|
43
|
+
export declare function imageCropSourceRect(crop: ImageCrop | undefined, naturalWidth: number, naturalHeight: number): {
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
w: number;
|
|
47
|
+
h: number;
|
|
48
|
+
} | null;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The stored crop of an image block (ADR 0037): a view on the source, never
|
|
3
|
+
* new bytes. The rectangle is normalised to the source image (0..1 on each
|
|
4
|
+
* axis), so it needs no pixel size and survives any resize.
|
|
5
|
+
*
|
|
6
|
+
* Append-only: a mask token, once shipped, is never renamed or removed. A
|
|
7
|
+
* token this build does not know reads as `free`.
|
|
8
|
+
*/
|
|
9
|
+
export const IMAGE_CROP_MASKS = ['free', '16:9', '4:3', '1:1'];
|
|
10
|
+
/**
|
|
11
|
+
* Below this a side is a sliver nobody can grab again; the crop tool never
|
|
12
|
+
* writes one, and a stored one is treated as damaged.
|
|
13
|
+
*/
|
|
14
|
+
export const IMAGE_CROP_MIN_SIDE = 0.02;
|
|
15
|
+
const EPSILON = 1e-6;
|
|
16
|
+
const isFraction = (value) => typeof value === 'number' && Number.isFinite(value);
|
|
17
|
+
/**
|
|
18
|
+
* The crop to paint, or `undefined` for the whole image.
|
|
19
|
+
*
|
|
20
|
+
* Every reader goes through here: the value may come from a peer, an import
|
|
21
|
+
* or a damaged document, and a crop that cannot be honoured shows the whole
|
|
22
|
+
* picture rather than an empty box or an error. A rectangle covering the
|
|
23
|
+
* whole image is "no crop" too, so nothing downstream has to tell them apart.
|
|
24
|
+
*/
|
|
25
|
+
export function readImageCrop(value) {
|
|
26
|
+
if (!value || typeof value !== 'object')
|
|
27
|
+
return undefined;
|
|
28
|
+
const { x, y, w, h, mask } = value;
|
|
29
|
+
if (!isFraction(x) || !isFraction(y) || !isFraction(w) || !isFraction(h)) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
if (x < -EPSILON || y < -EPSILON)
|
|
33
|
+
return undefined;
|
|
34
|
+
if (w < IMAGE_CROP_MIN_SIDE - EPSILON || h < IMAGE_CROP_MIN_SIDE - EPSILON) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
if (x + w > 1 + EPSILON || y + h > 1 + EPSILON)
|
|
38
|
+
return undefined;
|
|
39
|
+
if (isWholeImage({ x, y, w, h }))
|
|
40
|
+
return undefined;
|
|
41
|
+
const crop = {
|
|
42
|
+
x: Math.max(0, x),
|
|
43
|
+
y: Math.max(0, y),
|
|
44
|
+
w: Math.min(w, 1 - Math.max(0, x)),
|
|
45
|
+
h: Math.min(h, 1 - Math.max(0, y)),
|
|
46
|
+
};
|
|
47
|
+
if (typeof mask === 'string' &&
|
|
48
|
+
mask !== 'free' &&
|
|
49
|
+
IMAGE_CROP_MASKS.includes(mask)) {
|
|
50
|
+
crop.mask = mask;
|
|
51
|
+
}
|
|
52
|
+
return crop;
|
|
53
|
+
}
|
|
54
|
+
export function isWholeImage(rect) {
|
|
55
|
+
return (Math.abs(rect.x) < EPSILON &&
|
|
56
|
+
Math.abs(rect.y) < EPSILON &&
|
|
57
|
+
Math.abs(rect.w - 1) < EPSILON &&
|
|
58
|
+
Math.abs(rect.h - 1) < EPSILON);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The part of the source, in source pixels, a crop keeps — what a raster
|
|
62
|
+
* export hands to `drawImage(image, sx, sy, sw, sh, …)`.
|
|
63
|
+
*
|
|
64
|
+
* `null` when there is nothing to cut: no crop, or a source with no pixel
|
|
65
|
+
* size (an SVG without intrinsic dimensions loads as 0×0). The caller then
|
|
66
|
+
* draws the whole image into the box, as before ADR 0037; a source
|
|
67
|
+
* rectangle of 0×0 would draw nothing at all.
|
|
68
|
+
*/
|
|
69
|
+
export function imageCropSourceRect(crop, naturalWidth, naturalHeight) {
|
|
70
|
+
if (!crop || naturalWidth <= 0 || naturalHeight <= 0)
|
|
71
|
+
return null;
|
|
72
|
+
return {
|
|
73
|
+
x: crop.x * naturalWidth,
|
|
74
|
+
y: crop.y * naturalHeight,
|
|
75
|
+
w: crop.w * naturalWidth,
|
|
76
|
+
h: crop.h * naturalHeight,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GfxCommonBlockProps, GfxElementGeometry } from '../../../std/gfx/index.js';
|
|
2
2
|
import type { BlockMeta } from '../../utils/types.js';
|
|
3
|
+
import type { ImageCrop } from './image-crop.js';
|
|
3
4
|
import { ImageBlockTransformer } from './image-transformer.js';
|
|
4
5
|
export type ImageBlockProps = {
|
|
5
6
|
caption?: string;
|
|
@@ -9,6 +10,11 @@ export type ImageBlockProps = {
|
|
|
9
10
|
rotate: number;
|
|
10
11
|
size?: number;
|
|
11
12
|
comments?: Record<string, boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* The part of the source this block shows (ADR 0037). Absent means the
|
|
15
|
+
* whole image; read it through `readImageCrop`, never directly.
|
|
16
|
+
*/
|
|
17
|
+
crop?: ImageCrop;
|
|
12
18
|
} & Omit<GfxCommonBlockProps, 'scale'> & BlockMeta;
|
|
13
19
|
export declare const ImageBlockSchema: {
|
|
14
20
|
version: number;
|
|
@@ -39,3 +39,8 @@ export var ShapeStyle;
|
|
|
39
39
|
ShapeStyle["General"] = "General";
|
|
40
40
|
ShapeStyle["Scribbled"] = "Scribbled";
|
|
41
41
|
})(ShapeStyle || (ShapeStyle = {}));
|
|
42
|
+
// Moved here from `elements/shape/shape.ts`, unchanged, so the model's
|
|
43
|
+
// headless entry exports them without the element class (ADR 0012, P3 as
|
|
44
|
+
// amended 2026-10-14).
|
|
45
|
+
export const SHAPE_TEXT_PADDING = 20;
|
|
46
|
+
export const SHAPE_TEXT_VERTICAL_PADDING = 10;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants moved out of the element-class files of this folder, unchanged, so
|
|
3
|
+
* the model's headless entry (`@labre/affine-model/headless`) exports them
|
|
4
|
+
* without `@labre/std/gfx` behind them (ADR 0012, P3 as amended 2026-10-14).
|
|
5
|
+
* The folder index re-exports this file.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Width of the participant band — the left margin strip the pool name is
|
|
9
|
+
* written up, in model units.
|
|
10
|
+
*
|
|
11
|
+
* Declared HERE, in the model, and re-exported by `@labre/affine-gfx-bpmn`
|
|
12
|
+
* rather than the other way round. The pool's own hit test needs it (a pool is
|
|
13
|
+
* clickable by its title bands as well as its border, the bpmn.io convention),
|
|
14
|
+
* and `affine-model` cannot reach into `affine-block-surface` where the
|
|
15
|
+
* declaration is resolved. One number, owned by the layer that both the
|
|
16
|
+
* declaration and the hit test can read.
|
|
17
|
+
*/
|
|
18
|
+
export declare const POOL_BAND_WIDTH = 28;
|
|
19
|
+
/**
|
|
20
|
+
* Width of a lane's own title band — the strip immediately inside the
|
|
21
|
+
* participant band, with the lane name turned on its side.
|
|
22
|
+
*
|
|
23
|
+
* Four units narrower than {@link POOL_BAND_WIDTH}, and for the same reason the
|
|
24
|
+
* lane font is two points smaller: the two strips sit side by side, so the
|
|
25
|
+
* subordinate one has to say so. Identical widths read as a single 56-unit
|
|
26
|
+
* gutter rather than as a participant containing lanes, which is exactly the
|
|
27
|
+
* relationship the picture has to carry.
|
|
28
|
+
*
|
|
29
|
+
* NO fill, divider only — what bpmn.io, Camunda and Visio all draw.
|
|
30
|
+
*/
|
|
31
|
+
export declare const POOL_LANE_BAND_WIDTH = 24;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants moved out of the element-class files of this folder, unchanged, so
|
|
3
|
+
* the model's headless entry (`@labre/affine-model/headless`) exports them
|
|
4
|
+
* without `@labre/std/gfx` behind them (ADR 0012, P3 as amended 2026-10-14).
|
|
5
|
+
* The folder index re-exports this file.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Width of the participant band — the left margin strip the pool name is
|
|
9
|
+
* written up, in model units.
|
|
10
|
+
*
|
|
11
|
+
* Declared HERE, in the model, and re-exported by `@labre/affine-gfx-bpmn`
|
|
12
|
+
* rather than the other way round. The pool's own hit test needs it (a pool is
|
|
13
|
+
* clickable by its title bands as well as its border, the bpmn.io convention),
|
|
14
|
+
* and `affine-model` cannot reach into `affine-block-surface` where the
|
|
15
|
+
* declaration is resolved. One number, owned by the layer that both the
|
|
16
|
+
* declaration and the hit test can read.
|
|
17
|
+
*/
|
|
18
|
+
export const POOL_BAND_WIDTH = 28;
|
|
19
|
+
/**
|
|
20
|
+
* Width of a lane's own title band — the strip immediately inside the
|
|
21
|
+
* participant band, with the lane name turned on its side.
|
|
22
|
+
*
|
|
23
|
+
* Four units narrower than {@link POOL_BAND_WIDTH}, and for the same reason the
|
|
24
|
+
* lane font is two points smaller: the two strips sit side by side, so the
|
|
25
|
+
* subordinate one has to say so. Identical widths read as a single 56-unit
|
|
26
|
+
* gutter rather than as a participant containing lanes, which is exactly the
|
|
27
|
+
* relationship the picture has to carry.
|
|
28
|
+
*
|
|
29
|
+
* NO fill, divider only — what bpmn.io, Camunda and Visio all draw.
|
|
30
|
+
*/
|
|
31
|
+
export const POOL_LANE_BAND_WIDTH = 24;
|