@pixerate/editor-svelte 0.157.0 → 0.159.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/EdgeColorPanel.svelte +102 -0
- package/dist/image-editor/EdgeColorPanel.svelte.d.ts +15 -0
- package/dist/image-editor/LayersPanel.svelte +7 -0
- package/dist/image-editor/MaskEdgeCheck.svelte +76 -0
- package/dist/image-editor/MaskEdgeCheck.svelte.d.ts +17 -0
- package/dist/image-editor/RefineEdgePanel.svelte +2 -0
- package/dist/image-editor/index.d.ts +6 -0
- package/dist/image-editor/index.js +2 -0
- package/package.json +2 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ImageEditorController, ImageLayer } from '@pixerate/editor/image-editor';
|
|
3
|
+
import { untrack } from 'svelte';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Edge Colour: decontamination, despill and the live edge cast of a layer's soft edge, applied
|
|
7
|
+
* when compositing (nothing is baked), as the `set_edge_*` tools set them. A slider drag is one
|
|
8
|
+
* undo step.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
controller: ImageEditorController;
|
|
12
|
+
/** The layer to edit (a pixel, shape, type or smart object layer). */
|
|
13
|
+
layer: ImageLayer;
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let { controller, layer, class: className = '' }: Props = $props();
|
|
18
|
+
|
|
19
|
+
const SLIDERS = [
|
|
20
|
+
{ key: 'decontaminate', label: 'Decontaminate', hint: 'Unmix the old background from a soft-edged mask' },
|
|
21
|
+
{ key: 'despill', label: 'Despill', hint: "Take out the old background's hue at the edge" },
|
|
22
|
+
{ key: 'ambient', label: 'Cast', hint: 'Tint the edge with what is behind the layer, live' },
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
let tick = $state(0);
|
|
26
|
+
$effect(() => {
|
|
27
|
+
const c = controller;
|
|
28
|
+
return untrack(() => c.subscribe(() => tick++));
|
|
29
|
+
});
|
|
30
|
+
let error = $state<string | null>(null);
|
|
31
|
+
let commitNext = true;
|
|
32
|
+
const info = $derived.by(() => {
|
|
33
|
+
void tick;
|
|
34
|
+
return controller.getEdgeColor(layer.id);
|
|
35
|
+
});
|
|
36
|
+
const fixed = $derived(info.ambientSource !== 'auto');
|
|
37
|
+
|
|
38
|
+
function set(change: Parameters<ImageEditorController['setEdgeColor']>[1]) {
|
|
39
|
+
error = null;
|
|
40
|
+
try {
|
|
41
|
+
controller.setEdgeColor(layer.id, change, commitNext);
|
|
42
|
+
commitNext = false;
|
|
43
|
+
} catch (err) {
|
|
44
|
+
error = err instanceof Error ? err.message : String(err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const startDrag = () => (commitNext = true);
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<details class="text-xs {className}" data-testid="edge-color-panel" open={Boolean(info.decontaminate || info.despill || info.ambient) || undefined}>
|
|
51
|
+
<summary class="cursor-pointer text-muted-foreground">Edge Colour</summary>
|
|
52
|
+
<div class="flex flex-col gap-1.5 pt-1">
|
|
53
|
+
{#each SLIDERS as s (s.key)}
|
|
54
|
+
<label class="flex flex-col gap-0.5" title={s.hint}>
|
|
55
|
+
<span class="flex justify-between text-muted-foreground">
|
|
56
|
+
<span>{s.label}</span>
|
|
57
|
+
<span class="font-mono">{info[s.key]}%</span>
|
|
58
|
+
</span>
|
|
59
|
+
<input
|
|
60
|
+
type="range"
|
|
61
|
+
min="0"
|
|
62
|
+
max="100"
|
|
63
|
+
aria-label="Edge {s.label.toLowerCase()}"
|
|
64
|
+
value={info[s.key]}
|
|
65
|
+
onpointerdown={startDrag}
|
|
66
|
+
onpointerup={startDrag}
|
|
67
|
+
onkeydown={startDrag}
|
|
68
|
+
oninput={(e) => set({ [s.key]: Number((e.currentTarget as HTMLInputElement).value) })}
|
|
69
|
+
class="accent-primary"
|
|
70
|
+
/>
|
|
71
|
+
</label>
|
|
72
|
+
{/each}
|
|
73
|
+
<label class="flex items-center gap-1.5 text-foreground">
|
|
74
|
+
<input
|
|
75
|
+
type="checkbox"
|
|
76
|
+
aria-label="Fixed cast colour"
|
|
77
|
+
checked={fixed}
|
|
78
|
+
onchange={(e) => {
|
|
79
|
+
commitNext = true;
|
|
80
|
+
set({ ambientColor: (e.currentTarget as HTMLInputElement).checked ? '#808080' : 'auto' });
|
|
81
|
+
}}
|
|
82
|
+
class="accent-primary"
|
|
83
|
+
/>
|
|
84
|
+
Fixed cast colour
|
|
85
|
+
{#if fixed}
|
|
86
|
+
<input
|
|
87
|
+
type="color"
|
|
88
|
+
aria-label="Cast colour"
|
|
89
|
+
value={info.ambientSource}
|
|
90
|
+
onchange={(e) => {
|
|
91
|
+
commitNext = true;
|
|
92
|
+
set({ ambientColor: (e.currentTarget as HTMLInputElement).value });
|
|
93
|
+
}}
|
|
94
|
+
class="h-5 w-8 bg-background border border-border rounded"
|
|
95
|
+
/>
|
|
96
|
+
{/if}
|
|
97
|
+
</label>
|
|
98
|
+
{#if error}
|
|
99
|
+
<p role="alert" class="text-destructive">{error}</p>
|
|
100
|
+
{/if}
|
|
101
|
+
</div>
|
|
102
|
+
</details>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImageEditorController, ImageLayer } from '@pixerate/editor/image-editor';
|
|
2
|
+
/**
|
|
3
|
+
* Edge Colour: decontamination, despill and the live edge cast of a layer's soft edge, applied
|
|
4
|
+
* when compositing (nothing is baked), as the `set_edge_*` tools set them. A slider drag is one
|
|
5
|
+
* undo step.
|
|
6
|
+
*/
|
|
7
|
+
interface Props {
|
|
8
|
+
controller: ImageEditorController;
|
|
9
|
+
/** The layer to edit (a pixel, shape, type or smart object layer). */
|
|
10
|
+
layer: ImageLayer;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
declare const EdgeColorPanel: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type EdgeColorPanel = ReturnType<typeof EdgeColorPanel>;
|
|
15
|
+
export default EdgeColorPanel;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
} from '@pixerate/editor/image-editor';
|
|
24
24
|
import { untrack } from 'svelte';
|
|
25
25
|
import LayerEffectsPanel from './LayerEffectsPanel.svelte';
|
|
26
|
+
import EdgeColorPanel from './EdgeColorPanel.svelte';
|
|
26
27
|
|
|
27
28
|
interface Props {
|
|
28
29
|
controller: ImageEditorController;
|
|
@@ -283,6 +284,12 @@
|
|
|
283
284
|
</div>
|
|
284
285
|
{/if}
|
|
285
286
|
|
|
287
|
+
{#if snapshot.active && (snapshot.active.type === 'pixel' || snapshot.active.type === 'shape' || snapshot.active.type === 'type' || snapshot.active.type === 'smart')}
|
|
288
|
+
{#key snapshot.active.id}
|
|
289
|
+
<EdgeColorPanel {controller} layer={snapshot.active} class="border-t border-border pt-1.5" />
|
|
290
|
+
{/key}
|
|
291
|
+
{/if}
|
|
292
|
+
|
|
286
293
|
{#if effects && snapshot.active && snapshot.active.type !== 'adjustment'}
|
|
287
294
|
<LayerEffectsPanel {controller} class="border-t border-border pt-1.5" />
|
|
288
295
|
{/if}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ImageEditorController, MaskEdgeReport, MaskEdgeTarget, SelectionMask } from '@pixerate/editor/image-editor';
|
|
3
|
+
import { MASK_EDGE_THRESHOLDS } from '@pixerate/editor/image-editor';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check Edge: measures the selection's (or a mask's) edge, as the `inspect_mask_edge` tool does,
|
|
7
|
+
* and lists the scores (flagged past the thresholds), holes, islands and findings with fixes.
|
|
8
|
+
*/
|
|
9
|
+
interface Props {
|
|
10
|
+
controller: ImageEditorController;
|
|
11
|
+
/** The current selection (`state.selection`): a report on an older selection is cleared. */
|
|
12
|
+
selection?: SelectionMask | null;
|
|
13
|
+
/** What to check (default the selection); masks need `layerId`. */
|
|
14
|
+
target?: MaskEdgeTarget;
|
|
15
|
+
layerId?: string;
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let { controller, selection, target = 'selection', layerId, class: className = '' }: Props = $props();
|
|
20
|
+
|
|
21
|
+
const button =
|
|
22
|
+
'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';
|
|
23
|
+
const sel = $derived(selection === undefined ? controller.getSelection() : selection);
|
|
24
|
+
let result = $state<{ report: MaskEdgeReport; for: SelectionMask | null } | null>(null);
|
|
25
|
+
let error = $state<string | null>(null);
|
|
26
|
+
const report = $derived(result && (target !== 'selection' || result.for === sel) ? result.report : null);
|
|
27
|
+
const T = MASK_EDGE_THRESHOLDS;
|
|
28
|
+
const rows = $derived(
|
|
29
|
+
report
|
|
30
|
+
? [
|
|
31
|
+
{ label: 'Halo', value: report.haloScore, bad: report.haloScore >= T.halo },
|
|
32
|
+
{ label: 'Edge alignment', value: report.edgeAlignment, bad: report.edgeAlignment < T.alignment },
|
|
33
|
+
{ label: 'Jaggedness', value: report.jaggedness, bad: report.jaggedness >= T.jaggedness },
|
|
34
|
+
{ label: 'Soft edge', value: report.softFraction, bad: report.softFraction >= T.soft },
|
|
35
|
+
]
|
|
36
|
+
: []
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
function check() {
|
|
40
|
+
error = null;
|
|
41
|
+
try {
|
|
42
|
+
result = { report: controller.inspectMaskEdge(target, { layerId }), for: sel };
|
|
43
|
+
} catch (err) {
|
|
44
|
+
result = null;
|
|
45
|
+
error = err instanceof Error ? err.message : String(err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<div data-testid="mask-edge-check" class="flex flex-col gap-1.5 text-xs {className}">
|
|
51
|
+
<button type="button" class="{button} self-start" disabled={target === 'selection' && !sel} onclick={check}>Check Edge</button>
|
|
52
|
+
{#if report}
|
|
53
|
+
<dl class="grid grid-cols-[1fr_auto] gap-x-2 gap-y-0.5">
|
|
54
|
+
{#each rows as r (r.label)}
|
|
55
|
+
<dt class="text-muted-foreground">{r.label}</dt>
|
|
56
|
+
<dd class="font-mono text-right {r.bad ? 'text-destructive' : 'text-foreground'}">{r.value}</dd>
|
|
57
|
+
{/each}
|
|
58
|
+
<dt class="text-muted-foreground">Holes / islands</dt>
|
|
59
|
+
<dd class="font-mono text-right {report.holes.count || report.islands.count ? 'text-destructive' : 'text-foreground'}">
|
|
60
|
+
{report.holes.count} / {report.islands.count}
|
|
61
|
+
</dd>
|
|
62
|
+
</dl>
|
|
63
|
+
{#if report.issues.length}
|
|
64
|
+
<ul data-testid="mask-edge-issues" class="list-disc pl-4 flex flex-col gap-1 text-foreground">
|
|
65
|
+
{#each report.issues as s (s)}
|
|
66
|
+
<li>{s}</li>
|
|
67
|
+
{/each}
|
|
68
|
+
</ul>
|
|
69
|
+
{:else}
|
|
70
|
+
<p class="text-muted-foreground">The edge looks clean.</p>
|
|
71
|
+
{/if}
|
|
72
|
+
{/if}
|
|
73
|
+
{#if error}
|
|
74
|
+
<p role="alert" class="text-destructive">{error}</p>
|
|
75
|
+
{/if}
|
|
76
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ImageEditorController, MaskEdgeTarget, SelectionMask } from '@pixerate/editor/image-editor';
|
|
2
|
+
/**
|
|
3
|
+
* Check Edge: measures the selection's (or a mask's) edge, as the `inspect_mask_edge` tool does,
|
|
4
|
+
* and lists the scores (flagged past the thresholds), holes, islands and findings with fixes.
|
|
5
|
+
*/
|
|
6
|
+
interface Props {
|
|
7
|
+
controller: ImageEditorController;
|
|
8
|
+
/** The current selection (`state.selection`): a report on an older selection is cleared. */
|
|
9
|
+
selection?: SelectionMask | null;
|
|
10
|
+
/** What to check (default the selection); masks need `layerId`. */
|
|
11
|
+
target?: MaskEdgeTarget;
|
|
12
|
+
layerId?: string;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const MaskEdgeCheck: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type MaskEdgeCheck = ReturnType<typeof MaskEdgeCheck>;
|
|
17
|
+
export default MaskEdgeCheck;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { imageRangeClass, imageSectionTitleClass } from './styles.js';
|
|
3
|
+
import MaskEdgeCheck from './MaskEdgeCheck.svelte';
|
|
3
4
|
import type {
|
|
4
5
|
AdjustmentKind,
|
|
5
6
|
AdjustmentLayer,
|
|
@@ -157,6 +158,7 @@
|
|
|
157
158
|
{#if error}
|
|
158
159
|
<p role="alert" class="text-destructive">{error}</p>
|
|
159
160
|
{/if}
|
|
161
|
+
<MaskEdgeCheck {controller} selection={sel} />
|
|
160
162
|
|
|
161
163
|
<span class="font-semibold text-foreground uppercase tracking-wider text-[11px] mt-2">Layer Mask</span>
|
|
162
164
|
<div class="flex gap-1 items-center">
|
|
@@ -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 MaskEdgeCheckComponent from "./MaskEdgeCheck.svelte";
|
|
11
12
|
import type PathsPanelComponent from "./PathsPanel.svelte";
|
|
12
13
|
import type SelectAndMaskWorkspaceComponent from "./SelectAndMaskWorkspace.svelte";
|
|
13
14
|
import type ContentAwareFillWorkspaceComponent from "./ContentAwareFillWorkspace.svelte";
|
|
@@ -15,6 +16,7 @@ import type ChannelsPanelComponent from "./ChannelsPanel.svelte";
|
|
|
15
16
|
import type LayersPanelComponent from "./LayersPanel.svelte";
|
|
16
17
|
import type ColorProfilePanelComponent from "./ColorProfilePanel.svelte";
|
|
17
18
|
import type LayerEffectsPanelComponent from "./LayerEffectsPanel.svelte";
|
|
19
|
+
import type EdgeColorPanelComponent from "./EdgeColorPanel.svelte";
|
|
18
20
|
import type BrushOptionsBarComponent from "./BrushOptionsBar.svelte";
|
|
19
21
|
import type FreeTransformOptionsBarComponent from "./FreeTransformOptionsBar.svelte";
|
|
20
22
|
import type ShapeOptionsBarComponent from "./ShapeOptionsBar.svelte";
|
|
@@ -35,6 +37,7 @@ export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
|
35
37
|
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
36
38
|
export { default as SelectionOptionsBar } from './SelectionOptionsBar.svelte';
|
|
37
39
|
export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
40
|
+
export { default as MaskEdgeCheck } from './MaskEdgeCheck.svelte';
|
|
38
41
|
export { default as PathsPanel } from './PathsPanel.svelte';
|
|
39
42
|
export { default as SelectAndMaskWorkspace } from './SelectAndMaskWorkspace.svelte';
|
|
40
43
|
export { default as ContentAwareFillWorkspace } from './ContentAwareFillWorkspace.svelte';
|
|
@@ -42,6 +45,7 @@ export { default as ChannelsPanel } from './ChannelsPanel.svelte';
|
|
|
42
45
|
export { default as LayersPanel } from './LayersPanel.svelte';
|
|
43
46
|
export { default as ColorProfilePanel } from './ColorProfilePanel.svelte';
|
|
44
47
|
export { default as LayerEffectsPanel } from './LayerEffectsPanel.svelte';
|
|
48
|
+
export { default as EdgeColorPanel } from './EdgeColorPanel.svelte';
|
|
45
49
|
export { default as BrushOptionsBar } from './BrushOptionsBar.svelte';
|
|
46
50
|
export { default as FreeTransformOptionsBar } from './FreeTransformOptionsBar.svelte';
|
|
47
51
|
export { default as ShapeOptionsBar } from './ShapeOptionsBar.svelte';
|
|
@@ -64,6 +68,7 @@ export type CurvesEditorProps = ComponentProps<typeof CurvesEditorComponent>;
|
|
|
64
68
|
export type ControlSliderProps = ComponentProps<typeof ControlSliderComponent>;
|
|
65
69
|
export type SelectionOptionsBarProps = ComponentProps<typeof SelectionOptionsBarComponent>;
|
|
66
70
|
export type RefineEdgePanelProps = ComponentProps<typeof RefineEdgePanelComponent>;
|
|
71
|
+
export type MaskEdgeCheckProps = ComponentProps<typeof MaskEdgeCheckComponent>;
|
|
67
72
|
export type PathsPanelProps = ComponentProps<typeof PathsPanelComponent>;
|
|
68
73
|
export type SelectAndMaskWorkspaceProps = ComponentProps<typeof SelectAndMaskWorkspaceComponent>;
|
|
69
74
|
export type ContentAwareFillWorkspaceProps = ComponentProps<typeof ContentAwareFillWorkspaceComponent>;
|
|
@@ -71,6 +76,7 @@ export type ChannelsPanelProps = ComponentProps<typeof ChannelsPanelComponent>;
|
|
|
71
76
|
export type LayersPanelProps = ComponentProps<typeof LayersPanelComponent>;
|
|
72
77
|
export type ColorProfilePanelProps = ComponentProps<typeof ColorProfilePanelComponent>;
|
|
73
78
|
export type LayerEffectsPanelProps = ComponentProps<typeof LayerEffectsPanelComponent>;
|
|
79
|
+
export type EdgeColorPanelProps = ComponentProps<typeof EdgeColorPanelComponent>;
|
|
74
80
|
export type BrushOptionsBarProps = ComponentProps<typeof BrushOptionsBarComponent>;
|
|
75
81
|
export type FreeTransformOptionsBarProps = ComponentProps<typeof FreeTransformOptionsBarComponent>;
|
|
76
82
|
export type ShapeOptionsBarProps = ComponentProps<typeof ShapeOptionsBarComponent>;
|
|
@@ -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 MaskEdgeCheck } from './MaskEdgeCheck.svelte';
|
|
13
14
|
export { default as PathsPanel } from './PathsPanel.svelte';
|
|
14
15
|
export { default as SelectAndMaskWorkspace } from './SelectAndMaskWorkspace.svelte';
|
|
15
16
|
export { default as ContentAwareFillWorkspace } from './ContentAwareFillWorkspace.svelte';
|
|
@@ -17,6 +18,7 @@ export { default as ChannelsPanel } from './ChannelsPanel.svelte';
|
|
|
17
18
|
export { default as LayersPanel } from './LayersPanel.svelte';
|
|
18
19
|
export { default as ColorProfilePanel } from './ColorProfilePanel.svelte';
|
|
19
20
|
export { default as LayerEffectsPanel } from './LayerEffectsPanel.svelte';
|
|
21
|
+
export { default as EdgeColorPanel } from './EdgeColorPanel.svelte';
|
|
20
22
|
export { default as BrushOptionsBar } from './BrushOptionsBar.svelte';
|
|
21
23
|
export { default as FreeTransformOptionsBar } from './FreeTransformOptionsBar.svelte';
|
|
22
24
|
export { default as ShapeOptionsBar } from './ShapeOptionsBar.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor-svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.159.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.215.0"
|
|
169
169
|
},
|
|
170
170
|
"peerDependencies": {
|
|
171
171
|
"@dagrejs/dagre": "^1.1.4",
|