@snowcone-app/canvas 0.30.0 → 0.32.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.
Files changed (80) hide show
  1. package/ERROR_CONTRACT.md +11 -0
  2. package/STYLING_CONTRACT.md +3 -3
  3. package/dist/{CanvasRenderer-BEf0hXeF.js → CanvasRenderer-1j-twIbs.js} +443 -431
  4. package/dist/{CanvasRenderer-BEf0hXeF.js.map → CanvasRenderer-1j-twIbs.js.map} +1 -1
  5. package/dist/{CanvasStateV1-BDSyYo4A.js → CanvasStateV1-BmC1JfPv.js} +813 -798
  6. package/dist/{CanvasStateV1-BDSyYo4A.js.map → CanvasStateV1-BmC1JfPv.js.map} +1 -1
  7. package/dist/ContextualToolbars-BKU8IoAM.js +6474 -0
  8. package/dist/ContextualToolbars-BKU8IoAM.js.map +1 -0
  9. package/dist/{EditorCanvasImpl-DXeBz2CX.js → EditorCanvasImpl-4voOsj2k.js} +19 -20
  10. package/dist/{EditorCanvasImpl-DXeBz2CX.js.map → EditorCanvasImpl-4voOsj2k.js.map} +1 -1
  11. package/dist/{ExportManager-DUdis6se.js → ExportManager-Ci81K6xA.js} +783 -500
  12. package/dist/ExportManager-Ci81K6xA.js.map +1 -0
  13. package/dist/{FontAnalyzer-DKG5JK0x.js → FontAnalyzer-BrKY6XYn.js} +1604 -1444
  14. package/dist/FontAnalyzer-BrKY6XYn.js.map +1 -0
  15. package/dist/{ImagePanel-CBgGqmVV.js → ImagePanel-ntJBepby.js} +49 -49
  16. package/dist/{ImagePanel-CBgGqmVV.js.map → ImagePanel-ntJBepby.js.map} +1 -1
  17. package/dist/{SnowconeCanvas-BWPBngvI.js → SnowconeCanvas-CgQdiBXv.js} +27 -27
  18. package/dist/{SnowconeCanvas-BWPBngvI.js.map → SnowconeCanvas-CgQdiBXv.js.map} +1 -1
  19. package/dist/advanced.mjs +14 -14
  20. package/dist/components/ImageToolbar.d.ts +12 -0
  21. package/dist/components/ShapeToolbar.d.ts +8 -0
  22. package/dist/components/TextToolbar.d.ts +5 -1
  23. package/dist/components/toolbars/EmbeddedToolbarLayout.d.ts +6 -0
  24. package/dist/components/toolbars/GroupElementToolbar.d.ts +8 -0
  25. package/dist/components/toolbars/SecondaryPanels.d.ts +40 -1
  26. package/dist/components/toolbars/index.d.ts +2 -2
  27. package/dist/components/ui/SliderRow.d.ts +6 -0
  28. package/dist/components/ui/toolbar-button.d.ts +2 -2
  29. package/dist/core/BaseElement.d.ts +2 -1
  30. package/dist/core/image-adjustments.d.ts +32 -0
  31. package/dist/core/shape-fill.d.ts +31 -0
  32. package/dist/{custom-icons-BIaRovwG.js → custom-icons-DTWtkJ9N.js} +7 -7
  33. package/dist/{custom-icons-BIaRovwG.js.map → custom-icons-DTWtkJ9N.js.map} +1 -1
  34. package/dist/design-builder-BpbYUYtK.js +1672 -0
  35. package/dist/design-builder-BpbYUYtK.js.map +1 -0
  36. package/dist/{embed-Csez1hui.js → embed-C69x0jHc.js} +110 -111
  37. package/dist/{embed-Csez1hui.js.map → embed-C69x0jHc.js.map} +1 -1
  38. package/dist/embed.mjs +53 -54
  39. package/dist/embed.mjs.map +1 -1
  40. package/dist/errors/editorError.d.ts +7 -0
  41. package/dist/{guards-BSoX73yg.js → guards-BhaQgJrE.js} +2 -2
  42. package/dist/{guards-BSoX73yg.js.map → guards-BhaQgJrE.js.map} +1 -1
  43. package/dist/hooks/elementPatch.d.ts +14 -4
  44. package/dist/index.mjs +41 -41
  45. package/dist/internals.mjs +202 -133
  46. package/dist/internals.mjs.map +1 -1
  47. package/dist/rendering/LayerEffectsRenderer.d.ts +24 -0
  48. package/dist/rendering/element-painters.d.ts +0 -13
  49. package/dist/rendering/element-serializer.d.ts +3 -1
  50. package/dist/rendering/image-adjustments.d.ts +24 -0
  51. package/dist/rendering/renderer-types.d.ts +10 -1
  52. package/dist/state/CanvasStateV1.d.ts +22 -0
  53. package/dist/style.css +1 -1
  54. package/dist/template-fields-D-2oLhCi.js +505 -0
  55. package/dist/template-fields-D-2oLhCi.js.map +1 -0
  56. package/dist/testing.mjs +40 -41
  57. package/dist/testing.mjs.map +1 -1
  58. package/dist/types/index.d.ts +105 -1
  59. package/dist/types/public.d.ts +3 -2
  60. package/dist/{UnifiedFontService-Co9tQ59z.js → useCommands-DwnZHUg8.js} +2361 -2103
  61. package/dist/useCommands-DwnZHUg8.js.map +1 -0
  62. package/dist/{usePieceGuideBundle-CRLY2iQa.js → usePieceGuideBundle-CnSmYrmM.js} +2 -2
  63. package/dist/{usePieceGuideBundle-CRLY2iQa.js.map → usePieceGuideBundle-CnSmYrmM.js.map} +1 -1
  64. package/dist/utils/featureApplied.d.ts +6 -0
  65. package/dist/{validation-BGEl9rrE.js → validation-DyUOjRGa.js} +465 -465
  66. package/dist/{validation-BGEl9rrE.js.map → validation-DyUOjRGa.js.map} +1 -1
  67. package/dist/workers/export-worker.bundle.string.d.ts +1 -1
  68. package/example/package.json +1 -1
  69. package/package.json +1 -1
  70. package/dist/ContextualToolbars-C3D_6sep.js +0 -5960
  71. package/dist/ContextualToolbars-C3D_6sep.js.map +0 -1
  72. package/dist/ExportManager-DUdis6se.js.map +0 -1
  73. package/dist/FontAnalyzer-DKG5JK0x.js.map +0 -1
  74. package/dist/UnifiedFontService-Co9tQ59z.js.map +0 -1
  75. package/dist/design-builder-JYLO_Hyi.js +0 -470
  76. package/dist/design-builder-JYLO_Hyi.js.map +0 -1
  77. package/dist/editorErrors-WzaNxU1Y.js +0 -1206
  78. package/dist/editorErrors-WzaNxU1Y.js.map +0 -1
  79. package/dist/template-fields-DYPW7bVU.js +0 -716
  80. package/dist/template-fields-DYPW7bVU.js.map +0 -1
