fragment-tools 0.2.2 → 0.2.4
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/package.json +1 -1
- package/src/client/app/components/Build.svelte +64 -0
- package/src/client/app/{ui → components}/Preview.svelte +1 -2
- package/src/client/app/inputs/MIDI.js +0 -1
- package/src/client/app/modules/MidiPanel.svelte +23 -13
- package/src/client/app/modules/Params.svelte +31 -16
- package/src/client/app/state/Sketch.svelte.js +77 -73
- package/src/client/app/state/layout.svelte.js +8 -2
- package/src/client/app/state/rendering.svelte.js +23 -5
- package/src/client/app/state/utils.svelte.js +28 -4
- package/src/client/app/ui/Field.svelte +13 -11
- package/src/client/app/ui/FieldGroup.svelte +5 -2
- package/src/client/app/ui/FieldSection.svelte +4 -4
- package/src/client/app/ui/Layout.svelte +1 -1
- package/src/client/app/ui/LayoutBuild.svelte +54 -0
- package/src/client/app/ui/LayoutColumn.svelte +2 -2
- package/src/client/app/ui/LayoutComponent.svelte +14 -4
- package/src/client/app/ui/LayoutResizer.svelte +11 -2
- package/src/client/app/ui/LayoutRow.svelte +2 -2
- package/src/client/app/ui/fields/ButtonInput.svelte +3 -3
- package/src/client/app/ui/fields/ColorInput.svelte +23 -13
- package/src/client/app/ui/fields/ImportInput.svelte +52 -0
- package/src/client/app/ui/fields/Input.svelte +4 -2
- package/src/client/app/ui/fields/IntervalInput.svelte +8 -6
- package/src/client/app/ui/fields/ProgressInput.svelte +47 -17
- package/src/client/app/ui/fields/Select.svelte +35 -41
- package/src/client/app/ui/fields/VectorInput.svelte +63 -18
- package/src/client/app/utils/fields.utils.js +70 -48
- package/src/client/app/utils/math.utils.js +6 -0
- package/src/client/public/css/global.css +14 -0
- package/src/client/app/ui/Build.svelte +0 -91
package/package.json
CHANGED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { onDestroy } from 'svelte';
|
|
3
|
+
import { sketchesManager } from '../state/sketches.svelte';
|
|
4
|
+
import { rendering } from '../state/rendering.svelte';
|
|
5
|
+
import { layout } from '../state/layout.svelte';
|
|
6
|
+
import LayoutBuild from '../ui/LayoutBuild.svelte';
|
|
7
|
+
|
|
8
|
+
console.log(`Made with Fragment. https://fragment.tools`);
|
|
9
|
+
|
|
10
|
+
let sketchKey = $derived(sketchesManager.keys[0]);
|
|
11
|
+
let sketch = $derived(sketchesManager.sketches[sketchKey]);
|
|
12
|
+
let buildConfig = $derived(sketch?.buildConfig ?? {});
|
|
13
|
+
let persistent = $derived(buildConfig.layout?.persistent ?? false);
|
|
14
|
+
let styles = $derived(buildConfig?.styles ?? '');
|
|
15
|
+
|
|
16
|
+
/** @type {HTMLHeadElement} */
|
|
17
|
+
let head;
|
|
18
|
+
/** @type {HTMLStyleElement} */
|
|
19
|
+
let style;
|
|
20
|
+
|
|
21
|
+
$effect(() => {
|
|
22
|
+
if (__BUILD__) {
|
|
23
|
+
layout.persistent = persistent;
|
|
24
|
+
} else if (persistent && layout.previewing) {
|
|
25
|
+
console.warn(`Layout is not preserved while previewing`);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
$effect(() => {
|
|
30
|
+
rendering.override(sketch?.buildConfig);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
$effect(() => {
|
|
34
|
+
if (styles !== '') {
|
|
35
|
+
head = document.getElementsByTagName('head')[0];
|
|
36
|
+
|
|
37
|
+
if (style) {
|
|
38
|
+
head.removeChild(style);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
style = document.createElement('style');
|
|
42
|
+
style.setAttribute('type', 'text/css');
|
|
43
|
+
style.appendChild(document.createTextNode(styles));
|
|
44
|
+
head.appendChild(style);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
onDestroy(() => {
|
|
49
|
+
if (style && head) {
|
|
50
|
+
head.removeChild(style);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
{#if sketch}
|
|
56
|
+
{#if buildConfig.layout?.component}
|
|
57
|
+
{#await buildConfig.layout.component() then layoutModule}
|
|
58
|
+
{@const LayoutBuildCustom = layoutModule.default}
|
|
59
|
+
<LayoutBuildCustom {sketchKey} {buildConfig} {sketch} />
|
|
60
|
+
{/await}
|
|
61
|
+
{:else}
|
|
62
|
+
<LayoutBuild {sketchKey} {sketch} {buildConfig} />
|
|
63
|
+
{/if}
|
|
64
|
+
{/if}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { onDestroy, onMount } from 'svelte';
|
|
3
|
-
|
|
4
2
|
import { rendering } from '../state/rendering.svelte';
|
|
3
|
+
import { onDestroy } from 'svelte';
|
|
5
4
|
import Build from './Build.svelte';
|
|
6
5
|
|
|
7
6
|
const { resizing, width, height, pixelRatio, aspectRatio, scale, preset } =
|
|
@@ -6,17 +6,19 @@
|
|
|
6
6
|
|
|
7
7
|
let { mID, headless = false, ...restProps } = $props();
|
|
8
8
|
|
|
9
|
-
let input = $state(
|
|
10
|
-
let output = $state(
|
|
11
|
-
let inputs = $state(
|
|
12
|
-
let outputs = $state(
|
|
9
|
+
let input = $state(undefined);
|
|
10
|
+
let output = $state(undefined);
|
|
11
|
+
let inputs = $state(MIDI.inputs);
|
|
12
|
+
let outputs = $state(MIDI.outputs);
|
|
13
|
+
let inputOptions = $derived.by(() => createDeviceOptions(inputs));
|
|
14
|
+
let outputOptions = $derived.by(() => createDeviceOptions(outputs));
|
|
13
15
|
let messages = $state([]);
|
|
14
16
|
|
|
15
17
|
function createDeviceOptions(deviceMap = new Map()) {
|
|
16
18
|
let options = [];
|
|
17
19
|
|
|
18
20
|
if (deviceMap.size !== 0) {
|
|
19
|
-
options.push({ value:
|
|
21
|
+
options.push({ value: undefined, label: 'No device selected.' });
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
for (let entry of deviceMap) {
|
|
@@ -30,7 +32,7 @@
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
if (options.length === 0) {
|
|
33
|
-
options
|
|
35
|
+
options.push({ value: undefined, label: 'No device detected.' });
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
return options;
|
|
@@ -45,15 +47,23 @@
|
|
|
45
47
|
await MIDI.request();
|
|
46
48
|
|
|
47
49
|
function refresh() {
|
|
48
|
-
inputs =
|
|
49
|
-
outputs =
|
|
50
|
+
inputs = MIDI.inputs;
|
|
51
|
+
outputs = MIDI.outputs;
|
|
50
52
|
|
|
51
53
|
// if a single device is connected, select it by default
|
|
52
|
-
input =
|
|
53
|
-
|
|
54
|
+
input =
|
|
55
|
+
inputs.size === 1
|
|
56
|
+
? MIDI.inputs.values().next().value.id
|
|
57
|
+
: undefined;
|
|
58
|
+
output =
|
|
59
|
+
outputs.size === 1
|
|
60
|
+
? MIDI.outputs.values().next().value.id
|
|
61
|
+
: undefined;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
MIDI.addEventListener('connected',
|
|
64
|
+
MIDI.addEventListener('connected', () => {
|
|
65
|
+
refresh();
|
|
66
|
+
});
|
|
57
67
|
MIDI.addEventListener('disconnected', () => {
|
|
58
68
|
refresh();
|
|
59
69
|
});
|
|
@@ -83,7 +93,7 @@
|
|
|
83
93
|
value={input}
|
|
84
94
|
onchange={(value) => (input = value)}
|
|
85
95
|
params={{
|
|
86
|
-
options:
|
|
96
|
+
options: inputOptions,
|
|
87
97
|
}}
|
|
88
98
|
/>
|
|
89
99
|
<Field
|
|
@@ -91,7 +101,7 @@
|
|
|
91
101
|
value={output}
|
|
92
102
|
onchange={(value) => (output = value)}
|
|
93
103
|
params={{
|
|
94
|
-
options:
|
|
104
|
+
options: outputOptions,
|
|
95
105
|
}}
|
|
96
106
|
/>
|
|
97
107
|
<Field key="messages" value={messages} type="list" disabled />
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { layout } from '../state/layout.svelte';
|
|
8
8
|
import FieldGroup from '../ui/FieldGroup.svelte';
|
|
9
9
|
import { sketchesManager } from '../state/sketches.svelte';
|
|
10
|
+
import { parseFolder } from '../utils/fields.utils';
|
|
10
11
|
|
|
11
12
|
let {
|
|
12
13
|
id = layout.getID(),
|
|
@@ -52,16 +53,25 @@
|
|
|
52
53
|
|
|
53
54
|
if (!sketchPropGroup || group === sketchPropGroup) {
|
|
54
55
|
if (folder) {
|
|
56
|
+
const parsed = parseFolder(folder);
|
|
57
|
+
const current = parsed.find((m) => m.isCurrent);
|
|
58
|
+
|
|
55
59
|
const fieldgroup = sketch?.propsFolders.find(
|
|
56
|
-
(f) => f.id ===
|
|
60
|
+
(f) => f.id === current.id,
|
|
57
61
|
);
|
|
58
62
|
|
|
59
63
|
if (fieldgroup) {
|
|
60
|
-
const { depth,
|
|
64
|
+
const { depth, rootId } = fieldgroup;
|
|
65
|
+
const root =
|
|
66
|
+
rootId &&
|
|
67
|
+
sketch?.propsFolders.find((f) => f.id === rootId);
|
|
61
68
|
|
|
62
69
|
if (depth === 0 && !tree.includes(fieldgroup)) {
|
|
63
70
|
tree.push(fieldgroup);
|
|
64
|
-
} else if (
|
|
71
|
+
} else if (
|
|
72
|
+
root &&
|
|
73
|
+
!tree.some((fieldgroup) => fieldgroup.id === rootId)
|
|
74
|
+
) {
|
|
65
75
|
tree.push(root);
|
|
66
76
|
}
|
|
67
77
|
} else {
|
|
@@ -148,6 +158,9 @@
|
|
|
148
158
|
// value(event, sketch.params);
|
|
149
159
|
}}
|
|
150
160
|
onchange={(v) => {
|
|
161
|
+
if (v?.currentTarget && v?.type === 'change') {
|
|
162
|
+
v = v.currentTarget.value;
|
|
163
|
+
}
|
|
151
164
|
sketch.updateProp(key, v);
|
|
152
165
|
}}
|
|
153
166
|
/>
|
|
@@ -161,19 +174,21 @@
|
|
|
161
174
|
sketchProps[item.key],
|
|
162
175
|
)}
|
|
163
176
|
{:else if item.type === 'fieldgroup'}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
{#
|
|
173
|
-
{
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
+
{#if !item.hidden}
|
|
178
|
+
<FieldGroup
|
|
179
|
+
name={item.displayName}
|
|
180
|
+
collapsed={item.collapsed}
|
|
181
|
+
onchange={(collapsed) => {
|
|
182
|
+
sketch.updateFolder(item, collapsed);
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
{#if item.children.length > 0}
|
|
186
|
+
{#each item.children as child, childIndex}
|
|
187
|
+
{@render sketchPropItem(childIndex, child)}
|
|
188
|
+
{/each}
|
|
189
|
+
{/if}
|
|
190
|
+
</FieldGroup>
|
|
191
|
+
{/if}
|
|
177
192
|
{/if}
|
|
178
193
|
{/snippet}
|
|
179
194
|
{#each sketchPropsTree as sketchPropsTreeItem, index}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { parseFolder } from '../utils/fields.utils';
|
|
1
2
|
import { rendering } from './rendering.svelte';
|
|
2
3
|
import {
|
|
3
4
|
deepAssign,
|
|
5
|
+
deepClone,
|
|
4
6
|
deepEqual,
|
|
5
7
|
hydrate,
|
|
6
8
|
isFunction,
|
|
@@ -46,7 +48,10 @@ class Sketch {
|
|
|
46
48
|
|
|
47
49
|
reset() {
|
|
48
50
|
Object.keys(this.props).forEach((key) => {
|
|
49
|
-
this.updateProp(
|
|
51
|
+
this.updateProp(
|
|
52
|
+
key,
|
|
53
|
+
$state.snapshot(this.props[key].__initialValue),
|
|
54
|
+
);
|
|
50
55
|
});
|
|
51
56
|
|
|
52
57
|
this.propsFolders.forEach((fieldgroup) => {
|
|
@@ -89,12 +94,16 @@ class Sketch {
|
|
|
89
94
|
) {
|
|
90
95
|
deepAssign(newProp.value, prevProp.value);
|
|
91
96
|
deepAssign(instanceProp.value, prevProp.value);
|
|
92
|
-
newProp.__currentValue =
|
|
97
|
+
newProp.__currentValue = deepClone(
|
|
98
|
+
$state.snapshot(newProp.value),
|
|
99
|
+
);
|
|
93
100
|
} else if (
|
|
94
101
|
newProp.__initialValue === prevProp.__initialValue
|
|
95
102
|
) {
|
|
96
103
|
newProp.value = prevProp.value;
|
|
97
|
-
newProp.__currentValue =
|
|
104
|
+
newProp.__currentValue = deepClone(
|
|
105
|
+
$state.snapshot(newProp.value),
|
|
106
|
+
);
|
|
98
107
|
instanceProp.value = prevProp.value;
|
|
99
108
|
}
|
|
100
109
|
|
|
@@ -164,36 +173,25 @@ class Sketch {
|
|
|
164
173
|
propsFoldersCollection,
|
|
165
174
|
propsGroupsCollection,
|
|
166
175
|
) {
|
|
167
|
-
const duplicateInitialValue = (value) => {
|
|
168
|
-
if (isFunction(value)) {
|
|
169
|
-
return value;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (isObject(value)) {
|
|
173
|
-
return structuredClone(value);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return value;
|
|
177
|
-
};
|
|
178
|
-
|
|
179
176
|
let {
|
|
180
177
|
value,
|
|
181
178
|
params = {},
|
|
182
179
|
triggers = [],
|
|
183
180
|
group,
|
|
181
|
+
type,
|
|
184
182
|
folder,
|
|
185
183
|
displayName,
|
|
186
184
|
} = instanceProp;
|
|
187
185
|
|
|
188
|
-
if (value
|
|
186
|
+
if (value?.isColor) {
|
|
189
187
|
value = { r: value.r, g: value.g, b: value.b };
|
|
190
|
-
} else if (value
|
|
188
|
+
} else if (value?.isVector2) {
|
|
191
189
|
value = { x: value.x, y: value.y };
|
|
192
|
-
} else if (value
|
|
190
|
+
} else if (value?.isVector3) {
|
|
193
191
|
value = { x: value.x, y: value.y, z: value.z };
|
|
194
|
-
} else if (value
|
|
192
|
+
} else if (value?.isVector4) {
|
|
195
193
|
value = { x: value.x, y: value.y, z: value.z, w: value.w };
|
|
196
|
-
} else if (value
|
|
194
|
+
} else if (value?.isQuaternion) {
|
|
197
195
|
value = { x: value.x, y: value.y, z: value.z, w: value.w };
|
|
198
196
|
}
|
|
199
197
|
|
|
@@ -202,7 +200,7 @@ class Sketch {
|
|
|
202
200
|
? instanceProp.hidden
|
|
203
201
|
: () => instanceProp.hidden;
|
|
204
202
|
|
|
205
|
-
let initialValue =
|
|
203
|
+
let initialValue = deepClone(value);
|
|
206
204
|
|
|
207
205
|
if (group && !propsGroupsCollection.includes(group)) {
|
|
208
206
|
propsGroupsCollection.push(group);
|
|
@@ -215,8 +213,9 @@ class Sketch {
|
|
|
215
213
|
let prop = {
|
|
216
214
|
value,
|
|
217
215
|
__initialValue: initialValue,
|
|
218
|
-
__currentValue: value,
|
|
216
|
+
__currentValue: deepClone(value),
|
|
219
217
|
__hidden,
|
|
218
|
+
type,
|
|
220
219
|
params: structuredClone(params),
|
|
221
220
|
triggers,
|
|
222
221
|
group,
|
|
@@ -235,14 +234,16 @@ class Sketch {
|
|
|
235
234
|
|
|
236
235
|
if (prop) {
|
|
237
236
|
prop.value = newValue;
|
|
238
|
-
prop.__currentValue = newValue;
|
|
237
|
+
prop.__currentValue = deepClone(newValue);
|
|
239
238
|
}
|
|
240
239
|
|
|
241
240
|
if (instanceProp) {
|
|
242
|
-
if (
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
241
|
+
if (!deepEqual(instanceProp.value, newValue)) {
|
|
242
|
+
if (isObject(instanceProp.value) && isObject(newValue)) {
|
|
243
|
+
deepAssign(instanceProp.value, newValue);
|
|
244
|
+
} else {
|
|
245
|
+
instanceProp.value = newValue;
|
|
246
|
+
}
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
instanceProp.onChange?.(instanceProp, {
|
|
@@ -264,21 +265,24 @@ class Sketch {
|
|
|
264
265
|
if (!folder) return undefined;
|
|
265
266
|
|
|
266
267
|
let propFolder;
|
|
267
|
-
let names = folder.split('.');
|
|
268
268
|
|
|
269
|
-
|
|
270
|
-
let root;
|
|
271
|
-
let collapsedRegex = /^(.*?)(?:\[collapsed=(true|false)\])?$/;
|
|
269
|
+
const parsed = parseFolder(folder);
|
|
272
270
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
let match =
|
|
276
|
-
let
|
|
277
|
-
|
|
271
|
+
if (parsed.length > 0) {
|
|
272
|
+
for (let i = 0; i < parsed.length; i++) {
|
|
273
|
+
let match = parsed[i];
|
|
274
|
+
let {
|
|
275
|
+
depth,
|
|
276
|
+
id,
|
|
277
|
+
parentId,
|
|
278
|
+
rootId,
|
|
279
|
+
isCurrent,
|
|
280
|
+
name,
|
|
281
|
+
attributes = {},
|
|
282
|
+
} = match;
|
|
283
|
+
let { collapsed = false } = attributes;
|
|
284
|
+
let displayName = name;
|
|
278
285
|
|
|
279
|
-
let depth = i;
|
|
280
|
-
let id = [...names].slice(0, i + 1).join('.');
|
|
281
|
-
let parentId = [...names].slice(0, i).join('.');
|
|
282
286
|
let parent =
|
|
283
287
|
depth > 0
|
|
284
288
|
? collection.find((f) => f.id === parentId)
|
|
@@ -296,7 +300,8 @@ class Sketch {
|
|
|
296
300
|
children: [],
|
|
297
301
|
parent,
|
|
298
302
|
depth,
|
|
299
|
-
|
|
303
|
+
rootId,
|
|
304
|
+
hidden: false,
|
|
300
305
|
};
|
|
301
306
|
|
|
302
307
|
if (parent) {
|
|
@@ -306,11 +311,7 @@ class Sketch {
|
|
|
306
311
|
collection.push(fieldgroup);
|
|
307
312
|
}
|
|
308
313
|
|
|
309
|
-
if (
|
|
310
|
-
root = fieldgroup;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (i === names.length - 1) {
|
|
314
|
+
if (isCurrent) {
|
|
314
315
|
fieldgroup.children.push({
|
|
315
316
|
type: 'field',
|
|
316
317
|
key,
|
|
@@ -326,7 +327,7 @@ class Sketch {
|
|
|
326
327
|
|
|
327
328
|
updateFolder(folder, collapsed) {
|
|
328
329
|
this.propsFolders.forEach((f, index) => {
|
|
329
|
-
if (f === folder) {
|
|
330
|
+
if (f.id === folder.id) {
|
|
330
331
|
this.propsFolders[index].collapsed = collapsed;
|
|
331
332
|
}
|
|
332
333
|
});
|
|
@@ -365,7 +366,10 @@ class Sketch {
|
|
|
365
366
|
!isFunction(instanceProp.value) &&
|
|
366
367
|
!deepEqual(instanceProp.value, prop.__currentValue)
|
|
367
368
|
) {
|
|
368
|
-
this.updateProp(key,
|
|
369
|
+
this.updateProp(key, instanceProp.value);
|
|
370
|
+
prop.__initialValue = deepClone(
|
|
371
|
+
$state.snapshot(prop.value),
|
|
372
|
+
);
|
|
369
373
|
}
|
|
370
374
|
|
|
371
375
|
// sync displayName
|
|
@@ -440,34 +444,11 @@ class Sketch {
|
|
|
440
444
|
for (const paramKey in instanceProp.params) {
|
|
441
445
|
const instanceParam = instanceProp.params[paramKey];
|
|
442
446
|
const param = prop.params[paramKey];
|
|
443
|
-
let needsUpdate =
|
|
444
|
-
|
|
445
|
-
if (isObject(instanceParam)) {
|
|
446
|
-
Object.keys(instanceParam).forEach((key) => {
|
|
447
|
-
if (isObject(instanceParam[key])) {
|
|
448
|
-
Object.keys(instanceParam[key]).forEach(
|
|
449
|
-
(k) => {
|
|
450
|
-
if (
|
|
451
|
-
instanceParam[key][k] !==
|
|
452
|
-
param[key][k]
|
|
453
|
-
) {
|
|
454
|
-
needsUpdate = true;
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
);
|
|
458
|
-
} else if (instanceParam[key] !== param[key]) {
|
|
459
|
-
needsUpdate = true;
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
} else if (instanceParam !== param) {
|
|
463
|
-
needsUpdate = true;
|
|
464
|
-
}
|
|
447
|
+
let needsUpdate = !deepEqual(instanceParam, param);
|
|
465
448
|
|
|
466
449
|
if (needsUpdate) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
structuredClone(instanceParam);
|
|
470
|
-
}
|
|
450
|
+
prop.params[paramKey] =
|
|
451
|
+
structuredClone(instanceParam);
|
|
471
452
|
}
|
|
472
453
|
}
|
|
473
454
|
}
|
|
@@ -485,6 +466,29 @@ class Sketch {
|
|
|
485
466
|
delete this.props[key];
|
|
486
467
|
}
|
|
487
468
|
});
|
|
469
|
+
|
|
470
|
+
const fieldgroups = [...this.propsFolders].sort(
|
|
471
|
+
(a, b) => b.depth - a.depth,
|
|
472
|
+
);
|
|
473
|
+
|
|
474
|
+
fieldgroups.forEach((fieldgroup) => {
|
|
475
|
+
const hasAllFieldsHidden = fieldgroup.children
|
|
476
|
+
.filter((child) => child.type === 'field')
|
|
477
|
+
.every((child) => this.props[child.key].__hidden());
|
|
478
|
+
const hasAllFieldgroupsHidden = fieldgroup.children
|
|
479
|
+
.filter((child) => child.type === 'fieldgroup')
|
|
480
|
+
.every((child) => child.hidden);
|
|
481
|
+
|
|
482
|
+
if (hasAllFieldsHidden && hasAllFieldgroupsHidden) {
|
|
483
|
+
if (!fieldgroup.hidden) {
|
|
484
|
+
fieldgroup.hidden = true;
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
if (fieldgroup.hidden) {
|
|
488
|
+
fieldgroup.hidden = false;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
});
|
|
488
492
|
}
|
|
489
493
|
|
|
490
494
|
onBeforeCapture(fn) {
|
|
@@ -6,17 +6,22 @@ class Layout {
|
|
|
6
6
|
components = $state([]);
|
|
7
7
|
editing = $state(false);
|
|
8
8
|
previewing = $state(false);
|
|
9
|
+
persistent = $state(true);
|
|
9
10
|
|
|
10
11
|
getID() {
|
|
11
12
|
return COMPONENT_ID++;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
constructor() {
|
|
15
|
-
this.key =
|
|
16
|
+
this.key = __BUILD__ ? `layout${__START_TIME__}` : `layout`;
|
|
16
17
|
|
|
17
18
|
$effect.root(() => {
|
|
18
19
|
$effect(() => {
|
|
19
|
-
|
|
20
|
+
const isPersistent = __BUILD__
|
|
21
|
+
? this.persistent
|
|
22
|
+
: !this.previewing;
|
|
23
|
+
|
|
24
|
+
if (isPersistent) {
|
|
20
25
|
this.persist($state.snapshot(this.components));
|
|
21
26
|
}
|
|
22
27
|
});
|
|
@@ -156,6 +161,7 @@ class Layout {
|
|
|
156
161
|
type: source.type,
|
|
157
162
|
name: source.name,
|
|
158
163
|
minimized: source.minimized,
|
|
164
|
+
headless: source.headless,
|
|
159
165
|
params: source.params,
|
|
160
166
|
children: [...source.children],
|
|
161
167
|
}));
|
|
@@ -320,12 +320,27 @@ export class Render {
|
|
|
320
320
|
this.time = 0;
|
|
321
321
|
this.recording = false;
|
|
322
322
|
|
|
323
|
-
|
|
323
|
+
let resizeTimeout;
|
|
324
|
+
|
|
325
|
+
$effect.pre(() => {
|
|
324
326
|
const { width, height, pixelRatio } = rendering;
|
|
325
327
|
|
|
326
328
|
if (this.loaded) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
+
if (resizeTimeout) clearTimeout(resizeTimeout);
|
|
330
|
+
|
|
331
|
+
resizeTimeout = setTimeout(() => {
|
|
332
|
+
clearTimeout(resizeTimeout);
|
|
333
|
+
resizeTimeout = null;
|
|
334
|
+
|
|
335
|
+
this.resize(width, height, pixelRatio);
|
|
336
|
+
}, 0);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
$effect(() => {
|
|
341
|
+
const { width, height, pixelRatio } = rendering;
|
|
342
|
+
|
|
343
|
+
if (!this.loaded) {
|
|
329
344
|
this.width = width;
|
|
330
345
|
this.height = height;
|
|
331
346
|
this.pixelRatio = pixelRatio;
|
|
@@ -361,7 +376,7 @@ export class Render {
|
|
|
361
376
|
|
|
362
377
|
if (needsUpdate) {
|
|
363
378
|
console.warn(
|
|
364
|
-
`Canvas ${attributeName} was changed from sketch
|
|
379
|
+
`Canvas ${attributeName} was changed from sketch from ${rendering[attributeName]}px to ${dimension}px.`,
|
|
365
380
|
);
|
|
366
381
|
rendering[attributeName] = dimension;
|
|
367
382
|
|
|
@@ -460,6 +475,8 @@ export class Render {
|
|
|
460
475
|
};
|
|
461
476
|
|
|
462
477
|
this.init = async () => {
|
|
478
|
+
if (this.errored) return;
|
|
479
|
+
|
|
463
480
|
clearError(this.sketch.key);
|
|
464
481
|
this.mountParams = this.renderer?.onMountPreview?.(this.params);
|
|
465
482
|
if (this.mountParams && this.mountParams.canvas !== this.canvas) {
|
|
@@ -599,7 +616,8 @@ export class Render {
|
|
|
599
616
|
sketch.beforeRecord.forEach((fn) => fn(params));
|
|
600
617
|
},
|
|
601
618
|
onTick: ({ time, deltaTime }) => {
|
|
602
|
-
this.
|
|
619
|
+
this.time += deltaTime;
|
|
620
|
+
this.loop(this.time);
|
|
603
621
|
},
|
|
604
622
|
onComplete: (params) => {
|
|
605
623
|
sketch.afterRecord.forEach((fn) => fn(params));
|
|
@@ -50,11 +50,22 @@ export function deepAssign(target, source) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export function deepEqual(target, source) {
|
|
53
|
-
if (isObject(target) && isObject(
|
|
53
|
+
if (isObject(target) && isObject(source)) {
|
|
54
54
|
let isEqual = true;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
Array.isArray(target) &&
|
|
58
|
+
Array.isArray(source) &&
|
|
59
|
+
target.length !== source.length
|
|
60
|
+
) {
|
|
61
|
+
isEqual = false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (isEqual) {
|
|
65
|
+
for (const key in source) {
|
|
66
|
+
if (isEqual) {
|
|
67
|
+
isEqual = deepEqual(target[key], source[key]);
|
|
68
|
+
}
|
|
58
69
|
}
|
|
59
70
|
}
|
|
60
71
|
|
|
@@ -63,3 +74,16 @@ export function deepEqual(target, source) {
|
|
|
63
74
|
|
|
64
75
|
return target === source;
|
|
65
76
|
}
|
|
77
|
+
|
|
78
|
+
export function deepClone(value) {
|
|
79
|
+
if (isFunction(value)) {
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (isObject(value)) {
|
|
84
|
+
const clone = structuredClone(value);
|
|
85
|
+
return clone;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return value;
|
|
89
|
+
}
|