@pixerate/editor-svelte 0.22.0 → 0.23.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 +4 -0
- package/dist/MergePreview.svelte +201 -0
- package/dist/MergePreview.svelte.d.ts +25 -0
- package/dist/MergePreview.svelte.d.ts.map +1 -0
- package/dist/TemplateRenderer.svelte +4 -10
- package/dist/TemplateRenderer.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasArrange.svelte.d.ts.map +1 -1
- package/dist/canvas/createCanvasAutoLayout.svelte.d.ts +68 -0
- package/dist/canvas/createCanvasAutoLayout.svelte.d.ts.map +1 -0
- package/dist/canvas/createCanvasAutoLayout.svelte.js +78 -0
- package/dist/canvas/index.d.ts +2 -0
- package/dist/canvas/index.d.ts.map +1 -1
- package/dist/canvas/index.js +3 -0
- package/dist/find-replace/FindReplaceBar.svelte +203 -0
- package/dist/find-replace/FindReplaceBar.svelte.d.ts +15 -0
- package/dist/find-replace/FindReplaceBar.svelte.d.ts.map +1 -0
- package/dist/find-replace/findReplace.svelte.d.ts +27 -0
- package/dist/find-replace/findReplace.svelte.d.ts.map +1 -0
- package/dist/find-replace/findReplace.svelte.js +79 -0
- package/dist/find-replace/index.d.ts +6 -0
- package/dist/find-replace/index.d.ts.map +1 -0
- package/dist/find-replace/index.js +2 -0
- package/dist/generation/GenerationSettings.svelte +174 -0
- package/dist/generation/GenerationSettings.svelte.d.ts +23 -0
- package/dist/generation/GenerationSettings.svelte.d.ts.map +1 -0
- package/dist/generation/JobProgress.svelte +53 -0
- package/dist/generation/JobProgress.svelte.d.ts +17 -0
- package/dist/generation/JobProgress.svelte.d.ts.map +1 -0
- package/dist/generation/index.d.ts +10 -0
- package/dist/generation/index.d.ts.map +1 -0
- package/dist/generation/index.js +4 -0
- package/dist/generation/plan.svelte.d.ts +16 -0
- package/dist/generation/plan.svelte.d.ts.map +1 -0
- package/dist/generation/plan.svelte.js +26 -0
- package/dist/generation/progress.svelte.d.ts +25 -0
- package/dist/generation/progress.svelte.d.ts.map +1 -0
- package/dist/generation/progress.svelte.js +36 -0
- package/dist/image-editor/AdjustmentLayersPanel.svelte +309 -0
- package/dist/image-editor/AdjustmentLayersPanel.svelte.d.ts +11 -0
- package/dist/image-editor/AdjustmentLayersPanel.svelte.d.ts.map +1 -0
- package/dist/image-editor/ControlSlider.svelte +39 -0
- package/dist/image-editor/ControlSlider.svelte.d.ts +13 -0
- package/dist/image-editor/ControlSlider.svelte.d.ts.map +1 -0
- package/dist/image-editor/CurvesEditor.svelte +105 -0
- package/dist/image-editor/CurvesEditor.svelte.d.ts +13 -0
- package/dist/image-editor/CurvesEditor.svelte.d.ts.map +1 -0
- package/dist/image-editor/Histogram.svelte +49 -0
- package/dist/image-editor/Histogram.svelte.d.ts +12 -0
- package/dist/image-editor/Histogram.svelte.d.ts.map +1 -0
- package/dist/image-editor/ImageEditor.svelte +32 -140
- package/dist/image-editor/ImageEditor.svelte.d.ts.map +1 -1
- package/dist/image-editor/imageEditorState.svelte.d.ts +14 -1
- package/dist/image-editor/imageEditorState.svelte.d.ts.map +1 -1
- package/dist/image-editor/imageEditorState.svelte.js +40 -0
- package/dist/image-editor/index.d.ts +12 -0
- package/dist/image-editor/index.d.ts.map +1 -1
- package/dist/image-editor/index.js +4 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/merge.svelte.d.ts +51 -0
- package/dist/merge.svelte.d.ts.map +1 -0
- package/dist/merge.svelte.js +117 -0
- package/dist/persistence/RecoveryPrompt.svelte +57 -0
- package/dist/persistence/RecoveryPrompt.svelte.d.ts +18 -0
- package/dist/persistence/RecoveryPrompt.svelte.d.ts.map +1 -0
- package/dist/persistence/autosave.svelte.d.ts +63 -0
- package/dist/persistence/autosave.svelte.d.ts.map +1 -0
- package/dist/persistence/autosave.svelte.js +110 -0
- package/dist/persistence/index.d.ts +6 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +2 -0
- package/dist/review/documentCompare.svelte.d.ts +21 -0
- package/dist/review/documentCompare.svelte.d.ts.map +1 -0
- package/dist/review/documentCompare.svelte.js +23 -0
- package/dist/review/index.d.ts +1 -0
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +1 -0
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte +6 -3
- package/dist/spreadsheet/SpreadsheetContextMenu.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/SpreadsheetEditor.svelte +6 -2
- package/dist/spreadsheet/SpreadsheetEditor.svelte.d.ts.map +1 -1
- package/dist/spreadsheet/spreadsheet.svelte.d.ts +2 -0
- package/dist/spreadsheet/spreadsheet.svelte.d.ts.map +1 -1
- package/package.json +18 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Histogram.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/Histogram.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAIlE,UAAU,KAAK;IACb,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,gGAAgG;IAChG,OAAO,CAAC,EAAE,KAAK,GAAG,WAAW,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsCH,QAAA,MAAM,SAAS,2CAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -18,7 +18,12 @@
|
|
|
18
18
|
hitTestAnnotation,
|
|
19
19
|
normalizeProcessVersion,
|
|
20
20
|
LATEST_PROCESS_VERSION,
|
|
21
|
+
IMAGE_ADJUSTMENT_CONTROLS,
|
|
22
|
+
readAdjustmentControls,
|
|
21
23
|
} from '@pixerate/editor/image-editor';
|
|
24
|
+
import ControlSlider from './ControlSlider.svelte';
|
|
25
|
+
import Histogram from './Histogram.svelte';
|
|
26
|
+
import AdjustmentLayersPanel from './AdjustmentLayersPanel.svelte';
|
|
22
27
|
import { onDestroy, untrack } from 'svelte';
|
|
23
28
|
import { createReactiveImageEditor, type ReactiveImageEditor } from './imageEditorState.svelte.js';
|
|
24
29
|
|
|
@@ -886,150 +891,37 @@
|
|
|
886
891
|
</button>
|
|
887
892
|
</div>
|
|
888
893
|
|
|
889
|
-
|
|
890
|
-
<div>
|
|
891
|
-
<div class="flex justify-between text-slate-400 mb-1">
|
|
892
|
-
<span>Brightness</span>
|
|
893
|
-
<span class="font-mono">{editor.state.adjustments.brightness}</span>
|
|
894
|
-
</div>
|
|
895
|
-
<input
|
|
896
|
-
type="range"
|
|
897
|
-
min="-100"
|
|
898
|
-
max="100"
|
|
899
|
-
value={editor.state.adjustments.brightness}
|
|
900
|
-
oninput={(e) => editor.setAdjustments({ brightness: Number((e.target as HTMLInputElement).value) })}
|
|
901
|
-
class="w-full accent-indigo-500"
|
|
902
|
-
/>
|
|
903
|
-
</div>
|
|
904
|
-
|
|
905
|
-
<!-- Contrast -->
|
|
906
|
-
<div>
|
|
907
|
-
<div class="flex justify-between text-slate-400 mb-1">
|
|
908
|
-
<span>Contrast</span>
|
|
909
|
-
<span class="font-mono">{editor.state.adjustments.contrast}</span>
|
|
910
|
-
</div>
|
|
911
|
-
<input
|
|
912
|
-
type="range"
|
|
913
|
-
min="-100"
|
|
914
|
-
max="100"
|
|
915
|
-
value={editor.state.adjustments.contrast}
|
|
916
|
-
oninput={(e) => editor.setAdjustments({ contrast: Number((e.target as HTMLInputElement).value) })}
|
|
917
|
-
class="w-full accent-indigo-500"
|
|
918
|
-
/>
|
|
919
|
-
</div>
|
|
920
|
-
|
|
921
|
-
<!-- Saturation -->
|
|
922
|
-
<div>
|
|
923
|
-
<div class="flex justify-between text-slate-400 mb-1">
|
|
924
|
-
<span>Saturation</span>
|
|
925
|
-
<span class="font-mono">{editor.state.adjustments.saturation}</span>
|
|
926
|
-
</div>
|
|
927
|
-
<input
|
|
928
|
-
type="range"
|
|
929
|
-
min="-100"
|
|
930
|
-
max="100"
|
|
931
|
-
value={editor.state.adjustments.saturation}
|
|
932
|
-
oninput={(e) => editor.setAdjustments({ saturation: Number((e.target as HTMLInputElement).value) })}
|
|
933
|
-
class="w-full accent-indigo-500"
|
|
934
|
-
/>
|
|
935
|
-
</div>
|
|
936
|
-
|
|
937
|
-
<!-- Exposure -->
|
|
938
|
-
<div>
|
|
939
|
-
<div class="flex justify-between text-slate-400 mb-1">
|
|
940
|
-
<span>Exposure</span>
|
|
941
|
-
<span class="font-mono">{editor.state.adjustments.exposure}</span>
|
|
942
|
-
</div>
|
|
943
|
-
<input
|
|
944
|
-
type="range"
|
|
945
|
-
min="-100"
|
|
946
|
-
max="100"
|
|
947
|
-
value={editor.state.adjustments.exposure}
|
|
948
|
-
oninput={(e) => editor.setAdjustments({ exposure: Number((e.target as HTMLInputElement).value) })}
|
|
949
|
-
class="w-full accent-indigo-500"
|
|
950
|
-
/>
|
|
951
|
-
</div>
|
|
894
|
+
<Histogram histogram={editor.histogram} />
|
|
952
895
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
<input
|
|
960
|
-
type="range"
|
|
961
|
-
min="-100"
|
|
962
|
-
max="100"
|
|
963
|
-
value={editor.state.adjustments.temperature}
|
|
964
|
-
oninput={(e) => editor.setAdjustments({ temperature: Number((e.target as HTMLInputElement).value) })}
|
|
965
|
-
class="w-full accent-indigo-500"
|
|
896
|
+
{#each IMAGE_ADJUSTMENT_CONTROLS as spec (spec.id)}
|
|
897
|
+
<ControlSlider
|
|
898
|
+
{spec}
|
|
899
|
+
value={readAdjustmentControls(editor.state.adjustments)[spec.id]}
|
|
900
|
+
disabled={spec.requiresProcess !== undefined && legacyProcess}
|
|
901
|
+
onchange={(v) => editor.setAdjustments({ [spec.id]: v })}
|
|
966
902
|
/>
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
<div class="flex justify-between text-slate-400 mb-1">
|
|
972
|
-
<span>Tint</span>
|
|
973
|
-
<span class="font-mono">{editor.state.adjustments.tint ?? 0}</span>
|
|
974
|
-
</div>
|
|
975
|
-
<input
|
|
976
|
-
type="range"
|
|
977
|
-
min="-100"
|
|
978
|
-
max="100"
|
|
979
|
-
aria-label="Tint"
|
|
980
|
-
disabled={legacyProcess}
|
|
981
|
-
value={editor.state.adjustments.tint ?? 0}
|
|
982
|
-
oninput={(e) => editor.setAdjustments({ tint: Number((e.target as HTMLInputElement).value) })}
|
|
983
|
-
class="w-full accent-indigo-500 disabled:opacity-40"
|
|
984
|
-
/>
|
|
985
|
-
</div>
|
|
986
|
-
|
|
987
|
-
{#if legacyProcess}
|
|
988
|
-
<div
|
|
989
|
-
class="flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200"
|
|
990
|
-
data-testid="image-editor-process-notice"
|
|
991
|
-
>
|
|
992
|
-
<span>Legacy rendering (process 1). Tint needs the current process.</span>
|
|
993
|
-
<button
|
|
994
|
-
type="button"
|
|
995
|
-
onclick={() => editor.upgradeProcess()}
|
|
996
|
-
class="shrink-0 rounded bg-amber-500/20 px-2 py-0.5 hover:bg-amber-500/30"
|
|
903
|
+
{#if spec.id === 'tint' && legacyProcess}
|
|
904
|
+
<div
|
|
905
|
+
class="flex items-center justify-between gap-2 rounded border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-[10px] text-amber-200"
|
|
906
|
+
data-testid="image-editor-process-notice"
|
|
997
907
|
>
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
<input
|
|
1010
|
-
type="range"
|
|
1011
|
-
min="0"
|
|
1012
|
-
max="30"
|
|
1013
|
-
value={editor.state.adjustments.blur}
|
|
1014
|
-
oninput={(e) => editor.setAdjustments({ blur: Number((e.target as HTMLInputElement).value) })}
|
|
1015
|
-
class="w-full accent-indigo-500"
|
|
1016
|
-
/>
|
|
1017
|
-
</div>
|
|
908
|
+
<span>Legacy rendering (process 1). Tint needs the current process.</span>
|
|
909
|
+
<button
|
|
910
|
+
type="button"
|
|
911
|
+
onclick={() => editor.upgradeProcess()}
|
|
912
|
+
class="shrink-0 rounded bg-amber-500/20 px-2 py-0.5 hover:bg-amber-500/30"
|
|
913
|
+
>
|
|
914
|
+
Update
|
|
915
|
+
</button>
|
|
916
|
+
</div>
|
|
917
|
+
{/if}
|
|
918
|
+
{/each}
|
|
1018
919
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
</div>
|
|
1025
|
-
<input
|
|
1026
|
-
type="range"
|
|
1027
|
-
min="0"
|
|
1028
|
-
max="1"
|
|
1029
|
-
step="0.05"
|
|
1030
|
-
value={editor.state.adjustments.opacity}
|
|
1031
|
-
oninput={(e) => editor.setAdjustments({ opacity: Number((e.target as HTMLInputElement).value) })}
|
|
1032
|
-
class="w-full accent-indigo-500"
|
|
920
|
+
<div class="border-t border-slate-700/60 pt-3">
|
|
921
|
+
<AdjustmentLayersPanel
|
|
922
|
+
controller={editor.controller}
|
|
923
|
+
layers={editor.state.adjustments.layers}
|
|
924
|
+
histogram={editor.histogram}
|
|
1033
925
|
/>
|
|
1034
926
|
</div>
|
|
1035
927
|
</div>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/ImageEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAIR,aAAa,EAGb,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"ImageEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/ImageEditor.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAIR,aAAa,EAGb,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EACnB,MAAM,+BAA+B,CAAC;AAgBzC,OAAO,EAA6B,KAAK,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGjG,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,OAAO,CAAC,EAAE,kBAAkB,CAAC;CAC9B;AAw/BH,QAAA,MAAM,WAAW,2CAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { ImageEditorController, type ImageEditorOptions, type ImageEditorState, type ImageEditorTool, type CropBox, type AspectRatio, type ImageAdjustments, type DepthMaskOptions, type Annotation, type CreateAnnotationPayload, type ExportOptions, type SerializedImageEditorState, type ImagePoint } from '@pixerate/editor/image-editor';
|
|
1
|
+
import { ImageEditorController, type ImageEditorOptions, type ImageEditorState, type ImageEditorTool, type CropBox, type AspectRatio, type ImageAdjustments, type DepthMaskOptions, type Annotation, type CreateAnnotationPayload, type ExportOptions, type SerializedImageEditorState, type ImagePoint, type AdjustmentKind, type AdjustmentLayerInit, type AdjustmentLayerUpdate, type ImageHistogram } from '@pixerate/editor/image-editor';
|
|
2
2
|
export declare function createReactiveImageEditor(options?: ImageEditorOptions): {
|
|
3
3
|
readonly controller: ImageEditorController;
|
|
4
4
|
readonly state: ImageEditorState;
|
|
5
5
|
readonly canUndo: boolean;
|
|
6
|
+
/** Histogram of the last rendered preview (after adjustments and layers); null before a render. */
|
|
7
|
+
readonly histogram: ImageHistogram | null;
|
|
6
8
|
readonly canRedo: boolean;
|
|
7
9
|
setTool(tool: ImageEditorTool): void;
|
|
8
10
|
setCrop(crop: CropBox | null, addToHistory?: boolean): void;
|
|
@@ -16,6 +18,12 @@ export declare function createReactiveImageEditor(options?: ImageEditorOptions):
|
|
|
16
18
|
resetAdjustments(): void;
|
|
17
19
|
/** Update to Current Process: re-render the adjustments with the latest process (one undo step). */
|
|
18
20
|
upgradeProcess(): boolean;
|
|
21
|
+
/** Adds an adjustment layer (one undo step) and returns its id. */
|
|
22
|
+
addAdjustmentLayer(init: AdjustmentKind | AdjustmentLayerInit, index?: number): string;
|
|
23
|
+
updateAdjustmentLayer(id: string, update: AdjustmentLayerUpdate, commitToHistory?: boolean): boolean;
|
|
24
|
+
removeAdjustmentLayer(id: string): boolean;
|
|
25
|
+
moveAdjustmentLayer(id: string, toIndex: number): boolean;
|
|
26
|
+
toggleAdjustmentLayer(id: string, enabled?: boolean): boolean;
|
|
19
27
|
setDepthMask(partial: Partial<DepthMaskOptions>): void;
|
|
20
28
|
resetDepthMask(): void;
|
|
21
29
|
addAnnotation(ann: CreateAnnotationPayload): string;
|
|
@@ -52,4 +60,9 @@ export declare function createReactiveImageEditor(options?: ImageEditorOptions):
|
|
|
52
60
|
destroy(): void;
|
|
53
61
|
};
|
|
54
62
|
export type ReactiveImageEditor = ReturnType<typeof createReactiveImageEditor>;
|
|
63
|
+
/** The preview histogram of an image editor controller as a rune (`current`), updated after every render. */
|
|
64
|
+
export declare function createImageHistogram(controller: ImageEditorController): {
|
|
65
|
+
readonly current: ImageHistogram | null;
|
|
66
|
+
destroy(): void;
|
|
67
|
+
};
|
|
55
68
|
//# sourceMappingURL=imageEditorState.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageEditorState.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/imageEditorState.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"imageEditorState.svelte.d.ts","sourceRoot":"","sources":["../../src/image-editor/imageEditorState.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAEvC,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,kBAAuB;;;;IA2BtE,mGAAmG;;;kBAQrF,eAAe;kBAGf,OAAO,GAAG,IAAI;2BAGL,WAAW;;oBAMlB,MAAM;yBAGD,MAAM;;;4BASH,OAAO,CAAC,gBAAgB,CAAC;;IAMjD,oGAAoG;;IAIpG,mEAAmE;6BAC1C,cAAc,GAAG,mBAAmB,UAAU,MAAM;8BAGnD,MAAM,UAAU,qBAAqB;8BAGrC,MAAM;4BAGR,MAAM,WAAW,MAAM;8BAGrB,MAAM,YAAY,OAAO;0BAG7B,OAAO,CAAC,gBAAgB,CAAC;;uBAM5B,uBAAuB;yBAGrB,MAAM,WAAW,OAAO,CAAC,UAAU,CAAC;yBAGpC,MAAM;;yBAMN,MAAM,GAAG,IAAI;;;;oBAYlB,MAAM;qBAGL,MAAM;;kBAMT,MAAM;gBAGR,UAAU;4BAGE,OAAO;mBAGhB,MAAM,GAAG,gBAAgB;qBAGvB,aAAa;kBAGhB,aAAa;;mBAMZ,0BAA0B;sBAGvB;QAAE,cAAc,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;yBAG5C;QAAE,cAAc,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;2BAG7C,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,SAAS,CAAC;oCAGhC,MAAM;4CAGE,MAAM;IAG9C,8EAA8E;;EAMjF;AAED,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE/E,6GAA6G;AAC7G,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,qBAAqB;;;EAarE"}
|
|
@@ -3,10 +3,14 @@ export function createReactiveImageEditor(options = {}) {
|
|
|
3
3
|
const controller = new ImageEditorController(options);
|
|
4
4
|
let state = $state(controller.getState());
|
|
5
5
|
let historyTicks = $state(0);
|
|
6
|
+
let histogram = $state.raw(controller.getHistogram());
|
|
6
7
|
const unsubscribe = controller.subscribe((updated) => {
|
|
7
8
|
state = { ...updated };
|
|
8
9
|
historyTicks++;
|
|
9
10
|
});
|
|
11
|
+
const unsubscribeHistogram = controller.subscribeHistogram((h) => {
|
|
12
|
+
histogram = h;
|
|
13
|
+
});
|
|
10
14
|
return {
|
|
11
15
|
get controller() {
|
|
12
16
|
return controller;
|
|
@@ -19,6 +23,10 @@ export function createReactiveImageEditor(options = {}) {
|
|
|
19
23
|
void historyTicks;
|
|
20
24
|
return controller.canUndo;
|
|
21
25
|
},
|
|
26
|
+
/** Histogram of the last rendered preview (after adjustments and layers); null before a render. */
|
|
27
|
+
get histogram() {
|
|
28
|
+
return histogram;
|
|
29
|
+
},
|
|
22
30
|
get canRedo() {
|
|
23
31
|
void historyTicks;
|
|
24
32
|
return controller.canRedo;
|
|
@@ -57,6 +65,22 @@ export function createReactiveImageEditor(options = {}) {
|
|
|
57
65
|
upgradeProcess() {
|
|
58
66
|
return controller.upgradeProcess();
|
|
59
67
|
},
|
|
68
|
+
/** Adds an adjustment layer (one undo step) and returns its id. */
|
|
69
|
+
addAdjustmentLayer(init, index) {
|
|
70
|
+
return controller.addAdjustmentLayer(init, index);
|
|
71
|
+
},
|
|
72
|
+
updateAdjustmentLayer(id, update, commitToHistory = true) {
|
|
73
|
+
return controller.updateAdjustmentLayer(id, update, commitToHistory);
|
|
74
|
+
},
|
|
75
|
+
removeAdjustmentLayer(id) {
|
|
76
|
+
return controller.removeAdjustmentLayer(id);
|
|
77
|
+
},
|
|
78
|
+
moveAdjustmentLayer(id, toIndex) {
|
|
79
|
+
return controller.moveAdjustmentLayer(id, toIndex);
|
|
80
|
+
},
|
|
81
|
+
toggleAdjustmentLayer(id, enabled) {
|
|
82
|
+
return controller.toggleAdjustmentLayer(id, enabled);
|
|
83
|
+
},
|
|
60
84
|
setDepthMask(partial) {
|
|
61
85
|
controller.setDepthMask(partial);
|
|
62
86
|
},
|
|
@@ -136,6 +160,22 @@ export function createReactiveImageEditor(options = {}) {
|
|
|
136
160
|
return controller.applyBackgroundRemovedImage(newDataUrl);
|
|
137
161
|
},
|
|
138
162
|
/** Stops syncing controller state; call when the editor is no longer used. */
|
|
163
|
+
destroy() {
|
|
164
|
+
unsubscribe();
|
|
165
|
+
unsubscribeHistogram();
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/** The preview histogram of an image editor controller as a rune (`current`), updated after every render. */
|
|
170
|
+
export function createImageHistogram(controller) {
|
|
171
|
+
let current = $state.raw(controller.getHistogram());
|
|
172
|
+
const unsubscribe = controller.subscribeHistogram((h) => {
|
|
173
|
+
current = h;
|
|
174
|
+
});
|
|
175
|
+
return {
|
|
176
|
+
get current() {
|
|
177
|
+
return current;
|
|
178
|
+
},
|
|
139
179
|
destroy() {
|
|
140
180
|
unsubscribe();
|
|
141
181
|
},
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { ComponentProps } from "svelte";
|
|
2
2
|
import type ImageEditorComponent from "./ImageEditor.svelte";
|
|
3
|
+
import type HistogramComponent from "./Histogram.svelte";
|
|
4
|
+
import type AdjustmentLayersPanelComponent from "./AdjustmentLayersPanel.svelte";
|
|
5
|
+
import type CurvesEditorComponent from "./CurvesEditor.svelte";
|
|
6
|
+
import type ControlSliderComponent from "./ControlSlider.svelte";
|
|
3
7
|
export { default as ImageEditor } from './ImageEditor.svelte';
|
|
8
|
+
export { default as Histogram } from './Histogram.svelte';
|
|
9
|
+
export { default as AdjustmentLayersPanel } from './AdjustmentLayersPanel.svelte';
|
|
10
|
+
export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
11
|
+
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
4
12
|
export * from './imageEditorState.svelte.js';
|
|
5
13
|
export type ImageEditorProps = ComponentProps<typeof ImageEditorComponent>;
|
|
14
|
+
export type HistogramProps = ComponentProps<typeof HistogramComponent>;
|
|
15
|
+
export type AdjustmentLayersPanelProps = ComponentProps<typeof AdjustmentLayersPanelComponent>;
|
|
16
|
+
export type CurvesEditorProps = ComponentProps<typeof CurvesEditorComponent>;
|
|
17
|
+
export type ControlSliderProps = ComponentProps<typeof ControlSliderComponent>;
|
|
6
18
|
//# 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;
|
|
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;AAEjE,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,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"}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
export { default as ImageEditor } from './ImageEditor.svelte';
|
|
2
|
+
export { default as Histogram } from './Histogram.svelte';
|
|
3
|
+
export { default as AdjustmentLayersPanel } from './AdjustmentLayersPanel.svelte';
|
|
4
|
+
export { default as CurvesEditor } from './CurvesEditor.svelte';
|
|
5
|
+
export { default as ControlSlider } from './ControlSlider.svelte';
|
|
2
6
|
export * from './imageEditorState.svelte.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type BubbleMenuComponent from "./BubbleMenu.svelte";
|
|
|
4
4
|
import type TemplateRendererComponent from "./TemplateRenderer.svelte";
|
|
5
5
|
import type VariableFormComponent from "./VariableForm.svelte";
|
|
6
6
|
import type OutlinePanelComponent from "./OutlinePanel.svelte";
|
|
7
|
+
import type MergePreviewComponent from "./MergePreview.svelte";
|
|
7
8
|
export * from "./editor.svelte.js";
|
|
8
9
|
export * from "./navigationGuard.js";
|
|
9
10
|
export * from "./createNavigationGuard.svelte.js";
|
|
@@ -11,6 +12,7 @@ export * from "./history/index.js";
|
|
|
11
12
|
export * from "./fileImport.svelte.js";
|
|
12
13
|
export * from "./agentTools.svelte.js";
|
|
13
14
|
export * from "./outline.svelte.js";
|
|
15
|
+
export * from "./merge.svelte.js";
|
|
14
16
|
export { DirtyTracker, createDirtyTracker, defaultIsEqual, HistoryManager, createHistoryManager, bindDirtyToHistory, withoutDirty, } from "@pixerate/editor";
|
|
15
17
|
export type { DirtyTrackerOptions, Command, HistoryState, HistoryManagerOptions, HistoryEntry, HistoryMark, MergedExecutionOptions, HistoryDirtyBinding, BindDirtyToHistoryOptions, } from "@pixerate/editor";
|
|
16
18
|
export type EditableTextNodeEditorProps = ComponentProps<typeof EditableTextNodeEditorComponent>;
|
|
@@ -21,12 +23,17 @@ export { default as EditableTextNodeEditor } from "./EditableTextNodeEditor.svel
|
|
|
21
23
|
export { default as BubbleMenu } from "./BubbleMenu.svelte";
|
|
22
24
|
export { default as TemplateRenderer } from "./TemplateRenderer.svelte";
|
|
23
25
|
export { default as VariableForm } from "./VariableForm.svelte";
|
|
26
|
+
export type MergePreviewProps = ComponentProps<typeof MergePreviewComponent>;
|
|
27
|
+
export { default as MergePreview } from "./MergePreview.svelte";
|
|
24
28
|
export type OutlinePanelProps = ComponentProps<typeof OutlinePanelComponent>;
|
|
25
29
|
export { default as OutlinePanel } from "./OutlinePanel.svelte";
|
|
26
30
|
export type { Template, TemplateVersion, Token, TokenType, ColorGradient, RichTextPresetOptions, ImageOptions, } from "@pixerate/editor";
|
|
27
|
-
export type { PromptValues, PromptDiagnostic, VariableFormField, } from "@pixerate/editor";
|
|
31
|
+
export type { PromptValues, PromptDiagnostic, VariableFormField, MergeDataSource, MergeRecord, MergeRecordsResult, MergeOutput, } from "@pixerate/editor";
|
|
28
32
|
export * from "./spreadsheet/index.js";
|
|
29
33
|
export * from "./image-editor/index.js";
|
|
30
34
|
export * from "./review/index.js";
|
|
31
35
|
export * from "./commands/index.js";
|
|
36
|
+
export * from "./persistence/index.js";
|
|
37
|
+
export * from "./generation/index.js";
|
|
38
|
+
export * from "./find-replace/index.js";
|
|
32
39
|
//# sourceMappingURL=index.d.ts.map
|
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;AAE/D,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;
|
|
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;AAE/D,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;AAEhE,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
|
@@ -5,13 +5,18 @@ export * from "./history/index.js";
|
|
|
5
5
|
export * from "./fileImport.svelte.js";
|
|
6
6
|
export * from "./agentTools.svelte.js";
|
|
7
7
|
export * from "./outline.svelte.js";
|
|
8
|
+
export * from "./merge.svelte.js";
|
|
8
9
|
export { DirtyTracker, createDirtyTracker, defaultIsEqual, HistoryManager, createHistoryManager, bindDirtyToHistory, withoutDirty, } from "@pixerate/editor";
|
|
9
10
|
export { default as EditableTextNodeEditor } from "./EditableTextNodeEditor.svelte";
|
|
10
11
|
export { default as BubbleMenu } from "./BubbleMenu.svelte";
|
|
11
12
|
export { default as TemplateRenderer } from "./TemplateRenderer.svelte";
|
|
12
13
|
export { default as VariableForm } from "./VariableForm.svelte";
|
|
14
|
+
export { default as MergePreview } from "./MergePreview.svelte";
|
|
13
15
|
export { default as OutlinePanel } from "./OutlinePanel.svelte";
|
|
14
16
|
export * from "./spreadsheet/index.js";
|
|
15
17
|
export * from "./image-editor/index.js";
|
|
16
18
|
export * from "./review/index.js";
|
|
17
19
|
export * from "./commands/index.js";
|
|
20
|
+
export * from "./persistence/index.js";
|
|
21
|
+
export * from "./generation/index.js";
|
|
22
|
+
export * from "./find-replace/index.js";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type MergeRecordsOptions, type MergeRecordsResult, type ParseDataSourceOptions, type Template } from "@pixerate/editor";
|
|
2
|
+
export interface MergePreviewOptions {
|
|
3
|
+
/** The prompt merged with each record. */
|
|
4
|
+
template: string;
|
|
5
|
+
templates?: Template[];
|
|
6
|
+
bindings?: Record<string, string>;
|
|
7
|
+
/** How to read the data source text. */
|
|
8
|
+
parseOptions?: ParseDataSourceOptions;
|
|
9
|
+
/** Passed to `mergeRecords` by `merge()`. */
|
|
10
|
+
skipIf?: MergeRecordsOptions["skipIf"];
|
|
11
|
+
separator?: string;
|
|
12
|
+
maxOutputs?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Reactive mail-merge preview state for Svelte 5 (the counterpart of React's
|
|
16
|
+
* `useMergePreview`): parses a pasted or loaded data source, matches its
|
|
17
|
+
* fields to the template's variables (editable), steps through records and
|
|
18
|
+
* merges them all with `mergeRecords`.
|
|
19
|
+
*
|
|
20
|
+
* `getOptions` is read reactively, so pass `() => ({ template, templates })`
|
|
21
|
+
* built from props or state.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createMergePreview(getOptions: () => MergePreviewOptions, initialSource?: string): {
|
|
24
|
+
sourceText: string;
|
|
25
|
+
setSourceText: (text: string) => void;
|
|
26
|
+
/** Reads a picked file (CSV, TSV or JSON) into `sourceText`. */
|
|
27
|
+
loadFile(file: Blob): Promise<void>;
|
|
28
|
+
readonly source: import("@pixerate/editor").MergeDataSource;
|
|
29
|
+
/** Variable names the template uses, in order. */
|
|
30
|
+
readonly variables: string[];
|
|
31
|
+
/** Variable → field: automatic matches with the user's overrides applied. */
|
|
32
|
+
readonly mapping: Record<string, string | null>;
|
|
33
|
+
setFieldMapping(variable: string, field: string | null): void;
|
|
34
|
+
resetMapping(): void;
|
|
35
|
+
/** 0-based index of the previewed record. */
|
|
36
|
+
readonly index: number;
|
|
37
|
+
readonly count: number;
|
|
38
|
+
setIndex: (next: number) => void;
|
|
39
|
+
next(): void;
|
|
40
|
+
prev(): void;
|
|
41
|
+
readonly record: import("@pixerate/editor").MergeRecord;
|
|
42
|
+
/** Prompt values for the previewed record. */
|
|
43
|
+
readonly values: import("@pixerate/editor").PromptValues;
|
|
44
|
+
/** Merges every record with the current mapping and stores the result. */
|
|
45
|
+
merge(): MergeRecordsResult;
|
|
46
|
+
readonly result: MergeRecordsResult | null;
|
|
47
|
+
/** The last merge's outputs as text or JSON. */
|
|
48
|
+
serialize(format: "text" | "json"): string;
|
|
49
|
+
};
|
|
50
|
+
export type MergePreviewState = ReturnType<typeof createMergePreview>;
|
|
51
|
+
//# sourceMappingURL=merge.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.svelte.d.ts","sourceRoot":"","sources":["../src/merge.svelte.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,wCAAwC;IACxC,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,6CAA6C;IAC7C,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,mBAAmB,EACrC,aAAa,SAAK;gBA4CK,MAAM;0BAbA,MAAM;IAiBjC,gEAAgE;mBAC3C,IAAI;;IAMzB,kDAAkD;;IAIlD,6EAA6E;;8BAInD,MAAM,SAAS,MAAM,GAAG,IAAI;;IAOtD,6CAA6C;;;qBAlCvB,MAAM;;;;IAmD5B,8CAA8C;;IAI9C,0EAA0E;aACjE,kBAAkB;;IAe3B,gDAAgD;sBAC9B,MAAM,GAAG,MAAM,GAAG,MAAM;EAI7C;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { extractVariables, matchFields, mergeRecords, parseDataSource, recordToValues, serializeMergeOutputs, } from "@pixerate/editor";
|
|
2
|
+
/**
|
|
3
|
+
* Reactive mail-merge preview state for Svelte 5 (the counterpart of React's
|
|
4
|
+
* `useMergePreview`): parses a pasted or loaded data source, matches its
|
|
5
|
+
* fields to the template's variables (editable), steps through records and
|
|
6
|
+
* merges them all with `mergeRecords`.
|
|
7
|
+
*
|
|
8
|
+
* `getOptions` is read reactively, so pass `() => ({ template, templates })`
|
|
9
|
+
* built from props or state.
|
|
10
|
+
*/
|
|
11
|
+
export function createMergePreview(getOptions, initialSource = "") {
|
|
12
|
+
let sourceText = $state(initialSource);
|
|
13
|
+
let overrides = $state.raw({});
|
|
14
|
+
let index = $state(0);
|
|
15
|
+
let result = $state.raw(null);
|
|
16
|
+
const options = $derived(getOptions());
|
|
17
|
+
const source = $derived(parseDataSource(sourceText, options.parseOptions));
|
|
18
|
+
const variables = $derived(extractVariables(options.template, {
|
|
19
|
+
templates: options.templates,
|
|
20
|
+
bindings: options.bindings,
|
|
21
|
+
}).map((v) => v.name));
|
|
22
|
+
const mapping = $derived.by(() => {
|
|
23
|
+
const merged = {
|
|
24
|
+
...matchFields(variables, source.fields).mapping,
|
|
25
|
+
};
|
|
26
|
+
for (const [variable, field] of Object.entries(overrides)) {
|
|
27
|
+
if (variables.includes(variable) && (field === null || source.fields.includes(field))) {
|
|
28
|
+
merged[variable] = field;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return merged;
|
|
32
|
+
});
|
|
33
|
+
const count = $derived(source.records.length);
|
|
34
|
+
const current = $derived(count === 0 ? 0 : Math.min(index, count - 1));
|
|
35
|
+
const record = $derived(source.records[current]);
|
|
36
|
+
const values = $derived(record ? recordToValues(record, mapping) : {});
|
|
37
|
+
function setSourceText(text) {
|
|
38
|
+
sourceText = text;
|
|
39
|
+
index = 0;
|
|
40
|
+
result = null;
|
|
41
|
+
}
|
|
42
|
+
function setIndex(next) {
|
|
43
|
+
index = Math.max(0, Math.min(next, count - 1));
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
get sourceText() {
|
|
47
|
+
return sourceText;
|
|
48
|
+
},
|
|
49
|
+
set sourceText(text) {
|
|
50
|
+
setSourceText(text);
|
|
51
|
+
},
|
|
52
|
+
setSourceText,
|
|
53
|
+
/** Reads a picked file (CSV, TSV or JSON) into `sourceText`. */
|
|
54
|
+
async loadFile(file) {
|
|
55
|
+
setSourceText(await file.text());
|
|
56
|
+
},
|
|
57
|
+
get source() {
|
|
58
|
+
return source;
|
|
59
|
+
},
|
|
60
|
+
/** Variable names the template uses, in order. */
|
|
61
|
+
get variables() {
|
|
62
|
+
return variables;
|
|
63
|
+
},
|
|
64
|
+
/** Variable → field: automatic matches with the user's overrides applied. */
|
|
65
|
+
get mapping() {
|
|
66
|
+
return mapping;
|
|
67
|
+
},
|
|
68
|
+
setFieldMapping(variable, field) {
|
|
69
|
+
overrides = { ...overrides, [variable]: field };
|
|
70
|
+
result = null;
|
|
71
|
+
},
|
|
72
|
+
resetMapping() {
|
|
73
|
+
overrides = {};
|
|
74
|
+
},
|
|
75
|
+
/** 0-based index of the previewed record. */
|
|
76
|
+
get index() {
|
|
77
|
+
return current;
|
|
78
|
+
},
|
|
79
|
+
get count() {
|
|
80
|
+
return count;
|
|
81
|
+
},
|
|
82
|
+
setIndex,
|
|
83
|
+
next() {
|
|
84
|
+
setIndex(current + 1);
|
|
85
|
+
},
|
|
86
|
+
prev() {
|
|
87
|
+
setIndex(current - 1);
|
|
88
|
+
},
|
|
89
|
+
get record() {
|
|
90
|
+
return record;
|
|
91
|
+
},
|
|
92
|
+
/** Prompt values for the previewed record. */
|
|
93
|
+
get values() {
|
|
94
|
+
return values;
|
|
95
|
+
},
|
|
96
|
+
/** Merges every record with the current mapping and stores the result. */
|
|
97
|
+
merge() {
|
|
98
|
+
const merged = mergeRecords(options.template, source, {
|
|
99
|
+
templates: options.templates,
|
|
100
|
+
bindings: options.bindings,
|
|
101
|
+
mapping,
|
|
102
|
+
skipIf: options.skipIf,
|
|
103
|
+
separator: options.separator,
|
|
104
|
+
maxOutputs: options.maxOutputs,
|
|
105
|
+
});
|
|
106
|
+
result = merged;
|
|
107
|
+
return merged;
|
|
108
|
+
},
|
|
109
|
+
get result() {
|
|
110
|
+
return result;
|
|
111
|
+
},
|
|
112
|
+
/** The last merge's outputs as text or JSON. */
|
|
113
|
+
serialize(format) {
|
|
114
|
+
return result ? serializeMergeOutputs(result.outputs, format, options.separator) : "";
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { formatRecoveryMessage, type RecoveryMeta } from '@pixerate/editor/persistence';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/** `createAutosave(...).recovery`; nothing renders while it is `null`. */
|
|
6
|
+
recovery: { meta: RecoveryMeta } | null;
|
|
7
|
+
onRestore: () => void;
|
|
8
|
+
onDiscard: () => void;
|
|
9
|
+
/** Formats the snapshot time (default `toLocaleString`). */
|
|
10
|
+
formatTime?: (time: number) => string;
|
|
11
|
+
restoreLabel?: string;
|
|
12
|
+
discardLabel?: string;
|
|
13
|
+
class?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
recovery,
|
|
18
|
+
onRestore,
|
|
19
|
+
onDiscard,
|
|
20
|
+
formatTime,
|
|
21
|
+
restoreLabel = 'Restore',
|
|
22
|
+
discardLabel = 'Discard',
|
|
23
|
+
class: className = ''
|
|
24
|
+
}: Props = $props();
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
{#if recovery}
|
|
28
|
+
<div
|
|
29
|
+
role="alertdialog"
|
|
30
|
+
aria-label="Unsaved changes found"
|
|
31
|
+
data-recovery-prompt=""
|
|
32
|
+
class="flex flex-wrap items-center gap-3 rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm {className}"
|
|
33
|
+
>
|
|
34
|
+
<span class="min-w-0 flex-1">
|
|
35
|
+
{formatRecoveryMessage(recovery.meta, formatTime)}
|
|
36
|
+
{#if recovery.meta.name}
|
|
37
|
+
<span class="ml-1 text-xs text-muted-foreground">({recovery.meta.name})</span>
|
|
38
|
+
{/if}
|
|
39
|
+
</span>
|
|
40
|
+
<button
|
|
41
|
+
type="button"
|
|
42
|
+
data-recovery-restore=""
|
|
43
|
+
onclick={onRestore}
|
|
44
|
+
class="rounded-md bg-primary px-3 py-1 text-xs font-medium text-primary-foreground hover:opacity-90"
|
|
45
|
+
>
|
|
46
|
+
{restoreLabel}
|
|
47
|
+
</button>
|
|
48
|
+
<button
|
|
49
|
+
type="button"
|
|
50
|
+
data-recovery-discard=""
|
|
51
|
+
onclick={onDiscard}
|
|
52
|
+
class="rounded-md border border-border px-3 py-1 text-xs font-medium hover:bg-muted"
|
|
53
|
+
>
|
|
54
|
+
{discardLabel}
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
{/if}
|