fragment-tools 0.1.19 → 0.2.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.
Files changed (102) hide show
  1. package/bin/index.js +1 -0
  2. package/package.json +5 -6
  3. package/src/cli/templates/three-fragment/index.js +6 -6
  4. package/src/cli/templates/three-orthographic/index.js +3 -3
  5. package/src/cli/templates/three-perspective/index.js +3 -3
  6. package/src/client/app/actions/resize.js +14 -0
  7. package/src/client/app/components/HintLoading.svelte +94 -0
  8. package/src/client/app/components/HintPaused.svelte +88 -0
  9. package/src/client/app/components/HintRecord.svelte +62 -0
  10. package/src/client/app/components/IconLocked.svelte +51 -0
  11. package/src/client/app/components/IconTriggers.svelte +48 -0
  12. package/src/client/app/components/Init.svelte +14 -27
  13. package/src/client/app/components/KeyBinding.svelte +3 -6
  14. package/src/client/app/helpers.js +4 -40
  15. package/src/client/app/hooks.js +41 -17
  16. package/src/client/app/inputs/MIDI.js +2 -1
  17. package/src/client/app/lib/canvas-recorder/CanvasRecorder.js +6 -1
  18. package/src/client/app/lib/gl/Renderer.js +1 -0
  19. package/src/client/app/lib/svelte-json-tree/ErrorNode.svelte +28 -0
  20. package/src/client/app/lib/svelte-json-tree/ErrorStack.svelte +31 -0
  21. package/src/client/app/lib/svelte-json-tree/Expandable.svelte +25 -0
  22. package/src/client/app/lib/svelte-json-tree/JSONArrayNode.svelte +38 -0
  23. package/src/client/app/lib/svelte-json-tree/JSONArrow.svelte +47 -0
  24. package/src/client/app/lib/svelte-json-tree/JSONFunctionNode.svelte +114 -0
  25. package/src/client/app/lib/svelte-json-tree/JSONIterableArrayNode.svelte +60 -0
  26. package/src/client/app/lib/svelte-json-tree/JSONIterableMapNode.svelte +87 -0
  27. package/src/client/app/lib/svelte-json-tree/JSONNested.svelte +94 -0
  28. package/src/client/app/lib/svelte-json-tree/JSONNode.svelte +91 -0
  29. package/src/client/app/lib/svelte-json-tree/JSONObjectNode.svelte +40 -0
  30. package/src/client/app/lib/svelte-json-tree/JSONStringNode.svelte +31 -0
  31. package/src/client/app/lib/svelte-json-tree/JSONValueNode.svelte +31 -0
  32. package/src/client/app/lib/svelte-json-tree/PreviewList.svelte +38 -0
  33. package/src/client/app/lib/svelte-json-tree/RegExpNode.svelte +42 -0
  34. package/src/client/app/lib/svelte-json-tree/Root.svelte +75 -0
  35. package/src/client/app/lib/svelte-json-tree/Summary.svelte +9 -0
  36. package/src/client/app/lib/svelte-json-tree/TypedArrayNode.svelte +56 -0
  37. package/src/client/app/lib/svelte-json-tree/index.js +1 -0
  38. package/src/client/app/lib/svelte-json-tree/utils.js +57 -0
  39. package/src/client/app/modules/Console/ConsoleLine.svelte +12 -11
  40. package/src/client/app/modules/Console.svelte +82 -17
  41. package/src/client/app/modules/Exports.svelte +48 -48
  42. package/src/client/app/modules/MidiPanel.svelte +12 -19
  43. package/src/client/app/modules/Monitor.svelte +147 -55
  44. package/src/client/app/modules/Params.svelte +127 -80
  45. package/src/client/app/renderers/2DRenderer.js +1 -0
  46. package/src/client/app/renderers/FragmentRenderer.js +1 -1
  47. package/src/client/app/renderers/P5GLRenderer.js +11 -5
  48. package/src/client/app/renderers/P5Renderer.js +7 -3
  49. package/src/client/app/renderers/THREERenderer.js +42 -79
  50. package/src/client/app/state/Sketch.svelte.js +538 -0
  51. package/src/client/app/state/errors.svelte.js +17 -0
  52. package/src/client/app/state/exports.svelte.js +152 -0
  53. package/src/client/app/state/layout.svelte.js +205 -0
  54. package/src/client/app/state/monitors.svelte.js +36 -0
  55. package/src/client/app/state/renderers.svelte.js +77 -0
  56. package/src/client/app/state/rendering.svelte.js +697 -0
  57. package/src/client/app/state/sketches.svelte.js +73 -0
  58. package/src/client/app/state/utils.svelte.js +65 -0
  59. package/src/client/app/ui/Build.svelte +53 -60
  60. package/src/client/app/ui/ErrorOverlay.svelte +2 -2
  61. package/src/client/app/ui/Field.svelte +63 -189
  62. package/src/client/app/ui/FieldGroup.svelte +4 -5
  63. package/src/client/app/ui/FieldSection.svelte +14 -9
  64. package/src/client/app/ui/FieldSpace.svelte +1 -1
  65. package/src/client/app/ui/FieldTrigger.svelte +86 -84
  66. package/src/client/app/ui/FieldTriggers.svelte +25 -24
  67. package/src/client/app/ui/FloatingParams.svelte +50 -12
  68. package/src/client/app/ui/Layout.svelte +24 -13
  69. package/src/client/app/ui/LayoutColumn.svelte +2 -2
  70. package/src/client/app/ui/LayoutComponent.svelte +86 -195
  71. package/src/client/app/ui/LayoutResizer.svelte +25 -37
  72. package/src/client/app/ui/LayoutRoot.svelte +3 -5
  73. package/src/client/app/ui/LayoutRow.svelte +2 -2
  74. package/src/client/app/ui/LayoutToolbar.svelte +17 -76
  75. package/src/client/app/ui/Module.svelte +31 -35
  76. package/src/client/app/ui/ModuleHeaderAction.svelte +23 -16
  77. package/src/client/app/ui/ModuleHeaderButton.svelte +3 -3
  78. package/src/client/app/ui/ModuleHeaderSelect.svelte +4 -12
  79. package/src/client/app/ui/ModuleRenderer.svelte +84 -22
  80. package/src/client/app/ui/ParamsOutput.svelte +61 -77
  81. package/src/client/app/ui/Preview.svelte +15 -4
  82. package/src/client/app/ui/SelectChevrons.svelte +1 -2
  83. package/src/client/app/ui/SketchRenderer.svelte +89 -701
  84. package/src/client/app/ui/SketchSelect.svelte +14 -49
  85. package/src/client/app/ui/fields/ButtonInput.svelte +14 -11
  86. package/src/client/app/ui/fields/CheckboxInput.svelte +5 -12
  87. package/src/client/app/ui/fields/ColorInput.svelte +46 -121
  88. package/src/client/app/ui/fields/FieldInputRow.svelte +5 -1
  89. package/src/client/app/ui/fields/ImageInput.svelte +14 -14
  90. package/src/client/app/ui/fields/Input.svelte +19 -25
  91. package/src/client/app/ui/fields/IntervalInput.svelte +22 -22
  92. package/src/client/app/ui/fields/NumberInput.svelte +32 -38
  93. package/src/client/app/ui/fields/ProgressInput.svelte +14 -13
  94. package/src/client/app/ui/fields/Select.svelte +34 -45
  95. package/src/client/app/ui/fields/TextInput.svelte +10 -6
  96. package/src/client/app/ui/fields/VectorInput.svelte +25 -30
  97. package/src/client/app/utils/canvas.utils.js +8 -8
  98. package/src/client/app/utils/color.utils.js +46 -13
  99. package/src/client/app/utils/fields.utils.js +1 -1
  100. package/src/client/app/utils/glsl.utils.js +1 -1
  101. package/src/client/app/utils/glslErrors.js +1 -1
  102. package/src/client/main.js +2 -2
