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.
- package/dist/control/Color.svelte +45 -25
- package/dist/control/CubicBezier.svelte +0 -7
- package/dist/control/File.svelte +55 -0
- package/dist/control/File.svelte.d.ts +204 -0
- package/dist/control/Image.svelte +36 -2
- package/dist/control/Image.svelte.d.ts +18 -15
- package/dist/control/IntervalSlider.svelte +18 -14
- package/dist/control/Point.svelte +25 -26
- package/dist/control/RotationEuler.svelte +17 -12
- package/dist/control/RotationQuaternion.svelte +17 -12
- package/dist/control/Slider.svelte +2 -1
- package/dist/control/Stepper.svelte +30 -0
- package/dist/control/Stepper.svelte.d.ts +194 -0
- package/dist/core/Binding.svelte +18 -4
- package/dist/extra/AutoValue.svelte.d.ts +1 -1
- package/dist/extra/Element.svelte.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -5
- package/dist/internal/GenericBinding.svelte +4 -1
- package/dist/internal/GenericPane.svelte +12 -11
- package/dist/monitor/Profiler.svelte.d.ts +6 -0
- package/package.json +54 -39
- package/readme.md +7 -1
|
@@ -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
|
|
6
|
+
import { objectToTuple } from '../utils';
|
|
7
7
|
import { fillWith } from '../utils';
|
|
8
|
-
import { isColorObject,
|
|
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
|
|
18
|
-
if (
|
|
19
|
-
if (
|
|
20
|
-
internalValue =
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
40
|
+
console.error('Unreachable');
|
|
28
41
|
}
|
|
29
42
|
}
|
|
30
|
-
function
|
|
31
|
-
if (
|
|
32
|
-
if (
|
|
33
|
-
value =
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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,
|
|
53
|
-
$: internalValue,
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 `'
|
|
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 `'
|
|
28
|
+
* Image data as Base64-encoded string, or `undefined` to clear.
|
|
29
|
+
* @default `'undefined'`
|
|
30
30
|
* @bindable
|
|
31
31
|
*/
|
|
32
|
-
value:
|
|
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 &
|
|
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 '
|
|
148
|
+
* import { Button, Image, type ImageValue } from '..';
|
|
146
149
|
*
|
|
147
|
-
* let source
|
|
150
|
+
* let source: ImageValue;
|
|
148
151
|
*
|
|
149
152
|
* async function getRandomKittenUrl() {
|
|
150
|
-
* const { url } = await fetch(
|
|
151
|
-
* '
|
|
152
|
-
*
|
|
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 ===
|
|
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
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
internalValue = {
|
|
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
|
|
17
|
+
function updateValueFromInternalValue() {
|
|
19
18
|
if (Array.isArray(value)) {
|
|
20
|
-
const
|
|
21
|
-
value
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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,
|
|
43
|
-
$: internalValue,
|
|
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
|
|
24
|
+
function updateInternalValueFromValue() {
|
|
24
25
|
if (Array.isArray(value)) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
39
|
+
function updateValueFromInternalValue() {
|
|
40
40
|
if (Array.isArray(value)) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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,
|
|
56
|
-
$: internalValue,
|
|
54
|
+
$: value, updateInternalValueFromValue();
|
|
55
|
+
$: internalValue, updateValueFromInternalValue();
|
|
57
56
|
$: options = {
|
|
58
57
|
x: optionsX,
|
|
59
58
|
y: optionsY,
|