@formicoidea/labre-core 0.38.2 → 0.39.3
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-database/properties/rich-text/cell-renderer.js +14 -9
- package/dist/_pkgs/affine-block-frame/frame-manager.js +10 -9
- package/dist/_pkgs/affine-block-list/list-block.d.ts +8 -1
- package/dist/_pkgs/affine-block-list/list-block.js +27 -17
- package/dist/_pkgs/affine-block-paragraph/paragraph-block.d.ts +8 -1
- package/dist/_pkgs/affine-block-paragraph/paragraph-block.js +30 -15
- package/dist/_pkgs/affine-block-root/edgeless/clipboard/clipboard.js +3 -3
- package/dist/_pkgs/affine-block-root/keyboard/keymap.js +20 -0
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.d.ts +6 -4
- package/dist/_pkgs/affine-block-surface/extensions/export-manager/export-manager.js +15 -10
- package/dist/_pkgs/affine-block-surface/utils/priority-queue.js +2 -2
- package/dist/_pkgs/affine-components/toggle-button/toggle-button.d.ts +5 -0
- package/dist/_pkgs/affine-components/toggle-button/toggle-button.js +31 -18
- package/dist/_pkgs/affine-gfx-connector/connector-manager.d.ts +13 -1
- package/dist/_pkgs/affine-gfx-connector/connector-manager.js +9 -5
- package/dist/_pkgs/affine-gfx-connector/connector-watcher.js +48 -17
- package/dist/_pkgs/affine-gfx-connector/view/view.js +4 -0
- package/dist/_pkgs/affine-gfx-mindmap/view/view.js +9 -1
- package/dist/_pkgs/affine-gfx-mindmap/view.js +7 -2
- package/dist/_pkgs/affine-gfx-template/contribute.d.ts +32 -7
- package/dist/_pkgs/affine-gfx-template/contribute.js +66 -22
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.d.ts +7 -0
- package/dist/_pkgs/affine-gfx-template/toolbar/template-panel.js +19 -4
- package/dist/_pkgs/affine-model/elements/mindmap/mindmap.js +10 -1
- package/dist/_pkgs/affine-shared/adapters/middlewares/proxy.d.ts +10 -0
- package/dist/_pkgs/affine-shared/adapters/middlewares/proxy.js +19 -12
- package/dist/_pkgs/affine-shared/adapters/utils/fetch.js +4 -0
- package/dist/_pkgs/affine-widget-keyboard-toolbar/widget.js +18 -3
- package/dist/_pkgs/affine-widget-linked-doc/mobile-linked-doc-menu.d.ts +7 -1
- package/dist/_pkgs/affine-widget-linked-doc/mobile-linked-doc-menu.js +8 -2
- package/dist/_pkgs/std/gfx/index.d.ts +1 -1
- package/dist/_pkgs/std/gfx/model/surface/element-model.d.ts +2 -2
- package/dist/_pkgs/std/gfx/model/surface/element-model.js +2 -2
- package/dist/_pkgs/std/gfx/model/surface/surface-model.d.ts +1 -1
- package/dist/_pkgs/std/gfx/model/surface/surface-model.js +1 -1
- package/package.json +1 -1
|
@@ -167,14 +167,17 @@ export class RichTextCell extends BaseCellRenderer {
|
|
|
167
167
|
e.stopPropagation();
|
|
168
168
|
};
|
|
169
169
|
this._onPaste = (e) => {
|
|
170
|
-
e.preventDefault();
|
|
171
|
-
e.stopPropagation();
|
|
172
170
|
const inlineEditor = this.inlineEditor$.value;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
const inlineRange = inlineEditor?.getInlineRange();
|
|
172
|
+
// Bail out before cancelling the event: with no resolvable inline range
|
|
173
|
+
// there is nothing to insert into, and swallowing the paste here would
|
|
174
|
+
// drop the clipboard silently instead of letting the default path act.
|
|
175
|
+
if (!inlineEditor || !inlineRange)
|
|
177
176
|
return;
|
|
177
|
+
// The cell owns the paste: stop it before the document clipboard sees it,
|
|
178
|
+
// whichever branch below ends up handling the payload.
|
|
179
|
+
e.preventDefault();
|
|
180
|
+
e.stopPropagation();
|
|
178
181
|
if (e.clipboardData) {
|
|
179
182
|
try {
|
|
180
183
|
const getDeltas = (snapshot) => {
|
|
@@ -290,9 +293,11 @@ export class RichTextCell extends BaseCellRenderer {
|
|
|
290
293
|
richText.addEventListener('cut', this._onCut, true);
|
|
291
294
|
richText.addEventListener('paste', this._onPaste, true);
|
|
292
295
|
return () => {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
richText.removeEventListener('
|
|
296
|
+
// the capture flag is part of the listener identity: without it
|
|
297
|
+
// these three would never be removed.
|
|
298
|
+
richText.removeEventListener('copy', this._onCopy, true);
|
|
299
|
+
richText.removeEventListener('cut', this._onCut, true);
|
|
300
|
+
richText.removeEventListener('paste', this._onPaste, true);
|
|
296
301
|
};
|
|
297
302
|
}
|
|
298
303
|
return;
|
|
@@ -259,6 +259,15 @@ export class EdgelessFrameManager extends GfxExtension {
|
|
|
259
259
|
}
|
|
260
260
|
}));
|
|
261
261
|
this._disposable.add(doc.slots.blockUpdated.subscribe(payload => {
|
|
262
|
+
// Local adds only, exactly like the canvas-element half above. A block
|
|
263
|
+
// added by a remote peer was already adopted THERE: the frame's
|
|
264
|
+
// `childElementIds` arrives with the same sync. Adopting it again here
|
|
265
|
+
// is a duplicate write on every receiving peer — and a readonly viewer
|
|
266
|
+
// cannot write at all, which is how this surfaced (#251). See #242 for
|
|
267
|
+
// the rule: a cascade reacts to local transactions, the receiving peer
|
|
268
|
+
// trusts the sync.
|
|
269
|
+
if (!payload.isLocal)
|
|
270
|
+
return;
|
|
262
271
|
if (payload.type === 'add' &&
|
|
263
272
|
payload.model instanceof GfxBlockElementModel &&
|
|
264
273
|
renderableInEdgeless(doc, surfaceModel, payload.model)) {
|
|
@@ -275,15 +284,7 @@ export class EdgelessFrameManager extends GfxExtension {
|
|
|
275
284
|
if (this._enclosesFrame(payload.model, frame)) {
|
|
276
285
|
return;
|
|
277
286
|
}
|
|
278
|
-
|
|
279
|
-
this._adoptNewlyCreatedElement(frame, payload.model);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
// Remote adds: adopt only. The originating client reassigns the
|
|
283
|
-
// index and syncs it — reindexing here too would produce
|
|
284
|
-
// competing concurrent writes for the same element.
|
|
285
|
-
this.addElementsToFrame(frame, [payload.model]);
|
|
286
|
-
}
|
|
287
|
+
this._adoptNewlyCreatedElement(frame, payload.model);
|
|
287
288
|
}
|
|
288
289
|
}));
|
|
289
290
|
}
|
|
@@ -6,6 +6,14 @@ import { type TemplateResult } from 'lit';
|
|
|
6
6
|
export declare class ListBlockComponent extends CaptionedBlockComponent<ListBlockModel> {
|
|
7
7
|
static styles: import("lit").CSSResult;
|
|
8
8
|
private _inlineRangeProvider;
|
|
9
|
+
/**
|
|
10
|
+
* The collapse state a READER holds locally. Same contract as
|
|
11
|
+
* `affine-paragraph`: a readonly document is never written, so the toggle
|
|
12
|
+
* carries the reader's own expansion here instead of in the model. A signal
|
|
13
|
+
* rather than a Lit `@state()`, so BlockSuite effects can depend on it.
|
|
14
|
+
*/
|
|
15
|
+
private readonly _readonlyCollapsed;
|
|
16
|
+
private _setReadonlyCollapsed;
|
|
9
17
|
private readonly _onClickIcon;
|
|
10
18
|
get attributeRenderer(): import("../std/inline/types.js").AttributeRenderer<import("../affine-shared/types/index.js").AffineTextAttributes>;
|
|
11
19
|
get attributesSchema(): import("zod").ZodType<any, import("zod").ZodTypeDef, any>;
|
|
@@ -16,7 +24,6 @@ export declare class ListBlockComponent extends CaptionedBlockComponent<ListBloc
|
|
|
16
24
|
connectedCallback(): void;
|
|
17
25
|
getUpdateComplete(): Promise<boolean>;
|
|
18
26
|
renderBlock(): TemplateResult<1>;
|
|
19
|
-
private accessor _readonlyCollapsed;
|
|
20
27
|
private accessor _richTextElement;
|
|
21
28
|
accessor blockContainerStyles: {
|
|
22
29
|
margin: string;
|
|
@@ -42,9 +42,9 @@ import { DocModeProvider } from '../affine-shared/services/index.js';
|
|
|
42
42
|
import { getViewportElement } from '../affine-shared/utils/index.js';
|
|
43
43
|
import { BlockSelection, TextSelection } from '../std/index.js';
|
|
44
44
|
import { getInlineRangeProvider, } from '../std/inline/index.js';
|
|
45
|
-
import { effect } from '@preact/signals-core';
|
|
45
|
+
import { effect, signal } from '@preact/signals-core';
|
|
46
46
|
import { html, nothing } from 'lit';
|
|
47
|
-
import { query
|
|
47
|
+
import { query } from 'lit/decorators.js';
|
|
48
48
|
import { classMap } from 'lit/directives/class-map.js';
|
|
49
49
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
50
50
|
import { correctNumberedListsOrderToPrev } from './commands/utils.js';
|
|
@@ -52,9 +52,6 @@ import { listBlockStyles } from './styles.js';
|
|
|
52
52
|
import { getListIcon } from './utils/get-list-icon.js';
|
|
53
53
|
let ListBlockComponent = (() => {
|
|
54
54
|
let _classSuper = CaptionedBlockComponent;
|
|
55
|
-
let __readonlyCollapsed_decorators;
|
|
56
|
-
let __readonlyCollapsed_initializers = [];
|
|
57
|
-
let __readonlyCollapsed_extraInitializers = [];
|
|
58
55
|
let __richTextElement_decorators;
|
|
59
56
|
let __richTextElement_initializers = [];
|
|
60
57
|
let __richTextElement_extraInitializers = [];
|
|
@@ -62,12 +59,19 @@ let ListBlockComponent = (() => {
|
|
|
62
59
|
constructor() {
|
|
63
60
|
super(...arguments);
|
|
64
61
|
this._inlineRangeProvider = null;
|
|
62
|
+
/**
|
|
63
|
+
* The collapse state a READER holds locally. Same contract as
|
|
64
|
+
* `affine-paragraph`: a readonly document is never written, so the toggle
|
|
65
|
+
* carries the reader's own expansion here instead of in the model. A signal
|
|
66
|
+
* rather than a Lit `@state()`, so BlockSuite effects can depend on it.
|
|
67
|
+
*/
|
|
68
|
+
this._readonlyCollapsed = signal(false);
|
|
65
69
|
this._onClickIcon = (e) => {
|
|
66
70
|
e.stopPropagation();
|
|
67
71
|
e.preventDefault();
|
|
68
72
|
if (this.model.props.type === 'toggle') {
|
|
69
73
|
if (this.store.readonly) {
|
|
70
|
-
this.
|
|
74
|
+
this._setReadonlyCollapsed(!this._readonlyCollapsed.value);
|
|
71
75
|
}
|
|
72
76
|
else {
|
|
73
77
|
this.store.captureSync();
|
|
@@ -93,21 +97,22 @@ let ListBlockComponent = (() => {
|
|
|
93
97
|
}
|
|
94
98
|
this._select();
|
|
95
99
|
};
|
|
96
|
-
this.#
|
|
97
|
-
this.#_richTextElement_accessor_storage = (__runInitializers(this, __readonlyCollapsed_extraInitializers), __runInitializers(this, __richTextElement_initializers, null));
|
|
100
|
+
this.#_richTextElement_accessor_storage = __runInitializers(this, __richTextElement_initializers, null);
|
|
98
101
|
this.#blockContainerStyles_accessor_storage = (__runInitializers(this, __richTextElement_extraInitializers), {
|
|
99
102
|
margin: 'var(--affine-list-margin, 10px 0)',
|
|
100
103
|
});
|
|
101
104
|
}
|
|
102
105
|
static {
|
|
103
106
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
104
|
-
__readonlyCollapsed_decorators = [state()];
|
|
105
107
|
__richTextElement_decorators = [query('rich-text')];
|
|
106
|
-
__esDecorate(this, null, __readonlyCollapsed_decorators, { kind: "accessor", name: "_readonlyCollapsed", static: false, private: false, access: { has: obj => "_readonlyCollapsed" in obj, get: obj => obj._readonlyCollapsed, set: (obj, value) => { obj._readonlyCollapsed = value; } }, metadata: _metadata }, __readonlyCollapsed_initializers, __readonlyCollapsed_extraInitializers);
|
|
107
108
|
__esDecorate(this, null, __richTextElement_decorators, { kind: "accessor", name: "_richTextElement", static: false, private: false, access: { has: obj => "_richTextElement" in obj, get: obj => obj._richTextElement, set: (obj, value) => { obj._richTextElement = value; } }, metadata: _metadata }, __richTextElement_initializers, __richTextElement_extraInitializers);
|
|
108
109
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
109
110
|
}
|
|
110
111
|
static { this.styles = listBlockStyles; }
|
|
112
|
+
_setReadonlyCollapsed(collapsed) {
|
|
113
|
+
this._readonlyCollapsed.value = collapsed;
|
|
114
|
+
this.requestUpdate();
|
|
115
|
+
}
|
|
111
116
|
get attributeRenderer() {
|
|
112
117
|
return this.inlineManager.getRenderer();
|
|
113
118
|
}
|
|
@@ -137,9 +142,14 @@ let ListBlockComponent = (() => {
|
|
|
137
142
|
connectedCallback() {
|
|
138
143
|
super.connectedCallback();
|
|
139
144
|
this._inlineRangeProvider = getInlineRangeProvider(this);
|
|
145
|
+
// Only ENTERING readonly mode (or a later change of the persisted value)
|
|
146
|
+
// seeds the reader's local state; while readonly holds, the reader's own
|
|
147
|
+
// expansion is never overwritten. Aligned on `affine-paragraph`, where the
|
|
148
|
+
// unguarded version was a real defect (#262).
|
|
140
149
|
this.disposables.add(effect(() => {
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
if (this.store.readonly$.value) {
|
|
151
|
+
this._setReadonlyCollapsed(this.model.props.collapsed$.value);
|
|
152
|
+
}
|
|
143
153
|
}));
|
|
144
154
|
this.disposables.add(effect(() => {
|
|
145
155
|
const type = this.model.props.type$.value;
|
|
@@ -162,10 +172,12 @@ let ListBlockComponent = (() => {
|
|
|
162
172
|
renderBlock() {
|
|
163
173
|
const { model, _onClickIcon } = this;
|
|
164
174
|
const collapsed = this.store.readonly
|
|
165
|
-
? this._readonlyCollapsed
|
|
175
|
+
? this._readonlyCollapsed.value
|
|
166
176
|
: model.props.collapsed;
|
|
167
177
|
const listIcon = getListIcon(model, !collapsed, _onClickIcon);
|
|
178
|
+
const childrenId = `list-children-${this.model.id}`;
|
|
168
179
|
const children = html `<div
|
|
180
|
+
id=${childrenId}
|
|
169
181
|
class="affine-block-children-container"
|
|
170
182
|
style=${styleMap({
|
|
171
183
|
paddingLeft: `${BLOCK_CHILDREN_CONTAINER_PADDING_LEFT}px`,
|
|
@@ -187,9 +199,10 @@ let ListBlockComponent = (() => {
|
|
|
187
199
|
? html `
|
|
188
200
|
<blocksuite-toggle-button
|
|
189
201
|
.collapsed=${collapsed}
|
|
202
|
+
.controls=${childrenId}
|
|
190
203
|
.updateCollapsed=${(value) => {
|
|
191
204
|
if (this.store.readonly) {
|
|
192
|
-
this.
|
|
205
|
+
this._setReadonlyCollapsed(value);
|
|
193
206
|
}
|
|
194
207
|
else {
|
|
195
208
|
this.store.captureSync();
|
|
@@ -222,9 +235,6 @@ let ListBlockComponent = (() => {
|
|
|
222
235
|
</div>
|
|
223
236
|
`;
|
|
224
237
|
}
|
|
225
|
-
#_readonlyCollapsed_accessor_storage;
|
|
226
|
-
get _readonlyCollapsed() { return this.#_readonlyCollapsed_accessor_storage; }
|
|
227
|
-
set _readonlyCollapsed(value) { this.#_readonlyCollapsed_accessor_storage = value; }
|
|
228
238
|
#_richTextElement_accessor_storage;
|
|
229
239
|
get _richTextElement() { return this.#_richTextElement_accessor_storage; }
|
|
230
240
|
set _richTextElement(value) { this.#_richTextElement_accessor_storage = value; }
|
|
@@ -7,9 +7,17 @@ export declare class ParagraphBlockComponent extends CaptionedBlockComponent<Par
|
|
|
7
7
|
focused$: import("@preact/signals-core").ReadonlySignal<boolean>;
|
|
8
8
|
private readonly _composing;
|
|
9
9
|
private readonly _displayPlaceholder;
|
|
10
|
+
/**
|
|
11
|
+
* The collapse state a READER holds locally. A readonly document must never
|
|
12
|
+
* be written, so the chevron cannot touch `model.props.collapsed`; this
|
|
13
|
+
* signal carries the reader's own expansion instead. It is a signal rather
|
|
14
|
+
* than a Lit `@state()` so BlockSuite effects can depend on it as well.
|
|
15
|
+
*/
|
|
16
|
+
private readonly _readonlyCollapsed;
|
|
10
17
|
private _inlineRangeProvider;
|
|
11
18
|
private readonly _isInDatabase;
|
|
12
19
|
private get _placeholder();
|
|
20
|
+
private _setReadonlyCollapsed;
|
|
13
21
|
get citationService(): import("../affine-shared/services/index.js").CitationViewService;
|
|
14
22
|
get attributeRenderer(): import("../std/inline/types.js").AttributeRenderer<import("../affine-shared/types/index.js").AffineTextAttributes>;
|
|
15
23
|
get attributesSchema(): import("zod").ZodType<any, import("zod").ZodTypeDef, any>;
|
|
@@ -24,7 +32,6 @@ export declare class ParagraphBlockComponent extends CaptionedBlockComponent<Par
|
|
|
24
32
|
connectedCallback(): void;
|
|
25
33
|
getUpdateComplete(): Promise<boolean>;
|
|
26
34
|
renderBlock(): TemplateResult<1>;
|
|
27
|
-
private accessor _readonlyCollapsed;
|
|
28
35
|
private accessor _richTextElement;
|
|
29
36
|
accessor blockContainerStyles: {
|
|
30
37
|
margin: string;
|
|
@@ -42,7 +42,7 @@ import { TextSelection } from '../std/index.js';
|
|
|
42
42
|
import { getInlineRangeProvider, } from '../std/inline/index.js';
|
|
43
43
|
import { computed, effect, signal } from '@preact/signals-core';
|
|
44
44
|
import { html, nothing } from 'lit';
|
|
45
|
-
import { query
|
|
45
|
+
import { query } from 'lit/decorators.js';
|
|
46
46
|
import { classMap } from 'lit/directives/class-map.js';
|
|
47
47
|
import { styleMap } from 'lit/directives/style-map.js';
|
|
48
48
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
@@ -50,9 +50,6 @@ import { ParagraphBlockConfigExtension } from './paragraph-block-config.js';
|
|
|
50
50
|
import { paragraphBlockStyles } from './styles.js';
|
|
51
51
|
let ParagraphBlockComponent = (() => {
|
|
52
52
|
let _classSuper = CaptionedBlockComponent;
|
|
53
|
-
let __readonlyCollapsed_decorators;
|
|
54
|
-
let __readonlyCollapsed_initializers = [];
|
|
55
|
-
let __readonlyCollapsed_extraInitializers = [];
|
|
56
53
|
let __richTextElement_decorators;
|
|
57
54
|
let __richTextElement_initializers = [];
|
|
58
55
|
let __richTextElement_extraInitializers = [];
|
|
@@ -67,6 +64,13 @@ let ParagraphBlockComponent = (() => {
|
|
|
67
64
|
});
|
|
68
65
|
this._composing = signal(false);
|
|
69
66
|
this._displayPlaceholder = signal(false);
|
|
67
|
+
/**
|
|
68
|
+
* The collapse state a READER holds locally. A readonly document must never
|
|
69
|
+
* be written, so the chevron cannot touch `model.props.collapsed`; this
|
|
70
|
+
* signal carries the reader's own expansion instead. It is a signal rather
|
|
71
|
+
* than a Lit `@state()` so BlockSuite effects can depend on it as well.
|
|
72
|
+
*/
|
|
73
|
+
this._readonlyCollapsed = signal(false);
|
|
70
74
|
this._inlineRangeProvider = null;
|
|
71
75
|
this._isInDatabase = () => {
|
|
72
76
|
let parent = this.parentElement;
|
|
@@ -78,17 +82,14 @@ let ParagraphBlockComponent = (() => {
|
|
|
78
82
|
}
|
|
79
83
|
return false;
|
|
80
84
|
};
|
|
81
|
-
this.#
|
|
82
|
-
this.#_richTextElement_accessor_storage = (__runInitializers(this, __readonlyCollapsed_extraInitializers), __runInitializers(this, __richTextElement_initializers, null));
|
|
85
|
+
this.#_richTextElement_accessor_storage = __runInitializers(this, __richTextElement_initializers, null);
|
|
83
86
|
this.#blockContainerStyles_accessor_storage = (__runInitializers(this, __richTextElement_extraInitializers), {
|
|
84
87
|
margin: 'var(--affine-paragraph-margin, 10px 0)',
|
|
85
88
|
});
|
|
86
89
|
}
|
|
87
90
|
static {
|
|
88
91
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
89
|
-
__readonlyCollapsed_decorators = [state()];
|
|
90
92
|
__richTextElement_decorators = [query('rich-text')];
|
|
91
|
-
__esDecorate(this, null, __readonlyCollapsed_decorators, { kind: "accessor", name: "_readonlyCollapsed", static: false, private: false, access: { has: obj => "_readonlyCollapsed" in obj, get: obj => obj._readonlyCollapsed, set: (obj, value) => { obj._readonlyCollapsed = value; } }, metadata: _metadata }, __readonlyCollapsed_initializers, __readonlyCollapsed_extraInitializers);
|
|
92
93
|
__esDecorate(this, null, __richTextElement_decorators, { kind: "accessor", name: "_richTextElement", static: false, private: false, access: { has: obj => "_richTextElement" in obj, get: obj => obj._richTextElement, set: (obj, value) => { obj._richTextElement = value; } }, metadata: _metadata }, __richTextElement_initializers, __richTextElement_extraInitializers);
|
|
93
94
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
94
95
|
}
|
|
@@ -98,6 +99,10 @@ let ParagraphBlockComponent = (() => {
|
|
|
98
99
|
.get(ParagraphBlockConfigExtension.identifier)
|
|
99
100
|
?.getPlaceholder(this.model);
|
|
100
101
|
}
|
|
102
|
+
_setReadonlyCollapsed(collapsed) {
|
|
103
|
+
this._readonlyCollapsed.value = collapsed;
|
|
104
|
+
this.requestUpdate();
|
|
105
|
+
}
|
|
101
106
|
get citationService() {
|
|
102
107
|
return this.std.get(CitationProvider);
|
|
103
108
|
}
|
|
@@ -176,9 +181,19 @@ let ParagraphBlockComponent = (() => {
|
|
|
176
181
|
this.model.props.collapsed = false;
|
|
177
182
|
}
|
|
178
183
|
}));
|
|
184
|
+
// Entering readonly mode (and any later change of the persisted value)
|
|
185
|
+
// seeds the reader's local state. Deliberately NOT re-run on every
|
|
186
|
+
// selection change: this effect must not depend on the selection, or the
|
|
187
|
+
// reader's own expansion would be overwritten mid-drag.
|
|
188
|
+
this.disposables.add(effect(() => {
|
|
189
|
+
if (this.store.readonly$.value) {
|
|
190
|
+
this._setReadonlyCollapsed(this.model.props.collapsed$.value);
|
|
191
|
+
}
|
|
192
|
+
}));
|
|
179
193
|
this.disposables.add(effect(() => {
|
|
180
|
-
const collapsed = this.
|
|
181
|
-
|
|
194
|
+
const collapsed = this.store.readonly
|
|
195
|
+
? this._readonlyCollapsed.value
|
|
196
|
+
: this.model.props.collapsed$.value;
|
|
182
197
|
// reset text selection when selected block is collapsed
|
|
183
198
|
if (this.model.props.type$.value.startsWith('h') && collapsed) {
|
|
184
199
|
const collapsedSiblings = this.collapsedSiblings;
|
|
@@ -216,7 +231,7 @@ let ParagraphBlockComponent = (() => {
|
|
|
216
231
|
renderBlock() {
|
|
217
232
|
const { type$ } = this.model.props;
|
|
218
233
|
const collapsed = this.store.readonly
|
|
219
|
-
? this._readonlyCollapsed
|
|
234
|
+
? this._readonlyCollapsed.value
|
|
220
235
|
: this.model.props.collapsed;
|
|
221
236
|
const collapsedSiblings = this.collapsedSiblings;
|
|
222
237
|
let style = html ``;
|
|
@@ -231,7 +246,9 @@ let ParagraphBlockComponent = (() => {
|
|
|
231
246
|
</style>
|
|
232
247
|
`;
|
|
233
248
|
}
|
|
249
|
+
const childrenId = `heading-children-${this.model.id}`;
|
|
234
250
|
const children = html `<div
|
|
251
|
+
id=${childrenId}
|
|
235
252
|
class="affine-block-children-container"
|
|
236
253
|
style=${styleMap({
|
|
237
254
|
paddingLeft: `${BLOCK_CHILDREN_CONTAINER_PADDING_LEFT}px`,
|
|
@@ -275,9 +292,10 @@ let ParagraphBlockComponent = (() => {
|
|
|
275
292
|
? html `
|
|
276
293
|
<blocksuite-toggle-button
|
|
277
294
|
.collapsed=${collapsed}
|
|
295
|
+
.controls=${childrenId}
|
|
278
296
|
.updateCollapsed=${(value) => {
|
|
279
297
|
if (this.store.readonly) {
|
|
280
|
-
this.
|
|
298
|
+
this._setReadonlyCollapsed(value);
|
|
281
299
|
}
|
|
282
300
|
else {
|
|
283
301
|
this.store.captureSync();
|
|
@@ -328,9 +346,6 @@ let ParagraphBlockComponent = (() => {
|
|
|
328
346
|
</div>
|
|
329
347
|
`;
|
|
330
348
|
}
|
|
331
|
-
#_readonlyCollapsed_accessor_storage;
|
|
332
|
-
get _readonlyCollapsed() { return this.#_readonlyCollapsed_accessor_storage; }
|
|
333
|
-
set _readonlyCollapsed(value) { this.#_readonlyCollapsed_accessor_storage = value; }
|
|
334
349
|
#_richTextElement_accessor_storage;
|
|
335
350
|
get _richTextElement() { return this.#_richTextElement_accessor_storage; }
|
|
336
351
|
set _richTextElement(value) { this.#_richTextElement_accessor_storage = value; }
|
|
@@ -4,7 +4,7 @@ import { addImages } from '../../../affine-block-image/index.js';
|
|
|
4
4
|
import { CanvasRenderer, DefaultTool, EdgelessCRUDIdentifier, ExportManager, getSurfaceComponent, } from '../../../affine-block-surface/index.js';
|
|
5
5
|
import { splitIntoLines } from '../../../affine-gfx-text/index.js';
|
|
6
6
|
import { BookmarkStyles, DEFAULT_NOTE_HEIGHT, DEFAULT_NOTE_WIDTH, FrameBlockModel, MAX_IMAGE_WIDTH, } from '../../../affine-model/index.js';
|
|
7
|
-
import { ClipboardAdapter, decodeClipboardBlobs, } from '../../../affine-shared/adapters/index.js';
|
|
7
|
+
import { ClipboardAdapter, decodeClipboardBlobs, ImageProxyService, } from '../../../affine-shared/adapters/index.js';
|
|
8
8
|
import { CANVAS_EXPORT_IGNORE_TAGS, EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '../../../affine-shared/consts/index.js';
|
|
9
9
|
import { EmbedOptionProvider, ParseDocUrlProvider, TelemetryProvider, } from '../../../affine-shared/services/index.js';
|
|
10
10
|
import { convertToPng, isInsidePageEditor, isTopLevelBlock, isUrlInClipboard, matchModels, referenceToNode, } from '../../../affine-shared/utils/index.js';
|
|
@@ -324,7 +324,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
|
|
324
324
|
}
|
|
325
325
|
ctx.scale(dpr, dpr);
|
|
326
326
|
const replaceImgSrcWithSvg = this._exportManager?.replaceImgSrcWithSvg;
|
|
327
|
-
const imageProxy = host.std.
|
|
327
|
+
const imageProxy = host.std.get(ImageProxyService).imageProxyURL;
|
|
328
328
|
const html2canvasOption = {
|
|
329
329
|
ignoreElements: function (element) {
|
|
330
330
|
if (CANVAS_EXPORT_IGNORE_TAGS.includes(element.tagName) ||
|
|
@@ -351,7 +351,7 @@ export class EdgelessClipboardController extends PageClipboard {
|
|
|
351
351
|
await replaceImgSrcWithSvg?.(element);
|
|
352
352
|
},
|
|
353
353
|
backgroundColor: 'transparent',
|
|
354
|
-
useCORS: imageProxy
|
|
354
|
+
useCORS: !imageProxy,
|
|
355
355
|
proxy: imageProxy,
|
|
356
356
|
};
|
|
357
357
|
const _drawTopLevelBlock = async (block, isInFrame = false) => {
|
|
@@ -1,13 +1,33 @@
|
|
|
1
1
|
import { KeymapExtension } from '../../std/index.js';
|
|
2
|
+
const NATIVE_FOCUSABLE_SELECTOR = 'button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
3
|
+
/**
|
|
4
|
+
* The editor host swallows Tab and Shift-Tab so that indentation stays under
|
|
5
|
+
* the control of the block-scoped handlers. That would however trap the focus
|
|
6
|
+
* on the native controls the editor renders (the collapse button of headings
|
|
7
|
+
* and lists, for instance), which then could neither be reached nor left with
|
|
8
|
+
* the keyboard. When the event originates from such a control — and not from
|
|
9
|
+
* editable text — the native tabbing behaviour is let through.
|
|
10
|
+
*/
|
|
11
|
+
const isNativeFocusableTarget = (target) => {
|
|
12
|
+
if (!(target instanceof Element))
|
|
13
|
+
return false;
|
|
14
|
+
if (target instanceof HTMLElement && target.isContentEditable)
|
|
15
|
+
return false;
|
|
16
|
+
return !!target.closest(NATIVE_FOCUSABLE_SELECTOR);
|
|
17
|
+
};
|
|
2
18
|
export const fallbackKeymap = KeymapExtension(() => {
|
|
3
19
|
return {
|
|
4
20
|
Tab: ctx => {
|
|
5
21
|
const event = ctx.get('defaultState').event;
|
|
22
|
+
if (isNativeFocusableTarget(event.target))
|
|
23
|
+
return;
|
|
6
24
|
event.stopPropagation();
|
|
7
25
|
event.preventDefault();
|
|
8
26
|
},
|
|
9
27
|
'Shift-Tab': ctx => {
|
|
10
28
|
const event = ctx.get('defaultState').event;
|
|
29
|
+
if (isNativeFocusableTarget(event.target))
|
|
30
|
+
return;
|
|
11
31
|
event.stopPropagation();
|
|
12
32
|
event.preventDefault();
|
|
13
33
|
},
|
|
@@ -3,12 +3,14 @@ import { type BlockStdScope, type EditorHost } from '../../../std/index.js';
|
|
|
3
3
|
import { GfxBlockElementModel, type GfxController, GfxPrimitiveElementModel } from '../../../std/gfx/index.js';
|
|
4
4
|
import type { ExtensionType, Store } from '../../../store/index.js';
|
|
5
5
|
import { CanvasRenderer } from '../../renderer/canvas-renderer.js';
|
|
6
|
-
export type ExportOptions = {
|
|
7
|
-
imageProxyEndpoint: string;
|
|
8
|
-
};
|
|
9
6
|
export declare class ExportManager {
|
|
10
7
|
readonly std: BlockStdScope;
|
|
11
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The image proxy every remote-image fetch of the export goes through —
|
|
10
|
+
* resolved from {@link ImageProxyService}, the one host seam for it, never
|
|
11
|
+
* from a local constant. Empty means « fetch direct » (issue #258).
|
|
12
|
+
*/
|
|
13
|
+
private get _imageProxyURL();
|
|
12
14
|
replaceImgSrcWithSvg: (element: HTMLElement) => Promise<void>;
|
|
13
15
|
get doc(): Store;
|
|
14
16
|
get editorHost(): EditorHost;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ImageBlockModel } from '../../../affine-model/index.js';
|
|
2
|
-
import { FetchUtils } from '../../../affine-shared/adapters/index.js';
|
|
3
|
-
import { CANVAS_EXPORT_IGNORE_TAGS
|
|
2
|
+
import { FetchUtils, ImageProxyService } from '../../../affine-shared/adapters/index.js';
|
|
3
|
+
import { CANVAS_EXPORT_IGNORE_TAGS } from '../../../affine-shared/consts/index.js';
|
|
4
4
|
import { isInsidePageEditor, matchModels } from '../../../affine-shared/utils/index.js';
|
|
5
5
|
import { BlockSuiteError, ErrorCode } from '../../../global/exceptions/index.js';
|
|
6
6
|
import { deserializeXYWH } from '../../../global/gfx/index.js';
|
|
@@ -10,6 +10,14 @@ import { CanvasRenderer } from '../../renderer/canvas-renderer.js';
|
|
|
10
10
|
import { getBgGridGap } from '../../utils/get-bg-grip-gap.js';
|
|
11
11
|
import { FileExporter } from './file-exporter.js';
|
|
12
12
|
export class ExportManager {
|
|
13
|
+
/**
|
|
14
|
+
* The image proxy every remote-image fetch of the export goes through —
|
|
15
|
+
* resolved from {@link ImageProxyService}, the one host seam for it, never
|
|
16
|
+
* from a local constant. Empty means « fetch direct » (issue #258).
|
|
17
|
+
*/
|
|
18
|
+
get _imageProxyURL() {
|
|
19
|
+
return this.std.get(ImageProxyService).imageProxyURL;
|
|
20
|
+
}
|
|
13
21
|
get doc() {
|
|
14
22
|
return this.std.store;
|
|
15
23
|
}
|
|
@@ -18,14 +26,11 @@ export class ExportManager {
|
|
|
18
26
|
}
|
|
19
27
|
constructor(std) {
|
|
20
28
|
this.std = std;
|
|
21
|
-
this._exportOptions = {
|
|
22
|
-
imageProxyEndpoint: DEFAULT_IMAGE_PROXY_ENDPOINT,
|
|
23
|
-
};
|
|
24
29
|
this.replaceImgSrcWithSvg = async (element) => {
|
|
25
30
|
const imgList = Array.from(element.querySelectorAll('img'));
|
|
26
31
|
// Create an array of promises
|
|
27
32
|
const promises = imgList.map(img => {
|
|
28
|
-
return FetchUtils.fetchImage(img.src, undefined, this.
|
|
33
|
+
return FetchUtils.fetchImage(img.src, undefined, this._imageProxyURL)
|
|
29
34
|
.then(response => response && response.blob())
|
|
30
35
|
.then(async (blob) => {
|
|
31
36
|
if (!blob)
|
|
@@ -159,8 +164,8 @@ export class ExportManager {
|
|
|
159
164
|
x: pageLeft - viewport.left,
|
|
160
165
|
width: pageWidth,
|
|
161
166
|
height: viewportHeight,
|
|
162
|
-
useCORS: this.
|
|
163
|
-
proxy: this.
|
|
167
|
+
useCORS: !this._imageProxyURL,
|
|
168
|
+
proxy: this._imageProxyURL,
|
|
164
169
|
};
|
|
165
170
|
let data;
|
|
166
171
|
try {
|
|
@@ -228,8 +233,8 @@ export class ExportManager {
|
|
|
228
233
|
});
|
|
229
234
|
await this.replaceImgSrcWithSvg(element);
|
|
230
235
|
},
|
|
231
|
-
useCORS: this.
|
|
232
|
-
proxy: this.
|
|
236
|
+
useCORS: !this._imageProxyURL,
|
|
237
|
+
proxy: this._imageProxyURL,
|
|
233
238
|
};
|
|
234
239
|
let data;
|
|
235
240
|
try {
|
|
@@ -21,9 +21,9 @@ export class PriorityQueue {
|
|
|
21
21
|
if (rightChildIndex < length) {
|
|
22
22
|
leftChild = this.heap[leftChildIndex];
|
|
23
23
|
rightChild = this.heap[rightChildIndex];
|
|
24
|
-
if ((swap ===
|
|
24
|
+
if ((swap === -1 &&
|
|
25
25
|
this._compare(rightChild.priority, element.priority) < 0) ||
|
|
26
|
-
(swap !==
|
|
26
|
+
(swap !== -1 &&
|
|
27
27
|
this._compare(rightChild.priority, leftChild.priority) < 0)) {
|
|
28
28
|
swap = rightChildIndex;
|
|
29
29
|
}
|
|
@@ -6,6 +6,11 @@ export declare class ToggleButton extends ToggleButton_base {
|
|
|
6
6
|
render(): import("lit-html").TemplateResult<1>;
|
|
7
7
|
accessor collapsed: boolean;
|
|
8
8
|
accessor updateCollapsed: (collapsed: boolean) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Id of the children container this button expands and collapses,
|
|
11
|
+
* exposed to assistive technologies through `aria-controls`.
|
|
12
|
+
*/
|
|
13
|
+
accessor controls: string;
|
|
9
14
|
}
|
|
10
15
|
declare global {
|
|
11
16
|
interface HTMLElementTagNameMap {
|
|
@@ -48,13 +48,18 @@ let ToggleButton = (() => {
|
|
|
48
48
|
let _updateCollapsed_decorators;
|
|
49
49
|
let _updateCollapsed_initializers = [];
|
|
50
50
|
let _updateCollapsed_extraInitializers = [];
|
|
51
|
+
let _controls_decorators;
|
|
52
|
+
let _controls_initializers = [];
|
|
53
|
+
let _controls_extraInitializers = [];
|
|
51
54
|
return class ToggleButton extends _classSuper {
|
|
52
55
|
static {
|
|
53
56
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
54
57
|
_collapsed_decorators = [property({ attribute: false })];
|
|
55
58
|
_updateCollapsed_decorators = [property({ attribute: false })];
|
|
59
|
+
_controls_decorators = [property({ attribute: false })];
|
|
56
60
|
__esDecorate(this, null, _collapsed_decorators, { kind: "accessor", name: "collapsed", static: false, private: false, access: { has: obj => "collapsed" in obj, get: obj => obj.collapsed, set: (obj, value) => { obj.collapsed = value; } }, metadata: _metadata }, _collapsed_initializers, _collapsed_extraInitializers);
|
|
57
61
|
__esDecorate(this, null, _updateCollapsed_decorators, { kind: "accessor", name: "updateCollapsed", static: false, private: false, access: { has: obj => "updateCollapsed" in obj, get: obj => obj.updateCollapsed, set: (obj, value) => { obj.updateCollapsed = value; } }, metadata: _metadata }, _updateCollapsed_initializers, _updateCollapsed_extraInitializers);
|
|
62
|
+
__esDecorate(this, null, _controls_decorators, { kind: "accessor", name: "controls", static: false, private: false, access: { has: obj => "controls" in obj, get: obj => obj.controls, set: (obj, value) => { obj.controls = value; } }, metadata: _metadata }, _controls_initializers, _controls_extraInitializers);
|
|
58
63
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
59
64
|
}
|
|
60
65
|
static { this.styles = css `
|
|
@@ -63,6 +68,11 @@ let ToggleButton = (() => {
|
|
|
63
68
|
align-items: start;
|
|
64
69
|
justify-content: start;
|
|
65
70
|
position: absolute;
|
|
71
|
+
padding: 0;
|
|
72
|
+
border: 0;
|
|
73
|
+
color: inherit;
|
|
74
|
+
background: transparent;
|
|
75
|
+
font: inherit;
|
|
66
76
|
width: 16px;
|
|
67
77
|
height: 16px;
|
|
68
78
|
top: calc((1em - 16px) / 2 + 5px);
|
|
@@ -78,6 +88,11 @@ let ToggleButton = (() => {
|
|
|
78
88
|
background: var(--affine-hover-color);
|
|
79
89
|
}
|
|
80
90
|
|
|
91
|
+
.toggle-icon:focus-visible {
|
|
92
|
+
opacity: 1;
|
|
93
|
+
outline: 1px solid var(--affine-primary-color);
|
|
94
|
+
}
|
|
95
|
+
|
|
81
96
|
.toggle-icon[data-collapsed='true'] {
|
|
82
97
|
opacity: 1;
|
|
83
98
|
}
|
|
@@ -100,32 +115,23 @@ let ToggleButton = (() => {
|
|
|
100
115
|
}
|
|
101
116
|
`; }
|
|
102
117
|
render() {
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
class="toggle-icon"
|
|
107
|
-
@click=${() => this.updateCollapsed(!this.collapsed)}
|
|
108
|
-
>
|
|
109
|
-
${ToggleDownIcon({
|
|
110
|
-
width: '16px',
|
|
111
|
-
height: '16px',
|
|
112
|
-
})}
|
|
113
|
-
</div>
|
|
114
|
-
`;
|
|
115
|
-
const toggleRightTemplate = html `
|
|
116
|
-
<div
|
|
118
|
+
return html `
|
|
119
|
+
<button
|
|
120
|
+
type="button"
|
|
117
121
|
contenteditable="false"
|
|
118
122
|
class="toggle-icon"
|
|
119
123
|
data-collapsed=${this.collapsed}
|
|
124
|
+
aria-label=${this.collapsed ? 'Expand content' : 'Collapse content'}
|
|
125
|
+
aria-expanded=${!this.collapsed}
|
|
126
|
+
aria-controls=${this.controls}
|
|
120
127
|
@click=${() => this.updateCollapsed(!this.collapsed)}
|
|
121
128
|
>
|
|
122
|
-
${ToggleRightIcon({
|
|
129
|
+
${(this.collapsed ? ToggleRightIcon : ToggleDownIcon)({
|
|
123
130
|
width: '16px',
|
|
124
131
|
height: '16px',
|
|
125
132
|
})}
|
|
126
|
-
</
|
|
133
|
+
</button>
|
|
127
134
|
`;
|
|
128
|
-
return this.collapsed ? toggleRightTemplate : toggleDownTemplate;
|
|
129
135
|
}
|
|
130
136
|
#collapsed_accessor_storage = __runInitializers(this, _collapsed_initializers, void 0);
|
|
131
137
|
get collapsed() { return this.#collapsed_accessor_storage; }
|
|
@@ -133,9 +139,16 @@ let ToggleButton = (() => {
|
|
|
133
139
|
#updateCollapsed_accessor_storage = (__runInitializers(this, _collapsed_extraInitializers), __runInitializers(this, _updateCollapsed_initializers, void 0));
|
|
134
140
|
get updateCollapsed() { return this.#updateCollapsed_accessor_storage; }
|
|
135
141
|
set updateCollapsed(value) { this.#updateCollapsed_accessor_storage = value; }
|
|
142
|
+
#controls_accessor_storage = (__runInitializers(this, _updateCollapsed_extraInitializers), __runInitializers(this, _controls_initializers, void 0));
|
|
143
|
+
/**
|
|
144
|
+
* Id of the children container this button expands and collapses,
|
|
145
|
+
* exposed to assistive technologies through `aria-controls`.
|
|
146
|
+
*/
|
|
147
|
+
get controls() { return this.#controls_accessor_storage; }
|
|
148
|
+
set controls(value) { this.#controls_accessor_storage = value; }
|
|
136
149
|
constructor() {
|
|
137
150
|
super(...arguments);
|
|
138
|
-
__runInitializers(this,
|
|
151
|
+
__runInitializers(this, _controls_extraInitializers);
|
|
139
152
|
}
|
|
140
153
|
};
|
|
141
154
|
})();
|