@codingfactory/mediables-vue 2.11.0 → 2.13.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/dist/{PixiFrameExporter-apC6SqIv.cjs → PixiFrameExporter-BnAievFi.cjs} +2 -2
- package/dist/{PixiFrameExporter-apC6SqIv.cjs.map → PixiFrameExporter-BnAievFi.cjs.map} +1 -1
- package/dist/{PixiFrameExporter-D9swI3PO.js → PixiFrameExporter-DwbBy1Iu.js} +2 -2
- package/dist/{PixiFrameExporter-D9swI3PO.js.map → PixiFrameExporter-DwbBy1Iu.js.map} +1 -1
- package/dist/components/ImageEditorModal.vue.d.ts +9 -2
- package/dist/composables/useImageEditorModal.d.ts +1262 -86
- package/dist/composables/useRadialMenu.d.ts +1 -1
- package/dist/editor-BoDU3YXD.js +10862 -0
- package/dist/editor-BoDU3YXD.js.map +1 -0
- package/dist/editor-D-cJRASf.cjs +2 -0
- package/dist/editor-D-cJRASf.cjs.map +1 -0
- package/dist/{index-BFYtEc-Y.js → index-BGC4rPDc.js} +16370 -14565
- package/dist/index-BGC4rPDc.js.map +1 -0
- package/dist/index-CljyFIEv.cjs +357 -0
- package/dist/index-CljyFIEv.cjs.map +1 -0
- package/dist/mediables-vanilla.cjs +1 -1
- package/dist/mediables-vanilla.mjs +1 -1
- package/dist/mediables-vue.cjs +1 -1
- package/dist/mediables-vue.mjs +2 -2
- package/dist/style.css +1 -1
- package/dist/types/editor.d.ts +212 -27
- package/dist/vanilla-editor/VanillaImageEditor.d.ts +18 -0
- package/dist/vanilla-editor/VanillaImageEditorV2.d.ts +16 -0
- package/dist/vanilla-editor/core/EventEmitter.d.ts +12 -0
- package/dist/vanilla-editor/core/State.d.ts +98 -0
- package/dist/vanilla-editor/filters/categories.d.ts +69 -0
- package/dist/vanilla-editor/icons/icons.d.ts +42 -0
- package/dist/vanilla-editor/index.d.ts +342 -0
- package/dist/vanilla-editor/presets/index.d.ts +114 -0
- package/dist/vanilla-editor/renderer/CropManager.d.ts +140 -0
- package/dist/vanilla-editor/renderer/FilterManager.d.ts +132 -0
- package/dist/vanilla-editor/renderer/PixiRenderer.d.ts +274 -0
- package/dist/vanilla-editor/renderer/RemoveBgManager.d.ts +108 -0
- package/dist/vanilla-editor/styles/editor-v2.css +1366 -0
- package/dist/vanilla-editor/styles/editor.css +1403 -0
- package/dist/vanilla-editor/ui/ActiveFiltersPanel.d.ts +93 -0
- package/dist/vanilla-editor/ui/CategoryCarousel.d.ts +66 -0
- package/dist/vanilla-editor/ui/CropControls.d.ts +65 -0
- package/dist/vanilla-editor/ui/FilterAdjustments.d.ts +93 -0
- package/dist/vanilla-editor/ui/FilterCarousel.d.ts +74 -0
- package/dist/vanilla-editor/ui/MobileActiveFilters.d.ts +21 -0
- package/dist/vanilla-editor/ui/MobileFilterDrawer.d.ts +79 -0
- package/dist/vanilla-editor/ui/Toolbar.d.ts +35 -0
- package/dist/vanilla-editor/ui/UIBuilder.d.ts +87 -0
- package/dist/vanilla-editor/ui-v2/ActiveFiltersStack.d.ts +16 -0
- package/dist/vanilla-editor/ui-v2/BackgroundPanel.d.ts +16 -0
- package/dist/vanilla-editor/ui-v2/BottomDrawer.d.ts +55 -0
- package/dist/vanilla-editor/ui-v2/CategoryTabs.d.ts +21 -0
- package/dist/vanilla-editor/ui-v2/FilterControlsView.d.ts +16 -0
- package/dist/vanilla-editor/ui-v2/FilterListView.d.ts +32 -0
- package/dist/vanilla-editor/ui-v2/LayerStackPanel.d.ts +30 -0
- package/dist/vanilla-editor/ui-v2/MobileActiveChips.d.ts +23 -0
- package/dist/vanilla-editor/ui-v2/MobileNavigation.d.ts +51 -0
- package/dist/vanilla-editor/ui-v2/SplitPanelLayout.d.ts +70 -0
- package/dist/vanilla-editor/ui-v2/TextPanel.d.ts +58 -0
- package/dist/vanilla-exports.d.ts +9 -0
- package/package.json +3 -2
- package/dist/editor-BTwIhrcA.cjs +0 -2
- package/dist/editor-BTwIhrcA.cjs.map +0 -1
- package/dist/editor-CYj5y5bp.js +0 -8893
- package/dist/editor-CYj5y5bp.js.map +0 -1
- package/dist/index-BFYtEc-Y.js.map +0 -1
- package/dist/index-CAPdRZVb.cjs +0 -357
- package/dist/index-CAPdRZVb.cjs.map +0 -1
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vanilla Image Editor Type Declarations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { EventEmitter } from './core/EventEmitter';
|
|
6
|
+
|
|
7
|
+
export interface VanillaImageEditorOptions {
|
|
8
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
9
|
+
initialMode?: 'filters' | 'crop' | 'adjust';
|
|
10
|
+
cropShape?: 'free' | 'circle' | 'square';
|
|
11
|
+
initialAspectRatio?: string;
|
|
12
|
+
backgroundRemoval?: {
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
endpoint?: string;
|
|
15
|
+
optionsEndpoint?: string;
|
|
16
|
+
savedEndpoint?: string;
|
|
17
|
+
fallbackEndpoint?: string | null;
|
|
18
|
+
defaultTier?: 'fast' | 'balanced' | 'best';
|
|
19
|
+
maxMegapixels?: number;
|
|
20
|
+
};
|
|
21
|
+
backgroundReplacement?: BackgroundReplacementConfig | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface BackgroundReplacementConfig {
|
|
25
|
+
assetEndpoint?: string | null;
|
|
26
|
+
materializeEndpoint?: string | null;
|
|
27
|
+
targetMediaUuid?: string | null;
|
|
28
|
+
mediaChoices?: Array<{
|
|
29
|
+
id?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
source: ImageEditorLayerSource;
|
|
32
|
+
fit?: 'cover' | 'contain' | 'stretch' | 'tile';
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface FilterRegistry {
|
|
37
|
+
getAllFilters: () => FilterDefinition[];
|
|
38
|
+
getFilter: (id: string) => FilterDefinition | undefined;
|
|
39
|
+
getFiltersByCategory: (category: string) => FilterDefinition[];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ControlDefinition {
|
|
43
|
+
id: string;
|
|
44
|
+
type: 'slider' | 'toggle' | 'color' | 'select' | 'range' | 'button' | 'text';
|
|
45
|
+
label: string;
|
|
46
|
+
property?: string;
|
|
47
|
+
action?: string;
|
|
48
|
+
min?: number;
|
|
49
|
+
max?: number;
|
|
50
|
+
step?: number;
|
|
51
|
+
default?: number | boolean | string;
|
|
52
|
+
options?: Array<{ label: string; value: string | number }>;
|
|
53
|
+
tooltip?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface FilterDefinition {
|
|
57
|
+
id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
category: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
thumbnail?: string;
|
|
62
|
+
createFilter: (params: Record<string, unknown>) => unknown;
|
|
63
|
+
defaultParams: Record<string, unknown>;
|
|
64
|
+
controls: ControlDefinition[];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface SaveEventPayload {
|
|
68
|
+
blob: Blob;
|
|
69
|
+
mimeType: string;
|
|
70
|
+
dimensions: { width: number; height: number };
|
|
71
|
+
state: ImageEditorSessionState;
|
|
72
|
+
document?: ImageEditorDocument | null;
|
|
73
|
+
documentId?: string | null;
|
|
74
|
+
documentRevisionId?: string | null;
|
|
75
|
+
documentRevisionNumber?: number | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface ErrorEventPayload {
|
|
79
|
+
error: Error;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Canonical serializable editor session state (v3.0.0+) */
|
|
83
|
+
export interface ImageEditorSessionState {
|
|
84
|
+
version: 1;
|
|
85
|
+
crop: {
|
|
86
|
+
rect: { x: number; y: number; width: number; height: number } | null;
|
|
87
|
+
aspectRatio: string;
|
|
88
|
+
shape: 'free' | 'square' | 'circle';
|
|
89
|
+
};
|
|
90
|
+
transform?: {
|
|
91
|
+
rotation: number;
|
|
92
|
+
};
|
|
93
|
+
filters: Array<{
|
|
94
|
+
id: string;
|
|
95
|
+
enabled: boolean;
|
|
96
|
+
values: Record<string, string | number | boolean>;
|
|
97
|
+
}>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type ImageEditorLayerSource =
|
|
101
|
+
| { kind: 'media'; mediaUuid: string; originalWidth: number; originalHeight: number; sourceHash: string; url?: string; previewUrl?: string; sourceUrl?: string }
|
|
102
|
+
| { kind: 'edit-asset'; assetId: string; originalWidth: number; originalHeight: number; sourceHash: string; url?: string; previewUrl?: string; sourceUrl?: string }
|
|
103
|
+
| { kind: 'runtime'; runtimeRef: string; originalWidth: number; originalHeight: number; sourceHash: string | null; url?: string; previewUrl?: string; sourceUrl?: string }
|
|
104
|
+
| { kind: 'color'; color: string };
|
|
105
|
+
|
|
106
|
+
export type ImageEditorBackgroundFill =
|
|
107
|
+
| { kind: 'transparent' }
|
|
108
|
+
| { kind: 'color'; value: string; fit?: 'cover' | 'contain' | 'stretch' | 'tile' }
|
|
109
|
+
| { kind: 'gradient'; gradientType: 'linear' | 'radial'; angle: number; stops: Array<{ offset: number; color: string }>; fit: 'cover' | 'contain' | 'stretch' | 'tile' }
|
|
110
|
+
| { kind: 'media'; source: ImageEditorLayerSource; fit: 'cover' | 'contain' | 'stretch' | 'tile' };
|
|
111
|
+
|
|
112
|
+
export interface ImageEditorTextStyle {
|
|
113
|
+
fontFamily: string;
|
|
114
|
+
fontSize: number;
|
|
115
|
+
fontWeight: number;
|
|
116
|
+
fontStyle: 'normal' | 'italic';
|
|
117
|
+
fill: string;
|
|
118
|
+
align: 'left' | 'center' | 'right';
|
|
119
|
+
lineHeight: number;
|
|
120
|
+
letterSpacing: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface ImageEditorTextEffects {
|
|
124
|
+
stroke: { enabled: boolean; color: string; width: number };
|
|
125
|
+
shadow: { enabled: boolean; color: string; alpha: number; blur: number; distance: number; angle: number };
|
|
126
|
+
glow: { enabled: boolean; color: string; alpha: number; blur: number };
|
|
127
|
+
backdrop: { enabled: boolean; color: string; opacity: number; padding: number; radius: number; blur: number };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface ImageEditorTextBox {
|
|
131
|
+
x: number;
|
|
132
|
+
y: number;
|
|
133
|
+
width: number;
|
|
134
|
+
height: number;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface ImageEditorTextPayload {
|
|
138
|
+
content: string;
|
|
139
|
+
box: ImageEditorTextBox;
|
|
140
|
+
style: ImageEditorTextStyle;
|
|
141
|
+
effects: ImageEditorTextEffects;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface ImageEditorTextLayerPatch {
|
|
145
|
+
content?: string;
|
|
146
|
+
box?: Partial<ImageEditorTextBox>;
|
|
147
|
+
style?: Partial<ImageEditorTextStyle> & Record<string, unknown>;
|
|
148
|
+
effects?: Partial<{
|
|
149
|
+
stroke: Partial<ImageEditorTextEffects['stroke']>;
|
|
150
|
+
shadow: Partial<ImageEditorTextEffects['shadow']>;
|
|
151
|
+
glow: Partial<ImageEditorTextEffects['glow']>;
|
|
152
|
+
backdrop: Partial<ImageEditorTextEffects['backdrop']>;
|
|
153
|
+
}>;
|
|
154
|
+
transform?: Partial<{ x: number; y: number; scaleX: number; scaleY: number; rotation: number }>;
|
|
155
|
+
text?: Partial<ImageEditorTextPayload>;
|
|
156
|
+
opacity?: number;
|
|
157
|
+
blendMode?: ImageEditorLayer['blendMode'];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ImageEditorLayer {
|
|
161
|
+
id: string;
|
|
162
|
+
type: 'background' | 'image' | 'text';
|
|
163
|
+
role: 'background' | 'subject' | 'overlay' | 'text';
|
|
164
|
+
name: string;
|
|
165
|
+
visible: boolean;
|
|
166
|
+
locked: boolean;
|
|
167
|
+
opacity: number;
|
|
168
|
+
blendMode: 'normal' | 'multiply' | 'screen' | 'overlay';
|
|
169
|
+
transform: { x: number; y: number; scaleX: number; scaleY: number; rotation: number };
|
|
170
|
+
effects: unknown[];
|
|
171
|
+
metadata: Record<string, unknown>;
|
|
172
|
+
source?: ImageEditorLayerSource;
|
|
173
|
+
fill?: ImageEditorBackgroundFill;
|
|
174
|
+
text?: ImageEditorTextPayload;
|
|
175
|
+
crop: { x: number; y: number; width: number; height: number } | null;
|
|
176
|
+
filters: ImageEditorSessionState['filters'];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ImageEditorDocument {
|
|
180
|
+
version: 2;
|
|
181
|
+
id: string;
|
|
182
|
+
sourceMediaUuid: string | null;
|
|
183
|
+
canvas: { width: number; height: number; backgroundPreviewColor: string | null };
|
|
184
|
+
revision: number;
|
|
185
|
+
layers: ImageEditorLayer[];
|
|
186
|
+
activeLayerId: string | null;
|
|
187
|
+
export: {
|
|
188
|
+
mimeType: 'image/png' | 'image/jpeg' | 'image/webp';
|
|
189
|
+
quality: number | null;
|
|
190
|
+
preserveTransparency: boolean;
|
|
191
|
+
matteColor: string | null;
|
|
192
|
+
trimTransparentBounds: boolean;
|
|
193
|
+
};
|
|
194
|
+
createdAt?: string;
|
|
195
|
+
updatedAt?: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface EditorExportOptions {
|
|
199
|
+
maxEdge?: number;
|
|
200
|
+
maxPixels?: number;
|
|
201
|
+
dontUpscale?: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface EditorBlobExportResult {
|
|
205
|
+
blob: Blob;
|
|
206
|
+
width: number;
|
|
207
|
+
height: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export class VanillaImageEditor extends EventEmitter {
|
|
211
|
+
constructor(container: HTMLElement, options?: VanillaImageEditorOptions);
|
|
212
|
+
|
|
213
|
+
loadImage(
|
|
214
|
+
imageSource: string | Blob | File,
|
|
215
|
+
options?: { state?: ImageEditorSessionState | null; document?: ImageEditorDocument | null; documentId?: string | null; documentRevisionId?: string | null; documentRevisionNumber?: number | null; sessionKey?: string | number }
|
|
216
|
+
): Promise<void>;
|
|
217
|
+
exportImage(format?: 'png' | 'jpeg', quality?: number, options?: EditorExportOptions): string | null;
|
|
218
|
+
exportBlob(format?: 'png' | 'jpeg', quality?: number, options?: EditorExportOptions): Promise<EditorBlobExportResult | null>;
|
|
219
|
+
save(): void | Promise<void>;
|
|
220
|
+
reset(): void;
|
|
221
|
+
rotateBy(degrees: number): boolean;
|
|
222
|
+
setRotationAngle(angle: number): boolean;
|
|
223
|
+
resetRotation(): boolean;
|
|
224
|
+
setTheme(theme: 'light' | 'dark' | 'auto'): void;
|
|
225
|
+
setMode(mode: 'filters' | 'crop'): void;
|
|
226
|
+
setFilterRegistry(registry: FilterRegistry): void;
|
|
227
|
+
removeBackground(options?: { tier?: 'fast' | 'balanced' | 'best'; operationId?: string; sessionKey?: string; sourceHash?: string; model?: string; alpha_matting?: boolean; max_megapixels?: number }): Promise<Record<string, unknown>>;
|
|
228
|
+
canRemoveBackground(): boolean;
|
|
229
|
+
isBackgroundRemovalAvailable(): Promise<boolean>;
|
|
230
|
+
getState(): Record<string, unknown>;
|
|
231
|
+
getSerializableState(): ImageEditorSessionState;
|
|
232
|
+
getSerializableDocument?(): ImageEditorDocument | null;
|
|
233
|
+
getEditorDocumentBinding?(): { documentId: string | null; documentRevisionId: string | null; documentRevisionNumber: number | null } | null;
|
|
234
|
+
setBackgroundColor?(color: string): Promise<string | null>;
|
|
235
|
+
setBackgroundGradient?(gradient: Partial<Extract<ImageEditorBackgroundFill, { kind: 'gradient' }>>): Promise<string | null>;
|
|
236
|
+
setBackgroundMediaSource?(source: ImageEditorLayerSource, options?: { fit?: 'cover' | 'contain' | 'stretch' | 'tile' }): Promise<string | null>;
|
|
237
|
+
setBackgroundImageFromFile?(file: Blob, options?: { fit?: 'cover' | 'contain' | 'stretch' | 'tile' }): Promise<string | null>;
|
|
238
|
+
setBackgroundFit?(fit: 'cover' | 'contain' | 'stretch' | 'tile'): Promise<boolean>;
|
|
239
|
+
setBackgroundBlur?(amount: number): Promise<boolean>;
|
|
240
|
+
removeBackgroundLayer?(): Promise<boolean>;
|
|
241
|
+
selectLayer?(layerId: string): Promise<boolean>;
|
|
242
|
+
renameLayer?(layerId: string, name: string): Promise<boolean>;
|
|
243
|
+
duplicateLayer?(layerId: string): Promise<string | null>;
|
|
244
|
+
deleteLayer?(layerId: string): Promise<boolean>;
|
|
245
|
+
moveLayer?(layerId: string, direction: 'up' | 'down' | 'front' | 'back' | 'bring-forward' | 'send-backward' | 'bring-to-front' | 'send-to-back'): Promise<boolean>;
|
|
246
|
+
setLayerVisibility?(layerId: string, visible: boolean): Promise<boolean>;
|
|
247
|
+
setLayerLocked?(layerId: string, locked: boolean): Promise<boolean>;
|
|
248
|
+
addTextLayer?(payload?: ImageEditorTextLayerPatch): Promise<string | null>;
|
|
249
|
+
updateTextLayer?(layerId: string, patch?: ImageEditorTextLayerPatch): Promise<boolean>;
|
|
250
|
+
destroy(): void;
|
|
251
|
+
|
|
252
|
+
on(event: 'save', callback: (payload: SaveEventPayload) => void): void;
|
|
253
|
+
on(event: 'cancel', callback: () => void): void;
|
|
254
|
+
on(event: 'error', callback: (payload: ErrorEventPayload) => void): void;
|
|
255
|
+
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* v2 editor with persistent inspector panel layout.
|
|
260
|
+
* Mirrors VanillaImageEditor's public API so the Vue wrapper can swap between them.
|
|
261
|
+
*/
|
|
262
|
+
export class VanillaImageEditorV2 extends EventEmitter {
|
|
263
|
+
constructor(container: HTMLElement, options?: VanillaImageEditorOptions & { layout?: 'split-panel' });
|
|
264
|
+
|
|
265
|
+
loadImage(
|
|
266
|
+
imageSource: string | Blob | File,
|
|
267
|
+
options?: { state?: ImageEditorSessionState | null; document?: ImageEditorDocument | null; documentId?: string | null; documentRevisionId?: string | null; documentRevisionNumber?: number | null; sessionKey?: string | number }
|
|
268
|
+
): Promise<void>;
|
|
269
|
+
exportImage(format?: 'png' | 'jpeg', quality?: number, options?: EditorExportOptions): string | null;
|
|
270
|
+
exportBlob(format?: 'png' | 'jpeg', quality?: number, options?: EditorExportOptions): Promise<EditorBlobExportResult | null>;
|
|
271
|
+
save(): void | Promise<void>;
|
|
272
|
+
resetAll(expectedLayerId?: string | null): void;
|
|
273
|
+
rotateBy(degrees: number): boolean;
|
|
274
|
+
setRotationAngle(angle: number): boolean;
|
|
275
|
+
resetRotation(): boolean;
|
|
276
|
+
setTheme(theme: 'light' | 'dark' | 'auto'): void;
|
|
277
|
+
setMode(mode: 'filters' | 'crop'): void;
|
|
278
|
+
setFilterRegistry(registry: FilterRegistry): void;
|
|
279
|
+
removeBackground(options?: { tier?: 'fast' | 'balanced' | 'best'; operationId?: string; sessionKey?: string; sourceHash?: string; model?: string; alpha_matting?: boolean; max_megapixels?: number }): Promise<Record<string, unknown>>;
|
|
280
|
+
canRemoveBackground(): boolean;
|
|
281
|
+
isBackgroundRemovalAvailable(): Promise<boolean>;
|
|
282
|
+
getState(): Record<string, unknown>;
|
|
283
|
+
getSerializableState(): ImageEditorSessionState;
|
|
284
|
+
getSerializableDocument(): ImageEditorDocument | null;
|
|
285
|
+
getEditorDocumentBinding(): { documentId: string | null; documentRevisionId: string | null; documentRevisionNumber: number | null } | null;
|
|
286
|
+
setBackgroundColor(color: string): Promise<string | null>;
|
|
287
|
+
setBackgroundGradient(gradient: Partial<Extract<ImageEditorBackgroundFill, { kind: 'gradient' }>>): Promise<string | null>;
|
|
288
|
+
setBackgroundMediaSource(source: ImageEditorLayerSource, options?: { fit?: 'cover' | 'contain' | 'stretch' | 'tile' }): Promise<string | null>;
|
|
289
|
+
setBackgroundImageFromFile(file: Blob, options?: { fit?: 'cover' | 'contain' | 'stretch' | 'tile' }): Promise<string | null>;
|
|
290
|
+
setBackgroundFit(fit: 'cover' | 'contain' | 'stretch' | 'tile'): Promise<boolean>;
|
|
291
|
+
setBackgroundBlur(amount: number): Promise<boolean>;
|
|
292
|
+
removeBackgroundLayer(): Promise<boolean>;
|
|
293
|
+
selectLayer(layerId: string): Promise<boolean>;
|
|
294
|
+
renameLayer(layerId: string, name: string): Promise<boolean>;
|
|
295
|
+
duplicateLayer(layerId: string): Promise<string | null>;
|
|
296
|
+
deleteLayer(layerId: string): Promise<boolean>;
|
|
297
|
+
moveLayer(layerId: string, direction: 'up' | 'down' | 'front' | 'back' | 'bring-forward' | 'send-backward' | 'bring-to-front' | 'send-to-back'): Promise<boolean>;
|
|
298
|
+
setLayerVisibility(layerId: string, visible: boolean): Promise<boolean>;
|
|
299
|
+
setLayerLocked(layerId: string, locked: boolean): Promise<boolean>;
|
|
300
|
+
addTextLayer(payload?: ImageEditorTextLayerPatch): Promise<string | null>;
|
|
301
|
+
updateTextLayer(layerId: string, patch?: ImageEditorTextLayerPatch): Promise<boolean>;
|
|
302
|
+
destroy(): void;
|
|
303
|
+
|
|
304
|
+
on(event: 'save', callback: (payload: SaveEventPayload) => void): void;
|
|
305
|
+
on(event: 'cancel', callback: () => void): void;
|
|
306
|
+
on(event: 'error', callback: (payload: ErrorEventPayload) => void): void;
|
|
307
|
+
on(event: string, callback: (...args: unknown[]) => void): void;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Core utilities
|
|
311
|
+
export { EventEmitter } from './core/EventEmitter';
|
|
312
|
+
export { State, createState, getState } from './core/State';
|
|
313
|
+
|
|
314
|
+
// Renderer classes
|
|
315
|
+
export { PixiRenderer } from './renderer/PixiRenderer';
|
|
316
|
+
export { FilterManager } from './renderer/FilterManager';
|
|
317
|
+
export { CropManager } from './renderer/CropManager';
|
|
318
|
+
|
|
319
|
+
// UI components
|
|
320
|
+
export { Toolbar } from './ui/Toolbar';
|
|
321
|
+
export { CategoryCarousel } from './ui/CategoryCarousel';
|
|
322
|
+
export { FilterCarousel } from './ui/FilterCarousel';
|
|
323
|
+
export { FilterAdjustments } from './ui/FilterAdjustments';
|
|
324
|
+
export { CropControls } from './ui/CropControls';
|
|
325
|
+
export { ActiveFiltersPanel } from './ui/ActiveFiltersPanel';
|
|
326
|
+
|
|
327
|
+
// UI Builder utilities
|
|
328
|
+
export {
|
|
329
|
+
el,
|
|
330
|
+
createSlider,
|
|
331
|
+
createToggle,
|
|
332
|
+
createColorPicker,
|
|
333
|
+
createSelect,
|
|
334
|
+
createButton,
|
|
335
|
+
createIconButton,
|
|
336
|
+
createChip,
|
|
337
|
+
createCard,
|
|
338
|
+
createScrollContainer
|
|
339
|
+
} from './ui/UIBuilder';
|
|
340
|
+
|
|
341
|
+
// Icons
|
|
342
|
+
export * as icons from './icons/icons';
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a preset by name or return a custom preset object as-is.
|
|
3
|
+
* Falls back to the 'free' preset if the name is not recognized.
|
|
4
|
+
*
|
|
5
|
+
* @param {string|EditorPreset} preset - Preset name or custom preset object
|
|
6
|
+
* @returns {EditorPreset} Resolved preset
|
|
7
|
+
*/
|
|
8
|
+
export function getPreset(preset: string | EditorPreset): EditorPreset;
|
|
9
|
+
/**
|
|
10
|
+
* Merge a preset with explicit option overrides.
|
|
11
|
+
* Options take precedence over preset values.
|
|
12
|
+
*
|
|
13
|
+
* @param {EditorPreset} preset - Base preset
|
|
14
|
+
* @param {Partial<EditorPreset>} overrides - Explicit overrides
|
|
15
|
+
* @returns {EditorPreset} Merged result
|
|
16
|
+
*/
|
|
17
|
+
export function mergePresetWithOverrides(preset: EditorPreset, overrides: Partial<EditorPreset>): EditorPreset;
|
|
18
|
+
/**
|
|
19
|
+
* Parse an aspect ratio string into a numeric value.
|
|
20
|
+
* Handles standard ratios ('1:1', '16:9', etc.) and custom strings ('3:1', '21:9').
|
|
21
|
+
* Returns null for 'free' or invalid values.
|
|
22
|
+
*
|
|
23
|
+
* @param {string} ratio - Aspect ratio string
|
|
24
|
+
* @returns {number|null} Numeric ratio (width / height), or null for 'free'
|
|
25
|
+
*/
|
|
26
|
+
export function parseAspectRatio(ratio: string): number | null;
|
|
27
|
+
/**
|
|
28
|
+
* Built-in presets.
|
|
29
|
+
* @type {Record<string, EditorPreset>}
|
|
30
|
+
*/
|
|
31
|
+
export const PRESETS: Record<string, EditorPreset>;
|
|
32
|
+
export type EditorPreset = {
|
|
33
|
+
/**
|
|
34
|
+
* - Preset identifier (e.g., 'avatar', 'banner', 'product')
|
|
35
|
+
*/
|
|
36
|
+
name: string;
|
|
37
|
+
/**
|
|
38
|
+
* - Which tool is active when editor opens
|
|
39
|
+
*/
|
|
40
|
+
initialMode: "crop" | "filters";
|
|
41
|
+
/**
|
|
42
|
+
* - Default crop shape
|
|
43
|
+
*/
|
|
44
|
+
cropShape: "free" | "square" | "circle";
|
|
45
|
+
/**
|
|
46
|
+
* - Aspect ratio: 'free', '1:1', '4:3', '16:9', '3:2', '2:3', or custom like '3:1'
|
|
47
|
+
*/
|
|
48
|
+
aspectRatio: string;
|
|
49
|
+
/**
|
|
50
|
+
* - Smart zoom-out when crop exceeds image bounds
|
|
51
|
+
*/
|
|
52
|
+
autoZoomOnCropOverflow: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* - Prevent user from changing crop shape
|
|
55
|
+
*/
|
|
56
|
+
lockCropShape: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* - Prevent user from changing aspect ratio
|
|
59
|
+
*/
|
|
60
|
+
lockAspectRatio: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* - Whether filter panel is available
|
|
63
|
+
*/
|
|
64
|
+
showFilters: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* - Whether crop controls are available
|
|
67
|
+
*/
|
|
68
|
+
showCropControls: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* - Optional max output width in pixels
|
|
71
|
+
*/
|
|
72
|
+
maxExportWidth?: number | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* - Optional max output height in pixels
|
|
75
|
+
*/
|
|
76
|
+
maxExportHeight?: number | undefined;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Editor Preset System
|
|
80
|
+
*
|
|
81
|
+
* Presets configure the image editor for specific use cases (avatars, banners, etc.).
|
|
82
|
+
* Each preset defines initial tool state, crop shape, aspect ratio, and control visibility.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* import { getPreset, PRESETS } from './presets/index.js'
|
|
86
|
+
*
|
|
87
|
+
* // Get a built-in preset by name
|
|
88
|
+
* const avatarPreset = getPreset('avatar')
|
|
89
|
+
*
|
|
90
|
+
* // Use directly
|
|
91
|
+
* const editor = new VanillaImageEditor(container, { preset: avatarPreset })
|
|
92
|
+
*
|
|
93
|
+
* // Or pass by name (resolved later)
|
|
94
|
+
* const editor = new VanillaImageEditor(container, { preset: 'avatar' })
|
|
95
|
+
*/
|
|
96
|
+
/**
|
|
97
|
+
* @typedef {Object} EditorPreset
|
|
98
|
+
* @property {string} name - Preset identifier (e.g., 'avatar', 'banner', 'product')
|
|
99
|
+
* @property {'crop'|'filters'} initialMode - Which tool is active when editor opens
|
|
100
|
+
* @property {'free'|'square'|'circle'} cropShape - Default crop shape
|
|
101
|
+
* @property {string} aspectRatio - Aspect ratio: 'free', '1:1', '4:3', '16:9', '3:2', '2:3', or custom like '3:1'
|
|
102
|
+
* @property {boolean} autoZoomOnCropOverflow - Smart zoom-out when crop exceeds image bounds
|
|
103
|
+
* @property {boolean} lockCropShape - Prevent user from changing crop shape
|
|
104
|
+
* @property {boolean} lockAspectRatio - Prevent user from changing aspect ratio
|
|
105
|
+
* @property {boolean} showFilters - Whether filter panel is available
|
|
106
|
+
* @property {boolean} showCropControls - Whether crop controls are available
|
|
107
|
+
* @property {number} [maxExportWidth] - Optional max output width in pixels
|
|
108
|
+
* @property {number} [maxExportHeight] - Optional max output height in pixels
|
|
109
|
+
*/
|
|
110
|
+
/**
|
|
111
|
+
* Default values for an EditorPreset. Used as the base when merging.
|
|
112
|
+
* @type {EditorPreset}
|
|
113
|
+
*/
|
|
114
|
+
export const DEFAULT_PRESET: EditorPreset;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export class CropManager extends EventEmitter {
|
|
2
|
+
/**
|
|
3
|
+
* Padding factor for auto-zoom: image will be ~91% of crop size (1/1.1).
|
|
4
|
+
* Higher values = more aggressive zoom-out, more padding around image.
|
|
5
|
+
*/
|
|
6
|
+
static AUTO_ZOOM_PADDING: number;
|
|
7
|
+
/**
|
|
8
|
+
* Minimum interval (ms) between auto-zoom adjustments during drag.
|
|
9
|
+
*/
|
|
10
|
+
static AUTO_ZOOM_THROTTLE_MS: number;
|
|
11
|
+
/**
|
|
12
|
+
* Calculate the target zoom level for auto-zoom when crop exceeds image bounds.
|
|
13
|
+
* Pure function — returns the new zoom level, or null if no adjustment is needed.
|
|
14
|
+
*
|
|
15
|
+
* @param {{ width: number, height: number }} cropRect - Current crop dimensions
|
|
16
|
+
* @param {number} spriteWidth - Current sprite width on screen
|
|
17
|
+
* @param {number} spriteHeight - Current sprite height on screen
|
|
18
|
+
* @param {number} texWidth - Original texture width (pixels)
|
|
19
|
+
* @param {number} texHeight - Original texture height (pixels)
|
|
20
|
+
* @param {number} fitScale - Current fit-to-screen scale
|
|
21
|
+
* @param {number} currentZoom - Current zoom level
|
|
22
|
+
* @returns {number|null} Target zoom level, or null if no zoom needed
|
|
23
|
+
*/
|
|
24
|
+
static calcAutoZoom(cropRect: {
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
}, spriteWidth: number, spriteHeight: number, texWidth: number, texHeight: number, fitScale: number, currentZoom: number): number | null;
|
|
28
|
+
constructor(state: any, pixiRenderer: any);
|
|
29
|
+
state: any;
|
|
30
|
+
renderer: any;
|
|
31
|
+
_overlayCanvas: HTMLCanvasElement | null;
|
|
32
|
+
_isDragging: boolean;
|
|
33
|
+
_dragStart: {
|
|
34
|
+
x: any;
|
|
35
|
+
y: any;
|
|
36
|
+
} | null;
|
|
37
|
+
_dragMode: string | null;
|
|
38
|
+
_startRect: any;
|
|
39
|
+
_hoverMode: string | null;
|
|
40
|
+
_lastAutoZoomCheck: number;
|
|
41
|
+
HANDLE_SIZE: number;
|
|
42
|
+
EDGE_HIT_PAD: number;
|
|
43
|
+
_onPointerDown: (event: any) => void;
|
|
44
|
+
_onPointerMove: (event: any) => void;
|
|
45
|
+
_onPointerUp: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* Set the overlay canvas element
|
|
48
|
+
* @param {HTMLCanvasElement} canvas
|
|
49
|
+
*/
|
|
50
|
+
setOverlayCanvas(canvas: HTMLCanvasElement): void;
|
|
51
|
+
/**
|
|
52
|
+
* Get aspect ratio value from string
|
|
53
|
+
* @param {string} aspect
|
|
54
|
+
* @returns {number|null}
|
|
55
|
+
*/
|
|
56
|
+
_getAspectRatio(aspect: string): number | null;
|
|
57
|
+
/**
|
|
58
|
+
* Apply aspect ratio constraint to crop rect
|
|
59
|
+
*/
|
|
60
|
+
applyAspectRatio(): void;
|
|
61
|
+
/**
|
|
62
|
+
* Constrain crop rect to bounds
|
|
63
|
+
*/
|
|
64
|
+
constrainCropRect(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Check if auto-zoom is needed and apply it (throttled).
|
|
67
|
+
* Called during crop resize drags when autoZoomOnCropOverflow is enabled.
|
|
68
|
+
*/
|
|
69
|
+
_checkAutoZoom(): void;
|
|
70
|
+
/**
|
|
71
|
+
* Draw crop overlay on canvas
|
|
72
|
+
*/
|
|
73
|
+
drawOverlay(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Hit test for handles
|
|
76
|
+
* @param {number} px
|
|
77
|
+
* @param {number} py
|
|
78
|
+
* @returns {string|null}
|
|
79
|
+
*/
|
|
80
|
+
_hitHandle(px: number, py: number): string | null;
|
|
81
|
+
/**
|
|
82
|
+
* Handle pointer down event
|
|
83
|
+
*/
|
|
84
|
+
_handlePointerDown(event: any): void;
|
|
85
|
+
/**
|
|
86
|
+
* Handle pointer move event
|
|
87
|
+
*/
|
|
88
|
+
_handlePointerMove(event: any): void;
|
|
89
|
+
/**
|
|
90
|
+
* Handle pointer up event
|
|
91
|
+
*/
|
|
92
|
+
_handlePointerUp(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Enable crop mode
|
|
95
|
+
*/
|
|
96
|
+
enable(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Disable crop mode
|
|
99
|
+
*/
|
|
100
|
+
disable(): void;
|
|
101
|
+
/**
|
|
102
|
+
* Apply the crop
|
|
103
|
+
* @returns {{ texture: PIXI.Texture, preservedZoom: number }|null}
|
|
104
|
+
*/
|
|
105
|
+
apply(): {
|
|
106
|
+
texture: PIXI.Texture;
|
|
107
|
+
preservedZoom: number;
|
|
108
|
+
} | null;
|
|
109
|
+
/**
|
|
110
|
+
* Apply a crop from saved texture-pixel coordinates (for state rehydration).
|
|
111
|
+
* Unlike apply(), this does not read from crop.rect or require the interactive overlay.
|
|
112
|
+
* @param {{ x: number, y: number, width: number, height: number }} pixelRect
|
|
113
|
+
* @param {'free'|'circle'} shape
|
|
114
|
+
* @returns {{ texture: Object, preservedZoom: number }|null}
|
|
115
|
+
*/
|
|
116
|
+
applyFromPixelRect(pixelRect: {
|
|
117
|
+
x: number;
|
|
118
|
+
y: number;
|
|
119
|
+
width: number;
|
|
120
|
+
height: number;
|
|
121
|
+
}, shape?: "free" | "circle"): {
|
|
122
|
+
texture: Object;
|
|
123
|
+
preservedZoom: number;
|
|
124
|
+
} | null;
|
|
125
|
+
/**
|
|
126
|
+
* Cancel crop
|
|
127
|
+
*/
|
|
128
|
+
cancel(): void;
|
|
129
|
+
/**
|
|
130
|
+
* Set crop shape
|
|
131
|
+
* @param {'free'|'square'|'circle'} shape
|
|
132
|
+
*/
|
|
133
|
+
setShape(shape: "free" | "square" | "circle"): void;
|
|
134
|
+
/**
|
|
135
|
+
* Set aspect ratio
|
|
136
|
+
* @param {'free'|'1:1'|'4:3'|'16:9'|'3:2'|'2:3'|string} aspect
|
|
137
|
+
*/
|
|
138
|
+
setAspect(aspect: "free" | "1:1" | "4:3" | "16:9" | "3:2" | "2:3" | string): void;
|
|
139
|
+
}
|
|
140
|
+
import { EventEmitter } from '../core/EventEmitter.js';
|