@pixerate/editor-svelte 0.89.0 → 0.90.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.
@@ -8,7 +8,8 @@
8
8
  import PaperPanel from './PaperPanel.svelte';
9
9
  import WetPanel from './WetPanel.svelte';
10
10
  import StickerPanel from './StickerPanel.svelte';
11
- import { chip } from './paintEditorRune.svelte.js';
11
+ import PaintEffectsPanel from './PaintEffectsPanel.svelte';
12
+ import { chip, paintEffectsProvider } from './paintEditorRune.svelte.js';
12
13
 
13
14
  interface Props {
14
15
  controller: PaintEditorController;
@@ -22,7 +23,9 @@
22
23
  }
23
24
  let { controller, fileName, height = 720, presence, class: className = '' }: Props = $props();
24
25
  let tool = $state<PaintTool>('brush');
25
- let tab = $state<'color' | 'wet' | 'paper' | 'layers'>('color');
26
+ let tab = $state<'color' | 'wet' | 'paper' | 'layers' | 'effects'>('color');
27
+ const effects = paintEffectsProvider(() => controller);
28
+ const tabs = $derived(effects.current ? (['color', 'wet', 'paper', 'layers', 'effects'] as const) : (['color', 'wet', 'paper', 'layers'] as const));
26
29
  let error = $state<string | null>(null);
27
30
  </script>
28
31
 
@@ -37,14 +40,15 @@
37
40
  </div>
38
41
  <div class="flex w-64 shrink-0 flex-col gap-2 overflow-y-auto pr-1">
39
42
  <div class="flex gap-1" role="tablist" aria-label="Paint panels">
