svelte-tweakpane-ui 1.3.3 → 1.5.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.
@@ -3,10 +3,11 @@
3
3
  <script>
4
4
  import ClsPad from '../internal/ClsPad.svelte';
5
5
  import GenericInputFolding from '../internal/GenericInputFolding.svelte';
6
- import { objectToTuple, tupleToObject } from '../utils';
6
+ import { objectToTuple } from '../utils';
7
7
  import { fillWith } from '../utils';
8
- import { isColorObject, isObject, isRgbaColorObject, isRgbColorObject } from '@tweakpane/core';
8
+ import { isColorObject, isRgbaColorObject, isRgbColorObject } from '@tweakpane/core';
9
9
  import { BROWSER } from 'esm-env';
10
+ import { shallowEqual } from 'fast-equals';
10
11
  export let value;
11
12
  export let expanded = void 0;
12
13
  export let type = void 0;
@@ -14,34 +15,53 @@
14
15
  let options;
15
16
  let ref;
16
17
  const buttonClass = 'tp-colswv_b';
17
- function updateInternalValue() {
18
- if (Array.isArray(value)) {
19
- if (value.length === 4) {
20
- internalValue = tupleToObject(value, ['r', 'g', 'b', 'a']);
21
- } else if (value.length === 3) {
22
- internalValue = tupleToObject(value, ['r', 'g', 'b']);
23
- } else {
18
+ function updateInternalValueFromValue() {
19
+ if (typeof value === 'string') {
20
+ if (internalValue !== value) {
21
+ internalValue = value;
22
+ }
23
+ } else if (isColorObject(value)) {
24
+ if (!shallowEqual(value, internalValue)) {
25
+ internalValue = { ...value };
26
+ }
27
+ } else if (Array.isArray(value)) {
28
+ let newInternalValue =
29
+ value.length === 4
30
+ ? { r: value[0], g: value[1], b: value[2], a: value[3] }
31
+ : value.length === 3
32
+ ? { r: value[0], g: value[1], b: value[2] }
33
+ : void 0;
34
+ if (newInternalValue === void 0) {
24
35
  console.error('Unreachable');
36
+ } else if (!shallowEqual(newInternalValue, internalValue)) {
37
+ internalValue = newInternalValue;
25
38
  }
26
39
  } else {
27
- internalValue = value;
40
+ console.error('Unreachable');
28
41
  }
29
42
  }
30
- function updateValue() {
31
- if (Array.isArray(value) && isColorObject(internalValue)) {
32
- if (isRgbaColorObject(internalValue)) {
33
- value = objectToTuple(internalValue, ['r', 'g', 'b', 'a']);
34
- } else if (isRgbColorObject(internalValue)) {
35
- value = objectToTuple(internalValue, ['r', 'g', 'b']);
36
- } else {
37
- console.error('Unreachable');
43
+ function updateValueFromInternalValue() {
44
+ if (typeof value === 'string' && typeof internalValue === 'string') {
45
+ if (internalValue !== value) {
46
+ value = internalValue;
47
+ }
48
+ } else if (Array.isArray(value) && isColorObject(internalValue)) {
49
+ const newValue = isRgbaColorObject(internalValue)
50
+ ? objectToTuple(internalValue, ['r', 'g', 'b', 'a'])
51
+ : isRgbColorObject(internalValue)
52
+ ? objectToTuple(internalValue, ['r', 'g', 'b'])
53
+ : void 0;
54
+ if (newValue === void 0) {
55
+ console.error('Unreachable color type mismatch');
56
+ } else if (!shallowEqual(newValue, value)) {
57
+ value = newValue;
58
+ }
59
+ } else if (isColorObject(value) && isColorObject(internalValue)) {
60
+ if (!shallowEqual(internalValue, value)) {
61
+ value = { ...internalValue };
38
62
  }
39
- } else if (typeof value === 'string') {
40
- value = internalValue;
41
- } else if (isObject(value)) {
42
- value = internalValue;
43
63
  } else {
44
- console.error('Unreachable');
64
+ console.error('Unreachable color type mismatch');
45
65
  }
46
66
  }
47
67
  function addListeners() {
@@ -49,8 +69,8 @@
49
69
  ref.refresh();
50
70
  });
51
71
  }
52
- $: value, updateInternalValue();
53
- $: internalValue, updateValue();
72
+ $: value, updateInternalValueFromValue();
73
+ $: internalValue, updateValueFromInternalValue();
54
74
  $: ref !== void 0 && addListeners();
55
75
  $: options = {
56
76
  color: {
@@ -82,10 +82,3 @@
82
82
  <ClsPad keysAdd={fillWith('containerUnitSpacing', 2)} theme={$$props.theme} />
83
83
  {/if}
84
84
  {/if}
85
-
86
- <style>
87
- /* Fix overflow bug from the plugin TODO PR */
88
- :global(div.svelte-tweakpane-ui div.tp-cbzv:not(tp-cbzv-expanded) div.tp-cbzv_p) {
89
- overflow: hidden !important;
90
- }
91
- </style>
@@ -0,0 +1,55 @@
1
+ <script context="module"></script>
2
+
3
+ <script>
4
+ import ClsPad from '../internal/ClsPad.svelte';
5
+ import GenericInput from '../internal/GenericInput.svelte';
6
+ import { fillWith } from '../utils';
7
+ import * as pluginModule from '@kitschpatrol/tweakpane-plugin-file-import';
8
+ import { BROWSER } from 'esm-env';
9
+ import { shallowEqual } from 'fast-equals';
10
+ export let value = void 0;
11
+ export let rows = void 0;
12
+ export let invalidExtensionMessage = void 0;
13
+ export let extensions = void 0;
14
+ let internalValue;
15
+ function updateInternalValueFromValue() {
16
+ const newInternalValue = value ?? '';
17
+ if (!shallowEqual(internalValue, newInternalValue)) {
18
+ internalValue = newInternalValue;
19
+ }
20
+ }
21
+ function updateValueFromInternalValue() {
22
+ if (internalValue instanceof File) {
23
+ if (!shallowEqual(value, internalValue)) {
24
+ value = internalValue;
25
+ }
26
+ } else if (value !== void 0) {
27
+ value = void 0;
28
+ }
29
+ }
30
+ let options;
31
+ $: options = {
32
+ extensions,
33
+ filetypes: extensions,
34
+ invalidFiletypeMessage: invalidExtensionMessage,
35
+ lineCount: rows,
36
+ view: 'file-input'
37
+ };
38
+ $: value, updateInternalValueFromValue();
39
+ $: internalValue, updateValueFromInternalValue();
40
+ </script>
41
+
42
+ <GenericInput
43
+ bind:value={internalValue}
44
+ on:change
45
+ {options}
46
+ plugin={pluginModule}
47
+ {...$$restProps}
48
+ />
49
+ {#if !BROWSER}
50
+ {#if rows}
51
+ <ClsPad keysAdd={fillWith('containerUnitSize', rows)} theme={$$props.theme} />
52
+ {:else}
53
+ <ClsPad keysAdd={fillWith('containerUnitSize', 3)} theme={$$props.theme} />
54
+ {/if}
55
+ {/if}
@@ -0,0 +1,204 @@
1
+ import { SvelteComponent } from 'svelte';
2
+ import type { ValueChangeEvent } from '../utils.js';
3
+ export type FileValue = File | undefined;
4
+ export type FileChangeEvent = ValueChangeEvent<FileValue>;
5
+ declare const __propDef: {
6
+ props: {
7
+ /**
8
+ * File data, or `undefined` to clear the file input.
9
+ * @default `undefined`
10
+ * @bindable
11
+ */
12
+ value?: FileValue;
13
+ /**
14
+ * Array of valid file extensions.
15
+ * @default Any file extension
16
+ */
17
+ extensions?: string[] | undefined;
18
+ /**
19
+ * String shown when the user tries to upload an invalid filetype.
20
+ * @default `'Unaccepted file type.'`
21
+ */
22
+ invalidExtensionMessage?: string | undefined;
23
+ /**
24
+ * Height of the file input drop zone, in rows.
25
+ * @default `3`
26
+ */
27
+ rows?: number | undefined;
28
+ } & Omit<
29
+ {
30
+ /**
31
+ * File data, or `undefined` to clear the file input.
32
+ * @default `undefined`
33
+ * @bindable
34
+ */
35
+ value: string | File | null;
36
+ } & Omit<
37
+ {
38
+ /**
39
+ * The binding's target object with values to manipulate.
40
+ * @bindable
41
+ */
42
+ object: import('@tweakpane/core').Bindable & Record<string, string | File | null>;
43
+ /** The key for the value in the target `object` that the control should manipulate. */
44
+ key: string;
45
+ /**
46
+ * Prevent interactivity and gray out the control.
47
+ * @default `false`
48
+ */
49
+ disabled?: boolean;
50
+ /**
51
+ * Text displayed next to control.
52
+ * @default `undefined`
53
+ */
54
+ label?: string | undefined;
55
+ /**
56
+ * Tweakpane's internal options object.
57
+ *
58
+ * See [`BindingParams`](https://tweakpane.github.io/docs/api/types/BindingParams.html).
59
+ *
60
+ * Valid types are contingent on the type of the value `key` points to in `object`.
61
+ *
62
+ * This is intended internal use, when implementing convenience components wrapping Binding's
63
+ * functionality. Options of interest are instead exposed as top-level props in _Svelte
64
+ * Tweakpane UI_.
65
+ * @default `undefined`
66
+ */
67
+ options?: import('@tweakpane/core').BaseInputParams | undefined;
68
+ /**
69
+ * Custom color scheme.
70
+ *
71
+ * @default `undefined` \
72
+ * Inherits default Tweakpane theme equivalent to `ThemeUtils.presets.standard`, or the theme
73
+ * set with `setGlobalDefaultTheme()`.
74
+ */
75
+ theme?: import('..').Theme | undefined;
76
+ /**
77
+ * Reference to internal Tweakpane
78
+ * [`BindingApi`](https://tweakpane.github.io/docs/api/classes/_internal_.BindingApi.html) for
79
+ * this control.
80
+ *
81
+ * This property is exposed for advanced use cases only, such as when implementing convenience
82
+ * components wrapping `<Binding>`'s functionality.
83
+ *
84
+ * Direct manipulation of Tweakpane's internals can break _Svelte Tweakpane UI_ abstractions.
85
+ *
86
+ * @bindable
87
+ * @readonly
88
+ */
89
+ ref?: import('../internal/GenericInput.svelte').GenericInputRef | undefined;
90
+ /**
91
+ * Imported Tweakpane `TpPluginBundle` (aliased as `Plugin`) module to automatically register in
92
+ * the `<Binding>`'s containing `<Pane>`.
93
+ *
94
+ * This property is exposed for advanced use cases only, such as when implementing convenience
95
+ * components wrapping `<Binding>`'s functionality in combination with a Tweakpane plugin.
96
+ *
97
+ * Direct manipulation of Tweakpane's internals can break _Svelte Tweakpane UI_ abstractions.
98
+ *
99
+ * @default `undefined`
100
+ */
101
+ plugin?: import('../utils.js').Plugin | undefined;
102
+ },
103
+ 'object' | 'key'
104
+ >,
105
+ 'ref' | 'plugin' | 'value'
106
+ >;
107
+ slots: {};
108
+ events: {
109
+ /**
110
+ * Fires when `value` changes.
111
+ *
112
+ * _This event is provided for advanced use cases. It's usually preferred to bind to the `value` prop instead._
113
+ *
114
+ * The `event.details` payload includes a copy of the value and an `origin` field to distinguish between user-interactive changes (`internal`)
115
+ * and changes resulting from programmatic manipulation of the `value` (`external`).
116
+ *
117
+ * @extends ValueChangeEvent
118
+ * @event
119
+ * */
120
+ change: FileChangeEvent;
121
+ };
122
+ };
123
+ export type FileProps = typeof __propDef.props;
124
+ export type FileEvents = typeof __propDef.events;
125
+ export type FileSlots = typeof __propDef.slots;
126
+ /**
127
+ * A file input control.
128
+ *
129
+ * _Important: This component has some rough edges, and should be considered experimental._
130
+ *
131
+ * Integrates the [File Input](https://github.com/LuchoTurtle/tweakpane-plugin-file-import/blob/main/src/plugin.ts) control from [LuchoTurtle's](https://github.com/LuchoTurtle) [tweakpane-plugin-file-import](https://github.com/LuchoTurtle/tweakpane-plugin-file-import) plugin. Some of the control's parameter names have been changed for consistency with the `<Image>` CompositionEvent.
132
+ *
133
+ * Use the `<Image>` control instead if you're working with images and want to see a thumbnail preview of the image.
134
+ *
135
+ * There is currently a known bug where change events' `origin` values are sometimes incorrect. (This issue is limited to this component.)
136
+ *
137
+ * Usage outside of a `<Pane>` component will implicitly wrap the image control in `<Pane position="inline">`.
138
+ *
139
+ * Note that _Svelte Tweakpane UI_ embeds a functionally identical [fork](https://github.com/kitschpatrol/tweakpane-plugin-file-import) of the plugin with build optimizations.
140
+ *
141
+ *
142
+ * @emits {FileChangeEvent} change - When `value` changes. (This event is provided for advanced use cases. Prefer binding to `value`.)
143
+ *
144
+ * @example
145
+ * ```svelte
146
+ * <script lang="ts">
147
+ * import { File, type FileValue } from '..';
148
+ *
149
+ * let file: FileValue;
150
+ *
151
+ * async function getFileBase64(file: FileValue): Promise<string> {
152
+ * if (file === undefined) return 'Your bytes here...';
153
+ * return new Promise((resolve, reject) => {
154
+ * const reader = new FileReader();
155
+ * reader.addEventListener('load', () => {
156
+ * const { result } = reader;
157
+ * if (result && typeof result === 'string') resolve(result);
158
+ * else reject(new Error('Empty result'));
159
+ * });
160
+ * reader.addEventListener('error', reject);
161
+ * reader.readAsDataURL(file);
162
+ * });
163
+ * }
164
+ *
165
+ * function truncate(text: string, length: number) {
166
+ * return text.length > length ? text.slice(0, length - 1) + '...' : text;
167
+ * }
168
+ * </script>
169
+ *
170
+ * <File bind:value={file} label="File" />
171
+ *
172
+ * <div class="demo">
173
+ * <p>
174
+ * {#await getFileBase64(file)}
175
+ * Loading...
176
+ * {:then value}
177
+ * {truncate(value, 512)}
178
+ * {/await}
179
+ * </p>
180
+ * </div>
181
+ *
182
+ * <style>
183
+ * .demo {
184
+ * width: 100%;
185
+ * background: linear-gradient(45deg, orange, magenta);
186
+ * }
187
+ *
188
+ * .demo > p {
189
+ * margin: 0;
190
+ * padding: 0.5rem;
191
+ * font-family: monospace;
192
+ * line-height: 1.2;
193
+ * color: white;
194
+ * word-break: break-all;
195
+ * white-space: pre-wrap;
196
+ * }
197
+ * </style>
198
+ * ```
199
+ *
200
+ * @sourceLink
201
+ * [File.svelte](https://github.com/kitschpatrol/svelte-tweakpane-ui/blob/main/src/lib/control/File.svelte)
202
+ */
203
+ export default class File extends SvelteComponent<FileProps, FileEvents, FileSlots> {}
204
+ export {};
@@ -6,18 +6,52 @@
6
6
  import { fillWith } from '../utils';
7
7
  import * as pluginModule from '@kitschpatrol/tweakpane-plugin-image';
8
8
  import { BROWSER } from 'esm-env';
9
- export let value = 'placeholder';
9
+ import { shallowEqual } from 'fast-equals';
10
+ export let value = void 0;
10
11
  export let fit = void 0;
11
12
  export let extensions = void 0;
13
+ let internalValue = 'placeholder';
14
+ function updateInternalValueFromValue() {
15
+ const newInternalValue = value ?? 'placeholder';
16
+ if (!shallowEqual(internalValue, newInternalValue)) {
17
+ internalValue = newInternalValue;
18
+ }
19
+ }
20
+ function updateValueFromInternalValue() {
21
+ if (internalValue === 'placeholder') {
22
+ if (value !== void 0) {
23
+ value = void 0;
24
+ }
25
+ } else if (internalValue instanceof HTMLImageElement) {
26
+ if (value !== internalValue.src) {
27
+ value = internalValue.src;
28
+ }
29
+ } else if (internalValue instanceof File) {
30
+ console.warn('Image control does not support File objects.');
31
+ if (value !== void 0) {
32
+ value = void 0;
33
+ }
34
+ } else if (value !== internalValue) {
35
+ value = internalValue;
36
+ }
37
+ }
12
38
  let options;
13
39
  $: options = {
14
40
  extensions,
15
41
  imageFit: fit,
16
42
  view: 'input-image'
17
43
  };
44
+ $: value, updateInternalValueFromValue();
45
+ $: internalValue, updateValueFromInternalValue();
18
46
  </script>
19
47
 
20
- <GenericInput bind:value on:change {options} plugin={pluginModule} {...$$restProps} />
48
+ <GenericInput
49
+ bind:value={internalValue}
50
+ on:change
51
+ {options}
52
+ plugin={pluginModule}
53
+ {...$$restProps}
54
+ />
21
55
  {#if !BROWSER}
22
56
  <ClsPad keysAdd={fillWith('containerVerticalPadding', 2)} theme={$$props.theme} />
23
57
  {/if}
@@ -1,12 +1,12 @@
1
1
  import { SvelteComponent } from 'svelte';
2
2
  import type { ValueChangeEvent } from '../utils.js';
3
- export type ImageValue = 'placeholder' | File | HTMLImageElement | string | undefined;
3
+ export type ImageValue = string | undefined;
4
4
  export type ImageChangeEvent = ValueChangeEvent<ImageValue>;
5
5
  declare const __propDef: {
6
6
  props: {
7
7
  /**
8
- * Image data
9
- * @default `'placeholder'`
8
+ * Image data as Base64-encoded string, or `undefined` to clear.
9
+ * @default `'undefined'`
10
10
  * @bindable
11
11
  */
12
12
  value?: ImageValue;
@@ -25,18 +25,19 @@ declare const __propDef: {
25
25
  } & Omit<
26
26
  {
27
27
  /**
28
- * Image data
29
- * @default `'placeholder'`
28
+ * Image data as Base64-encoded string, or `undefined` to clear.
29
+ * @default `'undefined'`
30
30
  * @bindable
31
31
  */
32
- value: ImageValue;
32
+ value: string | HTMLImageElement | File | undefined;
33
33
  } & Omit<
34
34
  {
35
35
  /**
36
36
  * The binding's target object with values to manipulate.
37
37
  * @bindable
38
38
  */
39
- object: import('@tweakpane/core').Bindable & Record<string, ImageValue>;
39
+ object: import('@tweakpane/core').Bindable &
40
+ Record<string, string | HTMLImageElement | File | undefined>;
40
41
  /** The key for the value in the target `object` that the control should manipulate. */
41
42
  key: string;
42
43
  /**
@@ -130,6 +131,8 @@ export type ImageSlots = typeof __propDef.slots;
130
131
  * Dias](https://www.linkedin.com/in/matheusdbs/), [Palash Bansal](https://github.com/repalash), and
131
132
  * others.
132
133
  *
134
+ * Use the `<File>` control instead if you're working with other file types, or don't wish to display a thumbnail preview of an uploaded image.
135
+ *
133
136
  * There is currently a known bug where change events' `origin` values are sometimes incorrect. (This issue is limited to this component.)
134
137
  *
135
138
  * Usage outside of a `<Pane>` component will implicitly wrap the image control in `<Pane
@@ -142,15 +145,15 @@ export type ImageSlots = typeof __propDef.slots;
142
145
  * @example
143
146
  * ```svelte
144
147
  * <script lang="ts">
145
- * import { Button, Image } from 'svelte-tweakpane-ui';
148
+ * import { Button, Image, type ImageValue } from '..';
146
149
  *
147
- * let source = 'placeholder';
150
+ * let source: ImageValue;
148
151
  *
149
152
  * async function getRandomKittenUrl() {
150
- * const { url } = await fetch(
151
- * 'https://source.unsplash.com/800x800/?kitten',
152
- * { method: 'HEAD', redirect: 'follow' }
153
- * );
153
+ * const { url } = await fetch('https://loremflickr.com/800/800/kitten', {
154
+ * method: 'HEAD',
155
+ * redirect: 'follow'
156
+ * });
154
157
  * return url;
155
158
  * }
156
159
  * </script>
@@ -165,9 +168,9 @@ export type ImageSlots = typeof __propDef.slots;
165
168
  * />
166
169
  *
167
170
  * <div class="demo">
168
- * {#if source === 'placeholder'}
171
+ * {#if source === undefined}
169
172
  * <p>Tap “No Image” above to load an image from disk.</p>
170
- * {:else}
173
+ * {:else if typeof source === 'string'}
171
174
  * <img alt="" src={source} />
172
175
  * {/if}
173
176
  * </div>
@@ -3,30 +3,34 @@
3
3
  <script>
4
4
  import GenericSlider from '../internal/GenericSlider.svelte';
5
5
  import * as pluginModule from '@kitschpatrol/tweakpane-plugin-essentials';
6
+ import { shallowEqual } from 'fast-equals';
6
7
  export let value;
7
8
  export let meanValue = void 0;
8
9
  export let wide = void 0;
9
10
  let internalValue;
10
- function updateInternalValue() {
11
- if (Array.isArray(value)) {
12
- const [min, max] = value;
13
- internalValue = { min, max };
14
- } else {
15
- internalValue = value;
11
+ function updateInternalValueFromValue() {
12
+ const newInternalValue = Array.isArray(value) ? { min: value[0], max: value[1] } : value;
13
+ if (!shallowEqual(internalValue, newInternalValue)) {
14
+ internalValue = { ...newInternalValue };
16
15
  }
17
16
  }
18
- function updateValue() {
17
+ function updateValueFromInternalValue() {
19
18
  if (Array.isArray(value)) {
20
- const { min, max } = internalValue;
21
- value = [min, max];
22
- } else {
23
- value = internalValue;
19
+ const newValue = [internalValue.min, internalValue.max];
20
+ if (!shallowEqual(value, newValue)) {
21
+ value = newValue;
22
+ }
23
+ } else if (!shallowEqual(value, internalValue)) {
24
+ value = { ...internalValue };
24
25
  }
25
26
  }
26
27
  function updateValueFromMean() {
27
28
  if (meanValue !== void 0) {
28
29
  const r = internalValue.max - internalValue.min;
29
- internalValue = { min: meanValue - r / 2, max: meanValue + r / 2 };
30
+ const valueFromMean = { min: meanValue - r / 2, max: meanValue + r / 2 };
31
+ if (!shallowEqual(valueFromMean, internalValue)) {
32
+ internalValue = valueFromMean;
33
+ }
30
34
  }
31
35
  }
32
36
  let ref;
@@ -39,8 +43,8 @@
39
43
  }
40
44
  }
41
45
  $: ref && wide !== void 0 && updateWide(wide);
42
- $: value, updateInternalValue();
43
- $: internalValue, updateValue();
46
+ $: value, updateInternalValueFromValue();
47
+ $: internalValue, updateValueFromInternalValue();
44
48
  $: meanValue = (internalValue.min + internalValue.max) / 2;
45
49
  $: meanValue, updateValueFromMean();
46
50
  </script>
@@ -5,6 +5,7 @@
5
5
  import GenericInputFolding from '../internal/GenericInputFolding.svelte';
6
6
  import { removeKeys } from '../utils';
7
7
  import { BROWSER } from 'esm-env';
8
+ import { shallowEqual } from 'fast-equals';
8
9
  export let value;
9
10
  export let expanded = $$props.expanded ?? void 0;
10
11
  let pointerScale = $$props['pointerScale'] ?? void 0;
@@ -20,40 +21,38 @@
20
21
  let internalValue;
21
22
  let options;
22
23
  const buttonClass = 'tp-p2dv_b';
23
- function updateInternalValue() {
24
+ function updateInternalValueFromValue() {
24
25
  if (Array.isArray(value)) {
25
- if (value.length === 4) {
26
- const [x, y, z, w] = value;
27
- internalValue = { x, y, z, w };
28
- } else if (value.length === 3) {
29
- const [x, y, z] = value;
30
- internalValue = { x, y, z };
31
- } else {
32
- const [x, y] = value;
33
- internalValue = { x, y };
26
+ const newInternalValue =
27
+ value.length === 4
28
+ ? { x: value[0], y: value[1], z: value[2], w: value[3] }
29
+ : value.length === 3
30
+ ? { x: value[0], y: value[1], z: value[2] }
31
+ : { x: value[0], y: value[1] };
32
+ if (!shallowEqual(internalValue, newInternalValue)) {
33
+ internalValue = newInternalValue;
34
34
  }
35
- } else {
36
- internalValue = value;
35
+ } else if (!shallowEqual(internalValue, value)) {
36
+ internalValue = { ...value };
37
37
  }
38
38
  }
39
- function updateValue() {
39
+ function updateValueFromInternalValue() {
40
40
  if (Array.isArray(value)) {
41
- if ('w' in internalValue) {
42
- const { x, y, z, w } = internalValue;
43
- value = [x, y, z, w];
44
- } else if ('z' in internalValue) {
45
- const { x, y, z } = internalValue;
46
- value = [x, y, z];
47
- } else {
48
- const { x, y } = internalValue;
49
- value = [x, y];
41
+ const newValue =
42
+ 'w' in internalValue
43
+ ? [internalValue.x, internalValue.y, internalValue.z, internalValue.w]
44
+ : 'z' in internalValue
45
+ ? [internalValue.x, internalValue.y, internalValue.z]
46
+ : [internalValue.x, internalValue.y];
47
+ if (!shallowEqual(value, newValue)) {
48
+ value = newValue;
50
49
  }
51
- } else {
52
- value = internalValue;
50
+ } else if (!shallowEqual(value, internalValue)) {
51
+ value = { ...internalValue };
53
52
  }
54
53
  }
55
- $: value, updateInternalValue();
56
- $: internalValue, updateValue();
54
+ $: value, updateInternalValueFromValue();
55
+ $: internalValue, updateValueFromInternalValue();
57
56
  $: options = {
58
57
  x: optionsX,
59
58
  y: optionsY,