@nmmty/lazycanvas 1.0.0-dev.4 → 1.0.0-dev.7

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 (33) hide show
  1. package/dist/core/Scene.d.ts +4 -6
  2. package/dist/core/Scene.js +6 -22
  3. package/dist/jsx-runtime.js +1 -1
  4. package/dist/structures/LazyCanvas.d.ts +2 -0
  5. package/dist/structures/LazyCanvas.js +2 -0
  6. package/dist/structures/components/BaseLayer.d.ts +40 -28
  7. package/dist/structures/components/BaseLayer.js +45 -12
  8. package/dist/structures/components/BezierLayer.d.ts +10 -2
  9. package/dist/structures/components/BezierLayer.js +3 -3
  10. package/dist/structures/components/Div.d.ts +10 -7
  11. package/dist/structures/components/Div.js +18 -3
  12. package/dist/structures/components/ImageLayer.js +2 -2
  13. package/dist/structures/components/LineLayer.d.ts +10 -2
  14. package/dist/structures/components/LineLayer.js +3 -3
  15. package/dist/structures/components/MorphLayer.d.ts +1 -1
  16. package/dist/structures/components/MorphLayer.js +5 -5
  17. package/dist/structures/components/Path2DLayer.d.ts +4 -4
  18. package/dist/structures/components/Path2DLayer.js +10 -12
  19. package/dist/structures/components/PolygonLayer.d.ts +1 -1
  20. package/dist/structures/components/PolygonLayer.js +5 -5
  21. package/dist/structures/components/QuadraticLayer.d.ts +10 -2
  22. package/dist/structures/components/QuadraticLayer.js +3 -3
  23. package/dist/structures/components/TextLayer.d.ts +1 -1
  24. package/dist/structures/components/TextLayer.js +33 -12
  25. package/dist/structures/helpers/readers/JSONReader.js +13 -13
  26. package/dist/structures/managers/LayoutManager.d.ts +23 -0
  27. package/dist/structures/managers/LayoutManager.js +409 -0
  28. package/dist/structures/managers/RenderManager.d.ts +1 -0
  29. package/dist/structures/managers/RenderManager.js +35 -2
  30. package/dist/types/types.d.ts +25 -0
  31. package/dist/utils/utils.js +11 -7
  32. package/package.json +3 -2
  33. package/biome.json +0 -41
@@ -28,7 +28,7 @@ class Path2DLayer extends BaseLayer_1.BaseLayer {
28
28
  throw new LazyUtil_1.LazyError("The color of the layer must be provided");
29
29
  if (!(0, utils_1.isColor)(color))
30
30
  throw new LazyUtil_1.LazyError("The color of the layer must be a valid color");
31
- this.props.fillStyle = color;
31
+ this.props.color = color;
32
32
  return this;
33
33
  }
