@formicoidea/labre-core 0.45.0 → 0.46.1

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.
Files changed (73) hide show
  1. package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.d.ts +43 -0
  2. package/dist/_pkgs/affine-block-callout/commands/turn-callout-into.js +109 -0
  3. package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.d.ts +1 -1
  4. package/dist/_pkgs/affine-block-callout/commands/turn-into-callout.js +1 -1
  5. package/dist/_pkgs/affine-block-callout/configs/slash-menu.js +4 -2
  6. package/dist/_pkgs/affine-block-callout/configs/toolbar.d.ts +65 -0
  7. package/dist/_pkgs/affine-block-callout/configs/toolbar.js +178 -0
  8. package/dist/_pkgs/affine-block-callout/view.d.ts +30 -1
  9. package/dist/_pkgs/affine-block-callout/view.js +45 -3
  10. package/dist/_pkgs/affine-block-code/code-toolbar/components/lang-button.js +1 -1
  11. package/dist/_pkgs/affine-block-frame/commands.d.ts +27 -0
  12. package/dist/_pkgs/affine-block-frame/commands.js +49 -0
  13. package/dist/_pkgs/affine-block-frame/frame-manager.d.ts +11 -6
  14. package/dist/_pkgs/affine-block-frame/frame-manager.js +10 -5
  15. package/dist/_pkgs/affine-block-frame/frame-order.d.ts +43 -0
  16. package/dist/_pkgs/affine-block-frame/frame-order.js +93 -0
  17. package/dist/_pkgs/affine-block-frame/index.d.ts +2 -0
  18. package/dist/_pkgs/affine-block-frame/index.js +2 -0
  19. package/dist/_pkgs/affine-block-frame/present/frame-order-menu.d.ts +10 -2
  20. package/dist/_pkgs/affine-block-frame/present/frame-order-menu.js +32 -18
  21. package/dist/_pkgs/affine-block-frame/view.js +6 -0
  22. package/dist/_pkgs/affine-block-note/configs/toolbar.d.ts +19 -0
  23. package/dist/_pkgs/affine-block-note/configs/toolbar.js +38 -23
  24. package/dist/_pkgs/affine-block-note/translations.d.ts +2 -0
  25. package/dist/_pkgs/affine-block-note/translations.js +14 -1
  26. package/dist/_pkgs/affine-block-root/configs/toolbar.js +31 -2
  27. package/dist/_pkgs/affine-block-root/translations.d.ts +7 -2
  28. package/dist/_pkgs/affine-block-root/translations.js +10 -13
  29. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.d.ts +20 -9
  30. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/actions.js +57 -20
  31. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.d.ts +6 -8
  32. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/commands.js +21 -8
  33. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.d.ts +1 -1
  34. package/dist/_pkgs/affine-block-surface/extensions/selection-pane/index.js +1 -1
  35. package/dist/_pkgs/affine-components/portal/portal.d.ts +1 -1
  36. package/dist/_pkgs/affine-foundation/view.d.ts +8 -8
  37. package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.d.ts +34 -2
  38. package/dist/_pkgs/affine-fragment-frame-panel/body/frame-panel-body.js +194 -81
  39. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.d.ts +7 -4
  40. package/dist/_pkgs/affine-fragment-frame-panel/card/frame-card.js +9 -24
  41. package/dist/_pkgs/affine-fragment-frame-panel/index.d.ts +1 -0
  42. package/dist/_pkgs/affine-fragment-frame-panel/index.js +1 -0
  43. package/dist/_pkgs/affine-model/utils/types.d.ts +2 -2
  44. package/dist/_pkgs/affine-shared/services/edit-props-store.d.ts +4 -4
  45. package/dist/_pkgs/affine-shared/services/font-loader/config.d.ts +2 -2
  46. package/dist/_pkgs/affine-shared/services/font-loader/font-loader-service.d.ts +3 -3
  47. package/dist/_pkgs/affine-shared/services/index.d.ts +1 -1
  48. package/dist/_pkgs/affine-shared/services/index.js +1 -1
  49. package/dist/_pkgs/affine-shared/services/link-preview-service/link-preview-storage.d.ts +4 -4
  50. package/dist/_pkgs/affine-shared/services/outline-panel-service.d.ts +31 -0
  51. package/dist/_pkgs/affine-shared/services/outline-panel-service.js +17 -0
  52. package/dist/_pkgs/affine-shared/services/translation-service/chrome.d.ts +11 -0
  53. package/dist/_pkgs/affine-shared/services/translation-service/chrome.js +19 -0
  54. package/dist/_pkgs/affine-shared/utils/index.d.ts +1 -0
  55. package/dist/_pkgs/affine-shared/utils/index.js +1 -0
  56. package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.d.ts +85 -0
  57. package/dist/_pkgs/affine-shared/utils/panel-reorder-drag.js +162 -0
  58. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.d.ts +7 -6
  59. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/drop.js +11 -8
  60. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.d.ts +31 -15
  61. package/dist/_pkgs/affine-widget-edgeless-toolbar/selection-pane/selection-pane-widget.js +178 -142
  62. package/dist/_pkgs/std/scope/std-scope.d.ts +1 -1
  63. package/dist/commands.js +2 -0
  64. package/dist/extensions/view.js +5 -1
  65. package/dist/flags.d.ts +3 -0
  66. package/dist/flags.js +3 -0
  67. package/dist/host-panels.d.ts +90 -0
  68. package/dist/host-panels.js +111 -0
  69. package/package.json +5 -1
  70. package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.d.ts +0 -27
  71. package/dist/_pkgs/affine-fragment-frame-panel/utils/drag.js +0 -96
  72. package/dist/_pkgs/affine-shared/services/sidebar-service.d.ts +0 -8
  73. package/dist/_pkgs/affine-shared/services/sidebar-service.js +0 -7
