@pixerate/editor-svelte 0.128.4 → 0.129.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/effects/EffectParameters.svelte +48 -5
- package/dist/effects/EffectParameters.svelte.d.ts +3 -0
- package/dist/image-editor/AdjustmentLayersPanel.svelte +3 -14
- package/dist/image-editor/BrushOptionsBar.svelte +4 -15
- package/dist/image-editor/ImageEditor.svelte +2 -5
- package/dist/image-editor/ImageEffectControls.svelte +9 -2
- package/dist/image-editor/ImageEffectControls.svelte.d.ts +3 -0
- package/dist/image-editor/ImageProviderEffectsPanel.svelte +10 -5
- package/dist/image-editor/ImageProviderEffectsPanel.svelte.d.ts +3 -0
- package/dist/image-editor/LayerEffectsPanel.svelte +2 -1
- package/dist/image-editor/ShapeOptionsBar.svelte +4 -17
- package/dist/image-editor/TypeOptionsBar.svelte +3 -2
- package/dist/image-editor/controls/ImageColor.svelte +21 -0
- package/dist/image-editor/controls/ImageColor.svelte.d.ts +4 -0
- package/dist/image-editor/controls/ImageParameterColor.svelte +9 -0
- package/dist/image-editor/controls/ImageParameterColor.svelte.d.ts +4 -0
- package/dist/image-editor/controls/ImageParameterSelect.svelte +11 -0
- package/dist/image-editor/controls/ImageParameterSelect.svelte.d.ts +4 -0
- package/dist/image-editor/controls/ImageParameterSlider.svelte +9 -0
- package/dist/image-editor/controls/ImageParameterSlider.svelte.d.ts +4 -0
- package/dist/image-editor/controls/controls.d.ts +17 -0
- package/dist/image-editor/controls/parameterControls.d.ts +4 -0
- package/dist/image-editor/controls/parameterControls.js +11 -0
- package/dist/image-editor/index.d.ts +2 -1
- package/dist/image-editor/index.js +1 -0
- package/dist/parameters/ParameterColor.svelte +59 -51
- package/dist/parameters/ParameterColor.svelte.d.ts +2 -0
- package/dist/parameters/ParameterCommitInput.svelte +33 -4
- package/dist/parameters/ParameterFieldControl.svelte +7 -5
- package/dist/parameters/ParameterFieldControl.svelte.d.ts +2 -0
- package/dist/parameters/ParameterNumberInput.svelte +41 -17
- package/dist/parameters/ParameterNumberInput.svelte.d.ts +2 -0
- package/dist/parameters/ParameterSelect.svelte +25 -6
- package/dist/parameters/ParameterSelect.svelte.d.ts +2 -0
- package/dist/parameters/ParameterSlider.svelte +48 -20
- package/dist/parameters/ParameterSlider.svelte.d.ts +2 -0
- package/dist/parameters/ParameterVector.svelte +6 -3
- package/dist/parameters/ParameterVector.svelte.d.ts +2 -0
- package/dist/parameters/ParametersPanel.svelte +54 -18
- package/dist/parameters/ParametersPanel.svelte.d.ts +3 -0
- package/dist/parameters/controls.d.ts +89 -0
- package/dist/parameters/controls.js +19 -0
- package/dist/parameters/index.d.ts +1 -0
- package/dist/parameters/index.js +1 -0
- package/dist/parameters/styles.d.ts +6 -0
- package/dist/parameters/styles.js +7 -0
- package/package.json +2 -2
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { effectFieldValue, effectParameterFields, type EffectDescription, type EffectFieldOptions } from '@pixerate/editor/effects';
|
|
3
3
|
import { parameterLabel, parameterValuesEqual, type ParameterValue } from '@pixerate/editor/parameters';
|
|
4
4
|
import ParameterFieldControl from '../parameters/ParameterFieldControl.svelte';
|
|
5
|
+
import { parameterSelectStyle } from '../parameters/styles.js';
|
|
6
|
+
import { getParameterComponents, resolveParameterComponents, type ParameterComponents } from '../parameters/controls.js';
|
|
5
7
|
|
|
6
8
|
interface Props {
|
|
7
9
|
/** The effect's description (`describe`). */
|
|
@@ -25,12 +27,29 @@
|
|
|
25
27
|
addon?: import('svelte').Snippet<[string]>;
|
|
26
28
|
/** Families offered by font controls (`format: "font"`); default the system font catalog. */
|
|
27
29
|
fonts?: EffectFieldOptions['fonts'];
|
|
30
|
+
/** Custom host components for inputs, sliders, and selects. */
|
|
31
|
+
components?: ParameterComponents;
|
|
28
32
|
disabled?: boolean;
|
|
29
33
|
class?: string;
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
let {
|
|
36
|
+
let {
|
|
37
|
+
description,
|
|
38
|
+
values,
|
|
39
|
+
onchange,
|
|
40
|
+
onreset,
|
|
41
|
+
keyframed,
|
|
42
|
+
onpreset,
|
|
43
|
+
onpresetname,
|
|
44
|
+
addon,
|
|
45
|
+
fonts,
|
|
46
|
+
components,
|
|
47
|
+
disabled = false,
|
|
48
|
+
class: className = ''
|
|
49
|
+
}: Props = $props();
|
|
33
50
|
const fields = $derived(effectParameterFields(description, { fonts }));
|
|
51
|
+
const parameterContext = getParameterComponents();
|
|
52
|
+
const CustomPresetSelect = $derived(resolveParameterComponents(components, parameterContext).select);
|
|
34
53
|
const idBase = `fx-${Math.random().toString(36).slice(2, 8)}`;
|
|
35
54
|
let gesture: string | null = null;
|
|
36
55
|
let count = 0;
|
|
@@ -52,10 +71,33 @@
|
|
|
52
71
|
-->
|
|
53
72
|
<div class="space-y-2 {className}" data-effect-parameters={description.id}>
|
|
54
73
|
{#if (onpreset || onpresetname) && description.presets.length > 0}
|
|
55
|
-
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
74
|
+
{#if CustomPresetSelect}
|
|
75
|
+
<CustomPresetSelect
|
|
76
|
+
aria-label="{description.name} presets"
|
|
77
|
+
label="{description.name} presets"
|
|
78
|
+
value=""
|
|
79
|
+
options={[
|
|
80
|
+
{ value: '', label: 'Presets…' },
|
|
81
|
+
...description.presets.map((p) => ({ value: p.name, label: p.name }))
|
|
82
|
+
]}
|
|
83
|
+
class="w-full rounded border border-border px-1 py-0.5 text-xs"
|
|
84
|
+
style={parameterSelectStyle}
|
|
85
|
+
{disabled}
|
|
86
|
+
onchange={(val) => preset(String(val))}
|
|
87
|
+
/>
|
|
88
|
+
{:else}
|
|
89
|
+
<select
|
|
90
|
+
class="w-full rounded border border-border bg-transparent px-1 py-0.5 text-xs"
|
|
91
|
+
style={parameterSelectStyle}
|
|
92
|
+
aria-label="{description.name} presets"
|
|
93
|
+
value=""
|
|
94
|
+
{disabled}
|
|
95
|
+
onchange={(e) => preset(e.currentTarget.value)}
|
|
96
|
+
>
|
|
97
|
+
<option value="" style={parameterSelectStyle}>Presets…</option>
|
|
98
|
+
{#each description.presets as p (p.name)}<option value={p.name} style={parameterSelectStyle}>{p.name}</option>{/each}
|
|
99
|
+
</select>
|
|
100
|
+
{/if}
|
|
59
101
|
{/if}
|
|
60
102
|
{#each fields as field (field.id)}
|
|
61
103
|
{@const label = parameterLabel(field)}
|
|
@@ -75,6 +117,7 @@
|
|
|
75
117
|
{value}
|
|
76
118
|
id="{idBase}-{field.id}"
|
|
77
119
|
disabled={disabled || keyed}
|
|
120
|
+
{components}
|
|
78
121
|
onchange={(v) => onchange(field.id, v, gesture)}
|
|
79
122
|
ongesturestart={() => (gesture = `${idBase}:${field.id}:${++count}`)}
|
|
80
123
|
ongestureend={() => (gesture = null)}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type EffectDescription, type EffectFieldOptions } from '@pixerate/editor/effects';
|
|
2
2
|
import { type ParameterValue } from '@pixerate/editor/parameters';
|
|
3
|
+
import { type ParameterComponents } from '../parameters/controls.js';
|
|
3
4
|
interface Props {
|
|
4
5
|
/** The effect's description (`describe`). */
|
|
5
6
|
description: EffectDescription;
|
|
@@ -22,6 +23,8 @@ interface Props {
|
|
|
22
23
|
addon?: import('svelte').Snippet<[string]>;
|
|
23
24
|
/** Families offered by font controls (`format: "font"`); default the system font catalog. */
|
|
24
25
|
fonts?: EffectFieldOptions['fonts'];
|
|
26
|
+
/** Custom host components for inputs, sliders, and selects. */
|
|
27
|
+
components?: ParameterComponents;
|
|
25
28
|
disabled?: boolean;
|
|
26
29
|
class?: string;
|
|
27
30
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import ImageColor from './controls/ImageColor.svelte';
|
|
2
3
|
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
3
4
|
import ImageSelect from './controls/ImageSelect.svelte';
|
|
4
5
|
import { imageSectionTitleClass } from './styles.js';
|
|
@@ -242,13 +243,7 @@
|
|
|
242
243
|
{:else if layer.kind === 'photoFilter'}
|
|
243
244
|
<label class="flex items-center gap-2 text-foreground">
|
|
244
245
|
Filter colour
|
|
245
|
-
<
|
|
246
|
-
type="color"
|
|
247
|
-
aria-label="Filter colour"
|
|
248
|
-
value={layer.params.color}
|
|
249
|
-
oninput={(e) => setParam(layer, 'color', (e.target as HTMLInputElement).value)}
|
|
250
|
-
class="h-5 w-8 bg-transparent"
|
|
251
|
-
/>
|
|
246
|
+
<ImageColor label="Filter colour" value={layer.params.color} oninput={(v) => setParam(layer, 'color', v)} />
|
|
252
247
|
</label>
|
|
253
248
|
{:else if layer.kind === 'invert'}
|
|
254
249
|
<p class="text-muted-foreground text-[11px]">Invert has no settings.</p>
|
|
@@ -275,13 +270,7 @@
|
|
|
275
270
|
<ImageCheckbox label="Tint" checked={layer.params.tint !== null} onchange={(on) => setParam(layer, 'tint', on ? '#e1d3b3' : null)} />
|
|
276
271
|
Tint
|
|
277
272
|
{#if layer.params.tint}
|
|
278
|
-
<
|
|
279
|
-
type="color"
|
|
280
|
-
aria-label="Tint colour"
|
|
281
|
-
value={layer.params.tint}
|
|
282
|
-
oninput={(e) => setParam(layer, 'tint', (e.target as HTMLInputElement).value)}
|
|
283
|
-
class="h-5 w-8 bg-transparent"
|
|
284
|
-
/>
|
|
273
|
+
<ImageColor label="Tint colour" value={layer.params.tint} oninput={(v) => setParam(layer, 'tint', v)} />
|
|
285
274
|
{/if}
|
|
286
275
|
</label>
|
|
287
276
|
{/if}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import ImageColor from './controls/ImageColor.svelte';
|
|
2
3
|
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
3
|
-
import { imageChipClass
|
|
4
|
+
import { imageChipClass } from './styles.js';
|
|
4
5
|
import type { ImageEditorController } from '@pixerate/editor/image-editor';
|
|
5
6
|
import {
|
|
6
7
|
userErrorMessage,
|
|
@@ -70,23 +71,11 @@
|
|
|
70
71
|
|
|
71
72
|
<div class="flex items-center gap-2" role="group" aria-label="Colours">
|
|
72
73
|
<label class="flex items-center gap-1">
|
|
73
|
-
<
|
|
74
|
-
type="color"
|
|
75
|
-
aria-label="Foreground colour"
|
|
76
|
-
value={view.foreground}
|
|
77
|
-
oninput={(e) => controller.setPaintOptions({ foreground: (e.target as HTMLInputElement).value })}
|
|
78
|
-
class={imageColorInputClass}
|
|
79
|
-
/>
|
|
74
|
+
<ImageColor label="Foreground colour" value={view.foreground} oninput={(foreground) => controller.setPaintOptions({ foreground })} />
|
|
80
75
|
<span class="text-muted-foreground">FG</span>
|
|
81
76
|
</label>
|
|
82
77
|
<label class="flex items-center gap-1">
|
|
83
|
-
<
|
|
84
|
-
type="color"
|
|
85
|
-
aria-label="Background colour"
|
|
86
|
-
value={view.background}
|
|
87
|
-
oninput={(e) => controller.setPaintOptions({ background: (e.target as HTMLInputElement).value })}
|
|
88
|
-
class={imageColorInputClass}
|
|
89
|
-
/>
|
|
78
|
+
<ImageColor label="Background colour" value={view.background} oninput={(background) => controller.setPaintOptions({ background })} />
|
|
90
79
|
<span class="text-muted-foreground">BG</span>
|
|
91
80
|
</label>
|
|
92
81
|
<button type="button" title="Swap colours (X)" class={imageChipClass(false)} onclick={() => controller.swapPaintColors()}>Swap</button>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import ImageColor from './controls/ImageColor.svelte';
|
|
2
3
|
import { imageDividerClass, imageEditorFrameClass, imageEditorHeaderClass, imageErrorBannerClass, imageHeaderButtonClass, imagePrimaryButtonClass, imageRangeClass, imageSectionClass, imageSectionTitleClass, imageSelectClass, imageSidebarClass, imageSmallButtonClass, imageSpinnerClass, imageTabClass, imageTabListClass } from './styles.js';
|
|
3
4
|
import type {
|
|
4
5
|
ExportOptions,
|
|
@@ -747,11 +748,7 @@
|
|
|
747
748
|
<!-- Color & Size -->
|
|
748
749
|
<div class="flex items-center gap-2 mt-2">
|
|
749
750
|
<span class="text-muted-foreground">Color:</span>
|
|
750
|
-
<
|
|
751
|
-
type="color"
|
|
752
|
-
bind:value={activeColor}
|
|
753
|
-
class="w-8 h-8 rounded border border-border cursor-pointer bg-transparent"
|
|
754
|
-
/>
|
|
751
|
+
<ImageColor label="Annotation colour" value={activeColor} oninput={(c) => (activeColor = c)} />
|
|
755
752
|
<div class="flex-1 ml-2">
|
|
756
753
|
<div class="flex justify-between text-muted-foreground mb-0.5">
|
|
757
754
|
<span>Width:</span>
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import type { EffectProvider } from '@pixerate/editor/effects';
|
|
3
3
|
import EffectParameters from '../effects/EffectParameters.svelte';
|
|
4
4
|
import { effectDescriptionOf } from '../effects/effects.svelte.js';
|
|
5
|
+
import { getImageEditorControls } from './controls/controls.js';
|
|
6
|
+
import { imageEditorParameterComponents } from './controls/parameterControls.js';
|
|
7
|
+
import { getParameterComponents, resolveParameterComponents, type ParameterComponents } from '../parameters/controls.js';
|
|
5
8
|
|
|
6
9
|
interface Props {
|
|
7
10
|
provider: EffectProvider | null;
|
|
@@ -10,12 +13,16 @@
|
|
|
10
13
|
values: Readonly<Record<string, unknown>>;
|
|
11
14
|
onchange: (control: string, value: unknown, gesture: string | null) => void;
|
|
12
15
|
onpreset: (values: Readonly<Record<string, unknown>>) => void;
|
|
16
|
+
/** Host parameter controls; else those of `setParameterComponents`, else the image editor's host `Range` / `Select`. */
|
|
17
|
+
components?: ParameterComponents;
|
|
13
18
|
/** Extra classes on the root element. */
|
|
14
19
|
class?: string;
|
|
15
20
|
}
|
|
16
21
|
|
|
17
|
-
let { provider, effect, name, values, onchange, onpreset, class: className = '' }: Props = $props();
|
|
22
|
+
let { provider, effect, name, values, onchange, onpreset, components, class: className = '' }: Props = $props();
|
|
18
23
|
const loaded = effectDescriptionOf(() => provider, () => effect);
|
|
24
|
+
const fallback = resolveParameterComponents(getParameterComponents(), imageEditorParameterComponents(getImageEditorControls()));
|
|
25
|
+
const effectiveComponents = $derived(resolveParameterComponents(components, fallback));
|
|
19
26
|
</script>
|
|
20
27
|
|
|
21
28
|
<!-- One effect's controls, loaded from the provider; a note when it does not have the effect. -->
|
|
@@ -28,6 +35,6 @@
|
|
|
28
35
|
<p class="text-[11px] text-muted-foreground">Loading…</p>
|
|
29
36
|
{:else}
|
|
30
37
|
{@const description = loaded.description}
|
|
31
|
-
<EffectParameters {description} {values} {onchange} onreset={(k) => onchange(k, description.defaults[k], null)} {onpreset} />
|
|
38
|
+
<EffectParameters {description} {values} {onchange} onreset={(k) => onchange(k, description.defaults[k], null)} {onpreset} components={effectiveComponents} />
|
|
32
39
|
{/if}
|
|
33
40
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EffectProvider } from '@pixerate/editor/effects';
|
|
2
|
+
import { type ParameterComponents } from '../parameters/controls.js';
|
|
2
3
|
interface Props {
|
|
3
4
|
provider: EffectProvider | null;
|
|
4
5
|
effect: string;
|
|
@@ -6,6 +7,8 @@ interface Props {
|
|
|
6
7
|
values: Readonly<Record<string, unknown>>;
|
|
7
8
|
onchange: (control: string, value: unknown, gesture: string | null) => void;
|
|
8
9
|
onpreset: (values: Readonly<Record<string, unknown>>) => void;
|
|
10
|
+
/** Host parameter controls; else those of `setParameterComponents`, else the image editor's host `Range` / `Select`. */
|
|
11
|
+
components?: ParameterComponents;
|
|
9
12
|
/** Extra classes on the root element. */
|
|
10
13
|
class?: string;
|
|
11
14
|
}
|
|
@@ -4,13 +4,18 @@
|
|
|
4
4
|
import { untrack } from 'svelte';
|
|
5
5
|
import EffectsBrowser from '../effects/EffectsBrowser.svelte';
|
|
6
6
|
import ImageEffectControls from './ImageEffectControls.svelte';
|
|
7
|
+
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
8
|
+
import ImageRange from './controls/ImageRange.svelte';
|
|
9
|
+
import type { ParameterComponents } from '../parameters/index.js';
|
|
7
10
|
|
|
8
11
|
interface Props {
|
|
9
12
|
controller: ImageEditorController;
|
|
13
|
+
/** Host controls for the effects' parameters. */
|
|
14
|
+
components?: ParameterComponents;
|
|
10
15
|
class?: string;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
let { controller, class: className = '' }: Props = $props();
|
|
18
|
+
let { controller, components, class: className = '' }: Props = $props();
|
|
14
19
|
let tick = $state(0);
|
|
15
20
|
$effect(() => {
|
|
16
21
|
const c = controller;
|
|
@@ -78,6 +83,7 @@
|
|
|
78
83
|
effect={generator.effect}
|
|
79
84
|
name={generator.name}
|
|
80
85
|
values={generator.values}
|
|
86
|
+
{components}
|
|
81
87
|
onchange={(k, v, g) => run(() => controller.updateEffectLayer(id, { values: { [k]: v as never } }, commit(g)))}
|
|
82
88
|
onpreset={(values) => run(() => controller.updateEffectLayer(id, { values: values as never }))}
|
|
83
89
|
/>
|
|
@@ -91,8 +97,7 @@
|
|
|
91
97
|
{@const label = f.name ?? f.effect}
|
|
92
98
|
<li class="rounded border border-border p-1" data-smart-effect={f.id}>
|
|
93
99
|
<div class="flex items-center gap-1">
|
|
94
|
-
<
|
|
95
|
-
const enabled = e.currentTarget.checked;
|
|
100
|
+
<ImageCheckbox checked={f.enabled} label="{label} on" onchange={(enabled) => {
|
|
96
101
|
run(() => controller.updateEffectFilter(id, f.id, { enabled }));
|
|
97
102
|
}} />
|
|
98
103
|
<button type="button" class="min-w-0 flex-1 truncate text-left text-foreground" aria-expanded={open === f.id} onclick={() => (open = open === f.id ? null : f.id)}>{label}</button>
|
|
@@ -104,8 +109,7 @@
|
|
|
104
109
|
<div class="mt-1 space-y-2">
|
|
105
110
|
<label class="flex items-center gap-1">
|
|
106
111
|
<span class="w-14 text-[11px] text-foreground">Opacity</span>
|
|
107
|
-
<
|
|
108
|
-
const opacity = Number(e.currentTarget.value);
|
|
112
|
+
<ImageRange min={0} max={1} step={0.01} class="flex-1" value={f.opacity} label="{label} opacity" oninput={(opacity) => {
|
|
109
113
|
run(() => controller.updateEffectFilter(id, f.id, { opacity }));
|
|
110
114
|
}} />
|
|
111
115
|
</label>
|
|
@@ -114,6 +118,7 @@
|
|
|
114
118
|
effect={f.effect}
|
|
115
119
|
name={f.name}
|
|
116
120
|
values={f.values}
|
|
121
|
+
{components}
|
|
117
122
|
onchange={(k, v, g) => run(() => controller.updateEffectFilter(id, f.id, { values: { [k]: v as never } }, commit(g)))}
|
|
118
123
|
onpreset={(values) => run(() => controller.updateEffectFilter(id, f.id, { values: values as never }))}
|
|
119
124
|
/>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type ImageEditorController } from '@pixerate/editor/image-editor';
|
|
2
|
+
import type { ParameterComponents } from '../parameters/index.js';
|
|
2
3
|
interface Props {
|
|
3
4
|
controller: ImageEditorController;
|
|
5
|
+
/** Host controls for the effects' parameters. */
|
|
6
|
+
components?: ParameterComponents;
|
|
4
7
|
class?: string;
|
|
5
8
|
}
|
|
6
9
|
declare const ImageProviderEffectsPanel: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import ImageColor from './controls/ImageColor.svelte';
|
|
2
3
|
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
3
4
|
import ImageRange from './controls/ImageRange.svelte';
|
|
4
5
|
import ImageSelect from './controls/ImageSelect.svelte';
|
|
@@ -155,7 +156,7 @@
|
|
|
155
156
|
</label>
|
|
156
157
|
{:else if c.type === 'color'}
|
|
157
158
|
<label class="flex items-center gap-1.5 text-foreground">
|
|
158
|
-
<
|
|
159
|
+
<ImageColor label={c.label} value={c.value} disabled={view.model.readOnly} oninput={(v) => change(row.id, c, v)} />
|
|
159
160
|
{c.label}
|
|
160
161
|
</label>
|
|
161
162
|
{:else if c.type === 'checkbox'}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import ImageColor from './controls/ImageColor.svelte';
|
|
2
3
|
import ImageCheckbox from './controls/ImageCheckbox.svelte';
|
|
3
4
|
import ImageRange from './controls/ImageRange.svelte';
|
|
4
|
-
import { imageChipClass,
|
|
5
|
+
import { imageChipClass, imageFieldClass } from './styles.js';
|
|
5
6
|
import type { ImageEditorController, ShapeToolOptions } from '@pixerate/editor/image-editor';
|
|
6
7
|
import { LIVE_SHAPE_KINDS, SHAPE_KIND_LABELS, applyShapeOptions } from '@pixerate/editor/image-editor';
|
|
7
8
|
import { untrack } from 'svelte';
|
|
@@ -58,26 +59,12 @@
|
|
|
58
59
|
<label class="flex items-center gap-1">
|
|
59
60
|
<ImageCheckbox label="Fill" checked={options.fill !== null} onchange={(on) => set({ fill: on ? '#4f46e5' : null })} />
|
|
60
61
|
Fill
|
|
61
|
-
<
|
|
62
|
-
type="color"
|
|
63
|
-
aria-label="Fill colour"
|
|
64
|
-
disabled={options.fill === null}
|
|
65
|
-
value={options.fill ?? '#4f46e5'}
|
|
66
|
-
oninput={(e) => set({ fill: value(e) })}
|
|
67
|
-
class={imageColorInputClass}
|
|
68
|
-
/>
|
|
62
|
+
<ImageColor label="Fill colour" disabled={options.fill === null} value={options.fill ?? '#4f46e5'} oninput={(fill) => set({ fill })} />
|
|
69
63
|
</label>
|
|
70
64
|
<label class="flex items-center gap-1">
|
|
71
65
|
<ImageCheckbox label="Stroke" checked={options.stroke !== null} onchange={(on) => set({ stroke: on ? '#000000' : null })} />
|
|
72
66
|
Stroke
|
|
73
|
-
<
|
|
74
|
-
type="color"
|
|
75
|
-
aria-label="Stroke colour"
|
|
76
|
-
disabled={options.stroke === null}
|
|
77
|
-
value={options.stroke ?? '#000000'}
|
|
78
|
-
oninput={(e) => set({ stroke: value(e) })}
|
|
79
|
-
class={imageColorInputClass}
|
|
80
|
-
/>
|
|
67
|
+
<ImageColor label="Stroke colour" disabled={options.stroke === null} value={options.stroke ?? '#000000'} oninput={(stroke) => set({ stroke })} />
|
|
81
68
|
</label>
|
|
82
69
|
<label class="flex items-center gap-1">
|
|
83
70
|
Width
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import ImageColor from './controls/ImageColor.svelte';
|
|
3
|
+
import { imageChipClass } from './styles.js';
|
|
3
4
|
import type { ImageEditorController, TextAlign, TextEditSession, TextStyle, TypeToolOptions } from '@pixerate/editor/image-editor';
|
|
4
5
|
import { TEXT_ALIGNS } from '@pixerate/editor/image-editor';
|
|
5
6
|
import { untrack } from 'svelte';
|
|
@@ -100,7 +101,7 @@
|
|
|
100
101
|
</label>
|
|
101
102
|
<button type="button" aria-pressed={view.shown.fontWeight >= 600} class="{imageChipClass(view.shown.fontWeight >= 600)} font-bold" onclick={() => style({ fontWeight: view.shown.fontWeight >= 600 ? 400 : 700 })}>B</button>
|
|
102
103
|
<button type="button" aria-pressed={view.shown.italic} class="{imageChipClass(view.shown.italic)} italic" onclick={() => style({ italic: !view.shown.italic })}>I</button>
|
|
103
|
-
<
|
|
104
|
+
<ImageColor label="Text colour" value={view.shown.color} oninput={(color) => style({ color })} />
|
|
104
105
|
</div>
|
|
105
106
|
<div class="flex gap-1" role="toolbar" aria-label="Alignment">
|
|
106
107
|
{#each TEXT_ALIGNS as a (a)}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getImageEditorControls, type ImageColorProps } from './controls.js';
|
|
3
|
+
import { imageColorInputClass } from '../styles.js';
|
|
4
|
+
|
|
5
|
+
let { value, label, alpha = false, disabled = false, oninput, onstart, onend, class: className = '' }: ImageColorProps = $props();
|
|
6
|
+
const Host = getImageEditorControls().Color;
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
{#if Host}
|
|
10
|
+
<Host {value} {label} {alpha} {disabled} {oninput} {onstart} {onend} class={className} />
|
|
11
|
+
{:else}
|
|
12
|
+
<!-- The native well has no alpha: keep the stored alpha on what it picks. -->
|
|
13
|
+
<input
|
|
14
|
+
type="color"
|
|
15
|
+
aria-label={label}
|
|
16
|
+
value={value.slice(0, 7)}
|
|
17
|
+
{disabled}
|
|
18
|
+
oninput={(e) => oninput((e.currentTarget as HTMLInputElement).value + (alpha ? value.slice(7, 9) : ''))}
|
|
19
|
+
class="{imageColorInputClass} {className}"
|
|
20
|
+
/>
|
|
21
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ParameterColorProps } from '../../parameters/controls.js';
|
|
3
|
+
import ImageColor from './ImageColor.svelte';
|
|
4
|
+
|
|
5
|
+
let { value, label, alpha = false, disabled = false, class: className = '', onchange, ongesturestart, ongestureend }: ParameterColorProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<!-- A parameter colour drawn with the host's image-editor `Color`. -->
|
|
9
|
+
<ImageColor {value} {label} {alpha} {disabled} class={className} oninput={onchange} onstart={ongesturestart} onend={ongestureend} />
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { matchParameterOptionValue } from '@pixerate/editor/parameters';
|
|
3
|
+
import type { ParameterSelectProps } from '../../parameters/controls.js';
|
|
4
|
+
import ImageSelect from './ImageSelect.svelte';
|
|
5
|
+
|
|
6
|
+
let { value, options, label, disabled = false, class: className = '', onchange }: ParameterSelectProps = $props();
|
|
7
|
+
const imageOptions = $derived(options.map((o) => ({ value: String(o.value), label: o.label })));
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<!-- A parameter select drawn with the host's image-editor `Select` (string values mapped back to the options' own). -->
|
|
11
|
+
<ImageSelect value={String(value)} options={imageOptions} {label} {disabled} class={className} onchange={(v) => onchange(matchParameterOptionValue(options, v))} />
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ParameterSelectProps } from '../../parameters/controls.js';
|
|
2
|
+
declare const ImageParameterSelect: import("svelte").Component<ParameterSelectProps, {}, "">;
|
|
3
|
+
type ImageParameterSelect = ReturnType<typeof ImageParameterSelect>;
|
|
4
|
+
export default ImageParameterSelect;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { ParameterSliderProps } from '../../parameters/controls.js';
|
|
3
|
+
import ImageRange from './ImageRange.svelte';
|
|
4
|
+
|
|
5
|
+
let { value, min, max, step, label, disabled = false, class: className = '', oninput, ongesturestart, ongestureend }: ParameterSliderProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<!-- A parameter slider drawn with the host's image-editor `Range`. -->
|
|
9
|
+
<ImageRange {value} {min} {max} {step} {label} {disabled} class={className} {oninput} onstart={ongesturestart} onend={ongestureend} />
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ParameterSliderProps } from '../../parameters/controls.js';
|
|
2
|
+
declare const ImageParameterSlider: import("svelte").Component<ParameterSliderProps, {}, "">;
|
|
3
|
+
type ImageParameterSlider = ReturnType<typeof ImageParameterSlider>;
|
|
4
|
+
export default ImageParameterSlider;
|
|
@@ -42,6 +42,22 @@ export interface ImageSelectProps {
|
|
|
42
42
|
onchange: (value: string) => void;
|
|
43
43
|
class?: string;
|
|
44
44
|
}
|
|
45
|
+
/** A colour well in the image editor's panels. */
|
|
46
|
+
export interface ImageColorProps {
|
|
47
|
+
/** `#rrggbb`, or `#rrggbbaa` with `alpha`. */
|
|
48
|
+
value: string;
|
|
49
|
+
/** The accessible name. */
|
|
50
|
+
label: string;
|
|
51
|
+
/** Whether the colour has an alpha channel. */
|
|
52
|
+
alpha?: boolean;
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
/** Every change while the colour is picked. */
|
|
55
|
+
oninput: (value: string) => void;
|
|
56
|
+
/** A pick (e.g. a drag in the picker) starts: changes until `onend` merge into one undo step. */
|
|
57
|
+
onstart?: () => void;
|
|
58
|
+
onend?: () => void;
|
|
59
|
+
class?: string;
|
|
60
|
+
}
|
|
45
61
|
/**
|
|
46
62
|
* The host's own form controls for the image editor's panels. Any left out fall back to the
|
|
47
63
|
* editor's plain inputs.
|
|
@@ -50,6 +66,7 @@ export interface ImageEditorControls {
|
|
|
50
66
|
Checkbox?: Component<ImageCheckboxProps>;
|
|
51
67
|
Range?: Component<ImageRangeProps>;
|
|
52
68
|
Select?: Component<ImageSelectProps>;
|
|
69
|
+
Color?: Component<ImageColorProps>;
|
|
53
70
|
}
|
|
54
71
|
/**
|
|
55
72
|
* Makes the image editor's panels below this component use the host's controls (call it while
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ParameterComponents } from '../../parameters/controls.js';
|
|
2
|
+
import type { ImageEditorControls } from './controls.js';
|
|
3
|
+
/** The host's image-editor `Range`, `Select` and `Color` as parameter controls (only the ones it set). */
|
|
4
|
+
export declare function imageEditorParameterComponents(controls: ImageEditorControls): ParameterComponents;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ImageParameterColor from './ImageParameterColor.svelte';
|
|
2
|
+
import ImageParameterSelect from './ImageParameterSelect.svelte';
|
|
3
|
+
import ImageParameterSlider from './ImageParameterSlider.svelte';
|
|
4
|
+
/** The host's image-editor `Range`, `Select` and `Color` as parameter controls (only the ones it set). */
|
|
5
|
+
export function imageEditorParameterComponents(controls) {
|
|
6
|
+
return {
|
|
7
|
+
slider: controls.Range ? ImageParameterSlider : undefined,
|
|
8
|
+
select: controls.Select ? ImageParameterSelect : undefined,
|
|
9
|
+
color: controls.Color ? ImageParameterColor : undefined,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -43,7 +43,8 @@ export * from './imageEditorState.svelte.js';
|
|
|
43
43
|
export { default as ImageCheckbox } from './controls/ImageCheckbox.svelte';
|
|
44
44
|
export { default as ImageRange } from './controls/ImageRange.svelte';
|
|
45
45
|
export { default as ImageSelect } from './controls/ImageSelect.svelte';
|
|
46
|
-
export {
|
|
46
|
+
export { default as ImageColor } from './controls/ImageColor.svelte';
|
|
47
|
+
export { setImageEditorControls, getImageEditorControls, type ImageEditorControls, type ImageCheckboxProps, type ImageRangeProps, type ImageSelectProps, type ImageSelectOption, type ImageColorProps, } from './controls/controls.js';
|
|
47
48
|
export type ImageEditorProps = ComponentProps<typeof ImageEditorComponent>;
|
|
48
49
|
export type ImageEditorCanvasProps = ComponentProps<typeof ImageEditorCanvasComponent>;
|
|
49
50
|
export type CanvasSizePanelProps = ComponentProps<typeof CanvasSizePanelComponent>;
|
|
@@ -22,5 +22,6 @@ export * from './imageEditorState.svelte.js';
|
|
|
22
22
|
export { default as ImageCheckbox } from './controls/ImageCheckbox.svelte';
|
|
23
23
|
export { default as ImageRange } from './controls/ImageRange.svelte';
|
|
24
24
|
export { default as ImageSelect } from './controls/ImageSelect.svelte';
|
|
25
|
+
export { default as ImageColor } from './controls/ImageColor.svelte';
|
|
25
26
|
export { setImageEditorControls, getImageEditorControls, } from './controls/controls.js';
|
|
26
27
|
export { applyRegionMosaic, applyRegionBlur, resolveMosaicRegionBounds } from '@pixerate/editor/image-editor';
|