@pixerate/editor-svelte 0.149.0 → 0.151.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/image-editor/RefineEdgePanel.svelte +15 -1
- package/dist/image-editor/SelectAndMaskWorkspace.svelte +279 -0
- package/dist/image-editor/SelectAndMaskWorkspace.svelte.d.ts +16 -0
- package/dist/image-editor/SelectionOptionsBar.svelte +6 -0
- package/dist/image-editor/index.d.ts +3 -0
- package/dist/image-editor/index.js +1 -0
- package/package.json +2 -2
|
@@ -50,6 +50,11 @@
|
|
|
50
50
|
let newKind = $state<AdjustmentKind>('hueSaturation');
|
|
51
51
|
let output = $state<RefineOutput>('selection');
|
|
52
52
|
let decontaminate = $state(0);
|
|
53
|
+
let objectAware = $state(false);
|
|
54
|
+
const canObject = $derived.by(() => {
|
|
55
|
+
void tick;
|
|
56
|
+
return Boolean(controller.segmentationProvider);
|
|
57
|
+
});
|
|
53
58
|
const toLayer = $derived(output === 'new-layer' || output === 'new-layer-with-mask');
|
|
54
59
|
const target = $derived(list.find((l) => l.id === layerId) ?? list[list.length - 1]);
|
|
55
60
|
|
|
@@ -57,7 +62,10 @@
|
|
|
57
62
|
busy = true;
|
|
58
63
|
error = null;
|
|
59
64
|
try {
|
|
60
|
-
await controller.refineSelectionTo({ ...params }, output, {
|
|
65
|
+
await controller.refineSelectionTo({ ...params }, output, {
|
|
66
|
+
decontaminate: toLayer ? decontaminate : 0,
|
|
67
|
+
refineMode: canObject && objectAware ? 'object' : 'color',
|
|
68
|
+
});
|
|
61
69
|
} catch (err) {
|
|
62
70
|
error = err instanceof Error ? err.message : String(err);
|
|
63
71
|
} finally {
|
|
@@ -102,6 +110,12 @@
|
|
|
102
110
|
/>
|
|
103
111
|
Smart Radius
|
|
104
112
|
</label>
|
|
113
|
+
{#if canObject}
|
|
114
|
+
<label class="flex items-center gap-2 text-foreground">
|
|
115
|
+
<input type="checkbox" aria-label="Object aware" checked={objectAware} onchange={(e) => (objectAware = (e.currentTarget as HTMLInputElement).checked)} />
|
|
116
|
+
Object aware (segmentation model)
|
|
117
|
+
</label>
|
|
118
|
+
{/if}
|
|
105
119
|
<label class="flex items-center gap-2 text-muted-foreground">
|
|
106
120
|
Output to
|
|
107
121
|
<select
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
3
|
+
import ImageRange from './controls/ImageRange.svelte';
|
|
4
|
+
import ImageSelect from './controls/ImageSelect.svelte';
|
|
5
|
+
import { imageSectionTitleClass } from './styles.js';
|
|
6
|
+
import type { ImageEditorController, RefineOutput, RefineOutputResult, SelectAndMaskSettings, SelectAndMaskView } from '@pixerate/editor/image-editor';
|
|
7
|
+
import { REFINE_EDGE_CONTROLS, REFINE_OUTPUTS, SELECT_AND_MASK_TOOLS, SELECT_AND_MASK_VIEWS, SelectAndMaskSession } from '@pixerate/editor/image-editor';
|
|
8
|
+
import { untrack } from 'svelte';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Select and Mask: a full-window workspace over the editor with its own tools, view modes, edge
|
|
12
|
+
* and output settings, and a live preview. OK applies everything as one undo step, the same
|
|
13
|
+
* `refineSelectionTo` call an agent makes; Cancel leaves the document as it was. Keys as in
|
|
14
|
+
* Photoshop, plus Enter (OK), Escape (Cancel) and Ctrl/⌘+Z (undo the last stroke).
|
|
15
|
+
*/
|
|
16
|
+
interface Props {
|
|
17
|
+
controller: ImageEditorController;
|
|
18
|
+
/** Called with the result after OK, or `null` after Cancel. */
|
|
19
|
+
onclose: (result: RefineOutputResult | null) => void;
|
|
20
|
+
class?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let { controller, onclose, class: className = '' }: Props = $props();
|
|
24
|
+
|
|
25
|
+
const session = untrack(() => new SelectAndMaskSession(controller));
|
|
26
|
+
let tick = $state(0);
|
|
27
|
+
let zoom = $state(1);
|
|
28
|
+
let pan = $state({ x: 0, y: 0 });
|
|
29
|
+
let busy = $state(false);
|
|
30
|
+
let error = $state<string | null>(null);
|
|
31
|
+
let canvas: HTMLCanvasElement | undefined = $state();
|
|
32
|
+
let panFrom: { x: number; y: number; pan: { x: number; y: number } } | null = null;
|
|
33
|
+
|
|
34
|
+
$effect(() => {
|
|
35
|
+
const off = session.subscribe(() => tick++);
|
|
36
|
+
void session.open();
|
|
37
|
+
return off;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const settings = $derived.by(() => {
|
|
41
|
+
void tick;
|
|
42
|
+
return session.settings;
|
|
43
|
+
});
|
|
44
|
+
const size = $derived.by(() => {
|
|
45
|
+
void tick;
|
|
46
|
+
return session.previewSize;
|
|
47
|
+
});
|
|
48
|
+
const edits = $derived.by(() => {
|
|
49
|
+
void tick;
|
|
50
|
+
return session.edits.length;
|
|
51
|
+
});
|
|
52
|
+
const sessionError = $derived.by(() => {
|
|
53
|
+
void tick;
|
|
54
|
+
return session.error;
|
|
55
|
+
});
|
|
56
|
+
const note = $derived.by(() => {
|
|
57
|
+
void tick;
|
|
58
|
+
return session.note;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Draw the preview whenever it changes.
|
|
62
|
+
$effect(() => {
|
|
63
|
+
void tick;
|
|
64
|
+
const ctx = canvas?.getContext?.('2d');
|
|
65
|
+
if (!canvas || !ctx || !size.width || typeof ImageData === 'undefined') return;
|
|
66
|
+
canvas.width = size.width;
|
|
67
|
+
canvas.height = size.height;
|
|
68
|
+
ctx.putImageData(new ImageData(session.render() as Uint8ClampedArray<ArrayBuffer>, size.width, size.height), 0, 0);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const set = (changes: Partial<SelectAndMaskSettings>) => session.update(changes);
|
|
72
|
+
|
|
73
|
+
async function ok() {
|
|
74
|
+
busy = true;
|
|
75
|
+
error = null;
|
|
76
|
+
try {
|
|
77
|
+
onclose(await session.commit());
|
|
78
|
+
} catch (err) {
|
|
79
|
+
error = err instanceof Error ? err.message : String(err);
|
|
80
|
+
busy = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function onkeydown(e: KeyboardEvent) {
|
|
85
|
+
const t = e.target as HTMLElement | null;
|
|
86
|
+
if (t && (t.tagName === 'INPUT' || t.tagName === 'SELECT' || t.tagName === 'TEXTAREA')) return;
|
|
87
|
+
if (e.key === 'Escape') onclose(null);
|
|
88
|
+
else if (e.key === 'Enter') void ok();
|
|
89
|
+
else if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'z') session.undoEdit();
|
|
90
|
+
else if (e.ctrlKey || e.metaKey || e.altKey || !session.handleKey(e.key)) return;
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** The pointer's position in natural image pixels. */
|
|
95
|
+
function toImage(e: PointerEvent) {
|
|
96
|
+
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
|
97
|
+
const naturalW = size.width / size.scale;
|
|
98
|
+
const naturalH = size.height / size.scale;
|
|
99
|
+
return { x: ((e.clientX - rect.left) / Math.max(1, rect.width)) * naturalW, y: ((e.clientY - rect.top) / Math.max(1, rect.height)) * naturalH };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function onpointerdown(e: PointerEvent) {
|
|
103
|
+
if (settings.tool === 'hand') {
|
|
104
|
+
panFrom = { x: e.clientX, y: e.clientY, pan };
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (settings.tool === 'zoom') {
|
|
108
|
+
zoom = Math.min(16, Math.max(0.25, e.altKey ? zoom / 1.25 : zoom * 1.25));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
(e.currentTarget as HTMLElement).setPointerCapture?.(e.pointerId);
|
|
112
|
+
session.begin(toImage(e), { altKey: e.altKey });
|
|
113
|
+
}
|
|
114
|
+
function onpointermove(e: PointerEvent) {
|
|
115
|
+
if (panFrom) {
|
|
116
|
+
pan = { x: panFrom.pan.x + e.clientX - panFrom.x, y: panFrom.pan.y + e.clientY - panFrom.y };
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (e.buttons) session.move(toImage(e));
|
|
120
|
+
}
|
|
121
|
+
function onpointerup() {
|
|
122
|
+
panFrom = null;
|
|
123
|
+
session.end();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const toLayer = $derived(settings.output === 'new-layer' || settings.output === 'new-layer-with-mask');
|
|
127
|
+
const brushTool = $derived(settings.tool === 'quick-select' || settings.tool === 'brush' || settings.tool === 'refine-brush');
|
|
128
|
+
|
|
129
|
+
const button =
|
|
130
|
+
'px-2 py-1 rounded-md border border-border bg-background text-[11px] text-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-40';
|
|
131
|
+
const toggle = (on: boolean) => `${button} ${on ? 'bg-primary text-primary-foreground border-primary' : ''}`;
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<svelte:window {onkeydown} />
|
|
135
|
+
|
|
136
|
+
<div data-testid="select-and-mask-workspace" role="dialog" aria-label="Select and Mask" class="fixed inset-0 z-50 flex bg-background text-xs text-foreground {className}">
|
|
137
|
+
<div role="group" aria-label="Select and Mask tool" class="flex flex-col gap-1 p-2 border-r border-border">
|
|
138
|
+
{#each SELECT_AND_MASK_TOOLS as t (t.id)}
|
|
139
|
+
<button type="button" title="{t.label} ({t.key.toUpperCase()})" aria-pressed={settings.tool === t.id} class={toggle(settings.tool === t.id)} onclick={() => set({ tool: t.id })}>
|
|
140
|
+
{t.label}
|
|
141
|
+
</button>
|
|
142
|
+
{/each}
|
|
143
|
+
</div>
|
|
144
|
+
<div class="flex-1 flex flex-col min-w-0">
|
|
145
|
+
<div class="flex flex-wrap items-center gap-2 p-2 border-b border-border">
|
|
146
|
+
{#if brushTool}
|
|
147
|
+
<label class="flex items-center gap-1 text-muted-foreground">
|
|
148
|
+
Size
|
|
149
|
+
<input
|
|
150
|
+
type="number"
|
|
151
|
+
min="1"
|
|
152
|
+
aria-label="Brush size"
|
|
153
|
+
value={settings.brushSize}
|
|
154
|
+
oninput={(e) => set({ brushSize: Math.max(1, Number((e.currentTarget as HTMLInputElement).value) || 1) })}
|
|
155
|
+
class="w-16 bg-background border border-border rounded px-1 py-0.5 text-foreground"
|
|
156
|
+
/>
|
|
157
|
+
px
|
|
158
|
+
</label>
|
|
159
|
+
{/if}
|
|
160
|
+
{#if settings.tool !== 'refine-brush' && settings.tool !== 'hand' && settings.tool !== 'zoom'}
|
|
161
|
+
<div role="group" aria-label="Stroke mode" class="flex gap-1">
|
|
162
|
+
<button type="button" aria-pressed={settings.brushMode === 'add'} class={toggle(settings.brushMode === 'add')} onclick={() => set({ brushMode: 'add' })}>Add</button>
|
|
163
|
+
<button type="button" aria-pressed={settings.brushMode === 'subtract'} class={toggle(settings.brushMode === 'subtract')} onclick={() => set({ brushMode: 'subtract' })}>
|
|
164
|
+
Subtract
|
|
165
|
+
</button>
|
|
166
|
+
</div>
|
|
167
|
+
{/if}
|
|
168
|
+
<span class="text-muted-foreground">{edits} strokes</span>
|
|
169
|
+
<button type="button" class={button} disabled={!edits} onclick={() => session.undoEdit()}>Undo Stroke</button>
|
|
170
|
+
<span class="font-mono text-muted-foreground">{Math.round(zoom * 100)}%</span>
|
|
171
|
+
</div>
|
|
172
|
+
<div class="flex-1 overflow-hidden flex items-center justify-center bg-muted/30">
|
|
173
|
+
<canvas
|
|
174
|
+
bind:this={canvas}
|
|
175
|
+
data-testid="select-and-mask-preview"
|
|
176
|
+
{onpointerdown}
|
|
177
|
+
{onpointermove}
|
|
178
|
+
{onpointerup}
|
|
179
|
+
style:max-width="100%"
|
|
180
|
+
style:max-height="100%"
|
|
181
|
+
style:transform="translate({pan.x}px, {pan.y}px) scale({zoom})"
|
|
182
|
+
style:image-rendering={zoom > 2 ? 'pixelated' : undefined}
|
|
183
|
+
style:cursor={settings.tool === 'hand' ? 'grab' : settings.tool === 'zoom' ? 'zoom-in' : 'crosshair'}
|
|
184
|
+
></canvas>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="w-64 flex flex-col gap-3 p-3 border-l border-border overflow-y-auto">
|
|
188
|
+
<span class={imageSectionTitleClass}>View Mode</span>
|
|
189
|
+
<label class="flex items-center gap-2">
|
|
190
|
+
View
|
|
191
|
+
<ImageSelect
|
|
192
|
+
label="View"
|
|
193
|
+
value={settings.view}
|
|
194
|
+
options={SELECT_AND_MASK_VIEWS.map((v) => ({ value: v.id, label: `${v.label} (${v.key.toUpperCase()})` }))}
|
|
195
|
+
onchange={(v) => set({ view: v as SelectAndMaskView })}
|
|
196
|
+
/>
|
|
197
|
+
</label>
|
|
198
|
+
<label class="flex flex-col gap-1">
|
|
199
|
+
<span class="flex justify-between text-muted-foreground">
|
|
200
|
+
<span>Opacity</span>
|
|
201
|
+
<span class="font-mono">{Math.round(settings.opacity * 100)}%</span>
|
|
202
|
+
</span>
|
|
203
|
+
<ImageRange label="View opacity" min={0} max={100} step={1} value={Math.round(settings.opacity * 100)} oninput={(v) => set({ opacity: v / 100 })} />
|
|
204
|
+
</label>
|
|
205
|
+
<label class="flex items-center gap-2">
|
|
206
|
+
<ImageCheckbox label="Show Edge" checked={settings.showEdge} onchange={(on) => set({ showEdge: on })} />
|
|
207
|
+
Show Edge (J)
|
|
208
|
+
</label>
|
|
209
|
+
<label class="flex items-center gap-2">
|
|
210
|
+
<ImageCheckbox label="Show Original" checked={settings.showOriginal} onchange={(on) => set({ showOriginal: on })} />
|
|
211
|
+
Show Original (P)
|
|
212
|
+
</label>
|
|
213
|
+
<label class="flex items-center gap-2">
|
|
214
|
+
<ImageCheckbox label="Real-Time Refinement" checked={settings.realTime} onchange={(on) => set({ realTime: on })} />
|
|
215
|
+
Real-Time Refinement
|
|
216
|
+
</label>
|
|
217
|
+
<label class="flex items-center gap-2">
|
|
218
|
+
<ImageCheckbox label="High Quality Preview" checked={settings.highQuality} onchange={(on) => set({ highQuality: on })} />
|
|
219
|
+
High Quality Preview
|
|
220
|
+
</label>
|
|
221
|
+
|
|
222
|
+
<span class={imageSectionTitleClass}>Edge Detection and Refinement</span>
|
|
223
|
+
{#if controller.segmentationProvider}
|
|
224
|
+
<label class="flex items-center gap-2">
|
|
225
|
+
Mode
|
|
226
|
+
<ImageSelect
|
|
227
|
+
label="Refine mode"
|
|
228
|
+
value={settings.refineMode}
|
|
229
|
+
options={[
|
|
230
|
+
{ value: 'color', label: 'Color Aware' },
|
|
231
|
+
{ value: 'object', label: 'Object Aware' },
|
|
232
|
+
]}
|
|
233
|
+
onchange={(v) => set({ refineMode: v as 'color' | 'object' })}
|
|
234
|
+
/>
|
|
235
|
+
</label>
|
|
236
|
+
{/if}
|
|
237
|
+
{#each REFINE_EDGE_CONTROLS as c (c.id)}
|
|
238
|
+
<label class="flex flex-col gap-1">
|
|
239
|
+
<span class="flex justify-between text-muted-foreground">
|
|
240
|
+
<span>{c.label}</span>
|
|
241
|
+
<span class="font-mono">{settings.params[c.id]}{c.unit}</span>
|
|
242
|
+
</span>
|
|
243
|
+
<ImageRange label="Workspace {c.label}" min={c.min} max={c.max} step={c.step} value={settings.params[c.id]} oninput={(v) => set({ params: { ...settings.params, [c.id]: v } })} />
|
|
244
|
+
</label>
|
|
245
|
+
{/each}
|
|
246
|
+
<label class="flex items-center gap-2">
|
|
247
|
+
<ImageCheckbox label="Workspace Smart Radius" checked={settings.params.smartRadius} onchange={(on) => set({ params: { ...settings.params, smartRadius: on } })} />
|
|
248
|
+
Smart Radius
|
|
249
|
+
</label>
|
|
250
|
+
|
|
251
|
+
<span class={imageSectionTitleClass}>Output Settings</span>
|
|
252
|
+
<label class="flex flex-col gap-1">
|
|
253
|
+
<span class="flex justify-between text-muted-foreground">
|
|
254
|
+
<span>Decontaminate Colors{toLayer ? '' : ' (new layer outputs)'}</span>
|
|
255
|
+
<span class="font-mono">{settings.decontaminate}%</span>
|
|
256
|
+
</span>
|
|
257
|
+
<ImageRange label="Workspace decontaminate amount" min={0} max={100} step={1} value={settings.decontaminate} disabled={!toLayer} oninput={(v) => set({ decontaminate: v })} />
|
|
258
|
+
</label>
|
|
259
|
+
<label class="flex items-center gap-2">
|
|
260
|
+
Output To
|
|
261
|
+
<ImageSelect label="Output to" value={settings.output} options={REFINE_OUTPUTS.map((o) => ({ value: o.id, label: o.label }))} onchange={(v) => set({ output: v as RefineOutput })} />
|
|
262
|
+
</label>
|
|
263
|
+
<label class="flex items-center gap-2">
|
|
264
|
+
<ImageCheckbox label="Remember Settings" checked={settings.remember} onchange={(on) => set({ remember: on })} />
|
|
265
|
+
Remember Settings
|
|
266
|
+
</label>
|
|
267
|
+
{#if error ?? sessionError}
|
|
268
|
+
<p role="alert" class="text-destructive">{error ?? sessionError}</p>
|
|
269
|
+
{/if}
|
|
270
|
+
{#if note}
|
|
271
|
+
<p class="text-muted-foreground">{note}</p>
|
|
272
|
+
{/if}
|
|
273
|
+
<div class="flex gap-1 mt-auto">
|
|
274
|
+
<button type="button" class={button} onclick={() => session.reset()}>Reset</button>
|
|
275
|
+
<button type="button" class={button} onclick={() => onclose(null)}>Cancel</button>
|
|
276
|
+
<button type="button" class={toggle(true)} disabled={busy} aria-busy={busy} onclick={() => void ok()}>OK</button>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ImageEditorController, RefineOutputResult } from '@pixerate/editor/image-editor';
|
|
2
|
+
/**
|
|
3
|
+
* Select and Mask: a full-window workspace over the editor with its own tools, view modes, edge
|
|
4
|
+
* and output settings, and a live preview. OK applies everything as one undo step, the same
|
|
5
|
+
* `refineSelectionTo` call an agent makes; Cancel leaves the document as it was. Keys as in
|
|
6
|
+
* Photoshop, plus Enter (OK), Escape (Cancel) and Ctrl/⌘+Z (undo the last stroke).
|
|
7
|
+
*/
|
|
8
|
+
interface Props {
|
|
9
|
+
controller: ImageEditorController;
|
|
10
|
+
/** Called with the result after OK, or `null` after Cancel. */
|
|
11
|
+
onclose: (result: RefineOutputResult | null) => void;
|
|
12
|
+
class?: string;
|
|
13
|
+
}
|
|
14
|
+
declare const SelectAndMaskWorkspace: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type SelectAndMaskWorkspace = ReturnType<typeof SelectAndMaskWorkspace>;
|
|
16
|
+
export default SelectAndMaskWorkspace;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
3
3
|
import ImageRange from './controls/ImageRange.svelte';
|
|
4
4
|
import ImageSelect from './controls/ImageSelect.svelte';
|
|
5
|
+
import SelectAndMaskWorkspace from './SelectAndMaskWorkspace.svelte';
|
|
5
6
|
import type {
|
|
6
7
|
ColorRangePreset,
|
|
7
8
|
ImageEditorController,
|
|
@@ -109,6 +110,7 @@
|
|
|
109
110
|
let subject = $state('');
|
|
110
111
|
let segmenting = $state(false);
|
|
111
112
|
let subjectStatus = $state<string | null>(null);
|
|
113
|
+
let workspace = $state(false);
|
|
112
114
|
let skying = $state(false);
|
|
113
115
|
let skyStatus = $state<string | null>(null);
|
|
114
116
|
async function selectSky() {
|
|
@@ -426,6 +428,10 @@
|
|
|
426
428
|
<p role="status" class="text-muted-foreground">{subjectStatus}</p>
|
|
427
429
|
{/if}
|
|
428
430
|
</form>
|
|
431
|
+
<button type="button" class={btn(false)} onclick={() => (workspace = true)}>Select and Mask…</button>
|
|
432
|
+
{#if workspace}
|
|
433
|
+
<SelectAndMaskWorkspace {controller} onclose={() => (workspace = false)} />
|
|
434
|
+
{/if}
|
|
429
435
|
<div data-testid="select-sky" class="flex flex-col gap-1">
|
|
430
436
|
<button type="button" class={btn(false)} disabled={skying} aria-busy={skying} onclick={() => void selectSky()}>
|
|
431
437
|
{skying ? 'Selecting…' : 'Select Sky'}
|
|
@@ -8,6 +8,7 @@ import type CurvesEditorComponent from "./CurvesEditor.svelte";
|
|
|
8
8
|
import type ControlSliderComponent from "./ControlSlider.svelte";
|
|
9
9
|
import type SelectionOptionsBarComponent from "./SelectionOptionsBar.svelte";
|
|
10
10
|
import type RefineEdgePanelComponent from "./RefineEdgePanel.svelte";
|
|
11
|
+
import type SelectAndMaskWorkspaceComponent from "./SelectAndMaskWorkspace.svelte";
|
|
11
12
|
import type ChannelsPanelComponent from "./ChannelsPanel.svelte";
|
|
12
13
|
import type LayersPanelComponent from "./LayersPanel.svelte";
|
|
13
14
|
import type ColorProfilePanelComponent from "./ColorProfilePanel.svelte";
|
|
@@ -32,6 +33,7 @@ export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
|
32
33
|
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
33
34
|
export { default as SelectionOptionsBar } from './SelectionOptionsBar.svelte';
|
|
34
35
|
export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
36
|
+
export { default as SelectAndMaskWorkspace } from './SelectAndMaskWorkspace.svelte';
|
|
35
37
|
export { default as ChannelsPanel } from './ChannelsPanel.svelte';
|
|
36
38
|
export { default as LayersPanel } from './LayersPanel.svelte';
|
|
37
39
|
export { default as ColorProfilePanel } from './ColorProfilePanel.svelte';
|
|
@@ -58,6 +60,7 @@ export type CurvesEditorProps = ComponentProps<typeof CurvesEditorComponent>;
|
|
|
58
60
|
export type ControlSliderProps = ComponentProps<typeof ControlSliderComponent>;
|
|
59
61
|
export type SelectionOptionsBarProps = ComponentProps<typeof SelectionOptionsBarComponent>;
|
|
60
62
|
export type RefineEdgePanelProps = ComponentProps<typeof RefineEdgePanelComponent>;
|
|
63
|
+
export type SelectAndMaskWorkspaceProps = ComponentProps<typeof SelectAndMaskWorkspaceComponent>;
|
|
61
64
|
export type ChannelsPanelProps = ComponentProps<typeof ChannelsPanelComponent>;
|
|
62
65
|
export type LayersPanelProps = ComponentProps<typeof LayersPanelComponent>;
|
|
63
66
|
export type ColorProfilePanelProps = ComponentProps<typeof ColorProfilePanelComponent>;
|
|
@@ -10,6 +10,7 @@ export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
|
10
10
|
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
11
11
|
export { default as SelectionOptionsBar } from './SelectionOptionsBar.svelte';
|
|
12
12
|
export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
13
|
+
export { default as SelectAndMaskWorkspace } from './SelectAndMaskWorkspace.svelte';
|
|
13
14
|
export { default as ChannelsPanel } from './ChannelsPanel.svelte';
|
|
14
15
|
export { default as LayersPanel } from './LayersPanel.svelte';
|
|
15
16
|
export { default as ColorProfilePanel } from './ColorProfilePanel.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.151.0",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
"**/*.css"
|
|
166
166
|
],
|
|
167
167
|
"dependencies": {
|
|
168
|
-
"@pixerate/editor": "0.
|
|
168
|
+
"@pixerate/editor": "0.207.0"
|
|
169
169
|
},
|
|
170
170
|
"peerDependencies": {
|
|
171
171
|
"@dagrejs/dagre": "^1.1.4",
|