@@ -0,0 +1,73 @@
1
+ import { displayError } from '../state/errors.svelte.js';
2
+ import { sketches as all } from '@fragment/sketches';
3
+ import Sketch from './Sketch.svelte.js';
4
+ import { rendering } from './rendering.svelte.js';
5
+ import { removeHotListeners } from '../triggers/index.js';
6
+
7
+ class SketchesManager {
8
+ sketches = $state({});
9
+ keys = $derived(Object.keys(this.sketches));
10
+ count = $derived(this.keys.length);
11
+
12
+ async loadSketch(collection, key) {
13
+ try {
14
+ let sketch = await collection[key]();
15
+
16
+ await rendering.preloadRenderer({
17
+ renderingMode: sketch.rendering,
18
+ renderer: sketch.renderer,
19
+ });
20
+
21
+ return sketch;
22
+ } catch (error) {
23
+ console.error(error);
24
+ displayError(error, key);
25
+ }
26
+ }
27
+
28
+ async loadAll(collection) {
29
+ const keys = [...Object.keys(collection)];
30
+
31
+ Object.keys(this.sketches).forEach((key) => {
32
+ removeHotListeners(key);
33
+
34
+ if (!keys.includes(key)) {
35
+ delete this.sketches[key];
36
+ }
37
+ });
38
+
39
+ const loadedSketches = await Promise.all(
40
+ keys.map((key) => this.loadSketch(collection, key)),
41
+ );
42
+
43
+ const newSketches = keys.reduce((all, key, index) => {
44
+ if (loadedSketches[index]) {
45
+ all[key] = loadedSketches[index];
46
+ }
47
+
48
+ return all;
49
+ }, {});
50
+
51
+ const newInstancedSketches = Object.keys(newSketches).reduce(
52
+ (all, key, index) => {
53
+ const prevSketch = this.sketches[key];
54
+
55
+ const instanced = new Sketch({
56
+ key,
57
+ instance: newSketches[key],
58
+ previous: prevSketch,
59
+ });
60
+
61
+ all[key] = instanced;
62
+
63
+ return all;
64
+ },
65
+ {},
66
+ );
67
+
68
+ this.sketches = newInstancedSketches;
69
+ }
70
+ }
71
+
72
+ export let sketchesManager = new SketchesManager();
73
+ sketchesManager.loadAll(all);
@@ -0,0 +1,65 @@
1
+ export function persist(key, data) {
2
+ try {
3
+ window.localStorage.setItem(`fragment.${key}`, JSON.stringify(data));
4
+ } catch (err) {
5
+ throw err;
6
+ }
7
+ }
8
+
9
+ export function hydrate(key, target = {}, defaultValue = {}) {
10
+ try {
11
+ const storageKey = `fragment.${key}`;
12
+ const item = window.localStorage.getItem(storageKey);
13
+
14
+ if (item) {
15
+ const data = JSON.parse(item);
16
+
17
+ if (target && typeof data === 'object') {
18
+ Object.keys(data).forEach((key) => {
19
+ if (target[key] !== undefined) {
20
+ target[key] = data[key];
21
+ }
22
+ });
23
+ }
24
+
25
+ return data;
26
+ }
27
+
28
+ return defaultValue;
29
+ } catch (err) {
30
+ console.error(err);
31
+ }
32
+ }
33
+
34
+ export function isObject(item) {
35
+ return item && typeof item === 'object';
36
+ }
37
+
38
+ export function isFunction(item) {
39
+ return item && typeof item === 'function';
40
+ }
41
+
42
+ export function deepAssign(target, source) {
43
+ for (const key in source) {
44
+ if (isObject(source[key]) && isObject(target[key])) {
45
+ deepAssign(target[key], source[key]);
46
+ } else {
47
+ Object.assign(target, { [key]: source[key] });
48
+ }
49
+ }
50
+ }
51
+
52
+ export function deepEqual(target, source) {
53
+ if (isObject(target) && isObject(target)) {
54
+ let isEqual = true;
55
+ for (const key in source) {
56
+ if (isEqual) {
57
+ isEqual = deepEqual(target[key], source[key]);
58
+ }
59
+ }
60
+
61
+ return isEqual;
62
+ }
63
+
64
+ return target === source;
65
+ }
@@ -3,60 +3,50 @@
3
3
 
