@pixerate/editor-react 0.76.0 → 0.78.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/PaintGradientEditorView-CCPCY5Ib.d.cts +14 -0
- package/dist/PaintGradientEditorView-CCPCY5Ib.d.ts +14 -0
- package/dist/canvas/index.cjs +662 -561
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +36 -5
- package/dist/canvas/index.d.ts +36 -5
- package/dist/canvas/index.js +232 -129
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-LWMUV5TC.js → chunk-2EW42UXC.js} +639 -461
- package/dist/chunk-2EW42UXC.js.map +1 -0
- package/dist/chunk-FX3EREF5.js +206 -0
- package/dist/chunk-FX3EREF5.js.map +1 -0
- package/dist/chunk-MO354USR.js +126 -0
- package/dist/chunk-MO354USR.js.map +1 -0
- package/dist/chunk-ZQZAKUUM.js +416 -0
- package/dist/chunk-ZQZAKUUM.js.map +1 -0
- package/dist/effects/index.cjs +606 -0
- package/dist/effects/index.cjs.map +1 -0
- package/dist/effects/index.d.cts +80 -0
- package/dist/effects/index.d.ts +80 -0
- package/dist/effects/index.js +16 -0
- package/dist/effects/index.js.map +1 -0
- package/dist/image-editor/index.cjs +1388 -534
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +36 -3
- package/dist/image-editor/index.d.ts +36 -3
- package/dist/image-editor/index.js +10 -1
- package/dist/index.cjs +1806 -952
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/paint-editor/index.cjs +438 -289
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +8 -3
- package/dist/paint-editor/index.d.ts +8 -3
- package/dist/paint-editor/index.js +215 -187
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/parameters/index.js +55 -439
- package/dist/parameters/index.js.map +1 -1
- package/dist/video-editor/index.cjs +732 -17
- package/dist/video-editor/index.cjs.map +1 -1
- package/dist/video-editor/index.d.cts +31 -3
- package/dist/video-editor/index.d.ts +31 -3
- package/dist/video-editor/index.js +184 -17
- package/dist/video-editor/index.js.map +1 -1
- package/package.json +8 -3
- package/dist/chunk-LWMUV5TC.js.map +0 -1
package/dist/parameters/index.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KeyframeDiamond,
|
|
3
|
+
ParameterColor,
|
|
4
|
+
ParameterCommitInput,
|
|
5
|
+
ParameterFieldControl,
|
|
6
|
+
ParameterImage,
|
|
7
|
+
ParameterNumberInput,
|
|
8
|
+
ParameterSelect,
|
|
9
|
+
ParameterSlider,
|
|
10
|
+
ParameterText,
|
|
11
|
+
ParameterToggle,
|
|
12
|
+
ParameterVector,
|
|
13
|
+
parameterButtonClass,
|
|
14
|
+
parameterInputClass
|
|
15
|
+
} from "../chunk-ZQZAKUUM.js";
|
|
16
|
+
|
|
1
17
|
// src/parameters/useParameters.ts
|
|
2
18
|
import { useEffect, useMemo, useRef, useSyncExternalStore } from "react";
|
|
3
19
|
import {
|
|
@@ -51,414 +67,14 @@ function useParameterCommands(registry, controller, options = {}) {
|
|
|
51
67
|
}, [registry, controller, prefix, group, scope]);
|
|
52
68
|
}
|
|
53
69
|
|
|
54
|
-
// src/parameters/fields.tsx
|
|
55
|
-
import { useRef as useRef2 } from "react";
|
|
56
|
-
import {
|
|
57
|
-
choiceOptionLabel,
|
|
58
|
-
formatParameterNumber,
|
|
59
|
-
getChoiceOptions,
|
|
60
|
-
isSliderField,
|
|
61
|
-
normalizeHexColor,
|
|
62
|
-
parameterLabel,
|
|
63
|
-
parameterStep,
|
|
64
|
-
parseParameterNumberInput,
|
|
65
|
-
clampParameterNumber,
|
|
66
|
-
vectorComponentField,
|
|
67
|
-
vectorSize
|
|
68
|
-
} from "@pixerate/editor/parameters";
|
|
69
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
70
|
-
var parameterInputClass = "h-7 w-full min-w-0 rounded-md border border-input bg-background px-2 text-xs text-foreground tabular-nums focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
71
|
-
var parameterButtonClass = "inline-flex h-7 items-center justify-center gap-1 rounded-md border border-input bg-background px-2 text-xs text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:pointer-events-none disabled:opacity-50";
|
|
72
|
-
var rangeClass = "h-4 w-full min-w-0 flex-1 cursor-pointer accent-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
73
|
-
function ParameterCommitInput({ value, onCommit, multiline, className, onKeyDown, ...rest }) {
|
|
74
|
-
const commit = (el) => {
|
|
75
|
-
if (el.value !== value) onCommit(el.value, el);
|
|
76
|
-
};
|
|
77
|
-
const keyDown = (e) => {
|
|
78
|
-
onKeyDown?.(e);
|
|
79
|
-
if (e.defaultPrevented) return;
|
|
80
|
-
if (e.key === "Enter" && (!multiline || e.metaKey || e.ctrlKey)) {
|
|
81
|
-
e.preventDefault();
|
|
82
|
-
commit(e.currentTarget);
|
|
83
|
-
}
|
|
84
|
-
if (e.key === "Escape") e.currentTarget.value = value;
|
|
85
|
-
};
|
|
86
|
-
const props = {
|
|
87
|
-
defaultValue: value,
|
|
88
|
-
className: className ?? parameterInputClass,
|
|
89
|
-
onBlur: (e) => commit(e.currentTarget),
|
|
90
|
-
onKeyDown: keyDown,
|
|
91
|
-
...rest
|
|
92
|
-
};
|
|
93
|
-
return multiline ? /* @__PURE__ */ jsx("textarea", { ...props, className: `${props.className} h-auto min-h-[3.5rem] py-1` }, value) : /* @__PURE__ */ jsx("input", { type: "text", ...props }, value);
|
|
94
|
-
}
|
|
95
|
-
var plainNumber = (field, value) => formatParameterNumber({ ...field, unit: void 0 }, value);
|
|
96
|
-
function ParameterNumberInput({
|
|
97
|
-
field,
|
|
98
|
-
value,
|
|
99
|
-
onChange,
|
|
100
|
-
disabled,
|
|
101
|
-
id,
|
|
102
|
-
"aria-label": ariaLabel
|
|
103
|
-
}) {
|
|
104
|
-
return /* @__PURE__ */ jsxs("div", { className: "relative min-w-0 flex-1", children: [
|
|
105
|
-
/* @__PURE__ */ jsx(
|
|
106
|
-
ParameterCommitInput,
|
|
107
|
-
{
|
|
108
|
-
id,
|
|
109
|
-
inputMode: "decimal",
|
|
110
|
-
"aria-label": ariaLabel ?? parameterLabel(field),
|
|
111
|
-
value: plainNumber(field, value),
|
|
112
|
-
disabled: disabled || field.readOnly,
|
|
113
|
-
className: `${parameterInputClass} ${field.unit ? "pr-6" : ""}`,
|
|
114
|
-
onCommit: (text, input) => {
|
|
115
|
-
const n = parseParameterNumberInput(field, text);
|
|
116
|
-
if (n === null || n === value) input.value = plainNumber(field, value);
|
|
117
|
-
else onChange(n);
|
|
118
|
-
},
|
|
119
|
-
onKeyDown: (e) => {
|
|
120
|
-
if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return;
|
|
121
|
-
e.preventDefault();
|
|
122
|
-
const step = parameterStep(field) * (e.shiftKey ? 10 : 1);
|
|
123
|
-
onChange(clampParameterNumber(field, value + (e.key === "ArrowUp" ? step : -step)));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
),
|
|
127
|
-
field.unit && /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[10px] text-muted-foreground", children: field.unit })
|
|
128
|
-
] });
|
|
129
|
-
}
|
|
130
|
-
function ParameterSlider(props) {
|
|
131
|
-
const { field, value, onChange, onGestureStart, onGestureEnd, disabled } = props;
|
|
132
|
-
const dragging = useRef2(false);
|
|
133
|
-
const end = () => {
|
|
134
|
-
if (!dragging.current) return;
|
|
135
|
-
dragging.current = false;
|
|
136
|
-
onGestureEnd?.();
|
|
137
|
-
};
|
|
138
|
-
if (!isSliderField(field)) return /* @__PURE__ */ jsx(ParameterNumberInput, { ...props });
|
|
139
|
-
const step = parameterStep(field);
|
|
140
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
141
|
-
/* @__PURE__ */ jsx(
|
|
142
|
-
"input",
|
|
143
|
-
{
|
|
144
|
-
type: "range",
|
|
145
|
-
"aria-label": parameterLabel(field),
|
|
146
|
-
"aria-valuetext": formatParameterNumber(field, value),
|
|
147
|
-
min: field.min,
|
|
148
|
-
max: field.max,
|
|
149
|
-
step,
|
|
150
|
-
value,
|
|
151
|
-
disabled: disabled || field.readOnly,
|
|
152
|
-
className: rangeClass,
|
|
153
|
-
onPointerDown: () => {
|
|
154
|
-
if (dragging.current) return;
|
|
155
|
-
dragging.current = true;
|
|
156
|
-
onGestureStart?.();
|
|
157
|
-
},
|
|
158
|
-
onPointerUp: end,
|
|
159
|
-
onPointerCancel: end,
|
|
160
|
-
onBlur: end,
|
|
161
|
-
onChange: (e) => onChange(clampParameterNumber(field, Number(e.target.value)))
|
|
162
|
-
}
|
|
163
|
-
),
|
|
164
|
-
/* @__PURE__ */ jsx("div", { className: "w-20 shrink-0", children: /* @__PURE__ */ jsx(ParameterNumberInput, { ...props, id: props.id, "aria-label": `${parameterLabel(field)} value` }) })
|
|
165
|
-
] });
|
|
166
|
-
}
|
|
167
|
-
function ParameterToggle({ field, value, onChange, disabled, id }) {
|
|
168
|
-
return /* @__PURE__ */ jsx(
|
|
169
|
-
"button",
|
|
170
|
-
{
|
|
171
|
-
type: "button",
|
|
172
|
-
role: "switch",
|
|
173
|
-
id,
|
|
174
|
-
"aria-checked": value,
|
|
175
|
-
"aria-label": parameterLabel(field),
|
|
176
|
-
disabled: disabled || field.readOnly,
|
|
177
|
-
onClick: () => onChange(!value),
|
|
178
|
-
className: `relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-transparent transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:opacity-50 ${value ? "bg-primary" : "bg-muted"}`,
|
|
179
|
-
children: /* @__PURE__ */ jsx(
|
|
180
|
-
"span",
|
|
181
|
-
{
|
|
182
|
-
className: `pointer-events-none block h-4 w-4 rounded-full bg-background shadow transition-transform ${value ? "translate-x-4" : "translate-x-0.5"}`
|
|
183
|
-
}
|
|
184
|
-
)
|
|
185
|
-
}
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
function ParameterSelect({ field, value, onChange, disabled, id }) {
|
|
189
|
-
const options = getChoiceOptions(field);
|
|
190
|
-
const off = disabled || field.readOnly;
|
|
191
|
-
if (field.control === "segmented") {
|
|
192
|
-
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": parameterLabel(field), className: "inline-flex flex-wrap rounded-md border border-input bg-muted p-0.5", children: options.map((o) => /* @__PURE__ */ jsx(
|
|
193
|
-
"button",
|
|
194
|
-
{
|
|
195
|
-
type: "button",
|
|
196
|
-
role: "radio",
|
|
197
|
-
"aria-checked": o.value === value,
|
|
198
|
-
title: o.description,
|
|
199
|
-
disabled: off,
|
|
200
|
-
onClick: () => onChange(o.value),
|
|
201
|
-
className: `rounded px-2 py-0.5 text-xs disabled:opacity-50 ${o.value === value ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
202
|
-
children: choiceOptionLabel(o)
|
|
203
|
-
},
|
|
204
|
-
String(o.value)
|
|
205
|
-
)) });
|
|
206
|
-
}
|
|
207
|
-
const index = options.findIndex((o) => o.value === value);
|
|
208
|
-
return /* @__PURE__ */ jsx(
|
|
209
|
-
"select",
|
|
210
|
-
{
|
|
211
|
-
id,
|
|
212
|
-
"aria-label": parameterLabel(field),
|
|
213
|
-
value: String(index),
|
|
214
|
-
disabled: off,
|
|
215
|
-
onChange: (e) => {
|
|
216
|
-
const option = options[Number(e.target.value)];
|
|
217
|
-
if (option) onChange(option.value);
|
|
218
|
-
},
|
|
219
|
-
className: parameterInputClass,
|
|
220
|
-
children: options.map((o, i) => /* @__PURE__ */ jsx("option", { value: String(i), title: o.description, children: choiceOptionLabel(o) }, String(o.value)))
|
|
221
|
-
}
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
function ParameterColor({ field, value, onChange, onGestureStart, onGestureEnd, disabled, id }) {
|
|
225
|
-
const picking = useRef2(false);
|
|
226
|
-
const alpha = !!field.alpha;
|
|
227
|
-
const hex = normalizeHexColor(value, true) ?? "#000000ff";
|
|
228
|
-
const rgb = hex.slice(0, 7);
|
|
229
|
-
const a = hex.slice(7);
|
|
230
|
-
const off = disabled || field.readOnly;
|
|
231
|
-
const start = () => {
|
|
232
|
-
if (picking.current) return;
|
|
233
|
-
picking.current = true;
|
|
234
|
-
onGestureStart?.();
|
|
235
|
-
};
|
|
236
|
-
const end = () => {
|
|
237
|
-
if (!picking.current) return;
|
|
238
|
-
picking.current = false;
|
|
239
|
-
onGestureEnd?.();
|
|
240
|
-
};
|
|
241
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
242
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
243
|
-
/* @__PURE__ */ jsxs("span", { className: "relative h-7 w-9 shrink-0 overflow-hidden rounded-md border border-input bg-[repeating-conic-gradient(#d4d4d8_0_25%,#fff_0_50%)] bg-[length:8px_8px]", children: [
|
|
244
|
-
/* @__PURE__ */ jsx("span", { className: "absolute inset-0", style: { background: alpha ? hex : rgb } }),
|
|
245
|
-
/* @__PURE__ */ jsx(
|
|
246
|
-
"input",
|
|
247
|
-
{
|
|
248
|
-
type: "color",
|
|
249
|
-
"aria-label": parameterLabel(field),
|
|
250
|
-
value: rgb,
|
|
251
|
-
disabled: off,
|
|
252
|
-
className: "absolute inset-0 h-full w-full cursor-pointer opacity-0 disabled:cursor-not-allowed",
|
|
253
|
-
onChange: (e) => {
|
|
254
|
-
start();
|
|
255
|
-
onChange(alpha ? `${e.target.value}${a}` : e.target.value);
|
|
256
|
-
},
|
|
257
|
-
onBlur: end
|
|
258
|
-
}
|
|
259
|
-
)
|
|
260
|
-
] }),
|
|
261
|
-
/* @__PURE__ */ jsx(
|
|
262
|
-
ParameterCommitInput,
|
|
263
|
-
{
|
|
264
|
-
id,
|
|
265
|
-
"aria-label": `${parameterLabel(field)} hex`,
|
|
266
|
-
value: alpha ? hex : rgb,
|
|
267
|
-
disabled: off,
|
|
268
|
-
spellCheck: false,
|
|
269
|
-
className: `${parameterInputClass} font-mono`,
|
|
270
|
-
onCommit: (text) => {
|
|
271
|
-
const next = normalizeHexColor(text, alpha);
|
|
272
|
-
if (next) onChange(next);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
)
|
|
276
|
-
] }),
|
|
277
|
-
alpha && /* @__PURE__ */ jsx(
|
|
278
|
-
"input",
|
|
279
|
-
{
|
|
280
|
-
type: "range",
|
|
281
|
-
"aria-label": `${parameterLabel(field)} opacity`,
|
|
282
|
-
min: 0,
|
|
283
|
-
max: 255,
|
|
284
|
-
step: 1,
|
|
285
|
-
value: parseInt(a, 16),
|
|
286
|
-
disabled: off,
|
|
287
|
-
className: rangeClass,
|
|
288
|
-
onPointerDown: start,
|
|
289
|
-
onPointerUp: end,
|
|
290
|
-
onPointerCancel: end,
|
|
291
|
-
onBlur: end,
|
|
292
|
-
onChange: (e) => onChange(`${rgb}${Number(e.target.value).toString(16).padStart(2, "0")}`)
|
|
293
|
-
}
|
|
294
|
-
),
|
|
295
|
-
field.swatches && field.swatches.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: field.swatches.map((s) => {
|
|
296
|
-
const swatch = normalizeHexColor(s, alpha);
|
|
297
|
-
if (!swatch) return null;
|
|
298
|
-
return /* @__PURE__ */ jsx(
|
|
299
|
-
"button",
|
|
300
|
-
{
|
|
301
|
-
type: "button",
|
|
302
|
-
title: swatch,
|
|
303
|
-
"aria-label": `${parameterLabel(field)} ${swatch}`,
|
|
304
|
-
"aria-pressed": swatch === (alpha ? hex : rgb),
|
|
305
|
-
disabled: off,
|
|
306
|
-
onClick: () => onChange(swatch),
|
|
307
|
-
className: "h-5 w-5 rounded border border-input aria-pressed:ring-1 aria-pressed:ring-primary",
|
|
308
|
-
style: { background: swatch }
|
|
309
|
-
},
|
|
310
|
-
s
|
|
311
|
-
);
|
|
312
|
-
}) })
|
|
313
|
-
] });
|
|
314
|
-
}
|
|
315
|
-
function ParameterVector({ field, value, onChange, disabled, id }) {
|
|
316
|
-
const size = vectorSize(field);
|
|
317
|
-
return /* @__PURE__ */ jsx("div", { className: "grid gap-1.5", style: { gridTemplateColumns: `repeat(${size}, minmax(0, 1fr))` }, children: Array.from({ length: size }, (_, i) => {
|
|
318
|
-
const component = vectorComponentField(field, i);
|
|
319
|
-
return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 items-center gap-1", children: [
|
|
320
|
-
/* @__PURE__ */ jsx("span", { className: "w-3 shrink-0 text-[10px] uppercase text-muted-foreground", children: component.label }),
|
|
321
|
-
/* @__PURE__ */ jsx(
|
|
322
|
-
ParameterNumberInput,
|
|
323
|
-
{
|
|
324
|
-
field: component,
|
|
325
|
-
value: value[i] ?? 0,
|
|
326
|
-
id: i === 0 ? id : void 0,
|
|
327
|
-
"aria-label": `${parameterLabel(field)} ${component.label}`,
|
|
328
|
-
disabled: disabled || field.readOnly,
|
|
329
|
-
onChange: (n) => onChange(Array.from({ length: size }, (_2, j) => j === i ? n : value[j] ?? 0))
|
|
330
|
-
}
|
|
331
|
-
)
|
|
332
|
-
] }, i);
|
|
333
|
-
}) });
|
|
334
|
-
}
|
|
335
|
-
function ParameterImage({ field, value, onChange, disabled, id, resolveFile }) {
|
|
336
|
-
const off = disabled || field.readOnly;
|
|
337
|
-
const name = parameterLabel(field);
|
|
338
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
339
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
340
|
-
/* @__PURE__ */ jsx("div", { className: "flex h-12 w-16 shrink-0 items-center justify-center overflow-hidden rounded-md border border-input bg-muted", children: value ? /* @__PURE__ */ jsx("img", { src: value, alt: name, className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: "None" }) }),
|
|
341
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
|
|
342
|
-
/* @__PURE__ */ jsx(
|
|
343
|
-
ParameterCommitInput,
|
|
344
|
-
{
|
|
345
|
-
id,
|
|
346
|
-
"aria-label": `${name} URL`,
|
|
347
|
-
placeholder: "Image URL",
|
|
348
|
-
value: value.startsWith("data:") ? "" : value,
|
|
349
|
-
disabled: off,
|
|
350
|
-
onCommit: (text) => onChange(text.trim())
|
|
351
|
-
}
|
|
352
|
-
),
|
|
353
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
|
|
354
|
-
resolveFile && /* @__PURE__ */ jsxs("label", { className: `${parameterButtonClass} cursor-pointer ${off ? "pointer-events-none opacity-50" : ""}`, children: [
|
|
355
|
-
"Choose file\u2026",
|
|
356
|
-
/* @__PURE__ */ jsx(
|
|
357
|
-
"input",
|
|
358
|
-
{
|
|
359
|
-
type: "file",
|
|
360
|
-
className: "sr-only",
|
|
361
|
-
accept: field.accept ?? "image/*",
|
|
362
|
-
disabled: off,
|
|
363
|
-
"aria-label": `${name} file`,
|
|
364
|
-
onChange: async (e) => {
|
|
365
|
-
const file = e.target.files?.[0];
|
|
366
|
-
e.target.value = "";
|
|
367
|
-
if (file) onChange(await resolveFile(file));
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
)
|
|
371
|
-
] }),
|
|
372
|
-
value && /* @__PURE__ */ jsx("button", { type: "button", className: parameterButtonClass, disabled: off, onClick: () => onChange(""), "aria-label": `Clear ${name}`, children: "Clear" })
|
|
373
|
-
] })
|
|
374
|
-
] })
|
|
375
|
-
] }),
|
|
376
|
-
field.options && field.options.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: field.options.map((o) => /* @__PURE__ */ jsx(
|
|
377
|
-
"button",
|
|
378
|
-
{
|
|
379
|
-
type: "button",
|
|
380
|
-
title: o.label ?? o.url,
|
|
381
|
-
"aria-label": o.label ?? o.url,
|
|
382
|
-
"aria-pressed": o.url === value,
|
|
383
|
-
disabled: off,
|
|
384
|
-
onClick: () => onChange(o.url),
|
|
385
|
-
className: "h-9 w-12 overflow-hidden rounded border border-input aria-pressed:ring-2 aria-pressed:ring-primary",
|
|
386
|
-
children: /* @__PURE__ */ jsx("img", { src: o.url, alt: "", className: "h-full w-full object-cover" })
|
|
387
|
-
},
|
|
388
|
-
o.url
|
|
389
|
-
)) })
|
|
390
|
-
] });
|
|
391
|
-
}
|
|
392
|
-
function ParameterText({ field, value, onChange, disabled, id }) {
|
|
393
|
-
return /* @__PURE__ */ jsx(
|
|
394
|
-
ParameterCommitInput,
|
|
395
|
-
{
|
|
396
|
-
id,
|
|
397
|
-
"aria-label": parameterLabel(field),
|
|
398
|
-
multiline: field.multiline,
|
|
399
|
-
placeholder: field.placeholder,
|
|
400
|
-
maxLength: field.maxLength,
|
|
401
|
-
value,
|
|
402
|
-
disabled: disabled || field.readOnly,
|
|
403
|
-
onCommit: onChange
|
|
404
|
-
}
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
function KeyframeDiamond({ state, onToggle, label, disabled, className = "" }) {
|
|
408
|
-
const keyed = state === "keyed";
|
|
409
|
-
return /* @__PURE__ */ jsx(
|
|
410
|
-
"button",
|
|
411
|
-
{
|
|
412
|
-
type: "button",
|
|
413
|
-
"data-key-state": state,
|
|
414
|
-
"aria-pressed": keyed,
|
|
415
|
-
"aria-label": `${keyed ? "Remove" : "Add"} keyframe for ${label}`,
|
|
416
|
-
title: keyed ? "Remove keyframe here" : "Add keyframe at the playhead",
|
|
417
|
-
disabled,
|
|
418
|
-
onClick: onToggle,
|
|
419
|
-
className: `inline-flex h-4 w-4 shrink-0 items-center justify-center rounded-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary disabled:opacity-40 ${state === "none" ? "text-muted-foreground hover:text-foreground" : "text-amber-500"} ${className}`,
|
|
420
|
-
children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 10 10", className: "h-2.5 w-2.5", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
|
|
421
|
-
"path",
|
|
422
|
-
{
|
|
423
|
-
d: "M5 0.8 9.2 5 5 9.2 0.8 5Z",
|
|
424
|
-
fill: keyed ? "currentColor" : "none",
|
|
425
|
-
stroke: "currentColor",
|
|
426
|
-
strokeWidth: "1.3",
|
|
427
|
-
opacity: state === "animated" ? 0.7 : 1
|
|
428
|
-
}
|
|
429
|
-
) })
|
|
430
|
-
}
|
|
431
|
-
);
|
|
432
|
-
}
|
|
433
|
-
function ParameterFieldControl({ field, value, onChange, resolveFile, ...rest }) {
|
|
434
|
-
const set = onChange;
|
|
435
|
-
switch (field.type) {
|
|
436
|
-
case "number":
|
|
437
|
-
case "int":
|
|
438
|
-
return /* @__PURE__ */ jsx(ParameterSlider, { field, value, onChange: set, ...rest });
|
|
439
|
-
case "boolean":
|
|
440
|
-
return /* @__PURE__ */ jsx(ParameterToggle, { field, value, onChange: set, ...rest });
|
|
441
|
-
case "choice":
|
|
442
|
-
return /* @__PURE__ */ jsx(ParameterSelect, { field, value, onChange: set, ...rest });
|
|
443
|
-
case "color":
|
|
444
|
-
return /* @__PURE__ */ jsx(ParameterColor, { field, value, onChange: set, ...rest });
|
|
445
|
-
case "vector":
|
|
446
|
-
return /* @__PURE__ */ jsx(ParameterVector, { field, value, onChange: set, ...rest });
|
|
447
|
-
case "image":
|
|
448
|
-
return /* @__PURE__ */ jsx(ParameterImage, { field, value, onChange: set, resolveFile, ...rest });
|
|
449
|
-
case "text":
|
|
450
|
-
return /* @__PURE__ */ jsx(ParameterText, { field, value, onChange: set, ...rest });
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
70
|
// src/parameters/ParametersPanel.tsx
|
|
455
71
|
import { useId, useState } from "react";
|
|
456
72
|
import {
|
|
457
73
|
isParameterGroup,
|
|
458
|
-
parameterLabel
|
|
74
|
+
parameterLabel,
|
|
459
75
|
parameterValuesEqual
|
|
460
76
|
} from "@pixerate/editor/parameters";
|
|
461
|
-
import { jsx
|
|
77
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
462
78
|
function FieldRow({
|
|
463
79
|
controller,
|
|
464
80
|
state,
|
|
@@ -468,16 +84,16 @@ function FieldRow({
|
|
|
468
84
|
showFieldReset,
|
|
469
85
|
resolveFile
|
|
470
86
|
}) {
|
|
471
|
-
const label =
|
|
87
|
+
const label = parameterLabel(field);
|
|
472
88
|
const inputId = `${idBase}-${field.id}`;
|
|
473
89
|
const value = state.values[field.id];
|
|
474
90
|
const error = state.errors[field.id];
|
|
475
91
|
const changed = !parameterValuesEqual(value, state.defaults[field.id]);
|
|
476
|
-
return /* @__PURE__ */
|
|
477
|
-
/* @__PURE__ */
|
|
478
|
-
showKeyframes && /* @__PURE__ */
|
|
479
|
-
/* @__PURE__ */
|
|
480
|
-
showFieldReset && changed && !field.readOnly && /* @__PURE__ */
|
|
92
|
+
return /* @__PURE__ */ jsxs("div", { "data-parameter-id": field.id, "data-parameter-type": field.type, className: "space-y-1", children: [
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-[1.25rem] items-center gap-1.5", children: [
|
|
94
|
+
showKeyframes && /* @__PURE__ */ jsx(KeyframeDiamond, { state: state.keys[field.id] ?? "none", label, onToggle: () => controller.toggleKeyframe(field.id) }),
|
|
95
|
+
/* @__PURE__ */ jsx("label", { htmlFor: inputId, className: "min-w-0 flex-1 truncate text-xs font-medium text-foreground", title: field.description, children: label }),
|
|
96
|
+
showFieldReset && changed && !field.readOnly && /* @__PURE__ */ jsx(
|
|
481
97
|
"button",
|
|
482
98
|
{
|
|
483
99
|
type: "button",
|
|
@@ -489,8 +105,8 @@ function FieldRow({
|
|
|
489
105
|
}
|
|
490
106
|
)
|
|
491
107
|
] }),
|
|
492
|
-
field.description && /* @__PURE__ */
|
|
493
|
-
/* @__PURE__ */
|
|
108
|
+
field.description && /* @__PURE__ */ jsx("p", { className: "text-[11px] leading-snug text-muted-foreground", children: field.description }),
|
|
109
|
+
/* @__PURE__ */ jsx(
|
|
494
110
|
ParameterFieldControl,
|
|
495
111
|
{
|
|
496
112
|
field,
|
|
@@ -502,7 +118,7 @@ function FieldRow({
|
|
|
502
118
|
onGestureEnd: () => controller.endGesture()
|
|
503
119
|
}
|
|
504
120
|
),
|
|
505
|
-
error && /* @__PURE__ */
|
|
121
|
+
error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[11px] text-destructive", children: error })
|
|
506
122
|
] });
|
|
507
123
|
}
|
|
508
124
|
function PresetBar({ controller, state }) {
|
|
@@ -519,9 +135,9 @@ function PresetBar({ controller, state }) {
|
|
|
519
135
|
setMessage(null);
|
|
520
136
|
} else setMessage(result.message);
|
|
521
137
|
};
|
|
522
|
-
return /* @__PURE__ */
|
|
523
|
-
/* @__PURE__ */
|
|
524
|
-
/* @__PURE__ */
|
|
138
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", "data-parameter-presets": "", children: [
|
|
139
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
140
|
+
/* @__PURE__ */ jsxs(
|
|
525
141
|
"select",
|
|
526
142
|
{
|
|
527
143
|
"aria-label": "Preset",
|
|
@@ -529,16 +145,16 @@ function PresetBar({ controller, state }) {
|
|
|
529
145
|
value: state.activePreset ?? "",
|
|
530
146
|
onChange: (e) => e.target.value && controller.applyPreset(e.target.value),
|
|
531
147
|
children: [
|
|
532
|
-
/* @__PURE__ */
|
|
533
|
-
state.presets.map((p) => /* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ jsx("option", { value: "", children: state.presets.length ? "Presets\u2026" : "No presets" }),
|
|
149
|
+
state.presets.map((p) => /* @__PURE__ */ jsx("option", { value: p.name, title: p.description, children: p.name }, p.name))
|
|
534
150
|
]
|
|
535
151
|
}
|
|
536
152
|
),
|
|
537
|
-
/* @__PURE__ */
|
|
538
|
-
active && !active.builtIn && /* @__PURE__ */
|
|
153
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: parameterButtonClass, onClick: () => setSaving((s) => !s), "aria-expanded": saving, children: "Save\u2026" }),
|
|
154
|
+
active && !active.builtIn && /* @__PURE__ */ jsx("button", { type: "button", className: parameterButtonClass, "aria-label": `Delete preset ${active.name}`, onClick: () => controller.deletePreset(active.name), children: "Delete" })
|
|
539
155
|
] }),
|
|
540
|
-
saving && /* @__PURE__ */
|
|
541
|
-
/* @__PURE__ */
|
|
156
|
+
saving && /* @__PURE__ */ jsxs("form", { className: "flex items-center gap-1.5", onSubmit: save, children: [
|
|
157
|
+
/* @__PURE__ */ jsx(
|
|
542
158
|
"input",
|
|
543
159
|
{
|
|
544
160
|
autoFocus: true,
|
|
@@ -549,9 +165,9 @@ function PresetBar({ controller, state }) {
|
|
|
549
165
|
onChange: (e) => setName(e.target.value)
|
|
550
166
|
}
|
|
551
167
|
),
|
|
552
|
-
/* @__PURE__ */
|
|
168
|
+
/* @__PURE__ */ jsx("button", { type: "submit", className: parameterButtonClass, children: "Save" })
|
|
553
169
|
] }),
|
|
554
|
-
message && /* @__PURE__ */
|
|
170
|
+
message && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-[11px] text-destructive", children: message })
|
|
555
171
|
] });
|
|
556
172
|
}
|
|
557
173
|
function ParametersPanel({
|
|
@@ -572,7 +188,7 @@ function ParametersPanel({
|
|
|
572
188
|
const renderItems = (items) => items.map((item) => {
|
|
573
189
|
if (state.visible[item.id] === false) return null;
|
|
574
190
|
if (isParameterGroup(item)) return renderGroup(item);
|
|
575
|
-
return /* @__PURE__ */
|
|
191
|
+
return /* @__PURE__ */ jsx(
|
|
576
192
|
FieldRow,
|
|
577
193
|
{
|
|
578
194
|
controller,
|
|
@@ -589,8 +205,8 @@ function ParametersPanel({
|
|
|
589
205
|
const renderGroup = (group) => {
|
|
590
206
|
const collapsed = !!state.collapsed[group.id];
|
|
591
207
|
const bodyId = `${idBase}-group-${group.id}`;
|
|
592
|
-
return /* @__PURE__ */
|
|
593
|
-
/* @__PURE__ */
|
|
208
|
+
return /* @__PURE__ */ jsxs("section", { "data-parameter-group": group.id, className: "rounded-md border border-border", children: [
|
|
209
|
+
/* @__PURE__ */ jsxs(
|
|
594
210
|
"button",
|
|
595
211
|
{
|
|
596
212
|
type: "button",
|
|
@@ -599,22 +215,22 @@ function ParametersPanel({
|
|
|
599
215
|
onClick: () => controller.toggleCollapsed(group.id),
|
|
600
216
|
className: "flex w-full items-center gap-1.5 px-2 py-1.5 text-left text-xs font-semibold text-foreground hover:bg-muted",
|
|
601
217
|
children: [
|
|
602
|
-
/* @__PURE__ */
|
|
603
|
-
|
|
218
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: `inline-block text-[10px] text-muted-foreground transition-transform ${collapsed ? "" : "rotate-90"}`, children: "\u25B6" }),
|
|
219
|
+
parameterLabel(group)
|
|
604
220
|
]
|
|
605
221
|
}
|
|
606
222
|
),
|
|
607
|
-
!collapsed && /* @__PURE__ */
|
|
608
|
-
group.description && /* @__PURE__ */
|
|
223
|
+
!collapsed && /* @__PURE__ */ jsxs("div", { id: bodyId, className: "space-y-3 border-t border-border px-2 py-2", children: [
|
|
224
|
+
group.description && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: group.description }),
|
|
609
225
|
renderItems(group.fields)
|
|
610
226
|
] })
|
|
611
227
|
] }, group.id);
|
|
612
228
|
};
|
|
613
|
-
return /* @__PURE__ */
|
|
614
|
-
(heading || showToolbar) && /* @__PURE__ */
|
|
615
|
-
heading && /* @__PURE__ */
|
|
616
|
-
showToolbar && /* @__PURE__ */
|
|
617
|
-
/* @__PURE__ */
|
|
229
|
+
return /* @__PURE__ */ jsxs("div", { className: `space-y-3 text-foreground ${className}`, "data-parameters-panel": "", children: [
|
|
230
|
+
(heading || showToolbar) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
|
|
231
|
+
heading && /* @__PURE__ */ jsx("h3", { className: "mr-auto text-sm font-semibold", children: heading }),
|
|
232
|
+
showToolbar && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1", role: "toolbar", "aria-label": "Parameter actions", children: [
|
|
233
|
+
/* @__PURE__ */ jsx(
|
|
618
234
|
"button",
|
|
619
235
|
{
|
|
620
236
|
type: "button",
|
|
@@ -625,7 +241,7 @@ function ParametersPanel({
|
|
|
625
241
|
children: "Undo"
|
|
626
242
|
}
|
|
627
243
|
),
|
|
628
|
-
/* @__PURE__ */
|
|
244
|
+
/* @__PURE__ */ jsx(
|
|
629
245
|
"button",
|
|
630
246
|
{
|
|
631
247
|
type: "button",
|
|
@@ -636,12 +252,12 @@ function ParametersPanel({
|
|
|
636
252
|
children: "Redo"
|
|
637
253
|
}
|
|
638
254
|
),
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
255
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: parameterButtonClass, disabled: !state.modified, onClick: () => controller.reset(), children: "Reset" }),
|
|
256
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: parameterButtonClass, onClick: () => controller.randomize(), children: "Randomize" })
|
|
641
257
|
] })
|
|
642
258
|
] }),
|
|
643
|
-
showPresets && /* @__PURE__ */
|
|
644
|
-
state.fields.length === 0 ? /* @__PURE__ */
|
|
259
|
+
showPresets && /* @__PURE__ */ jsx(PresetBar, { controller, state }),
|
|
260
|
+
state.fields.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: emptyMessage }) : renderItems(state.schema.fields)
|
|
645
261
|
] });
|
|
646
262
|
}
|
|
647
263
|
export {
|