@rasamjs/core 0.2.0 → 0.3.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/API.md +14 -4
- package/CHANGELOG.md +59 -0
- package/COMPONENTS.md +229 -0
- package/README.md +39 -6
- package/RELEASING.md +4 -2
- package/dist/advanced.d.ts +1 -1
- package/dist/advanced.d.ts.map +1 -1
- package/dist/catalog/fragment.d.ts +2 -2
- package/dist/catalog/fragment.d.ts.map +1 -1
- package/dist/catalog/fragment.js.map +1 -1
- package/dist/changes/derived.d.ts +10 -0
- package/dist/changes/derived.d.ts.map +1 -0
- package/dist/changes/derived.js +14 -0
- package/dist/changes/derived.js.map +1 -0
- package/dist/changes/restore.d.ts.map +1 -1
- package/dist/changes/restore.js +22 -4
- package/dist/changes/restore.js.map +1 -1
- package/dist/changes/service.d.ts +5 -0
- package/dist/changes/service.d.ts.map +1 -1
- package/dist/changes/service.js +16 -2
- package/dist/changes/service.js.map +1 -1
- package/dist/components/changes.d.ts +34 -0
- package/dist/components/changes.d.ts.map +1 -0
- package/dist/components/changes.js +119 -0
- package/dist/components/changes.js.map +1 -0
- package/dist/components/component.d.ts +62 -0
- package/dist/components/component.d.ts.map +1 -0
- package/dist/components/component.js +355 -0
- package/dist/components/component.js.map +1 -0
- package/dist/components/decorators.d.ts +7 -0
- package/dist/components/decorators.d.ts.map +1 -0
- package/dist/components/decorators.js +81 -0
- package/dist/components/decorators.js.map +1 -0
- package/dist/components/metadata.d.ts +10 -0
- package/dist/components/metadata.d.ts.map +1 -0
- package/dist/components/metadata.js +85 -0
- package/dist/components/metadata.js.map +1 -0
- package/dist/components/registry.d.ts +24 -0
- package/dist/components/registry.d.ts.map +1 -0
- package/dist/components/registry.js +78 -0
- package/dist/components/registry.js.map +1 -0
- package/dist/components/types.d.ts +54 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/components/types.js +2 -0
- package/dist/components/types.js.map +1 -0
- package/dist/components/view.d.ts +9 -0
- package/dist/components/view.d.ts.map +1 -0
- package/dist/components/view.js +104 -0
- package/dist/components/view.js.map +1 -0
- package/dist/components.d.ts +6 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +5 -0
- package/dist/components.js.map +1 -0
- package/dist/core/node.d.ts +7 -0
- package/dist/core/node.d.ts.map +1 -1
- package/dist/core/node.js +30 -0
- package/dist/core/node.js.map +1 -1
- package/dist/interchange/clone.d.ts.map +1 -1
- package/dist/interchange/clone.js +3 -2
- package/dist/interchange/clone.js.map +1 -1
- package/dist/interchange/reconstruct.d.ts.map +1 -1
- package/dist/interchange/reconstruct.js +16 -12
- package/dist/interchange/reconstruct.js.map +1 -1
- package/dist/interchange/references.d.ts.map +1 -1
- package/dist/interchange/references.js +10 -4
- package/dist/interchange/references.js.map +1 -1
- package/dist/mixins/parent-internals.d.ts +6 -0
- package/dist/mixins/parent-internals.d.ts.map +1 -1
- package/dist/mixins/parent-internals.js +34 -0
- package/dist/mixins/parent-internals.js.map +1 -1
- package/dist/mixins/parent.d.ts.map +1 -1
- package/dist/mixins/parent.js +6 -1
- package/dist/mixins/parent.js.map +1 -1
- package/dist/mixins/types.d.ts +2 -2
- package/dist/mixins/types.d.ts.map +1 -1
- package/dist/resources/references.d.ts +2 -0
- package/dist/resources/references.d.ts.map +1 -1
- package/dist/resources/references.js +3 -3
- package/dist/resources/references.js.map +1 -1
- package/dist/services/catalog.d.ts.map +1 -1
- package/dist/services/catalog.js +5 -3
- package/dist/services/catalog.js.map +1 -1
- package/dist/services/defs-manager.d.ts +2 -0
- package/dist/services/defs-manager.d.ts.map +1 -1
- package/dist/services/defs-manager.js +4 -0
- package/dist/services/defs-manager.js.map +1 -1
- package/dist/services/element-key.d.ts +4 -0
- package/dist/services/element-key.d.ts.map +1 -0
- package/dist/services/element-key.js +12 -0
- package/dist/services/element-key.js.map +1 -0
- package/dist/services/initialization.d.ts +7 -0
- package/dist/services/initialization.d.ts.map +1 -0
- package/dist/services/initialization.js +27 -0
- package/dist/services/initialization.js.map +1 -0
- package/dist/services/registry.d.ts +8 -0
- package/dist/services/registry.d.ts.map +1 -1
- package/dist/services/registry.js +45 -10
- package/dist/services/registry.js.map +1 -1
- package/dist/services/types.d.ts +17 -0
- package/dist/services/types.d.ts.map +1 -1
- package/dist/template/parts.d.ts +12 -6
- package/dist/template/parts.d.ts.map +1 -1
- package/dist/template/parts.js +36 -29
- package/dist/template/parts.js.map +1 -1
- package/dist/template/render.d.ts +6 -7
- package/dist/template/render.d.ts.map +1 -1
- package/dist/template/render.js +188 -44
- package/dist/template/render.js.map +1 -1
- package/dist/template/svg-tag.d.ts +5 -1
- package/dist/template/svg-tag.d.ts.map +1 -1
- package/dist/template/svg-tag.js.map +1 -1
- package/dist/text/internals.d.ts +1 -0
- package/dist/text/internals.d.ts.map +1 -1
- package/dist/types/common.d.ts +27 -0
- package/dist/types/common.d.ts.map +1 -1
- package/package.json +156 -148
- package/reports/adoption.json +20 -20
- package/reports/animation-benchmark.json +612 -612
- package/reports/benchmark.json +40 -40
- package/reports/components-benchmark-before.json +10 -0
- package/reports/components-benchmark.json +10 -0
- package/reports/creation.json +26 -26
- package/reports/interchange-benchmark.json +85 -85
- package/reports/public-api-contract.json +334 -17
- package/reports/size-components.json +102 -0
- package/reports/size-parity.json +47 -34
- package/reports/size.json +6 -4
- package/reports/svgjs-comparison.json +3100 -3100
- package/reports/svgjs-comparison.md +16 -16
- package/reports/svgjs-parity-current.json +135 -42
- package/src/advanced.ts +1 -1
- package/src/catalog/fragment.ts +2 -2
- package/src/changes/derived.ts +19 -0
- package/src/changes/restore.ts +27 -4
- package/src/changes/service.ts +21 -6
- package/src/components/changes.ts +131 -0
- package/src/components/component.ts +401 -0
- package/src/components/decorators.ts +104 -0
- package/src/components/metadata.ts +111 -0
- package/src/components/registry.ts +79 -0
- package/src/components/types.ts +66 -0
- package/src/components/view.ts +123 -0
- package/src/components.ts +15 -0
- package/src/core/node.ts +32 -1
- package/src/interchange/clone.ts +3 -2
- package/src/interchange/reconstruct.ts +16 -12
- package/src/interchange/references.ts +12 -4
- package/src/mixins/parent-internals.ts +37 -0
- package/src/mixins/parent.ts +13 -4
- package/src/mixins/types.ts +2 -2
- package/src/resources/references.ts +5 -5
- package/src/services/catalog.ts +5 -3
- package/src/services/defs-manager.ts +5 -0
- package/src/services/element-key.ts +14 -0
- package/src/services/initialization.ts +25 -0
- package/src/services/registry.ts +47 -10
- package/src/services/types.ts +21 -0
- package/src/template/parts.ts +54 -39
- package/src/template/render.ts +211 -54
- package/src/template/svg-tag.ts +6 -1
- package/src/text/internals.ts +1 -0
- package/src/types/common.ts +29 -0
package/src/template/render.ts
CHANGED
|
@@ -1,73 +1,180 @@
|
|
|
1
1
|
import { mutation } from '../changes/mutation.js';
|
|
2
2
|
import type { AnyNode } from '../core/types.js';
|
|
3
|
+
import { destroySubtrees } from '../core/destruction.js';
|
|
3
4
|
import type { ParentNode } from '../mixins/types.js';
|
|
4
5
|
import { Guards } from '../mixins/guards.js';
|
|
5
6
|
import { Group } from '../elements/group.js';
|
|
6
7
|
import type { Registry } from '../services/registry.js';
|
|
8
|
+
import type { ElementClass } from '../services/types.js';
|
|
7
9
|
import { BindingPart, TemplateCompiler } from './parts.js';
|
|
8
|
-
import type { TemplateDescription } from './parts.js';
|
|
9
|
-
import
|
|
10
|
+
import type { ContentItem, TemplateDescription } from './parts.js';
|
|
11
|
+
import { SvgTemplate } from './svg-tag.js';
|
|
12
|
+
import type { TemplateValue } from './svg-tag.js';
|
|
10
13
|
import { appendTextSlot, type TextBinding } from '../text/internals.js';
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
type Segment = AnyNode | ChildPart;
|
|
16
|
+
/** The nodes and child holes one template places in one parent, from index `base()`. */
|
|
17
|
+
interface Sequence {
|
|
18
|
+
parent: ParentNode;
|
|
19
|
+
readonly segments: Segment[];
|
|
20
|
+
base(): number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const size = (segments: readonly Segment[]) =>
|
|
24
|
+
segments.reduce((total, segment) => total + (segment instanceof ChildPart ? segment.size : 1), 0);
|
|
25
|
+
const flat = (segments: readonly Segment[]): AnyNode[] =>
|
|
26
|
+
segments.flatMap((segment) => (segment instanceof ChildPart ? segment.nodes : [segment]));
|
|
27
|
+
/** Semantic disposal: unlike `destroy()`, undo can restore it and history isn't cleared. */
|
|
28
|
+
const dispose = (nodes: readonly AnyNode[]) => {
|
|
29
|
+
const live = nodes.filter((node) => !node.isDestroyed);
|
|
30
|
+
if (live.length) live[0][destroySubtrees](live);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/** Flattens a child hole's value into templates. */
|
|
34
|
+
function templates(value: TemplateValue, out: SvgTemplate[] = []): SvgTemplate[] {
|
|
35
|
+
if (value instanceof SvgTemplate) out.push(value);
|
|
36
|
+
else if (typeof value == 'object' && value && Symbol.iterator in value)
|
|
37
|
+
for (const item of value) templates(item, out);
|
|
38
|
+
else if (value != null && typeof value != 'boolean' && value !== '')
|
|
39
|
+
throw new TypeError('Child bindings take templates, iterables of them, or null');
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Validates and builds an update without changing the drawing: new items are built in
|
|
45
|
+
* detached `stagings` groups. The returned commit applies it.
|
|
46
|
+
*/
|
|
47
|
+
type Prepare = (values: readonly TemplateValue[], stagings: Group[]) => () => void;
|
|
48
|
+
|
|
49
|
+
/** Prepares and commits, disposing the staging groups whether or not it succeeds. */
|
|
50
|
+
function commit(prepare: Prepare, values: readonly TemplateValue[]): void {
|
|
51
|
+
const stagings: Group[] = [];
|
|
52
|
+
try {
|
|
53
|
+
prepare(values, stagings)();
|
|
54
|
+
} finally {
|
|
55
|
+
dispose(stagings);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** A hole between elements: the items it renders, reused by index while their literal matches. */
|
|
60
|
+
class ChildPart {
|
|
61
|
+
private items: Mount[] = [];
|
|
62
|
+
constructor(
|
|
63
|
+
private readonly sequence: Sequence,
|
|
64
|
+
private readonly hole: number,
|
|
65
|
+
private readonly registry: Registry,
|
|
66
|
+
) {}
|
|
67
|
+
|
|
68
|
+
get size(): number {
|
|
69
|
+
return this.items.reduce((total, item) => total + item.size, 0);
|
|
70
|
+
}
|
|
71
|
+
get nodes(): AnyNode[] {
|
|
72
|
+
return this.items.flatMap((item) => item.nodes);
|
|
73
|
+
}
|
|
74
|
+
/** The index of this part's first node, or of `item`'s first node. */
|
|
75
|
+
private start(item?: Mount): number {
|
|
76
|
+
const { segments } = this.sequence;
|
|
77
|
+
let index = this.sequence.base() + size(segments.slice(0, segments.indexOf(this)));
|
|
78
|
+
for (const other of item ? this.items : []) {
|
|
79
|
+
if (other === item) break;
|
|
80
|
+
index += other.size;
|
|
81
|
+
}
|
|
82
|
+
return index;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
readonly prepare: Prepare = (values, stagings) => {
|
|
86
|
+
const parent = this.sequence.parent;
|
|
87
|
+
const forbidden = new Set<string>();
|
|
88
|
+
for (let node: AnyNode | null = parent; node; node = node.parent)
|
|
89
|
+
for (const tag of (node.constructor as ElementClass).forbiddenDescendantTags ?? [])
|
|
90
|
+
forbidden.add(tag);
|
|
91
|
+
const plans = templates(values[this.hole]).map((template, index) => {
|
|
92
|
+
const item = this.items[index];
|
|
93
|
+
if (item?.template.strings === template.strings)
|
|
94
|
+
return { item, commit: item.prepare(template.values, stagings) };
|
|
95
|
+
const content = TemplateCompiler.content(parent.context.dom, template.strings);
|
|
96
|
+
TemplateCompiler.validate(
|
|
97
|
+
content,
|
|
98
|
+
this.registry,
|
|
99
|
+
forbidden,
|
|
100
|
+
parent.constructor as ElementClass,
|
|
101
|
+
);
|
|
102
|
+
const staging = new Group(parent.context);
|
|
103
|
+
stagings.push(staging);
|
|
104
|
+
return { item: new Mount(template, staging, this.registry, content) };
|
|
105
|
+
});
|
|
106
|
+
return () => {
|
|
107
|
+
const items = plans.map((plan) => plan.item);
|
|
108
|
+
dispose(this.items.filter((item) => !items.includes(item)).flatMap((item) => item.nodes));
|
|
109
|
+
this.items = items;
|
|
110
|
+
for (const { item, commit } of plans)
|
|
111
|
+
if (!commit) {
|
|
112
|
+
// Detach first, so history records new nodes rather than a move from staging.
|
|
113
|
+
for (const node of item.nodes) parent.add(node.remove());
|
|
114
|
+
item.sequence.parent = parent;
|
|
115
|
+
item.sequence.base = () => this.start(item);
|
|
116
|
+
}
|
|
117
|
+
for (const plan of plans) plan.commit?.();
|
|
118
|
+
let index = this.start();
|
|
119
|
+
for (const node of this.nodes) parent.add(node, index++);
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** One template's nodes and parts, mounted as a sequence inside a parent. */
|
|
125
|
+
class Mount {
|
|
126
|
+
readonly sequence: Sequence;
|
|
127
|
+
private readonly parts: (BindingPart | ChildPart)[] = [];
|
|
16
128
|
|
|
17
129
|
constructor(
|
|
18
|
-
parent: ParentNode,
|
|
19
130
|
readonly template: SvgTemplate,
|
|
20
|
-
|
|
21
|
-
|
|
131
|
+
parent: ParentNode,
|
|
132
|
+
private readonly registry: Registry,
|
|
133
|
+
content: readonly ContentItem[],
|
|
22
134
|
) {
|
|
23
|
-
this.
|
|
24
|
-
|
|
25
|
-
this.nodes = descriptions.map((description) =>
|
|
26
|
-
this.instantiate(description, this.host, registry),
|
|
27
|
-
);
|
|
28
|
-
} catch (error) {
|
|
29
|
-
this.host.destroy();
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
135
|
+
this.sequence = { parent, segments: [], base: () => 0 };
|
|
136
|
+
this.fill(content, this.sequence);
|
|
32
137
|
}
|
|
33
138
|
|
|
34
|
-
get
|
|
35
|
-
return this.
|
|
139
|
+
get size(): number {
|
|
140
|
+
return size(this.sequence.segments);
|
|
141
|
+
}
|
|
142
|
+
get nodes(): AnyNode[] {
|
|
143
|
+
return flat(this.sequence.segments);
|
|
36
144
|
}
|
|
37
145
|
|
|
38
|
-
update
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
part.validate(value);
|
|
46
|
-
return { part, value };
|
|
47
|
-
});
|
|
48
|
-
this.host.batch(() => {
|
|
49
|
-
for (const { part, value } of changes) part.commit(value);
|
|
50
|
-
});
|
|
51
|
-
return this;
|
|
146
|
+
/** Validates every binding first, so an update changes all or nothing. */
|
|
147
|
+
readonly prepare: Prepare = (values, stagings) => {
|
|
148
|
+
const commits = this.parts.map((part) => {
|
|
149
|
+
if (part instanceof ChildPart) return part.prepare(values, stagings);
|
|
150
|
+
const value = part.evaluate(values);
|
|
151
|
+
part.validate(value);
|
|
152
|
+
return () => part.commit(value);
|
|
52
153
|
});
|
|
53
|
-
|
|
154
|
+
return () => commits.forEach((commit) => commit());
|
|
155
|
+
};
|
|
54
156
|
|
|
55
|
-
|
|
56
|
-
|
|
157
|
+
private fill(content: readonly ContentItem[], sequence: Sequence): void {
|
|
158
|
+
for (const item of content) {
|
|
159
|
+
if ('tag' in item) sequence.segments.push(this.element(item, sequence.parent));
|
|
160
|
+
else
|
|
161
|
+
for (const hole of item.parts)
|
|
162
|
+
if (typeof hole == 'number') {
|
|
163
|
+
const part = new ChildPart(sequence, hole, this.registry);
|
|
164
|
+
sequence.segments.push(part);
|
|
165
|
+
this.parts.push(part);
|
|
166
|
+
commit(part.prepare, this.template.values);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
57
169
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
description: TemplateDescription,
|
|
61
|
-
parent: ParentNode,
|
|
62
|
-
registry: Registry,
|
|
63
|
-
): AnyNode {
|
|
64
|
-
const node = registry.createEmpty(description.tag, parent.context);
|
|
170
|
+
private element(description: TemplateDescription, parent: ParentNode): AnyNode {
|
|
171
|
+
const node = this.registry.createEmpty(description.tag, parent.context);
|
|
65
172
|
parent.add(node);
|
|
66
173
|
for (const [name, values] of Object.entries(description.attributes))
|
|
67
174
|
this.bind(new BindingPart(node, name, values));
|
|
68
175
|
if (appendTextSlot in node && Guards.isParent(node)) {
|
|
69
176
|
for (const part of description.content) {
|
|
70
|
-
if ('tag' in part) this.
|
|
177
|
+
if ('tag' in part) this.element(part, node);
|
|
71
178
|
else {
|
|
72
179
|
const binding = (node[appendTextSlot] as (value: string) => TextBinding)('');
|
|
73
180
|
this.bind(new BindingPart(node, null, part.parts, binding));
|
|
@@ -75,22 +182,69 @@ export class TemplateInstance {
|
|
|
75
182
|
}
|
|
76
183
|
return node;
|
|
77
184
|
}
|
|
78
|
-
if (
|
|
79
|
-
this.bind(new BindingPart(node, null, description.text));
|
|
185
|
+
if (Guards.isTextual(node)) {
|
|
186
|
+
if (description.text.length > 0) this.bind(new BindingPart(node, null, description.text));
|
|
187
|
+
} else if (Guards.isParent(node)) {
|
|
188
|
+
this.fill(description.content, { parent: node, segments: [], base: () => 0 });
|
|
189
|
+
return node;
|
|
190
|
+
}
|
|
80
191
|
if (description.children.length > 0 && !Guards.isParent(node))
|
|
81
192
|
throw new TypeError('Children require the Parent mixin');
|
|
82
|
-
for (const child of description.children) this.
|
|
193
|
+
for (const child of description.children) this.element(child, node as ParentNode);
|
|
83
194
|
return node;
|
|
84
195
|
}
|
|
85
196
|
|
|
86
197
|
private bind(part: BindingPart): void {
|
|
87
198
|
const value = part.evaluate(this.template.values);
|
|
88
199
|
part.validate(value);
|
|
89
|
-
part.commit(value
|
|
200
|
+
part.commit(value);
|
|
90
201
|
this.parts.push(part);
|
|
91
202
|
}
|
|
92
203
|
}
|
|
93
204
|
|
|
205
|
+
export class TemplateInstance {
|
|
206
|
+
readonly host: Group;
|
|
207
|
+
private readonly mount: Mount;
|
|
208
|
+
|
|
209
|
+
constructor(
|
|
210
|
+
parent: ParentNode,
|
|
211
|
+
readonly template: SvgTemplate,
|
|
212
|
+
registry: Registry,
|
|
213
|
+
content: readonly ContentItem[],
|
|
214
|
+
) {
|
|
215
|
+
this.host = new Group(parent.context);
|
|
216
|
+
try {
|
|
217
|
+
this.mount = new Mount(template, this.host, registry, content);
|
|
218
|
+
} catch (error) {
|
|
219
|
+
this.host.destroy();
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** The current top-level nodes, including those that child holes render. */
|
|
225
|
+
get nodes(): readonly AnyNode[] {
|
|
226
|
+
return this.mount.nodes;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
get isDestroyed(): boolean {
|
|
230
|
+
return this.host.isDestroyed;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
update(template: SvgTemplate): this {
|
|
234
|
+
return mutation(this, () => {
|
|
235
|
+
this.host.assertLive();
|
|
236
|
+
if (template.strings !== this.template.strings)
|
|
237
|
+
throw new TypeError('An instance can only update its original template');
|
|
238
|
+
this.host.batch(() => commit(this.mount.prepare, template.values));
|
|
239
|
+
return this;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
destroy(): void {
|
|
244
|
+
this.host.destroy();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
94
248
|
export class Renderer {
|
|
95
249
|
private static readonly renderers = new WeakMap<ParentNode, Renderer>();
|
|
96
250
|
private instance: TemplateInstance | null = null;
|
|
@@ -126,12 +280,15 @@ export class Renderer {
|
|
|
126
280
|
this.instance.template.strings === template.strings
|
|
127
281
|
)
|
|
128
282
|
return this.instance.update(template);
|
|
129
|
-
const
|
|
130
|
-
TemplateCompiler.validate(
|
|
131
|
-
const instance = new TemplateInstance(this.parent, template, this.registry,
|
|
283
|
+
const content = TemplateCompiler.content(this.parent.context.dom, template.strings);
|
|
284
|
+
TemplateCompiler.validate(content, this.registry);
|
|
285
|
+
const instance = new TemplateInstance(this.parent, template, this.registry, content);
|
|
132
286
|
try {
|
|
133
|
-
|
|
134
|
-
this.parent.
|
|
287
|
+
// Replacing a template disposes the old one semantically, so undo restores it.
|
|
288
|
+
this.parent.context.changes.run(this.parent, () => {
|
|
289
|
+
if (this.instance) dispose([this.instance.host]);
|
|
290
|
+
this.parent.add(instance.host);
|
|
291
|
+
});
|
|
135
292
|
} catch (error) {
|
|
136
293
|
instance.destroy();
|
|
137
294
|
throw error;
|
package/src/template/svg-tag.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Attribute and text holes take primitives. A hole between elements also takes a nested
|
|
3
|
+
* template or an iterable of them; `null`, `undefined`, booleans and `''` render nothing.
|
|
4
|
+
*/
|
|
5
|
+
export type TemplateValue =
|
|
6
|
+
string | number | boolean | null | undefined | SvgTemplate | Iterable<TemplateValue>;
|
|
2
7
|
|
|
3
8
|
export class SvgTemplate {
|
|
4
9
|
constructor(
|
package/src/text/internals.ts
CHANGED
package/src/types/common.ts
CHANGED
|
@@ -101,3 +101,32 @@ export interface Disposable {
|
|
|
101
101
|
readonly isDestroyed: boolean;
|
|
102
102
|
destroy(): void;
|
|
103
103
|
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Per-node editing limits that tools read structurally from `node.editRules`, for
|
|
107
|
+
* example from a component type. A node without rules edits freely.
|
|
108
|
+
*/
|
|
109
|
+
export interface EditRules {
|
|
110
|
+
/** `'free'` (default), a positive step in degrees that divides 360, or `false`. */
|
|
111
|
+
readonly rotate?: 'free' | number | false;
|
|
112
|
+
/** Whether flips and mirroring resizes are allowed. Defaults to true. */
|
|
113
|
+
readonly flip?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* `'scale'` (default), `false`, or `'props'`: a resize changes the node's own width and
|
|
116
|
+
* height through `size()` instead of scaling it. Multi-node resizes don't apply to it.
|
|
117
|
+
*/
|
|
118
|
+
readonly resize?: 'scale' | 'props' | false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* A named connection point that connectors read structurally from
|
|
123
|
+
* `node.portDefinitions`, for example from a component. `x` and `y` are in the node's
|
|
124
|
+
* local coordinates, before its own transform.
|
|
125
|
+
*/
|
|
126
|
+
export interface PortDefinition {
|
|
127
|
+
readonly name: string;
|
|
128
|
+
readonly x: number;
|
|
129
|
+
readonly y: number;
|
|
130
|
+
/** The side a link leaves from, before the node's transform. Elbow routing uses it. */
|
|
131
|
+
readonly side?: 'left' | 'right' | 'top' | 'bottom';
|
|
132
|
+
}
|