@@ -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 row `dragId`: the
48
- * model it lands directly ABOVE (`null` = the bottom of its stack), or `null`
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 row's
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, dragId: string, stackOf: (id: string) => string | undefined): {
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 row `dragId`: the
63
- * model it lands directly ABOVE (`null` = the bottom of its stack), or `null`
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 row's
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, dragId, stackOf) {
75
- const before = list.slice(0, index).filter(node => node.id !== dragId);
76
- const after = list.slice(index).filter(node => node.id !== dragId);
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;
@@ -24,8 +24,9 @@ export declare const EDGELESS_SELECTION_PANE_WIDGET = "edgeless-selection-pane-w
24
24
  * (shift / ctrl / cmd adds or removes it, like on the canvas), the padlock
25
25
  * locks that row alone, a double-click renames a group or a frame (a frame is
26
26
  * a row at its place in the stack, ADR 0031 amendments), and a drag moves a row
27
- * among its siblings. Every write goes through `runCommand`, so the read-only
28
- * refusal and the undo step live in one place.
27
+ * — or, pressed on a selected row, the whole selection of one stack — among
28
+ * its siblings (the side panels' one drag, ADR 0034). Every write goes through
29
+ * `runCommand`, so the read-only refusal and the undo step live in one place.
29
30
  */
30
31
  export declare class EdgelessSelectionPaneWidget extends WidgetComponent<RootBlockModel> {
31
32
  static styles: import("lit").CSSResult;
@@ -36,19 +37,22 @@ export declare class EdgelessSelectionPaneWidget extends WidgetComponent<RootBlo
36
37
  private accessor _filter;
37
38
  /** The group row being renamed, or `null`. */
38
39
  private accessor _renaming;
39
- /** Where the dragged row would land. */
40
+ /** Where the dragged rows would land; `null` while refused. */
40
41
  private accessor _drop;
41
42
  /** Where the dragged row's ghost is drawn, in the panel's own box. */
42
43
  private accessor _ghost;
43
44
  /** Bumped when the canvas selection changes, so the rows repaint. */
44
45
  private accessor _selectionRevision;
45
- private _drag;
46
+ /** The drag under way, from its pick-up to its end. */
47
+ private accessor _drag;
48
+ /** The last row pressed: what a pick-up picks up. */
49
+ private _pressed;
50
+ /** The side panels' one reorder gesture, wired in `_wire()`. */
51
+ private _reorder;
46
52
  /** The rows of the last render, top first: what a drag hit-tests. */
47
53
  private _visibleRows;
48
54
  /** The sibling lists before the filter: what a drop is computed in. */
49
55
  private _lists;
50
- /** A drag ends with a click on the row it started on; that click is not one. */
51
- private _swallowNextClick;
52
56
  get paneOpen(): boolean;
53
57
  private get _gfx();
54
58
  private _setOpen;
@@ -109,7 +113,21 @@ export declare class EdgelessSelectionPaneWidget extends WidgetComponent<RootBlo
109
113
  private _onRowContextMenu;
110
114
  private _commitRename;
111
115
  private readonly _onRenameKeydown;
116
+ private _createReorderDrag;
117
+ private _panel;
118
+ private _paneBody;
119
+ /** The rows on screen, top first, with the rows they draw. */
120
+ private _shownRows;
112
121
  private _onRowPointerDown;
122
+ /**
123
+ * The press became a drag. A canvas row picked up is selected, as the frame
124
+ * panel selects a card — unless it already is, and then the whole selection
125
+ * moves with it, as in the frame panel: every selected row the pane lists.
126
+ * Rows that are not all in the pressed row's stack and list have no one
127
+ * place to land, so every drop of theirs is refused, honestly, with a
128
+ * `not-allowed` cursor rather than a line that would write nothing.
129
+ */
130
+ private _pickUp;
113
131
  /**
114
132
  * Which model stands for a row in the dragged row's own stack — the stack
115
133
  * `canvas.element.reorder` restacks it in, the models sharing its raw
@@ -119,20 +137,18 @@ export declare class EdgelessSelectionPaneWidget extends WidgetComponent<RootBlo
119
137
  * mindmap node moves with its mindmap).
120
138
  */
121
139
  private _stackOf;
122
- /** Where a release at `(clientX, clientY)` would land the dragged row. */
140
+ /**
141
+ * Where a release over the gap `gap` (the controller's count of rows whose
142
+ * middle is above the pointer, at `clientY`) would land the dragged rows,
143
+ * or `null` to refuse it.
144
+ */
123
145
  private _dropAt;
124
- private _moveGhost;
125
- private readonly _onDocumentPointerMove;
126
- /** A canvas row picked up is selected, as the frame panel selects a card. */
127
- private _pickUp;
128
- private readonly _onDocumentPointerUp;
129
146
  /**
130
147
  * One write per gesture, through the command: `layer` for a drop into a
131
- * layer, one `index` for a slot. The command writes nothing when the slot
132
- * is where the row already is, and a refused drop never reaches it.
148
+ * layer, one restack for a slot. The command writes nothing when the slot
149
+ * is where the rows already are, and a refused drop never reaches it.
133
150
  */
134
151
  private _commitDrop;
135
- private _endDrag;
136
152
  private _renderGhost;
137
153
  private _renderDropIndicator;
138
154
  private _filterName;