40
- {#each ['color', 'wet', 'paper', 'layers'] as const as t (t)}
41
- <button type="button" role="tab" aria-selected={tab === t} class={chip(tab === t)} onclick={() => (tab = t)}>{t === 'color' ? 'Colour' : t === 'wet' ? 'Wet' : t === 'paper' ? 'Paper' : 'Layers'}</button>
43
+ {#each tabs as t (t)}
44
+ <button type="button" role="tab" aria-selected={tab === t} class={chip(tab === t)} onclick={() => (tab = t)}>{t === 'color' ? 'Colour' : t === 'wet' ? 'Wet' : t === 'paper' ? 'Paper' : t === 'layers' ? 'Layers' : 'Effects'}</button>
42
45
  {/each}
43
46
  </div>
44
47
  {#if tab === 'color'}<ColorPanel {controller} />{/if}
45
48
  {#if tab === 'wet'}<WetPanel {controller} />{/if}
46
49
  {#if tab === 'paper'}<PaperPanel {controller} />{/if}
47
50
  {#if tab === 'layers'}<PaintLayersPanel {controller} /><StickerPanel {controller} />{/if}
51
+ {#if tab === 'effects' && effects.current}<PaintEffectsPanel {controller} />{/if}
48
52
  </div>
49
53
  </div>
50
54
  </div>
@@ -1 +1 @@
1
- {"version":3,"file":"PaintEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/PaintEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAa,MAAM,+BAA+B,CAAC;AAYnG,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"PaintEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/PaintEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAa,MAAM,+BAA+B,CAAC;AAanG,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAgDH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,127 @@
1
+ <script lang="ts">
2
+ import { PAPER_EFFECT_BLENDS, type PaintEditorController, type PaperEffectBlend } from '@pixerate/editor/paint-editor';
3
+ import type { EffectUse } from '@pixerate/editor/effects';
4
+ import EffectsBrowser from '../effects/EffectsBrowser.svelte';
5
+ import ImageEffectControls from '../image-editor/ImageEffectControls.svelte';
6
+ import { attempt, button, paintEditorState, paintEffectsProvider, panel } from './paintEditorRune.svelte.js';
7
+
8
+ interface Props {
9
+ controller: PaintEditorController;
10
+ class?: string;
11
+ }
12
+ let { controller, class: className = '' }: Props = $props();
13
+ const editor = paintEditorState(() => controller);
14
+ const effects = paintEffectsProvider(() => controller);
15
+ const provider = $derived(effects.current);
16
+ const view = $derived.by(() => {
17
+ const doc = editor.current.document;
18
+ const activeId = doc.activeLayerId;
19
+ return {
20
+ activeId,
21
+ paper: controller.getPaperEffect(),
22
+ layerEffect: activeId ? controller.getEffectLayer(activeId) : undefined,
23
+ pixel: activeId ? controller.getLayer(activeId)?.type === 'pixel' : false,
24
+ };
25
+ });
26
+ type Browse = null | 'paper' | 'layer' | 'fill' | 'light';
27
+ const BROWSERS: Record<Exclude<Browse, null>, { uses: EffectUse[]; title: string }> = {
28
+ paper: { uses: ['generator'], title: 'Effect paper' },
29
+ layer: { uses: ['generator', 'overlay', 'title'], title: 'Effect layer' },
30
+ fill: { uses: ['generator', 'overlay', 'title'], title: 'Fill the layer' },
31
+ light: { uses: ['filter'], title: 'Light on the paint' },
32
+ };
33
+ let browse = $state<Browse>(null);
34
+ let error = $state<string | null>(null);
35
+ let busy = $state(false);
36
+ const run = (work: () => unknown) =>
37
+ attempt(() => {
38
+ busy = true;
39
+ return Promise.resolve().then(work).finally(() => (busy = false));
40
+ }, (m) => (error = m));
41
+ const drags = new Set<string>();
42
+ /** The first change of a drag records the undo step; later ones join it. */
43
+ function commit(gesture: string | null) {
44
+ if (!gesture) return true;
45
+ if (drags.has(gesture)) return false;
46
+ drags.add(gesture);
47
+ return true;
48
+ }
49
+ function toggle(b: Exclude<Browse, null>) {
50
+ browse = browse === b ? null : b;
51
+ }
52
+ function pick(id: string) {
53
+ const kind = browse;
54
+ const layerId = view.activeId;
55
+ browse = null;
56
+ if (kind === 'paper') run(() => controller.setPaperEffect(id));
57
+ else if (kind === 'layer') run(() => controller.addEffectLayer(id));
58
+ else if (kind === 'fill') run(() => controller.fillLayerWithEffect(id));
59
+ else if (kind === 'light' && layerId) run(() => controller.applyLightEffect(layerId, id));
60
+ }
61
+ </script>
62
+
63
+ <!--
64
+ Provider effects in the paint editor: effect paper (a generator over the sheet, multiplied so the
65
+ grain shows), effect layers, effect fills and light baked onto the active layer's dried paint;
66
+ plus the controls of the effect paper and of an active effect layer. Each change is one undo
67
+ step (a slider drag is one). Without a provider it says why nothing can be added.
68
+ -->
69
+ <div class={`${panel} ${className}`} data-testid="paint-effects-panel" aria-busy={busy}>
70
+ <div class="flex flex-wrap items-center gap-1">
71
+ <span class="flex-1 font-medium text-slate-300">Effects</span>
72
+ <button type="button" class={button} disabled={!provider} aria-pressed={browse === 'paper'} onclick={() => toggle('paper')}>Paper…</button>
73
+ <button type="button" class={button} disabled={!provider} aria-pressed={browse === 'layer'} onclick={() => toggle('layer')}>Layer…</button>
74
+ <button type="button" class={button} disabled={!provider || !view.pixel} aria-pressed={browse === 'fill'} onclick={() => toggle('fill')}>Fill…</button>
75
+ <button type="button" class={button} disabled={!provider || !view.pixel} aria-pressed={browse === 'light'} onclick={() => toggle('light')} title="Bake a light, glow or grade into the active layer's dried paint">Light…</button>
76
+ </div>
77
+ {#if !provider}<p class="text-[11px] text-slate-400">No effects provider is registered. Effects in the painting are kept.</p>{/if}
78
+ {#if browse}
79
+ <EffectsBrowser {provider} uses={BROWSERS[browse].uses} title={BROWSERS[browse].title} onpick={(e) => pick(e.id)} />
80
+ {/if}
81
+ {#if view.paper}
82
+ {@const paper = view.paper}
83
+ <div class="flex flex-col gap-1 rounded border border-slate-700 p-1" data-effect-part="paper">
84
+ <div class="flex items-center gap-1">
85
+ <span class="flex-1 truncate">Paper: {paper.name ?? paper.effect}</span>
86
+ <button type="button" class={button} aria-label="Remove the effect paper" onclick={() => run(() => controller.setPaperEffect(null))}>✕</button>
87
+ </div>
88
+ <label class="flex items-center gap-1">
89
+ <span class="w-14 text-[11px] text-slate-400">Opacity</span>
90
+ <input type="range" min="0" max="1" step="0.01" class="flex-1" aria-label="Effect paper opacity" value={paper.opacity} onchange={(e) => { const opacity = Number(e.currentTarget.value); run(() => controller.updatePaperEffect({ opacity })); }} />
91
+ </label>
92
+ <label class="flex items-center gap-1">
93
+ <span class="w-14 text-[11px] text-slate-400">Blend</span>
94
+ <select class="flex-1 rounded bg-slate-800 px-1 py-0.5 text-[11px]" aria-label="Effect paper blend" value={paper.blend} onchange={(e) => { const blend = e.currentTarget.value as PaperEffectBlend; run(() => controller.updatePaperEffect({ blend })); }}>
95
+ {#each PAPER_EFFECT_BLENDS as b (b)}<option value={b}>{b}</option>{/each}
96
+ </select>
97
+ </label>
98
+ <ImageEffectControls
99
+ {provider}
100
+ effect={paper.effect}
101
+ name={paper.name}
102
+ values={paper.values}
103
+ onchange={(k, v, gesture) => run(() => controller.updatePaperEffect({ values: { [k]: v as never } }, commit(gesture)))}
104
+ onpreset={(values) => run(() => controller.updatePaperEffect({ values: { ...values } as never }))}
105
+ />
106
+ </div>
107
+ {/if}
108
+ {#if view.layerEffect && view.activeId}
109
+ {@const fx = view.layerEffect}
110
+ {@const layerId = view.activeId}
111
+ <div class="flex flex-col gap-1 rounded border border-slate-700 p-1" data-effect-part="layer">
112
+ <div class="flex items-center gap-1">
113
+ <span class="flex-1 truncate">Layer: {fx.name ?? fx.effect}</span>
114
+ <button type="button" class={button} title="Keep the pixels as a plain layer" onclick={() => run(() => controller.rasterizeEffectLayer(layerId))}>Rasterize</button>
115
+ </div>
116
+ <ImageEffectControls
117
+ {provider}
118
+ effect={fx.effect}
119
+ name={fx.name}
120
+ values={fx.values}
121
+ onchange={(k, v, gesture) => run(() => controller.updateEffectLayer(layerId, { values: { [k]: v as never } }, commit(gesture)))}
122
+ onpreset={(values) => run(() => controller.updateEffectLayer(layerId, { values: { ...values } as never }))}
123
+ />
124
+ </div>
125
+ {/if}
126
+ {#if error}<p role="alert" class="text-[11px] text-rose-400">{error}</p>{/if}
127
+ </div>
@@ -0,0 +1,9 @@
1
+ import { type PaintEditorController } from '@pixerate/editor/paint-editor';
2
+ interface Props {
3
+ controller: PaintEditorController;
4
+ class?: string;
5
+ }
6
+ declare const PaintEffectsPanel: import("svelte").Component<Props, {}, "">;
7
+ type PaintEffectsPanel = ReturnType<typeof PaintEffectsPanel>;
8
+ export default PaintEffectsPanel;
9
+ //# sourceMappingURL=PaintEffectsPanel.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaintEffectsPanel.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/PaintEffectsPanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,qBAAqB,EAAyB,MAAM,+BAA+B,CAAC;AAOrH,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA6GH,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -8,6 +8,7 @@ import type ColorPanelComponent from './ColorPanel.svelte';
8
8
  import type PaintLayersPanelComponent from './PaintLayersPanel.svelte';
9
9
  import type WetPanelComponent from './WetPanel.svelte';
10
10
  import type StickerPanelComponent from './StickerPanel.svelte';
11
+ import type PaintEffectsPanelComponent from './PaintEffectsPanel.svelte';
11
12
  import type PaintGradientEditorComponent from './PaintGradientEditor.svelte';
12
13
  export { default as PaintEditor } from './PaintEditor.svelte';
13
14
  export { default as PaintCanvas } from './PaintCanvas.svelte';
@@ -18,10 +19,11 @@ export { default as ColorPanel } from './ColorPanel.svelte';
18
19
  export { default as PaintLayersPanel } from './PaintLayersPanel.svelte';
19
20
  export { default as WetPanel } from './WetPanel.svelte';
20
21
  export { default as StickerPanel } from './StickerPanel.svelte';
22
+ export { default as PaintEffectsPanel } from './PaintEffectsPanel.svelte';
21
23
  export { default as PaintGradientEditor } from './PaintGradientEditor.svelte';
22
24
  export { default as PaintSlider } from './PaintSlider.svelte';
23
25
  export { default as PaintPresenceLayer } from './PaintPresenceLayer.svelte';
24
- export { createPaintDirector, createReactivePaintEditor, paintEditorState } from './paintEditorRune.svelte.js';
26
+ export { createPaintDirector, createReactivePaintEditor, paintEditorState, paintEffectsProvider, usePaintEffectsTools } from './paintEditorRune.svelte.js';
25
27
  export type PaintEditorProps = ComponentProps<typeof PaintEditorComponent>;
26
28
  export type PaintCanvasProps = ComponentProps<typeof PaintCanvasComponent>;
27
29
  export type PaintToolbarProps = ComponentProps<typeof PaintToolbarComponent>;
@@ -31,5 +33,6 @@ export type ColorPanelProps = ComponentProps<typeof ColorPanelComponent>;
31
33
  export type PaintLayersPanelProps = ComponentProps<typeof PaintLayersPanelComponent>;
32
34
  export type WetPanelProps = ComponentProps<typeof WetPanelComponent>;
33
35
  export type StickerPanelProps = ComponentProps<typeof StickerPanelComponent>;
36
+ export type PaintEffectsPanelProps = ComponentProps<typeof PaintEffectsPanelComponent>;
34
37
  export type PaintGradientEditorProps = ComponentProps<typeof PaintGradientEditorComponent>;
35
38
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/paint-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,4BAA4B,MAAM,8BAA8B,CAAC;AAE7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/G,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE7E,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/paint-editor/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,oBAAoB,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,0BAA0B,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,4BAA4B,MAAM,8BAA8B,CAAC;AAE7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAE3J,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAC3E,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAAC,OAAO,yBAAyB,CAAC,CAAC;AACrF,MAAM,MAAM,aAAa,GAAG,cAAc,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACrE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,MAAM,MAAM,sBAAsB,GAAG,cAAc,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEvF,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
@@ -7,7 +7,8 @@ export { default as ColorPanel } from './ColorPanel.svelte';
7
7
  export { default as PaintLayersPanel } from './PaintLayersPanel.svelte';
8
8
  export { default as WetPanel } from './WetPanel.svelte';
9
9
  export { default as StickerPanel } from './StickerPanel.svelte';
10
+ export { default as PaintEffectsPanel } from './PaintEffectsPanel.svelte';
10
11
  export { default as PaintGradientEditor } from './PaintGradientEditor.svelte';
11
12
  export { default as PaintSlider } from './PaintSlider.svelte';
12
13
  export { default as PaintPresenceLayer } from './PaintPresenceLayer.svelte';
13
- export { createPaintDirector, createReactivePaintEditor, paintEditorState } from './paintEditorRune.svelte.js';
14
+ export { createPaintDirector, createReactivePaintEditor, paintEditorState, paintEffectsProvider, usePaintEffectsTools } from './paintEditorRune.svelte.js';
@@ -1,4 +1,6 @@
1
- import { PaintDirector, PaintEditorController, PaintPresence, type PaintDirectorOptions, type PaintEditorOptions, type PaintEditorState } from '@pixerate/editor/paint-editor';
1
+ import { PaintDirector, PaintEditorController, PaintPresence, type PaintDirectorOptions, type PaintEditorOptions, type PaintEditorState, type PaintEffectsToolProviderOptions } from '@pixerate/editor/paint-editor';
2
+ import type { EffectProvider } from '@pixerate/editor/effects';
3
+ import type { ToolRegistry } from '@pixerate/editor/tools';
2
4
  /**
3
5
  * A `PaintEditorController` (created from `options`, or the one given) with its state as a
4
6
  * rune: `editor.state` updates after every change. Call `destroy()` to unsubscribe.
@@ -26,4 +28,14 @@ export declare const button = "px-2 py-1 rounded text-[11px] bg-slate-800 text-s
26
28
  export declare const panel = "flex flex-col gap-2 text-xs text-slate-200";
27
29
  /** Runs `fn` and returns the error message it threw (or a rejected promise's, through `onAsync`). */
28
30
  export declare function attempt(fn: () => unknown, onError: (msg: string | null) => void): void;
31
+ /** The controller's effects provider as a rune, following `setEffectsProvider`. */
32
+ export declare function paintEffectsProvider(controller: () => PaintEditorController): {
33
+ readonly current: EffectProvider | null;
34
+ };
35
+ /**
36
+ * Registers the paint editor's provider-effect tools (`set_paper_effect`, `add_effect_layer`,
37
+ * `fill_layer_with_effect`, `apply_effect`, …) for the lifetime of the calling component. Before
38
+ * an effects provider is registered the read tools say so and the write tools refuse.
39
+ */
40
+ export declare function usePaintEffectsTools(registry: ToolRegistry | null | undefined | (() => ToolRegistry | null | undefined), controller: PaintEditorController, options?: PaintEffectsToolProviderOptions): void;
29
41
  //# sourceMappingURL=paintEditorRune.svelte.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paintEditorRune.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/paintEditorRune.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAE/K;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,kBAAkB,GAAG,qBAA0B;;;;EAiBjG;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,qBAAqB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAoBhH;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,EAAE,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAM,GAAG;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAG9K;AAED,eAAO,MAAM,IAAI,GAAI,IAAI,OAAO,WAAwH,CAAC;AACzJ,eAAO,MAAM,MAAM,qGAAqG,CAAC;AACzH,eAAO,MAAM,KAAK,+CAA+C,CAAC;AAElE,qGAAqG;AACrG,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAQtF"}
1
+ {"version":3,"file":"paintEditorRune.svelte.d.ts","sourceRoot":"","sources":["../../src/paint-editor/paintEditorRune.svelte.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,KAAK,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AACrP,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,kBAAkB,GAAG,qBAA0B;;;;EAiBjG;AAED,8FAA8F;AAC9F,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,qBAAqB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAoBhH;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,qBAAqB,EAAE,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAM,GAAG;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,CAG9K;AAED,eAAO,MAAM,IAAI,GAAI,IAAI,OAAO,WAAwH,CAAC;AACzJ,eAAO,MAAM,MAAM,qGAAqG,CAAC;AACzH,eAAO,MAAM,KAAK,+CAA+C,CAAC;AAElE,qGAAqG;AACrG,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAQtF;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,qBAAqB,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,CAgBzH;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,MAAM,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,EACnF,UAAU,EAAE,qBAAqB,EACjC,OAAO,GAAE,+BAAoC,GAC5C,IAAI,CAMN"}
@@ -1,5 +1,5 @@
1
1
  import { untrack } from 'svelte';
2
- import { PaintDirector, PaintEditorController, PaintPresence } from '@pixerate/editor/paint-editor';
2
+ import { createPaintEffectsToolProvider, PaintDirector, PaintEditorController, PaintPresence } from '@pixerate/editor/paint-editor';
3
3
  /**
4
4
  * A `PaintEditorController` (created from `options`, or the one given) with its state as a
5
5
  * rune: `editor.state` updates after every change. Call `destroy()` to unsubscribe.
@@ -68,3 +68,34 @@ export function attempt(fn, onError) {
68
68
  onError(e instanceof Error ? e.message : String(e));
69
69
  }
70
70
  }
71
+ /** The controller's effects provider as a rune, following `setEffectsProvider`. */
72
+ export function paintEffectsProvider(controller) {
73
+ let provider = $state.raw(controller().effectsProvider);
74
+ $effect(() => {
75
+ const c = controller();
76
+ return untrack(() => {
77
+ provider = c.effectsProvider;
78
+ return c.effects.subscribe((p) => {
79
+ provider = p;
80
+ });
81
+ });
82
+ });
83
+ return {
84
+ get current() {
85
+ return provider;
86
+ },
87
+ };
88
+ }
89
+ /**
90
+ * Registers the paint editor's provider-effect tools (`set_paper_effect`, `add_effect_layer`,
91
+ * `fill_layer_with_effect`, `apply_effect`, …) for the lifetime of the calling component. Before
92
+ * an effects provider is registered the read tools say so and the write tools refuse.
93
+ */
94
+ export function usePaintEffectsTools(registry, controller, options = {}) {
95
+ $effect(() => {
96
+ const target = typeof registry === 'function' ? registry() : registry;
97
+ if (!target)
98
+ return;
99
+ return target.register(createPaintEffectsToolProvider(controller, options));
100
+ });
101
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor-svelte",
3
- "version": "0.89.0",
3
+ "version": "0.90.0",
4
4
  "description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -144,7 +144,7 @@
144
144
  "@tiptap/extension-bubble-menu": "^2.11.5",
145
145
  "@tiptap/extension-placeholder": "^2.11.5",
146
146
  "@tiptap/starter-kit": "^2.11.5",
147
- "@pixerate/editor": "0.125.0"
147
+ "@pixerate/editor": "0.126.0"
148
148
  },
149
149
  "peerDependencies": {
150
150
  "@dagrejs/dagre": "^1.1.4",