@formicoidea/labre-core 0.53.0 → 0.55.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-data-view/data-view-block.js +1 -1
- package/dist/_pkgs/affine-block-database/components/title/index.js +7 -2
- package/dist/_pkgs/affine-block-database/database-block-styles.js +9 -1
- package/dist/_pkgs/affine-block-embed-doc/page-drop/page-drop.d.ts +70 -0
- package/dist/_pkgs/affine-block-embed-doc/page-drop/page-drop.js +196 -0
- package/dist/_pkgs/affine-block-embed-doc/view.js +3 -0
- package/dist/_pkgs/affine-block-frame/frame-template.d.ts +11 -0
- package/dist/_pkgs/affine-block-frame/frame-template.js +24 -4
- package/dist/_pkgs/affine-block-frame/translations.d.ts +3 -0
- package/dist/_pkgs/affine-block-frame/translations.js +7 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-svg/render.js +9 -3
- package/dist/_pkgs/affine-block-surface/framework-background/renderer.js +9 -5
- package/dist/_pkgs/affine-block-surface/index.d.ts +1 -0
- package/dist/_pkgs/affine-block-surface/index.js +1 -0
- package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.d.ts +55 -3
- package/dist/_pkgs/affine-block-surface/renderer/canvas-renderer.js +139 -6
- package/dist/_pkgs/affine-block-surface/renderer/notation-tint.d.ts +92 -0
- package/dist/_pkgs/affine-block-surface/renderer/notation-tint.js +113 -0
- package/dist/_pkgs/affine-block-surface/surface-block.js +2 -2
- package/dist/_pkgs/affine-components/color-picker/styles.js +1 -1
- package/dist/_pkgs/affine-components/context-menu/input.js +2 -1
- package/dist/_pkgs/affine-components/context-menu/menu-renderer.d.ts +7 -0
- package/dist/_pkgs/affine-components/context-menu/menu-renderer.js +53 -13
- package/dist/_pkgs/affine-components/drop-indicator/file-drop-manager.js +15 -0
- package/dist/_pkgs/affine-gfx-shape/element-renderer/shape/index.js +4 -2
- package/dist/_pkgs/affine-inline-link/link-node/link-popup/styles.js +1 -1
- package/dist/_pkgs/affine-inline-reference/reference-node/reference-popup/reference-popup.js +9 -9
- package/dist/_pkgs/affine-shared/consts/notation.d.ts +1 -0
- package/dist/_pkgs/affine-shared/consts/notation.js +29 -0
- package/dist/_pkgs/affine-shared/services/frame-template-service.d.ts +5 -0
- package/dist/_pkgs/affine-shared/services/index.d.ts +1 -0
- package/dist/_pkgs/affine-shared/services/index.js +1 -0
- package/dist/_pkgs/affine-shared/services/page-drop-service.d.ts +61 -0
- package/dist/_pkgs/affine-shared/services/page-drop-service.js +30 -0
- package/dist/_pkgs/affine-shared/styles/scrollbar-style.js +1 -1
- package/dist/_pkgs/affine-widget-edgeless-auto-connect/index.js +5 -5
- package/dist/_pkgs/affine-widget-edgeless-selected-rect/edgeless-auto-complete.js +2 -2
- package/dist/_pkgs/affine-widget-keyboard-toolbar/config.js +6 -6
- package/dist/_pkgs/affine-widget-keyboard-toolbar/styles.js +1 -1
- package/dist/_pkgs/affine-widget-linked-doc/config.d.ts +8 -0
- package/dist/_pkgs/affine-widget-linked-doc/config.js +8 -1
- package/dist/_pkgs/affine-widget-linked-doc/linked-doc-popover.js +40 -32
- package/dist/_pkgs/affine-widget-linked-doc/styles.js +1 -1
- package/dist/_pkgs/affine-widget-linked-doc/translations.d.ts +2 -0
- package/dist/_pkgs/affine-widget-linked-doc/translations.js +6 -0
- package/dist/_pkgs/affine-widget-thread-marks/widget.d.ts +3 -1
- package/dist/_pkgs/affine-widget-thread-marks/widget.js +6 -1
- package/dist/_pkgs/affine-widget-toolbar/utils.d.ts +2 -1
- package/dist/_pkgs/affine-widget-toolbar/utils.js +5 -2
- package/dist/_pkgs/data-view/core/common/properties.js +2 -2
- package/dist/_pkgs/data-view/core/common/property-menu.d.ts +3 -3
- package/dist/_pkgs/data-view/core/common/property-menu.js +7 -7
- package/dist/_pkgs/data-view/core/component/overflow/overflow.js +4 -1
- package/dist/_pkgs/data-view/core/group-by/renderer/base.d.ts +4 -1
- package/dist/_pkgs/data-view/core/group-by/renderer/base.js +17 -2
- package/dist/_pkgs/data-view/core/group-by/renderer/number-group.js +1 -1
- package/dist/_pkgs/data-view/core/group-by/renderer/select-group.d.ts +0 -3
- package/dist/_pkgs/data-view/core/group-by/renderer/select-group.js +63 -118
- package/dist/_pkgs/data-view/core/group-by/renderer/string-group.js +1 -1
- package/dist/_pkgs/data-view/core/group-by/setting.js +2 -2
- package/dist/_pkgs/data-view/core/utils/wording.d.ts +6 -2
- package/dist/_pkgs/data-view/core/utils/wording.js +5 -3
- package/dist/_pkgs/data-view/core/view/default-name.d.ts +6 -0
- package/dist/_pkgs/data-view/core/view/default-name.js +8 -0
- package/dist/_pkgs/data-view/translations.d.ts +45 -0
- package/dist/_pkgs/data-view/translations.js +118 -0
- package/dist/_pkgs/data-view/view-presets/flat/flat-view-ui.d.ts +3 -1
- package/dist/_pkgs/data-view/view-presets/flat/flat-view-ui.js +5 -1
- package/dist/_pkgs/data-view/view-presets/kanban/mobile/card.d.ts +6 -0
- package/dist/_pkgs/data-view/view-presets/kanban/mobile/card.js +11 -0
- package/dist/_pkgs/data-view/view-presets/kanban/mobile/cell.js +9 -10
- package/dist/_pkgs/data-view/view-presets/kanban/mobile/kanban-view-ui-logic.js +3 -0
- package/dist/_pkgs/data-view/view-presets/table/mobile/cell.js +7 -4
- package/dist/_pkgs/data-view/view-presets/table/mobile/column-header.d.ts +3 -1
- package/dist/_pkgs/data-view/view-presets/table/mobile/column-header.js +102 -124
- package/dist/_pkgs/data-view/view-presets/table/mobile/group.js +12 -7
- package/dist/_pkgs/data-view/view-presets/table/mobile/header.d.ts +8 -2
- package/dist/_pkgs/data-view/view-presets/table/mobile/header.js +64 -24
- package/dist/_pkgs/data-view/view-presets/table/mobile/menu.d.ts +3 -1
- package/dist/_pkgs/data-view/view-presets/table/mobile/menu.js +7 -3
- package/dist/_pkgs/data-view/view-presets/table/mobile/row.d.ts +23 -1
- package/dist/_pkgs/data-view/view-presets/table/mobile/row.js +138 -55
- package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-style.d.ts +17 -0
- package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-style.js +31 -6
- package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-ui-logic.d.ts +5 -1
- package/dist/_pkgs/data-view/view-presets/table/mobile/table-view-ui-logic.js +11 -4
- package/dist/_pkgs/data-view/view-presets/table/pc/group.js +4 -2
- package/dist/_pkgs/data-view/view-presets/table/pc/row/row.js +5 -1
- package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/filter/index.js +1 -2
- package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/filter/list-view.d.ts +3 -1
- package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/filter/list-view.js +23 -3
- package/dist/_pkgs/data-view/widget-presets/quick-setting-bar/index.js +8 -8
- package/dist/_pkgs/data-view/widget-presets/tools/presets/filter/filter.d.ts +3 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/filter/filter.js +125 -60
- package/dist/_pkgs/data-view/widget-presets/tools/presets/search/search.d.ts +3 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/search/search.js +37 -5
- package/dist/_pkgs/data-view/widget-presets/tools/presets/sort/sort.d.ts +3 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/sort/sort.js +131 -66
- package/dist/_pkgs/data-view/widget-presets/tools/presets/table-add-row/add-row.d.ts +3 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/table-add-row/add-row.js +143 -40
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-options.js +30 -22
- package/dist/_pkgs/data-view/widget-presets/tools/presets/view-options/view-settings.js +8 -6
- package/dist/_pkgs/data-view/widget-presets/views-bar/views-view.js +15 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColorScheme } from '../../affine-model/index.js';
|
|
1
|
+
import { ColorScheme, ConnectorElementModel, FrameworkBackgroundElementModel, } from '../../affine-model/index.js';
|
|
2
2
|
import { FeatureFlagService } from '../../affine-shared/services/index.js';
|
|
3
3
|
import { requestConnectedFrame } from '../../affine-shared/utils/index.js';
|
|
4
4
|
import { DisposableGroup } from '../../global/disposable/index.js';
|
|
@@ -9,9 +9,26 @@ import last from 'lodash-es/last.js';
|
|
|
9
9
|
import { Subject } from 'rxjs';
|
|
10
10
|
import { ElementRendererIdentifier } from '../extensions/element-renderer.js';
|
|
11
11
|
import { RoughCanvas } from '../utils/rough/canvas.js';
|
|
12
|
+
import { NotationDarkPaletteIdentifier, NotationTint, } from './notation-tint.js';
|
|
12
13
|
import { isPainted } from './paint-predicate.js';
|
|
14
|
+
/** The stored fill an element paints as its body, if it paints one. */
|
|
15
|
+
function paperOf(element) {
|
|
16
|
+
const { filled, fillColor } = element;
|
|
17
|
+
return filled && typeof fillColor === 'string' && fillColor
|
|
18
|
+
? fillColor
|
|
19
|
+
: null;
|
|
20
|
+
}
|
|
13
21
|
const STACKING_CANVAS_PADDING = 32;
|
|
14
22
|
export class CanvasRenderer {
|
|
23
|
+
/**
|
|
24
|
+
* The dark notation table while a NOTATION element is being painted on a
|
|
25
|
+
* dark canvas, `null` otherwise (light scheme, a neutral element, outside a
|
|
26
|
+
* paint). Painters read it through `notationColor` and
|
|
27
|
+
* {@link getColorValue}; see `notation-tint.ts` and ADR 0039.
|
|
28
|
+
*/
|
|
29
|
+
get notationTint() {
|
|
30
|
+
return this._notationTint;
|
|
31
|
+
}
|
|
15
32
|
get stackingCanvas() {
|
|
16
33
|
return this._stackingCanvas;
|
|
17
34
|
}
|
|
@@ -44,6 +61,11 @@ export class CanvasRenderer {
|
|
|
44
61
|
};
|
|
45
62
|
this.stackingCanvasUpdated = new Subject();
|
|
46
63
|
this.usePlaceholder = false;
|
|
64
|
+
/** Set by {@link withColorScheme} for the length of one paint. */
|
|
65
|
+
this._schemeOverride = null;
|
|
66
|
+
/** Built on the first dark paint, from the registered framework entries. */
|
|
67
|
+
this._darkTint = null;
|
|
68
|
+
this._notationTint = null;
|
|
47
69
|
this._lastDebugSnapshot = {
|
|
48
70
|
canvasMemoryBytes: 0,
|
|
49
71
|
canvasMemorySnapshots: [],
|
|
@@ -72,6 +94,7 @@ export class CanvasRenderer {
|
|
|
72
94
|
if (options.enableStackingCanvas) {
|
|
73
95
|
this._initStackingCanvas(options.onStackingCanvasCreated);
|
|
74
96
|
}
|
|
97
|
+
this._surface = options.surfaceModel;
|
|
75
98
|
this._watchSurface(options.surfaceModel);
|
|
76
99
|
}
|
|
77
100
|
/**
|
|
@@ -440,6 +463,9 @@ export class CanvasRenderer {
|
|
|
440
463
|
this.grid.search(bound, {
|
|
441
464
|
filter: ['canvas', 'local'],
|
|
442
465
|
});
|
|
466
|
+
const tint = this._tintForPass();
|
|
467
|
+
let boards = null;
|
|
468
|
+
const papers = [];
|
|
443
469
|
for (const element of elements) {
|
|
444
470
|
const display = isPainted(element, this._gfx.localVisibility);
|
|
445
471
|
if (display && intersects(getBoundWithRotation(element), bound)) {
|
|
@@ -463,7 +489,24 @@ export class CanvasRenderer {
|
|
|
463
489
|
ctx.globalAlpha = element.opacity ?? 1;
|
|
464
490
|
const dx = element.x - bound.x;
|
|
465
491
|
const dy = element.y - bound.y;
|
|
466
|
-
|
|
492
|
+
if (tint) {
|
|
493
|
+
// Every board of the surface, not of this pass: a stacking canvas
|
|
494
|
+
// paints one layer, and the board may sit in another.
|
|
495
|
+
boards ??= this._surface.elementModels.filter((e) => e instanceof FrameworkBackgroundElementModel);
|
|
496
|
+
this._notationTint =
|
|
497
|
+
this._isNotation(element, boards) &&
|
|
498
|
+
!this._sitsOnKeptPaper(element, papers, tint)
|
|
499
|
+
? tint
|
|
500
|
+
: null;
|
|
501
|
+
if (paperOf(element))
|
|
502
|
+
papers.push(element);
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
renderFn(element, ctx, matrix.translate(dx, dy), this, rc, bound);
|
|
506
|
+
}
|
|
507
|
+
finally {
|
|
508
|
+
this._notationTint = null;
|
|
509
|
+
}
|
|
467
510
|
ctx.restore();
|
|
468
511
|
}
|
|
469
512
|
}
|
|
@@ -557,13 +600,103 @@ export class CanvasRenderer {
|
|
|
557
600
|
this._renderByBound(ctx, matrix, rc, bound, surfaceElements);
|
|
558
601
|
}
|
|
559
602
|
getColorScheme() {
|
|
560
|
-
return this.
|
|
603
|
+
return (this._schemeOverride ??
|
|
604
|
+
this.provider.getColorScheme?.() ??
|
|
605
|
+
ColorScheme.Light);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* A stored colour, resolved for the scheme in force.
|
|
609
|
+
*
|
|
610
|
+
* While a notation element is painted on a dark canvas, a PLAIN stored value
|
|
611
|
+
* (a string: what every framework writes) goes through the dark notation
|
|
612
|
+
* table as `use`; a `{ light, dark }` pair already knows its dark side and
|
|
613
|
+
* is never tinted, nor is a fallback (ADR 0039).
|
|
614
|
+
*/
|
|
615
|
+
getColorValue(color, fallback, real, use = 'ink') {
|
|
616
|
+
const value = this.provider.getColorValue?.(color, fallback, real, this._schemeOverride ?? undefined) ?? 'transparent';
|
|
617
|
+
return this._notationTint && typeof color === 'string' && color
|
|
618
|
+
? this._notationTint.resolve(value, use)
|
|
619
|
+
: value;
|
|
561
620
|
}
|
|
562
|
-
|
|
563
|
-
|
|
621
|
+
/**
|
|
622
|
+
* The colour of words drawn on a fill of the same element: tinted like any
|
|
623
|
+
* ink, unless the fill is painted as stored, in which case the words keep
|
|
624
|
+
* the colour they were chosen for on it ("ink follows its paper", ADR 0039).
|
|
625
|
+
* `fill` is `null` when the element draws no fill.
|
|
626
|
+
*/
|
|
627
|
+
getInkColorValue(color, fallback, fill) {
|
|
628
|
+
const tint = this._notationTint;
|
|
629
|
+
if (tint && typeof fill === 'string' && fill && tint.keepsInkOn(fill)) {
|
|
630
|
+
return (this.provider.getColorValue?.(color, fallback, true, this._schemeOverride ?? undefined) ?? 'transparent');
|
|
631
|
+
}
|
|
632
|
+
return this.getColorValue(color, fallback, true);
|
|
564
633
|
}
|
|
565
634
|
getPropertyValue(property) {
|
|
566
|
-
return this.provider.getPropertyValue?.(property) ?? '';
|
|
635
|
+
return (this.provider.getPropertyValue?.(property, this._schemeOverride ?? undefined) ?? '');
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Paint with `scheme` whatever the canvas shows. The SVG export paints
|
|
639
|
+
* light: a file is printed on white and read back by colour (ADR 0039).
|
|
640
|
+
*/
|
|
641
|
+
withColorScheme(scheme, paint) {
|
|
642
|
+
const previous = this._schemeOverride;
|
|
643
|
+
this._schemeOverride = scheme;
|
|
644
|
+
try {
|
|
645
|
+
return paint();
|
|
646
|
+
}
|
|
647
|
+
finally {
|
|
648
|
+
this._schemeOverride = previous;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* "Ink follows its paper" for words that are elements of their own (a C4
|
|
653
|
+
* title, an Event Storming label): text with no fill of its own, drawn on
|
|
654
|
+
* the topmost filled element under it that keeps its stored fill, keeps its
|
|
655
|
+
* stored colour too (ADR 0039). `papers` are the filled elements painted
|
|
656
|
+
* before it in this pass, in z-order.
|
|
657
|
+
*/
|
|
658
|
+
_sitsOnKeptPaper(element, papers, tint) {
|
|
659
|
+
if (paperOf(element))
|
|
660
|
+
return false;
|
|
661
|
+
const bound = element.elementBound;
|
|
662
|
+
for (let i = papers.length - 1; i >= 0; i--) {
|
|
663
|
+
const paper = papers[i];
|
|
664
|
+
if (paper.elementBound.contains(bound)) {
|
|
665
|
+
return tint.keepsInkOn(paperOf(paper));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
/** The dark table when this pass paints dark, else `null`. */
|
|
671
|
+
_tintForPass() {
|
|
672
|
+
if (this.getColorScheme() !== ColorScheme.Dark)
|
|
673
|
+
return null;
|
|
674
|
+
this._darkTint ??= new NotationTint([
|
|
675
|
+
...this.std.provider.getAll(NotationDarkPaletteIdentifier).values(),
|
|
676
|
+
]);
|
|
677
|
+
return this._darkTint;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Whether an element is part of a notation, read off the document as the
|
|
681
|
+
* colour carousel reads it (ADR 0027): its own role or its being a board,
|
|
682
|
+
* else (a connector) a role at either end, else a framework board it sits
|
|
683
|
+
* inside. A neutral element anywhere else is painted exactly as stored.
|
|
684
|
+
*/
|
|
685
|
+
_isNotation(element, boards) {
|
|
686
|
+
if (element.role)
|
|
687
|
+
return true;
|
|
688
|
+
// A board is notation whether or not it stamps a role (Cynefin does not).
|
|
689
|
+
if (element instanceof FrameworkBackgroundElementModel)
|
|
690
|
+
return true;
|
|
691
|
+
if (element instanceof ConnectorElementModel) {
|
|
692
|
+
for (const end of [element.source?.id, element.target?.id]) {
|
|
693
|
+
const model = end ? this._gfx.getElementById(end) : null;
|
|
694
|
+
if (model?.role)
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
const bound = element.elementBound;
|
|
699
|
+
return boards.some(board => board !== element && board.elementBound.contains(bound));
|
|
567
700
|
}
|
|
568
701
|
getDebugMetrics() {
|
|
569
702
|
return {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { FrameworkId } from '../../std/index.js';
|
|
2
|
+
import type { ExtensionType } from '../../store/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* The dark variant of the framework notations, resolved AT RENDER TIME
|
|
5
|
+
* (ADR 0039).
|
|
6
|
+
*
|
|
7
|
+
* A notation element stores plain colour values (`'#438dd5'`, the scale's
|
|
8
|
+
* `'#1f2328'`). On a dark canvas those values are not rewritten: the painter
|
|
9
|
+
* asks this table what to paint instead, so the document, the undo stack, the
|
|
10
|
+
* sync and every reader of a stored colour see exactly what they saw before.
|
|
11
|
+
*
|
|
12
|
+
* The rule is "the paper inverts, the hues stay":
|
|
13
|
+
*
|
|
14
|
+
* - the shared neutrals ({@link NOTATION_NEUTRALS}) map key for key onto
|
|
15
|
+
* {@link NOTATION_NEUTRALS_DARK};
|
|
16
|
+
* - a framework adds the few values of its own that would vanish on the dark
|
|
17
|
+
* card (a stencil ink, a near-black label, a pale wash behind words) through
|
|
18
|
+
* {@link NotationDarkPaletteExtension};
|
|
19
|
+
* - everything else, every hue of a standard included, is painted as stored.
|
|
20
|
+
* EDGY's facets, the C4 ladder, a BPMN end event and a colour typed by hand
|
|
21
|
+
* all stay what they are.
|
|
22
|
+
*
|
|
23
|
+
* White is the one value with two jobs: as a SURFACE (a node body, the board
|
|
24
|
+
* card) it is the paper and inverts; as an INK (white words on a C4 person,
|
|
25
|
+
* EDGY's white pictos) it stays. Hence the two uses below.
|
|
26
|
+
*/
|
|
27
|
+
/** What a colour is painted as: a line or words, or a surface. */
|
|
28
|
+
export type NotationColorUse = 'ink' | 'fill';
|
|
29
|
+
/**
|
|
30
|
+
* One framework's dark entries, light value → dark value. Keys are `#rrggbb`
|
|
31
|
+
* (any case); a stored `#rrggbbaa` keeps its alpha.
|
|
32
|
+
*
|
|
33
|
+
* `kept` lists the swatches of the framework's palette that deliberately have
|
|
34
|
+
* no dark entry (a standard's hue that reads on the dark card as it is), so a
|
|
35
|
+
* swatch added later without a decision fails `notation-dark-palettes`.
|
|
36
|
+
*/
|
|
37
|
+
export type NotationDarkPalette = {
|
|
38
|
+
framework: FrameworkId;
|
|
39
|
+
colors: Readonly<Record<string, string>>;
|
|
40
|
+
kept?: readonly string[];
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Multi-instance, keyed by framework, like `FrameworkPaletteIdentifier`: two
|
|
44
|
+
* registrations for one framework collide at set-up.
|
|
45
|
+
*/
|
|
46
|
+
export declare const NotationDarkPaletteIdentifier: import("../../global/di/types.js").ServiceIdentifier<NotationDarkPalette> & (<U extends NotationDarkPalette = NotationDarkPalette>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
|
|
47
|
+
/**
|
|
48
|
+
* Register a framework's dark entries. Call it from the ALWAYS-ON render view
|
|
49
|
+
* extension, beside the renderers: painting a stored document is content, so
|
|
50
|
+
* it never depends on the framework's flag (ADR 0009).
|
|
51
|
+
*/
|
|
52
|
+
export declare function NotationDarkPaletteExtension(palette: NotationDarkPalette): ExtensionType;
|
|
53
|
+
/**
|
|
54
|
+
* A resolved dark table: the neutrals plus every registered framework's
|
|
55
|
+
* entries. Pure; the canvas renderer builds one per editor and hands it to
|
|
56
|
+
* the painters of notation elements only.
|
|
57
|
+
*/
|
|
58
|
+
export declare class NotationTint {
|
|
59
|
+
private readonly _inks;
|
|
60
|
+
private readonly _surfaces;
|
|
61
|
+
/**
|
|
62
|
+
* `palettes` in any order. A light value two frameworks map differently is
|
|
63
|
+
* a declaration bug; the first one wins here and
|
|
64
|
+
* `notation-dark-palettes.unit.spec.ts` names it.
|
|
65
|
+
*/
|
|
66
|
+
constructor(palettes?: readonly NotationDarkPalette[]);
|
|
67
|
+
/**
|
|
68
|
+
* What to paint for a stored or declared `value`. Anything that is not a
|
|
69
|
+
* hex literal (`rgba(…)`, `transparent`, a variable) is returned untouched.
|
|
70
|
+
*/
|
|
71
|
+
resolve(value: string, use?: NotationColorUse): string;
|
|
72
|
+
/**
|
|
73
|
+
* Whether words drawn on this fill keep their stored colour ("ink follows
|
|
74
|
+
* its paper"): true when the fill is painted as stored and is opaque enough
|
|
75
|
+
* to be what the words sit on. A fill that inverts, or a wash below half
|
|
76
|
+
* opacity, puts the words on the dark card, so they invert too.
|
|
77
|
+
*
|
|
78
|
+
* This is what keeps black words on a C4 component and dark words on an
|
|
79
|
+
* Event Storming sticky readable while the same black on the bare card turns
|
|
80
|
+
* light.
|
|
81
|
+
*/
|
|
82
|
+
keepsInkOn(fill: string): boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The colour a painter of a notation element should use for a CONSTANT it
|
|
86
|
+
* holds (a board's declared wash, a glyph's stencil ink).
|
|
87
|
+
*
|
|
88
|
+
* `renderer` is optional and duck-typed on purpose: a unit test drives a
|
|
89
|
+
* painter with a bare stub, or with no renderer at all, and both must paint
|
|
90
|
+
* the value as given.
|
|
91
|
+
*/
|
|
92
|
+
export declare function notationColor(renderer: unknown, value: string, use?: NotationColorUse): string;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { NOTATION_NEUTRALS, NOTATION_NEUTRALS_DARK, } from '../../affine-shared/consts/index.js';
|
|
2
|
+
import { createIdentifier } from '../../global/di/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Multi-instance, keyed by framework, like `FrameworkPaletteIdentifier`: two
|
|
5
|
+
* registrations for one framework collide at set-up.
|
|
6
|
+
*/
|
|
7
|
+
export const NotationDarkPaletteIdentifier = createIdentifier('NotationDarkPalette');
|
|
8
|
+
/**
|
|
9
|
+
* Register a framework's dark entries. Call it from the ALWAYS-ON render view
|
|
10
|
+
* extension, beside the renderers: painting a stored document is content, so
|
|
11
|
+
* it never depends on the framework's flag (ADR 0009).
|
|
12
|
+
*/
|
|
13
|
+
export function NotationDarkPaletteExtension(palette) {
|
|
14
|
+
return {
|
|
15
|
+
setup: di => {
|
|
16
|
+
di.addImpl(NotationDarkPaletteIdentifier(palette.framework), () => palette);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const HEX = /^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
21
|
+
/** `#rgb` / `#rrggbb` / `#rrggbbaa` → lower-case `#rrggbb` and the alpha tail. */
|
|
22
|
+
function splitHex(value) {
|
|
23
|
+
const match = HEX.exec(value.trim());
|
|
24
|
+
if (!match)
|
|
25
|
+
return null;
|
|
26
|
+
const digits = match[1].toLowerCase();
|
|
27
|
+
if (digits.length === 3) {
|
|
28
|
+
return { rgb: `#${[...digits].map(d => d + d).join('')}`, alpha: '' };
|
|
29
|
+
}
|
|
30
|
+
return { rgb: `#${digits.slice(0, 6)}`, alpha: digits.slice(6) };
|
|
31
|
+
}
|
|
32
|
+
function normalised(table) {
|
|
33
|
+
const out = new Map();
|
|
34
|
+
for (const [light, dark] of Object.entries(table)) {
|
|
35
|
+
const key = splitHex(light);
|
|
36
|
+
if (key)
|
|
37
|
+
out.set(key.rgb, dark.toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
const NEUTRAL_KEYS = Object.keys(NOTATION_NEUTRALS);
|
|
42
|
+
/** The scale, light → dark, minus the card: white is a surface only. */
|
|
43
|
+
const NEUTRAL_INKS = Object.fromEntries(NEUTRAL_KEYS.filter(key => key !== 'cardFill').map(key => [
|
|
44
|
+
NOTATION_NEUTRALS[key],
|
|
45
|
+
NOTATION_NEUTRALS_DARK[key],
|
|
46
|
+
]));
|
|
47
|
+
/**
|
|
48
|
+
* A resolved dark table: the neutrals plus every registered framework's
|
|
49
|
+
* entries. Pure; the canvas renderer builds one per editor and hands it to
|
|
50
|
+
* the painters of notation elements only.
|
|
51
|
+
*/
|
|
52
|
+
export class NotationTint {
|
|
53
|
+
/**
|
|
54
|
+
* `palettes` in any order. A light value two frameworks map differently is
|
|
55
|
+
* a declaration bug; the first one wins here and
|
|
56
|
+
* `notation-dark-palettes.unit.spec.ts` names it.
|
|
57
|
+
*/
|
|
58
|
+
constructor(palettes = []) {
|
|
59
|
+
this._inks = normalised(NEUTRAL_INKS);
|
|
60
|
+
for (const palette of palettes) {
|
|
61
|
+
for (const [light, dark] of normalised(palette.colors)) {
|
|
62
|
+
if (!this._inks.has(light))
|
|
63
|
+
this._inks.set(light, dark);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
this._surfaces = normalised({
|
|
67
|
+
[NOTATION_NEUTRALS.cardFill]: NOTATION_NEUTRALS_DARK.cardFill,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What to paint for a stored or declared `value`. Anything that is not a
|
|
72
|
+
* hex literal (`rgba(…)`, `transparent`, a variable) is returned untouched.
|
|
73
|
+
*/
|
|
74
|
+
resolve(value, use = 'ink') {
|
|
75
|
+
const parts = splitHex(value);
|
|
76
|
+
if (!parts)
|
|
77
|
+
return value;
|
|
78
|
+
const dark = (use === 'fill' ? this._surfaces.get(parts.rgb) : undefined) ??
|
|
79
|
+
this._inks.get(parts.rgb);
|
|
80
|
+
return dark ? dark + parts.alpha : value;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Whether words drawn on this fill keep their stored colour ("ink follows
|
|
84
|
+
* its paper"): true when the fill is painted as stored and is opaque enough
|
|
85
|
+
* to be what the words sit on. A fill that inverts, or a wash below half
|
|
86
|
+
* opacity, puts the words on the dark card, so they invert too.
|
|
87
|
+
*
|
|
88
|
+
* This is what keeps black words on a C4 component and dark words on an
|
|
89
|
+
* Event Storming sticky readable while the same black on the bare card turns
|
|
90
|
+
* light.
|
|
91
|
+
*/
|
|
92
|
+
keepsInkOn(fill) {
|
|
93
|
+
const parts = splitHex(fill);
|
|
94
|
+
if (!parts)
|
|
95
|
+
return false;
|
|
96
|
+
if (parts.alpha && Number.parseInt(parts.alpha, 16) < 128)
|
|
97
|
+
return false;
|
|
98
|
+
return this.resolve(fill, 'fill') === fill;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The colour a painter of a notation element should use for a CONSTANT it
|
|
103
|
+
* holds (a board's declared wash, a glyph's stencil ink).
|
|
104
|
+
*
|
|
105
|
+
* `renderer` is optional and duck-typed on purpose: a unit test drives a
|
|
106
|
+
* painter with a bare stub, or with no renderer at all, and both must paint
|
|
107
|
+
* the value as given.
|
|
108
|
+
*/
|
|
109
|
+
export function notationColor(renderer, value, use = 'ink') {
|
|
110
|
+
const tint = renderer
|
|
111
|
+
?.notationTint;
|
|
112
|
+
return tint ? tint.resolve(value, use) : value;
|
|
113
|
+
}
|
|
@@ -152,9 +152,9 @@ let SurfaceBlockComponent = (() => {
|
|
|
152
152
|
gridManager: gfx.grid,
|
|
153
153
|
provider: {
|
|
154
154
|
generateColorProperty: (color, fallback) => themeService.generateColorProperty(color, fallback, themeService.edgelessTheme),
|
|
155
|
-
getColorValue: (color, fallback, real) => themeService.getColorValue(color, fallback, real, themeService.edgelessTheme),
|
|
155
|
+
getColorValue: (color, fallback, real, theme) => themeService.getColorValue(color, fallback, real, theme ?? themeService.edgelessTheme),
|
|
156
156
|
getColorScheme: () => themeService.edgelessTheme,
|
|
157
|
-
getPropertyValue: (property) => themeService.getCssVariableColor(property, themeService.edgelessTheme),
|
|
157
|
+
getPropertyValue: (property, theme) => themeService.getCssVariableColor(property, theme ?? themeService.edgelessTheme),
|
|
158
158
|
selectedElements: () => gfx.selection.selectedIds,
|
|
159
159
|
},
|
|
160
160
|
surfaceModel: this.model,
|
|
@@ -77,7 +77,8 @@ let MenuInput = (() => {
|
|
|
77
77
|
|
|
78
78
|
.affine-menu-input:focus {
|
|
79
79
|
border: 1px solid ${unsafeCSSVarV2('layer/insideBorder/primaryBorder')};
|
|
80
|
-
box-shadow: 0px 0px 0px 2px
|
|
80
|
+
box-shadow: 0px 0px 0px 2px
|
|
81
|
+
color-mix(in srgb, var(--affine-primary-color) 30%, transparent);
|
|
81
82
|
}
|
|
82
83
|
`; }
|
|
83
84
|
complete() {
|
|
@@ -34,6 +34,11 @@ export declare class MobileMenuComponent extends MobileMenuComponent_base implem
|
|
|
34
34
|
getFirstFocusableElement(): HTMLElement | null;
|
|
35
35
|
getFocusableElements(): HTMLElement[];
|
|
36
36
|
render(): import("lit-html").TemplateResult<1>;
|
|
37
|
+
/**
|
|
38
|
+
* Back, title, "Done": the two ends share what the title leaves, so the
|
|
39
|
+
* title stays centred, and "Done" is never cut, whatever its translation
|
|
40
|
+
* ("Terminé" overflowed the 50px it had).
|
|
41
|
+
*/
|
|
37
42
|
renderTitle(): import("lit-html").TemplateResult<1>;
|
|
38
43
|
accessor menu: Menu;
|
|
39
44
|
}
|
|
@@ -48,6 +53,8 @@ export type PopupTarget = {
|
|
|
48
53
|
targetRect: ReferenceElement;
|
|
49
54
|
root: HTMLElement;
|
|
50
55
|
popupStart: () => () => void;
|
|
56
|
+
/** The element the popup opens from, when there is one. */
|
|
57
|
+
element?: HTMLElement;
|
|
51
58
|
};
|
|
52
59
|
export declare const popupTargetFromElement: (element: HTMLElement) => PopupTarget;
|
|
53
60
|
export declare const createPopup: (target: PopupTarget, content: HTMLElement, options?: {
|
|
@@ -40,7 +40,7 @@ import { ArrowLeftBigIcon, ArrowLeftSmallIcon, CloseIcon, SearchIcon, } from '@b
|
|
|
40
40
|
import { ShadowlessElement, stdContext } from '../../std/index.js';
|
|
41
41
|
import { RANGE_SYNC_EXCLUDE_ATTR } from '../../std/inline/index.js';
|
|
42
42
|
import { autoPlacement, autoUpdate, computePosition, offset, shift, } from '@floating-ui/dom';
|
|
43
|
-
import { consume } from '@lit/context';
|
|
43
|
+
import { consume, ContextEvent, ContextProvider } from '@lit/context';
|
|
44
44
|
import { css, html, nothing } from 'lit';
|
|
45
45
|
import { property } from 'lit/decorators.js';
|
|
46
46
|
import { createRef, ref } from 'lit/directives/ref.js';
|
|
@@ -299,17 +299,22 @@ let MobileMenuComponent = (() => {
|
|
|
299
299
|
get std() { return this.#std_accessor_storage; }
|
|
300
300
|
set std(value) { this.#std_accessor_storage = value; }
|
|
301
301
|
static { this.styles = css `
|
|
302
|
+
/* A bottom action sheet, not a full-screen page: the view stays visible
|
|
303
|
+
above it and a tap on the scrim closes it (popMobileMenu). */
|
|
302
304
|
mobile-menu {
|
|
303
|
-
height:
|
|
305
|
+
max-height: 85%;
|
|
304
306
|
font-family: var(--affine-font-family);
|
|
305
307
|
display: flex;
|
|
306
308
|
flex-direction: column;
|
|
307
309
|
user-select: none;
|
|
308
310
|
width: 100%;
|
|
309
311
|
background-color: ${unsafeCSSVarV2('layer/background/secondary')};
|
|
310
|
-
padding: calc(8px + env(safe-area-inset-
|
|
311
|
-
calc(8px + env(safe-area-inset-bottom, 0px)) 8px;
|
|
312
|
+
padding: 8px 8px calc(8px + env(safe-area-inset-bottom, 0px)) 8px;
|
|
312
313
|
position: absolute;
|
|
314
|
+
left: 0;
|
|
315
|
+
bottom: 0;
|
|
316
|
+
border-radius: 12px 12px 0 0;
|
|
317
|
+
box-shadow: var(--affine-overlay-shadow);
|
|
313
318
|
z-index: 999;
|
|
314
319
|
color: ${unsafeCSSVarV2('text/primary')};
|
|
315
320
|
}
|
|
@@ -339,6 +344,11 @@ let MobileMenuComponent = (() => {
|
|
|
339
344
|
<div class="mobile-menu-body">${result}</div>
|
|
340
345
|
`;
|
|
341
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Back, title, "Done": the two ends share what the title leaves, so the
|
|
349
|
+
* title stays centred, and "Done" is never cut, whatever its translation
|
|
350
|
+
* ("Terminé" overflowed the 50px it had).
|
|
351
|
+
*/
|
|
342
352
|
renderTitle() {
|
|
343
353
|
const title = this.menu.options.title;
|
|
344
354
|
return html `
|
|
@@ -346,7 +356,7 @@ let MobileMenuComponent = (() => {
|
|
|
346
356
|
style="display:flex;align-items:center;height: 44px;"
|
|
347
357
|
@mouseenter="${() => this.menu.closeSubMenu()}"
|
|
348
358
|
>
|
|
349
|
-
<div style="
|
|
359
|
+
<div style="flex: 1 1 0;min-width: 50px;margin-left: 10px;">
|
|
350
360
|
${title?.onBack
|
|
351
361
|
? html ` <div
|
|
352
362
|
@click="${() => {
|
|
@@ -365,27 +375,33 @@ let MobileMenuComponent = (() => {
|
|
|
365
375
|
</div>
|
|
366
376
|
<div
|
|
367
377
|
style="
|
|
368
|
-
flex:1;
|
|
378
|
+
flex: 0 1 auto;
|
|
379
|
+
min-width: 0;
|
|
380
|
+
overflow: hidden;
|
|
381
|
+
text-overflow: ellipsis;
|
|
382
|
+
white-space: nowrap;
|
|
369
383
|
font-size: 17px;
|
|
370
384
|
font-style: normal;
|
|
371
385
|
font-weight: 500;
|
|
372
386
|
line-height: 22px;
|
|
373
387
|
color: var(--affine-text-primary-color);
|
|
374
|
-
|
|
375
|
-
justify-content: center;
|
|
388
|
+
text-align: center;
|
|
376
389
|
"
|
|
377
390
|
>
|
|
378
391
|
${title?.text}
|
|
379
392
|
</div>
|
|
380
393
|
<div
|
|
381
394
|
@click="${this.onClose}"
|
|
395
|
+
data-testid="mobile-menu-done"
|
|
382
396
|
style="
|
|
383
397
|
display:flex;
|
|
398
|
+
justify-content: flex-end;
|
|
384
399
|
font-weight: 500;
|
|
385
400
|
font-size: 17px;
|
|
386
401
|
color: ${unsafeCSSVarV2('button/primary')};
|
|
387
|
-
|
|
388
|
-
|
|
402
|
+
flex: 1 1 0;
|
|
403
|
+
min-width: max-content;
|
|
404
|
+
white-space: nowrap;
|
|
389
405
|
margin-right: 10px;
|
|
390
406
|
"
|
|
391
407
|
>
|
|
@@ -452,6 +468,7 @@ export const popupTargetFromElement = (element) => {
|
|
|
452
468
|
},
|
|
453
469
|
},
|
|
454
470
|
root: getDefaultModalRoot(element),
|
|
471
|
+
element,
|
|
455
472
|
popupStart: () => {
|
|
456
473
|
if (!count) {
|
|
457
474
|
isActive = element.classList.contains('active');
|
|
@@ -509,9 +526,32 @@ export const createPopup = (target, content, options) => {
|
|
|
509
526
|
};
|
|
510
527
|
return close;
|
|
511
528
|
};
|
|
512
|
-
|
|
529
|
+
/** The editor an element sits in, asked the way a `@consume` asks. */
|
|
530
|
+
const stdAround = (element) => {
|
|
531
|
+
let std;
|
|
532
|
+
element?.dispatchEvent(new ContextEvent(stdContext, element, value => {
|
|
533
|
+
std = value;
|
|
534
|
+
}));
|
|
535
|
+
return std;
|
|
536
|
+
};
|
|
537
|
+
/**
|
|
538
|
+
* A phone's sheet hangs from the body, out of the editor's DOM, where nothing
|
|
539
|
+
* provides `std`: its modal provides the editor of the element it opens from,
|
|
540
|
+
* so the sheet's "Done" and whatever it renders speak the host's catalogue,
|
|
541
|
+
* and a sub-menu opened from it finds the same editor again.
|
|
542
|
+
*/
|
|
543
|
+
const popMobileMenu = (options, target) => {
|
|
513
544
|
const model = createModal(document.body);
|
|
545
|
+
const std = stdAround(target?.element);
|
|
546
|
+
if (std) {
|
|
547
|
+
new ContextProvider(model, { context: stdContext, initialValue: std });
|
|
548
|
+
}
|
|
514
549
|
model.style.position = 'fixed';
|
|
550
|
+
model.style.background = 'var(--affine-v2-layer-background-mobile-modal)';
|
|
551
|
+
model.addEventListener('click', e => {
|
|
552
|
+
if (e.target === model)
|
|
553
|
+
menu.close();
|
|
554
|
+
});
|
|
515
555
|
const menu = new Menu({
|
|
516
556
|
...options,
|
|
517
557
|
onClose: () => {
|
|
@@ -530,13 +570,13 @@ const popMobileMenu = (options) => {
|
|
|
530
570
|
menu,
|
|
531
571
|
reopen: () => {
|
|
532
572
|
menu.close();
|
|
533
|
-
popMobileMenu(options);
|
|
573
|
+
popMobileMenu(options, target);
|
|
534
574
|
},
|
|
535
575
|
};
|
|
536
576
|
};
|
|
537
577
|
export const popMenu = (target, props) => {
|
|
538
578
|
if (IS_MOBILE) {
|
|
539
|
-
return popMobileMenu(props.options);
|
|
579
|
+
return popMobileMenu(props.options, target);
|
|
540
580
|
}
|
|
541
581
|
const popupEnd = target.popupStart();
|
|
542
582
|
const onClose = () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NoteBlockModel } from '../../affine-model/index.js';
|
|
2
|
+
import { pageDropVerdict } from '../../affine-shared/services/index.js';
|
|
2
3
|
import { calcDropTarget, getClosestBlockComponentByPoint, isInsidePageEditor, matchModels, } from '../../affine-shared/utils/index.js';
|
|
3
4
|
import { createIdentifier } from '../../global/di/index.js';
|
|
4
5
|
import { Point } from '../../global/gfx/index.js';
|
|
@@ -59,7 +60,21 @@ export class FileDropExtension extends LifeCycleWatcher {
|
|
|
59
60
|
this.point$.value = null;
|
|
60
61
|
};
|
|
61
62
|
this.onDragOver = (event) => {
|
|
63
|
+
// A page the host refuses here (`PageDropProvider`): no drop line, and
|
|
64
|
+
// no preventDefault, so the browser shows its no-drop cursor and never
|
|
65
|
+
// fires the drop.
|
|
66
|
+
const verdict = pageDropVerdict(this.std, event.dataTransfer);
|
|
67
|
+
if (verdict === 'refuse') {
|
|
68
|
+
if (event.dataTransfer)
|
|
69
|
+
event.dataTransfer.dropEffect = 'none';
|
|
70
|
+
this.onDragLeave();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
62
73
|
event.preventDefault();
|
|
74
|
+
// The host's drag allows 'move' only: say so, or the drop never fires.
|
|
75
|
+
if (verdict === 'accept' && event.dataTransfer) {
|
|
76
|
+
event.dataTransfer.dropEffect = 'move';
|
|
77
|
+
}
|
|
63
78
|
if (this.shouldIgnoreEvent(event))
|
|
64
79
|
return;
|
|
65
80
|
this.updatePoint(event);
|
|
@@ -18,8 +18,10 @@ const shapeRenderers = {
|
|
|
18
18
|
polygon,
|
|
19
19
|
};
|
|
20
20
|
export const shape = (model, ctx, matrix, renderer, rc) => {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// A notation body is a surface: on a dark canvas a white one inverts with
|
|
22
|
+
// the paper, and the words on it follow their paper (ADR 0039).
|
|
23
|
+
const fillColor = renderer.getColorValue(model.fillColor, DefaultTheme.shapeFillColor, true, 'fill');
|
|
24
|
+
const color = renderer.getInkColorValue(model.color, DefaultTheme.shapeTextColor, model.filled ? model.fillColor : null);
|
|
23
25
|
const strokeColor = renderer.getColorValue(model.strokeColor, DefaultTheme.shapeStrokeColor, true);
|
|
24
26
|
const colors = { color, fillColor, strokeColor };
|
|
25
27
|
shapeRenderers[model.shapeType](model, ctx, matrix, renderer, rc, colors);
|