@snowcone-app/canvas 0.28.0 → 0.30.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/ERROR_CONTRACT.md +13 -0
- package/dist/{CanvasRenderer-B_3GISlW.js → CanvasRenderer-BEf0hXeF.js} +1083 -1071
- package/dist/CanvasRenderer-BEf0hXeF.js.map +1 -0
- package/dist/{CanvasStateV1-kL09wsAn.js → CanvasStateV1-BDSyYo4A.js} +872 -844
- package/dist/{CanvasStateV1-kL09wsAn.js.map → CanvasStateV1-BDSyYo4A.js.map} +1 -1
- package/dist/ContextualToolbars-C3D_6sep.js +5960 -0
- package/dist/ContextualToolbars-C3D_6sep.js.map +1 -0
- package/dist/{EditorCanvasImpl-CrI9C_xM.js → EditorCanvasImpl-DXeBz2CX.js} +8 -8
- package/dist/{EditorCanvasImpl-CrI9C_xM.js.map → EditorCanvasImpl-DXeBz2CX.js.map} +1 -1
- package/dist/{ExportManager-J2xK86uq.js → ExportManager-DUdis6se.js} +1307 -970
- package/dist/ExportManager-DUdis6se.js.map +1 -0
- package/dist/{FontAnalyzer-PE6nysqE.js → FontAnalyzer-DKG5JK0x.js} +1419 -1342
- package/dist/FontAnalyzer-DKG5JK0x.js.map +1 -0
- package/dist/{ImagePanel-CmQCxBGm.js → ImagePanel-CBgGqmVV.js} +53 -53
- package/dist/{ImagePanel-CmQCxBGm.js.map → ImagePanel-CBgGqmVV.js.map} +1 -1
- package/dist/SnowconeCanvas-BWPBngvI.js +1192 -0
- package/dist/SnowconeCanvas-BWPBngvI.js.map +1 -0
- package/dist/{UnifiedFontService-BJzoqfBF.js → UnifiedFontService-Co9tQ59z.js} +869 -826
- package/dist/UnifiedFontService-Co9tQ59z.js.map +1 -0
- package/dist/advanced.mjs +14 -14
- package/dist/api/embed.d.ts +2 -0
- package/dist/api/stable.d.ts +2 -0
- package/dist/components/CanvasContextMenu.d.ts +15 -0
- package/dist/components/CanvasEditor/hooks/useCanvasInteraction.d.ts +27 -0
- package/dist/components/CanvasEditor.d.ts +8 -0
- package/dist/components/embed/SnowconeCanvas.d.ts +13 -0
- package/dist/components/embed/kernel.d.ts +8 -0
- package/dist/components/toolbars/SecondaryPanels.d.ts +11 -0
- package/dist/components/ui/icons.d.ts +2 -0
- package/dist/contexts/CanvasServicesContext.d.ts +17 -0
- package/dist/contexts/EditorContext.d.ts +7 -0
- package/dist/core/TextElement.d.ts +13 -0
- package/dist/core/TextMetrics.d.ts +17 -3
- package/dist/core/rich-text-layout.d.ts +2 -0
- package/dist/core/text-spacing.d.ts +74 -0
- package/dist/{custom-icons-BWiUGqD6.js → custom-icons-BIaRovwG.js} +2 -2
- package/dist/{custom-icons-BWiUGqD6.js.map → custom-icons-BIaRovwG.js.map} +1 -1
- package/dist/{design-builder-bquxIHct.js → design-builder-JYLO_Hyi.js} +2 -2
- package/dist/{design-builder-bquxIHct.js.map → design-builder-JYLO_Hyi.js.map} +1 -1
- package/dist/{editorErrors-8uDRMhow.js → editorErrors-WzaNxU1Y.js} +181 -194
- package/dist/editorErrors-WzaNxU1Y.js.map +1 -0
- package/dist/{embed-L3oRIgsj.js → embed-Csez1hui.js} +113 -112
- package/dist/{embed-L3oRIgsj.js.map → embed-Csez1hui.js.map} +1 -1
- package/dist/embed.mjs +51 -45
- package/dist/embed.mjs.map +1 -1
- package/dist/errors/editorError.d.ts +8 -0
- package/dist/{guards-BlbhM5MX.js → guards-BSoX73yg.js} +2 -2
- package/dist/{guards-BlbhM5MX.js.map → guards-BSoX73yg.js.map} +1 -1
- package/dist/hooks/useKeyboardShortcuts.d.ts +15 -2
- package/dist/hooks/useLayers.d.ts +2 -0
- package/dist/hooks/useTextToolbar.d.ts +8 -0
- package/dist/index.mjs +42 -37
- package/dist/index.mjs.map +1 -1
- package/dist/internals.mjs +47 -47
- package/dist/rendering/renderer-types.d.ts +4 -0
- package/dist/rendering/rich-text-renderer.d.ts +4 -0
- package/dist/rendering/text-renderer.d.ts +4 -1
- package/dist/state/CanvasStateV1.d.ts +34 -3
- package/dist/state/index.d.ts +2 -2
- package/dist/{template-fields-ai7vnW8g.js → template-fields-DYPW7bVU.js} +40 -40
- package/dist/{template-fields-ai7vnW8g.js.map → template-fields-DYPW7bVU.js.map} +1 -1
- package/dist/testing.mjs +13 -13
- package/dist/types/index.d.ts +26 -0
- package/dist/{usePieceGuideBundle-CMe5br2a.js → usePieceGuideBundle-CRLY2iQa.js} +2 -2
- package/dist/{usePieceGuideBundle-CMe5br2a.js.map → usePieceGuideBundle-CRLY2iQa.js.map} +1 -1
- package/dist/utils/custom-fonts.d.ts +99 -0
- package/dist/utils/featureApplied.d.ts +6 -0
- package/dist/validation-BGEl9rrE.js +8686 -0
- package/dist/validation-BGEl9rrE.js.map +1 -0
- package/dist/workers/export-protocol.d.ts +13 -0
- package/dist/workers/export-worker.bundle.string.d.ts +1 -1
- package/example/package.json +1 -1
- package/package.json +1 -1
- package/dist/CanvasRenderer-B_3GISlW.js.map +0 -1
- package/dist/ContextualToolbars-C69oYLdw.js +0 -5771
- package/dist/ContextualToolbars-C69oYLdw.js.map +0 -1
- package/dist/ExportManager-J2xK86uq.js.map +0 -1
- package/dist/FontAnalyzer-PE6nysqE.js.map +0 -1
- package/dist/SnowconeCanvas-CQiFVR0X.js +0 -1173
- package/dist/SnowconeCanvas-CQiFVR0X.js.map +0 -1
- package/dist/UnifiedFontService-BJzoqfBF.js.map +0 -1
- package/dist/editorErrors-8uDRMhow.js.map +0 -1
- package/dist/validation-B8kIYutI.js +0 -8397
- package/dist/validation-B8kIYutI.js.map +0 -1
package/dist/embed.mjs
CHANGED
|
@@ -1,54 +1,60 @@
|
|
|
1
|
-
import { C as a, a as
|
|
2
|
-
import { E as
|
|
3
|
-
import {
|
|
4
|
-
import { D as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { C as a, a as t, b as r, u as o, d as i, f as n, g as m } from "./UnifiedFontService-Co9tQ59z.js";
|
|
2
|
+
import { E as u, R as l, a as E, b as c, S as p, c as g, d as f, f as x, p as S, e as C, g as T, h as v, v as y } from "./embed-Csez1hui.js";
|
|
3
|
+
import { E as P, y as b } from "./FontAnalyzer-DKG5JK0x.js";
|
|
4
|
+
import { D as R, d as h, a as k, i as D } from "./design-builder-JYLO_Hyi.js";
|
|
5
|
+
import { u as L } from "./editorErrors-WzaNxU1Y.js";
|
|
6
|
+
import { D as M, T as A, h as G, i as K, j as _, k as j, l as z, m as N, r as Y, u as q, a as H, b as J, c as O, d as Q, e as U, f as V, w as W } from "./template-fields-DYPW7bVU.js";
|
|
7
|
+
import { c as Z, e as $, l as ee, r as se } from "./ExportManager-DUdis6se.js";
|
|
8
|
+
import { s as te } from "./CanvasStateV1-BDSyYo4A.js";
|
|
7
9
|
export {
|
|
8
10
|
a as CanvasServicesProvider,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
R as DesignBuilder,
|
|
12
|
+
M as DesignStateStore,
|
|
13
|
+
u as Editor,
|
|
14
|
+
P as EditorError,
|
|
15
|
+
l as RealtimeCanvas,
|
|
14
16
|
E as RealtimeEmbed,
|
|
15
17
|
c as RealtimeMockup,
|
|
16
18
|
p as SnowconeEditor,
|
|
17
|
-
|
|
19
|
+
A as TEMPLATE_FIELDS_KEY,
|
|
18
20
|
g as auditEditor,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
_ as
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
N as
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
21
|
+
f as collectEmbedIssues,
|
|
22
|
+
t as createProxyGenerate,
|
|
23
|
+
r as createProxyImageSearch,
|
|
24
|
+
Z as customFontRegistry,
|
|
25
|
+
h as design,
|
|
26
|
+
G as editorElementKind,
|
|
27
|
+
$ as ensureCustomFontsLoaded,
|
|
28
|
+
x as formatBuyPrice,
|
|
29
|
+
k as isColorToken,
|
|
30
|
+
b as isEditorError,
|
|
31
|
+
K as isGroupElement,
|
|
32
|
+
_ as isImageElement,
|
|
33
|
+
D as isLayerToken,
|
|
34
|
+
j as isPathElement,
|
|
35
|
+
z as isShapeElement,
|
|
36
|
+
N as isTextElement,
|
|
37
|
+
ee as loadCustomFont,
|
|
38
|
+
S as productToRenderConfig,
|
|
39
|
+
Y as readTemplateFields,
|
|
40
|
+
se as registerCustomFonts,
|
|
41
|
+
te as serializeState,
|
|
42
|
+
o as useArtboards,
|
|
43
|
+
i as useCanvasServices,
|
|
44
|
+
q as useColorBinding,
|
|
45
|
+
H as useCommands,
|
|
46
|
+
L as useEditor,
|
|
47
|
+
J as useElementByName,
|
|
42
48
|
n as useExport,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
O as useFontBinding,
|
|
50
|
+
Q as useImageBinding,
|
|
51
|
+
m as useLayers,
|
|
52
|
+
C as usePlacements,
|
|
53
|
+
T as useProductSelection,
|
|
54
|
+
v as useRealtimeMockups,
|
|
55
|
+
U as useSelectedElement,
|
|
56
|
+
V as useTextBinding,
|
|
57
|
+
y as validateEmbed,
|
|
58
|
+
W as withTemplateFields
|
|
53
59
|
};
|
|
54
60
|
//# sourceMappingURL=embed.mjs.map
|
package/dist/embed.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"embed.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -88,6 +88,14 @@ export type EditorErrorCode =
|
|
|
88
88
|
/** `auditEditor()` called with no `<Editor.Root>` mounted — the imperative
|
|
89
89
|
* audit reads the most-recent mounted Root's registry (#10). */
|
|
90
90
|
| 'E_AUDIT_NO_ROOT'
|
|
91
|
+
/** A custom (brand) font failed to load from its hosted URL — the binary
|
|
92
|
+
* fetch failed (CORS, 404, network) or FontFace rejected the bytes.
|
|
93
|
+
* Custom fonts NEVER fall back silently to a system face: the design
|
|
94
|
+
* would render with a different typeface/metrics everywhere it's
|
|
95
|
+
* consumed. `data` carries `family`, `url`, `weight`, `style`. Fix the
|
|
96
|
+
* URL (must serve the font file over a plain cross-origin GET) and
|
|
97
|
+
* re-register. Dev AND prod. */
|
|
98
|
+
| 'E_FONT_LOAD_FAILED'
|
|
91
99
|
/** `computeDistribute()` called with fewer than 3 movable elements —
|
|
92
100
|
* distributing needs something between the two ends. Gate the action on
|
|
93
101
|
* `useAlignDistribute().canDistribute` instead of calling below the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as n, I as t, P as a, S as s, T as i } from "./FontAnalyzer-
|
|
1
|
+
import { G as n, I as t, P as a, S as s, T as i } from "./FontAnalyzer-DKG5JK0x.js";
|
|
2
2
|
function r(e) {
|
|
3
3
|
return e instanceof i;
|
|
4
4
|
}
|
|
@@ -21,4 +21,4 @@ export {
|
|
|
21
21
|
r as d,
|
|
22
22
|
u as i
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=guards-
|
|
24
|
+
//# sourceMappingURL=guards-BSoX73yg.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guards-
|
|
1
|
+
{"version":3,"file":"guards-BSoX73yg.js","sources":["../src/types/guards.ts"],"sourcesContent":["/**\n * Type guards for EditorElement discrimination\n *\n * These guards use instanceof checks against the concrete element classes,\n * matching the pattern established in EditorContext.tsx. They accept\n * BaseElement | EditorElement | undefined | null for maximum flexibility\n * at call sites.\n */\n\nimport { BaseElement } from '../core/BaseElement.js';\nimport { TextElement } from '../core/TextElement.js';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { PathElement } from '../core/PathElement.js';\n\ntype Narrowable = BaseElement | TextElement | ImageElement | GroupElement | ShapeElement | PathElement | undefined | null;\n\n/**\n * Type guard: checks if an element is a TextElement (or any text-based transform subclass).\n *\n * TextElement is the base class for all text transforms (custom, circle, arch, wave, etc.),\n * so this returns true for any text-based element regardless of its specific transformType.\n */\nexport function isTextElement(element: Narrowable): element is TextElement {\n return element instanceof TextElement;\n}\n\n/**\n * Type guard: checks if an element is an ImageElement.\n */\nexport function isImageElement(element: Narrowable): element is ImageElement {\n return element instanceof ImageElement;\n}\n\n/**\n * Type guard: checks if an element is a GroupElement.\n */\nexport function isGroupElement(element: Narrowable): element is GroupElement {\n return element instanceof GroupElement;\n}\n\n/**\n * Type guard: checks if an element is a ShapeElement.\n */\nexport function isShapeElement(element: Narrowable): element is ShapeElement {\n return element instanceof ShapeElement;\n}\n\n/**\n * Type guard: checks if an element is a PathElement.\n */\nexport function isPathElement(element: Narrowable): element is PathElement {\n return element instanceof PathElement;\n}\n"],"names":["isTextElement","element","TextElement","isImageElement","ImageElement","isGroupElement","GroupElement","isShapeElement","ShapeElement","isPathElement","PathElement"],"mappings":";AAwBO,SAASA,EAAcC,GAA6C;AACzE,SAAOA,aAAmBC;AAC5B;AAKO,SAASC,EAAeF,GAA8C;AAC3E,SAAOA,aAAmBG;AAC5B;AAKO,SAASC,EAAeJ,GAA8C;AAC3E,SAAOA,aAAmBK;AAC5B;AAKO,SAASC,EAAeN,GAA8C;AAC3E,SAAOA,aAAmBO;AAC5B;AAKO,SAASC,EAAcR,GAA6C;AACzE,SAAOA,aAAmBS;AAC5B;"}
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
import { useEditor } from '../contexts/EditorContext.js';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
3
|
+
* Select every element on the ACTIVE artboard (multi-selection).
|
|
4
|
+
*
|
|
5
|
+
* Shared implementation behind Cmd/Ctrl+A AND the canvas context menu's
|
|
6
|
+
* "Select All" entry — one definition so the two surfaces can't drift.
|
|
7
|
+
* Locked elements are included — locking gates manipulation, not selection
|
|
8
|
+
* (gotcha #20); hidden elements are skipped to mirror marquee selection.
|
|
9
|
+
* Same state path as marquee selection: the multi-selection array is the
|
|
10
|
+
* source of truth; single selection is cleared alongside it.
|
|
4
11
|
*/
|
|
12
|
+
export declare function selectAllOnActiveArtboard(opts: {
|
|
13
|
+
elements: ReturnType<typeof useEditor>['elements'];
|
|
14
|
+
artboardManager: ReturnType<typeof useEditor>['artboardManager'];
|
|
15
|
+
handleSelectionChange: (id: string | null) => void;
|
|
16
|
+
setMultiSelection: (ids: string[]) => void;
|
|
17
|
+
}): void;
|
|
5
18
|
/**
|
|
6
19
|
* Hook that sets up keyboard shortcuts for the editor
|
|
7
20
|
* Handles copy/paste, delete, undo/redo, and other shortcuts
|
|
@@ -40,6 +40,8 @@ export interface UseLayersReturn {
|
|
|
40
40
|
reorderWithinGroup: (draggedId: string, targetId: string, position: 'before' | 'after', groupId: string) => void;
|
|
41
41
|
moveLayerForward: (id: string) => void;
|
|
42
42
|
moveLayerBackward: (id: string) => void;
|
|
43
|
+
bringToFront: (id: string) => void;
|
|
44
|
+
sendToBack: (id: string) => void;
|
|
43
45
|
groupLayers: (ids: string[]) => void;
|
|
44
46
|
ungroupLayer: (id: string) => void;
|
|
45
47
|
addToGroup: (elementId: string, groupId: string) => void;
|
|
@@ -12,8 +12,16 @@ export interface UseTextToolbarReturn {
|
|
|
12
12
|
italic: boolean;
|
|
13
13
|
underline: boolean;
|
|
14
14
|
letterCase: string;
|
|
15
|
+
/** Letter-spacing in px per character (element-level default; 0 = none). */
|
|
16
|
+
letterSpacing: number;
|
|
17
|
+
/** Line-height multiplier (1.2 = the layout default). */
|
|
18
|
+
lineHeight: number;
|
|
15
19
|
handleFontSizeChange: (size: number) => void;
|
|
16
20
|
handleFontSizeIncrement: (delta: number) => void;
|
|
21
|
+
/** Per-character aware (applies to the selection while editing text). */
|
|
22
|
+
handleLetterSpacingChange: (spacing: number) => void;
|
|
23
|
+
/** Element-level only (line layout is an element concern, not a span one). */
|
|
24
|
+
handleLineHeightChange: (lineHeight: number) => void;
|
|
17
25
|
handleFontFamilyChange: (family: string) => void;
|
|
18
26
|
handleFontColorChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
19
27
|
handleBoldToggle: () => void;
|
package/dist/index.mjs
CHANGED
|
@@ -1,64 +1,69 @@
|
|
|
1
|
-
import { e as u } from "./UnifiedFontService-
|
|
2
|
-
import { C as
|
|
3
|
-
import { E as
|
|
4
|
-
import { u as
|
|
5
|
-
import { T as
|
|
6
|
-
import { A as Z, C as G, E as H, M as j, P as k, r as q, v as J } from "./validation-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { e as u } from "./UnifiedFontService-Co9tQ59z.js";
|
|
2
|
+
import { C as p, c as x, a as I, b as v, u as A, d as g, f as T, g as B } from "./UnifiedFontService-Co9tQ59z.js";
|
|
3
|
+
import { E as y, S as F, S as L, u as _, a as O } from "./SnowconeCanvas-BWPBngvI.js";
|
|
4
|
+
import { u as m, a as d } from "./editorErrors-WzaNxU1Y.js";
|
|
5
|
+
import { T as M, r as z, u as w, a as D, b as K, c as N, d as V, e as b, f as h, w as U } from "./template-fields-DYPW7bVU.js";
|
|
6
|
+
import { A as Z, C as G, E as H, M as j, P as k, r as q, v as J } from "./validation-BGEl9rrE.js";
|
|
7
|
+
import { c as W, e as X, l as $, r as ee } from "./ExportManager-DUdis6se.js";
|
|
8
|
+
import { C as ae, D as te, d as oe, s as re } from "./design-builder-JYLO_Hyi.js";
|
|
9
|
+
import { c as ie, e as ue } from "./compose-DtQL_oit.js";
|
|
10
|
+
import { d as de, m as Ce, s as Se, v as Ee } from "./CanvasStateV1-BDSyYo4A.js";
|
|
11
|
+
function E() {
|
|
12
|
+
const { isCanvasReady: e } = m();
|
|
12
13
|
return e;
|
|
13
14
|
}
|
|
14
|
-
function
|
|
15
|
-
const { zoom: e, panOffset:
|
|
16
|
-
return { zoom: e, panOffset:
|
|
15
|
+
function c() {
|
|
16
|
+
const { zoom: e, panOffset: s, zoomIn: a, zoomOut: t, zoomToFit: o, resetView: r, setZoom: n, setPanOffset: i } = d();
|
|
17
|
+
return { zoom: e, panOffset: s, zoomIn: a, zoomOut: t, zoomToFit: o, resetView: r, setZoom: n, setPanOffset: i };
|
|
17
18
|
}
|
|
18
19
|
u();
|
|
19
20
|
export {
|
|
20
21
|
Z as ALL_CAPABILITIES,
|
|
21
|
-
|
|
22
|
+
ae as CANVAS_STATE_SCHEMA_VERSION,
|
|
22
23
|
G as COMPACT_CUSTOMIZER,
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
p as CanvasServicesProvider,
|
|
25
|
+
te as DesignBuilder,
|
|
25
26
|
H as EMBED_ONLY,
|
|
26
|
-
|
|
27
|
+
y as ErrorBoundary,
|
|
27
28
|
j as MINIMAL_CAPABILITIES,
|
|
28
29
|
k as PRO_STUDIO,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
F as SnowconeCanvas,
|
|
31
|
+
M as TEMPLATE_FIELDS_KEY,
|
|
32
|
+
ie as createKit,
|
|
32
33
|
x as createProxyBgRemove,
|
|
33
34
|
I as createProxyGenerate,
|
|
34
35
|
v as createProxyImageSearch,
|
|
36
|
+
W as customFontRegistry,
|
|
35
37
|
L as default,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
de as deserializeState,
|
|
39
|
+
oe as design,
|
|
40
|
+
X as ensureCustomFontsLoaded,
|
|
41
|
+
ue as extendKit,
|
|
42
|
+
$ as loadCustomFont,
|
|
43
|
+
Ce as migrateState,
|
|
44
|
+
z as readTemplateFields,
|
|
45
|
+
ee as registerCustomFonts,
|
|
41
46
|
q as resolveKit,
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
Se as serializeState,
|
|
48
|
+
re as serializeStateForServer,
|
|
44
49
|
A as useArtboards,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
_ as useAutoExport,
|
|
51
|
+
E as useCanvasReady,
|
|
52
|
+
g as useCanvasServices,
|
|
53
|
+
w as useColorBinding,
|
|
49
54
|
D as useCommands,
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
O as useContentReady,
|
|
56
|
+
m as useEditor,
|
|
52
57
|
K as useElementByName,
|
|
53
|
-
|
|
58
|
+
T as useExport,
|
|
54
59
|
N as useFontBinding,
|
|
55
60
|
V as useImageBinding,
|
|
56
61
|
B as useLayers,
|
|
57
62
|
b as useSelectedElement,
|
|
58
63
|
h as useTextBinding,
|
|
59
|
-
|
|
64
|
+
c as useViewport,
|
|
60
65
|
J as validateKit,
|
|
61
|
-
|
|
66
|
+
Ee as validateState,
|
|
62
67
|
U as withTemplateFields
|
|
63
68
|
};
|
|
64
69
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/hooks/useCanvasReady.ts","../src/hooks/useViewport.ts"],"sourcesContent":["import { useEditor } from '../contexts/EditorContext.js';\n\n/**\n * Returns whether the canvas is fully initialized and ready for operations.\n *\n * The canvas is not ready until the underlying `<canvas>` element is mounted\n * and the editor has completed its initial setup. Use this to gate operations\n * like export or programmatic element manipulation that require a live canvas.\n *\n * @returns `true` when the canvas is mounted and ready, `false` otherwise.\n *\n * @example\n * ```tsx\n * function ExportButton() {\n * const ready = useCanvasReady();\n * return (\n * <button disabled={!ready} onClick={handleExport}>\n * Export PNG\n * </button>\n * );\n * }\n * ```\n */\nexport function useCanvasReady(): boolean {\n const { isCanvasReady } = useEditor();\n return isCanvasReady;\n}\n","import React from 'react';\nimport { useViewportContext } from '../contexts/ViewportContext.js';\nimport type { PanOffset } from '../contexts/ViewportContext.js';\n\n/**\n * Return type for {@link useViewport}.\n */\nexport interface UseViewportReturn {\n /** Current zoom level (1.0 = 100%) */\n zoom: number;\n /** Current pan offset in world coordinates */\n panOffset: PanOffset;\n /** Increment zoom by one step */\n zoomIn: () => void;\n /** Decrement zoom by one step */\n zoomOut: () => void;\n /** Zoom to fit the active artboard in the viewport */\n zoomToFit: () => void;\n /** Reset zoom to 100% and pan offset to origin */\n resetView: () => void;\n /** Set zoom to an exact value */\n setZoom: React.Dispatch<React.SetStateAction<number>>;\n /** Set pan offset to an exact value */\n setPanOffset: React.Dispatch<React.SetStateAction<PanOffset>>;\n}\n\n/**\n * Returns viewport state (zoom, pan) and control functions.\n *\n * This hook now reads directly from ViewportContext (instead of the full\n * EditorContext), so components using it will only re-render when viewport\n * state changes -- not when elements, selection, or other state changes.\n *\n * @example\n * ```tsx\n * function ZoomBar() {\n * const { zoom, zoomIn, zoomOut, zoomToFit } = useViewport();\n * return (\n * <div>\n * <button onClick={zoomOut}>-</button>\n * <span>{Math.round(zoom * 100)}%</span>\n * <button onClick={zoomIn}>+</button>\n * <button onClick={zoomToFit}>Fit</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useViewport(): UseViewportReturn {\n const { zoom, panOffset, zoomIn, zoomOut, zoomToFit, resetView, setZoom, setPanOffset } = useViewportContext();\n return { zoom, panOffset, zoomIn, zoomOut, zoomToFit, resetView, setZoom, setPanOffset };\n}\n"],"names":["useCanvasReady","isCanvasReady","useEditor","useViewport","zoom","panOffset","zoomIn","zoomOut","zoomToFit","resetView","setZoom","setPanOffset","useViewportContext"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/hooks/useCanvasReady.ts","../src/hooks/useViewport.ts"],"sourcesContent":["import { useEditor } from '../contexts/EditorContext.js';\n\n/**\n * Returns whether the canvas is fully initialized and ready for operations.\n *\n * The canvas is not ready until the underlying `<canvas>` element is mounted\n * and the editor has completed its initial setup. Use this to gate operations\n * like export or programmatic element manipulation that require a live canvas.\n *\n * @returns `true` when the canvas is mounted and ready, `false` otherwise.\n *\n * @example\n * ```tsx\n * function ExportButton() {\n * const ready = useCanvasReady();\n * return (\n * <button disabled={!ready} onClick={handleExport}>\n * Export PNG\n * </button>\n * );\n * }\n * ```\n */\nexport function useCanvasReady(): boolean {\n const { isCanvasReady } = useEditor();\n return isCanvasReady;\n}\n","import React from 'react';\nimport { useViewportContext } from '../contexts/ViewportContext.js';\nimport type { PanOffset } from '../contexts/ViewportContext.js';\n\n/**\n * Return type for {@link useViewport}.\n */\nexport interface UseViewportReturn {\n /** Current zoom level (1.0 = 100%) */\n zoom: number;\n /** Current pan offset in world coordinates */\n panOffset: PanOffset;\n /** Increment zoom by one step */\n zoomIn: () => void;\n /** Decrement zoom by one step */\n zoomOut: () => void;\n /** Zoom to fit the active artboard in the viewport */\n zoomToFit: () => void;\n /** Reset zoom to 100% and pan offset to origin */\n resetView: () => void;\n /** Set zoom to an exact value */\n setZoom: React.Dispatch<React.SetStateAction<number>>;\n /** Set pan offset to an exact value */\n setPanOffset: React.Dispatch<React.SetStateAction<PanOffset>>;\n}\n\n/**\n * Returns viewport state (zoom, pan) and control functions.\n *\n * This hook now reads directly from ViewportContext (instead of the full\n * EditorContext), so components using it will only re-render when viewport\n * state changes -- not when elements, selection, or other state changes.\n *\n * @example\n * ```tsx\n * function ZoomBar() {\n * const { zoom, zoomIn, zoomOut, zoomToFit } = useViewport();\n * return (\n * <div>\n * <button onClick={zoomOut}>-</button>\n * <span>{Math.round(zoom * 100)}%</span>\n * <button onClick={zoomIn}>+</button>\n * <button onClick={zoomToFit}>Fit</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useViewport(): UseViewportReturn {\n const { zoom, panOffset, zoomIn, zoomOut, zoomToFit, resetView, setZoom, setPanOffset } = useViewportContext();\n return { zoom, panOffset, zoomIn, zoomOut, zoomToFit, resetView, setZoom, setPanOffset };\n}\n"],"names":["useCanvasReady","isCanvasReady","useEditor","useViewport","zoom","panOffset","zoomIn","zoomOut","zoomToFit","resetView","setZoom","setPanOffset","useViewportContext"],"mappings":";;;;;;;;;;AAuBO,SAASA,IAA0B;AACxC,QAAM,EAAE,eAAAC,EAAA,IAAkBC,EAAA;AAC1B,SAAOD;AACT;ACsBO,SAASE,IAAiC;AAC/C,QAAM,EAAE,MAAAC,GAAM,WAAAC,GAAW,QAAAC,GAAQ,SAAAC,GAAS,WAAAC,GAAW,WAAAC,GAAW,SAAAC,GAAS,cAAAC,EAAA,IAAiBC,EAAA;AAC1F,SAAO,EAAE,MAAAR,GAAM,WAAAC,GAAW,QAAAC,GAAQ,SAAAC,GAAS,WAAAC,GAAW,WAAAC,GAAW,SAAAC,GAAS,cAAAC,EAAA;AAC5E;;"}
|
package/dist/internals.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { A as w, a as b, C as I, I as R, R as W, S as A, T as E } from "./CanvasRenderer-
|
|
2
|
-
import {
|
|
3
|
-
import { D as O, E as F, I as L, W as X,
|
|
4
|
-
import {
|
|
5
|
-
import { A as Hr, e as Or, C as Fr, S as Lr } from "./CanvasStateV1-
|
|
1
|
+
import { A as w, a as b, C as I, I as R, R as W, S as A, T as E } from "./CanvasRenderer-BEf0hXeF.js";
|
|
2
|
+
import { a as p } from "./ExportManager-DUdis6se.js";
|
|
3
|
+
import { D as O, E as F, I as L, W as X, b as z, d as K, f as Y, h as B, i as J, j as _, k as N, m as V, n as j, o as q, p as G, q as Q, s as U, t as Z, u as $, v as m, w as x, x as D, y as rr, z as or, A as sr, B as ir, C as ar, F as er, G as nr, H as tr, J as hr } from "./ExportManager-DUdis6se.js";
|
|
4
|
+
import { J as cr, K as fr, L as pr, M as gr, N as lr, O as ur, Q as Tr, V as kr, W as Mr, X as yr, Y as Cr, Z as vr, _ as Sr, $ as Pr, c as wr, a0 as br, a1 as Ir, a2 as Rr, a3 as Wr, a4 as Ar } from "./FontAnalyzer-DKG5JK0x.js";
|
|
5
|
+
import { A as Hr, e as Or, C as Fr, S as Lr } from "./CanvasStateV1-BDSyYo4A.js";
|
|
6
6
|
function y(r, o) {
|
|
7
7
|
return !r.needsCropPixelConversion || r.cropWidth === void 0 ? r : {
|
|
8
8
|
...r,
|
|
@@ -14,10 +14,10 @@ function y(r, o) {
|
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
function C(r, o, c) {
|
|
17
|
-
var
|
|
17
|
+
var e, n;
|
|
18
18
|
r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180);
|
|
19
|
-
let
|
|
20
|
-
if (o.flipHorizontal && (
|
|
19
|
+
let a = 1, h = 1;
|
|
20
|
+
if (o.flipHorizontal && (a = -1), o.flipVertical && (h = -1), (a !== 1 || h !== 1) && r.scale(a, h), o.opacity !== void 0 && o.opacity !== 1 && (r.globalAlpha = o.opacity), o.borderRadius && o.borderRadius > 0) {
|
|
21
21
|
const i = Math.min(
|
|
22
22
|
o.borderRadius / 100 * Math.min(o.width, o.height),
|
|
23
23
|
o.width / 2,
|
|
@@ -37,7 +37,7 @@ function C(r, o, c) {
|
|
|
37
37
|
-o.height / 2,
|
|
38
38
|
o.width,
|
|
39
39
|
o.height
|
|
40
|
-
) : r.drawImage(c, -o.width / 2, -o.height / 2, o.width, o.height), r.restore(), (
|
|
40
|
+
) : r.drawImage(c, -o.width / 2, -o.height / 2, o.width, o.height), r.restore(), (e = o.stroke) != null && e.enabled) {
|
|
41
41
|
const i = ((n = o.knockoutParts) == null ? void 0 : n.stroke) === !0, s = {
|
|
42
42
|
x: o.x,
|
|
43
43
|
y: o.y,
|
|
@@ -79,13 +79,13 @@ function T(r, o) {
|
|
|
79
79
|
return c.width = r, c.height = o, c;
|
|
80
80
|
}
|
|
81
81
|
function v(r, o) {
|
|
82
|
-
var
|
|
83
|
-
const c = o.opacity ?? 1,
|
|
84
|
-
c < 1 &&
|
|
82
|
+
var e;
|
|
83
|
+
const c = o.opacity ?? 1, a = !!((e = o.stroke) != null && e.enabled);
|
|
84
|
+
c < 1 && a ? k(r, o, c) : g(r, o, c);
|
|
85
85
|
}
|
|
86
86
|
function k(r, o, c) {
|
|
87
87
|
var f;
|
|
88
|
-
const
|
|
88
|
+
const a = o.transformData, e = (((f = o.stroke) == null ? void 0 : f.width) || 2) + 2, n = Math.ceil(a.width + e * 2), i = Math.ceil(a.height + e * 2), s = T(n, i), t = s.getContext("2d");
|
|
89
89
|
if (!t) {
|
|
90
90
|
g(r, o, c);
|
|
91
91
|
return;
|
|
@@ -98,65 +98,65 @@ function k(r, o, c) {
|
|
|
98
98
|
g(t, d, 1), r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c, r.drawImage(s, -n / 2, -i / 2), r.restore();
|
|
99
99
|
}
|
|
100
100
|
function g(r, o, c) {
|
|
101
|
-
var
|
|
102
|
-
const
|
|
103
|
-
if (r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c * h, r.fillStyle =
|
|
101
|
+
var e;
|
|
102
|
+
const a = o.transformData, h = a.fillOpacity ?? 1;
|
|
103
|
+
if (r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180), r.globalAlpha = c * h, r.fillStyle = a.fillColor || "#3b82f6", r.beginPath(), u(r, a), r.fill(), r.restore(), (e = o.stroke) != null && e.enabled) {
|
|
104
104
|
r.save(), r.translate(o.x, o.y), o.rotation && r.rotate(-o.rotation * Math.PI / 180);
|
|
105
105
|
const n = o.stroke;
|
|
106
|
-
r.globalAlpha = c * (n.opacity ?? 1), r.strokeStyle = n.color || "#000000", r.lineWidth = n.width || 2, r.lineCap = n.lineCap || "round", r.lineJoin = n.lineJoin || "round", r.beginPath(), u(r,
|
|
106
|
+
r.globalAlpha = c * (n.opacity ?? 1), r.strokeStyle = n.color || "#000000", r.lineWidth = n.width || 2, r.lineCap = n.lineCap || "round", r.lineJoin = n.lineJoin || "round", r.beginPath(), u(r, a), r.stroke(), r.restore();
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
function u(r, o) {
|
|
110
|
-
const { shapeType: c, width:
|
|
110
|
+
const { shapeType: c, width: a, height: h } = o;
|
|
111
111
|
switch (c) {
|
|
112
112
|
case "rectangle": {
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
const s = Math.min(
|
|
116
|
-
r.roundRect(n, i,
|
|
113
|
+
const e = o.borderRadius || 0, n = -a / 2, i = -h / 2;
|
|
114
|
+
if (e > 0) {
|
|
115
|
+
const s = Math.min(e / 100 * Math.min(a, h), a / 2, h / 2);
|
|
116
|
+
r.roundRect(n, i, a, h, s);
|
|
117
117
|
} else
|
|
118
|
-
r.rect(n, i,
|
|
118
|
+
r.rect(n, i, a, h);
|
|
119
119
|
break;
|
|
120
120
|
}
|
|
121
121
|
case "circle": {
|
|
122
|
-
const
|
|
123
|
-
r.arc(0, 0,
|
|
122
|
+
const e = Math.min(a, h) / 2;
|
|
123
|
+
r.arc(0, 0, e, 0, Math.PI * 2);
|
|
124
124
|
break;
|
|
125
125
|
}
|
|
126
126
|
case "ellipse": {
|
|
127
|
-
r.ellipse(0, 0,
|
|
127
|
+
r.ellipse(0, 0, a / 2, h / 2, 0, 0, Math.PI * 2);
|
|
128
128
|
break;
|
|
129
129
|
}
|
|
130
130
|
case "triangle": {
|
|
131
|
-
const
|
|
132
|
-
r.moveTo(0, -n), r.lineTo(
|
|
131
|
+
const e = a / 2, n = h / 2;
|
|
132
|
+
r.moveTo(0, -n), r.lineTo(e, n), r.lineTo(-e, n), r.closePath();
|
|
133
133
|
break;
|
|
134
134
|
}
|
|
135
135
|
case "polygon": {
|
|
136
|
-
const
|
|
137
|
-
for (let i = 0; i <
|
|
138
|
-
const s = i * 2 * Math.PI /
|
|
136
|
+
const e = o.sides || 5, n = Math.min(a, h) / 2;
|
|
137
|
+
for (let i = 0; i < e; i++) {
|
|
138
|
+
const s = i * 2 * Math.PI / e - Math.PI / 2, t = n * Math.cos(s), d = n * Math.sin(s);
|
|
139
139
|
i === 0 ? r.moveTo(t, d) : r.lineTo(t, d);
|
|
140
140
|
}
|
|
141
141
|
r.closePath();
|
|
142
142
|
break;
|
|
143
143
|
}
|
|
144
144
|
case "star": {
|
|
145
|
-
const
|
|
146
|
-
for (let s = 0; s <
|
|
147
|
-
const t = s * Math.PI /
|
|
145
|
+
const e = o.points || 5, n = Math.min(a, h) / 2, i = n * (o.innerRadius || 0.4);
|
|
146
|
+
for (let s = 0; s < e * 2; s++) {
|
|
147
|
+
const t = s * Math.PI / e - Math.PI / 2, d = s % 2 === 0 ? n : i, f = d * Math.cos(t), l = d * Math.sin(t);
|
|
148
148
|
s === 0 ? r.moveTo(f, l) : r.lineTo(f, l);
|
|
149
149
|
}
|
|
150
150
|
r.closePath();
|
|
151
151
|
break;
|
|
152
152
|
}
|
|
153
153
|
case "line": {
|
|
154
|
-
const
|
|
155
|
-
r.rect(-
|
|
154
|
+
const e = a / 2, n = h / 2;
|
|
155
|
+
r.rect(-e, -n, a, h);
|
|
156
156
|
break;
|
|
157
157
|
}
|
|
158
158
|
default:
|
|
159
|
-
r.rect(-
|
|
159
|
+
r.rect(-a / 2, -h / 2, a, h);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
export {
|
|
@@ -193,22 +193,22 @@ export {
|
|
|
193
193
|
Sr as calculateResizeHandles,
|
|
194
194
|
Pr as calculateRotationHandlePosition,
|
|
195
195
|
B as clearImageBitmapCache,
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
J as clearMaskCache,
|
|
197
|
+
_ as clearRegisteredBitmapKeys,
|
|
198
198
|
N as createCirclePath,
|
|
199
199
|
V as createImagePath,
|
|
200
200
|
wr as createLogger,
|
|
201
201
|
j as createRectPath,
|
|
202
202
|
q as createTextPath,
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
G as getFontMetrics,
|
|
204
|
+
Q as getSharedWorkerExportManager,
|
|
205
205
|
br as hitTestCircle,
|
|
206
206
|
Ir as hitTestRect,
|
|
207
|
-
|
|
207
|
+
U as invalidateMaskCache,
|
|
208
208
|
Rr as logger,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
Z as measureTextWidth,
|
|
210
|
+
$ as removeFromImageBitmapCache,
|
|
211
|
+
m as renderCustomTransform,
|
|
212
212
|
C as renderImageElement,
|
|
213
213
|
p as renderImageStroke,
|
|
214
214
|
x as renderMultilineText,
|
|
@@ -218,8 +218,8 @@ export {
|
|
|
218
218
|
or as renderTextElement,
|
|
219
219
|
sr as renderTextFillOnly,
|
|
220
220
|
ir as renderTextStroke,
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
ar as renderWithKnockout,
|
|
222
|
+
er as renderWithMasks,
|
|
223
223
|
y as resolveServerCrop,
|
|
224
224
|
Wr as splitRichTextIntoLines,
|
|
225
225
|
nr as terminateSharedWorkerExportManager,
|
|
@@ -19,6 +19,10 @@ export interface SerializedTextElement {
|
|
|
19
19
|
italic: boolean;
|
|
20
20
|
underline: boolean;
|
|
21
21
|
strikethrough: boolean;
|
|
22
|
+
/** Extra advance per character in px (custom transform only; spans may override). */
|
|
23
|
+
letterSpacing?: number;
|
|
24
|
+
/** Line-height multiplier; undefined = LINE_HEIGHT_MULTIPLIER (1.2). Custom transform only. */
|
|
25
|
+
lineHeight?: number;
|
|
22
26
|
transformData: AnyTransformData;
|
|
23
27
|
stroke?: StrokeConfig;
|
|
24
28
|
openTypeFeatures?: OpenTypeFeatures;
|
|
@@ -15,4 +15,8 @@ export declare function renderRichTextFillOnly(ctx: RenderContext, richText: Ric
|
|
|
15
15
|
underline?: boolean;
|
|
16
16
|
strikethrough?: boolean;
|
|
17
17
|
textAlign?: TextAlign;
|
|
18
|
+
/** Element-level letter-spacing default (px/char); spans may override. */
|
|
19
|
+
letterSpacing?: number;
|
|
20
|
+
/** Line-height multiplier; undefined = LINE_HEIGHT_MULTIPLIER (1.2). */
|
|
21
|
+
lineHeight?: number;
|
|
18
22
|
}, maxWidth?: number, lockedLineCount?: number): void;
|
|
@@ -6,8 +6,9 @@ import { RenderContext, SerializedTextElement } from './renderer-types.js';
|
|
|
6
6
|
export declare function buildFontString(fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean): string;
|
|
7
7
|
/**
|
|
8
8
|
* Measure text width
|
|
9
|
+
* @param letterSpacing - Extra advance per character in px (default 0 — legacy width)
|
|
9
10
|
*/
|
|
10
|
-
export declare function measureTextWidth(text: string, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean): number;
|
|
11
|
+
export declare function measureTextWidth(text: string, fontSize: number, fontFamily: string, bold?: boolean, italic?: boolean, letterSpacing?: number): number;
|
|
11
12
|
/**
|
|
12
13
|
* Get font metrics for accurate text positioning
|
|
13
14
|
*/
|
|
@@ -49,6 +50,8 @@ export declare function renderTextFillOnly(ctx: RenderContext, element: {
|
|
|
49
50
|
italic?: boolean;
|
|
50
51
|
textAlign?: TextAlign;
|
|
51
52
|
color: string;
|
|
53
|
+
/** Extra advance per character in px (custom transform only). */
|
|
54
|
+
letterSpacing?: number;
|
|
52
55
|
}): void;
|
|
53
56
|
/**
|
|
54
57
|
* Word wrap text to fit within a given width
|