@pixerate/editor-svelte 0.73.1 → 0.74.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/FreeTransformOptionsBar.svelte +98 -0
- package/dist/image-editor/FreeTransformOptionsBar.svelte.d.ts +9 -0
- package/dist/image-editor/FreeTransformOptionsBar.svelte.d.ts.map +1 -0
- package/dist/image-editor/ImageEditor.svelte +116 -5
- package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -1
- package/dist/image-editor/LayersPanel.svelte +13 -0
- package/dist/image-editor/LayersPanel.svelte.d.ts.map +1 -1
- package/dist/image-editor/index.d.ts +3 -0
- package/dist/image-editor/index.d.ts.map +1 -1
- package/dist/image-editor/index.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { FreeTransformField, FreeTransformTool, Interpolation } from '@pixerate/editor/image-editor';
|
|
3
|
+
import { FREE_TRANSFORM_FIELDS, FREE_TRANSFORM_MODE_OPTIONS, INTERPOLATIONS, TRANSFORM_ANCHORS } from '@pixerate/editor/image-editor';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Free Transform's options bar (Photoshop's): the mode switch (Free, Rotate, Skew, Distort,
|
|
7
|
+
* Perspective), the reference-point locator, X / Y of the reference point, W / H in percent
|
|
8
|
+
* with the proportional chain, the angle and skews, the interpolation, and Commit (Enter) /
|
|
9
|
+
* Cancel (Esc). Typed values apply on Enter or when the field loses focus.
|
|
10
|
+
*/
|
|
11
|
+
let { tool, class: className = '' }: { tool: FreeTransformTool; class?: string } = $props();
|
|
12
|
+
|
|
13
|
+
let tick = $state(0);
|
|
14
|
+
$effect(() => tool.subscribe(() => tick++));
|
|
15
|
+
|
|
16
|
+
/** What the bar shows, re-read whenever the tool changes. */
|
|
17
|
+
const view = $derived.by(() => {
|
|
18
|
+
void tick;
|
|
19
|
+
return { bar: tool.active ? tool.bar() : null, mode: tool.mode, proportional: tool.proportional, interpolation: tool.interpolation, error: tool.error };
|
|
20
|
+
});
|
|
21
|
+
const bar = $derived(view.bar);
|
|
22
|
+
const chip = (on: boolean) => `px-2 py-1 rounded text-[11px] ${on ? 'bg-indigo-600 text-white' : 'bg-slate-800 text-slate-300 hover:text-white'}`;
|
|
23
|
+
const round = (v: number, unit: string) => (unit === 'px' ? Math.round(v * 10) / 10 : Math.round(v * 100) / 100);
|
|
24
|
+
|
|
25
|
+
function apply(field: FreeTransformField, raw: string) {
|
|
26
|
+
const b = tool.bar();
|
|
27
|
+
const v = Number(raw);
|
|
28
|
+
if (b && raw.trim() !== '' && Number.isFinite(v) && Math.abs(v - b[field]) > 1e-9) tool.setField(field, v);
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
{#if bar}
|
|
33
|
+
<div class="flex flex-wrap items-center gap-2 text-xs text-slate-200 {className}" data-testid="free-transform-options" role="toolbar" aria-label="Free Transform options">
|
|
34
|
+
<div class="flex gap-1" role="group" aria-label="Transform mode">
|
|
35
|
+
{#each FREE_TRANSFORM_MODE_OPTIONS as m (m.id)}
|
|
36
|
+
<button type="button" title={m.title} aria-pressed={view.mode === m.id} class={chip(view.mode === m.id)} onclick={() => tool.setMode(m.id)}>{m.label}</button>
|
|
37
|
+
{/each}
|
|
38
|
+
</div>
|
|
39
|
+
<div class="grid grid-cols-3 gap-px" role="group" aria-label="Reference point">
|
|
40
|
+
{#each TRANSFORM_ANCHORS as a (a)}
|
|
41
|
+
<button type="button" aria-label={`Reference point ${a}`} title={`Reference point: ${a}`} class="h-2.5 w-2.5 rounded-sm bg-slate-700 hover:bg-indigo-500" onclick={() => tool.setReference(a)}></button>
|
|
42
|
+
{/each}
|
|
43
|
+
</div>
|
|
44
|
+
{#each FREE_TRANSFORM_FIELDS as f (f.id)}
|
|
45
|
+
<label class="flex items-center gap-1" title={f.title}>
|
|
46
|
+
<span class="text-slate-400">{f.label}</span>
|
|
47
|
+
{#key round(bar[f.id], f.unit)}
|
|
48
|
+
<input
|
|
49
|
+
type="number"
|
|
50
|
+
aria-label={f.title}
|
|
51
|
+
value={round(bar[f.id], f.unit)}
|
|
52
|
+
disabled={!bar.affine}
|
|
53
|
+
step={f.unit === 'px' ? 1 : 0.1}
|
|
54
|
+
class="w-16 rounded border border-slate-700 bg-slate-900 px-1 py-0.5 text-right disabled:opacity-40"
|
|
55
|
+
onblur={(e) => apply(f.id, e.currentTarget.value)}
|
|
56
|
+
onkeydown={(e) => {
|
|
57
|
+
if (e.key === 'Enter') {
|
|
58
|
+
e.preventDefault();
|
|
59
|
+
e.stopPropagation();
|
|
60
|
+
apply(f.id, e.currentTarget.value);
|
|
61
|
+
}
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
{/key}
|
|
65
|
+
<span class="text-slate-500">{f.unit}</span>
|
|
66
|
+
{#if f.id === 'scaleX'}
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
aria-label="Keep width and height proportional"
|
|
70
|
+
aria-pressed={view.proportional}
|
|
71
|
+
class={chip(view.proportional)}
|
|
72
|
+
onclick={() => {
|
|
73
|
+
tool.proportional = !tool.proportional;
|
|
74
|
+
tick++;
|
|
75
|
+
}}>⛓︎</button>
|
|
76
|
+
{/if}
|
|
77
|
+
</label>
|
|
78
|
+
{/each}
|
|
79
|
+
<label class="flex items-center gap-1">
|
|
80
|
+
<span class="text-slate-400">Interpolation</span>
|
|
81
|
+
<select
|
|
82
|
+
aria-label="Interpolation"
|
|
83
|
+
value={view.interpolation}
|
|
84
|
+
onchange={(e) => tool.setInterpolation(e.currentTarget.value as Interpolation)}
|
|
85
|
+
class="rounded border border-slate-700 bg-slate-900 px-1 py-0.5"
|
|
86
|
+
>
|
|
87
|
+
{#each INTERPOLATIONS as i (i)}
|
|
88
|
+
<option value={i}>{i[0].toUpperCase() + i.slice(1)}</option>
|
|
89
|
+
{/each}
|
|
90
|
+
</select>
|
|
91
|
+
</label>
|
|
92
|
+
<button type="button" title="Commit (Enter)" class="px-2 py-1 rounded bg-emerald-600 text-white hover:bg-emerald-500" onclick={() => tool.commit()}>Commit</button>
|
|
93
|
+
<button type="button" title="Cancel (Esc)" class={chip(false)} onclick={() => tool.cancel()}>Cancel</button>
|
|
94
|
+
{#if view.error}
|
|
95
|
+
<span role="alert" class="text-rose-400">{view.error}</span>
|
|
96
|
+
{/if}
|
|
97
|
+
</div>
|
|
98
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FreeTransformTool } from '@pixerate/editor/image-editor';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
tool: FreeTransformTool;
|
|
4
|
+
class?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const FreeTransformOptionsBar: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type FreeTransformOptionsBar = ReturnType<typeof FreeTransformOptionsBar>;
|
|
8
|
+
export default FreeTransformOptionsBar;
|
|
9
|
+
//# sourceMappingURL=FreeTransformOptionsBar.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FreeTransformOptionsBar.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/FreeTransformOptionsBar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAsB,iBAAiB,EAAiB,MAAM,+BAA+B,CAAC;AAGzG,KAAK,gBAAgB,GAAI;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAmFtE,QAAA,MAAM,uBAAuB,sDAAwC,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
PaintGesture,
|
|
27
27
|
handlePaintShortcut,
|
|
28
28
|
pointerPressure,
|
|
29
|
+
FreeTransformTool,
|
|
30
|
+
getViewportProjection,
|
|
29
31
|
type SelectionToolOptions,
|
|
30
32
|
} from '@pixerate/editor/image-editor';
|
|
31
33
|
import ControlSlider from './ControlSlider.svelte';
|
|
@@ -35,6 +37,7 @@
|
|
|
35
37
|
import BrushOptionsBar from './BrushOptionsBar.svelte';
|
|
36
38
|
import SelectionOptionsBar from './SelectionOptionsBar.svelte';
|
|
37
39
|
import RefineEdgePanel from './RefineEdgePanel.svelte';
|
|
40
|
+
import FreeTransformOptionsBar from './FreeTransformOptionsBar.svelte';
|
|
38
41
|
import { onDestroy, untrack } from 'svelte';
|
|
39
42
|
import { createReactiveImageEditor, type ReactiveImageEditor } from './imageEditorState.svelte.js';
|
|
40
43
|
|
|
@@ -81,6 +84,75 @@
|
|
|
81
84
|
// Paint tools (Move, Brush, Eraser): the pointer gesture and the brush cursor.
|
|
82
85
|
const paintGesture = $derived(new PaintGesture(editor.controller));
|
|
83
86
|
let brushCursor: ImagePoint | null = null;
|
|
87
|
+
|
|
88
|
+
// Free Transform (Ctrl/Cmd+T): the shared tool drives a session; its overlay is drawn by the renderer.
|
|
89
|
+
const transformTool = $derived(
|
|
90
|
+
new FreeTransformTool(editor.controller, {
|
|
91
|
+
schedule: (run) => (typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(run) : run()),
|
|
92
|
+
})
|
|
93
|
+
);
|
|
94
|
+
let transformTick = $state(0);
|
|
95
|
+
let transformCursor = $state('default');
|
|
96
|
+
const transformActive = $derived((void transformTick, transformTool.active));
|
|
97
|
+
const transformError = $derived((void transformTick, transformTool.error));
|
|
98
|
+
$effect(() => {
|
|
99
|
+
const tool = transformTool;
|
|
100
|
+
const off = tool.subscribe(() => {
|
|
101
|
+
transformTick++;
|
|
102
|
+
void renderCanvas();
|
|
103
|
+
});
|
|
104
|
+
return () => {
|
|
105
|
+
off();
|
|
106
|
+
tool.cancel();
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
$effect(() => {
|
|
110
|
+
if (typeof window === 'undefined') return;
|
|
111
|
+
const tool = transformTool;
|
|
112
|
+
const onKey = (e: KeyboardEvent) => {
|
|
113
|
+
if (tool.key(e)) e.preventDefault();
|
|
114
|
+
};
|
|
115
|
+
window.addEventListener('keydown', onKey);
|
|
116
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
/** The document point of a pointer event and the hit tolerance (6 screen px). */
|
|
120
|
+
function transformPoint(e: PointerEvent) {
|
|
121
|
+
const rect = canvasEl!.getBoundingClientRect();
|
|
122
|
+
const sx = rect.width > 0 ? canvasEl!.width / rect.width : 1;
|
|
123
|
+
const sy = rect.height > 0 ? canvasEl!.height / rect.height : 1;
|
|
124
|
+
const s = editor.controller.getState();
|
|
125
|
+
const cropping = activeTab === 'crop';
|
|
126
|
+
const projection = getViewportProjection(s, canvasEl!.width, canvasEl!.height, cropping);
|
|
127
|
+
const pt = canvasToImagePoint({ x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy }, s, canvasEl!.width, canvasEl!.height, cropping);
|
|
128
|
+
transformTool.setView(projection.scale);
|
|
129
|
+
return { pt, tolerance: 6 / (projection.scale || 1) };
|
|
130
|
+
}
|
|
131
|
+
function handleTransformPointerDown(e: PointerEvent): boolean {
|
|
132
|
+
if (!transformTool.active || !canvasEl) return false;
|
|
133
|
+
if (e.button !== 0) return true;
|
|
134
|
+
e.preventDefault();
|
|
135
|
+
try {
|
|
136
|
+
canvasEl.setPointerCapture?.(e.pointerId);
|
|
137
|
+
} catch {
|
|
138
|
+
// Synthetic events have no active pointer to capture.
|
|
139
|
+
}
|
|
140
|
+
const { pt, tolerance } = transformPoint(e);
|
|
141
|
+
transformTool.down(pt, tolerance);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
function handleTransformPointerMove(e: PointerEvent): boolean {
|
|
145
|
+
if (!transformTool.active || !canvasEl) return false;
|
|
146
|
+
const { pt, tolerance } = transformPoint(e);
|
|
147
|
+
if (e.buttons & 1) transformTool.move(pt, e);
|
|
148
|
+
else transformCursor = transformTool.cursor(transformTool.hit(pt, tolerance));
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
function handleTransformPointerUp(): boolean {
|
|
152
|
+
if (!transformTool.active) return false;
|
|
153
|
+
transformTool.up();
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
84
156
|
let paintError = $state<string | null>(null);
|
|
85
157
|
let selectionDraft = $state.raw<ImagePoint[] | null>(null);
|
|
86
158
|
let selectionError = $state<string | null>(null);
|
|
@@ -216,9 +288,10 @@
|
|
|
216
288
|
draftCrop: overrideCrop !== undefined ? overrideCrop : draftCrop,
|
|
217
289
|
draftSelectionPath: selectionDraft,
|
|
218
290
|
brushCursor:
|
|
219
|
-
activeTab === 'paint' && brushCursor && editor.controller.getState().activeTool !== 'move'
|
|
291
|
+
activeTab === 'paint' && brushCursor && editor.controller.getState().activeTool !== 'move' && !transformTool.active
|
|
220
292
|
? { ...brushCursor, diameter: editor.controller.getState().paint.brush.size }
|
|
221
293
|
: null,
|
|
294
|
+
freeTransform: transformTool.overlay(),
|
|
222
295
|
});
|
|
223
296
|
}
|
|
224
297
|
|
|
@@ -236,6 +309,7 @@
|
|
|
236
309
|
}));
|
|
237
310
|
}
|
|
238
311
|
function handlePaintPointerDown(e: PointerEvent) {
|
|
312
|
+
if (handleTransformPointerDown(e)) return;
|
|
239
313
|
if (activeTab !== 'paint' || e.button !== 0 || !canvasEl) return;
|
|
240
314
|
e.preventDefault();
|
|
241
315
|
try {
|
|
@@ -246,6 +320,7 @@
|
|
|
246
320
|
paintError = paintGesture.down(paintSamples(e)[0]);
|
|
247
321
|
}
|
|
248
322
|
function handlePaintPointerMove(e: PointerEvent) {
|
|
323
|
+
if (handleTransformPointerMove(e)) return;
|
|
249
324
|
if (activeTab !== 'paint' || !canvasEl) return;
|
|
250
325
|
const samples = paintSamples(e);
|
|
251
326
|
brushCursor = samples[samples.length - 1] ?? null;
|
|
@@ -253,6 +328,7 @@
|
|
|
253
328
|
else void renderCanvas();
|
|
254
329
|
}
|
|
255
330
|
function handlePaintPointerUp() {
|
|
331
|
+
if (handleTransformPointerUp()) return;
|
|
256
332
|
if (activeTab !== 'paint' || !paintGesture.active) return;
|
|
257
333
|
paintGesture.up();
|
|
258
334
|
if (paintGesture.error) paintError = paintGesture.error;
|
|
@@ -319,7 +395,7 @@
|
|
|
319
395
|
}
|
|
320
396
|
|
|
321
397
|
function handleMouseDown(e: MouseEvent) {
|
|
322
|
-
if (!canvasEl) return;
|
|
398
|
+
if (!canvasEl || transformTool.active) return;
|
|
323
399
|
const canvasPt = getCanvasEventPoint(e);
|
|
324
400
|
|
|
325
401
|
if (activeTab === 'select') {
|
|
@@ -398,7 +474,7 @@
|
|
|
398
474
|
}
|
|
399
475
|
|
|
400
476
|
function handleMouseMove(e: MouseEvent) {
|
|
401
|
-
if (!canvasEl) return;
|
|
477
|
+
if (!canvasEl || transformTool.active) return;
|
|
402
478
|
const canvasPt = getCanvasEventPoint(e);
|
|
403
479
|
|
|
404
480
|
if (activeTab === 'select') {
|
|
@@ -559,7 +635,7 @@
|
|
|
559
635
|
}
|
|
560
636
|
|
|
561
637
|
function handleMouseUp(e: MouseEvent) {
|
|
562
|
-
if (!canvasEl) return;
|
|
638
|
+
if (!canvasEl || transformTool.active) return;
|
|
563
639
|
const canvasPt = getCanvasEventPoint(e);
|
|
564
640
|
|
|
565
641
|
if (activeTab === 'select') {
|
|
@@ -876,6 +952,13 @@
|
|
|
876
952
|
</div>
|
|
877
953
|
|
|
878
954
|
<!-- Main Viewport + Sidebar Layout -->
|
|
955
|
+
<!-- Free Transform options bar (Ctrl/Cmd+T), above the viewport while a transform is open -->
|
|
956
|
+
{#if transformActive}
|
|
957
|
+
<FreeTransformOptionsBar tool={transformTool} class="border-b border-slate-800 bg-slate-900/95 px-4 py-2" />
|
|
958
|
+
{:else if transformError}
|
|
959
|
+
<div role="alert" class="border-b border-rose-900 bg-rose-950/80 px-4 py-1.5 text-xs text-rose-200">{transformError}</div>
|
|
960
|
+
{/if}
|
|
961
|
+
|
|
879
962
|
<div class="flex flex-col md:flex-row flex-1 min-h-[520px] md:h-[560px]">
|
|
880
963
|
<!-- Canvas Area -->
|
|
881
964
|
<div
|
|
@@ -893,8 +976,10 @@
|
|
|
893
976
|
onpointerup={handlePaintPointerUp}
|
|
894
977
|
onpointercancel={() => paintGesture.cancel()}
|
|
895
978
|
data-testid="image-editor-canvas"
|
|
896
|
-
|
|
979
|
+
style={transformActive ? `cursor: ${transformCursor}` : undefined}
|
|
980
|
+
class="absolute inset-0 w-full h-full block {transformActive ? 'touch-none' : activeTab === 'paint' ? 'touch-none cursor-crosshair' : ''}"
|
|
897
981
|
></canvas>
|
|
982
|
+
|
|
898
983
|
</div>
|
|
899
984
|
|
|
900
985
|
<!-- Tab Controls Sidebar -->
|
|
@@ -1076,6 +1161,12 @@
|
|
|
1076
1161
|
{#if activeTab === 'layers'}
|
|
1077
1162
|
<div class="flex flex-col gap-3 text-xs">
|
|
1078
1163
|
<span class="font-semibold text-slate-200 uppercase tracking-wider text-[11px]">Layers</span>
|
|
1164
|
+
<button
|
|
1165
|
+
type="button"
|
|
1166
|
+
title="Edit › Free Transform (Ctrl/Cmd+T): the selected pixels, or the whole active layer"
|
|
1167
|
+
class="px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40"
|
|
1168
|
+
disabled={transformActive}
|
|
1169
|
+
onclick={() => transformTool.begin()}>Free Transform</button>
|
|
1079
1170
|
<LayersPanel controller={editor.controller} />
|
|
1080
1171
|
</div>
|
|
1081
1172
|
{/if}
|
|
@@ -1084,6 +1175,12 @@
|
|
|
1084
1175
|
<div class="flex flex-col gap-3 text-xs">
|
|
1085
1176
|
<span class="font-semibold text-slate-200 uppercase tracking-wider text-[11px]">Paint</span>
|
|
1086
1177
|
<BrushOptionsBar controller={editor.controller} />
|
|
1178
|
+
<button
|
|
1179
|
+
type="button"
|
|
1180
|
+
title="Edit › Free Transform (Ctrl/Cmd+T): the selected pixels, or the whole active layer"
|
|
1181
|
+
class="px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40"
|
|
1182
|
+
disabled={transformActive}
|
|
1183
|
+
onclick={() => transformTool.begin()}>Free Transform</button>
|
|
1087
1184
|
{#if paintError}
|
|
1088
1185
|
<p role="alert" class="text-rose-400" data-testid="paint-error">{paintError}</p>
|
|
1089
1186
|
{/if}
|
|
@@ -1331,6 +1428,20 @@
|
|
|
1331
1428
|
{#if selectionError}
|
|
1332
1429
|
<p role="alert" class="text-rose-400">{selectionError}</p>
|
|
1333
1430
|
{/if}
|
|
1431
|
+
<div class="flex gap-1">
|
|
1432
|
+
<button
|
|
1433
|
+
type="button"
|
|
1434
|
+
title="Select › Transform Selection: the outline only"
|
|
1435
|
+
class="px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40"
|
|
1436
|
+
disabled={transformActive}
|
|
1437
|
+
onclick={() => transformTool.begin({ content: 'selection-outline' })}>Transform Selection</button>
|
|
1438
|
+
<button
|
|
1439
|
+
type="button"
|
|
1440
|
+
title="Edit › Free Transform: the selected pixels of the active layer"
|
|
1441
|
+
class="px-2 py-1 rounded text-[11px] bg-slate-800 text-slate-300 hover:text-white self-start disabled:opacity-40"
|
|
1442
|
+
disabled={transformActive}
|
|
1443
|
+
onclick={() => transformTool.begin({ content: 'selection' })}>Free Transform Pixels</button>
|
|
1444
|
+
</div>
|
|
1334
1445
|
<RefineEdgePanel
|
|
1335
1446
|
controller={editor.controller}
|
|
1336
1447
|
selection={editor.state.selection ?? null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/ImageEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAIR,aAAa,EAGb,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACf,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"ImageEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/ImageEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAIR,aAAa,EAGb,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACf,MAAM,+BAA+B,CAAC;AA6BzC,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGjG,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AA+uCH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -326,6 +326,19 @@
|
|
|
326
326
|
class="shrink-0 grid place-items-center rounded bg-slate-800 text-[9px] text-slate-400 ring-1 ring-slate-700"
|
|
327
327
|
style="width: {thumbnailSize}px; height: {thumbnailSize}px">{layerBadge(layer)}</span>
|
|
328
328
|
{/if}
|
|
329
|
+
{#if layer.mask && !layer.mask.source && layer.type === 'pixel'}
|
|
330
|
+
<button
|
|
331
|
+
type="button"
|
|
332
|
+
aria-label={`${layer.mask.linked === false ? 'Link' : 'Unlink'} ${row.label} mask`}
|
|
333
|
+
aria-pressed={layer.mask.linked !== false}
|
|
334
|
+
title={layer.mask.linked === false ? 'Mask unlinked: it stays put when the layer moves or transforms. Click to link.' : 'Mask linked: it moves with the layer. Click to unlink.'}
|
|
335
|
+
data-testid="layer-mask-link"
|
|
336
|
+
class="shrink-0 text-[10px] leading-none {layer.mask.linked === false ? 'text-slate-600' : 'text-slate-300'}"
|
|
337
|
+
onclick={(e) => {
|
|
338
|
+
e.stopPropagation();
|
|
339
|
+
attempt(() => controller.setLayerMaskProps(layer.id, { linked: layer.mask!.linked === false }));
|
|
340
|
+
}}>{layer.mask.linked === false ? '⛓︎̸' : '⛓︎'}</button>
|
|
341
|
+
{/if}
|
|
329
342
|
{#if layer.mask}
|
|
330
343
|
<canvas
|
|
331
344
|
use:paint={maskThumb(layer)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LayersPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/LayersPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAA2D,MAAM,+BAA+B,CAAC;AAkBlI,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,yCAAyC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"LayersPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/LayersPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAA2D,MAAM,+BAA+B,CAAC;AAkBlI,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,yCAAyC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAwRH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -9,6 +9,7 @@ import type RefineEdgePanelComponent from "./RefineEdgePanel.svelte";
|
|
|
9
9
|
import type LayersPanelComponent from "./LayersPanel.svelte";
|
|
10
10
|
import type LayerEffectsPanelComponent from "./LayerEffectsPanel.svelte";
|
|
11
11
|
import type BrushOptionsBarComponent from "./BrushOptionsBar.svelte";
|
|
12
|
+
import type FreeTransformOptionsBarComponent from "./FreeTransformOptionsBar.svelte";
|
|
12
13
|
export { default as ImageEditor } from './ImageEditor.svelte';
|
|
13
14
|
export { default as Histogram } from './Histogram.svelte';
|
|
14
15
|
export { default as AdjustmentLayersPanel } from './AdjustmentLayersPanel.svelte';
|
|
@@ -19,6 +20,7 @@ export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
|
19
20
|
export { default as LayersPanel } from './LayersPanel.svelte';
|
|
20
21
|
export { default as LayerEffectsPanel } from './LayerEffectsPanel.svelte';
|
|
21
22
|
export { default as BrushOptionsBar } from './BrushOptionsBar.svelte';
|
|
23
|
+
export { default as FreeTransformOptionsBar } from './FreeTransformOptionsBar.svelte';
|
|
22
24
|
export * from './imageEditorState.svelte.js';
|
|
23
25
|
export type ImageEditorProps = ComponentProps<typeof ImageEditorComponent>;
|
|
24
26
|
export type HistogramProps = ComponentProps<typeof HistogramComponent>;
|
|
@@ -30,5 +32,6 @@ export type RefineEdgePanelProps = ComponentProps<typeof RefineEdgePanelComponen
|
|
|
30
32
|
export type LayersPanelProps = ComponentProps<typeof LayersPanelComponent>;
|
|
31
33
|
export type LayerEffectsPanelProps = ComponentProps<typeof LayerEffectsPanelComponent>;
|
|
32
34
|
export type BrushOptionsBarProps = ComponentProps<typeof BrushOptionsBarComponent>;
|
|
35
|
+
export type FreeTransformOptionsBarProps = ComponentProps<typeof FreeTransformOptionsBarComponent>;
|
|
33
36
|
export { applyRegionMosaic, applyRegionBlur, resolveMosaicRegionBounds, type MosaicRegion, type MosaicImageDataLike } from '@pixerate/editor/image-editor';
|
|
34
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/image-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,kBAAkB,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,8BAA8B,MAAM,gCAAgC,CAAC;AACjF,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,4BAA4B,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,0BAA0B,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/image-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,kBAAkB,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,8BAA8B,MAAM,gCAAgC,CAAC;AACjF,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,4BAA4B,MAAM,8BAA8B,CAAC;AAC7E,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,0BAA0B,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,wBAAwB,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,gCAAgC,MAAM,kCAAkC,CAAC;AAErF,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AACtF,cAAc,8BAA8B,CAAC;AAE7C,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACvE,MAAM,MAAM,0BAA0B,GAAG,cAAc,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAC/F,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAC3F,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,wBAAwB,CAAC,CAAC;AACnF,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,sBAAsB,GAAG,cAAc,CAAC,OAAO,0BAA0B,CAAC,CAAC;AACvF,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,wBAAwB,CAAC,CAAC;AACnF,MAAM,MAAM,4BAA4B,GAAG,cAAc,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAEnG,OAAO,EACN,iBAAiB,EACjB,eAAe,EACf,yBAAyB,EACzB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,MAAM,+BAA+B,CAAC"}
|
|
@@ -8,5 +8,6 @@ export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
|
8
8
|
export { default as LayersPanel } from './LayersPanel.svelte';
|
|
9
9
|
export { default as LayerEffectsPanel } from './LayerEffectsPanel.svelte';
|
|
10
10
|
export { default as BrushOptionsBar } from './BrushOptionsBar.svelte';
|
|
11
|
+
export { default as FreeTransformOptionsBar } from './FreeTransformOptionsBar.svelte';
|
|
11
12
|
export * from './imageEditorState.svelte.js';
|
|
12
13
|
export { applyRegionMosaic, applyRegionBlur, resolveMosaicRegionBounds } from '@pixerate/editor/image-editor';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.74.0",
|
|
4
4
|
"description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"@tiptap/extension-bubble-menu": "^2.11.5",
|
|
132
132
|
"@tiptap/extension-placeholder": "^2.11.5",
|
|
133
133
|
"@tiptap/starter-kit": "^2.11.5",
|
|
134
|
-
"@pixerate/editor": "0.
|
|
134
|
+
"@pixerate/editor": "0.99.0"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
137
|
"@dagrejs/dagre": "^1.1.4",
|