34
34
  setPath(path) {
@@ -136,6 +136,12 @@ class Path2DLayer extends BaseLayer_1.BaseLayer {
136
136
  async draw(ctx, canvas, manager, debug) {
137
137
  ctx.beginPath();
138
138
  ctx.save();
139
+ if (debug)
140
+ LazyUtil_1.LazyLog.log("none", `Drawing Path2D Layer: `, {
141
+ layerId: this.id,
142
+ type: this.type,
143
+ path: this.props.path2D.toSVGString(),
144
+ });
139
145
  if (this.props.transform) {
140
146
  (0, utils_1.transform)(ctx, this.props.transform, { width: 0, height: 0, x: 0, y: 0, type: this.type });
141
147
  }
@@ -143,8 +149,8 @@ class Path2DLayer extends BaseLayer_1.BaseLayer {
143
149
  if (this.props.clipPath) {
144
150
  ctx.clip(this.props.path2D);
145
151
  }
146
- else if (this.props.fillStyle) {
147
- let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.fillStyle, { debug, manager });
152
+ else if (this.props.color) {
153
+ let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.color, { debug, manager });
148
154
  if (this.props.globalComposite) {
149
155
  ctx.globalCompositeOperation = this.props.globalComposite;
150
156
  }
@@ -182,16 +188,8 @@ class Path2DLayer extends BaseLayer_1.BaseLayer {
182
188
  validateProps(data) {
183
189
  return {
184
190
  ...super.validateProps(data),
185
- fillStyle: data.fillStyle || "#000000",
191
+ color: data.color || "#000000",
186
192
  path2D: data.path2D || new canvas_1.Path2D(),
187
- stroke: {
188
- width: data.stroke?.width || 1,
189
- cap: data.stroke?.cap || "butt",
190
- join: data.stroke?.join || "miter",
191
- dashOffset: data.stroke?.dashOffset || 0,
192
- dash: data.stroke?.dash || [],
193
- miterLimit: data.stroke?.miterLimit || 10,
194
- },
195
193
  loadFromSVG: data.loadFromSVG || false,
196
194
  clipPath: data.clipPath || false,
197
195
  };
@@ -37,7 +37,7 @@ export interface IPolygonLayerProps extends IBaseLayerProps {
37
37
  /**
38
38
  * The fill style (color or pattern) of the layer.
39
39
  */
40
- fillStyle: ColorType;
40
+ color: ColorType;
41
41
  /**
42
42
  * The stroke properties of the polygon.
43
43
  */
@@ -40,7 +40,7 @@ class PolygonLayer extends BaseLayer_1.BaseLayer {
40
40
  throw new LazyUtil_1.LazyError("The color of the layer must be provided");
41
41
  if (!(0, utils_1.isColor)(color))
42
42
  throw new LazyUtil_1.LazyError("The color of the layer must be a valid color");
43
- this.props.fillStyle = color;
43
+ this.props.color = color;
44
44
  return this;
45
45
  }
46
46
  /**
@@ -74,13 +74,13 @@ class PolygonLayer extends BaseLayer_1.BaseLayer {
74
74
  async draw(ctx, canvas, manager, debug) {
75
75
  const parcer = (0, utils_1.parser)(ctx, canvas, manager);
76
76
  const { xs, ys, w } = parcer.parseBatch({
77
- xs: { v: this.props.position.x },
78
- ys: { v: this.props.position.y, options: LazyUtil_1.defaultArg.vl(true) },
77
+ xs: { v: this.props.position?.x || 0 },
78
+ ys: { v: this.props.position?.y || 0, options: LazyUtil_1.defaultArg.vl(true) },
79
79
  w: { v: this.props.size.width },
80
80
  });
81
81
  const h = parcer.parse(this.props.size.height, LazyUtil_1.defaultArg.wh(w), LazyUtil_1.defaultArg.vl(true));
82
82
  let { x, y } = (0, utils_1.centring)(this.props.centring, this.type, w, h, xs, ys);
83
- let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.fillStyle, {
83
+ let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.color, {
84
84
  debug,
85
85
  layer: { width: w, height: h, x: xs, y: ys, align: this.props.centring },
86
86
  manager,
@@ -198,7 +198,7 @@ class PolygonLayer extends BaseLayer_1.BaseLayer {
198
198
  radius: data.size?.radius || 0,
199
199
  count: data.size?.count || 3,
200
200
  },
201
- fillStyle: data.fillStyle || "#000000",
201
+ color: data.color || "#000000",
202
202
  };
203
203
  }
204
204
  }
@@ -19,7 +19,15 @@ export interface IQuadraticLayer extends IBaseLayer {
19
19
  * Interface representing the properties of a Quadratic layer.
20
20
  */
21
21
  export interface IQuadraticLayerProps extends IBaseLayerProps {
22
- position: IBaseLayerProps["position"] & {
22
+ position: {
23
+ /**
24
+ * The x coordinate of the quadratic curve's starting point.
25
+ */
26
+ x: ScaleType;
27
+ /**
28
+ * The y coordinate of the quadratic curve's starting point.
29
+ */
30
+ y: ScaleType;
23
31
  /**
24
32
  * The end x coordinate of the quadratic curve.
25
33
  */
@@ -40,7 +48,7 @@ export interface IQuadraticLayerProps extends IBaseLayerProps {
40
48
  /**
41
49
  * The fill style (color or pattern) of the layer.
42
50
  */
43
- fillStyle: ColorType;
51
+ color: ColorType;
44
52
  /**
45
53
  * The stroke properties of the quadratic curve.
46
54
  */
@@ -53,7 +53,7 @@ class QuadraticLayer extends BaseLayer_1.BaseLayer {
53
53
  throw new LazyUtil_1.LazyError("The color of the layer must be provided");
54
54
  if (!(0, utils_1.isColor)(color))
55
55
  throw new LazyUtil_1.LazyError("The color of the layer must be a valid color");
56
- this.props.fillStyle = color;
56
+ this.props.color = color;
57
57
  return this;
58
58
  }
59
59
  /**
@@ -123,7 +123,7 @@ class QuadraticLayer extends BaseLayer_1.BaseLayer {
123
123
  { x: cx, y: cy },
124
124
  { x: xe, y: ye },
125
125
  ]);
126
- let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.fillStyle, {
126
+ let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.color, {
127
127
  debug,
128
128
  layer: { width, height, x: min.x, y: min.y, align: "none" },
129
129
  manager,
@@ -200,7 +200,7 @@ class QuadraticLayer extends BaseLayer_1.BaseLayer {
200
200
  endX: data.position?.endX || 0,
201
201
  endY: data.position?.endY || 0,
202
202
  },
203
- fillStyle: data.fillStyle || "#000000",
203
+ color: data.color || "#000000",
204
204
  centring: data.centring || types_1.Centring.None,
205
205
  controlPoints: data.controlPoints || [{ x: 0, y: 0 }],
206
206
  stroke: {
@@ -26,7 +26,7 @@ export interface ITextLayerProps extends IBaseLayerProps {
26
26
  /**
27
27
  * The fill style (color or pattern) of the layer.
28
28
  */
29
- fillStyle: ColorType;
29
+ color: ColorType;
30
30
  /**
31
31
  * Array of substring color configurations for partial text coloring.
32
32
  */
@@ -88,7 +88,7 @@ class TextLayer extends BaseLayer_1.BaseLayer {
88
88
  throw new LazyUtil_1.LazyError("The color of the layer must be provided");
89
89
  if (!(0, utils_1.isColor)(color))
90
90
  throw new LazyUtil_1.LazyError("The color of the layer must be a valid color");
91
- this.props.fillStyle = color;
91
+ this.props.color = color;
92
92
  if (sub && sub.length > 0) {
93
93
  this.props.subStringColors = sub;
94
94
  }
@@ -167,13 +167,32 @@ class TextLayer extends BaseLayer_1.BaseLayer {
167
167
  * @returns {Object} The width and height of the text.
168
168
  */
169
169
  measureText(ctx, canvas) {
170
+ ctx.font = `${this.props.font.weight} ${this.props.font.size}px ${this.props.font.family}`;
170
171
  if (this.props?.multiline?.enabled) {
171
172
  const w = (0, utils_1.parseToNormal)(this.props.size?.width || "vw", ctx, canvas);
172
- const h = (0, utils_1.parseToNormal)(this.props.size?.height || 0, ctx, canvas, { width: w, height: 0 }, { vertical: true });
173
- return { width: w, height: h };
173
+ // Calculate actual height based on text wrapping
174
+ const words = this.props.text.split(" ");
175
+ let line = "";
176
+ let linesCount = 1;
177
+ for (let word of words) {
178
+ let linePlus = line + word + " ";
179
+ if (ctx.measureText(linePlus).width > w) {
180
+ linesCount++;
181
+ line = word + " ";
182
+ }
183
+ else {
184
+ line = linePlus;
185
+ }
186
+ }
187
+ const lineHeight = this.props.font.size * (this.props.multiline.spacing || 1.1);
188
+ const calculatedHeight = linesCount * lineHeight;
189
+ // If height is fixed in props, use it, otherwise use calculated height
190
+ const fixedHeight = this.props.size?.height
191
+ ? (0, utils_1.parseToNormal)(this.props.size.height, ctx, canvas, { width: w, height: 0 }, { vertical: true })
192
+ : 0;
193
+ return { width: w, height: fixedHeight || calculatedHeight };
174
194
  }
175
195
  else {
176
- ctx.font = `${this.props.font.weight} ${this.props.font.size}px ${this.props.font.family}`;
177
196
  let data = ctx.measureText(this.props.text);
178
197
  return { width: data.width, height: this.props.font.size };
179
198
  }
@@ -188,8 +207,8 @@ class TextLayer extends BaseLayer_1.BaseLayer {
188
207
  async draw(ctx, canvas, manager, debug) {
189
208
  const parcer = (0, utils_1.parser)(ctx, canvas, manager);
190
209
  const { x, y, w } = parcer.parseBatch({
191
- x: { v: this.props.position.x },
192
- y: { v: this.props.position.y, options: LazyUtil_1.defaultArg.vl(true) },
210
+ x: { v: this.props.position?.x || 0 },
211
+ y: { v: this.props.position?.y || 0, options: LazyUtil_1.defaultArg.vl(true) },
193
212
  w: { v: this.props.size?.width || "vw" },
194
213
  });
195
214
  const h = parcer.parse(this.props.size?.height || 0, LazyUtil_1.defaultArg.wh(w), LazyUtil_1.defaultArg.vl(true));
@@ -208,16 +227,18 @@ class TextLayer extends BaseLayer_1.BaseLayer {
208
227
  DrawUtils_1.DrawUtils.drawShadow(ctx, this.props.shadow);
209
228
  DrawUtils_1.DrawUtils.opacity(ctx, this.props.opacity);
210
229
  DrawUtils_1.DrawUtils.filters(ctx, this.props.filter);
211
- ctx.textAlign = this.props.align;
230
+ // When layout is managed by Yoga, always use top-left alignment
231
+ // since Yoga calculates position as top-left corner
232
+ const useLayoutAlignment = this.props._computedLayout === true;
233
+ ctx.textAlign = useLayoutAlignment ? "left" : this.props.align;
212
234
  if (this.props.letterSpacing)
213
235
  ctx.letterSpacing = `${this.props.letterSpacing}px`;
214
236
  if (this.props.wordSpacing)
215
237
  ctx.wordSpacing = `${this.props.wordSpacing}px`;
216
- if (this.props.baseline)
217
- ctx.textBaseline = this.props.baseline;
238
+ ctx.textBaseline = useLayoutAlignment ? "top" : this.props.baseline || "alphabetic";
218
239
  if (this.props.direction)
219
240
  ctx.direction = this.props.direction;
220
- let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.fillStyle, {
241
+ let fillStyle = await (0, utils_1.parseFillStyle)(ctx, this.props.color, {
221
242
  debug,
222
243
  layer: { width: w, height: h, x, y, align: "center" },
223
244
  manager,
@@ -391,7 +412,7 @@ class TextLayer extends BaseLayer_1.BaseLayer {
391
412
  validateProps(data) {
392
413
  return {
393
414
  ...super.validateProps(data),
394
- fillStyle: data.fillStyle || "#000000",
415
+ color: data.color || "#000000",
395
416
  text: data.text || "",
396
417
  font: {
397
418
  family: data.font?.family || "Arial",
@@ -403,7 +424,7 @@ class TextLayer extends BaseLayer_1.BaseLayer {
403
424
  spacing: data.multiline?.spacing || 1.1,
404
425
  },
405
426
  size: {
406
- width: data.size?.width || "vw",
427
+ width: data.size?.width || 0,
407
428
  height: data.size?.height || 0,
408
429
  },
409
430
  align: data.align || types_1.TextAlign.Left,
@@ -115,7 +115,7 @@ class JSONReader {
115
115
  */
116
116
  static layerParse(layer, misc) {
117
117
  if (layer instanceof components_1.Div) {
118
- return new components_1.Div(misc).add(...layer.layers.map((l) => this.layerParse(l)));
118
+ return new components_1.Div({}, misc).add(...layer.layers.map((l) => this.layerParse(l)));
119
119
  }
120
120
  else {
121
121
  switch (layer.type) {
@@ -136,7 +136,7 @@ class JSONReader {
136
136
  case types_1.LayerType.Polygon:
137
137
  return new components_1.PolygonLayer(layer.props, misc).setColor(this.fillParse(layer));
138
138
  case types_1.LayerType.Group:
139
- return new components_1.Div(misc).add(...layer.layers.map((l) => this.layerParse(l)));
139
+ return new components_1.Div({}, misc).add(...layer.layers.map((l) => this.layerParse(l)));
140
140
  default:
141
141
  return layer;
142
142
  }
@@ -148,25 +148,25 @@ class JSONReader {
148
148
  * @returns {string | Gradient | Pattern} The parsed fill style.
149
149
  */
150
150
  static fillParse(layer) {
151
- if ("fillStyle" in layer.props) {
152
- if ((0, Signal_1.isSignal)(layer.props.fillStyle)) {
151
+ if ("color" in layer.props) {
152
+ if ((0, Signal_1.isSignal)(layer.props.color)) {
153
153
  throw new LazyUtil_1.LazyError("Signals are not supported in JSON fill styles");
154
154
  }
155
- if (typeof layer.props.fillStyle === "object") {
156
- switch (layer.props.fillStyle?.fillType) {
155
+ if (typeof layer.props.color === "object") {
156
+ switch (layer.props.color?.fillType) {
157
157
  case "gradient":
158
- return new __1.Gradient({ props: layer.props.fillStyle });
158
+ return new __1.Gradient({ props: layer.props.color });
159
159
  case "pattern":
160
160
  return new __1.Pattern()
161
- .setType(layer.props.fillStyle.type)
162
- .setSrc(typeof layer.props.fillStyle.src === "string"
163
- ? layer.props.fillStyle.src
164
- : this.read(layer.props.fillStyle.src));
161
+ .setType(layer.props.color.type)
162
+ .setSrc(typeof layer.props.color.src === "string"
163
+ ? layer.props.color.src
164
+ : this.read(layer.props.color.src));
165
165
  default:
166
- return layer.props.fillStyle;
166
+ return layer.props.color;
167
167
  }
168
168
  }
169
- return layer.props.fillStyle || "#000000";
169
+ return layer.props.color || "#000000";
170
170
  }
171
171
  else {
172
172
  return "#000000";
@@ -0,0 +1,23 @@
1
+ import { Div } from "../components";
2
+ import { AnyLayer } from "../../types";
3
+ import { SKRSContext2D, Canvas, SvgCanvas } from "@napi-rs/canvas";
4
+ export declare class LayoutManager {
5
+ private yoga;
6
+ private debug;
7
+ ready: Promise<void>;
8
+ constructor(opts?: {
9
+ debug?: boolean;
10
+ });
11
+ private init;
12
+ calculateLayout(root: AnyLayer | Div, width: number, height: number, ctx?: SKRSContext2D, canvas?: Canvas | SvgCanvas): void;
13
+ private createNode;
14
+ private applyLayout;
15
+ private freeNode;
16
+ private getFlexDirection;
17
+ private getJustifyContent;
18
+ private getAlignItems;
19
+ private getPositionType;
20
+ private setDimension;
21
+ private setPadding;
22
+ private setMargin;
23
+ }