4
4
  import Monitor from '../modules/Monitor.svelte';
5
5
  import Params from '../modules/Params.svelte';
6
- import { layout } from '../stores/layout';
7
- import { override, preview } from '../stores/rendering';
8
- import { sketches, sketchesKeys } from '../stores/sketches';
9
6
  import FloatingParams from './FloatingParams.svelte';
10
7
  import Column from './LayoutColumn.svelte';
11
8
  import Row from './LayoutRow.svelte';
9
+ import { sketchesManager } from '../state/sketches.svelte';
10
+ import { rendering } from '../state/rendering.svelte';
12
11
 
13
12
  console.log(`Made with Fragment. https://fragment.tools`);
14
13
 
15
- let gui, style, head;
16
- let defaultGUIConfig = {
17
- position: 'float',
18
- align: 'right',
19
- size: 0.3,
20
- output: false,
21
- hidden: false,
22
- };
14
+ let sketchKey = $derived(sketchesManager.keys[0]);
23
15
 
24
- let guiConfig = defaultGUIConfig;
25
- $: sketchKey = $layout.previewing && $preview ? $preview : $sketchesKeys[0];
26
- $: sketch = $sketches[sketchKey];
16
+ let sketch = $derived(sketchesManager.sketches[sketchKey]);
27
17
 
