@bendyline/squisq-editor-react 2.2.0 → 2.3.1

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.
@@ -0,0 +1,223 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ContentContainer } from '@bendyline/squisq/storage';
3
+ import { ImageEditExportFormat, ImageEditVersionManager } from '@bendyline/squisq/imageEdit';
4
+ import { Theme, SurfaceScheme, ImageEditDoc, ImageEditLayer } from '@bendyline/squisq/schemas';
5
+ import { ResourcePolicy } from '@bendyline/squisq/markdown';
6
+
7
+ /**
8
+ * ImageViewer
9
+ *
10
+ * Read-only image viewer used when EditorShell runs in `image` file mode
11
+ * (PNG/JPEG/etc.). Renders a centered image that fits its container with
12
+ * a small overlay toolbar for fit / 100% / zoom in / zoom out, and a
13
+ * status row showing intrinsic dimensions and current zoom.
14
+ *
15
+ * Lifecycle of the `src` URL is the caller's responsibility — when fed a
16
+ * blob URL, the host should `URL.revokeObjectURL` on unmount or src change.
17
+ *
18
+ * Future image-editing actions (rotate, flip, crop) will slot in alongside
19
+ * the existing zoom controls.
20
+ */
21
+ interface ImageViewerProps {
22
+ /** Image source — typically a blob: URL the host owns and revokes. */
23
+ src: string;
24
+ /** Alt text for accessibility. Defaults to empty string (decorative). */
25
+ alt?: string;
26
+ /** Additional class name on the outer container. */
27
+ className?: string;
28
+ /** Color theme for the chrome around the image. */
29
+ theme?: 'light' | 'dark';
30
+ }
31
+ declare function ImageViewer({ src, alt, className, theme }: ImageViewerProps): react_jsx_runtime.JSX.Element;
32
+
33
+ interface ImageEditorProps {
34
+ /**
35
+ * Scoped sidecar container for this image — typically
36
+ * `scopeContainer(parent, basename + '_files')`.
37
+ */
38
+ filesContainer: ContentContainer;
39
+ /**
40
+ * Source URL used to seed `assets/source.<ext>` and layer 0 the
41
+ * first time the sidecar is opened. Ignored once `state.json` exists.
42
+ */
43
+ initialSrc?: string;
44
+ /** Override the state filename. Default: `state.json`. */
45
+ stateFilename?: string;
46
+ /** Enable version-history snapshots in `.versions/`. Default: `false`. */
47
+ allowVersioning?: boolean;
48
+ /** Auto-save idle delay (ms) for version snapshots. Default: `5000`. */
49
+ versioningAutoSaveIdleMs?: number;
50
+ /** Called after the user clicks Export and the blob is produced. */
51
+ onExport?: (blob: Blob, format: ImageEditExportFormat) => void;
52
+ /**
53
+ * What the toolbar's Save button does:
54
+ * - `'flush'` (default): write `state.json` to the sidecar.
55
+ * - `'export'`: rasterize the canvas in `saveFormat` and fire
56
+ * {@link onExport} — the same code path the Export menu uses.
57
+ * Hosts that want one-click "save and close" semantics use this.
58
+ */
59
+ saveBehavior?: 'flush' | 'export';
60
+ /** Format used when `saveBehavior === 'export'`. Default: `'png'`. */
61
+ saveFormat?: ImageEditExportFormat;
62
+ /** Override the Save button label. Default: `'Save'`. */
63
+ saveLabel?: string;
64
+ /** Override the Save button tooltip. */
65
+ saveTitle?: string;
66
+ /**
67
+ * Squisq Theme to color the editor chrome (toolbar, panels, controls).
68
+ * Defaults to `DEFAULT_THEME`. Combined with {@link surface} the same
69
+ * way `<JsonView>` and `<LinearDocView>` do.
70
+ */
71
+ theme?: Theme;
72
+ /**
73
+ * Surface scheme — `LIGHT_SURFACE`, `DARK_SURFACE`, an explicit
74
+ * `SurfaceScheme` object, or `'auto'` to track the user's OS
75
+ * `prefers-color-scheme`. When omitted, the theme's own background is
76
+ * used as-is.
77
+ */
78
+ surface?: SurfaceScheme | 'auto';
79
+ /** Optional className for the root element. */
80
+ className?: string;
81
+ }
82
+ declare function ImageEditor(props: ImageEditorProps): react_jsx_runtime.JSX.Element;
83
+
84
+ /**
85
+ * Pure state + reducer for the `<ImageEditor>` component.
86
+ *
87
+ * Kept React-free so it's easy to unit-test in isolation. The actual
88
+ * React hook that wires this to a {@link ContentContainer} (and the
89
+ * version manager) lives in `useImageEditor.ts`.
90
+ */
91
+
92
+ type DOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
93
+ /**
94
+ * Layer payload accepted by the `add-layer` action — the `id` field is
95
+ * optional and will be assigned by the underlying `addLayer` helper if
96
+ * the caller doesn't supply one.
97
+ */
98
+ type ImageEditLayerInput = ImageEditLayer | (DOmit<ImageEditLayer, 'id'> & {
99
+ id?: string;
100
+ });
101
+ /** The currently active interaction tool. */
102
+ type ImageEditorTool = 'select' | 'text' | 'shape' | 'image' | 'crop' | 'zoom-rect';
103
+ /** A pixel-space rectangle in canvas coordinates. */
104
+ interface CanvasRect {
105
+ x: number;
106
+ y: number;
107
+ width: number;
108
+ height: number;
109
+ }
110
+ interface ImageEditorState {
111
+ /** The persisted document. */
112
+ doc: ImageEditDoc;
113
+ /** Selected layer id, or `null` when nothing is selected. */
114
+ selectedLayerId: string | null;
115
+ /** Active tool. */
116
+ tool: ImageEditorTool;
117
+ /**
118
+ * The shape kind the shape tool will drop next (a drawing palette kind,
119
+ * e.g. `'rectangle'`, `'diamond'`, `'arrow-right'`). Set when the user
120
+ * picks from the shape palette; defaults to `'rectangle'`.
121
+ */
122
+ shapeKind: string;
123
+ /**
124
+ * Dirty flag — true when the in-memory doc has unsaved changes
125
+ * relative to the last `markClean()` call. The hook uses this to
126
+ * debounce writes back to `state.json`.
127
+ */
128
+ dirty: boolean;
129
+ }
130
+ type ImageEditorAction = {
131
+ type: 'load';
132
+ doc: ImageEditDoc;
133
+ } | {
134
+ type: 'mark-clean';
135
+ } | {
136
+ type: 'set-tool';
137
+ tool: ImageEditorTool;
138
+ } | {
139
+ type: 'set-shape-kind';
140
+ kind: string;
141
+ } | {
142
+ type: 'select';
143
+ layerId: string | null;
144
+ } | {
145
+ type: 'set-canvas';
146
+ canvas: ImageEditDoc['canvas'];
147
+ } | {
148
+ type: 'add-layer';
149
+ layer: ImageEditLayerInput;
150
+ select?: boolean;
151
+ } | {
152
+ type: 'remove-layer';
153
+ layerId: string;
154
+ } | {
155
+ type: 'update-layer';
156
+ layerId: string;
157
+ patch: Partial<ImageEditLayer>;
158
+ } | {
159
+ type: 'reorder-layer';
160
+ layerId: string;
161
+ toIndex: number;
162
+ } | {
163
+ type: 'crop';
164
+ rect: CanvasRect;
165
+ };
166
+ /** Build the initial state from a freshly-loaded doc. */
167
+ declare function initialImageEditorState(doc: ImageEditDoc): ImageEditorState;
168
+ declare function imageEditorReducer(state: ImageEditorState, action: ImageEditorAction): ImageEditorState;
169
+
170
+ /**
171
+ * React hook that bundles the image-editor reducer with sidecar
172
+ * persistence, versioning, and an object-URL cache for asset bytes.
173
+ *
174
+ * Hosts pass an already-scoped {@link ContentContainer} (typically built
175
+ * with `scopeContainer(parent, basename + '_files')`); the hook never
176
+ * looks above that root.
177
+ */
178
+
179
+ interface UseImageEditorOptions {
180
+ /** Sidecar container for the image being edited. */
181
+ container: ContentContainer;
182
+ /**
183
+ * Initial source image URL — used to seed layer 0 when the sidecar has
184
+ * no `state.json` yet. Bytes are fetched and copied into
185
+ * `assets/source.<ext>` so the doc is portable.
186
+ */
187
+ initialSrc?: string;
188
+ /** Policy and byte/time limits for fetching `initialSrc`. */
189
+ resourcePolicy?: ResourcePolicy;
190
+ /** Override the state filename. Defaults to `state.json`. */
191
+ stateFilename?: string;
192
+ /** Enable version history. Default: `false`. */
193
+ allowVersioning?: boolean;
194
+ /** Auto-save idle delay (ms). `0` disables. Default: `5000`. */
195
+ versioningAutoSaveIdleMs?: number;
196
+ /** Debounced write delay for state.json (ms). Default: `500`. */
197
+ persistDebounceMs?: number;
198
+ }
199
+ interface UseImageEditorReturn {
200
+ /** Current reducer state (or `null` while still loading the initial doc). */
201
+ state: ImageEditorState | null;
202
+ /** Dispatch a reducer action. No-op while loading. */
203
+ dispatch: (action: ImageEditorAction) => void;
204
+ /** Manually trigger a synchronous write of `state.json`. */
205
+ flush: () => Promise<void>;
206
+ /** Resolve an asset path inside the sidecar to a blob URL (cached). */
207
+ resolveAssetUrl: (path: string) => Promise<string>;
208
+ /**
209
+ * Write a new asset (raster image) into `assets/` and return the
210
+ * sidecar-relative path. The caller is then expected to push a layer
211
+ * referencing that path.
212
+ */
213
+ uploadAsset: (file: Blob, suggestedName?: string) => Promise<string>;
214
+ /** Versioning handle. `null` when `allowVersioning` is false or no container. */
215
+ versioning: ImageEditVersionManager | null;
216
+ /** True after the initial load completes (either an existing doc or seeded). */
217
+ ready: boolean;
218
+ /** Last load / persistence error, if any. */
219
+ error: Error | null;
220
+ }
221
+ declare function useImageEditor(options: UseImageEditorOptions): UseImageEditorReturn;
222
+
223
+ export { type CanvasRect, ImageEditor, type ImageEditorAction, type ImageEditorProps, type ImageEditorState, type ImageEditorTool, ImageViewer, type ImageViewerProps, type UseImageEditorOptions, type UseImageEditorReturn, imageEditorReducer, initialImageEditorState, useImageEditor };
@@ -0,0 +1,15 @@
1
+ import {
2
+ ImageEditor,
3
+ ImageViewer,
4
+ imageEditorReducer,
5
+ initialImageEditorState,
6
+ useImageEditor
7
+ } from "../chunk-V44VP242.js";
8
+ import "../chunk-GS7QWYFT.js";
9
+ export {
10
+ ImageEditor,
11
+ ImageViewer,
12
+ imageEditorReducer,
13
+ initialImageEditorState,
14
+ useImageEditor
15
+ };