@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
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { generateKeyBetweenV2, GfxControllerIdentifier } from '../std/gfx/index.js';
|
|
2
|
+
import { EdgelessFrameManagerIdentifier } from './frame-manager.js';
|
|
3
|
+
/**
|
|
4
|
+
* The one write of the frames' PRESENTATION order (ADR 0034): the
|
|
5
|
+
* order a presentation walks the frames in, held by each frame's
|
|
6
|
+
* `presentationIndex` — a fractional key, never a position.
|
|
7
|
+
*
|
|
8
|
+
* Why one function: two sites wrote that order by hand — the frame panel's
|
|
9
|
+
* drag and the presentation toolbar's order menu — each its own way, neither
|
|
10
|
+
* refusing a read-only document, and the panel taking its undo checkpoint
|
|
11
|
+
* AFTER the write, so the reorder merged into whatever gesture came before.
|
|
12
|
+
* Both now reach this through `canvas.frame.reorder`, and so does a host's own
|
|
13
|
+
* slide panel: the guards below live here, once.
|
|
14
|
+
*
|
|
15
|
+
* Mirrors the selection pane's `reorderPaneElement`
|
|
16
|
+
* (`blocks/surface/src/extensions/selection-pane/actions.ts`):
|
|
17
|
+
*
|
|
18
|
+
* - refuses on a read-only document before reading anything else;
|
|
19
|
+
* - writes nothing when nothing would change — an unchanged write is an empty
|
|
20
|
+
* undo step, and an undo that "does nothing" reads as a broken undo;
|
|
21
|
+
* - takes ONE `captureSync()` first, so one gesture is one undo step, the
|
|
22
|
+
* legacy keys `refreshLegacyFrameOrder` may write included (it writes in
|
|
23
|
+
* the same capture window, so it joins the gesture's step);
|
|
24
|
+
* - writes through `gfx.updateElement`, which is `store.updateBlock` for a
|
|
25
|
+
* frame — not the CRUD `updateElement`, which would also record the moved
|
|
26
|
+
* frame's props as the flavour's last-used props.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Move the frames `ids` so they sit, as one block, directly BEFORE `before` in
|
|
30
|
+
* the presentation order — `null` puts them at the end. The moved frames keep
|
|
31
|
+
* their current relative order, whatever order `ids` lists them in. Answers
|
|
32
|
+
* whether anything was written.
|
|
33
|
+
*
|
|
34
|
+
* Refused, with nothing written: a read-only document; an id that is not a
|
|
35
|
+
* frame of this document; a `before` that is one of the moved frames, or not
|
|
36
|
+
* a frame; and a target that is where the frames already are.
|
|
37
|
+
*
|
|
38
|
+
* Each moved frame gets a key between its new neighbours, so only the moved
|
|
39
|
+
* frames are written and nothing else shifts. Two neighbours with equal (or
|
|
40
|
+
* inverted) keys cannot be split — `generateKeyBetweenV2` throws on them, and
|
|
41
|
+
* the model's default key is random per frame, so a pasted, imported or
|
|
42
|
+
* hand-made document can carry them: refusing beats throwing in a drop.
|
|
43
|
+
*/
|
|
44
|
+
export function reorderFramePresentation(std, ids, before) {
|
|
45
|
+
if (std.store.readonly)
|
|
46
|
+
return false;
|
|
47
|
+
const manager = std.get(EdgelessFrameManagerIdentifier);
|
|
48
|
+
const frames = manager.frames;
|
|
49
|
+
const moving = new Set(ids);
|
|
50
|
+
if (moving.size === 0)
|
|
51
|
+
return false;
|
|
52
|
+
if (before !== null && moving.has(before))
|
|
53
|
+
return false;
|
|
54
|
+
const known = new Set(frames.map(frame => frame.id));
|
|
55
|
+
for (const id of moving)
|
|
56
|
+
if (!known.has(id))
|
|
57
|
+
return false;
|
|
58
|
+
if (before !== null && !known.has(before))
|
|
59
|
+
return false;
|
|
60
|
+
// `frames` is already in presentation order, so filtering keeps the moved
|
|
61
|
+
// frames' relative order.
|
|
62
|
+
const moved = frames.filter(frame => moving.has(frame.id));
|
|
63
|
+
const rest = frames.filter(frame => !moving.has(frame.id));
|
|
64
|
+
const position = before === null
|
|
65
|
+
? rest.length
|
|
66
|
+
: rest.findIndex(frame => frame.id === before);
|
|
67
|
+
const target = [
|
|
68
|
+
...rest.slice(0, position),
|
|
69
|
+
...moved,
|
|
70
|
+
...rest.slice(position),
|
|
71
|
+
];
|
|
72
|
+
if (target.every((frame, i) => frame === frames[i]))
|
|
73
|
+
return false;
|
|
74
|
+
std.store.captureSync();
|
|
75
|
+
// Gives a key to legacy frames that have none, keeping their order, so the
|
|
76
|
+
// neighbours' keys below mean what the list shows. A no-op on any document
|
|
77
|
+
// where a frame already carries one.
|
|
78
|
+
manager.refreshLegacyFrameOrder();
|
|
79
|
+
const lower = rest[position - 1]?.props.presentationIndex || null;
|
|
80
|
+
const upper = rest[position]?.props.presentationIndex || null;
|
|
81
|
+
if (lower !== null && upper !== null && lower >= upper)
|
|
82
|
+
return false;
|
|
83
|
+
const gfx = std.get(GfxControllerIdentifier);
|
|
84
|
+
std.store.transact(() => {
|
|
85
|
+
let previous = lower;
|
|
86
|
+
for (const frame of moved) {
|
|
87
|
+
const presentationIndex = generateKeyBetweenV2(previous, upper);
|
|
88
|
+
gfx.updateElement(frame, { presentationIndex });
|
|
89
|
+
previous = presentationIndex;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
export * from './commands.js';
|
|
1
2
|
export * from './edgeless-clipboard-config.js';
|
|
2
3
|
export * from './edgeless-toolbar/index.js';
|
|
3
4
|
export * from './frame-block.js';
|
|
4
5
|
export * from './frame-highlight-manager.js';
|
|
5
6
|
export * from './frame-manager.js';
|
|
7
|
+
export * from './frame-order.js';
|
|
6
8
|
export * from './frame-spec.js';
|
|
7
9
|
export * from './frame-tool.js';
|
|
8
10
|
export * from './frame-toolbar.js';
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
export * from './commands.js';
|
|
1
2
|
export * from './edgeless-clipboard-config.js';
|
|
2
3
|
export * from './edgeless-toolbar/index.js';
|
|
3
4
|
export * from './frame-block.js';
|
|
4
5
|
export * from './frame-highlight-manager.js';
|
|
5
6
|
export * from './frame-manager.js';
|
|
7
|
+
export * from './frame-order.js';
|
|
6
8
|
export * from './frame-spec.js';
|
|
7
9
|
export * from './frame-tool.js';
|
|
8
10
|
export * from './frame-toolbar.js';
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BlockComponent } from '../../std/index.js';
|
|
2
2
|
import { LitElement } from 'lit';
|
|
3
3
|
declare const EdgelessFrameOrderMenu_base: typeof LitElement & import("../../global/utils/types.js").Constructor<import("../../global/lit/with-disposable.js").DisposableClass>;
|
|
4
|
+
/**
|
|
5
|
+
* The presentation toolbar's order menu. Its WRITE is `canvas.frame.reorder`
|
|
6
|
+
* (ADR 0034); its drag gesture is its own.
|
|
7
|
+
*
|
|
8
|
+
* ponytail: a drag-to-reorder gesture of its own, beside the frame panel's and
|
|
9
|
+
* the selection pane's — its ceiling is a 256px popover, which the panels' one
|
|
10
|
+
* controller (`createPanelReorderDrag`, ADR 0034) is not built for. If the
|
|
11
|
+
* menu ever becomes a panel, move it onto that controller and delete this one.
|
|
12
|
+
*/
|
|
4
13
|
export declare class EdgelessFrameOrderMenu extends EdgelessFrameOrderMenu_base {
|
|
5
14
|
static styles: import("lit").CSSResult;
|
|
6
|
-
get crud(): import("../../affine-block-surface/index.js").EdgelessCRUDExtension;
|
|
7
15
|
private get _frameMgr();
|
|
8
16
|
private get _frames();
|
|
9
17
|
private _bindEvent;
|
|
@@ -32,14 +32,37 @@ var __runInitializers = (this && this.__runInitializers) || function (thisArg, i
|
|
|
32
32
|
}
|
|
33
33
|
return useValue ? value : void 0;
|
|
34
34
|
};
|
|
35
|
-
import { EdgelessCRUDIdentifier } from '../../affine-block-surface/index.js';
|
|
36
35
|
import { DisposableGroup } from '../../global/disposable/index.js';
|
|
37
36
|
import { SignalWatcher, WithDisposable } from '../../global/lit/index.js';
|
|
38
|
-
import {
|
|
37
|
+
import { runCommand, } from '../../std/index.js';
|
|
39
38
|
import { css, html, LitElement, nothing } from 'lit';
|
|
40
39
|
import { property, query, state } from 'lit/decorators.js';
|
|
41
40
|
import { repeat } from 'lit/directives/repeat.js';
|
|
41
|
+
import { frameCommands } from '../commands.js';
|
|
42
42
|
import { EdgelessFrameManagerIdentifier } from '../frame-manager.js';
|
|
43
|
+
/**
|
|
44
|
+
* How the menu invokes the registry: from the editor's chrome, on the frames
|
|
45
|
+
* it names, like the selection pane's rows.
|
|
46
|
+
*/
|
|
47
|
+
const MENU_INVOCATION = {
|
|
48
|
+
surface: 'contextual-toolbar',
|
|
49
|
+
source: 'toolbar:general',
|
|
50
|
+
};
|
|
51
|
+
function reorderCommand() {
|
|
52
|
+
const command = frameCommands.find(c => c.id === 'canvas.frame.reorder');
|
|
53
|
+
if (!command)
|
|
54
|
+
throw new Error('frame order menu: no canvas.frame.reorder');
|
|
55
|
+
return command;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The presentation toolbar's order menu. Its WRITE is `canvas.frame.reorder`
|
|
59
|
+
* (ADR 0034); its drag gesture is its own.
|
|
60
|
+
*
|
|
61
|
+
* ponytail: a drag-to-reorder gesture of its own, beside the frame panel's and
|
|
62
|
+
* the selection pane's — its ceiling is a 256px popover, which the panels' one
|
|
63
|
+
* controller (`createPanelReorderDrag`, ADR 0034) is not built for. If the
|
|
64
|
+
* menu ever becomes a panel, move it onto that controller and delete this one.
|
|
65
|
+
*/
|
|
43
66
|
let EdgelessFrameOrderMenu = (() => {
|
|
44
67
|
let _classSuper = SignalWatcher(WithDisposable(LitElement));
|
|
45
68
|
let __clone_decorators;
|
|
@@ -161,9 +184,6 @@ let EdgelessFrameOrderMenu = (() => {
|
|
|
161
184
|
width: 90%;
|
|
162
185
|
}
|
|
163
186
|
`; }
|
|
164
|
-
get crud() {
|
|
165
|
-
return this.edgeless.std.get(EdgelessCRUDIdentifier);
|
|
166
|
-
}
|
|
167
187
|
get _frameMgr() {
|
|
168
188
|
return this.edgeless.std.get(EdgelessFrameManagerIdentifier);
|
|
169
189
|
}
|
|
@@ -225,20 +245,14 @@ let EdgelessFrameOrderMenu = (() => {
|
|
|
225
245
|
this._disposables.addFromEvent(document, 'pointerup', () => {
|
|
226
246
|
clone.style.visibility = 'hidden';
|
|
227
247
|
indicatorLine.style.visibility = 'hidden';
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const before = this._frames[newIndex - 1]?.props.presentationIndex || null;
|
|
236
|
-
const after = this._frames[newIndex]?.props.presentationIndex || null;
|
|
237
|
-
const frame = this._frames[index];
|
|
238
|
-
this.crud.updateElement(frame.id, {
|
|
239
|
-
presentationIndex: generateKeyBetweenV2(before, after),
|
|
248
|
+
const frames = this._frames;
|
|
249
|
+
// A drop on its own slot (before itself) or on the next one is refused
|
|
250
|
+
// by the command: nothing is written, no undo step is pushed.
|
|
251
|
+
if (newIndex >= 0 && newIndex <= frames.length && frames[index]) {
|
|
252
|
+
runCommand(this.edgeless.std, reorderCommand(), MENU_INVOCATION, {
|
|
253
|
+
ids: [frames[index].id],
|
|
254
|
+
before: frames[newIndex]?.id ?? null,
|
|
240
255
|
});
|
|
241
|
-
this.edgeless.store.captureSync();
|
|
242
256
|
this.requestUpdate();
|
|
243
257
|
}
|
|
244
258
|
this._disposables.dispose();
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ViewExtensionProvider, } from '../affine-ext-loader/index.js';
|
|
2
|
+
import { CommandExtension } from '../std/index.js';
|
|
3
|
+
import { frameCommands } from './commands.js';
|
|
2
4
|
import { EdgelessClipboardFrameConfig } from './edgeless-clipboard-config.js';
|
|
3
5
|
import { frameQuickTool } from './edgeless-toolbar/index.js';
|
|
4
6
|
import { effects } from './effects.js';
|
|
@@ -30,6 +32,10 @@ export class FrameViewExtension extends ViewExtensionProvider {
|
|
|
30
32
|
context.register(edgelessNavigatorBgWidget);
|
|
31
33
|
context.register(EdgelessClipboardFrameConfig);
|
|
32
34
|
context.register(FrameBlockInteraction);
|
|
35
|
+
// The presentation order's one write (ADR 0034). The frame panel also
|
|
36
|
+
// mounts in page mode: it runs the imported descriptor, not this
|
|
37
|
+
// registration, so its reorder works in both modes.
|
|
38
|
+
context.register(CommandExtension(frameCommands));
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
}
|
|
@@ -1,2 +1,21 @@
|
|
|
1
|
+
import { NoteDisplayMode } from '../../affine-model/index.js';
|
|
2
|
+
import { type BlockStdScope } from '../../std/index.js';
|
|
1
3
|
import type { ExtensionType } from '../../store/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* The toast shown after a note's display mode changes. Its "View in TOC" link
|
|
6
|
+
* is offered only when the host registered an outline panel
|
|
7
|
+
* (`OutlinePanelExtension`, ADR 0034 §1): a link that opens nothing is a lie,
|
|
8
|
+
* so a host with no outline, or one that passed `null`, gets a toast with no
|
|
9
|
+
* link, and a body without the "Find it in the TOC" sentence that points at
|
|
10
|
+
* it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function displayModeToast(std: BlockStdScope, newMode: NoteDisplayMode): {
|
|
13
|
+
title: string;
|
|
14
|
+
message: string;
|
|
15
|
+
actions: {
|
|
16
|
+
key: string;
|
|
17
|
+
label: string;
|
|
18
|
+
onClick: () => void;
|
|
19
|
+
}[];
|
|
20
|
+
};
|
|
2
21
|
export declare const createBuiltinToolbarConfigExtension: (flavour: string) => ExtensionType[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EdgelessLegacySlotIdentifier } from '../../affine-block-surface/index.js';
|
|
2
2
|
import { NoteBlockModel, NoteDisplayMode } from '../../affine-model/index.js';
|
|
3
|
-
import { NotificationProvider,
|
|
3
|
+
import { NotificationProvider, OutlinePanelProvider, TOAST_NOTE_REMOVED_FROM_PAGE, ToolbarModuleExtension, translateKey, } from '../../affine-shared/services/index.js';
|
|
4
4
|
import { Bound } from '../../global/gfx/index.js';
|
|
5
5
|
import { AutoHeightIcon, CustomizedHeightIcon, InsertIntoPageIcon, ScissorsIcon, } from '@blocksuite/icons/lit';
|
|
6
6
|
import { BlockFlavourIdentifier } from '../../std/index.js';
|
|
@@ -8,7 +8,7 @@ import { computed } from '@preact/signals-core';
|
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { changeNoteDisplayMode } from '../commands/index.js';
|
|
10
10
|
import { NoteConfigExtension } from '../config.js';
|
|
11
|
-
import { NOTE_TOAST_ADDED_TO_PAGE_BODY, NOTE_TOAST_DISPLAYED_IN_PAGE_MODE, NOTE_TOAST_REMOVED_FROM_PAGE_BODY, NOTE_TOAST_VIEW_IN_TOC, NOTE_TOOLBAR_AUTO_HEIGHT, NOTE_TOOLBAR_CUSTOMIZED_HEIGHT, NOTE_TOOLBAR_CUTTING_MODE, NOTE_TOOLBAR_DISPLAY_IN_PAGE, NOTE_TOOLBAR_DISPLAYED_IN_PAGE, NOTE_TOOLBAR_REMOVE_FROM_PAGE_TOOLTIP, NOTE_TOOLBAR_SIZE, NOTE_TOOLBAR_SLICER, } from '../translations.js';
|
|
11
|
+
import { NOTE_TOAST_ADDED_TO_PAGE_BODY, NOTE_TOAST_ADDED_TO_PAGE_BODY_NO_TOC, NOTE_TOAST_DISPLAYED_IN_PAGE_MODE, NOTE_TOAST_REMOVED_FROM_PAGE_BODY, NOTE_TOAST_REMOVED_FROM_PAGE_BODY_NO_TOC, NOTE_TOAST_VIEW_IN_TOC, NOTE_TOOLBAR_AUTO_HEIGHT, NOTE_TOOLBAR_CUSTOMIZED_HEIGHT, NOTE_TOOLBAR_CUTTING_MODE, NOTE_TOOLBAR_DISPLAY_IN_PAGE, NOTE_TOOLBAR_DISPLAYED_IN_PAGE, NOTE_TOOLBAR_REMOVE_FROM_PAGE_TOOLTIP, NOTE_TOOLBAR_SIZE, NOTE_TOOLBAR_SLICER, } from '../translations.js';
|
|
12
12
|
const trackBaseProps = {
|
|
13
13
|
category: 'note',
|
|
14
14
|
};
|
|
@@ -238,6 +238,41 @@ const builtinSurfaceToolbarConfig = {
|
|
|
238
238
|
],
|
|
239
239
|
when: ctx => ctx.getSurfaceModelsByType(NoteBlockModel).length > 0,
|
|
240
240
|
};
|
|
241
|
+
/**
|
|
242
|
+
* The toast shown after a note's display mode changes. Its "View in TOC" link
|
|
243
|
+
* is offered only when the host registered an outline panel
|
|
244
|
+
* (`OutlinePanelExtension`, ADR 0034 §1): a link that opens nothing is a lie,
|
|
245
|
+
* so a host with no outline, or one that passed `null`, gets a toast with no
|
|
246
|
+
* link, and a body without the "Find it in the TOC" sentence that points at
|
|
247
|
+
* it.
|
|
248
|
+
*/
|
|
249
|
+
export function displayModeToast(std, newMode) {
|
|
250
|
+
const outline = std.getOptional(OutlinePanelProvider);
|
|
251
|
+
const removed = newMode === NoteDisplayMode.EdgelessOnly;
|
|
252
|
+
const title = removed
|
|
253
|
+
? TOAST_NOTE_REMOVED_FROM_PAGE
|
|
254
|
+
: NOTE_TOAST_DISPLAYED_IN_PAGE_MODE;
|
|
255
|
+
const body = removed
|
|
256
|
+
? outline
|
|
257
|
+
? NOTE_TOAST_REMOVED_FROM_PAGE_BODY
|
|
258
|
+
: NOTE_TOAST_REMOVED_FROM_PAGE_BODY_NO_TOC
|
|
259
|
+
: outline
|
|
260
|
+
? NOTE_TOAST_ADDED_TO_PAGE_BODY
|
|
261
|
+
: NOTE_TOAST_ADDED_TO_PAGE_BODY_NO_TOC;
|
|
262
|
+
return {
|
|
263
|
+
title: translateKey(std, ...title),
|
|
264
|
+
message: translateKey(std, ...body),
|
|
265
|
+
actions: outline
|
|
266
|
+
? [
|
|
267
|
+
{
|
|
268
|
+
key: 'view-in-toc',
|
|
269
|
+
label: translateKey(std, ...NOTE_TOAST_VIEW_IN_TOC),
|
|
270
|
+
onClick: () => outline.open(),
|
|
271
|
+
},
|
|
272
|
+
]
|
|
273
|
+
: [],
|
|
274
|
+
};
|
|
275
|
+
}
|
|
241
276
|
function setDisplayMode(ctx, model, newMode) {
|
|
242
277
|
const displayMode = model.props.displayMode;
|
|
243
278
|
ctx.command.exec(changeNoteDisplayMode, {
|
|
@@ -249,31 +284,11 @@ function setDisplayMode(ctx, model, newMode) {
|
|
|
249
284
|
if (newMode === NoteDisplayMode.DocOnly) {
|
|
250
285
|
ctx.selection.clear();
|
|
251
286
|
}
|
|
252
|
-
const data = newMode === NoteDisplayMode.EdgelessOnly
|
|
253
|
-
? {
|
|
254
|
-
title: translateKey(ctx.std, ...TOAST_NOTE_REMOVED_FROM_PAGE),
|
|
255
|
-
message: translateKey(ctx.std, ...NOTE_TOAST_REMOVED_FROM_PAGE_BODY),
|
|
256
|
-
}
|
|
257
|
-
: {
|
|
258
|
-
title: translateKey(ctx.std, ...NOTE_TOAST_DISPLAYED_IN_PAGE_MODE),
|
|
259
|
-
message: translateKey(ctx.std, ...NOTE_TOAST_ADDED_TO_PAGE_BODY),
|
|
260
|
-
};
|
|
261
287
|
const notification = ctx.std.getOptional(NotificationProvider);
|
|
262
288
|
notification?.notifyWithUndoAction({
|
|
263
|
-
|
|
264
|
-
message: data.message,
|
|
289
|
+
...displayModeToast(ctx.std, newMode),
|
|
265
290
|
accent: 'success',
|
|
266
291
|
duration: 5 * 1000,
|
|
267
|
-
actions: [
|
|
268
|
-
{
|
|
269
|
-
key: 'view-in-toc',
|
|
270
|
-
label: translateKey(ctx.std, ...NOTE_TOAST_VIEW_IN_TOC),
|
|
271
|
-
onClick: () => {
|
|
272
|
-
const sidebar = ctx.std.getOptional(SidebarExtensionIdentifier);
|
|
273
|
-
sidebar?.open('outline');
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
],
|
|
277
292
|
});
|
|
278
293
|
ctx.track('NoteDisplayModeChanged', {
|
|
279
294
|
...trackBaseProps,
|
|
@@ -66,6 +66,8 @@ export declare const NOTE_DISPLAY_MODE_PAGE: ChromeWording;
|
|
|
66
66
|
export declare const NOTE_TOAST_DISPLAYED_IN_PAGE_MODE: ChromeWording;
|
|
67
67
|
export declare const NOTE_TOAST_REMOVED_FROM_PAGE_BODY: ChromeWording;
|
|
68
68
|
export declare const NOTE_TOAST_ADDED_TO_PAGE_BODY: ChromeWording;
|
|
69
|
+
export declare const NOTE_TOAST_REMOVED_FROM_PAGE_BODY_NO_TOC: ChromeWording;
|
|
70
|
+
export declare const NOTE_TOAST_ADDED_TO_PAGE_BODY_NO_TOC: ChromeWording;
|
|
69
71
|
export declare const NOTE_TOAST_VIEW_IN_TOC: ChromeWording;
|
|
70
72
|
export declare const NOTE_TOOLBAR_DISPLAY_IN_PAGE: ChromeWording;
|
|
71
73
|
export declare const NOTE_TOOLBAR_DISPLAYED_IN_PAGE: ChromeWording;
|
|
@@ -154,7 +154,10 @@ export const NOTE_DISPLAY_MODE_PAGE = DISPLAY_MODE_PAGE;
|
|
|
154
154
|
* `TOAST_NOTE_REMOVED_FROM_PAGE` (already in `chrome.ts`); its opposite gets
|
|
155
155
|
* its own key here. Each toast's BODY bakes in the trailing "Find it in the
|
|
156
156
|
* TOC…" sentence rather than composing it at the call site — one full
|
|
157
|
-
* sentence per key, never a fragment plus a suffix.
|
|
157
|
+
* sentence per key, never a fragment plus a suffix. That sentence promises the
|
|
158
|
+
* "View in TOC" link, which exists only when the host registers an outline
|
|
159
|
+
* panel (`OutlinePanelExtension`, ADR 0034); each body therefore has a
|
|
160
|
+
* `body-no-toc` twin without it, picked when no outline answers.
|
|
158
161
|
*/
|
|
159
162
|
export const NOTE_TOAST_DISPLAYED_IN_PAGE_MODE = [
|
|
160
163
|
'com.labre.note.toast.displayed-in-page-mode',
|
|
@@ -168,6 +171,14 @@ export const NOTE_TOAST_ADDED_TO_PAGE_BODY = [
|
|
|
168
171
|
'com.labre.note.toast.added-to-page.body',
|
|
169
172
|
'Content added to your document. Find it in the TOC for quick navigation.',
|
|
170
173
|
];
|
|
174
|
+
export const NOTE_TOAST_REMOVED_FROM_PAGE_BODY_NO_TOC = [
|
|
175
|
+
'com.labre.note.toast.removed-from-page.body-no-toc',
|
|
176
|
+
'Content removed from your document.',
|
|
177
|
+
];
|
|
178
|
+
export const NOTE_TOAST_ADDED_TO_PAGE_BODY_NO_TOC = [
|
|
179
|
+
'com.labre.note.toast.added-to-page.body-no-toc',
|
|
180
|
+
'Content added to your document.',
|
|
181
|
+
];
|
|
171
182
|
export const NOTE_TOAST_VIEW_IN_TOC = [
|
|
172
183
|
'com.labre.note.toast.view-in-toc',
|
|
173
184
|
'View in Toc',
|
|
@@ -236,6 +247,8 @@ export const NOTE_WORDINGS = [
|
|
|
236
247
|
NOTE_TOAST_DISPLAYED_IN_PAGE_MODE,
|
|
237
248
|
NOTE_TOAST_REMOVED_FROM_PAGE_BODY,
|
|
238
249
|
NOTE_TOAST_ADDED_TO_PAGE_BODY,
|
|
250
|
+
NOTE_TOAST_REMOVED_FROM_PAGE_BODY_NO_TOC,
|
|
251
|
+
NOTE_TOAST_ADDED_TO_PAGE_BODY_NO_TOC,
|
|
239
252
|
NOTE_TOAST_VIEW_IN_TOC,
|
|
240
253
|
NOTE_TOOLBAR_DISPLAY_IN_PAGE,
|
|
241
254
|
NOTE_TOOLBAR_DISPLAYED_IN_PAGE,
|
|
@@ -271,12 +271,41 @@ export const builtinToolbarConfig = {
|
|
|
271
271
|
blockId: block.model.id,
|
|
272
272
|
})));
|
|
273
273
|
}
|
|
274
|
-
|
|
274
|
+
// The copy lands right after the last selected block that no other
|
|
275
|
+
// selected block contains. Said explicitly: the command's default
|
|
276
|
+
// anchors on the LAST selected model, which in `flat` mode below
|
|
277
|
+
// is a descendant — and `highest` keeps a block-selected child of
|
|
278
|
+
// a block-selected parent too, so with both selected the copy went
|
|
279
|
+
// INSIDE the parent, after the child.
|
|
280
|
+
const [, { selectedModels: highest = [] }] = chain
|
|
275
281
|
.pipe(getSelectedModelsCommand, {
|
|
276
282
|
types: ['block', 'image'],
|
|
277
283
|
mode: 'highest',
|
|
278
284
|
})
|
|
279
|
-
.
|
|
285
|
+
.run();
|
|
286
|
+
const selected = new Set(highest);
|
|
287
|
+
const hasSelectedAncestor = (model) => {
|
|
288
|
+
for (let at = store.getParent(model); at; at = store.getParent(at))
|
|
289
|
+
if (selected.has(at))
|
|
290
|
+
return true;
|
|
291
|
+
return false;
|
|
292
|
+
};
|
|
293
|
+
const last = highest.findLast(model => !hasSelectedAncestor(model));
|
|
294
|
+
const parentModel = last && store.getParent(last);
|
|
295
|
+
if (!last || !parentModel)
|
|
296
|
+
return;
|
|
297
|
+
// `flat`, not `highest`: `draftSelectedModelsCommand` keeps a
|
|
298
|
+
// drafted block's children only when they are selected too, so a
|
|
299
|
+
// paragraph duplicated alone lost its nested children.
|
|
300
|
+
chain
|
|
301
|
+
.pipe(getSelectedModelsCommand, {
|
|
302
|
+
types: ['block', 'image'],
|
|
303
|
+
mode: 'flat',
|
|
304
|
+
})
|
|
305
|
+
.pipe(duplicateSelectedModelsCommand, {
|
|
306
|
+
parentModel,
|
|
307
|
+
index: parentModel.children.indexOf(last) + 1,
|
|
308
|
+
})
|
|
280
309
|
.run();
|
|
281
310
|
},
|
|
282
311
|
},
|
|
@@ -4,6 +4,10 @@ import { type ChromeWording } from '../affine-shared/services/index.js';
|
|
|
4
4
|
* `PACKAGE_SEED_WORDINGS` in `@labre/affine/translations` — see that file and
|
|
5
5
|
* `packages/affine/shared/src/services/translation-service/README.md`.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Aliases (L7 dedupe): the callout's own row says the same two words (#468),
|
|
9
|
+
* so they live in `chrome.ts` under the keys they always had.
|
|
10
|
+
*/
|
|
7
11
|
export declare const ROOT_TOOLBAR_CONVERSIONS_ARIA: ChromeWording;
|
|
8
12
|
export declare const ROOT_TOOLBAR_TURN_INTO: ChromeWording;
|
|
9
13
|
export declare const ROOT_TOOLBAR_CREATE_TABLE: ChromeWording;
|
|
@@ -51,8 +55,9 @@ export declare const ROOT_TOAST_ZOOM_TO_SELECTION: ChromeWording;
|
|
|
51
55
|
export declare const ROOT_MINDMAP_SEED_NEW_NODE: ChromeWording;
|
|
52
56
|
/**
|
|
53
57
|
* This package's own CHROME wordings — L7 dedupe aliased
|
|
54
|
-
* `
|
|
55
|
-
*
|
|
58
|
+
* `ROOT_TOOLBAR_CONVERSIONS_ARIA`, `ROOT_TOOLBAR_CREATE_LINKED_DOC`,
|
|
59
|
+
* `ROOT_TOOLBAR_FRAME`, `ROOT_TOOLBAR_RELOAD`, `ROOT_TOOLBAR_REMOVE_LINK` and
|
|
60
|
+
* `ROOT_TOOLBAR_TURN_INTO` to `chrome.ts` wordings — not listed again
|
|
56
61
|
* here, same rule the note/slash-menu packages' own chrome aliases already
|
|
57
62
|
* follow.
|
|
58
63
|
*/
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { TOOL_NAME_FRAME, TOOLBAR_CREATE_LINKED_DOC_TITLE, TOOLBAR_RELOAD, TOOLBAR_REMOVE_LINK, } from '../affine-shared/services/index.js';
|
|
1
|
+
import { TOOL_NAME_FRAME, TOOLBAR_CONVERSIONS_ARIA, TOOLBAR_CREATE_LINKED_DOC_TITLE, TOOLBAR_RELOAD, TOOLBAR_REMOVE_LINK, TOOLBAR_TURN_INTO, } from '../affine-shared/services/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* This package's own wordings, joined into `PACKAGE_WORDINGS` /
|
|
4
4
|
* `PACKAGE_SEED_WORDINGS` in `@labre/affine/translations` — see that file and
|
|
5
5
|
* `packages/affine/shared/src/services/translation-service/README.md`.
|
|
6
6
|
*/
|
|
7
7
|
/* ── The block contextual toolbar (`configs/toolbar.ts`) ──────────────── */
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export const
|
|
13
|
-
|
|
14
|
-
'Turn into',
|
|
15
|
-
];
|
|
8
|
+
/**
|
|
9
|
+
* Aliases (L7 dedupe): the callout's own row says the same two words (#468),
|
|
10
|
+
* so they live in `chrome.ts` under the keys they always had.
|
|
11
|
+
*/
|
|
12
|
+
export const ROOT_TOOLBAR_CONVERSIONS_ARIA = TOOLBAR_CONVERSIONS_ARIA;
|
|
13
|
+
export const ROOT_TOOLBAR_TURN_INTO = TOOLBAR_TURN_INTO;
|
|
16
14
|
export const ROOT_TOOLBAR_CREATE_TABLE = [
|
|
17
15
|
'com.labre.root.toolbar.create-table',
|
|
18
16
|
'Create Table',
|
|
@@ -134,14 +132,13 @@ export const ROOT_MINDMAP_SEED_NEW_NODE = [
|
|
|
134
132
|
];
|
|
135
133
|
/**
|
|
136
134
|
* This package's own CHROME wordings — L7 dedupe aliased
|
|
137
|
-
* `
|
|
138
|
-
*
|
|
135
|
+
* `ROOT_TOOLBAR_CONVERSIONS_ARIA`, `ROOT_TOOLBAR_CREATE_LINKED_DOC`,
|
|
136
|
+
* `ROOT_TOOLBAR_FRAME`, `ROOT_TOOLBAR_RELOAD`, `ROOT_TOOLBAR_REMOVE_LINK` and
|
|
137
|
+
* `ROOT_TOOLBAR_TURN_INTO` to `chrome.ts` wordings — not listed again
|
|
139
138
|
* here, same rule the note/slash-menu packages' own chrome aliases already
|
|
140
139
|
* follow.
|
|
141
140
|
*/
|
|
142
141
|
export const ROOT_CHROME_WORDINGS = [
|
|
143
|
-
ROOT_TOOLBAR_CONVERSIONS_ARIA,
|
|
144
|
-
ROOT_TOOLBAR_TURN_INTO,
|
|
145
142
|
ROOT_TOOLBAR_CREATE_TABLE,
|
|
146
143
|
ROOT_ALIGNMENT_MENU_ARIA,
|
|
147
144
|
ROOT_ALIGN_LEFT,
|
|
@@ -4,17 +4,28 @@ import type { SelectionPaneNode } from './tree.js';
|
|
|
4
4
|
* Move `id` so it sits directly ABOVE `above` in the stack — `null` puts it at
|
|
5
5
|
* the bottom of its stack. Answers whether anything was written.
|
|
6
6
|
*
|
|
7
|
-
* The
|
|
8
|
-
* X means "directly above X". The new `index` is a key between the two
|
|
9
|
-
* neighbours (the same `fractional-indexing` keys `LayerManager` generates), so
|
|
10
|
-
* one field of one model is written and nothing else moves.
|
|
11
|
-
*
|
|
12
|
-
* Refused, with nothing written: a read-only document; a mindmap node (it has
|
|
13
|
-
* no index of its own — the whole mindmap moves as one, as the toolbar's
|
|
14
|
-
* reorder already says); an `above` that is not stacked with `id`; and a
|
|
15
|
-
* target that is where the model already is.
|
|
7
|
+
* The one-row case of {@link reorderPaneElements}, kept for its callers.
|
|
16
8
|
*/
|
|
17
9
|
export declare function reorderPaneElement(std: BlockStdScope, id: string, above: string | null): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Move the models `ids`, as one block, so they sit directly ABOVE `above` in
|
|
12
|
+
* their stack — `null` puts them at the bottom of it. They keep their current
|
|
13
|
+
* relative z-order, whatever order `ids` lists them in. Answers whether
|
|
14
|
+
* anything was written.
|
|
15
|
+
*
|
|
16
|
+
* The drop target of a drag in a top-first list: dropping rows just over row
|
|
17
|
+
* X means "directly above X". Each moved model gets a new `index` between its
|
|
18
|
+
* new neighbours (the same `fractional-indexing` keys `LayerManager`
|
|
19
|
+
* generates), so only the moved models are written and nothing else shifts.
|
|
20
|
+
*
|
|
21
|
+
* Refused, with nothing written: a read-only document; an unknown id; a
|
|
22
|
+
* mindmap node (it has no index of its own — the whole mindmap moves as one,
|
|
23
|
+
* as the toolbar's reorder already says); models that are not all stacked
|
|
24
|
+
* together (a selection spanning two stacks has no one place to land, ADR
|
|
25
|
+
* 0034); an `above` that is one of them or not stacked with them; and a
|
|
26
|
+
* target that is where the models already are.
|
|
27
|
+
*/
|
|
28
|
+
export declare function reorderPaneElements(std: BlockStdScope, ids: readonly string[], above: string | null): boolean;
|
|
18
29
|
/**
|
|
19
30
|
* Lock or unlock each model ON ITS OWN. Answers whether anything was written.
|
|
20
31
|
*
|
|
@@ -48,26 +48,53 @@ function stackSiblings(std, model) {
|
|
|
48
48
|
* Move `id` so it sits directly ABOVE `above` in the stack — `null` puts it at
|
|
49
49
|
* the bottom of its stack. Answers whether anything was written.
|
|
50
50
|
*
|
|
51
|
-
* The
|
|
52
|
-
* X means "directly above X". The new `index` is a key between the two
|
|
53
|
-
* neighbours (the same `fractional-indexing` keys `LayerManager` generates), so
|
|
54
|
-
* one field of one model is written and nothing else moves.
|
|
55
|
-
*
|
|
56
|
-
* Refused, with nothing written: a read-only document; a mindmap node (it has
|
|
57
|
-
* no index of its own — the whole mindmap moves as one, as the toolbar's
|
|
58
|
-
* reorder already says); an `above` that is not stacked with `id`; and a
|
|
59
|
-
* target that is where the model already is.
|
|
51
|
+
* The one-row case of {@link reorderPaneElements}, kept for its callers.
|
|
60
52
|
*/
|
|
61
53
|
export function reorderPaneElement(std, id, above) {
|
|
54
|
+
return reorderPaneElements(std, [id], above);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Move the models `ids`, as one block, so they sit directly ABOVE `above` in
|
|
58
|
+
* their stack — `null` puts them at the bottom of it. They keep their current
|
|
59
|
+
* relative z-order, whatever order `ids` lists them in. Answers whether
|
|
60
|
+
* anything was written.
|
|
61
|
+
*
|
|
62
|
+
* The drop target of a drag in a top-first list: dropping rows just over row
|
|
63
|
+
* X means "directly above X". Each moved model gets a new `index` between its
|
|
64
|
+
* new neighbours (the same `fractional-indexing` keys `LayerManager`
|
|
65
|
+
* generates), so only the moved models are written and nothing else shifts.
|
|
66
|
+
*
|
|
67
|
+
* Refused, with nothing written: a read-only document; an unknown id; a
|
|
68
|
+
* mindmap node (it has no index of its own — the whole mindmap moves as one,
|
|
69
|
+
* as the toolbar's reorder already says); models that are not all stacked
|
|
70
|
+
* together (a selection spanning two stacks has no one place to land, ADR
|
|
71
|
+
* 0034); an `above` that is one of them or not stacked with them; and a
|
|
72
|
+
* target that is where the models already are.
|
|
73
|
+
*/
|
|
74
|
+
export function reorderPaneElements(std, ids, above) {
|
|
62
75
|
if (std.store.readonly)
|
|
63
76
|
return false;
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
77
|
+
const moving = new Set(ids);
|
|
78
|
+
if (moving.size === 0)
|
|
66
79
|
return false;
|
|
67
|
-
if (
|
|
80
|
+
if (above !== null && moving.has(above))
|
|
68
81
|
return false;
|
|
69
|
-
const
|
|
70
|
-
|
|
82
|
+
const models = [];
|
|
83
|
+
for (const id of moving) {
|
|
84
|
+
const model = gfxModel(std, id);
|
|
85
|
+
if (!model)
|
|
86
|
+
return false;
|
|
87
|
+
if (model.group instanceof MindmapElementModel)
|
|
88
|
+
return false;
|
|
89
|
+
models.push(model);
|
|
90
|
+
}
|
|
91
|
+
const siblings = stackSiblings(std, models[0]);
|
|
92
|
+
if (models.some(model => !siblings.includes(model)))
|
|
93
|
+
return false;
|
|
94
|
+
// `siblings` is in stacking order, bottom first, so filtering keeps the
|
|
95
|
+
// moved models' relative order.
|
|
96
|
+
const moved = siblings.filter(model => moving.has(model.id));
|
|
97
|
+
const others = siblings.filter(model => !moving.has(model.id));
|
|
71
98
|
let position = 0;
|
|
72
99
|
if (above !== null) {
|
|
73
100
|
const target = others.findIndex(other => other.id === above);
|
|
@@ -75,10 +102,13 @@ export function reorderPaneElement(std, id, above) {
|
|
|
75
102
|
return false;
|
|
76
103
|
position = target + 1;
|
|
77
104
|
}
|
|
78
|
-
// Already there: the
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
105
|
+
// Already there: the stack would read the same after the move.
|
|
106
|
+
const after = [
|
|
107
|
+
...others.slice(0, position),
|
|
108
|
+
...moved,
|
|
109
|
+
...others.slice(position),
|
|
110
|
+
];
|
|
111
|
+
if (after.every((model, i) => model === siblings[i]))
|
|
82
112
|
return false;
|
|
83
113
|
const lower = others[position - 1]?.index ?? null;
|
|
84
114
|
const upper = others[position]?.index ?? null;
|
|
@@ -86,9 +116,16 @@ export function reorderPaneElement(std, id, above) {
|
|
|
86
116
|
// this only guards a hand-made document; refusing beats throwing in a drop.
|
|
87
117
|
if (lower !== null && upper !== null && lower >= upper)
|
|
88
118
|
return false;
|
|
89
|
-
const
|
|
119
|
+
const gfx = std.get(GfxControllerIdentifier);
|
|
90
120
|
std.store.captureSync();
|
|
91
|
-
std.
|
|
121
|
+
std.store.transact(() => {
|
|
122
|
+
let previous = lower;
|
|
123
|
+
for (const model of moved) {
|
|
124
|
+
const index = generateKeyBetween(previous, upper);
|
|
125
|
+
gfx.updateElement(model, { index });
|
|
126
|
+
previous = index;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
92
129
|
return true;
|
|
93
130
|
}
|
|
94
131
|
/**
|