@pixerate/editor-svelte 0.151.0 → 0.153.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.
|
@@ -55,7 +55,11 @@
|
|
|
55
55
|
void tick;
|
|
56
56
|
return Boolean(controller.segmentationProvider);
|
|
57
57
|
});
|
|
58
|
-
const toLayer = $derived(output
|
|
58
|
+
const toLayer = $derived(output !== 'selection' && output !== 'layer-mask');
|
|
59
|
+
const outputs = $derived.by(() => {
|
|
60
|
+
void tick;
|
|
61
|
+
return REFINE_OUTPUTS.filter((o) => !o.needsDocuments || controller.canOpenDocuments);
|
|
62
|
+
});
|
|
59
63
|
const target = $derived(list.find((l) => l.id === layerId) ?? list[list.length - 1]);
|
|
60
64
|
|
|
61
65
|
async function refine() {
|
|
@@ -124,14 +128,14 @@
|
|
|
124
128
|
onchange={(e) => (output = (e.currentTarget as HTMLSelectElement).value as RefineOutput)}
|
|
125
129
|
class="flex-1 bg-background border border-border rounded px-1 py-1 text-foreground"
|
|
126
130
|
>
|
|
127
|
-
{#each
|
|
131
|
+
{#each outputs as o (o.id)}
|
|
128
132
|
<option value={o.id}>{o.label}</option>
|
|
129
133
|
{/each}
|
|
130
134
|
</select>
|
|
131
135
|
</label>
|
|
132
136
|
<label class="flex flex-col gap-1">
|
|
133
137
|
<span class="flex justify-between text-muted-foreground">
|
|
134
|
-
<span>Decontaminate colors{toLayer ? '' : ' (new layer outputs)'}</span>
|
|
138
|
+
<span>Decontaminate colors{toLayer ? '' : ' (new layer or document outputs)'}</span>
|
|
135
139
|
<span class="font-mono">{decontaminate}%</span>
|
|
136
140
|
</span>
|
|
137
141
|
<input
|
|
@@ -57,6 +57,10 @@
|
|
|
57
57
|
void tick;
|
|
58
58
|
return session.note;
|
|
59
59
|
});
|
|
60
|
+
const computing = $derived.by(() => {
|
|
61
|
+
void tick;
|
|
62
|
+
return session.computing;
|
|
63
|
+
});
|
|
60
64
|
|
|
61
65
|
// Draw the preview whenever it changes.
|
|
62
66
|
$effect(() => {
|
|
@@ -123,7 +127,7 @@
|
|
|
123
127
|
session.end();
|
|
124
128
|
}
|
|
125
129
|
|
|
126
|
-
const toLayer = $derived(settings.output
|
|
130
|
+
const toLayer = $derived(settings.output !== 'selection' && settings.output !== 'layer-mask');
|
|
127
131
|
const brushTool = $derived(settings.tool === 'quick-select' || settings.tool === 'brush' || settings.tool === 'refine-brush');
|
|
128
132
|
|
|
129
133
|
const button =
|
|
@@ -168,6 +172,9 @@
|
|
|
168
172
|
<span class="text-muted-foreground">{edits} strokes</span>
|
|
169
173
|
<button type="button" class={button} disabled={!edits} onclick={() => session.undoEdit()}>Undo Stroke</button>
|
|
170
174
|
<span class="font-mono text-muted-foreground">{Math.round(zoom * 100)}%</span>
|
|
175
|
+
{#if computing}
|
|
176
|
+
<span role="status" class="text-muted-foreground">Updating preview…</span>
|
|
177
|
+
{/if}
|
|
171
178
|
</div>
|
|
172
179
|
<div class="flex-1 overflow-hidden flex items-center justify-center bg-muted/30">
|
|
173
180
|
<canvas
|
|
@@ -251,14 +258,19 @@
|
|
|
251
258
|
<span class={imageSectionTitleClass}>Output Settings</span>
|
|
252
259
|
<label class="flex flex-col gap-1">
|
|
253
260
|
<span class="flex justify-between text-muted-foreground">
|
|
254
|
-
<span>Decontaminate Colors{toLayer ? '' : ' (new layer outputs)'}</span>
|
|
261
|
+
<span>Decontaminate Colors{toLayer ? '' : ' (new layer or document outputs)'}</span>
|
|
255
262
|
<span class="font-mono">{settings.decontaminate}%</span>
|
|
256
263
|
</span>
|
|
257
264
|
<ImageRange label="Workspace decontaminate amount" min={0} max={100} step={1} value={settings.decontaminate} disabled={!toLayer} oninput={(v) => set({ decontaminate: v })} />
|
|
258
265
|
</label>
|
|
259
266
|
<label class="flex items-center gap-2">
|
|
260
267
|
Output To
|
|
261
|
-
<ImageSelect
|
|
268
|
+
<ImageSelect
|
|
269
|
+
label="Output to"
|
|
270
|
+
value={settings.output}
|
|
271
|
+
options={REFINE_OUTPUTS.filter((o) => !o.needsDocuments || controller.canOpenDocuments).map((o) => ({ value: o.id, label: o.label }))}
|
|
272
|
+
onchange={(v) => set({ output: v as RefineOutput })}
|
|
273
|
+
/>
|
|
262
274
|
</label>
|
|
263
275
|
<label class="flex items-center gap-2">
|
|
264
276
|
<ImageCheckbox label="Remember Settings" checked={settings.remember} onchange={(on) => set({ remember: on })} />
|
|
@@ -107,6 +107,20 @@
|
|
|
107
107
|
void tick;
|
|
108
108
|
return Boolean(controller.segmentationProvider);
|
|
109
109
|
});
|
|
110
|
+
// The long selection running now (Select Subject, Sky, Focus Area): its progress and Cancel.
|
|
111
|
+
let task = $state<{ stage: string; fraction: number } | null>(null);
|
|
112
|
+
let taskAbort: AbortController | null = null;
|
|
113
|
+
function tracked() {
|
|
114
|
+
const abort = new AbortController();
|
|
115
|
+
taskAbort = abort;
|
|
116
|
+
task = { stage: 'Starting', fraction: 0 };
|
|
117
|
+
return { signal: abort.signal, onProgress: (fraction: number, stage: string) => (task = { stage, fraction }) };
|
|
118
|
+
}
|
|
119
|
+
function untracked() {
|
|
120
|
+
taskAbort = null;
|
|
121
|
+
task = null;
|
|
122
|
+
}
|
|
123
|
+
const failure = (err: unknown) => ((err as { name?: string })?.name === 'AbortError' ? 'Cancelled.' : err instanceof Error ? err.message : String(err));
|
|
110
124
|
let subject = $state('');
|
|
111
125
|
let segmenting = $state(false);
|
|
112
126
|
let subjectStatus = $state<string | null>(null);
|
|
@@ -118,11 +132,12 @@
|
|
|
118
132
|
skying = true;
|
|
119
133
|
skyStatus = null;
|
|
120
134
|
try {
|
|
121
|
-
const { note } = await controller.selectSky({ mode: options.mode });
|
|
135
|
+
const { note } = await controller.selectSky({ mode: options.mode, ...tracked() });
|
|
122
136
|
skyStatus = note ?? null;
|
|
123
137
|
} catch (err) {
|
|
124
|
-
skyStatus =
|
|
138
|
+
skyStatus = failure(err);
|
|
125
139
|
} finally {
|
|
140
|
+
untracked();
|
|
126
141
|
skying = false;
|
|
127
142
|
}
|
|
128
143
|
}
|
|
@@ -138,11 +153,13 @@
|
|
|
138
153
|
noise: options.focusNoise ?? 0,
|
|
139
154
|
softness: options.focusSoftness ?? 4,
|
|
140
155
|
mode: options.mode,
|
|
156
|
+
...tracked(),
|
|
141
157
|
});
|
|
142
158
|
focusStatus = selection ? null : 'No part of the image stands out as in focus.';
|
|
143
159
|
} catch (err) {
|
|
144
|
-
focusStatus =
|
|
160
|
+
focusStatus = failure(err);
|
|
145
161
|
} finally {
|
|
162
|
+
untracked();
|
|
146
163
|
focusing = false;
|
|
147
164
|
}
|
|
148
165
|
}
|
|
@@ -152,12 +169,13 @@
|
|
|
152
169
|
segmenting = true;
|
|
153
170
|
subjectStatus = null;
|
|
154
171
|
try {
|
|
155
|
-
const { segments, method, note } = await controller.selectSubject(canSegment ? target : '', { mode: options.mode });
|
|
172
|
+
const { segments, method, note } = await controller.selectSubject(canSegment ? target : '', { mode: options.mode, ...tracked() });
|
|
156
173
|
// Without a model, say only when nothing stood out.
|
|
157
174
|
subjectStatus = segments.length ? null : method === 'saliency' ? (note ?? 'Nothing stands out from the background.') : `Nothing matching “${target}” was found.`;
|
|
158
175
|
} catch (err) {
|
|
159
|
-
subjectStatus =
|
|
176
|
+
subjectStatus = failure(err);
|
|
160
177
|
} finally {
|
|
178
|
+
untracked();
|
|
161
179
|
segmenting = false;
|
|
162
180
|
}
|
|
163
181
|
}
|
|
@@ -428,6 +446,22 @@
|
|
|
428
446
|
<p role="status" class="text-muted-foreground">{subjectStatus}</p>
|
|
429
447
|
{/if}
|
|
430
448
|
</form>
|
|
449
|
+
{#if task}
|
|
450
|
+
<div data-testid="selection-progress" class="flex items-center gap-2">
|
|
451
|
+
<div
|
|
452
|
+
role="progressbar"
|
|
453
|
+
aria-label={task.stage}
|
|
454
|
+
aria-valuemin={0}
|
|
455
|
+
aria-valuemax={100}
|
|
456
|
+
aria-valuenow={Math.round(task.fraction * 100)}
|
|
457
|
+
class="flex-1 h-1.5 rounded bg-muted overflow-hidden"
|
|
458
|
+
>
|
|
459
|
+
<div class="h-full bg-primary" style:width="{Math.round(task.fraction * 100)}%"></div>
|
|
460
|
+
</div>
|
|
461
|
+
<span class="text-muted-foreground">{task.stage}</span>
|
|
462
|
+
<button type="button" class={btn(false)} onclick={() => taskAbort?.abort()}>Cancel</button>
|
|
463
|
+
</div>
|
|
464
|
+
{/if}
|
|
431
465
|
<button type="button" class={btn(false)} onclick={() => (workspace = true)}>Select and Mask…</button>
|
|
432
466
|
{#if workspace}
|
|
433
467
|
<SelectAndMaskWorkspace {controller} onclose={() => (workspace = false)} />
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.153.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.209.0"
|
|
169
169
|
},
|
|
170
170
|
"peerDependencies": {
|
|
171
171
|
"@dagrejs/dagre": "^1.1.4",
|