@@ -63,6 +63,25 @@ export interface FlagTransformData {
63
63
  /** Container width for text layout */
64
64
  width: number;
65
65
  }
66
+ /**
67
+ * Color adjustments for image elements. Each channel is a multiplier where
68
+ * `1` is neutral (no change); the canonical neutral state is the ABSENCE of
69
+ * the `adjustments` object (omit = neutral, never `{1, 1, 1}`).
70
+ *
71
+ * Semantics match the CSS Filter Effects spec functions `brightness()`,
72
+ * `contrast()` and `saturate()`, applied in that order to the SOURCE bitmap
73
+ * before crop / flip / border-radius compositing. The math lives in
74
+ * `rendering/image-adjustments.ts` and is shared verbatim by the live
75
+ * renderer and the export worker, so live and exported pixels always match.
76
+ */
77
+ export interface ImageAdjustments {
78
+ /** Brightness multiplier — 1 neutral, 0 black, > 1 brighter. */
79
+ brightness: number;
80
+ /** Contrast multiplier — 1 neutral, 0 solid grey, > 1 punchier. */
81
+ contrast: number;
82
+ /** Saturation multiplier — 1 neutral, 0 grayscale, > 1 more vivid. */
83
+ saturation: number;
84
+ }
66
85
  export interface ImageTransformData {
67
86
  type: 'image';
68
87
  width: number;
@@ -74,6 +93,8 @@ export interface ImageTransformData {
74
93
  flipHorizontal: boolean;
75
94
  flipVertical: boolean;
76
95
  borderRadius: number;
96
+ /** Brightness/contrast/saturation — omitted when neutral. See {@link ImageAdjustments}. */
97
+ adjustments?: ImageAdjustments;
77
98
  }
78
99
  export interface GroupTransformData {
79
100
  type: 'group';
@@ -82,6 +103,43 @@ export interface ArtboardTransformData {
82
103
  type: 'artboard';
83
104
  }
84
105
  export type ShapeType = 'rectangle' | 'circle' | 'ellipse' | 'triangle' | 'polygon' | 'star' | 'line';
106
+ /** One color stop on a gradient fill. `offset` is 0..1 along the gradient line. */
107
+ export interface GradientStop {
108
+ offset: number;
109
+ color: string;
110
+ }
111
+ /**
112
+ * Shape fill — a discriminated union so an invalid mix (e.g. a "gradient
113
+ * enabled" flag with no stops) is unrepresentable.
114
+ *
115
+ * - `solid` — a single CSS color.
116
+ * - `linear` — CSS-like angle semantics: `0` = up (bottom → top),
117
+ * `90` = right (left → right), increasing clockwise. The gradient line is
118
+ * sized to the shape's local bounds exactly like CSS `linear-gradient`
119
+ * (line length = |w·sin θ| + |h·cos θ|), so offset 0/1 land on the
120
+ * shape's edges at every angle.
121
+ * - `radial` — centered on the shape, radius = farthest corner
122
+ * (√(w² + h²) / 2), matching CSS `radial-gradient(circle farthest-corner)`.
123
+ *
124
+ * Gradients need ≥ 2 stops with offsets in 0..1 — violations throw
125
+ * `E_INVALID_FILL` at every write boundary (constructor, `updateElement`
126
+ * patch), dev AND prod.
127
+ *
128
+ * Back-compat: when `fill` is absent, the legacy `fillColor` string renders
129
+ * as a solid fill (it is the wire format of every saved design). When both
130
+ * are present, `fill` wins.
131
+ */
132
+ export type ShapeFill = {
133
+ type: 'solid';
134
+ color: string;
135
+ } | {
136
+ type: 'linear';
137
+ angle: number;
138
+ stops: GradientStop[];
139
+ } | {
140
+ type: 'radial';
141
+ stops: GradientStop[];
142
+ };
85
143
  export interface ShapeTransformData {
86
144
  type: 'shape';
87
145
  shapeType: ShapeType;
@@ -93,8 +151,17 @@ export interface ShapeTransformData {
93
151
  sides?: number;
94
152
  points?: number;
95
153
  innerRadius?: number;
154
+ /**
155
+ * Legacy solid fill color. Still the default write path for solid fills;
156
+ * ignored when `fill` is present.
157
+ */
96
158
  fillColor?: string;
97
159
  fillOpacity?: number;
160
+ /**
161
+ * Rich fill (solid or gradient). Wins over `fillColor` when present —
162
+ * see {@link ShapeFill} for angle/geometry semantics and validation.
163
+ */
164
+ fill?: ShapeFill;
98
165
  }
99
166
  /**
100
167
  * Path point types define how curve handles behave
@@ -154,7 +221,16 @@ export interface TransformStartData {
154
221
  childrenStartData?: TransformStartData[];
155
222
  [key: string]: unknown;
156
223
  }
157
- export type BlendMode = 'normal' | 'knockout' | 'clip';
224
+ /**
225
+ * Standard blend modes — map 1:1 to canvas `globalCompositeOperation` values.
226
+ * The element composites AS A UNIT onto the layers below it (Photoshop layer
227
+ * semantics), handled by LayerEffectsRenderer in both the live renderer and
228
+ * the export worker.
229
+ */
230
+ export type StandardBlendMode = 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten';
231
+ /** All standard blend modes, in UI display order. */
232
+ export declare const STANDARD_BLEND_MODES: readonly StandardBlendMode[];
233
+ export type BlendMode = 'normal' | 'knockout' | 'clip' | StandardBlendMode;
158
234
  export type CompositingScope = 'group' | 'artboard';
159
235
  export type KnockoutScope = CompositingScope;
160
236
  export interface CompositingConfig {
@@ -174,6 +250,25 @@ export interface StrokeConfig {
174
250
  opacity?: number;
175
251
  feather?: number;
176
252
  }
253
+ /**
254
+ * Drop shadow cast by an element's final silhouette (after masks, stroke,
255
+ * distress). All distances are WORLD-SPACE pixels — the shadow scales with
256
+ * canvas zoom and export resolution exactly like the element content does
257
+ * (it is artwork, not zoom-invariant chrome).
258
+ */
259
+ export interface ShadowConfig {
260
+ enabled: boolean;
261
+ /** Any CSS color (hex, rgb(a), named). Alpha multiplies with `opacity`. */
262
+ color: string;
263
+ /** Blur radius in world-space px (>= 0) */
264
+ blur: number;
265
+ /** Horizontal offset in world-space px (positive = right) */
266
+ offsetX: number;
267
+ /** Vertical offset in world-space px (positive = down) */
268
+ offsetY: number;
269
+ /** Shadow strength 0-1 (default 1), multiplies the color's own alpha */
270
+ opacity?: number;
271
+ }
177
272
  /**
178
273
  * Rendering context metadata passed to renderers
179
274
  * Used to customize rendering behavior for specific contexts (e.g., knockout, export, preview)
@@ -439,6 +534,7 @@ export interface BaseElementConfig {
439
534
  stroke?: StrokeConfig;
440
535
  masks?: MaskDefinition[];
441
536
  distressEffect?: DistressEffect;
537
+ shadow?: ShadowConfig;
442
538
  name?: string;
443
539
  visible?: boolean;
444
540
  locked?: boolean;
@@ -767,6 +863,14 @@ export declare function isPathTransform(data: AnyTransformData): data is PathTra
767
863
  export declare function hasStroke(config: AnyElementConfig): boolean;
768
864
  export declare function hasMasks(config: AnyElementConfig): boolean;
769
865
  export declare function isKnockout(config: AnyElementConfig): boolean;
866
+ /**
867
+ * Standard blend mode type guard. Narrows a BlendMode (or raw string from
868
+ * serialized JSON) to the modes that map 1:1 onto globalCompositeOperation.
869
+ * 'normal', 'knockout', 'clip' and undefined are all NOT standard blend modes
870
+ * — knockout/clip keep their special compositing path untouched.
871
+ */
872
+ export declare function isStandardBlendMode(mode: BlendMode | string | undefined | null): mode is StandardBlendMode;
873
+ export declare function hasShadow(config: AnyElementConfig): boolean;
770
874
  export declare function hasDistressEffect(config: AnyElementConfig): boolean;
771
875
  /**
772
876
  * Categories of errors that can occur within the canvas.
@@ -16,7 +16,8 @@ export type { TransformType, AnyTransformData, CustomTransformData, DistortTrans
16
16
  export type { AnyElementConfig, BaseElementConfig, BaseTextElementConfig, TextOnlyElementConfig, CustomElementConfig, DistortElementConfig, CircleElementConfig, LeanElementConfig, ArchElementConfig, AscendElementConfig, WaveElementConfig, FlagElementConfig, ImageElementConfig, GroupElementConfig, ShapeElementConfig, PathElementConfig, } from './index.js';
17
17
  export type { ArtboardConfig as ArtboardElementConfig, ArtboardBackgroundType, ClipShape, } from './index.js';
18
18
  export type { BoundingBox, Point, ResizeAnchor, } from './index.js';
19
- export type { BlendMode, KnockoutScope, KnockoutConfig, StrokeConfig, MaskType, MaskDefinition, DistressStyle, DistressEffect, } from './index.js';
19
+ export type { BlendMode, StandardBlendMode, KnockoutScope, KnockoutConfig, StrokeConfig, ShadowConfig, MaskType, MaskDefinition, DistressStyle, DistressEffect, } from './index.js';
20
+ export { STANDARD_BLEND_MODES } from './index.js';
20
21
  export type { TextAlign, CharacterStyle, TextSpan, GlyphOverride, GlyphAlternate, OpenTypeFeatures, } from './index.js';
21
22
  export { RichText } from './index.js';
22
23
  export type { ShapeType, } from './index.js';
@@ -27,5 +28,5 @@ export type { CanvasError, CanvasErrorCategory, } from './index.js';
27
28
  export type { Theme } from '../contexts/ThemeContext.js';
28
29
  export { isTextElementConfig, isImageElementConfig, isCustomElementConfig, isCircleElementConfig, isLeanElementConfig, isArchElementConfig, isAscendElementConfig, isWaveElementConfig, isFlagElementConfig, isGroupElementConfig, isShapeElementConfig, isPathElementConfig, } from './index.js';
29
30
  export { isCustomTransform, isDistortTransform, isCircleTransform, isLeanTransform, isArchTransform, isAscendTransform, isWaveTransform, isFlagTransform, isImageTransform, isGroupTransform, isArtboardTransform, isShapeTransform, isPathTransform, } from './index.js';
30
- export { hasStroke, hasMasks, isKnockout, hasDistressEffect, } from './index.js';
31
+ export { hasStroke, hasMasks, isKnockout, hasDistressEffect, hasShadow, isStandardBlendMode, } from './index.js';
31
32
  export { isTextElement, isImageElement, isGroupElement, isShapeElement, isPathElement, } from './guards.js';