@pixerate/editor-svelte 0.133.3 → 0.135.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/AdjustmentLayersPanel.svelte +1 -1
- package/dist/image-editor/ImageEditor.svelte +1 -0
- package/dist/image-editor/ImageEditorCanvas.svelte +30 -3
- package/dist/image-editor/ImageProviderEffectsPanel.svelte +1 -1
- package/dist/image-editor/LayersPanel.svelte +10 -2
- package/dist/image-editor/SelectionOptionsBar.svelte +182 -7
- package/dist/image-editor/SelectionOptionsBar.svelte.d.ts +3 -1
- package/package.json +2 -2
|
@@ -954,6 +954,7 @@
|
|
|
954
954
|
onOptionsChange={(next) => (selectionOptions = next)}
|
|
955
955
|
selection={editor.state.selection ?? null}
|
|
956
956
|
quickMask={Boolean(editor.state.quickMask)}
|
|
957
|
+
selectionDisplay={editor.state.selectionDisplay}
|
|
957
958
|
/>
|
|
958
959
|
{#if selectionError}
|
|
959
960
|
<p role="alert" class="text-destructive">{selectionError}</p>
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
measureCanvasViewport,
|
|
24
24
|
watchCanvasViewport,
|
|
25
25
|
startMarchingAnts,
|
|
26
|
+
handleSelectionShortcut,
|
|
26
27
|
ShapeDrawGesture,
|
|
27
28
|
TypeToolGesture,
|
|
28
29
|
DEFAULT_SHAPE_TOOL_OPTIONS,
|
|
@@ -594,6 +595,28 @@
|
|
|
594
595
|
if (paintGesture.error) report('paint', paintGesture.error);
|
|
595
596
|
}
|
|
596
597
|
|
|
598
|
+
$effect(() => {
|
|
599
|
+
if (mode !== 'select' || typeof window === 'undefined') return;
|
|
600
|
+
const gesture = selectionGesture;
|
|
601
|
+
// The polygonal lasso: Enter closes it, Escape cancels, Backspace removes the last corner.
|
|
602
|
+
const onKey = (e: KeyboardEvent) => {
|
|
603
|
+
const target = e.target as HTMLElement | null;
|
|
604
|
+
if (target?.closest?.('input, textarea, select, [contenteditable="true"]')) return;
|
|
605
|
+
// Leave Copy to the page while text on it is selected.
|
|
606
|
+
if (window.getSelection?.()?.toString()) return;
|
|
607
|
+
if (handleSelectionShortcut(editor.controller, e, (message) => report('select', message))) {
|
|
608
|
+
e.preventDefault();
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (gesture.key(e.key)) {
|
|
612
|
+
e.preventDefault();
|
|
613
|
+
selectionDraft = gesture.draftPath;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
window.addEventListener('keydown', onKey);
|
|
617
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
618
|
+
});
|
|
619
|
+
|
|
597
620
|
$effect(() => {
|
|
598
621
|
if (mode !== 'paint' || typeof window === 'undefined') return;
|
|
599
622
|
const c = editor.controller;
|
|
@@ -663,7 +686,10 @@
|
|
|
663
686
|
if (mode === 'select') {
|
|
664
687
|
const gesture = selectionGesture;
|
|
665
688
|
const imgPt = canvasToImagePoint(canvasPt, editor.state, view.width, view.height, false);
|
|
666
|
-
void gesture.begin(imgPt, e).then(() =>
|
|
689
|
+
void gesture.begin(imgPt, e).then(() => {
|
|
690
|
+
report('select', gesture.error);
|
|
691
|
+
selectionDraft = gesture.draftPath;
|
|
692
|
+
});
|
|
667
693
|
return;
|
|
668
694
|
}
|
|
669
695
|
|
|
@@ -771,7 +797,7 @@
|
|
|
771
797
|
|
|
772
798
|
if (mode === 'select') {
|
|
773
799
|
const gesture = selectionGesture;
|
|
774
|
-
if (gesture.active && gesture.move(canvasToImagePoint(canvasPt, editor.state, view.width, view.height, false))) {
|
|
800
|
+
if (gesture.active && gesture.move(canvasToImagePoint(canvasPt, editor.state, view.width, view.height, false), e)) {
|
|
775
801
|
selectionDraft = gesture.draftPath;
|
|
776
802
|
renderCanvas();
|
|
777
803
|
}
|
|
@@ -924,7 +950,8 @@
|
|
|
924
950
|
const gesture = selectionGesture;
|
|
925
951
|
if (gesture.active) {
|
|
926
952
|
gesture.end(canvasToImagePoint(canvasPt, editor.state, view.width, view.height, false), e);
|
|
927
|
-
|
|
953
|
+
// A polygonal lasso stays open between clicks.
|
|
954
|
+
selectionDraft = gesture.draftPath;
|
|
928
955
|
renderCanvas();
|
|
929
956
|
}
|
|
930
957
|
return;
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
</div>
|
|
163
163
|
{#if browse === 'filter'}
|
|
164
164
|
{@const id = layer.id}
|
|
165
|
-
<EffectsBrowser {provider} uses={['filter']} title="Filters" onpick={(e) => ((browse = null), run(() => controller.applyEffectFilter(id, e.id)))} />
|
|
165
|
+
<EffectsBrowser {provider} uses={['filter']} title="Filters" onpick={(e) => ((browse = null), run(() => controller.applyEffectFilter(id, e.id, { useSelection: true })))} />
|
|
166
166
|
{/if}
|
|
167
167
|
{/if}
|
|
168
168
|
{#if layer && all.some((f) => f.kind === 'effect')}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
downloadPsd,
|
|
9
9
|
dropPlacement,
|
|
10
10
|
dropZone,
|
|
11
|
+
maskThumbnailClick,
|
|
12
|
+
layerThumbnailClick,
|
|
11
13
|
layerBadge,
|
|
12
14
|
layerEffectsBadge,
|
|
13
15
|
layerHasThumbnail,
|
|
@@ -333,6 +335,13 @@
|
|
|
333
335
|
<canvas
|
|
334
336
|
use:paint={thumb(layer)}
|
|
335
337
|
aria-label={`${row.label} pixels`}
|
|
338
|
+
data-testid="layer-thumbnail"
|
|
339
|
+
onclick={(e) => {
|
|
340
|
+
if (e.ctrlKey || e.metaKey) {
|
|
341
|
+
e.stopPropagation();
|
|
342
|
+
attempt(() => layerThumbnailClick(controller, layer, e));
|
|
343
|
+
}
|
|
344
|
+
}}
|
|
336
345
|
style="width: {thumbnailSize}px; height: {thumbnailSize}px"
|
|
337
346
|
class={thumbClass(row.active && snapshot.activeTarget === 'pixels' && Boolean(layer.mask))}
|
|
338
347
|
></canvas>
|
|
@@ -371,8 +380,7 @@
|
|
|
371
380
|
class={thumbClass(row.active && snapshot.activeTarget === 'mask')}
|
|
372
381
|
onclick={(e) => {
|
|
373
382
|
e.stopPropagation();
|
|
374
|
-
|
|
375
|
-
else attempt(() => controller.setActiveLayer(layer.id, 'mask'));
|
|
383
|
+
attempt(() => maskThumbnailClick(controller, layer, e));
|
|
376
384
|
}}
|
|
377
385
|
></canvas>
|
|
378
386
|
{/if}
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
import ImageRange from './controls/ImageRange.svelte';
|
|
4
4
|
import ImageSelect from './controls/ImageSelect.svelte';
|
|
5
5
|
import type {
|
|
6
|
+
ColorRangePreset,
|
|
6
7
|
ImageEditorController,
|
|
8
|
+
SelectionDisplay,
|
|
7
9
|
SelectionMask,
|
|
8
10
|
SelectionModifyOp,
|
|
9
11
|
SelectionToolOptions,
|
|
10
12
|
} from '@pixerate/editor/image-editor';
|
|
11
13
|
import {
|
|
14
|
+
COLOR_RANGE_PRESETS,
|
|
15
|
+
COLOR_RANGE_PRESET_LABELS,
|
|
12
16
|
SELECTION_MODES,
|
|
13
17
|
SELECTION_MODE_LABELS,
|
|
14
18
|
SELECTION_TOOLS,
|
|
@@ -24,10 +28,12 @@
|
|
|
24
28
|
selection?: SelectionMask | null;
|
|
25
29
|
/** The Quick Mask view flag (`state.quickMask`). Omit to follow the controller. */
|
|
26
30
|
quickMask?: boolean;
|
|
31
|
+
/** How the canvas shows the selection (`state.selectionDisplay`); wins over `quickMask`. */
|
|
32
|
+
selectionDisplay?: SelectionDisplay;
|
|
27
33
|
class?: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
let { controller, options, onOptionsChange, selection, quickMask, class: className = '' }: Props = $props();
|
|
36
|
+
let { controller, options, onOptionsChange, selection, quickMask, selectionDisplay, class: className = '' }: Props = $props();
|
|
31
37
|
|
|
32
38
|
let tick = $state(0);
|
|
33
39
|
$effect(() => {
|
|
@@ -38,10 +44,60 @@
|
|
|
38
44
|
void tick;
|
|
39
45
|
return selection === undefined ? controller.getSelection() : selection;
|
|
40
46
|
});
|
|
41
|
-
const
|
|
47
|
+
const display = $derived.by((): SelectionDisplay => {
|
|
42
48
|
void tick;
|
|
43
|
-
return
|
|
49
|
+
return selectionDisplay ?? (quickMask === undefined ? controller.getSelectionDisplay() : quickMask ? 'quickMask' : 'ants');
|
|
44
50
|
});
|
|
51
|
+
const DISPLAYS: { id: SelectionDisplay; label: string }[] = [
|
|
52
|
+
{ id: 'ants', label: 'Ants' },
|
|
53
|
+
{ id: 'quickMask', label: 'Quick Mask' },
|
|
54
|
+
{ id: 'none', label: 'Hidden' },
|
|
55
|
+
];
|
|
56
|
+
const numberInput = 'w-14 bg-background border border-border rounded px-1 py-0.5 text-foreground';
|
|
57
|
+
|
|
58
|
+
// Color Range presets.
|
|
59
|
+
let preset = $state<ColorRangePreset>('reds');
|
|
60
|
+
let rangeStatus = $state<string | null>(null);
|
|
61
|
+
const canReselect = $derived.by(() => {
|
|
62
|
+
void tick;
|
|
63
|
+
void sel;
|
|
64
|
+
return controller.canReselect();
|
|
65
|
+
});
|
|
66
|
+
let colorStatus = $state<string | null>(null);
|
|
67
|
+
let strokeWidth = $state(4);
|
|
68
|
+
let strokeLocation = $state<'inside' | 'center' | 'outside'>('outside');
|
|
69
|
+
function edit(fn: () => unknown) {
|
|
70
|
+
colorStatus = null;
|
|
71
|
+
try {
|
|
72
|
+
fn();
|
|
73
|
+
} catch (err) {
|
|
74
|
+
colorStatus = err instanceof Error ? err.message : String(err);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function runColor(op: 'grow' | 'similar') {
|
|
78
|
+
colorStatus = null;
|
|
79
|
+
const opts = { tolerance: options.tolerance, sampleMerged: options.sampleMerged, sample: options.sample };
|
|
80
|
+
try {
|
|
81
|
+
await (op === 'grow' ? controller.growSelection(opts) : controller.selectSimilar(opts));
|
|
82
|
+
} catch (err) {
|
|
83
|
+
colorStatus = err instanceof Error ? err.message : String(err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function applyPreset() {
|
|
87
|
+
rangeStatus = null;
|
|
88
|
+
try {
|
|
89
|
+
await controller.selectColorRangePreset(preset, {
|
|
90
|
+
mode: options.mode,
|
|
91
|
+
feather: options.feather ?? 0,
|
|
92
|
+
invert: options.rangeInvert ?? false,
|
|
93
|
+
falloff: options.fuzziness ?? 20,
|
|
94
|
+
sampleMerged: options.sampleMerged,
|
|
95
|
+
sample: options.sample,
|
|
96
|
+
});
|
|
97
|
+
} catch (err) {
|
|
98
|
+
rangeStatus = err instanceof Error ? err.message : String(err);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
45
101
|
|
|
46
102
|
let radius = $state(2);
|
|
47
103
|
|
|
@@ -69,8 +125,8 @@
|
|
|
69
125
|
}
|
|
70
126
|
|
|
71
127
|
const MODIFY_OPS: { op: SelectionModifyOp; label: string }[] = [
|
|
72
|
-
{ op: '
|
|
73
|
-
{ op: '
|
|
128
|
+
{ op: 'expand', label: 'Expand' },
|
|
129
|
+
{ op: 'contract', label: 'Contract' },
|
|
74
130
|
{ op: 'feather', label: 'Feather' },
|
|
75
131
|
{ op: 'border', label: 'Border' },
|
|
76
132
|
{ op: 'smooth', label: 'Smooth' },
|
|
@@ -114,6 +170,18 @@
|
|
|
114
170
|
<ImageCheckbox label="Contiguous" checked={options.contiguous} onchange={(on) => set({ contiguous: on })} />
|
|
115
171
|
Contiguous
|
|
116
172
|
</label>
|
|
173
|
+
<label class="flex items-center gap-2 text-foreground">
|
|
174
|
+
Distance
|
|
175
|
+
<ImageSelect
|
|
176
|
+
label="Colour distance"
|
|
177
|
+
value={options.distance}
|
|
178
|
+
options={[
|
|
179
|
+
{ value: 'rgb', label: 'RGB' },
|
|
180
|
+
{ value: 'perceptual', label: 'Perceptual' },
|
|
181
|
+
]}
|
|
182
|
+
onchange={(v) => set({ distance: v as 'rgb' | 'perceptual' })}
|
|
183
|
+
/>
|
|
184
|
+
</label>
|
|
117
185
|
<label class="flex items-center gap-2 text-foreground">
|
|
118
186
|
<ImageCheckbox label="Sample adjusted image" checked={options.sampleMerged} onchange={(on) => set({ sampleMerged: on })} />
|
|
119
187
|
Sample adjusted image
|
|
@@ -132,6 +200,64 @@
|
|
|
132
200
|
</label>
|
|
133
201
|
</div>
|
|
134
202
|
{/if}
|
|
203
|
+
{#if options.tool === 'polygon'}
|
|
204
|
+
<p class="text-muted-foreground">Click to add corners (Shift for 45°), drag for a free-hand stretch; double-click, Enter or a click on the first corner closes it, Backspace removes a corner, Escape cancels.</p>
|
|
205
|
+
{/if}
|
|
206
|
+
{#if options.tool === 'range'}
|
|
207
|
+
<div data-testid="color-range-options" class="flex flex-col gap-2">
|
|
208
|
+
<p class="text-muted-foreground">Click a colour to select it; Shift-click adds a colour, Alt-click removes one.</p>
|
|
209
|
+
<label class="flex flex-col gap-1">
|
|
210
|
+
<span class="flex justify-between text-muted-foreground">
|
|
211
|
+
<span>Fuzziness</span>
|
|
212
|
+
<span class="font-mono">{options.fuzziness ?? 40}</span>
|
|
213
|
+
</span>
|
|
214
|
+
<ImageRange label="Fuzziness" min={0} max={200} step={1} value={options.fuzziness ?? 40} oninput={(v) => set({ fuzziness: v })} />
|
|
215
|
+
</label>
|
|
216
|
+
<label class="flex items-center gap-1 text-muted-foreground">
|
|
217
|
+
Localized radius
|
|
218
|
+
<input
|
|
219
|
+
type="number"
|
|
220
|
+
min="0"
|
|
221
|
+
step="1"
|
|
222
|
+
aria-label="Localized radius"
|
|
223
|
+
value={options.localized ?? 0}
|
|
224
|
+
oninput={(e) => set({ localized: Math.max(0, Number((e.currentTarget as HTMLInputElement).value) || 0) })}
|
|
225
|
+
class={numberInput}
|
|
226
|
+
/>
|
|
227
|
+
px
|
|
228
|
+
</label>
|
|
229
|
+
<label class="flex items-center gap-2 text-foreground">
|
|
230
|
+
<ImageCheckbox label="Invert" checked={options.rangeInvert ?? false} onchange={(on) => set({ rangeInvert: on })} />
|
|
231
|
+
Invert
|
|
232
|
+
</label>
|
|
233
|
+
<div class="flex items-center gap-1">
|
|
234
|
+
<ImageSelect
|
|
235
|
+
label="Color Range preset"
|
|
236
|
+
value={preset}
|
|
237
|
+
options={COLOR_RANGE_PRESETS.map((p) => ({ value: p, label: COLOR_RANGE_PRESET_LABELS[p] }))}
|
|
238
|
+
onchange={(v) => (preset = v as ColorRangePreset)}
|
|
239
|
+
/>
|
|
240
|
+
<button type="button" class={btn(false)} onclick={() => void applyPreset()}>Select</button>
|
|
241
|
+
</div>
|
|
242
|
+
{#if rangeStatus}
|
|
243
|
+
<p role="status" class="text-muted-foreground">{rangeStatus}</p>
|
|
244
|
+
{/if}
|
|
245
|
+
</div>
|
|
246
|
+
{/if}
|
|
247
|
+
<label class="flex items-center gap-1 text-muted-foreground">
|
|
248
|
+
Feather
|
|
249
|
+
<input
|
|
250
|
+
type="number"
|
|
251
|
+
min="0"
|
|
252
|
+
max="1000"
|
|
253
|
+
step="0.5"
|
|
254
|
+
aria-label="Feather"
|
|
255
|
+
value={options.feather ?? 0}
|
|
256
|
+
oninput={(e) => set({ feather: Math.max(0, Number((e.currentTarget as HTMLInputElement).value) || 0) })}
|
|
257
|
+
class={numberInput}
|
|
258
|
+
/>
|
|
259
|
+
px
|
|
260
|
+
</label>
|
|
135
261
|
{#if canSegment}
|
|
136
262
|
<form
|
|
137
263
|
data-testid="select-subject"
|
|
@@ -167,7 +293,15 @@
|
|
|
167
293
|
<button type="button" class={btn(false)} onclick={() => controller.selectAll()}>Select All</button>
|
|
168
294
|
<button type="button" class={btn(false)} disabled={!sel} onclick={() => controller.deselect()}>Deselect</button>
|
|
169
295
|
<button type="button" class={btn(false)} onclick={() => controller.invertSelection()}>Inverse</button>
|
|
170
|
-
<button type="button"
|
|
296
|
+
<button type="button" class={btn(false)} disabled={!canReselect} onclick={() => controller.reselect()}>Reselect</button>
|
|
297
|
+
<button type="button" class={btn(false)} disabled={!sel} title="Add connected pixels of a selected colour (wand tolerance)" onclick={() => void runColor('grow')}>Grow</button>
|
|
298
|
+
<button type="button" class={btn(false)} disabled={!sel} title="Add every pixel of a selected colour (wand tolerance)" onclick={() => void runColor('similar')}>Similar</button>
|
|
299
|
+
</div>
|
|
300
|
+
<div role="group" aria-label="Show selection" class="flex flex-wrap items-center gap-1">
|
|
301
|
+
<span class="text-muted-foreground">Show</span>
|
|
302
|
+
{#each DISPLAYS as d (d.id)}
|
|
303
|
+
<button type="button" aria-pressed={display === d.id} class={btn(display === d.id)} onclick={() => controller.setSelectionDisplay(d.id)}>{d.label}</button>
|
|
304
|
+
{/each}
|
|
171
305
|
</div>
|
|
172
306
|
<div class="flex flex-wrap items-center gap-1">
|
|
173
307
|
<label class="flex items-center gap-1 text-muted-foreground">
|
|
@@ -180,12 +314,53 @@
|
|
|
180
314
|
aria-label="Modify radius"
|
|
181
315
|
value={radius}
|
|
182
316
|
oninput={(e) => (radius = Math.max(0, Number((e.currentTarget as HTMLInputElement).value) || 0))}
|
|
183
|
-
class=
|
|
317
|
+
class={numberInput}
|
|
184
318
|
/>
|
|
185
319
|
</label>
|
|
186
320
|
{#each MODIFY_OPS as m (m.op)}
|
|
187
321
|
<button type="button" class={btn(false)} disabled={!sel} onclick={() => controller.modifySelection(m.op, radius)}>{m.label}</button>
|
|
188
322
|
{/each}
|
|
189
323
|
</div>
|
|
324
|
+
<div role="group" aria-label="Edit selection" class="flex flex-wrap items-center gap-1">
|
|
325
|
+
<label class="flex items-center gap-1 text-muted-foreground">
|
|
326
|
+
Stroke
|
|
327
|
+
<input
|
|
328
|
+
type="number"
|
|
329
|
+
min="1"
|
|
330
|
+
max="250"
|
|
331
|
+
step="1"
|
|
332
|
+
aria-label="Stroke width"
|
|
333
|
+
value={strokeWidth}
|
|
334
|
+
oninput={(e) => (strokeWidth = Math.min(250, Math.max(1, Number((e.currentTarget as HTMLInputElement).value) || 1)))}
|
|
335
|
+
class={numberInput}
|
|
336
|
+
/>
|
|
337
|
+
px
|
|
338
|
+
</label>
|
|
339
|
+
<ImageSelect
|
|
340
|
+
label="Stroke location"
|
|
341
|
+
value={strokeLocation}
|
|
342
|
+
options={[
|
|
343
|
+
{ value: 'outside', label: 'Outside' },
|
|
344
|
+
{ value: 'center', label: 'Center' },
|
|
345
|
+
{ value: 'inside', label: 'Inside' },
|
|
346
|
+
]}
|
|
347
|
+
onchange={(v) => (strokeLocation = v as 'inside' | 'center' | 'outside')}
|
|
348
|
+
/>
|
|
349
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => edit(() => controller.strokeSelection({ width: strokeWidth, location: strokeLocation }))}>Stroke</button>
|
|
350
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => edit(() => controller.cropToSelection())}>Crop to Selection</button>
|
|
351
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => edit(() => controller.contentAwareFill({ output: 'new-layer' }))}>Content-Aware Fill</button>
|
|
352
|
+
</div>
|
|
353
|
+
<div role="group" aria-label="Clipboard" class="flex flex-wrap gap-1">
|
|
354
|
+
<button type="button" class={btn(false)} onclick={() => edit(() => controller.copyPixels())}>Copy</button>
|
|
355
|
+
<button type="button" class={btn(false)} onclick={() => edit(() => controller.copyPixels({ merged: true }))}>Copy Merged</button>
|
|
356
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => edit(() => controller.cutPixels())}>Cut</button>
|
|
357
|
+
<button type="button" class={btn(false)} onclick={() => edit(() => controller.pastePixels('new-layer'))}>Paste</button>
|
|
358
|
+
<button type="button" class={btn(false)} onclick={() => edit(() => controller.pastePixels('in-place'))}>Paste in Place</button>
|
|
359
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => edit(() => controller.pastePixels('into'))}>Paste Into</button>
|
|
360
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => edit(() => controller.pastePixels('outside'))}>Paste Outside</button>
|
|
361
|
+
</div>
|
|
362
|
+
{#if colorStatus}
|
|
363
|
+
<p role="status" class="text-muted-foreground">{colorStatus}</p>
|
|
364
|
+
{/if}
|
|
190
365
|
<p data-testid="selection-status" class="text-muted-foreground">{describeSelection(sel)}</p>
|
|
191
366
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageEditorController, SelectionMask, SelectionToolOptions } from '@pixerate/editor/image-editor';
|
|
1
|
+
import type { ImageEditorController, SelectionDisplay, SelectionMask, SelectionToolOptions } from '@pixerate/editor/image-editor';
|
|
2
2
|
interface Props {
|
|
3
3
|
controller: ImageEditorController;
|
|
4
4
|
options: SelectionToolOptions;
|
|
@@ -7,6 +7,8 @@ interface Props {
|
|
|
7
7
|
selection?: SelectionMask | null;
|
|
8
8
|
/** The Quick Mask view flag (`state.quickMask`). Omit to follow the controller. */
|
|
9
9
|
quickMask?: boolean;
|
|
10
|
+
/** How the canvas shows the selection (`state.selectionDisplay`); wins over `quickMask`. */
|
|
11
|
+
selectionDisplay?: SelectionDisplay;
|
|
10
12
|
class?: string;
|
|
11
13
|
}
|
|
12
14
|
declare const SelectionOptionsBar: import("svelte").Component<Props, {}, "">;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.135.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.185.0"
|
|
169
169
|
},
|
|
170
170
|
"peerDependencies": {
|
|
171
171
|
"@dagrejs/dagre": "^1.1.4",
|