@formicoidea/labre-core 0.52.0 → 0.54.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/services/thread-marks-service.d.ts +32 -1
- 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/excerpt.d.ts +6 -2
- package/dist/_pkgs/affine-widget-thread-marks/excerpt.js +8 -0
- package/dist/_pkgs/affine-widget-thread-marks/index.d.ts +1 -0
- package/dist/_pkgs/affine-widget-thread-marks/index.js +1 -0
- package/dist/_pkgs/affine-widget-thread-marks/text-range.d.ts +26 -0
- package/dist/_pkgs/affine-widget-thread-marks/text-range.js +59 -0
- package/dist/_pkgs/affine-widget-thread-marks/toolbar.d.ts +4 -3
- package/dist/_pkgs/affine-widget-thread-marks/toolbar.js +24 -8
- package/dist/_pkgs/affine-widget-thread-marks/widget.d.ts +33 -2
- package/dist/_pkgs/affine-widget-thread-marks/widget.js +121 -5
- 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 +47 -0
- package/dist/_pkgs/data-view/translations.js +124 -0
- 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 +4 -2
- package/dist/_pkgs/data-view/view-presets/table/mobile/header.js +17 -9
- package/dist/_pkgs/data-view/view-presets/table/mobile/row.js +20 -11
- 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.js +2 -2
- package/dist/_pkgs/data-view/view-presets/table/pc/group.js +4 -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/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/table-add-row/add-row.d.ts +3 -0
- package/dist/_pkgs/data-view/widget-presets/tools/presets/table-add-row/add-row.js +99 -35
- 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/dist/host-panels.d.ts +1 -1
- package/dist/host-panels.js +2 -1
- package/package.json +1 -1
package/dist/_pkgs/affine-inline-reference/reference-node/reference-popup/reference-popup.js
CHANGED
|
@@ -137,7 +137,7 @@ let ReferencePopup = (() => {
|
|
|
137
137
|
box-sizing: border-box;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
.overlay-mask {
|
|
140
|
+
reference-popup .overlay-mask {
|
|
141
141
|
position: fixed;
|
|
142
142
|
z-index: var(--affine-z-index-popover);
|
|
143
143
|
top: 0;
|
|
@@ -146,8 +146,8 @@ let ReferencePopup = (() => {
|
|
|
146
146
|
height: 100vh;
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
${panelBaseStyle('.popover-container')}
|
|
150
|
-
.popover-container {
|
|
149
|
+
${panelBaseStyle('reference-popup .popover-container')}
|
|
150
|
+
reference-popup .popover-container {
|
|
151
151
|
position: absolute;
|
|
152
152
|
display: flex;
|
|
153
153
|
gap: 8px;
|
|
@@ -169,7 +169,7 @@ let ReferencePopup = (() => {
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
input {
|
|
172
|
+
reference-popup input {
|
|
173
173
|
display: flex;
|
|
174
174
|
flex: 1;
|
|
175
175
|
padding: 0;
|
|
@@ -177,16 +177,16 @@ let ReferencePopup = (() => {
|
|
|
177
177
|
background: transparent;
|
|
178
178
|
color: var(--affine-text-primary-color);
|
|
179
179
|
}
|
|
180
|
-
${fontXSStyle('input')}
|
|
181
|
-
input::placeholder {
|
|
180
|
+
${fontXSStyle('reference-popup input')}
|
|
181
|
+
reference-popup input::placeholder {
|
|
182
182
|
color: var(--affine-placeholder-color);
|
|
183
183
|
}
|
|
184
|
-
input:focus {
|
|
184
|
+
reference-popup input:focus {
|
|
185
185
|
outline: none;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
${fontXSStyle('editor-icon-button.save .label')}
|
|
189
|
-
editor-icon-button.save .label {
|
|
188
|
+
${fontXSStyle('reference-popup editor-icon-button.save .label')}
|
|
189
|
+
reference-popup editor-icon-button.save .label {
|
|
190
190
|
color: inherit;
|
|
191
191
|
text-transform: none;
|
|
192
192
|
}
|
|
@@ -63,3 +63,32 @@ const SCALE = {
|
|
|
63
63
|
* colour is (a helper whose parameter type is inferred from a default).
|
|
64
64
|
*/
|
|
65
65
|
export const NOTATION_NEUTRALS = Object.freeze(SCALE);
|
|
66
|
+
/**
|
|
67
|
+
* The same scale on the dark canvas, key for key (ADR 0039). A canvas in the
|
|
68
|
+
* dark scheme does not show a white card with a near-black ink: the PAPER
|
|
69
|
+
* inverts and the hues stay. These values are what a notation element is
|
|
70
|
+
* painted with at render time when the canvas is dark; nothing is written to a
|
|
71
|
+
* document, and the SVG export keeps the light scale.
|
|
72
|
+
*
|
|
73
|
+
* Read off the dark chrome the editor already paints (`@toeverything/theme`,
|
|
74
|
+
* AFFiNE's dark tables): the card is the dark page itself (`rgb(20, 20, 20)`,
|
|
75
|
+
* `--affine-background-primary-color`), exactly as the light card is the white
|
|
76
|
+
* page, so a board is told apart by its border in both schemes; the ink is the
|
|
77
|
+
* dark primary text (`rgb(234, 234, 234)`) and the label the dark secondary
|
|
78
|
+
* text (`rgb(156, 156, 160)`). Every other step keeps the contrast its light
|
|
79
|
+
* twin has on white, within a hair (`notation-dark-scale.unit.spec.ts`).
|
|
80
|
+
*
|
|
81
|
+
* The card being the page is also what keeps a dark accent around 3:1 under a
|
|
82
|
+
* selection (labre ADR-0049, question 2): anything lighter than the page
|
|
83
|
+
* beneath a selection frame lowers it.
|
|
84
|
+
*/
|
|
85
|
+
const DARK_SCALE = {
|
|
86
|
+
ink: '#eaeaea',
|
|
87
|
+
frameInk: '#c4c5c9',
|
|
88
|
+
label: '#9c9ca0',
|
|
89
|
+
divider: '#5f6166',
|
|
90
|
+
cardFill: '#141414',
|
|
91
|
+
cardBorder: '#3a3a3c',
|
|
92
|
+
legendBorder: '#4b4d52',
|
|
93
|
+
};
|
|
94
|
+
export const NOTATION_NEUTRALS_DARK = Object.freeze(DARK_SCALE);
|
|
@@ -61,6 +61,10 @@ export interface FrameTemplateFrameRef {
|
|
|
61
61
|
* your id for the template: link what the copy references (its images) to
|
|
62
62
|
* that document. Not called when the insertion failed.
|
|
63
63
|
*
|
|
64
|
+
* - `showTemplates` (since 0.54) is called by the « View » action of the
|
|
65
|
+
* notification that says a save succeeded: open the place where the viewer
|
|
66
|
+
* finds the saved template. Absent, that notification has no action.
|
|
67
|
+
*
|
|
64
68
|
* Both notifications may come twice for one gesture (two editors mounted on
|
|
65
69
|
* one document): make them idempotent.
|
|
66
70
|
*/
|
|
@@ -70,6 +74,7 @@ export interface FrameTemplateService {
|
|
|
70
74
|
frameDeleted?(frame: FrameTemplateFrameRef): void;
|
|
71
75
|
frameRestored?(frame: FrameTemplateFrameRef): void;
|
|
72
76
|
frameInserted?(insertion: FrameTemplateInsertion): void;
|
|
77
|
+
showTemplates?(): void;
|
|
73
78
|
}
|
|
74
79
|
export declare const FrameTemplateProvider: import("../../global/di/types.js").ServiceIdentifier<FrameTemplateService> & (<U extends FrameTemplateService = FrameTemplateService>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
|
|
75
80
|
/**
|
|
@@ -29,6 +29,7 @@ export * from './native-clipboard-service.js';
|
|
|
29
29
|
export * from './notification-service.js';
|
|
30
30
|
export * from './open-doc-config.js';
|
|
31
31
|
export * from './outline-panel-service.js';
|
|
32
|
+
export * from './page-drop-service.js';
|
|
32
33
|
export * from './page-viewport-service.js';
|
|
33
34
|
export * from './parse-url-service.js';
|
|
34
35
|
export * from './pivot-materiality-publisher.js';
|
|
@@ -29,6 +29,7 @@ export * from './native-clipboard-service.js';
|
|
|
29
29
|
export * from './notification-service.js';
|
|
30
30
|
export * from './open-doc-config.js';
|
|
31
31
|
export * from './outline-panel-service.js';
|
|
32
|
+
export * from './page-drop-service.js';
|
|
32
33
|
export * from './page-viewport-service.js';
|
|
33
34
|
export * from './parse-url-service.js';
|
|
34
35
|
export * from './pivot-materiality-publisher.js';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { BlockStdScope } from '../../std/index.js';
|
|
2
|
+
import type { ExtensionType } from '../../store/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* What the host says about a native drag over an editor (dragover).
|
|
5
|
+
*
|
|
6
|
+
* - `'ignore'`: not one of the host's pages; the editor treats it as before.
|
|
7
|
+
* - `'refuse'`: one of the host's pages that may not land in this document;
|
|
8
|
+
* the browser shows its no-drop cursor and no drop line is drawn.
|
|
9
|
+
* - `'accept'`: the drop line is drawn and the drop calls `drop`.
|
|
10
|
+
*/
|
|
11
|
+
export type PageDropVerdict = 'ignore' | 'refuse' | 'accept';
|
|
12
|
+
/** The page a drop placed, and how to undo what the host did for it. */
|
|
13
|
+
export interface PageDrop {
|
|
14
|
+
/** The page whose `affine:embed-linked-doc` card goes where it was dropped. */
|
|
15
|
+
pageId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Called when the undo step that holds the card is undone (Mod+Z, the
|
|
18
|
+
* history), after the card is gone: put back what `drop` changed.
|
|
19
|
+
*/
|
|
20
|
+
undo?: () => void;
|
|
21
|
+
/** Called when that step is redone, after the card is back. */
|
|
22
|
+
redo?: () => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Pages dragged from the host's own chrome (a sidebar tree) into the editor
|
|
26
|
+
* (labre P7, ADR-0045 §7 amended 2026-10-16): the host recognises its drag
|
|
27
|
+
* and decides what the drop means; the editor draws the drop line and places
|
|
28
|
+
* a card of the page where it was dropped (the drop line in a note, the drop
|
|
29
|
+
* point on the canvas), in one undo step that also carries the host's
|
|
30
|
+
* `undo` / `redo`.
|
|
31
|
+
*
|
|
32
|
+
* - `verdict` is called on every dragover. The browser exposes only
|
|
33
|
+
* `dataTransfer.types` then, never the data: the host knows which page it is
|
|
34
|
+
* dragging from its own state. A read-only document refuses whatever the
|
|
35
|
+
* host says.
|
|
36
|
+
* - `drop` is called once, synchronously, for a drop the last `verdict`
|
|
37
|
+
* accepted. Return `null` to place nothing (the host changed its mind).
|
|
38
|
+
* The editor never copies or creates a page: the card references `pageId`.
|
|
39
|
+
*/
|
|
40
|
+
export interface PageDropService {
|
|
41
|
+
verdict(drag: {
|
|
42
|
+
types: readonly string[];
|
|
43
|
+
docId: string;
|
|
44
|
+
}): PageDropVerdict;
|
|
45
|
+
drop(drag: {
|
|
46
|
+
dataTransfer: DataTransfer;
|
|
47
|
+
docId: string;
|
|
48
|
+
}): PageDrop | null;
|
|
49
|
+
}
|
|
50
|
+
export declare const PageDropProvider: import("../../global/di/types.js").ServiceIdentifier<PageDropService> & (<U extends PageDropService = PageDropService>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
|
|
51
|
+
/**
|
|
52
|
+
* Host seam: accept pages dragged from the host into the editor. Absent, such
|
|
53
|
+
* a drag is any other foreign drag: the page view draws its drop line and the
|
|
54
|
+
* drop does nothing.
|
|
55
|
+
*
|
|
56
|
+
* `di.override`, like `FrameTemplateExtension`, so a later registration wins
|
|
57
|
+
* and registering twice never throws at boot.
|
|
58
|
+
*/
|
|
59
|
+
export declare function PageDropExtension(service: PageDropService): ExtensionType;
|
|
60
|
+
/** The verdict for a native drag over `std`'s editor, read-only included. */
|
|
61
|
+
export declare function pageDropVerdict(std: Pick<BlockStdScope, 'getOptional' | 'store'>, dataTransfer: DataTransfer | null): PageDropVerdict;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createIdentifier } from '../../global/di/index.js';
|
|
2
|
+
export const PageDropProvider = createIdentifier('AffinePageDrop');
|
|
3
|
+
/**
|
|
4
|
+
* Host seam: accept pages dragged from the host into the editor. Absent, such
|
|
5
|
+
* a drag is any other foreign drag: the page view draws its drop line and the
|
|
6
|
+
* drop does nothing.
|
|
7
|
+
*
|
|
8
|
+
* `di.override`, like `FrameTemplateExtension`, so a later registration wins
|
|
9
|
+
* and registering twice never throws at boot.
|
|
10
|
+
*/
|
|
11
|
+
export function PageDropExtension(service) {
|
|
12
|
+
return {
|
|
13
|
+
setup: di => {
|
|
14
|
+
di.override(PageDropProvider, () => service);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** The verdict for a native drag over `std`'s editor, read-only included. */
|
|
19
|
+
export function pageDropVerdict(std, dataTransfer) {
|
|
20
|
+
const service = std.getOptional(PageDropProvider);
|
|
21
|
+
if (!service || !dataTransfer)
|
|
22
|
+
return 'ignore';
|
|
23
|
+
const verdict = service.verdict({
|
|
24
|
+
types: [...dataTransfer.types],
|
|
25
|
+
docId: std.store.id,
|
|
26
|
+
});
|
|
27
|
+
if (verdict === 'ignore')
|
|
28
|
+
return 'ignore';
|
|
29
|
+
return std.store.readonly ? 'refuse' : verdict;
|
|
30
|
+
}
|
|
@@ -6,6 +6,21 @@ import type { ReadonlySignal } from '@preact/signals-core';
|
|
|
6
6
|
* the one the library already gives it: a block id, an element id.
|
|
7
7
|
*/
|
|
8
8
|
export type ThreadMarkTargetType = 'block' | 'element';
|
|
9
|
+
/**
|
|
10
|
+
* A run of text inside one block (ADR 0038, amendment of 2026-10-15): two
|
|
11
|
+
* Yjs relative positions on the block's `Y.Text`, each encoded with
|
|
12
|
+
* `Y.encodeRelativePosition` then base64. Opaque to the host, which stores
|
|
13
|
+
* and returns the two strings as they are; only the library reads them.
|
|
14
|
+
*
|
|
15
|
+
* A relative position follows the text through local and remote edits and is
|
|
16
|
+
* computed by reading, never by writing: nothing lands in the document. When
|
|
17
|
+
* the text it points at is gone, the range no longer resolves and the library
|
|
18
|
+
* falls back to the block.
|
|
19
|
+
*/
|
|
20
|
+
export interface ThreadTextRange {
|
|
21
|
+
start: string;
|
|
22
|
+
end: string;
|
|
23
|
+
}
|
|
9
24
|
/**
|
|
10
25
|
* One marked target of the mounted document, as the host computes it. Ids and
|
|
11
26
|
* counters only: the library never learns what the host attaches to a target,
|
|
@@ -19,6 +34,14 @@ export interface ThreadMark {
|
|
|
19
34
|
targetId: string;
|
|
20
35
|
count: number;
|
|
21
36
|
unread: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The text the discussion is anchored to, for a `block` target (ignored on
|
|
39
|
+
* an `element`). Optional (ADR 0038 amendment): without it only the
|
|
40
|
+
* block's mark is drawn; with it the run is also highlighted in the page
|
|
41
|
+
* view, and a click on it opens the discussion. A range that no longer
|
|
42
|
+
* resolves is not drawn, and the block's mark stays.
|
|
43
|
+
*/
|
|
44
|
+
range?: ThreadTextRange;
|
|
22
45
|
}
|
|
23
46
|
/**
|
|
24
47
|
* What the library hands the host when someone clicks a mark or "Discuss"
|
|
@@ -26,7 +49,8 @@ export interface ThreadMark {
|
|
|
26
49
|
*
|
|
27
50
|
* `excerpt` is computed here because the library knows the content: the
|
|
28
51
|
* block's text (its descendants' for a container such as a note), a canvas
|
|
29
|
-
* element's label as the selection pane reads it, else the kind of target
|
|
52
|
+
* element's label as the selection pane reads it, else the kind of target;
|
|
53
|
+
* for a text range, the text it covers.
|
|
30
54
|
* Whitespace is collapsed and it is cut to at most 280 characters, an
|
|
31
55
|
* ellipsis included (`THREAD_EXCERPT_MAX`). It is a snapshot for the host to
|
|
32
56
|
* store beside its anchor; the library keeps no copy.
|
|
@@ -36,6 +60,13 @@ export interface ThreadOpenRequest {
|
|
|
36
60
|
targetType: ThreadMarkTargetType;
|
|
37
61
|
targetId: string;
|
|
38
62
|
excerpt: string;
|
|
63
|
+
/**
|
|
64
|
+
* Set when the discussion starts on a text selection, or on a highlighted
|
|
65
|
+
* range (ADR 0038 amendment): the block is still `targetId` and
|
|
66
|
+
* `excerpt` is the selected text itself. Absent for a whole block or an
|
|
67
|
+
* element.
|
|
68
|
+
*/
|
|
69
|
+
range?: ThreadTextRange;
|
|
39
70
|
}
|
|
40
71
|
/** The longest excerpt `openThread` is ever handed, in code points. */
|
|
41
72
|
export declare const THREAD_EXCERPT_MAX = 280;
|
|
@@ -23,7 +23,7 @@ export const scrollbarStyle = (container) => {
|
|
|
23
23
|
}
|
|
24
24
|
${unsafeCSS(container)}::-webkit-scrollbar-thumb {
|
|
25
25
|
border-radius: 2px;
|
|
26
|
-
background-color:
|
|
26
|
+
background-color: var(--affine-text-disable-color);
|
|
27
27
|
}
|
|
28
28
|
${unsafeCSS(container)}::-webkit-scrollbar-corner {
|
|
29
29
|
display: none;
|
|
@@ -157,7 +157,7 @@ let EdgelessAutoConnectWidget = (() => {
|
|
|
157
157
|
.page-visible-index-label {
|
|
158
158
|
box-sizing: border-box;
|
|
159
159
|
padding: 0px 6px;
|
|
160
|
-
border: 1px solid
|
|
160
|
+
border: 1px solid var(--affine-black-10);
|
|
161
161
|
|
|
162
162
|
width: fit-content;
|
|
163
163
|
height: 24px;
|
|
@@ -179,9 +179,9 @@ let EdgelessAutoConnectWidget = (() => {
|
|
|
179
179
|
width: 48px;
|
|
180
180
|
padding: 4px;
|
|
181
181
|
border-radius: 58px;
|
|
182
|
-
border: 1px solid
|
|
182
|
+
border: 1px solid var(--affine-border-color);
|
|
183
183
|
transition: opacity 0.5s ease-in-out;
|
|
184
|
-
background:
|
|
184
|
+
background: var(--affine-background-overlay-panel-color);
|
|
185
185
|
display: flex;
|
|
186
186
|
align-items: center;
|
|
187
187
|
justify-content: space-between;
|
|
@@ -197,7 +197,7 @@ let EdgelessAutoConnectWidget = (() => {
|
|
|
197
197
|
.navigator span {
|
|
198
198
|
display: inline-block;
|
|
199
199
|
height: 8px;
|
|
200
|
-
border: 1px solid
|
|
200
|
+
border: 1px solid var(--affine-border-color);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
.navigator div:hover {
|
|
@@ -357,7 +357,7 @@ let EdgelessAutoConnectWidget = (() => {
|
|
|
357
357
|
const iconStyle = {
|
|
358
358
|
width: '16px',
|
|
359
359
|
height: '16px',
|
|
360
|
-
style: 'color
|
|
360
|
+
style: 'color:var(--affine-icon-color);',
|
|
361
361
|
};
|
|
362
362
|
return html `<div class=${className} style=${navigatorStyle}>
|
|
363
363
|
<div
|
|
@@ -180,8 +180,8 @@ let EdgelessAutoComplete = (() => {
|
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
.edgeless-auto-complete-arrow svg {
|
|
183
|
-
fill:
|
|
184
|
-
color:
|
|
183
|
+
fill: var(--affine-icon-color);
|
|
184
|
+
color: var(--affine-icon-color);
|
|
185
185
|
}
|
|
186
186
|
.edgeless-auto-complete-arrow:hover svg {
|
|
187
187
|
fill: #ffffff;
|
|
@@ -563,7 +563,7 @@ const textStyleToolItems = [
|
|
|
563
563
|
icon: BoldIcon(),
|
|
564
564
|
background: ({ std }) => {
|
|
565
565
|
const [_, { textAttributes }] = std.command.exec(getTextAttributes);
|
|
566
|
-
return textAttributes?.bold ? '
|
|
566
|
+
return textAttributes?.bold ? 'var(--affine-hover-color)' : '';
|
|
567
567
|
},
|
|
568
568
|
action: ({ std }) => {
|
|
569
569
|
std.command.exec(toggleBold);
|
|
@@ -574,7 +574,7 @@ const textStyleToolItems = [
|
|
|
574
574
|
icon: ItalicIcon(),
|
|
575
575
|
background: ({ std }) => {
|
|
576
576
|
const [_, { textAttributes }] = std.command.exec(getTextAttributes);
|
|
577
|
-
return textAttributes?.italic ? '
|
|
577
|
+
return textAttributes?.italic ? 'var(--affine-hover-color)' : '';
|
|
578
578
|
},
|
|
579
579
|
action: ({ std }) => {
|
|
580
580
|
std.command.exec(toggleItalic);
|
|
@@ -585,7 +585,7 @@ const textStyleToolItems = [
|
|
|
585
585
|
icon: UnderLineIcon(),
|
|
586
586
|
background: ({ std }) => {
|
|
587
587
|
const [_, { textAttributes }] = std.command.exec(getTextAttributes);
|
|
588
|
-
return textAttributes?.underline ? '
|
|
588
|
+
return textAttributes?.underline ? 'var(--affine-hover-color)' : '';
|
|
589
589
|
},
|
|
590
590
|
action: ({ std }) => {
|
|
591
591
|
std.command.exec(toggleUnderline);
|
|
@@ -596,7 +596,7 @@ const textStyleToolItems = [
|
|
|
596
596
|
icon: StrikeThroughIcon(),
|
|
597
597
|
background: ({ std }) => {
|
|
598
598
|
const [_, { textAttributes }] = std.command.exec(getTextAttributes);
|
|
599
|
-
return textAttributes?.strike ? '
|
|
599
|
+
return textAttributes?.strike ? 'var(--affine-hover-color)' : '';
|
|
600
600
|
},
|
|
601
601
|
action: ({ std }) => {
|
|
602
602
|
std.command.exec(toggleStrike);
|
|
@@ -607,7 +607,7 @@ const textStyleToolItems = [
|
|
|
607
607
|
icon: CodeIcon(),
|
|
608
608
|
background: ({ std }) => {
|
|
609
609
|
const [_, { textAttributes }] = std.command.exec(getTextAttributes);
|
|
610
|
-
return textAttributes?.code ? '
|
|
610
|
+
return textAttributes?.code ? 'var(--affine-hover-color)' : '';
|
|
611
611
|
},
|
|
612
612
|
action: ({ std }) => {
|
|
613
613
|
std.command.exec(toggleCode);
|
|
@@ -618,7 +618,7 @@ const textStyleToolItems = [
|
|
|
618
618
|
icon: LinkIcon(),
|
|
619
619
|
background: ({ std }) => {
|
|
620
620
|
const [_, { textAttributes }] = std.command.exec(getTextAttributes);
|
|
621
|
-
return textAttributes?.link ? '
|
|
621
|
+
return textAttributes?.link ? 'var(--affine-hover-color)' : '';
|
|
622
622
|
},
|
|
623
623
|
action: ({ std }) => {
|
|
624
624
|
std.command.exec(toggleLink);
|
|
@@ -44,6 +44,14 @@ export declare function createLinkedDocMenuGroup(query: string, abort: () => voi
|
|
|
44
44
|
overflowText: string;
|
|
45
45
|
};
|
|
46
46
|
export declare function createNewDocMenuGroup(query: string, abort: () => void, editorHost: EditorHost, inlineEditor: AffineInlineEditor): LinkedMenuGroup;
|
|
47
|
+
/**
|
|
48
|
+
* The default `@` menu REFERENCES a page that exists; it creates nothing.
|
|
49
|
+
* Creating a page is the slash menu's job ("New Page", which goes through
|
|
50
|
+
* `LinkedDocCreationProvider`), so the two gestures never overlap: `@` points,
|
|
51
|
+
* `/` makes (PO, 2026-10-14). The creation group is still exported through
|
|
52
|
+
* {@link LinkedWidgetUtils} for a host that wants it back in its own
|
|
53
|
+
* `getMenus`.
|
|
54
|
+
*/
|
|
47
55
|
export declare function getMenus(query: string, abort: () => void, editorHost: EditorHost, inlineEditor: AffineInlineEditor): Promise<LinkedMenuGroup[]>;
|
|
48
56
|
export declare const LinkedWidgetUtils: {
|
|
49
57
|
createNewDocMenuGroup: typeof createNewDocMenuGroup;
|
|
@@ -120,10 +120,17 @@ export function createNewDocMenuGroup(query, abort, editorHost, inlineEditor) {
|
|
|
120
120
|
items,
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* The default `@` menu REFERENCES a page that exists; it creates nothing.
|
|
125
|
+
* Creating a page is the slash menu's job ("New Page", which goes through
|
|
126
|
+
* `LinkedDocCreationProvider`), so the two gestures never overlap: `@` points,
|
|
127
|
+
* `/` makes (PO, 2026-10-14). The creation group is still exported through
|
|
128
|
+
* {@link LinkedWidgetUtils} for a host that wants it back in its own
|
|
129
|
+
* `getMenus`.
|
|
130
|
+
*/
|
|
123
131
|
export function getMenus(query, abort, editorHost, inlineEditor) {
|
|
124
132
|
return Promise.resolve([
|
|
125
133
|
createLinkedDocMenuGroup(query, abort, editorHost, inlineEditor),
|
|
126
|
-
createNewDocMenuGroup(query, abort, editorHost, inlineEditor),
|
|
127
134
|
]);
|
|
128
135
|
}
|
|
129
136
|
export const LinkedWidgetUtils = {
|
|
@@ -47,7 +47,7 @@ import { property, query, queryAll, state } from 'lit/decorators.js';
|
|
|
47
47
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
48
48
|
import throttle from 'lodash-es/throttle.js';
|
|
49
49
|
import { linkedDocPopoverStyles } from './styles.js';
|
|
50
|
-
import { LINKED_DOC_OVERFLOW_MORE } from './translations.js';
|
|
50
|
+
import { LINKED_DOC_NO_RESULT, LINKED_DOC_OVERFLOW_MORE, } from './translations.js';
|
|
51
51
|
import { createLinkedDocKeydownInterceptor, resolveSignal } from './utils.js';
|
|
52
52
|
let LinkedDocPopover = (() => {
|
|
53
53
|
let _classDecorators = [requiredProperties({
|
|
@@ -239,46 +239,54 @@ let LinkedDocPopover = (() => {
|
|
|
239
239
|
isHidden,
|
|
240
240
|
};
|
|
241
241
|
});
|
|
242
|
+
const shown = actionGroups.filter(group => (group.items.length > 0 || group.isLoading) && !group.isHidden);
|
|
243
|
+
// An empty box reads as a broken menu: since "@" only references
|
|
244
|
+
// existing pages, "no match" is an ordinary outcome and says so.
|
|
242
245
|
return html `<div class="linked-doc-popover" style="${style}">
|
|
243
|
-
${
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
${shown.length === 0
|
|
247
|
+
? html `<div class="group-title" data-testid="linked-doc-no-result">
|
|
248
|
+
<div class="group-title-text">
|
|
249
|
+
${translateKey(this.context.std, ...LINKED_DOC_NO_RESULT)}
|
|
250
|
+
</div>
|
|
251
|
+
</div>`
|
|
252
|
+
: nothing}
|
|
253
|
+
${shown.map((group, idx) => {
|
|
246
254
|
return html `
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
255
|
+
<div class="divider" ?hidden=${idx === 0}></div>
|
|
256
|
+
<div class="group-title">
|
|
257
|
+
<div class="group-title-text">${group.name}</div>
|
|
258
|
+
${group.isLoading
|
|
251
259
|
? html `<span class="loading-icon">${LoadingIcon()}</span>`
|
|
252
260
|
: nothing}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
261
|
+
</div>
|
|
262
|
+
<div class="group" style=${group.styles ?? ''}>
|
|
263
|
+
${group.items.map(({ key, name, icon, action }) => {
|
|
256
264
|
const tooltip = this._showTooltip
|
|
257
265
|
? html `<affine-tooltip
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
+
tip-position=${'right'}
|
|
267
|
+
.tooltipStyle=${css `
|
|
268
|
+
* {
|
|
269
|
+
color: ${unsafeCSSVar('white')} !important;
|
|
270
|
+
}
|
|
271
|
+
`}
|
|
272
|
+
>${name}</affine-tooltip
|
|
273
|
+
>`
|
|
266
274
|
: nothing;
|
|
267
275
|
return html `<icon-button
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
276
|
+
width="260px"
|
|
277
|
+
height="30px"
|
|
278
|
+
data-id=${key}
|
|
279
|
+
.text=${name}
|
|
280
|
+
hover=${this._activatedItemKey === key}
|
|
281
|
+
@pointerdown=${(e) => {
|
|
274
282
|
// Prevent event listeners being registered on the root document
|
|
275
283
|
// eg., radix-ui dialogs usePointerDownOutside hooks
|
|
276
284
|
e.stopPropagation();
|
|
277
285
|
}}
|
|
278
|
-
|
|
286
|
+
@click=${() => {
|
|
279
287
|
action()?.catch(console.error);
|
|
280
288
|
}}
|
|
281
|
-
|
|
289
|
+
@mousemove=${() => {
|
|
282
290
|
// Use `mousemove` instead of `mouseover` to avoid navigate conflict with keyboard
|
|
283
291
|
this._activatedItemKey = key;
|
|
284
292
|
// show tooltip whether text length overflows
|
|
@@ -290,12 +298,12 @@ let LinkedDocPopover = (() => {
|
|
|
290
298
|
}
|
|
291
299
|
}
|
|
292
300
|
}}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
301
|
+
>
|
|
302
|
+
${icon} ${tooltip}
|
|
303
|
+
</icon-button>`;
|
|
296
304
|
})}
|
|
297
|
-
|
|
298
|
-
|
|
305
|
+
</div>
|
|
306
|
+
`;
|
|
299
307
|
})}
|
|
300
308
|
</div>`;
|
|
301
309
|
}
|
|
@@ -18,6 +18,8 @@ export declare const LINKED_DOC_NEW_DOC: ChromeWording;
|
|
|
18
18
|
* word, in the same package.
|
|
19
19
|
*/
|
|
20
20
|
export declare const LINKED_DOC_IMPORT: ChromeWording;
|
|
21
|
+
/** Said when no page matches the query, instead of an empty popover. */
|
|
22
|
+
export declare const LINKED_DOC_NO_RESULT: ChromeWording;
|
|
21
23
|
/** The "Create doc" item's own wording, interpolated with the truncated name. */
|
|
22
24
|
export declare const LINKED_DOC_CREATE_DOC: ChromeWording;
|
|
23
25
|
/**
|
|
@@ -25,6 +25,11 @@ export const LINKED_DOC_IMPORT = [
|
|
|
25
25
|
'com.labre.linked-doc.import',
|
|
26
26
|
'Import',
|
|
27
27
|
];
|
|
28
|
+
/** Said when no page matches the query, instead of an empty popover. */
|
|
29
|
+
export const LINKED_DOC_NO_RESULT = [
|
|
30
|
+
'com.labre.linked-doc.no-result',
|
|
31
|
+
'No page found',
|
|
32
|
+
];
|
|
28
33
|
/** The "Create doc" item's own wording, interpolated with the truncated name. */
|
|
29
34
|
export const LINKED_DOC_CREATE_DOC = [
|
|
30
35
|
'com.labre.linked-doc.create-doc',
|
|
@@ -92,6 +97,7 @@ export const LINKED_DOC_WORDINGS = [
|
|
|
92
97
|
LINKED_DOC_LINK_TO_DOC,
|
|
93
98
|
LINKED_DOC_IMPORT,
|
|
94
99
|
LINKED_DOC_CREATE_DOC,
|
|
100
|
+
LINKED_DOC_NO_RESULT,
|
|
95
101
|
LINKED_DOC_IMPORT_SUCCESS_TOAST,
|
|
96
102
|
LINKED_DOC_OVERFLOW_MORE,
|
|
97
103
|
LINKED_DOC_IMPORT_NOTION_MARKDOWN_DEPRECATED,
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { type ThreadMarkTargetType } from '../affine-shared/services/index.js';
|
|
1
|
+
import { type ThreadMarkTargetType, type ThreadTextRange } from '../affine-shared/services/index.js';
|
|
2
2
|
import type { BlockStdScope } from '../std/index.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* A block or a canvas element, by the id the library gave it, and for a
|
|
5
|
+
* block optionally a run of its text (ADR 0038, amendment of 2026-10-15).
|
|
6
|
+
*/
|
|
4
7
|
export interface ThreadTarget {
|
|
5
8
|
targetType: ThreadMarkTargetType;
|
|
6
9
|
targetId: string;
|
|
10
|
+
range?: ThreadTextRange;
|
|
7
11
|
}
|
|
8
12
|
/**
|
|
9
13
|
* Collapse whitespace and cut to {@link THREAD_EXCERPT_MAX} code points, the
|
|
@@ -2,6 +2,7 @@ import { getSurfaceBlock } from '../affine-block-surface/index.js';
|
|
|
2
2
|
import { THREAD_EXCERPT_MAX, } from '../affine-shared/services/index.js';
|
|
3
3
|
import { selectionPaneRowLabel, selectionPaneTypeLabel, } from '../affine-widget-edgeless-toolbar/index.js';
|
|
4
4
|
import { GfxBlockElementModel } from '../std/gfx/index.js';
|
|
5
|
+
import { resolveThreadRange } from './text-range.js';
|
|
5
6
|
const ELLIPSIS = '…';
|
|
6
7
|
/**
|
|
7
8
|
* Collapse whitespace and cut to {@link THREAD_EXCERPT_MAX} code points, the
|
|
@@ -45,6 +46,13 @@ function rawExcerpt(std, target) {
|
|
|
45
46
|
const model = std.store.getModelById(target.targetId);
|
|
46
47
|
if (!model)
|
|
47
48
|
return '';
|
|
49
|
+
// A run of text reads as itself: the quote a reader selected. A range
|
|
50
|
+
// that no longer resolves falls back to the block, like its mark.
|
|
51
|
+
const yText = model.text?.yText;
|
|
52
|
+
const run = target.range && yText ? resolveThreadRange(yText, target.range) : null;
|
|
53
|
+
if (yText && run) {
|
|
54
|
+
return yText.toString().slice(run.index, run.index + run.length);
|
|
55
|
+
}
|
|
48
56
|
const text = blockText(model);
|
|
49
57
|
if (text.trim())
|
|
50
58
|
return text;
|
|
@@ -2,6 +2,7 @@ import { WidgetViewExtension } from '../std/index.js';
|
|
|
2
2
|
import { literal, unsafeStatic } from 'lit/static-html.js';
|
|
3
3
|
import { AFFINE_THREAD_MARKS_WIDGET } from './widget.js';
|
|
4
4
|
export * from './excerpt.js';
|
|
5
|
+
export * from './text-range.js';
|
|
5
6
|
export * from './toolbar.js';
|
|
6
7
|
export * from './translations.js';
|
|
7
8
|
export * from './widget.js';
|