@kubohiroya/turbowarp-extension-data-editor 0.7.0 → 0.8.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.
- package/LICENSE +373 -0
- package/README.ja.md +7 -1
- package/README.md +7 -1
- package/dist/build-info.json +3 -3
- package/dist/turbowarp/appearance.d.ts +7 -6
- package/dist/turbowarp/bridge.d.ts +14 -19
- package/dist/turbowarp/bridge.js +21 -16
- package/dist/turbowarp/error-session.d.ts +3 -17
- package/dist/turbowarp/error-session.js +2 -2
- package/dist/turbowarp/fixed-fields.d.ts +62 -77
- package/dist/turbowarp/fixed-fields.js +6 -6
- package/dist/turbowarp/fixed-transaction.d.ts +23 -18
- package/dist/turbowarp/fixed-transaction.js +13 -13
- package/dist/turbowarp/host.d.ts +2 -18
- package/dist/turbowarp/host.js +9 -6
- package/dist/turbowarp/icon.d.ts +1 -8
- package/dist/turbowarp/icon.js +6 -6
- package/dist/turbowarp/native-types.d.ts +136 -0
- package/dist/turbowarp/native-types.js +1 -0
- package/dist/turbowarp/subtree.d.ts +12 -9
- package/dist/turbowarp/subtree.js +3 -2
- package/dist/webpack4/THIRD_PARTY_LICENSES.md +1229 -0
- package/dist/webpack4/metafile.json +14 -14
- package/dist/webpack4/turbowarp.js +36 -29
- package/dist/webpack4/turbowarp.js.map +2 -2
- package/docs/ci-success-gate.md +2 -2
- package/docs/common-layout.ja.md +4 -4
- package/docs/descendants.md +2 -2
- package/docs/dialog-window.md +2 -2
- package/docs/schema-stage1.ja.md +3 -3
- package/docs/template-fixture-separation.ja.md +5 -5
- package/package.json +7 -5
- package/webpack4.cjs +19 -20
|
@@ -1,82 +1,67 @@
|
|
|
1
|
+
import type { FixedInputMetadata } from '../fixed-input-types.js';
|
|
2
|
+
import type { ArgumentSlot } from '../types.js';
|
|
3
|
+
import type { Identify, NativeBlock, NativeField, NativeFieldClass, NativeScratchBlocks, NativeTarget, VMBlock } from './native-types.js';
|
|
4
|
+
export interface FieldBinding {
|
|
5
|
+
block: NativeBlock;
|
|
6
|
+
field: NativeField;
|
|
7
|
+
fieldName: string;
|
|
8
|
+
value: string;
|
|
9
|
+
vmBlock: VMBlock;
|
|
10
|
+
kind: 'text' | 'number' | 'menu' | 'color';
|
|
11
|
+
Class: NativeFieldClass;
|
|
12
|
+
prototype: object;
|
|
13
|
+
allowedValues: readonly string[] | null | undefined;
|
|
14
|
+
restoreValue: NativeField['setValue'];
|
|
15
|
+
rawState: PropertyState[];
|
|
16
|
+
restoreHandles(): void;
|
|
17
|
+
restoreDom(): void;
|
|
18
|
+
restoreState?: ReturnType<typeof colorState>;
|
|
19
|
+
}
|
|
20
|
+
interface Inspection {
|
|
21
|
+
slot: ArgumentSlot;
|
|
22
|
+
metadata: FixedInputMetadata;
|
|
23
|
+
signatureParts: unknown[];
|
|
24
|
+
binding?: FieldBinding;
|
|
25
|
+
}
|
|
26
|
+
type PropertyState = [name: string, descriptor: PropertyDescriptor | undefined];
|
|
1
27
|
/** Freeze native method identities once when the host attaches, before opening editors. */
|
|
2
|
-
export function initializeFixedFields(ScratchBlocks:
|
|
28
|
+
export declare function initializeFixedFields(ScratchBlocks: NativeScratchBlocks): void;
|
|
29
|
+
declare const colorState: (block: NativeBlock, field: NativeField) => {
|
|
30
|
+
colors: unknown[];
|
|
31
|
+
hsv: unknown[][];
|
|
32
|
+
blockProperties: PropertyState[];
|
|
33
|
+
};
|
|
3
34
|
/** Native objects stay local; only primitive metadata is returned in snapshots. */
|
|
4
|
-
export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, argument, role, identify, extensionId }: {
|
|
5
|
-
ScratchBlocks:
|
|
6
|
-
block:
|
|
7
|
-
vmBlock:
|
|
8
|
-
target:
|
|
9
|
-
argument:
|
|
10
|
-
role:
|
|
11
|
-
identify:
|
|
12
|
-
extensionId:
|
|
13
|
-
}):
|
|
14
|
-
slot: {
|
|
15
|
-
kind: string;
|
|
16
|
-
value: string | number | boolean;
|
|
17
|
-
} | {
|
|
18
|
-
kind: string;
|
|
19
|
-
value?: never;
|
|
20
|
-
};
|
|
21
|
-
metadata: {
|
|
22
|
-
role: any;
|
|
23
|
-
source: any;
|
|
24
|
-
identity: string;
|
|
25
|
-
reason: any;
|
|
26
|
-
};
|
|
27
|
-
signatureParts: any[];
|
|
28
|
-
} | {
|
|
29
|
-
slot: {
|
|
30
|
-
kind: string;
|
|
31
|
-
value?: never;
|
|
32
|
-
};
|
|
33
|
-
metadata: {
|
|
34
|
-
role: any;
|
|
35
|
-
source: string;
|
|
36
|
-
identity: string;
|
|
37
|
-
field?: never;
|
|
38
|
-
};
|
|
39
|
-
signatureParts: any[];
|
|
40
|
-
} | {
|
|
41
|
-
signatureParts: any[];
|
|
42
|
-
binding?: {
|
|
43
|
-
restoreState?: {
|
|
44
|
-
colors: any[];
|
|
45
|
-
hsv: any[][];
|
|
46
|
-
blockProperties: any;
|
|
47
|
-
};
|
|
48
|
-
block: any;
|
|
49
|
-
field: any;
|
|
50
|
-
fieldName: any;
|
|
51
|
-
value: string;
|
|
52
|
-
vmBlock: any;
|
|
53
|
-
kind: string;
|
|
54
|
-
Class: any;
|
|
55
|
-
prototype: any;
|
|
56
|
-
allowedValues: readonly string[] | null | undefined;
|
|
57
|
-
restoreValue: any;
|
|
58
|
-
rawState: any;
|
|
59
|
-
restoreHandles: any;
|
|
60
|
-
restoreDom: any;
|
|
61
|
-
};
|
|
62
|
-
slot: {
|
|
63
|
-
kind: string;
|
|
64
|
-
value: string | number;
|
|
65
|
-
};
|
|
66
|
-
metadata: {
|
|
67
|
-
role: any;
|
|
68
|
-
source: string;
|
|
69
|
-
identity: string;
|
|
70
|
-
field: {
|
|
71
|
-
blockId: any;
|
|
72
|
-
name: any;
|
|
73
|
-
type: string | undefined;
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
} | null;
|
|
35
|
+
export declare function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, argument, role, identify, extensionId }: {
|
|
36
|
+
ScratchBlocks: NativeScratchBlocks;
|
|
37
|
+
block: NativeBlock;
|
|
38
|
+
vmBlock: VMBlock;
|
|
39
|
+
target: NativeTarget;
|
|
40
|
+
argument: string;
|
|
41
|
+
role: FixedInputMetadata['role'];
|
|
42
|
+
identify: Identify;
|
|
43
|
+
extensionId: string;
|
|
44
|
+
}): Inspection | null;
|
|
77
45
|
/** Validate the exact saved primitive; native setters must not silently normalize it. */
|
|
78
|
-
export function prepareFixedChange(binding:
|
|
46
|
+
export declare function prepareFixedChange(binding: FieldBinding, value: unknown): {
|
|
47
|
+
next: string;
|
|
48
|
+
block: NativeBlock;
|
|
49
|
+
field: NativeField;
|
|
50
|
+
fieldName: string;
|
|
51
|
+
value: string;
|
|
52
|
+
vmBlock: VMBlock;
|
|
53
|
+
kind: "text" | "number" | "menu" | "color";
|
|
54
|
+
Class: NativeFieldClass;
|
|
55
|
+
prototype: object;
|
|
56
|
+
allowedValues: readonly string[] | null | undefined;
|
|
57
|
+
restoreValue: NativeField["setValue"];
|
|
58
|
+
rawState: PropertyState[];
|
|
59
|
+
restoreHandles(): void;
|
|
60
|
+
restoreDom(): void;
|
|
61
|
+
restoreState?: ReturnType<typeof colorState>;
|
|
62
|
+
};
|
|
79
63
|
/** Capture a later external value without invoking replacement field methods. */
|
|
80
|
-
export function captureFixedFieldState(binding:
|
|
64
|
+
export declare function captureFixedFieldState(binding: FieldBinding): FieldBinding;
|
|
81
65
|
/** Restore raw text and the standard color field's additional block/UI state. */
|
|
82
|
-
export function restoreFixedField(binding:
|
|
66
|
+
export declare function restoreFixedField(binding: FieldBinding): void;
|
|
67
|
+
export {};
|
|
@@ -3,7 +3,7 @@ const own = (object, key) => {
|
|
|
3
3
|
const descriptor = object && Object.getOwnPropertyDescriptor(object, key);
|
|
4
4
|
return descriptor && 'value' in descriptor ? descriptor.value : undefined;
|
|
5
5
|
};
|
|
6
|
-
const primitive = value => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
6
|
+
const primitive = (value) => typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
|
|
7
7
|
const token = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$/u;
|
|
8
8
|
// Inspect data properties without invoking custom field accessors or menu providers.
|
|
9
9
|
const inherited = (object, name) => {
|
|
@@ -41,7 +41,7 @@ const safeField = (field, Class) => {
|
|
|
41
41
|
if (currentPrototype !== entry.prototype)
|
|
42
42
|
return false;
|
|
43
43
|
for (const [name, expected] of entry.own) {
|
|
44
|
-
const actual = Object.getOwnPropertyDescriptor(
|
|
44
|
+
const actual = Object.getOwnPropertyDescriptor(entry.prototype, name);
|
|
45
45
|
if (Boolean(actual) !== Boolean(expected) ||
|
|
46
46
|
(actual && (!('value' in actual) || !expected || !('value' in expected) || actual.value !== expected.value)))
|
|
47
47
|
return false;
|
|
@@ -71,7 +71,7 @@ const safeField = (field, Class) => {
|
|
|
71
71
|
}
|
|
72
72
|
return false;
|
|
73
73
|
};
|
|
74
|
-
const arrayData = value => {
|
|
74
|
+
const arrayData = (value) => {
|
|
75
75
|
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
|
|
76
76
|
return null;
|
|
77
77
|
const result = [];
|
|
@@ -83,7 +83,7 @@ const arrayData = value => {
|
|
|
83
83
|
}
|
|
84
84
|
return result;
|
|
85
85
|
};
|
|
86
|
-
const staticValues = field => {
|
|
86
|
+
const staticValues = (field) => {
|
|
87
87
|
const items = arrayData(own(field, 'menuGenerator_'));
|
|
88
88
|
if (!items || items.length === 0)
|
|
89
89
|
return null;
|
|
@@ -156,7 +156,7 @@ export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, ar
|
|
|
156
156
|
return { slot: { kind: 'reporter' }, metadata: { role, source: 'reporter', identity: JSON.stringify(sourceIdentity) },
|
|
157
157
|
signatureParts: sourceIdentity };
|
|
158
158
|
}
|
|
159
|
-
|
|
159
|
+
const owner = direct ? block : connected;
|
|
160
160
|
if (!owner) {
|
|
161
161
|
if (vmBlock.fields && owns(vmBlock.fields, argument))
|
|
162
162
|
return null;
|
|
@@ -204,7 +204,7 @@ export function inspectFixedArgument({ ScratchBlocks, block, vmBlock, target, ar
|
|
|
204
204
|
}
|
|
205
205
|
if (names.length !== 1)
|
|
206
206
|
return unavailable('unsupported', 'The menu shadow does not have one standard field.');
|
|
207
|
-
|
|
207
|
+
name = names[0];
|
|
208
208
|
}
|
|
209
209
|
else
|
|
210
210
|
return unavailable('unsupported', 'The shadow field family is unsupported.');
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import type { FixedInputEditorHost } from '../fixed-input-types.js';
|
|
2
|
+
import type { EditorRegistry } from '../registry.js';
|
|
3
|
+
import type { Identify, NativeChange, NativeScratchBlocks, NativeVM, NativeWorkspace } from './native-types.js';
|
|
4
|
+
interface FixedPortOptions {
|
|
5
|
+
ScratchBlocks: NativeScratchBlocks;
|
|
6
|
+
workspace: NativeWorkspace;
|
|
7
|
+
vm: NativeVM;
|
|
8
|
+
registry: EditorRegistry;
|
|
9
|
+
identify: Identify;
|
|
10
|
+
getState(): {
|
|
11
|
+
disposed: boolean;
|
|
12
|
+
revision: number;
|
|
13
|
+
generation: number;
|
|
14
|
+
externalRevision: number;
|
|
15
|
+
};
|
|
16
|
+
begin(): void;
|
|
17
|
+
markEvent(event: NativeChange): void;
|
|
18
|
+
finish(succeeded: boolean): void;
|
|
19
|
+
onError(error: unknown): void;
|
|
20
|
+
subscribeScope(listener: () => void): () => void;
|
|
21
|
+
}
|
|
22
|
+
export default function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }: FixedPortOptions): FixedInputEditorHost;
|
|
23
|
+
export {};
|
|
@@ -4,7 +4,7 @@ import { initializeFixedFields, inspectFixedArgument, prepareFixedChange, restor
|
|
|
4
4
|
import { snapshotJson } from '../schema-json.js';
|
|
5
5
|
import { validateFixedBranchChanges } from '../fixed-input-branches.js';
|
|
6
6
|
const own = (object, name) => {
|
|
7
|
-
const descriptor = object
|
|
7
|
+
const descriptor = object ? Object.getOwnPropertyDescriptor(object, name) : undefined;
|
|
8
8
|
if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
9
9
|
throw new TypeError('Expected an own data property.');
|
|
10
10
|
}
|
|
@@ -21,9 +21,10 @@ const inheritedData = (object, key) => {
|
|
|
21
21
|
}
|
|
22
22
|
return undefined;
|
|
23
23
|
};
|
|
24
|
-
const ensureNativeHistory = stack => {
|
|
24
|
+
const ensureNativeHistory = (stack) => {
|
|
25
|
+
var _a;
|
|
25
26
|
if (!Array.isArray(stack) || !Object.isExtensible(stack) ||
|
|
26
|
-
Object.getOwnPropertySymbols(stack).length || !Object.getOwnPropertyDescriptor(stack, 'length').writable) {
|
|
27
|
+
Object.getOwnPropertySymbols(stack).length || !((_a = Object.getOwnPropertyDescriptor(stack, 'length')) === null || _a === void 0 ? void 0 : _a.writable)) {
|
|
27
28
|
throw new TypeError('Unsupported undo history.');
|
|
28
29
|
}
|
|
29
30
|
if (Object.getOwnPropertyNames(stack).length !== stack.length + 1)
|
|
@@ -35,7 +36,7 @@ const ensureNativeHistory = stack => {
|
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
};
|
|
38
|
-
const copyHistory = stack => {
|
|
39
|
+
const copyHistory = (stack) => {
|
|
39
40
|
const copy = [];
|
|
40
41
|
for (let index = 0; index < stack.length; index++)
|
|
41
42
|
copy.push(own(stack, String(index)));
|
|
@@ -46,11 +47,11 @@ const replaceHistory = (stack, values) => {
|
|
|
46
47
|
for (const value of values)
|
|
47
48
|
Array.prototype.push.call(stack, value);
|
|
48
49
|
};
|
|
49
|
-
|
|
50
|
+
function conflict() { throw new BlockEditorConflictError(); }
|
|
50
51
|
const aborted = Object.getOwnPropertyDescriptor(AbortSignal.prototype, 'aborted').get;
|
|
51
|
-
const isAborted = signal => aborted.call(signal);
|
|
52
|
+
const isAborted = (signal) => aborted.call(signal);
|
|
52
53
|
const optionalOwn = (object, name) => {
|
|
53
|
-
const descriptor = object
|
|
54
|
+
const descriptor = object ? Object.getOwnPropertyDescriptor(object, name) : undefined;
|
|
54
55
|
if (descriptor && !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
55
56
|
throw new TypeError('VM state must contain data properties.');
|
|
56
57
|
}
|
|
@@ -79,7 +80,7 @@ const untouchedState = (block, vmBlock, target, bindings, identify) => {
|
|
|
79
80
|
}
|
|
80
81
|
const seen = new Set();
|
|
81
82
|
const records = [];
|
|
82
|
-
const capture = item => {
|
|
83
|
+
const capture = (item) => {
|
|
83
84
|
if (!item || seen.has(item))
|
|
84
85
|
return;
|
|
85
86
|
seen.add(item);
|
|
@@ -112,8 +113,7 @@ const untouchedState = (block, vmBlock, target, bindings, identify) => {
|
|
|
112
113
|
});
|
|
113
114
|
return JSON.stringify([records, connections, statementConnections]);
|
|
114
115
|
};
|
|
115
|
-
const sameDeclaration = (left, right) => JSON.stringify(captureFixedInputDeclaration(left)) ===
|
|
116
|
-
JSON.stringify(captureFixedInputDeclaration(right));
|
|
116
|
+
const sameDeclaration = (left, right) => JSON.stringify(captureFixedInputDeclaration(left)) === JSON.stringify(captureFixedInputDeclaration(right));
|
|
117
117
|
// Fixed inputs deliberately use a separate transaction from the legacy TEXT adapter.
|
|
118
118
|
export default function createFixedInputPort({ ScratchBlocks, workspace, vm, registry, identify, getState, begin, markEvent, finish, onError, subscribeScope }) {
|
|
119
119
|
initializeFixedFields(ScratchBlocks);
|
|
@@ -162,7 +162,7 @@ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, reg
|
|
|
162
162
|
} }, reference, declaration);
|
|
163
163
|
return { snapshot, bindings, declaration, target, block, vmBlock, state, untouched, runtime: vm.runtime };
|
|
164
164
|
};
|
|
165
|
-
const commit = request => {
|
|
165
|
+
const commit = (request) => {
|
|
166
166
|
var _a;
|
|
167
167
|
const expectedInput = own(request, 'expected');
|
|
168
168
|
const changesInput = own(request, 'changes');
|
|
@@ -238,7 +238,7 @@ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, reg
|
|
|
238
238
|
ensureNativeHistory(redoStack);
|
|
239
239
|
const configuredMaxUndo = inheritedData(workspace, 'MAX_UNDO');
|
|
240
240
|
const maxUndo = configuredMaxUndo === undefined ? Infinity : configuredMaxUndo;
|
|
241
|
-
if (maxUndo !== Infinity && (!Number.isSafeInteger(maxUndo) || maxUndo < 0)) {
|
|
241
|
+
if (typeof maxUndo !== 'number' || (maxUndo !== Infinity && (!Number.isSafeInteger(maxUndo) || maxUndo < 0))) {
|
|
242
242
|
throw new TypeError('Unsupported undo configuration.');
|
|
243
243
|
}
|
|
244
244
|
const undo = copyHistory(undoStack);
|
|
@@ -290,7 +290,7 @@ export default function createFixedInputPort({ ScratchBlocks, workspace, vm, reg
|
|
|
290
290
|
const fields = edited.vmBlock.fields;
|
|
291
291
|
const field = fields && fields[edited.fieldName];
|
|
292
292
|
externalWrites.set(edited.field, { binding: captureFixedFieldState(edited),
|
|
293
|
-
|
|
293
|
+
field, descriptors: field && Object.getOwnPropertyDescriptors(field) });
|
|
294
294
|
}
|
|
295
295
|
activeEvent = previous;
|
|
296
296
|
}
|
package/dist/turbowarp/host.d.ts
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
|
+
import type { TurboWarpHostOptions, TurboWarpBlockEditorHost } from '../turbowarp.js';
|
|
2
|
+
declare const createBlockEditorHost: ({ ScratchBlocks: nativeBlocks, workspace: nativeWorkspace, vm: nativeVM, registry, enableDescendants, enableFixedInputs, onError }: TurboWarpHostOptions) => TurboWarpBlockEditorHost;
|
|
1
3
|
export default createBlockEditorHost;
|
|
2
|
-
declare function createBlockEditorHost({ ScratchBlocks, workspace, vm, registry, enableDescendants, enableFixedInputs, onError }: {
|
|
3
|
-
ScratchBlocks: any;
|
|
4
|
-
workspace: any;
|
|
5
|
-
vm: any;
|
|
6
|
-
registry: any;
|
|
7
|
-
enableDescendants?: boolean | undefined;
|
|
8
|
-
enableFixedInputs?: boolean | undefined;
|
|
9
|
-
onError?: ((...data: any[]) => void) | undefined;
|
|
10
|
-
}): {
|
|
11
|
-
isCommitting: () => boolean;
|
|
12
|
-
readBlock: (reference: any) => any;
|
|
13
|
-
commit: ({ expected, changes }: {
|
|
14
|
-
expected: any;
|
|
15
|
-
changes: any;
|
|
16
|
-
}) => void;
|
|
17
|
-
invalidate: () => void;
|
|
18
|
-
dispose: () => void;
|
|
19
|
-
};
|
package/dist/turbowarp/host.js
CHANGED
|
@@ -3,7 +3,10 @@ import collectBlockEditorSubtree from './subtree.js';
|
|
|
3
3
|
import createFixedInputPort from './fixed-transaction.js';
|
|
4
4
|
const owns = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
5
5
|
// Adapt only standard, unvalidated text shadows; never evaluate connected reporters.
|
|
6
|
-
const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableDescendants = false, enableFixedInputs = false, onError = console.error }) => {
|
|
6
|
+
const createBlockEditorHost = ({ ScratchBlocks: nativeBlocks, workspace: nativeWorkspace, vm: nativeVM, registry, enableDescendants = false, enableFixedInputs = false, onError = console.error }) => {
|
|
7
|
+
const ScratchBlocks = nativeBlocks;
|
|
8
|
+
const workspace = nativeWorkspace;
|
|
9
|
+
const vm = nativeVM;
|
|
7
10
|
let disposed = false;
|
|
8
11
|
let committing = false;
|
|
9
12
|
let revision = 0;
|
|
@@ -30,12 +33,12 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
30
33
|
};
|
|
31
34
|
let notifyInvalidations = () => { };
|
|
32
35
|
const identities = new WeakMap();
|
|
33
|
-
const identify = object => {
|
|
36
|
+
const identify = (object) => {
|
|
34
37
|
if (!identities.has(object))
|
|
35
38
|
identities.set(object, ++identity);
|
|
36
39
|
return identities.get(object);
|
|
37
40
|
};
|
|
38
|
-
const invalidate = event => {
|
|
41
|
+
const invalidate = (event) => {
|
|
39
42
|
if (event && event.isUiEvent)
|
|
40
43
|
return;
|
|
41
44
|
revision++;
|
|
@@ -163,7 +166,7 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
163
166
|
vmBlock
|
|
164
167
|
};
|
|
165
168
|
};
|
|
166
|
-
const collect = reference => collectBlockEditorSubtree({ ScratchBlocks, reference, inspect, generation });
|
|
169
|
+
const collect = (reference) => collectBlockEditorSubtree({ ScratchBlocks, reference, inspect, generation });
|
|
167
170
|
notifyInvalidations = () => {
|
|
168
171
|
if (committing)
|
|
169
172
|
return;
|
|
@@ -171,7 +174,7 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
171
174
|
let matches = false;
|
|
172
175
|
try {
|
|
173
176
|
const current = collect(item.reference);
|
|
174
|
-
matches = current && JSON.stringify(current.snapshot) === JSON.stringify(item.snapshot);
|
|
177
|
+
matches = current !== null && JSON.stringify(current.snapshot) === JSON.stringify(item.snapshot);
|
|
175
178
|
}
|
|
176
179
|
catch (error) {
|
|
177
180
|
// A malformed replacement graph invalidates an already open session too.
|
|
@@ -201,7 +204,7 @@ const createBlockEditorHost = ({ ScratchBlocks, workspace, vm, registry, enableD
|
|
|
201
204
|
Events.disable();
|
|
202
205
|
committing = true;
|
|
203
206
|
try {
|
|
204
|
-
if (signal && signal.aborted)
|
|
207
|
+
if (!target || (signal && signal.aborted))
|
|
205
208
|
throw new BlockEditorConflictError();
|
|
206
209
|
for (const item of prepared) {
|
|
207
210
|
item.field.setValue(item.next);
|
package/dist/turbowarp/icon.d.ts
CHANGED
|
@@ -1,9 +1,2 @@
|
|
|
1
|
+
declare const bindBlockEditorIcon: ({ element, label, canOpen, onOpen, onHover, onLeave }: Parameters<typeof import("../turbowarp.js").bindBlockEditorIcon>[0]) => () => void;
|
|
1
2
|
export default bindBlockEditorIcon;
|
|
2
|
-
declare function bindBlockEditorIcon({ element, label, canOpen, onOpen, onHover, onLeave }: {
|
|
3
|
-
element: any;
|
|
4
|
-
label: any;
|
|
5
|
-
canOpen: any;
|
|
6
|
-
onOpen: any;
|
|
7
|
-
onHover?: (() => void) | undefined;
|
|
8
|
-
onLeave?: (() => void) | undefined;
|
|
9
|
-
}): () => void;
|
package/dist/turbowarp/icon.js
CHANGED
|
@@ -4,13 +4,13 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
|
|
|
4
4
|
const previous = attributes.map(name => element.getAttribute(name));
|
|
5
5
|
const oldCursor = element.style.cursor;
|
|
6
6
|
let press = null;
|
|
7
|
-
const stop = event => {
|
|
7
|
+
const stop = (event) => {
|
|
8
8
|
if (!canOpen())
|
|
9
9
|
return;
|
|
10
10
|
event.stopPropagation();
|
|
11
11
|
event.preventDefault();
|
|
12
12
|
};
|
|
13
|
-
const down = event => {
|
|
13
|
+
const down = (event) => {
|
|
14
14
|
if (!canOpen() || event.button !== 0 || event.isPrimary === false)
|
|
15
15
|
return;
|
|
16
16
|
stop(event);
|
|
@@ -19,14 +19,14 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
|
|
|
19
19
|
if (element.setPointerCapture)
|
|
20
20
|
element.setPointerCapture(event.pointerId);
|
|
21
21
|
};
|
|
22
|
-
const move = event => {
|
|
22
|
+
const move = (event) => {
|
|
23
23
|
if (!press || press.id !== event.pointerId)
|
|
24
24
|
return;
|
|
25
25
|
stop(event);
|
|
26
26
|
if (Math.hypot(event.clientX - press.x, event.clientY - press.y) > 4)
|
|
27
27
|
press.moved = true;
|
|
28
28
|
};
|
|
29
|
-
const up = event => {
|
|
29
|
+
const up = (event) => {
|
|
30
30
|
if (!press || press.id !== event.pointerId)
|
|
31
31
|
return;
|
|
32
32
|
move(event);
|
|
@@ -41,7 +41,7 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
|
|
|
41
41
|
const cancel = () => {
|
|
42
42
|
press = null;
|
|
43
43
|
};
|
|
44
|
-
const key = event => {
|
|
44
|
+
const key = (event) => {
|
|
45
45
|
if ((event.key === 'Enter' || event.key === ' ') && canOpen()) {
|
|
46
46
|
stop(event);
|
|
47
47
|
if (!event.repeat)
|
|
@@ -68,7 +68,7 @@ const bindBlockEditorIcon = ({ element, label, canOpen, onOpen, onHover = () =>
|
|
|
68
68
|
for (const [type, listener] of listeners)
|
|
69
69
|
element.removeEventListener(type, listener);
|
|
70
70
|
attributes.forEach((name, index) => {
|
|
71
|
-
if (previous[index]
|
|
71
|
+
if (previous[index] == null)
|
|
72
72
|
element.removeAttribute(name);
|
|
73
73
|
else
|
|
74
74
|
element.setAttribute(name, previous[index]);
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { BlockSnapshot } from '../types.js';
|
|
2
|
+
export interface NativeField {
|
|
3
|
+
name?: string;
|
|
4
|
+
getValue(): unknown;
|
|
5
|
+
getText(): string;
|
|
6
|
+
setValue(value: string): void;
|
|
7
|
+
getValidator(): unknown;
|
|
8
|
+
}
|
|
9
|
+
interface ImageField extends NativeField {
|
|
10
|
+
fieldGroup_: SVGElement;
|
|
11
|
+
imageElement_: {
|
|
12
|
+
tooltip: unknown;
|
|
13
|
+
};
|
|
14
|
+
setTooltip(label: string): void;
|
|
15
|
+
}
|
|
16
|
+
export interface NativeFieldClass {
|
|
17
|
+
new (...args: never[]): NativeField;
|
|
18
|
+
prototype: NativeField;
|
|
19
|
+
}
|
|
20
|
+
interface Connection {
|
|
21
|
+
targetConnection: Connection | null;
|
|
22
|
+
targetBlock(): NativeBlock | null;
|
|
23
|
+
}
|
|
24
|
+
export interface NativeBlock {
|
|
25
|
+
id: string;
|
|
26
|
+
type: string;
|
|
27
|
+
isInFlyout?: boolean;
|
|
28
|
+
inputList: Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
type: number;
|
|
31
|
+
fieldRow: NativeField[];
|
|
32
|
+
connection: Connection | null;
|
|
33
|
+
}>;
|
|
34
|
+
previousConnection: Connection | null;
|
|
35
|
+
nextConnection: Connection | null;
|
|
36
|
+
outputConnection: Connection | null;
|
|
37
|
+
isShadow(): boolean;
|
|
38
|
+
isEditable(): boolean;
|
|
39
|
+
getInput(name: string): NativeBlock['inputList'][number] | null;
|
|
40
|
+
getField(name: string): NativeField | null;
|
|
41
|
+
getParent(): NativeBlock | null;
|
|
42
|
+
getNextBlock(): NativeBlock | null;
|
|
43
|
+
getColour(): unknown;
|
|
44
|
+
getColourSecondary(): unknown;
|
|
45
|
+
getColourTertiary(): unknown;
|
|
46
|
+
getColourQuaternary(): unknown;
|
|
47
|
+
setColour(...colors: string[]): void;
|
|
48
|
+
}
|
|
49
|
+
export interface NativeChange {
|
|
50
|
+
type: string;
|
|
51
|
+
element?: string;
|
|
52
|
+
name?: string;
|
|
53
|
+
blockId?: string;
|
|
54
|
+
ids?: string[];
|
|
55
|
+
isUiEvent?: boolean;
|
|
56
|
+
oldValue?: unknown;
|
|
57
|
+
recordUndo: boolean;
|
|
58
|
+
}
|
|
59
|
+
export interface NativeScratchBlocks {
|
|
60
|
+
INPUT_VALUE: number;
|
|
61
|
+
NEXT_STATEMENT: number;
|
|
62
|
+
FieldImage: new (...args: never[]) => ImageField;
|
|
63
|
+
FieldTextInput: NativeFieldClass;
|
|
64
|
+
FieldNumber: NativeFieldClass;
|
|
65
|
+
FieldDropdown: NativeFieldClass;
|
|
66
|
+
FieldColourSlider: NativeFieldClass;
|
|
67
|
+
hideChaff(): void;
|
|
68
|
+
Events: {
|
|
69
|
+
Change: new (block: NativeBlock, element: string, name: string, before: string, after: string) => NativeChange;
|
|
70
|
+
recordUndo: boolean;
|
|
71
|
+
isEnabled(): boolean;
|
|
72
|
+
getGroup(): string | boolean;
|
|
73
|
+
setGroup(group: string | boolean): void;
|
|
74
|
+
disable(): void;
|
|
75
|
+
enable(): void;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export interface NativeWorkspace {
|
|
79
|
+
isFlyout?: boolean;
|
|
80
|
+
options: {
|
|
81
|
+
readOnly?: boolean;
|
|
82
|
+
};
|
|
83
|
+
isDragging?(): boolean;
|
|
84
|
+
getBlockById(id: string): NativeBlock | null;
|
|
85
|
+
getAllBlocks(ordered: boolean): NativeBlock[];
|
|
86
|
+
addChangeListener(listener: (event: NativeChange) => void): void;
|
|
87
|
+
removeChangeListener(listener: (event: NativeChange) => void): void;
|
|
88
|
+
undoStack_: NativeChange[];
|
|
89
|
+
redoStack_: NativeChange[];
|
|
90
|
+
fireChangeListener(event: NativeChange): void;
|
|
91
|
+
}
|
|
92
|
+
export interface VMField {
|
|
93
|
+
[name: string]: unknown;
|
|
94
|
+
id?: string;
|
|
95
|
+
value: unknown;
|
|
96
|
+
}
|
|
97
|
+
export interface VMBlock {
|
|
98
|
+
opcode: string;
|
|
99
|
+
parent?: string | null;
|
|
100
|
+
next?: string | null;
|
|
101
|
+
fields: Record<string, VMField>;
|
|
102
|
+
inputs: Record<string, {
|
|
103
|
+
block?: string;
|
|
104
|
+
shadow?: string;
|
|
105
|
+
}>;
|
|
106
|
+
mutation?: unknown;
|
|
107
|
+
}
|
|
108
|
+
export interface NativeTarget {
|
|
109
|
+
id: string;
|
|
110
|
+
blocks: {
|
|
111
|
+
getBlock(id: string): VMBlock | null;
|
|
112
|
+
blocklyListen(event: NativeChange): void;
|
|
113
|
+
resetCache?(): void;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export interface NativeVM {
|
|
117
|
+
editingTarget: NativeTarget | null;
|
|
118
|
+
runtime: {
|
|
119
|
+
emitProjectChanged(): void;
|
|
120
|
+
};
|
|
121
|
+
on(name: string, listener: () => void): void;
|
|
122
|
+
removeListener(name: string, listener: () => void): void;
|
|
123
|
+
}
|
|
124
|
+
export interface TextBinding {
|
|
125
|
+
shadow: NativeBlock;
|
|
126
|
+
field: NativeField;
|
|
127
|
+
value: string;
|
|
128
|
+
}
|
|
129
|
+
export interface BlockRecord {
|
|
130
|
+
block: NativeBlock;
|
|
131
|
+
vmBlock: VMBlock;
|
|
132
|
+
fields: Map<string, TextBinding>;
|
|
133
|
+
snapshot: BlockSnapshot;
|
|
134
|
+
}
|
|
135
|
+
export type Identify = (value: object) => number;
|
|
136
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import type { SubtreeSnapshot } from '../descendant-types.js';
|
|
2
|
+
import type { BlockReference } from '../types.js';
|
|
3
|
+
import type { BlockRecord, NativeScratchBlocks } from './native-types.js';
|
|
4
|
+
declare const collectBlockEditorSubtree: ({ ScratchBlocks, reference, inspect, generation }: {
|
|
5
|
+
ScratchBlocks: NativeScratchBlocks;
|
|
6
|
+
reference: BlockReference;
|
|
7
|
+
inspect(reference: BlockReference, structural: boolean): BlockRecord | null;
|
|
8
|
+
generation: number;
|
|
9
|
+
}) => {
|
|
10
|
+
snapshot: SubtreeSnapshot;
|
|
11
|
+
records: Map<string, BlockRecord>;
|
|
10
12
|
} | null;
|
|
13
|
+
export default collectBlockEditorSubtree;
|
|
@@ -4,9 +4,10 @@ const collectBlockEditorSubtree = ({ ScratchBlocks, reference, inspect, generati
|
|
|
4
4
|
const nodes = [];
|
|
5
5
|
const records = new Map();
|
|
6
6
|
const pending = {};
|
|
7
|
-
|
|
7
|
+
function invalid(message) {
|
|
8
8
|
throw new BlockEditorStructureError(message, 'invalid-structure');
|
|
9
|
-
}
|
|
9
|
+
}
|
|
10
|
+
;
|
|
10
11
|
const visit = (id, depth) => {
|
|
11
12
|
if (records.has(id)) {
|
|
12
13
|
throw new BlockEditorStructureError('A statement block is connected more than once.', 'cycle');
|