@formicoidea/labre-core 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.d.ts +43 -0
- package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.js +109 -0
- package/dist/_pkgs/affine-block-callout/configs/toolbar.d.ts +65 -0
- package/dist/_pkgs/affine-block-callout/configs/toolbar.js +178 -0
- package/dist/_pkgs/affine-block-callout/view.js +7 -1
- package/dist/_pkgs/affine-block-frame/commands.d.ts +27 -0
- package/dist/_pkgs/affine-block-frame/commands.js +49 -0
- package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +11 -6
- package/dist/_pkgs/affine-block-frame/frame-manager.js +10 -5
- package/dist/_pkgs/affine-block-frame/frame-order.d.ts +43 -0
- package/dist/_pkgs/affine-block-frame/frame-order.js +93 -0
- package/dist/_pkgs/affine-block-frame/index.d.ts +2 -0
- package/dist/_pkgs/affine-block-frame/index.js +2 -0
- package/dist/_pkgs/affine-block-frame/present/frame-order-menu.d.ts +10 -2
- package/dist/_pkgs/affine-block-frame/present/frame-order-menu.js +32 -18
- package/dist/_pkgs/affine-block-frame/view.js +6 -0
- package/dist/_pkgs/affine-block-note/configs/toolbar.d.ts +19 -0
- package/dist/_pkgs/affine-block-note/configs/toolbar.js +38 -23
- package/dist/_pkgs/affine-block-note/translations.d.ts +2 -0
- package/dist/_pkgs/affine-block-note/translations.js +14 -1
- package/dist/_pkgs/affine-block-root/configs/toolbar.js +31 -2
- package/dist/_pkgs/affine-block-root/translations.d.ts +7 -2
- package/dist/_pkgs/affine-block-root/translations.js +10 -13
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.d.ts +20 -9
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.js +57 -20
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.d.ts +6 -8
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.js +21 -8
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.d.ts +1 -1
- package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.js +1 -1
- package/dist/_pkgs/affine-components/portal/portal.d.ts +1 -1
- package/dist/_pkgs/affine-foundation/view.d.ts +8 -8
- package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.d.ts +34 -2
- package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +194 -81
- package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.d.ts +7 -4
- package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +9 -24
- package/dist/_pkgs/affine-fragment-frame-panel/index.d.ts +1 -0
- package/dist/_pkgs/affine-fragment-frame-panel/index.js +1 -0
- package/dist/_pkgs/affine-model/utils/types.d.ts +2 -2
- package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +4 -4
- package/dist/_pkgs/affine-shared/services/font-loader/config.d.ts +2 -2
- package/dist/_pkgs/affine-shared/services/font-loader/font-loader-service.d.ts +3 -3
- package/dist/_pkgs/affine-shared/services/index.d.ts +1 -1
- package/dist/_pkgs/affine-shared/services/index.js +1 -1
- package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-storage.d.ts +4 -4
- package/dist/_pkgs/affine-shared/services/outline-panel-service.d.ts +31 -0
- package/dist/_pkgs/affine-shared/services/outline-panel-service.js +17 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +11 -0
- package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +19 -0
- package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
- package/dist/_pkgs/affine-shared/utils/index.js +1 -0
- package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.d.ts +85 -0
- package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.js +162 -0
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.d.ts +7 -6
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.js +11 -8
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.d.ts +31 -15
- package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.js +178 -142
- package/dist/_pkgs/std/scope/std-scope.d.ts +1 -1
- package/dist/commands.js +2 -0
- package/dist/host-panels.d.ts +90 -0
- package/dist/host-panels.js +111 -0
- package/package.json +5 -1
- package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.d.ts +0 -27
- package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.js +0 -96
- package/dist/_pkgs/affine-shared/services/sidebar-service.d.ts +0 -8
- package/dist/_pkgs/affine-shared/services/sidebar-service.js +0 -7
|
@@ -32,8 +32,6 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { panelDragStarted } from '../../affine-shared/styles/index.js';
|
|
36
|
-
import { on, once } from '../../affine-shared/utils/index.js';
|
|
37
35
|
import { WithDisposable } from '../../global/lit/index.js';
|
|
38
36
|
import { ShadowlessElement } from '../../std/index.js';
|
|
39
37
|
import { css, html, nothing } from 'lit';
|
|
@@ -169,32 +167,19 @@ let FrameCard = (() => {
|
|
|
169
167
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
170
168
|
}
|
|
171
169
|
static { this.styles = styles; }
|
|
170
|
+
/**
|
|
171
|
+
* Hand the press to the panel body: the threshold, the selection and the
|
|
172
|
+
* drag itself belong to the side panels' one controller, which the body
|
|
173
|
+
* holds (`createPanelReorderDrag`, ADR 0034).
|
|
174
|
+
*/
|
|
172
175
|
_dispatchDragEvent(e) {
|
|
173
176
|
e.preventDefault();
|
|
174
177
|
if (e.button !== 0)
|
|
175
178
|
return;
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
if (!panelDragStarted({ x: startX, y: startY }, { x: e.clientX, y: e.clientY })) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (this.status !== 'selected') {
|
|
182
|
-
this._dispatchSelectEvent(e);
|
|
183
|
-
}
|
|
184
|
-
const event = new CustomEvent('drag', {
|
|
185
|
-
detail: {
|
|
186
|
-
clientX: e.clientX,
|
|
187
|
-
clientY: e.clientY,
|
|
188
|
-
pageX: e.pageX,
|
|
189
|
-
pageY: e.pageY,
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
this.dispatchEvent(event);
|
|
193
|
-
disposeDragStart();
|
|
194
|
-
});
|
|
195
|
-
once(this.ownerDocument, 'mouseup', () => {
|
|
196
|
-
disposeDragStart();
|
|
179
|
+
const event = new CustomEvent('drag', {
|
|
180
|
+
detail: { event: e },
|
|
197
181
|
});
|
|
182
|
+
this.dispatchEvent(event);
|
|
198
183
|
}
|
|
199
184
|
_dispatchFitViewEvent(e) {
|
|
200
185
|
e.stopPropagation();
|
|
@@ -248,7 +233,7 @@ let FrameCard = (() => {
|
|
|
248
233
|
class="frame-card-body"
|
|
249
234
|
@click=${this._dispatchSelectEvent}
|
|
250
235
|
@dblclick=${this._dispatchFitViewEvent}
|
|
251
|
-
@
|
|
236
|
+
@pointerdown=${this._dispatchDragEvent}
|
|
252
237
|
>
|
|
253
238
|
${this.status === 'dragging' && stackOrder !== 0
|
|
254
239
|
? nothing
|
|
@@ -10,13 +10,13 @@ export declare const LinkPreviewDataSchema: z.ZodObject<{
|
|
|
10
10
|
}, "strip", z.ZodTypeAny, {
|
|
11
11
|
description: string | null;
|
|
12
12
|
title: string | null;
|
|
13
|
-
image: string | null;
|
|
14
13
|
icon: string | null;
|
|
14
|
+
image: string | null;
|
|
15
15
|
}, {
|
|
16
16
|
description: string | null;
|
|
17
17
|
title: string | null;
|
|
18
|
-
image: string | null;
|
|
19
18
|
icon: string | null;
|
|
19
|
+
image: string | null;
|
|
20
20
|
}>;
|
|
21
21
|
export type LinkPreviewData = z.infer<typeof LinkPreviewDataSchema>;
|
|
22
22
|
export type Connectable = Exclude<GfxModel, ConnectorElementModel | BrushElementModel | GroupElementModel>;
|
|
@@ -24,12 +24,12 @@ declare const LocalPropsSchema: z.ZodObject<{
|
|
|
24
24
|
centerY: z.ZodNumber;
|
|
25
25
|
zoom: z.ZodNumber;
|
|
26
26
|
}, "strip", z.ZodTypeAny, {
|
|
27
|
-
centerX: number;
|
|
28
27
|
zoom: number;
|
|
28
|
+
centerX: number;
|
|
29
29
|
centerY: number;
|
|
30
30
|
}, {
|
|
31
|
-
centerX: number;
|
|
32
31
|
zoom: number;
|
|
32
|
+
centerX: number;
|
|
33
33
|
centerY: number;
|
|
34
34
|
}>, z.ZodObject<{
|
|
35
35
|
xywh: z.ZodString;
|
|
@@ -68,8 +68,8 @@ declare const LocalPropsSchema: z.ZodObject<{
|
|
|
68
68
|
localShowGrid: z.ZodBoolean;
|
|
69
69
|
}, "strip", z.ZodTypeAny, {
|
|
70
70
|
viewport: {
|
|
71
|
-
centerX: number;
|
|
72
71
|
zoom: number;
|
|
72
|
+
centerX: number;
|
|
73
73
|
centerY: number;
|
|
74
74
|
} | {
|
|
75
75
|
xywh: string;
|
|
@@ -86,8 +86,8 @@ declare const LocalPropsSchema: z.ZodObject<{
|
|
|
86
86
|
localShowGrid: boolean;
|
|
87
87
|
}, {
|
|
88
88
|
viewport: {
|
|
89
|
-
centerX: number;
|
|
90
89
|
zoom: number;
|
|
90
|
+
centerX: number;
|
|
91
91
|
centerY: number;
|
|
92
92
|
} | {
|
|
93
93
|
xywh: string;
|
|
@@ -6,13 +6,13 @@ export declare const fontConfigSchema: z.ZodObject<{
|
|
|
6
6
|
style: z.ZodString;
|
|
7
7
|
}, "strip", z.ZodTypeAny, {
|
|
8
8
|
style: string;
|
|
9
|
-
font: string;
|
|
10
9
|
url: string;
|
|
10
|
+
font: string;
|
|
11
11
|
weight: string;
|
|
12
12
|
}, {
|
|
13
13
|
style: string;
|
|
14
|
-
font: string;
|
|
15
14
|
url: string;
|
|
15
|
+
font: string;
|
|
16
16
|
weight: string;
|
|
17
17
|
}>;
|
|
18
18
|
export type FontConfig = z.infer<typeof fontConfigSchema>;
|
|
@@ -36,18 +36,18 @@ export declare class FontLoaderService extends LifeCycleWatcher {
|
|
|
36
36
|
}
|
|
37
37
|
export declare const FontConfigIdentifier: import("../../../global/di/types.js").ServiceIdentifier<{
|
|
38
38
|
style: string;
|
|
39
|
-
font: string;
|
|
40
39
|
url: string;
|
|
40
|
+
font: string;
|
|
41
41
|
weight: string;
|
|
42
42
|
}[]> & (<U extends {
|
|
43
43
|
style: string;
|
|
44
|
-
font: string;
|
|
45
44
|
url: string;
|
|
45
|
+
font: string;
|
|
46
46
|
weight: string;
|
|
47
47
|
}[] = {
|
|
48
48
|
style: string;
|
|
49
|
-
font: string;
|
|
50
49
|
url: string;
|
|
50
|
+
font: string;
|
|
51
51
|
weight: string;
|
|
52
52
|
}[]>(variant: import("../../../global/di/types.js").ServiceVariant) => import("../../../global/di/types.js").ServiceIdentifier<U>);
|
|
53
53
|
export declare const FontConfigExtension: (fontConfig: FontConfig[]) => ExtensionType;
|
|
@@ -25,13 +25,13 @@ export * from './linked-doc-creation-service.js';
|
|
|
25
25
|
export * from './native-clipboard-service.js';
|
|
26
26
|
export * from './notification-service.js';
|
|
27
27
|
export * from './open-doc-config.js';
|
|
28
|
+
export * from './outline-panel-service.js';
|
|
28
29
|
export * from './page-viewport-service.js';
|
|
29
30
|
export * from './parse-url-service.js';
|
|
30
31
|
export * from './pivot-materiality-publisher.js';
|
|
31
32
|
export * from './pivot-properties-service.js';
|
|
32
33
|
export * from './quick-search-service.js';
|
|
33
34
|
export * from './selection-pane-service.js';
|
|
34
|
-
export * from './sidebar-service.js';
|
|
35
35
|
export * from './telemetry-service/index.js';
|
|
36
36
|
export * from './theme-service.js';
|
|
37
37
|
export * from './toolbar-service/index.js';
|
|
@@ -25,13 +25,13 @@ export * from './linked-doc-creation-service.js';
|
|
|
25
25
|
export * from './native-clipboard-service.js';
|
|
26
26
|
export * from './notification-service.js';
|
|
27
27
|
export * from './open-doc-config.js';
|
|
28
|
+
export * from './outline-panel-service.js';
|
|
28
29
|
export * from './page-viewport-service.js';
|
|
29
30
|
export * from './parse-url-service.js';
|
|
30
31
|
export * from './pivot-materiality-publisher.js';
|
|
31
32
|
export * from './pivot-properties-service.js';
|
|
32
33
|
export * from './quick-search-service.js';
|
|
33
34
|
export * from './selection-pane-service.js';
|
|
34
|
-
export * from './sidebar-service.js';
|
|
35
35
|
export * from './telemetry-service/index.js';
|
|
36
36
|
export * from './theme-service.js';
|
|
37
37
|
export * from './toolbar-service/index.js';
|
|
@@ -8,29 +8,29 @@ declare const _StorageSchema: z.ZodObject<{
|
|
|
8
8
|
}, "strip", z.ZodTypeAny, {
|
|
9
9
|
description?: string | null | undefined;
|
|
10
10
|
title?: string | null | undefined;
|
|
11
|
-
image?: string | null | undefined;
|
|
12
11
|
icon?: string | null | undefined;
|
|
12
|
+
image?: string | null | undefined;
|
|
13
13
|
}, {
|
|
14
14
|
description?: string | null | undefined;
|
|
15
15
|
title?: string | null | undefined;
|
|
16
|
-
image?: string | null | undefined;
|
|
17
16
|
icon?: string | null | undefined;
|
|
17
|
+
image?: string | null | undefined;
|
|
18
18
|
}>>;
|
|
19
19
|
expires: z.ZodOptional<z.ZodNumber>;
|
|
20
20
|
}, "strip", z.ZodTypeAny, {
|
|
21
21
|
data: Record<string, {
|
|
22
22
|
description?: string | null | undefined;
|
|
23
23
|
title?: string | null | undefined;
|
|
24
|
-
image?: string | null | undefined;
|
|
25
24
|
icon?: string | null | undefined;
|
|
25
|
+
image?: string | null | undefined;
|
|
26
26
|
}>;
|
|
27
27
|
expires?: number | undefined;
|
|
28
28
|
}, {
|
|
29
29
|
data: Record<string, {
|
|
30
30
|
description?: string | null | undefined;
|
|
31
31
|
title?: string | null | undefined;
|
|
32
|
-
image?: string | null | undefined;
|
|
33
32
|
icon?: string | null | undefined;
|
|
33
|
+
image?: string | null | undefined;
|
|
34
34
|
}>;
|
|
35
35
|
expires?: number | undefined;
|
|
36
36
|
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ExtensionType } from '../../store/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The outline panel (ADR 0034 §1): the document's table of contents, drawn by
|
|
4
|
+
* the host beside the editor.
|
|
5
|
+
*
|
|
6
|
+
* The library never mounts an outline itself, so there is no default: a host
|
|
7
|
+
* that draws one registers this seam, a host that does not leaves it out. Its
|
|
8
|
+
* only caller in the library is the "View in TOC" link of the toast the note
|
|
9
|
+
* toolbar shows after a note's display mode changes
|
|
10
|
+
* (`blocks/note/src/configs/toolbar.ts`). Absent or `null`, that toast offers
|
|
11
|
+
* no link, because a link that opens nothing is a lie.
|
|
12
|
+
*
|
|
13
|
+
* It replaces the `open(tabId?)` seam inherited from AFFiNE (removed in 0.46,
|
|
14
|
+
* ADR 0034 §2): one caller, which opened a tab named by a string nobody typed
|
|
15
|
+
* anywhere else. Shaped exactly like `SelectionPaneService`, so every panel
|
|
16
|
+
* the library asks a host to show answers the same two verbs.
|
|
17
|
+
*/
|
|
18
|
+
export interface OutlinePanelService {
|
|
19
|
+
/** Show the outline. */
|
|
20
|
+
open(): void;
|
|
21
|
+
/** Put it away. Writes nothing. */
|
|
22
|
+
close(): void;
|
|
23
|
+
}
|
|
24
|
+
export declare const OutlinePanelProvider: import("../../global/di/types.js").ServiceIdentifier<OutlinePanelService> & (<U extends OutlinePanelService = OutlinePanelService>(variant: import("../../global/di/types.js").ServiceVariant) => import("../../global/di/types.js").ServiceIdentifier<U>);
|
|
25
|
+
/**
|
|
26
|
+
* Host seam: the host's outline panel, or `null` to say there is none.
|
|
27
|
+
*
|
|
28
|
+
* `di.override`, like `SelectionPaneExtension`, so a later registration always
|
|
29
|
+
* wins and registering twice never throws at boot.
|
|
30
|
+
*/
|
|
31
|
+
export declare function OutlinePanelExtension(service: OutlinePanelService | null): ExtensionType;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createIdentifier } from '../../global/di/index.js';
|
|
2
|
+
export const OutlinePanelProvider = createIdentifier('AffineOutlinePanel');
|
|
3
|
+
/**
|
|
4
|
+
* Host seam: the host's outline panel, or `null` to say there is none.
|
|
5
|
+
*
|
|
6
|
+
* `di.override`, like `SelectionPaneExtension`, so a later registration always
|
|
7
|
+
* wins and registering twice never throws at boot.
|
|
8
|
+
*/
|
|
9
|
+
export function OutlinePanelExtension(service) {
|
|
10
|
+
return {
|
|
11
|
+
setup: di => {
|
|
12
|
+
// `null` rides through the factory on purpose: `getOptional` then
|
|
13
|
+
// reports the panel as absent, which is the whole "no link" story.
|
|
14
|
+
di.override(OutlinePanelProvider, () => service);
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -464,6 +464,17 @@ export declare const FILL_COLOR_LABEL: ChromeWording;
|
|
|
464
464
|
* `ROOT_TOOLBAR_CREATE_LINKED_DOC` (`blocks/root`).
|
|
465
465
|
*/
|
|
466
466
|
export declare const TOOLBAR_CREATE_LINKED_DOC_TITLE: ChromeWording;
|
|
467
|
+
/**
|
|
468
|
+
* "Turn into" — the block toolbar's conversions dropdown, said identically by
|
|
469
|
+
* the note's text row and the callout's own row (#468). Was
|
|
470
|
+
* `ROOT_TOOLBAR_TURN_INTO` (`blocks/root`); the key is kept.
|
|
471
|
+
*/
|
|
472
|
+
export declare const TOOLBAR_TURN_INTO: ChromeWording;
|
|
473
|
+
/**
|
|
474
|
+
* …and that dropdown's accessible name. Was `ROOT_TOOLBAR_CONVERSIONS_ARIA`
|
|
475
|
+
* (`blocks/root`); the key is kept.
|
|
476
|
+
*/
|
|
477
|
+
export declare const TOOLBAR_CONVERSIONS_ARIA: ChromeWording;
|
|
467
478
|
/**
|
|
468
479
|
* "Edgeless content" — the surface-ref placeholder's own generic reference
|
|
469
480
|
* kind, said identically by the drag-handle preview's fallback label. Was
|
|
@@ -1034,6 +1034,23 @@ export const TOOLBAR_CREATE_LINKED_DOC_TITLE = [
|
|
|
1034
1034
|
'com.labre.root.toolbar.create-linked-doc',
|
|
1035
1035
|
'Create Linked Doc',
|
|
1036
1036
|
];
|
|
1037
|
+
/**
|
|
1038
|
+
* "Turn into" — the block toolbar's conversions dropdown, said identically by
|
|
1039
|
+
* the note's text row and the callout's own row (#468). Was
|
|
1040
|
+
* `ROOT_TOOLBAR_TURN_INTO` (`blocks/root`); the key is kept.
|
|
1041
|
+
*/
|
|
1042
|
+
export const TOOLBAR_TURN_INTO = [
|
|
1043
|
+
'com.labre.root.toolbar.turn-into',
|
|
1044
|
+
'Turn into',
|
|
1045
|
+
];
|
|
1046
|
+
/**
|
|
1047
|
+
* …and that dropdown's accessible name. Was `ROOT_TOOLBAR_CONVERSIONS_ARIA`
|
|
1048
|
+
* (`blocks/root`); the key is kept.
|
|
1049
|
+
*/
|
|
1050
|
+
export const TOOLBAR_CONVERSIONS_ARIA = [
|
|
1051
|
+
'com.labre.root.toolbar.conversions',
|
|
1052
|
+
'Conversions',
|
|
1053
|
+
];
|
|
1037
1054
|
/**
|
|
1038
1055
|
* "Edgeless content" — the surface-ref placeholder's own generic reference
|
|
1039
1056
|
* kind, said identically by the drag-handle preview's fallback label. Was
|
|
@@ -1283,6 +1300,8 @@ export const CHROME_WORDINGS = [
|
|
|
1283
1300
|
COLOR_LABEL,
|
|
1284
1301
|
FILL_COLOR_LABEL,
|
|
1285
1302
|
TOOLBAR_CREATE_LINKED_DOC_TITLE,
|
|
1303
|
+
TOOLBAR_TURN_INTO,
|
|
1304
|
+
TOOLBAR_CONVERSIONS_ARIA,
|
|
1286
1305
|
EDGELESS_CONTENT_LABEL,
|
|
1287
1306
|
TOOLBAR_EDIT,
|
|
1288
1307
|
TOOLBAR_REMOVE_LINK,
|
|
@@ -18,6 +18,7 @@ export * from './label-mode.js';
|
|
|
18
18
|
export * from './link-preview-refresh.js';
|
|
19
19
|
export * from './math.js';
|
|
20
20
|
export * from './model/index.js';
|
|
21
|
+
export * from './panel-reorder-drag.js';
|
|
21
22
|
export * from './popper-position.js';
|
|
22
23
|
export * from './print-to-pdf.js';
|
|
23
24
|
export * from './reference.js';
|
|
@@ -18,6 +18,7 @@ export * from './label-mode.js';
|
|
|
18
18
|
export * from './link-preview-refresh.js';
|
|
19
19
|
export * from './math.js';
|
|
20
20
|
export * from './model/index.js';
|
|
21
|
+
export * from './panel-reorder-drag.js';
|
|
21
22
|
export * from './popper-position.js';
|
|
22
23
|
export * from './print-to-pdf.js';
|
|
23
24
|
export * from './reference.js';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE drag-to-reorder gesture of the side panels (ADR 0034):
|
|
3
|
+
* the frame panel's cards and the selection pane's rows.
|
|
4
|
+
*
|
|
5
|
+
* Why it exists: the two panels each wrote their own drag and the two
|
|
6
|
+
* drifted. The frame panel's (`fragments/frame-panel/src/utils/drag.ts`, now
|
|
7
|
+
* deleted) ran on mouse events, never refused a read-only document, drew the
|
|
8
|
+
* drop line at 0 for a drop after the last card, and had no way out but the
|
|
9
|
+
* release. The selection pane's (hand-written in `selection-pane-widget.ts`)
|
|
10
|
+
* ran on pointer events, refused read-only and showed a `not-allowed` cursor,
|
|
11
|
+
* and swallowed Escape. Only the threshold was shared, and a comment held the
|
|
12
|
+
* rest together. Both panels now hand this controller what is theirs — the
|
|
13
|
+
* rows, the drop rule, the ghost, the write — and it owns the gesture:
|
|
14
|
+
*
|
|
15
|
+
* - pointer events, listened to on the document in the CAPTURE phase from the
|
|
16
|
+
* press to the end, so a panel that stops its own events' propagation (the
|
|
17
|
+
* pane does, to keep the canvas out of them) still sees every move;
|
|
18
|
+
* - a read-only document never starts one: the press adds no listener;
|
|
19
|
+
* - a press becomes a drag past {@link panelDragStarted} — called here and
|
|
20
|
+
* nowhere else — and only then is anything picked up;
|
|
21
|
+
* - over the whole viewport, a mask carries the cursor: `grabbing` over a gap
|
|
22
|
+
* that takes the drop, `not-allowed` elsewhere (its geometry stays in each
|
|
23
|
+
* panel's stylesheet, the controller sets the cursor and nothing else);
|
|
24
|
+
* - Escape or `pointercancel` CANCELS: nothing is written, the release that
|
|
25
|
+
* follows writes nothing, and the Escape does not reach the panel (which
|
|
26
|
+
* would close it);
|
|
27
|
+
* - the click that follows a release or a cancel is not a click: the panel
|
|
28
|
+
* asks {@link PanelReorderDrag.consumeSwallowedClick} in its click handler.
|
|
29
|
+
*
|
|
30
|
+
* Multi-selection is the panel's business: `onPickUp` decides what moves,
|
|
31
|
+
* `dropAt` skips the rows that move with it.
|
|
32
|
+
*/
|
|
33
|
+
/** A pointer position, in client coordinates. */
|
|
34
|
+
export interface PanelDragPoint {
|
|
35
|
+
clientX: number;
|
|
36
|
+
clientY: number;
|
|
37
|
+
}
|
|
38
|
+
export interface PanelReorderDragOptions<Drop> {
|
|
39
|
+
/** Read at the press: a read-only document never starts a drag. */
|
|
40
|
+
readonly: () => boolean;
|
|
41
|
+
/** The rows, top first, read LIVE at every move. */
|
|
42
|
+
rows: () => readonly HTMLElement[];
|
|
43
|
+
/** The box a drop must land in; outside it, or `null`, refuses. */
|
|
44
|
+
bounds: () => HTMLElement | null;
|
|
45
|
+
/** The press became a drag: select what moves, build the ghost. */
|
|
46
|
+
onPickUp: (press: PanelDragPoint) => void;
|
|
47
|
+
/**
|
|
48
|
+
* What a release at the gap `gap` — before `rows()[gap]`, `rows().length`
|
|
49
|
+
* after the last — would do, or `null` to refuse it.
|
|
50
|
+
*/
|
|
51
|
+
dropAt: (gap: number, point: PanelDragPoint) => Drop | null;
|
|
52
|
+
/** Every move of a drag: draw the ghost at `ghost`, the line for `drop`. */
|
|
53
|
+
onMove: (drop: Drop | null, ghost: PanelDragPoint) => void;
|
|
54
|
+
/** The release, over a gap that takes it. Before `onEnd`. */
|
|
55
|
+
onDrop: (drop: Drop) => void;
|
|
56
|
+
/** A drag ended — dropped, refused, cancelled or disposed. Always last. */
|
|
57
|
+
onEnd: () => void;
|
|
58
|
+
/** The cursor mask: appended to `host()` on pick-up, removed at the end. */
|
|
59
|
+
mask: {
|
|
60
|
+
host: () => ParentNode | null;
|
|
61
|
+
className: string;
|
|
62
|
+
testId?: string;
|
|
63
|
+
};
|
|
64
|
+
/** Carries `data-drag="valid" | "invalid"` while a drag is live. */
|
|
65
|
+
stateHost?: () => HTMLElement | null;
|
|
66
|
+
}
|
|
67
|
+
export interface PanelReorderDrag {
|
|
68
|
+
/** Hand it the row's `pointerdown`. */
|
|
69
|
+
press(event: PointerEvent): void;
|
|
70
|
+
/**
|
|
71
|
+
* Whether the click being handled follows a drag's release or cancel —
|
|
72
|
+
* answered `true` once, then `false`.
|
|
73
|
+
*/
|
|
74
|
+
consumeSwallowedClick(): boolean;
|
|
75
|
+
/** Whether a press has become a drag that has not ended yet. */
|
|
76
|
+
readonly dragging: boolean;
|
|
77
|
+
/** Ends a live drag (`onEnd`, nothing written) and removes the listeners. */
|
|
78
|
+
dispose(): void;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The gap a pointer at `clientY` is over: how many rows have their middle
|
|
82
|
+
* above it. `0` is before the first row, `rects.length` after the last.
|
|
83
|
+
*/
|
|
84
|
+
export declare function panelReorderGap(rects: readonly DOMRect[], clientY: number): number;
|
|
85
|
+
export declare function createPanelReorderDrag<Drop>(options: PanelReorderDragOptions<Drop>): PanelReorderDrag;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { panelDragStarted } from '../styles/panel-header.js';
|
|
2
|
+
/**
|
|
3
|
+
* The gap a pointer at `clientY` is over: how many rows have their middle
|
|
4
|
+
* above it. `0` is before the first row, `rects.length` after the last.
|
|
5
|
+
*/
|
|
6
|
+
export function panelReorderGap(rects, clientY) {
|
|
7
|
+
let gap = 0;
|
|
8
|
+
for (const rect of rects) {
|
|
9
|
+
if (clientY > rect.top + rect.height / 2)
|
|
10
|
+
gap++;
|
|
11
|
+
}
|
|
12
|
+
return gap;
|
|
13
|
+
}
|
|
14
|
+
export function createPanelReorderDrag(options) {
|
|
15
|
+
let start = null;
|
|
16
|
+
let dragging = false;
|
|
17
|
+
let listening = null;
|
|
18
|
+
let mask = null;
|
|
19
|
+
let swallowClick = false;
|
|
20
|
+
const point = (event) => ({
|
|
21
|
+
clientX: event.clientX,
|
|
22
|
+
clientY: event.clientY,
|
|
23
|
+
});
|
|
24
|
+
const resolve = (at) => {
|
|
25
|
+
const bounds = options.bounds();
|
|
26
|
+
if (!bounds)
|
|
27
|
+
return null;
|
|
28
|
+
const box = bounds.getBoundingClientRect();
|
|
29
|
+
if (at.clientX < box.left ||
|
|
30
|
+
at.clientX > box.right ||
|
|
31
|
+
at.clientY < box.top ||
|
|
32
|
+
at.clientY > box.bottom) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const rects = options.rows().map(row => row.getBoundingClientRect());
|
|
36
|
+
return options.dropAt(panelReorderGap(rects, at.clientY), at);
|
|
37
|
+
};
|
|
38
|
+
const show = (drop) => {
|
|
39
|
+
if (mask)
|
|
40
|
+
mask.style.cursor = drop ? 'grabbing' : 'not-allowed';
|
|
41
|
+
const host = options.stateHost?.();
|
|
42
|
+
if (host)
|
|
43
|
+
host.dataset.drag = drop ? 'valid' : 'invalid';
|
|
44
|
+
};
|
|
45
|
+
const unlisten = () => {
|
|
46
|
+
if (!listening)
|
|
47
|
+
return;
|
|
48
|
+
listening.removeEventListener('pointermove', onPointerMove, true);
|
|
49
|
+
listening.removeEventListener('pointerup', onPointerUp, true);
|
|
50
|
+
listening.removeEventListener('pointercancel', onPointerCancel, true);
|
|
51
|
+
listening.removeEventListener('keydown', onKeydown, true);
|
|
52
|
+
listening = null;
|
|
53
|
+
};
|
|
54
|
+
/** Back to idle; `onEnd` only when something was picked up. */
|
|
55
|
+
const finish = () => {
|
|
56
|
+
unlisten();
|
|
57
|
+
start = null;
|
|
58
|
+
if (!dragging)
|
|
59
|
+
return;
|
|
60
|
+
dragging = false;
|
|
61
|
+
mask?.remove();
|
|
62
|
+
mask = null;
|
|
63
|
+
const host = options.stateHost?.();
|
|
64
|
+
if (host)
|
|
65
|
+
delete host.dataset.drag;
|
|
66
|
+
options.onEnd();
|
|
67
|
+
};
|
|
68
|
+
const cancel = () => {
|
|
69
|
+
if (dragging)
|
|
70
|
+
swallowClick = true;
|
|
71
|
+
finish();
|
|
72
|
+
};
|
|
73
|
+
const pickUp = (event) => {
|
|
74
|
+
dragging = true;
|
|
75
|
+
const host = options.mask.host();
|
|
76
|
+
if (host) {
|
|
77
|
+
const doc = event.target?.ownerDocument ?? document;
|
|
78
|
+
mask = doc.createElement('div');
|
|
79
|
+
mask.className = options.mask.className;
|
|
80
|
+
if (options.mask.testId)
|
|
81
|
+
mask.dataset.testid = options.mask.testId;
|
|
82
|
+
mask.style.cursor = 'grabbing';
|
|
83
|
+
host.append(mask);
|
|
84
|
+
}
|
|
85
|
+
options.onPickUp({ clientX: start.x, clientY: start.y });
|
|
86
|
+
};
|
|
87
|
+
function onPointerMove(event) {
|
|
88
|
+
if (!start)
|
|
89
|
+
return;
|
|
90
|
+
if (!dragging) {
|
|
91
|
+
if (!panelDragStarted(start, { x: event.clientX, y: event.clientY })) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
pickUp(event);
|
|
95
|
+
}
|
|
96
|
+
const at = point(event);
|
|
97
|
+
const drop = resolve(at);
|
|
98
|
+
show(drop);
|
|
99
|
+
options.onMove(drop, at);
|
|
100
|
+
}
|
|
101
|
+
function onPointerUp(event) {
|
|
102
|
+
if (!dragging) {
|
|
103
|
+
// A press that never became a drag: the click that follows is a click.
|
|
104
|
+
finish();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const drop = resolve(point(event));
|
|
108
|
+
swallowClick = true;
|
|
109
|
+
try {
|
|
110
|
+
if (drop !== null)
|
|
111
|
+
options.onDrop(drop);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
finish();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function onPointerCancel() {
|
|
118
|
+
cancel();
|
|
119
|
+
}
|
|
120
|
+
function onKeydown(event) {
|
|
121
|
+
if (event.key !== 'Escape')
|
|
122
|
+
return;
|
|
123
|
+
if (!dragging) {
|
|
124
|
+
// A press still under the threshold: forget it, and let the Escape do
|
|
125
|
+
// what it does in the panel.
|
|
126
|
+
finish();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
event.stopPropagation();
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
cancel();
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
press(event) {
|
|
135
|
+
// Any new press clears a click left armed by a release or a cancel
|
|
136
|
+
// that no click followed (released over another element).
|
|
137
|
+
swallowClick = false;
|
|
138
|
+
if (event.button !== 0 || start)
|
|
139
|
+
return;
|
|
140
|
+
if (options.readonly())
|
|
141
|
+
return;
|
|
142
|
+
start = { x: event.clientX, y: event.clientY };
|
|
143
|
+
const doc = event.target?.ownerDocument ?? document;
|
|
144
|
+
doc.addEventListener('pointermove', onPointerMove, true);
|
|
145
|
+
doc.addEventListener('pointerup', onPointerUp, true);
|
|
146
|
+
doc.addEventListener('pointercancel', onPointerCancel, true);
|
|
147
|
+
doc.addEventListener('keydown', onKeydown, true);
|
|
148
|
+
listening = doc;
|
|
149
|
+
},
|
|
150
|
+
consumeSwallowedClick() {
|
|
151
|
+
const swallowed = swallowClick;
|
|
152
|
+
swallowClick = false;
|
|
153
|
+
return swallowed;
|
|
154
|
+
},
|
|
155
|
+
get dragging() {
|
|
156
|
+
return dragging;
|
|
157
|
+
},
|
|
158
|
+
dispose() {
|
|
159
|
+
finish();
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -44,18 +44,19 @@ export interface PaneSlot {
|
|
|
44
44
|
*/
|
|
45
45
|
export declare function paneSlotAtGap(rows: readonly PaneDropRow[], gap: number, parent: string, { lists, parentOf }: PaneLists): PaneSlot | null;
|
|
46
46
|
/**
|
|
47
|
-
* What a drop at `index` of `list` writes for the dragged
|
|
48
|
-
*
|
|
49
|
-
* when the slot is refused.
|
|
47
|
+
* What a drop at `index` of `list` writes for the dragged rows `dragged` (one
|
|
48
|
+
* id, or the set a multi-row drag moves): the model they land directly ABOVE
|
|
49
|
+
* (`null` = the bottom of their stack), or `null` when the slot is refused.
|
|
50
50
|
*
|
|
51
|
-
* `stackOf(id)` names the model that stands for a row in the dragged
|
|
51
|
+
* `stackOf(id)` names the model that stands for a row in the dragged rows'
|
|
52
52
|
* own stack — itself, or the frame it belongs to when the dragged row is a
|
|
53
53
|
* loose element and that row is a frame's member (a frame's members paint
|
|
54
54
|
* together, right above it) — or `undefined` for a row that is not in that
|
|
55
55
|
* stack at all. A slot is refused when neither neighbour is in the stack, or
|
|
56
56
|
* when both stand for the same model: the inside of a frame's block of rows,
|
|
57
|
-
* where a loose element cannot be put.
|
|
57
|
+
* where a loose element cannot be put. A row that stands for a dragged model
|
|
58
|
+
* (a dragged frame's member) moves with it, so it is no neighbour either.
|
|
58
59
|
*/
|
|
59
|
-
export declare function paneDropAbove(list: readonly SelectionPaneNode[], index: number,
|
|
60
|
+
export declare function paneDropAbove(list: readonly SelectionPaneNode[], index: number, dragged: string | ReadonlySet<string>, stackOf: (id: string) => string | undefined): {
|
|
60
61
|
above: string | null;
|
|
61
62
|
} | null;
|
|
@@ -59,21 +59,24 @@ export function paneSlotAtGap(rows, gap, parent, { lists, parentOf }) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
* What a drop at `index` of `list` writes for the dragged
|
|
63
|
-
*
|
|
64
|
-
* when the slot is refused.
|
|
62
|
+
* What a drop at `index` of `list` writes for the dragged rows `dragged` (one
|
|
63
|
+
* id, or the set a multi-row drag moves): the model they land directly ABOVE
|
|
64
|
+
* (`null` = the bottom of their stack), or `null` when the slot is refused.
|
|
65
65
|
*
|
|
66
|
-
* `stackOf(id)` names the model that stands for a row in the dragged
|
|
66
|
+
* `stackOf(id)` names the model that stands for a row in the dragged rows'
|
|
67
67
|
* own stack — itself, or the frame it belongs to when the dragged row is a
|
|
68
68
|
* loose element and that row is a frame's member (a frame's members paint
|
|
69
69
|
* together, right above it) — or `undefined` for a row that is not in that
|
|
70
70
|
* stack at all. A slot is refused when neither neighbour is in the stack, or
|
|
71
71
|
* when both stand for the same model: the inside of a frame's block of rows,
|
|
72
|
-
* where a loose element cannot be put.
|
|
72
|
+
* where a loose element cannot be put. A row that stands for a dragged model
|
|
73
|
+
* (a dragged frame's member) moves with it, so it is no neighbour either.
|
|
73
74
|
*/
|
|
74
|
-
export function paneDropAbove(list, index,
|
|
75
|
-
const
|
|
76
|
-
const
|
|
75
|
+
export function paneDropAbove(list, index, dragged, stackOf) {
|
|
76
|
+
const moving = typeof dragged === 'string' ? new Set([dragged]) : dragged;
|
|
77
|
+
const stays = (node) => !moving.has(node.id) && !moving.has(stackOf(node.id) ?? '');
|
|
78
|
+
const before = list.slice(0, index).filter(stays);
|
|
79
|
+
const after = list.slice(index).filter(stays);
|
|
77
80
|
const upper = before.length
|
|
78
81
|
? stackOf(before[before.length - 1].id)
|
|
79
82
|
: undefined;
|