@pixerate/editor-svelte 0.81.0 → 0.82.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.
@@ -1,6 +1,18 @@
1
1
  <script lang="ts">
2
2
  import type { ImageEditorController } from '@pixerate/editor/image-editor';
3
- import { BRUSH_OPTION_CONTROLS, MIXER_MIXING_OPTIONS, MIXER_OPTION_CONTROLS, PAINT_TOOLS, rgbUnitToHex } from '@pixerate/editor/image-editor';
3
+ import {
4
+ BRUSH_OPTION_CONTROLS,
5
+ MIXER_MIXING_OPTIONS,
6
+ MIXER_OPTION_CONTROLS,
7
+ PAINT_TOOLS,
8
+ RETOUCH_CHOICES,
9
+ RETOUCH_OPTION_CONTROLS,
10
+ RETOUCH_TOGGLES,
11
+ cloneSourceLabel,
12
+ isRetouchPaintTool,
13
+ rgbUnitToHex,
14
+ setRetouchChoice,
15
+ } from '@pixerate/editor/image-editor';
4
16
  import { untrack } from 'svelte';
5
17
  import ControlSlider from './ControlSlider.svelte';
6
18
 
@@ -20,7 +32,7 @@
20
32
  const view = $derived.by(() => {
21
33
  void tick;
22
34
  const s = controller.getState();
23
- return { tool: s.activeTool, ...s.paint };
35
+ return { tool: s.activeTool, sourceLabel: cloneSourceLabel(controller), ...s.paint };
24
36
  });
25
37
  let error = $state<string | null>(null);
26
38
 
@@ -37,12 +49,12 @@
37
49
  </script>
38
50
 
39
51
  <div class="flex flex-col gap-2 text-xs text-slate-200 {className}" data-testid="brush-options">
40
- <div class="flex gap-1" role="toolbar" aria-label="Paint tools">
52
+ <div class="flex flex-wrap gap-1" role="toolbar" aria-label="Paint tools">
41
53
  {#each PAINT_TOOLS as t (t.id)}
42
54
  <button
43
55
  type="button"
44
56
  aria-pressed={view.tool === t.id}
45
- title={`${t.label} (${t.shortcut})`}
57
+ title={t.shortcut ? `${t.label} (${t.shortcut})` : t.label}
46
58
  class={chip(view.tool === t.id)}
47
59
  onclick={() => controller.setTool(t.id)}>{t.label}</button>
48
60
  {/each}
@@ -128,6 +140,49 @@
128
140
  </div>
129
141
  {/if}
130
142
 
143
+ {#if isRetouchPaintTool(view.tool)}
144
+ <div class="flex flex-col gap-2 border-t border-slate-800 pt-2" role="group" aria-label="Retouch options" data-testid="retouch-options">
145
+ {#if view.tool === 'clone' || view.tool === 'heal'}
146
+ <div class="flex items-center gap-2">
147
+ <span class="text-slate-400" data-testid="clone-source">{view.sourceLabel}</span>
148
+ {#if view.cloneSource}
149
+ <button type="button" title="Forget the source point" class={chip(false)} onclick={() => controller.setCloneSource(null)}>Clear source</button>
150
+ {/if}
151
+ </div>
152
+ {/if}
153
+ {#each RETOUCH_CHOICES.filter((c) => c.tools.includes(view.tool as never)) as choice (choice.id)}
154
+ <div class="flex flex-wrap items-center gap-1" role="group" aria-label={choice.label}>
155
+ <span class="text-slate-400">{choice.label}</span>
156
+ {#each choice.options as o (o.id)}
157
+ <button
158
+ type="button"
159
+ aria-pressed={view.retouch[choice.id] === o.id}
160
+ title={o.title}
161
+ class={chip(view.retouch[choice.id] === o.id)}
162
+ onclick={() => setRetouchChoice(controller, choice.id, o.id)}>{o.label}</button>
163
+ {/each}
164
+ </div>
165
+ {/each}
166
+ {#each RETOUCH_OPTION_CONTROLS.filter((c) => c.tools.includes(view.tool as never)) as spec (spec.id)}
167
+ <ControlSlider {spec} value={view.retouch[spec.id]} onchange={(v) => controller.setPaintOptions({ retouch: { [spec.id]: v } })} />
168
+ {/each}
169
+ <div class="flex flex-wrap gap-3 text-slate-300">
170
+ {#each RETOUCH_TOGGLES.filter((t) => t.tools.includes(view.tool as never)) as t (t.id)}
171
+ <label class="flex items-center gap-1.5">
172
+ <input
173
+ type="checkbox"
174
+ aria-label={t.label}
175
+ checked={view.retouch[t.id]}
176
+ onchange={(e) => controller.setPaintOptions({ retouch: { [t.id]: (e.target as HTMLInputElement).checked } })}
177
+ class="accent-indigo-500"
178
+ />
179
+ {t.label}
180
+ </label>
181
+ {/each}
182
+ </div>
183
+ </div>
184
+ {/if}
185
+
131
186
  <div class="flex flex-wrap gap-3 text-slate-300" role="group" aria-label="Pressure">
132
187
  <label class="flex items-center gap-1.5">
133
188
  <input
@@ -1 +1 @@
1
- {"version":3,"file":"BrushOptionsBar.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/BrushOptionsBar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAMzE,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA8GH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"BrushOptionsBar.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/BrushOptionsBar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAkBzE,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA8IH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -381,7 +381,7 @@
381
381
  } catch {
382
382
  // Synthetic events have no active pointer to capture.
383
383
  }
384
- paintError = paintGesture.down(paintSamples(e)[0]);
384
+ paintError = paintGesture.down({ ...paintSamples(e)[0], altKey: e.altKey });
385
385
  }
386
386
  function handlePaintPointerMove(e: PointerEvent) {
387
387
  if (handleTransformPointerMove(e)) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor-svelte",
3
- "version": "0.81.0",
3
+ "version": "0.82.0",
4
4
  "description": "Svelte bindings and prompt/rich-text components for @pixerate/editor",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -139,7 +139,7 @@
139
139
  "@tiptap/extension-bubble-menu": "^2.11.5",
140
140
  "@tiptap/extension-placeholder": "^2.11.5",
141
141
  "@tiptap/starter-kit": "^2.11.5",
142
- "@pixerate/editor": "0.112.0"
142
+ "@pixerate/editor": "0.113.0"
143
143
  },
144
144
  "peerDependencies": {
145
145
  "@dagrejs/dagre": "^1.1.4",