@pixerate/editor-svelte 0.23.0 → 0.24.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/README.md +2 -2
- package/dist/StylesGallery.svelte +169 -0
- package/dist/StylesGallery.svelte.d.ts +27 -0
- package/dist/StylesGallery.svelte.d.ts.map +1 -0
- package/dist/canvas/TokenBindingPicker.svelte +93 -0
- package/dist/canvas/TokenBindingPicker.svelte.d.ts +20 -0
- package/dist/canvas/TokenBindingPicker.svelte.d.ts.map +1 -0
- package/dist/canvas/TokenModeSwitcher.svelte +55 -0
- package/dist/canvas/TokenModeSwitcher.svelte.d.ts +18 -0
- package/dist/canvas/TokenModeSwitcher.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasArrange.svelte.d.ts +4 -0
- package/dist/canvas/createCanvasArrange.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasAutoLayout.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasTokens.svelte.d.ts +31 -0
- package/dist/canvas/createCanvasTokens.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasTokens.svelte.js +50 -0
- package/dist/canvas/index.d.ts +5 -0
- package/dist/canvas/index.d.ts.map +1 -1
- package/dist/canvas/index.js +7 -0
- package/dist/fileImport.svelte.d.ts +8 -1
- package/dist/fileImport.svelte.d.ts.map +1 -1
- package/dist/fileImport.svelte.js +11 -1
- package/dist/generation/AssetMentionChips.svelte +130 -0
- package/dist/generation/AssetMentionChips.svelte.d.ts +21 -0
- package/dist/generation/AssetMentionChips.svelte.d.ts.map +1 -0
- package/dist/generation/GenerationHistory.svelte +161 -0
- package/dist/generation/GenerationHistory.svelte.d.ts +28 -0
- package/dist/generation/GenerationHistory.svelte.d.ts.map +1 -0
- package/dist/generation/index.d.ts +7 -0
- package/dist/generation/index.d.ts.map +1 -1
- package/dist/generation/index.js +3 -0
- package/dist/generation/records.svelte.d.ts +18 -0
- package/dist/generation/records.svelte.d.ts.map +1 -0
- package/dist/generation/records.svelte.js +66 -0
- package/dist/image-editor/ImageEditor.svelte +72 -1
- package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -1
- package/dist/image-editor/RefineEdgePanel.svelte +180 -0
- package/dist/image-editor/RefineEdgePanel.svelte.d.ts +13 -0
- package/dist/image-editor/RefineEdgePanel.svelte.d.ts.map +1 -0
- package/dist/image-editor/SelectionOptionsBar.svelte +135 -0
- package/dist/image-editor/SelectionOptionsBar.svelte.d.ts +15 -0
- package/dist/image-editor/SelectionOptionsBar.svelte.d.ts.map +1 -0
- package/dist/image-editor/index.d.ts +6 -0
- package/dist/image-editor/index.d.ts.map +1 -1
- package/dist/image-editor/index.js +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/paragraphStyles.svelte.d.ts +30 -0
- package/dist/paragraphStyles.svelte.d.ts.map +1 -0
- package/dist/paragraphStyles.svelte.js +44 -0
- package/dist/review/TrackedChangesList.svelte +67 -0
- package/dist/review/TrackedChangesList.svelte.d.ts +13 -0
- package/dist/review/TrackedChangesList.svelte.d.ts.map +1 -0
- package/dist/review/index.d.ts +3 -0
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +1 -0
- package/dist/review/review.svelte.d.ts +6 -0
- package/dist/review/review.svelte.d.ts.map +1 -1
- package/dist/review/review.svelte.js +3 -0
- package/dist/spreadsheet/FormulaBar.svelte +13 -4
- package/dist/spreadsheet/FormulaBar.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/FormulaHints.svelte +7 -5
- package/dist/spreadsheet/FormulaHints.svelte.d.ts +3 -0
- package/dist/spreadsheet/FormulaHints.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/NameManager.svelte +165 -0
- package/dist/spreadsheet/NameManager.svelte.d.ts +11 -0
- package/dist/spreadsheet/NameManager.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/SheetTabs.svelte +161 -0
- package/dist/spreadsheet/SheetTabs.svelte.d.ts +10 -0
- package/dist/spreadsheet/SheetTabs.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/SpreadsheetConditionalFormatPanel.svelte +184 -0
- package/dist/spreadsheet/SpreadsheetConditionalFormatPanel.svelte.d.ts +9 -0
- package/dist/spreadsheet/SpreadsheetConditionalFormatPanel.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte +9 -4
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts +5 -1
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetDataValidationPanel.svelte +141 -0
- package/dist/spreadsheet/SpreadsheetDataValidationPanel.svelte.d.ts +9 -0
- package/dist/spreadsheet/SpreadsheetDataValidationPanel.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte +197 -13
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts +2 -0
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetValidationDialog.svelte +92 -0
- package/dist/spreadsheet/SpreadsheetValidationDialog.svelte.d.ts +9 -0
- package/dist/spreadsheet/SpreadsheetValidationDialog.svelte.d.ts.map +1 -0
- package/dist/spreadsheet/index.d.ts +9 -0
- package/dist/spreadsheet/index.d.ts.map +1 -1
- package/dist/spreadsheet/index.js +5 -0
- package/dist/spreadsheet/spreadsheet.svelte.d.ts +55 -2
- package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/spreadsheet.svelte.js +105 -6
- package/dist/tokens/TokenSwatch.svelte +14 -0
- package/dist/tokens/TokenSwatch.svelte.d.ts +8 -0
- package/dist/tokens/TokenSwatch.svelte.d.ts.map +1 -0
- package/dist/tokens/TokensPanel.svelte +323 -0
- package/dist/tokens/TokensPanel.svelte.d.ts +14 -0
- package/dist/tokens/TokensPanel.svelte.d.ts.map +1 -0
- package/dist/tokens/createTokens.svelte.d.ts +31 -0
- package/dist/tokens/createTokens.svelte.d.ts.map +1 -0
- package/dist/tokens/createTokens.svelte.js +43 -0
- package/dist/tokens/index.d.ts +7 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +3 -0
- package/package.json +10 -2
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
AdjustmentKind,
|
|
4
|
+
AdjustmentLayer,
|
|
5
|
+
ImageEditorController,
|
|
6
|
+
RefineEdgeParams,
|
|
7
|
+
SelectionMask,
|
|
8
|
+
} from '@pixerate/editor/image-editor';
|
|
9
|
+
import {
|
|
10
|
+
ADJUSTMENT_KINDS,
|
|
11
|
+
REFINE_EDGE_CONTROLS,
|
|
12
|
+
adjustmentKindLabel,
|
|
13
|
+
layerMaskFromSelection,
|
|
14
|
+
} from '@pixerate/editor/image-editor';
|
|
15
|
+
import { untrack } from 'svelte';
|
|
16
|
+
|
|
17
|
+
interface Props {
|
|
18
|
+
controller: ImageEditorController;
|
|
19
|
+
/** The current selection (`state.selection`). Omit to follow the controller. */
|
|
20
|
+
selection?: SelectionMask | null;
|
|
21
|
+
/** The adjustment layers (`state.adjustments.layers`). Omit to follow the controller. */
|
|
22
|
+
layers?: AdjustmentLayer[];
|
|
23
|
+
class?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let { controller, selection, layers: layersProp, class: className = '' }: Props = $props();
|
|
27
|
+
|
|
28
|
+
let tick = $state(0);
|
|
29
|
+
$effect(() => {
|
|
30
|
+
const c = controller;
|
|
31
|
+
return untrack(() => c.subscribe(() => tick++));
|
|
32
|
+
});
|
|
33
|
+
const sel = $derived.by(() => {
|
|
34
|
+
void tick;
|
|
35
|
+
return selection === undefined ? controller.getSelection() : selection;
|
|
36
|
+
});
|
|
37
|
+
const list = $derived.by(() => {
|
|
38
|
+
void tick;
|
|
39
|
+
return layersProp ?? controller.getAdjustmentLayers();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const DEFAULT_PARAMS: Required<RefineEdgeParams> = { radius: 8, smartRadius: false, smooth: 0, feather: 0, contrast: 0, shiftEdge: 0 };
|
|
43
|
+
let params = $state<Required<RefineEdgeParams>>({ ...DEFAULT_PARAMS });
|
|
44
|
+
let busy = $state(false);
|
|
45
|
+
let error = $state<string | null>(null);
|
|
46
|
+
let layerId = $state('');
|
|
47
|
+
let newKind = $state<AdjustmentKind>('hueSaturation');
|
|
48
|
+
const target = $derived(list.find((l) => l.id === layerId) ?? list[list.length - 1]);
|
|
49
|
+
|
|
50
|
+
async function refine() {
|
|
51
|
+
busy = true;
|
|
52
|
+
error = null;
|
|
53
|
+
try {
|
|
54
|
+
await controller.refineSelection({ ...params });
|
|
55
|
+
} catch (err) {
|
|
56
|
+
error = err instanceof Error ? err.message : String(err);
|
|
57
|
+
} finally {
|
|
58
|
+
busy = false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function newMaskedLayer() {
|
|
63
|
+
const s = controller.getSelection();
|
|
64
|
+
if (s) layerId = controller.addAdjustmentLayer({ kind: newKind, mask: layerMaskFromSelection(s) });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const button =
|
|
68
|
+
'px-2 py-1 rounded-md border border-slate-800 bg-slate-950 text-[11px] text-slate-200 hover:text-white disabled:opacity-40';
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<div data-testid="refine-edge-panel" class="flex flex-col gap-3 text-xs {className}">
|
|
72
|
+
<span class="font-semibold text-slate-200 uppercase tracking-wider text-[11px]">Refine Edge</span>
|
|
73
|
+
{#each REFINE_EDGE_CONTROLS as c (c.id)}
|
|
74
|
+
<label class="flex flex-col gap-1">
|
|
75
|
+
<span class="flex justify-between text-slate-400">
|
|
76
|
+
<span>{c.label}</span>
|
|
77
|
+
<span class="font-mono">{params[c.id]}{c.unit}</span>
|
|
78
|
+
</span>
|
|
79
|
+
<input
|
|
80
|
+
type="range"
|
|
81
|
+
min={c.min}
|
|
82
|
+
max={c.max}
|
|
83
|
+
step={c.step}
|
|
84
|
+
aria-label={c.label}
|
|
85
|
+
value={params[c.id]}
|
|
86
|
+
oninput={(e) => (params = { ...params, [c.id]: Number((e.currentTarget as HTMLInputElement).value) })}
|
|
87
|
+
class="w-full accent-indigo-500"
|
|
88
|
+
/>
|
|
89
|
+
</label>
|
|
90
|
+
{/each}
|
|
91
|
+
<label class="flex items-center gap-2 text-slate-300">
|
|
92
|
+
<input
|
|
93
|
+
type="checkbox"
|
|
94
|
+
checked={params.smartRadius}
|
|
95
|
+
onchange={(e) => (params = { ...params, smartRadius: (e.currentTarget as HTMLInputElement).checked })}
|
|
96
|
+
/>
|
|
97
|
+
Smart Radius
|
|
98
|
+
</label>
|
|
99
|
+
<div class="flex gap-1">
|
|
100
|
+
<button type="button" class={button} disabled={!sel || busy} onclick={refine}>Refine Edge</button>
|
|
101
|
+
<button type="button" class={button} onclick={() => (params = { ...DEFAULT_PARAMS })}>Reset</button>
|
|
102
|
+
</div>
|
|
103
|
+
{#if error}
|
|
104
|
+
<p role="alert" class="text-rose-400">{error}</p>
|
|
105
|
+
{/if}
|
|
106
|
+
|
|
107
|
+
<span class="font-semibold text-slate-200 uppercase tracking-wider text-[11px] mt-2">Layer Mask</span>
|
|
108
|
+
<div class="flex gap-1 items-center">
|
|
109
|
+
<select
|
|
110
|
+
aria-label="New masked layer kind"
|
|
111
|
+
value={newKind}
|
|
112
|
+
onchange={(e) => (newKind = (e.currentTarget as HTMLSelectElement).value as AdjustmentKind)}
|
|
113
|
+
class="flex-1 bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200"
|
|
114
|
+
>
|
|
115
|
+
{#each ADJUSTMENT_KINDS as k (k.kind)}
|
|
116
|
+
<option value={k.kind}>{k.label}</option>
|
|
117
|
+
{/each}
|
|
118
|
+
</select>
|
|
119
|
+
<button type="button" class={button} disabled={!sel} onclick={newMaskedLayer}>New Masked Layer</button>
|
|
120
|
+
</div>
|
|
121
|
+
{#if list.length > 0 && target}
|
|
122
|
+
<div class="flex flex-col gap-2">
|
|
123
|
+
<select
|
|
124
|
+
aria-label="Mask layer"
|
|
125
|
+
value={target.id}
|
|
126
|
+
onchange={(e) => (layerId = (e.currentTarget as HTMLSelectElement).value)}
|
|
127
|
+
class="bg-slate-950 border border-slate-800 rounded px-1 py-1 text-slate-200"
|
|
128
|
+
>
|
|
129
|
+
{#each list as l (l.id)}
|
|
130
|
+
<option value={l.id}>{l.name || adjustmentKindLabel(l.kind)}{l.mask ? ' (masked)' : ''}</option>
|
|
131
|
+
{/each}
|
|
132
|
+
</select>
|
|
133
|
+
<div class="flex flex-wrap gap-1">
|
|
134
|
+
<button type="button" class={button} disabled={!sel} onclick={() => controller.applySelectionAsLayerMask(target.id)}>
|
|
135
|
+
Mask with Selection
|
|
136
|
+
</button>
|
|
137
|
+
<button type="button" class={button} disabled={!target.mask} onclick={() => controller.selectionFromLayerMask(target.id)}>
|
|
138
|
+
Load as Selection
|
|
139
|
+
</button>
|
|
140
|
+
<button type="button" class={button} disabled={!target.mask} onclick={() => controller.setAdjustmentLayerMask(target.id, null)}>
|
|
141
|
+
Remove Mask
|
|
142
|
+
</button>
|
|
143
|
+
</div>
|
|
144
|
+
{#if target.mask}
|
|
145
|
+
<label class="flex flex-col gap-1">
|
|
146
|
+
<span class="flex justify-between text-slate-400">
|
|
147
|
+
<span>Density</span>
|
|
148
|
+
<span class="font-mono">{Math.round((target.mask.density ?? 1) * 100)}%</span>
|
|
149
|
+
</span>
|
|
150
|
+
<input
|
|
151
|
+
type="range"
|
|
152
|
+
min="0"
|
|
153
|
+
max="100"
|
|
154
|
+
step="1"
|
|
155
|
+
aria-label="Mask density"
|
|
156
|
+
value={Math.round((target.mask.density ?? 1) * 100)}
|
|
157
|
+
oninput={(e) => controller.setAdjustmentLayerMaskProps(target.id, { density: Number((e.currentTarget as HTMLInputElement).value) / 100 })}
|
|
158
|
+
class="w-full accent-indigo-500"
|
|
159
|
+
/>
|
|
160
|
+
</label>
|
|
161
|
+
<label class="flex flex-col gap-1">
|
|
162
|
+
<span class="flex justify-between text-slate-400">
|
|
163
|
+
<span>Mask Feather</span>
|
|
164
|
+
<span class="font-mono">{target.mask.feather ?? 0}px</span>
|
|
165
|
+
</span>
|
|
166
|
+
<input
|
|
167
|
+
type="range"
|
|
168
|
+
min="0"
|
|
169
|
+
max="50"
|
|
170
|
+
step="0.5"
|
|
171
|
+
aria-label="Mask feather"
|
|
172
|
+
value={target.mask.feather ?? 0}
|
|
173
|
+
oninput={(e) => controller.setAdjustmentLayerMaskProps(target.id, { feather: Number((e.currentTarget as HTMLInputElement).value) })}
|
|
174
|
+
class="w-full accent-indigo-500"
|
|
175
|
+
/>
|
|
176
|
+
</label>
|
|
177
|
+
{/if}
|
|
178
|
+
</div>
|
|
179
|
+
{/if}
|
|
180
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AdjustmentLayer, ImageEditorController, SelectionMask } from '@pixerate/editor/image-editor';
|
|
2
|
+
interface Props {
|
|
3
|
+
controller: ImageEditorController;
|
|
4
|
+
/** The current selection (`state.selection`). Omit to follow the controller. */
|
|
5
|
+
selection?: SelectionMask | null;
|
|
6
|
+
/** The adjustment layers (`state.adjustments.layers`). Omit to follow the controller. */
|
|
7
|
+
layers?: AdjustmentLayer[];
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const RefineEdgePanel: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type RefineEdgePanel = ReturnType<typeof RefineEdgePanel>;
|
|
12
|
+
export default RefineEdgePanel;
|
|
13
|
+
//# sourceMappingURL=RefineEdgePanel.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RefineEdgePanel.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/RefineEdgePanel.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAER,eAAe,EACf,qBAAqB,EAErB,aAAa,EACd,MAAM,+BAA+B,CAAC;AAUvC,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,gFAAgF;IAChF,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,yFAAyF;IACzF,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4HH,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
ImageEditorController,
|
|
4
|
+
SelectionMask,
|
|
5
|
+
SelectionModifyOp,
|
|
6
|
+
SelectionToolOptions,
|
|
7
|
+
} from '@pixerate/editor/image-editor';
|
|
8
|
+
import {
|
|
9
|
+
SELECTION_MODES,
|
|
10
|
+
SELECTION_MODE_LABELS,
|
|
11
|
+
SELECTION_TOOLS,
|
|
12
|
+
describeSelection,
|
|
13
|
+
} from '@pixerate/editor/image-editor';
|
|
14
|
+
import { untrack } from 'svelte';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
controller: ImageEditorController;
|
|
18
|
+
options: SelectionToolOptions;
|
|
19
|
+
onOptionsChange: (next: SelectionToolOptions) => void;
|
|
20
|
+
/** The current selection (`state.selection`). Omit to follow the controller. */
|
|
21
|
+
selection?: SelectionMask | null;
|
|
22
|
+
/** The Quick Mask view flag (`state.quickMask`). Omit to follow the controller. */
|
|
23
|
+
quickMask?: boolean;
|
|
24
|
+
class?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let { controller, options, onOptionsChange, selection, quickMask, class: className = '' }: Props = $props();
|
|
28
|
+
|
|
29
|
+
let tick = $state(0);
|
|
30
|
+
$effect(() => {
|
|
31
|
+
const c = controller;
|
|
32
|
+
return untrack(() => c.subscribe(() => tick++));
|
|
33
|
+
});
|
|
34
|
+
const sel = $derived.by(() => {
|
|
35
|
+
void tick;
|
|
36
|
+
return selection === undefined ? controller.getSelection() : selection;
|
|
37
|
+
});
|
|
38
|
+
const qm = $derived.by(() => {
|
|
39
|
+
void tick;
|
|
40
|
+
return quickMask ?? Boolean(controller.getState().quickMask);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
let radius = $state(2);
|
|
44
|
+
|
|
45
|
+
const MODIFY_OPS: { op: SelectionModifyOp; label: string }[] = [
|
|
46
|
+
{ op: 'grow', label: 'Grow' },
|
|
47
|
+
{ op: 'shrink', label: 'Shrink' },
|
|
48
|
+
{ op: 'feather', label: 'Feather' },
|
|
49
|
+
{ op: 'border', label: 'Border' },
|
|
50
|
+
{ op: 'smooth', label: 'Smooth' },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
function set(patch: Partial<SelectionToolOptions>) {
|
|
54
|
+
onOptionsChange({ ...options, ...patch });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const btn = (on: boolean) =>
|
|
58
|
+
`px-2 py-1 rounded-md border text-[11px] transition-colors ${
|
|
59
|
+
on ? 'bg-indigo-600 border-indigo-500 text-white' : 'bg-slate-950 border-slate-800 text-slate-300 hover:text-white'
|
|
60
|
+
}`;
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
<div data-testid="selection-options-bar" class="flex flex-col gap-3 text-xs {className}">
|
|
64
|
+
<div role="group" aria-label="Selection tool" class="flex flex-wrap gap-1">
|
|
65
|
+
{#each SELECTION_TOOLS as t (t.id)}
|
|
66
|
+
<button type="button" aria-pressed={options.tool === t.id} class={btn(options.tool === t.id)} onclick={() => set({ tool: t.id })}>
|
|
67
|
+
{t.label}
|
|
68
|
+
</button>
|
|
69
|
+
{/each}
|
|
70
|
+
</div>
|
|
71
|
+
<div role="group" aria-label="Selection mode" class="flex flex-wrap gap-1">
|
|
72
|
+
{#each SELECTION_MODES as m (m)}
|
|
73
|
+
<button type="button" aria-pressed={options.mode === m} class={btn(options.mode === m)} onclick={() => set({ mode: m })}>
|
|
74
|
+
{SELECTION_MODE_LABELS[m]}
|
|
75
|
+
</button>
|
|
76
|
+
{/each}
|
|
77
|
+
</div>
|
|
78
|
+
{#if options.tool === 'wand'}
|
|
79
|
+
<div class="flex flex-col gap-2">
|
|
80
|
+
<label class="flex flex-col gap-1">
|
|
81
|
+
<span class="flex justify-between text-slate-400">
|
|
82
|
+
<span>Tolerance</span>
|
|
83
|
+
<span class="font-mono">{options.tolerance}</span>
|
|
84
|
+
</span>
|
|
85
|
+
<input
|
|
86
|
+
type="range"
|
|
87
|
+
min="0"
|
|
88
|
+
max="255"
|
|
89
|
+
step="1"
|
|
90
|
+
aria-label="Tolerance"
|
|
91
|
+
value={options.tolerance}
|
|
92
|
+
oninput={(e) => set({ tolerance: Number((e.currentTarget as HTMLInputElement).value) })}
|
|
93
|
+
class="w-full accent-indigo-500"
|
|
94
|
+
/>
|
|
95
|
+
</label>
|
|
96
|
+
<label class="flex items-center gap-2 text-slate-300">
|
|
97
|
+
<input type="checkbox" checked={options.contiguous} onchange={(e) => set({ contiguous: (e.currentTarget as HTMLInputElement).checked })} />
|
|
98
|
+
Contiguous
|
|
99
|
+
</label>
|
|
100
|
+
<label class="flex items-center gap-2 text-slate-300">
|
|
101
|
+
<input type="checkbox" checked={options.sampleMerged} onchange={(e) => set({ sampleMerged: (e.currentTarget as HTMLInputElement).checked })} />
|
|
102
|
+
Sample adjusted image
|
|
103
|
+
</label>
|
|
104
|
+
</div>
|
|
105
|
+
{/if}
|
|
106
|
+
<label class="flex items-center gap-2 text-slate-300">
|
|
107
|
+
<input type="checkbox" checked={options.antiAlias} onchange={(e) => set({ antiAlias: (e.currentTarget as HTMLInputElement).checked })} />
|
|
108
|
+
Anti-alias
|
|
109
|
+
</label>
|
|
110
|
+
<div class="flex flex-wrap gap-1">
|
|
111
|
+
<button type="button" class={btn(false)} onclick={() => controller.selectAll()}>Select All</button>
|
|
112
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => controller.deselect()}>Deselect</button>
|
|
113
|
+
<button type="button" class={btn(false)} onclick={() => controller.invertSelection()}>Inverse</button>
|
|
114
|
+
<button type="button" aria-pressed={qm} class={btn(qm)} onclick={() => controller.setQuickMask(!qm)}>Quick Mask</button>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="flex flex-wrap items-center gap-1">
|
|
117
|
+
<label class="flex items-center gap-1 text-slate-400">
|
|
118
|
+
Radius
|
|
119
|
+
<input
|
|
120
|
+
type="number"
|
|
121
|
+
min="0"
|
|
122
|
+
max="500"
|
|
123
|
+
step="1"
|
|
124
|
+
aria-label="Modify radius"
|
|
125
|
+
value={radius}
|
|
126
|
+
oninput={(e) => (radius = Math.max(0, Number((e.currentTarget as HTMLInputElement).value) || 0))}
|
|
127
|
+
class="w-14 bg-slate-950 border border-slate-800 rounded px-1 py-0.5 text-slate-200"
|
|
128
|
+
/>
|
|
129
|
+
</label>
|
|
130
|
+
{#each MODIFY_OPS as m (m.op)}
|
|
131
|
+
<button type="button" class={btn(false)} disabled={!sel} onclick={() => controller.modifySelection(m.op, radius)}>{m.label}</button>
|
|
132
|
+
{/each}
|
|
133
|
+
</div>
|
|
134
|
+
<p data-testid="selection-status" class="text-slate-400">{describeSelection(sel)}</p>
|
|
135
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ImageEditorController, SelectionMask, SelectionToolOptions } from '@pixerate/editor/image-editor';
|
|
2
|
+
interface Props {
|
|
3
|
+
controller: ImageEditorController;
|
|
4
|
+
options: SelectionToolOptions;
|
|
5
|
+
onOptionsChange: (next: SelectionToolOptions) => void;
|
|
6
|
+
/** The current selection (`state.selection`). Omit to follow the controller. */
|
|
7
|
+
selection?: SelectionMask | null;
|
|
8
|
+
/** The Quick Mask view flag (`state.quickMask`). Omit to follow the controller. */
|
|
9
|
+
quickMask?: boolean;
|
|
10
|
+
class?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const SelectionOptionsBar: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type SelectionOptionsBar = ReturnType<typeof SelectionOptionsBar>;
|
|
14
|
+
export default SelectionOptionsBar;
|
|
15
|
+
//# sourceMappingURL=SelectionOptionsBar.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionOptionsBar.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/SelectionOptionsBar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACR,qBAAqB,EACrB,aAAa,EAEb,oBAAoB,EACrB,MAAM,+BAA+B,CAAC;AAUvC,UAAU,KAAK;IACb,UAAU,EAAE,qBAAqB,CAAC;IAClC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,eAAe,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,gFAAgF;IAChF,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,mFAAmF;IACnF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAqGH,QAAA,MAAM,mBAAmB,2CAAwC,CAAC;AAClE,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAClE,eAAe,mBAAmB,CAAC"}
|
|
@@ -4,15 +4,21 @@ import type HistogramComponent from "./Histogram.svelte";
|
|
|
4
4
|
import type AdjustmentLayersPanelComponent from "./AdjustmentLayersPanel.svelte";
|
|
5
5
|
import type CurvesEditorComponent from "./CurvesEditor.svelte";
|
|
6
6
|
import type ControlSliderComponent from "./ControlSlider.svelte";
|
|
7
|
+
import type SelectionOptionsBarComponent from "./SelectionOptionsBar.svelte";
|
|
8
|
+
import type RefineEdgePanelComponent from "./RefineEdgePanel.svelte";
|
|
7
9
|
export { default as ImageEditor } from './ImageEditor.svelte';
|
|
8
10
|
export { default as Histogram } from './Histogram.svelte';
|
|
9
11
|
export { default as AdjustmentLayersPanel } from './AdjustmentLayersPanel.svelte';
|
|
10
12
|
export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
11
13
|
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
14
|
+
export { default as SelectionOptionsBar } from './SelectionOptionsBar.svelte';
|
|
15
|
+
export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
12
16
|
export * from './imageEditorState.svelte.js';
|
|
13
17
|
export type ImageEditorProps = ComponentProps<typeof ImageEditorComponent>;
|
|
14
18
|
export type HistogramProps = ComponentProps<typeof HistogramComponent>;
|
|
15
19
|
export type AdjustmentLayersPanelProps = ComponentProps<typeof AdjustmentLayersPanelComponent>;
|
|
16
20
|
export type CurvesEditorProps = ComponentProps<typeof CurvesEditorComponent>;
|
|
17
21
|
export type ControlSliderProps = ComponentProps<typeof ControlSliderComponent>;
|
|
22
|
+
export type SelectionOptionsBarProps = ComponentProps<typeof SelectionOptionsBarComponent>;
|
|
23
|
+
export type RefineEdgePanelProps = ComponentProps<typeof RefineEdgePanelComponent>;
|
|
18
24
|
//# 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;
|
|
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;AAErE,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,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"}
|
|
@@ -3,4 +3,6 @@ export { default as Histogram } from './Histogram.svelte';
|
|
|
3
3
|
export { default as AdjustmentLayersPanel } from './AdjustmentLayersPanel.svelte';
|
|
4
4
|
export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
5
5
|
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
6
|
+
export { default as SelectionOptionsBar } from './SelectionOptionsBar.svelte';
|
|
7
|
+
export { default as RefineEdgePanel } from './RefineEdgePanel.svelte';
|
|
6
8
|
export * from './imageEditorState.svelte.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type TemplateRendererComponent from "./TemplateRenderer.svelte";
|
|
|
5
5
|
import type VariableFormComponent from "./VariableForm.svelte";
|
|
6
6
|
import type OutlinePanelComponent from "./OutlinePanel.svelte";
|
|
7
7
|
import type MergePreviewComponent from "./MergePreview.svelte";
|
|
8
|
+
import type StylesGalleryComponent from "./StylesGallery.svelte";
|
|
8
9
|
export * from "./editor.svelte.js";
|
|
9
10
|
export * from "./navigationGuard.js";
|
|
10
11
|
export * from "./createNavigationGuard.svelte.js";
|
|
@@ -27,6 +28,9 @@ export type MergePreviewProps = ComponentProps<typeof MergePreviewComponent>;
|
|
|
27
28
|
export { default as MergePreview } from "./MergePreview.svelte";
|
|
28
29
|
export type OutlinePanelProps = ComponentProps<typeof OutlinePanelComponent>;
|
|
29
30
|
export { default as OutlinePanel } from "./OutlinePanel.svelte";
|
|
31
|
+
export * from "./paragraphStyles.svelte.js";
|
|
32
|
+
export type StylesGalleryProps = ComponentProps<typeof StylesGalleryComponent>;
|
|
33
|
+
export { default as StylesGallery } from "./StylesGallery.svelte";
|
|
30
34
|
export type { Template, TemplateVersion, Token, TokenType, ColorGradient, RichTextPresetOptions, ImageOptions, } from "@pixerate/editor";
|
|
31
35
|
export type { PromptValues, PromptDiagnostic, VariableFormField, MergeDataSource, MergeRecord, MergeRecordsResult, MergeOutput, } from "@pixerate/editor";
|
|
32
36
|
export * from "./spreadsheet/index.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,KAAK,+BAA+B,MAAM,iCAAiC,CAAC;AACnF,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE7C,OAAO,KAAK,+BAA+B,MAAM,iCAAiC,CAAC;AACnF,OAAO,KAAK,mBAAmB,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,yBAAyB,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,qBAAqB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AAEjE,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mCAAmC,CAAC;AAClD,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAElC,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,mBAAmB,EACnB,OAAO,EACP,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,WAAW,EACX,sBAAsB,EACtB,mBAAmB,EACnB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAG1B,MAAM,MAAM,2BAA2B,GAAG,cAAc,CACtD,OAAO,+BAA+B,CACvC,CAAC;AACF,MAAM,MAAM,eAAe,GAAG,cAAc,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACzE,MAAM,MAAM,qBAAqB,GAAG,cAAc,CAChD,OAAO,yBAAyB,CACjC,CAAC;AACF,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE7E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,cAAc,6BAA6B,CAAC;AAC5C,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAElE,YAAY,EACV,QAAQ,EACR,eAAe,EACf,KAAK,EACL,SAAS,EACT,aAAa,EACb,qBAAqB,EACrB,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAE1B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,8 @@ export { default as TemplateRenderer } from "./TemplateRenderer.svelte";
|
|
|
13
13
|
export { default as VariableForm } from "./VariableForm.svelte";
|
|
14
14
|
export { default as MergePreview } from "./MergePreview.svelte";
|
|
15
15
|
export { default as OutlinePanel } from "./OutlinePanel.svelte";
|
|
16
|
+
export * from "./paragraphStyles.svelte.js";
|
|
17
|
+
export { default as StylesGallery } from "./StylesGallery.svelte";
|
|
16
18
|
export * from "./spreadsheet/index.js";
|
|
17
19
|
export * from "./image-editor/index.js";
|
|
18
20
|
export * from "./review/index.js";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
import { type CreateStyleFromSelectionOptions, type ParagraphStylesSnapshot, type StyleDefinition, type StyleRegistry } from "@pixerate/editor";
|
|
3
|
+
export type { ParagraphStylesSnapshot, StyleDefinition } from "@pixerate/editor";
|
|
4
|
+
export interface SvelteParagraphStyles {
|
|
5
|
+
/** Snapshot: gallery, styles, character styles, current style id, version. */
|
|
6
|
+
readonly current: ParagraphStylesSnapshot;
|
|
7
|
+
readonly registry: StyleRegistry | null;
|
|
8
|
+
/** The style of the block at the selection. */
|
|
9
|
+
readonly currentStyle: StyleDefinition | null;
|
|
10
|
+
/** Applies a paragraph style to the selected blocks. */
|
|
11
|
+
apply(id: string): boolean;
|
|
12
|
+
/** Resets the selected blocks to Normal. */
|
|
13
|
+
clear(): boolean;
|
|
14
|
+
/** Updates a style (default: the current one) to the formatting at the selection. */
|
|
15
|
+
updateFromSelection(id?: string): boolean;
|
|
16
|
+
/** Creates (and applies) a style from the formatting at the selection; returns its id. */
|
|
17
|
+
createFromSelection(name: string, options?: CreateStyleFromSelectionOptions): string | null;
|
|
18
|
+
/** Applies a character style to the selection. */
|
|
19
|
+
applyCharacterStyle(id: string): boolean;
|
|
20
|
+
destroy(): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Reactive paragraph styles for Svelte 5 (the counterpart of React's
|
|
24
|
+
* `useParagraphStyles`): the gallery, all styles and the style at the
|
|
25
|
+
* selection, with commands. `current` is replaced only when the styles or
|
|
26
|
+
* the current style change. Call `destroy()` when done (or create it inside
|
|
27
|
+
* a component's `$effect`).
|
|
28
|
+
*/
|
|
29
|
+
export declare function createParagraphStyles(editor: Editor | null | undefined): SvelteParagraphStyles;
|
|
30
|
+
//# sourceMappingURL=paragraphStyles.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paragraphStyles.svelte.d.ts","sourceRoot":"","sources":["../src/paragraphStyles.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,KAAK,+BAA+B,EACpC,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEjF,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IACxC,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9C,wDAAwD;IACxD,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,4CAA4C;IAC5C,KAAK,IAAI,OAAO,CAAC;IACjB,qFAAqF;IACrF,mBAAmB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC1C,0FAA0F;IAC1F,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,+BAA+B,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5F,kDAAkD;IAClD,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,qBAAqB,CAmC9F"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { createParagraphStylesStore, getStyleRegistry, } from "@pixerate/editor";
|
|
2
|
+
/**
|
|
3
|
+
* Reactive paragraph styles for Svelte 5 (the counterpart of React's
|
|
4
|
+
* `useParagraphStyles`): the gallery, all styles and the style at the
|
|
5
|
+
* selection, with commands. `current` is replaced only when the styles or
|
|
6
|
+
* the current style change. Call `destroy()` when done (or create it inside
|
|
7
|
+
* a component's `$effect`).
|
|
8
|
+
*/
|
|
9
|
+
export function createParagraphStyles(editor) {
|
|
10
|
+
const store = createParagraphStylesStore(editor);
|
|
11
|
+
const registry = getStyleRegistry(editor);
|
|
12
|
+
let current = $state.raw(store.getSnapshot());
|
|
13
|
+
const unsubscribe = store.subscribe(() => {
|
|
14
|
+
current = store.getSnapshot();
|
|
15
|
+
});
|
|
16
|
+
const live = () => (editor && !editor.isDestroyed ? editor : null);
|
|
17
|
+
return {
|
|
18
|
+
get current() {
|
|
19
|
+
return current;
|
|
20
|
+
},
|
|
21
|
+
get registry() {
|
|
22
|
+
return registry;
|
|
23
|
+
},
|
|
24
|
+
get currentStyle() {
|
|
25
|
+
return (current.currentStyleId && registry?.get(current.currentStyleId)) || null;
|
|
26
|
+
},
|
|
27
|
+
apply: (id) => !!live()?.chain().focus().setParagraphStyle(id).run(),
|
|
28
|
+
clear: () => !!live()?.chain().focus().clearParagraphStyle().run(),
|
|
29
|
+
updateFromSelection: (id) => !!live()?.chain().focus().updateParagraphStyleFromSelection(id).run(),
|
|
30
|
+
createFromSelection: (name, options) => {
|
|
31
|
+
const e = live();
|
|
32
|
+
if (!e || !registry)
|
|
33
|
+
return null;
|
|
34
|
+
const id = options?.id ?? registry.newId(name.trim());
|
|
35
|
+
const ok = e.chain().focus().createParagraphStyleFromSelection(name, { ...options, id }).run();
|
|
36
|
+
return ok ? id : null;
|
|
37
|
+
},
|
|
38
|
+
applyCharacterStyle: (id) => !!live()?.chain().focus().setCharacterStyle(id).run(),
|
|
39
|
+
destroy() {
|
|
40
|
+
unsubscribe();
|
|
41
|
+
store.destroy();
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Editor } from "@tiptap/core";
|
|
3
|
+
import { trackedChangeLabel } from "@pixerate/editor";
|
|
4
|
+
import { createTrackChanges, type SvelteTrackChanges } from "./review.svelte.js";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
editor?: Editor | null;
|
|
8
|
+
class?: string;
|
|
9
|
+
itemClass?: string;
|
|
10
|
+
activeItemClass?: string;
|
|
11
|
+
/** Text shown when there are no changes. */
|
|
12
|
+
emptyState?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
editor = null,
|
|
17
|
+
class: className = "flex flex-col gap-1 text-sm",
|
|
18
|
+
itemClass = "flex items-center gap-2 rounded px-2 py-1 hover:bg-muted/50",
|
|
19
|
+
activeItemClass = "bg-primary/10",
|
|
20
|
+
emptyState = "No tracked changes.",
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
const buttonClass =
|
|
24
|
+
"rounded px-1.5 py-0.5 text-xs text-foreground hover:bg-muted disabled:opacity-40";
|
|
25
|
+
|
|
26
|
+
let review = $state.raw<SvelteTrackChanges>(createTrackChanges(null));
|
|
27
|
+
|
|
28
|
+
$effect(() => {
|
|
29
|
+
const r = createTrackChanges(editor);
|
|
30
|
+
review = r;
|
|
31
|
+
return () => r.destroy();
|
|
32
|
+
});
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
{#if review.changes.length === 0}
|
|
36
|
+
<div class={className} data-tracked-changes-list="">
|
|
37
|
+
<div class="pixerate-changes-empty text-xs text-muted-foreground">{emptyState}</div>
|
|
38
|
+
</div>
|
|
39
|
+
{:else}
|
|
40
|
+
<ul class={className} role="list" aria-label="Tracked changes" data-tracked-changes-list="">
|
|
41
|
+
{#each review.changes as change (`${change.type}:${change.id}`)}
|
|
42
|
+
<li
|
|
43
|
+
class={change.id === review.currentChangeId ? `${itemClass} ${activeItemClass}` : itemClass}
|
|
44
|
+
data-change-type={change.type}
|
|
45
|
+
data-change-id={change.id}
|
|
46
|
+
>
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
class="min-w-0 flex-1 truncate text-left text-xs"
|
|
50
|
+
title={`${change.author.name}: ${change.description}`}
|
|
51
|
+
onclick={() => review.select(change.id)}
|
|
52
|
+
>
|
|
53
|
+
<span class="font-medium">{trackedChangeLabel(change)}</span>{change.author.name
|
|
54
|
+
? ` · ${change.author.name}`
|
|
55
|
+
: ""}
|
|
56
|
+
<span class="block truncate text-muted-foreground">{change.description}</span>
|
|
57
|
+
</button>
|
|
58
|
+
<button type="button" class={buttonClass} onclick={() => review.accept(change.id)}>
|
|
59
|
+
Accept
|
|
60
|
+
</button>
|
|
61
|
+
<button type="button" class={buttonClass} onclick={() => review.reject(change.id)}>
|
|
62
|
+
Reject
|
|
63
|
+
</button>
|
|
64
|
+
</li>
|
|
65
|
+
{/each}
|
|
66
|
+
</ul>
|
|
67
|
+
{/if}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Editor } from "@tiptap/core";
|
|
2
|
+
interface Props {
|
|
3
|
+
editor?: Editor | null;
|
|
4
|
+
class?: string;
|
|
5
|
+
itemClass?: string;
|
|
6
|
+
activeItemClass?: string;
|
|
7
|
+
/** Text shown when there are no changes. */
|
|
8
|
+
emptyState?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const TrackedChangesList: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type TrackedChangesList = ReturnType<typeof TrackedChangesList>;
|
|
12
|
+
export default TrackedChangesList;
|
|
13
|
+
//# sourceMappingURL=TrackedChangesList.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TrackedChangesList.svelte.d.ts","sourceRoot":"","sources":["../../src/review/TrackedChangesList.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAKzC,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsDH,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
|
package/dist/review/index.d.ts
CHANGED
|
@@ -2,6 +2,9 @@ import type { ComponentProps } from "svelte";
|
|
|
2
2
|
import type CommentsPanelComponent from "./CommentsPanel.svelte";
|
|
3
3
|
import type ReviewToolbarComponent from "./ReviewToolbar.svelte";
|
|
4
4
|
import type CommentButtonComponent from "./CommentButton.svelte";
|
|
5
|
+
import type TrackedChangesListComponent from "./TrackedChangesList.svelte";
|
|
6
|
+
export { default as TrackedChangesList } from "./TrackedChangesList.svelte";
|
|
7
|
+
export type TrackedChangesListProps = ComponentProps<typeof TrackedChangesListComponent>;
|
|
5
8
|
export { default as CommentsPanel } from "./CommentsPanel.svelte";
|
|
6
9
|
export { default as ReviewToolbar } from "./ReviewToolbar.svelte";
|
|
7
10
|
export { default as CommentButton } from "./CommentButton.svelte";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,sBAAsB,MAAM,wBAAwB,CAAC;AACjE,OAAO,KAAK,2BAA2B,MAAM,6BAA6B,CAAC;AAE3E,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,OAAO,2BAA2B,CAAC,CAAC;AACzF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,cAAc,oBAAoB,CAAC;AACnC,cAAc,6BAA6B,CAAC;AAE5C,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC/E,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
package/dist/review/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { default as TrackedChangesList } from "./TrackedChangesList.svelte";
|
|
1
2
|
export { default as CommentsPanel } from "./CommentsPanel.svelte";
|
|
2
3
|
export { default as ReviewToolbar } from "./ReviewToolbar.svelte";
|
|
3
4
|
export { default as CommentButton } from "./CommentButton.svelte";
|
|
@@ -29,6 +29,12 @@ export interface SvelteTrackChanges extends TrackChangesSnapshot {
|
|
|
29
29
|
rejectAll(): void;
|
|
30
30
|
next(): void;
|
|
31
31
|
previous(): void;
|
|
32
|
+
/** Selects a change in the editor. */
|
|
33
|
+
select(id: string): void;
|
|
34
|
+
/** Accepts a tracked move (both ends). */
|
|
35
|
+
acceptMove(id: string): void;
|
|
36
|
+
/** Rejects a tracked move (both ends). */
|
|
37
|
+
rejectMove(id: string): void;
|
|
32
38
|
subscribe(run: (value: TrackChangesSnapshot) => void): () => void;
|
|
33
39
|
destroy(): void;
|
|
34
40
|
}
|