28
- $: {
29
- if (sketch) {
30
- if (sketch.buildConfig) {
31
- override(sketch.buildConfig);
32
- }
33
-
34
- const config = sketch.buildConfig ? sketch.buildConfig : {};
35
- gui = config.gui;
18
+ let gui = $derived(sketch?.buildConfig?.gui);
19
+ let guiOutput = $derived(gui?.output);
20
+ let guiAlign = $derived(gui?.align ?? 'right');
21
+ let guiHidden = $derived(gui?.hidden);
22
+ let guiSize = $derived(gui?.size ?? 0.25);
23
+ let guiMinimize = $derived(gui?.minimize);
24
+ let guiPosition = $derived(gui?.position);
25
+ let styles = $derived(sketch?.buildConfig?.styles ?? '');
36
26
 
37
- if (gui && typeof gui === 'object') {
38
- guiConfig = {
39
- ...defaultGUIConfig,
40
- ...gui,
41
- };
42
- }
27
+ /** @type {HTMLHeadElement} */
28
+ let head;
29
+ /** @type {HTMLStyleElement} */
30
+ let style;
43
31
 
44
- const { styles = '' } = config;
45
-
46
- if (styles !== '') {
47
- head = document.getElementsByTagName('head')[0];
32
+ $effect(() => {
33
+ rendering.override(sketch?.buildConfig);
34
+ });
48
35
 
49
- if (style) {
50
- head.removeChild(style);
51
- }
36
+ $effect(() => {
37
+ if (styles !== '') {
38
+ head = document.getElementsByTagName('head')[0];
52
39
 
53
- style = document.createElement('style');
54
- style.setAttribute('type', 'text/css');
55
- style.appendChild(document.createTextNode(styles));
56
- head.appendChild(style);
40
+ if (style) {
41
+ head.removeChild(style);
57
42
  }
43
+
44
+ style = document.createElement('style');
45
+ style.setAttribute('type', 'text/css');
46
+ style.appendChild(document.createTextNode(styles));
47
+ head.appendChild(style);
58
48
  }
59
- }
49
+ });
60
50
 
61
51
  onDestroy(() => {
62
52
  if (style && head) {
@@ -65,34 +55,37 @@
65
55
  });
66
56
  </script>
67
57
 
68
- {#if gui}
69
- {#if guiConfig.position === 'fixed'}
58
+ {#if sketch}
59
+ {#if guiPosition === 'fixed'}
70
60
  <Row>
71
- {#if guiConfig.align === 'right'}
72
- <Column size={1 - guiConfig.size}>
73
- <Monitor hasHeader={false} {sketchKey} />
61
+ {#if guiAlign === 'left'}
62
+ <Column size={guiSize}>
63
+ <Params />
74
64
  </Column>
75
- <Column size={guiConfig.size}>
76
- <Params hasHeader={false} />
65
+ <Column size={1 - guiSize}>
66
+ <Monitor params={{ selected: sketchKey }} />
77
67
  </Column>
78
68
  {:else}
79
- <Column size={guiConfig.size}>
80
- <Params hasHeader={false} />
69
+ <Column size={1 - guiSize}>
70
+ <Monitor params={{ selected: sketchKey }} />
81
71
  </Column>
82
- <Column size={1 - guiConfig.size}>
83
- <Monitor hasHeader={false} {sketchKey} />
72
+ <Column size={guiSize}>
73
+ <Params />
84
74
  </Column>
85
75
  {/if}
86
76
  </Row>
87
77
  {:else}
88
- <Monitor hasHeader={false} {sketchKey} />
89
- <FloatingParams
90
- output={guiConfig.output}
91
- align={guiConfig.align}
92
- size={guiConfig.size}
93
- hidden={guiConfig.hidden}
94
- />
78
+ <Row>
79
+ <Monitor headless {sketchKey} params={{ selected: sketchKey }} />
80
+ {#if gui}
81
+ <FloatingParams
82
+ output={guiOutput}
83
+ align={guiAlign}
84
+ size={guiSize}
85
+ hidden={guiHidden}
86
+ minimize={guiMinimize}
87
+ />
88
+ {/if}
89
+ </Row>
95
90
  {/if}
96
- {:else}
97
- <Monitor hasHeader={false} />
98
91
  {/if}
@@ -1,5 +1,5 @@
1
1
  <script>
2
- import { clearErrors } from '../stores/errors';
2
+ import { clearErrors } from '../state/errors.svelte';
3
3
 
4
4
  export let error;
5
5
 
@@ -20,7 +20,7 @@
20
20
  ? error.stack
21
21
  .split('\n')
22
22
  .filter((line, i, s) => (s.length === 1 ? true : i !== 0))
23
- .filter((line) => !line.includes('/app'))
23
+ .filter((line) => !line.includes('/app/'))
24
24
  .map((line) => {
25
25
  // remove path to file in URL
26
26
  line = line.replace(
@@ -27,66 +27,42 @@
27
27
  </script>
28
28
 
29
29
  <script>
30
- import { createEventDispatcher } from 'svelte';
31
-
32
30
  import FieldSection from './FieldSection.svelte';
33
31
  import FieldTriggers from './FieldTriggers.svelte';
34
32
  import { download } from '../utils/file.utils.js';
35
33
  import { map } from '../utils/math.utils';
36
34
  import frameDebounce from '../lib/helpers/frameDebounce.js';
37
- import { getStore } from '../stores/utils';
38
- import { writable } from 'svelte/store';
39
35
  import { inferFieldType } from '../utils/fields.utils.js';
40
-
41
- export let key = '';
42
- export let value = null;
43
- export let initialValue = value;
44
- export let context = null;
45
- export let params = {};
46
- export let type = null;
47
- export let disabled = false;
48
- export let displayName = undefined;
49
- export let index = null;
50
-
51
- let offsetWidth;
52
- let showTriggers = false;
53
-
54
- const store = getStore(
55
- context,
56
- { props: {} },
57
- {
58
- persist: context !== null,
59
- },
60
- );
61
-
62
- if (!$store.props[key]) {
63
- $store.props[key] = { triggers: [] };
64
- }
65
-
66
- let triggers = writable(
67
- $store.props[key].triggers.filter(
68
- (trigger) => trigger.inputType !== undefined,
69
- ),
70
- );
71
- triggers.subscribe((all) => {
72
- store.update((curr) => {
73
- curr.props[key].triggers = all;
74
-
75
- return curr;
76
- });
77
- });
78
-
79
- const dispatch = createEventDispatcher();
36
+ import IconTriggers from '../components/IconTriggers.svelte';
37
+ import IconLocked from '../components/IconLocked.svelte';
38
+
39
+ let {
40
+ key,
41
+ value = null,
42
+ initialValue = value,
43
+ context = null,
44
+ params = $bindable({}),
45
+ type = null,
46
+ disabled = false,
47
+ displayName = undefined,
48
+ index = null,
49
+ onchange,
50
+ onclick = () => {},
51
+ children,
52
+ triggers = [],
53
+ } = $props();
54
+
55
+ let showTriggers = $state(false);
80
56
 
81
57
  const onTriggers = {
82
58
  checkbox: () => {
83
59
  value = !value;
84
60
 
85
- dispatch('change', value);
61
+ onchange(value);
86
62
  },
87
63
  button: (event) => {
88
64
  value(event);
89
- dispatch('click', event);
65
+ onclick(event);
90
66
  },
91
67
  download: (event) => {
92
68
  let [data, filename] = value(event);
@@ -105,32 +81,23 @@
105
81
  let step = params.step ? params.step : 1;
106
82
  let value = Math.round(v * (1 / step)) / (1 / step);
107
83
 
108
- dispatch('change', value);
84
+ onchange(value);
109
85
  }
110
86
  },
111
87
  };
112
88
 
113
- $: fieldType = inferFieldType({ type, value, params, key });
114
- $: fieldProps = composeFieldProps(params, disabled);
115
- $: onTrigger = frameDebounce(onTriggers[fieldType]);
116
- $: input = fields[fieldType];
117
- $: triggerable =
89
+ let fieldType = $derived(inferFieldType({ type, value, params, key }));
90
+ let fieldProps = $derived(composeFieldProps(params, disabled));
91
+ let onTrigger = $derived(frameDebounce(onTriggers[fieldType]));
92
+ let input = $derived(fields[fieldType]);
93
+ let triggerable = $derived(
118
94
  params.triggerable !== false &&
119
- ((fieldType === fieldTypes.NUMBER &&
120
- isFinite(params.min) &&
121
- isFinite(params.max)) ||
122
- fieldType === fieldTypes.BUTTON);
123
- $: {
124
- const isDownload = fieldType === fieldTypes.DOWNLOAD;
125
- const isButton = fieldType === fieldTypes.BUTTON;
126
- if ((isDownload || isButton) && params.label == undefined) {
127
- fieldProps.label = isDownload ? 'download' : 'run';
128
- }
129
- }
130
- $: xxsmall = offsetWidth < 200;
131
- $: xsmall = !xxsmall && offsetWidth < 260;
132
- $: small = !xxsmall && !xsmall && offsetWidth < 320;
133
- $: triggersActive = $triggers.length > 0;
95
+ ((fieldType === fieldTypes.NUMBER &&
96
+ isFinite(params.min) &&
97
+ isFinite(params.max)) ||
98
+ fieldType === fieldTypes.BUTTON),
99
+ );
100
+ let triggersActive = $derived(triggers.length > 0);
134
101
 
135
102
  function toggleTriggers(event) {
136
103
  event.preventDefault();
@@ -153,140 +120,45 @@
153
120
  <div
154
121
  class="field"
155
122
  class:disabled
156
- class:xxsmall
157
- class:xsmall
158
- class:small
159
123
  class:changed={!disabled && hasChanged(initialValue, value)}
160
- bind:offsetWidth
161
124
  style="--index: {index};"
162
125
  >
163
126
  <FieldSection
164
127
  {key}
165
128
  {displayName}
166
129
  interactive={triggerable}
167
- on:click={toggleTriggers}
130
+ onclick={toggleTriggers}
168
131
  {disabled}
169
132
  >
170
- <div slot="infos" class="field__actions">
171
- {#if triggerable && !disabled}
172
- <button
173
- on:click={toggleTriggers}
174
- class="field__action field__action--triggers"
175
- class:active={triggersActive}
176
- >
177
- <svg width="16" height="16" fill="none" viewBox="0 0 24 24">
178
- <path
179
- stroke="currentColor"
180
- stroke-linecap="round"
181
- stroke-linejoin="round"
182
- stroke-width="1.5"
183
- d="M4.75 8H7.25"
184
- />
185
- <path
186
- stroke="currentColor"
187
- stroke-linecap="round"
188
- stroke-linejoin="round"
189
- stroke-width="1.5"
190
- d="M12.75 8H19.25"
191
- />
192
- <path
193
- stroke="currentColor"
194
- stroke-linecap="round"
195
- stroke-linejoin="round"
196
- stroke-width="1.5"
197
- d="M4.75 16H12.25"
198
- />
199
- <path
200
- stroke="currentColor"
201
- stroke-linecap="round"
202
- stroke-linejoin="round"
203
- stroke-width="1.5"
204
- d="M17.75 16H19.25"
205
- />
206
- <circle
207
- cx="10"
208
- cy="8"
209
- r="2.25"
210
- stroke="currentColor"
211
- stroke-linecap="round"
212
- stroke-linejoin="round"
213
- stroke-width="1.5"
214
- />
215
- <circle
216
- cx="15"
217
- cy="16"
218
- r="2.25"
219
- stroke="currentColor"
220
- stroke-linecap="round"
221
- stroke-linejoin="round"
222
- stroke-width="1.5"
223
- />
224
- </svg>
225
- </button>
226
- {/if}
227
- {#if fieldType === 'vec' && !disabled}
228
- <button
229
- class="field__action field__action--lock"
230
- on:click={() => (params.locked = !params.locked)}
231
- >
232
- {#if params.locked}
233
- <svg
234
- class="action__icon"
235
- width="16"
236
- height="16"
237
- fill="none"
238
- viewBox="0 0 24 24"
239
- >
240
- <path
241
- stroke="currentColor"
242
- stroke-linecap="round"
243
- stroke-linejoin="round"
244
- stroke-width="1.5"
245
- d="M5.75 11.75C5.75 11.1977 6.19772 10.75 6.75 10.75H17.25C17.8023 10.75 18.25 11.1977 18.25 11.75V17.25C18.25 18.3546 17.3546 19.25 16.25 19.25H7.75C6.64543 19.25 5.75 18.3546 5.75 17.25V11.75Z"
246
- />
247
- <path
248
- stroke="currentColor"
249
- stroke-linecap="round"
250
- stroke-linejoin="round"
251
- stroke-width="1.5"
252
- d="M7.75 10.5V10.3427C7.75 8.78147 7.65607 7.04125 8.74646 5.9239C9.36829 5.2867 10.3745 4.75 12 4.75C13.6255 4.75 14.6317 5.2867 15.2535 5.9239C16.3439 7.04125 16.25 8.78147 16.25 10.3427V10.5"
253
- />
254
- </svg>
255
- {:else}
256
- <svg
257
- class="action__icon"
258
- width="16"
259
- height="16"
260
- fill="none"
261
- viewBox="0 0 24 24"
262
- >
263
- <path
264
- stroke="currentColor"
265
- stroke-linecap="round"
266
- stroke-linejoin="round"
267
- stroke-width="1.5"
268
- d="M5.75 11.75C5.75 11.1977 6.19772 10.75 6.75 10.75H17.25C17.8023 10.75 18.25 11.1977 18.25 11.75V17.25C18.25 18.3546 17.3546 19.25 16.25 19.25H7.75C6.64543 19.25 5.75 18.3546 5.75 17.25V11.75Z"
269
- />
270
- <path
271
- stroke="currentColor"
272
- stroke-linecap="round"
273
- stroke-linejoin="round"
274
- stroke-width="1.5"
275
- d="M7.75 10.5V9.84343C7.75 8.61493 7.70093 7.29883 8.42416 6.30578C8.99862 5.51699 10.0568 4.75 12 4.75C14 4.75 15.25 6.25 15.25 6.25"
276
- />
277
- </svg>
278
- {/if}
279
- </button>
280
- {/if}
281
- </div>
133
+ {#snippet infos()}
134
+ <div class="field__actions">
135
+ {#if triggerable && !disabled}
136
+ <button
137
+ onclick={toggleTriggers}
138
+ class="field__action field__action--triggers"
139
+ class:active={triggersActive}
140
+ >
141
+ <IconTriggers />
142
+ </button>
143
+ {/if}
144
+ {#if fieldType === fieldTypes.VEC && !disabled}
145
+ <button
146
+ class="field__action field__action--lock"
147
+ onclick={() => (params.locked = !params.locked)}
148
+ >
149
+ <IconLocked locked={params.locked} />
150
+ </button>
151
+ {/if}
152
+ </div>
153
+ {/snippet}
282
154
  <svelte:component
283
155
  this={input}
284
156
  {value}
285
157
  {...fieldProps}
286
- on:change
287
- on:click={onTrigger}
158
+ {onchange}
159
+ onclick={onTrigger}
288
160
  />
289
- <slot />
161
+ {@render children?.()}
290
162
  </FieldSection>
291
163
  {#if triggerable}
292
164
  <FieldSection {key} visible={showTriggers} secondary>
@@ -294,8 +166,8 @@
294
166
  {triggers}
295
167
  {onTrigger}
296
168
  {context}
297
- triggerable={fieldType === 'button'}
298
- controllable={fieldType === 'number'}
169
+ triggerable={fieldType === fieldTypes.BUTTON}
170
+ controllable={fieldType === fieldTypes.NUMBER}
299
171
  />
300
172
  </FieldSection>
301
173
  {/if}
@@ -306,6 +178,8 @@
306
178
  --column-gap: 3px;
307
179
  --padding: 6px;
308
180
 
181
+ position: relative;
182
+
309
183
  width: 100%;
310
184
 
311
185
  padding: 3px 6px 3px 12px;
@@ -1,16 +1,15 @@
1
1
  <script>
2
- export let name;
3
-
4
- export let collapsed = false;
2
+ let { name, collapsed = false, children, onchange = () => {} } = $props();
5
3
 
6
4
  function handleClick() {
7
5
  collapsed = !collapsed;
6
+ onchange(collapsed);
8
7
  }
9
8
  </script>
10
9
 
11
10
  <div class="field-group {collapsed ? 'collapsed' : ''}">
12
11
  <header class="header">
13
- <button class="header__action" on:click={handleClick}>
12
+ <button class="header__action" onclick={handleClick}>
14
13
  <svg
15
14
  class="header__icon"
16
15
  width="24"
@@ -30,7 +29,7 @@
30
29
  </button>
31
30
  </header>
32
31
  <div class="content">
33
- <slot />
32
+ {@render children?.()}
34
33
  </div>
35
34
  </div>
36
35