@codehz/draw-call 0.5.0 → 0.5.2

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/browser/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1
2
 
2
3
  //#region src/compat/index.ts
3
4
  const DOMMatrix = typeof window !== "undefined" ? window.DOMMatrix : void 0;
@@ -82,6 +83,19 @@ function normalizeBorderRadius(value) {
82
83
 
83
84
  //#endregion
84
85
  //#region src/layout/components/box.ts
86
+ /**
87
+ * 安全获取元素的 margin
88
+ * Transform 元素没有 margin,返回默认 spacing
89
+ */
90
+ function getElementMargin$2(element) {
91
+ if (element.type === "transform") return {
92
+ top: 0,
93
+ right: 0,
94
+ bottom: 0,
95
+ left: 0
96
+ };
97
+ return normalizeSpacing(element.margin);
98
+ }
85
99
  function calcEffectiveSize(element, padding, availableWidth) {
86
100
  return {
87
101
  width: typeof element.width === "number" ? element.width - padding.left - padding.right : availableWidth > 0 ? availableWidth : 0,
@@ -91,7 +105,7 @@ function calcEffectiveSize(element, padding, availableWidth) {
91
105
  function collectChildSizes(children, ctx, availableWidth, padding, measureChild) {
92
106
  const childSizes = [];
93
107
  for (const child of children) {
94
- const childMargin = normalizeSpacing(child.margin);
108
+ const childMargin = getElementMargin$2(child);
95
109
  const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
96
110
  childSizes.push({
97
111
  width: childSize.width,
@@ -160,7 +174,7 @@ function measureBoxSize(element, ctx, availableWidth, measureChild) {
160
174
  contentHeight = wrapped.height;
161
175
  } else for (let i = 0; i < children.length; i++) {
162
176
  const child = children[i];
163
- const childMargin = normalizeSpacing(child.margin);
177
+ const childMargin = getElementMargin$2(child);
164
178
  const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
165
179
  if (isRow) {
166
180
  contentWidth += childSize.width + childMargin.left + childMargin.right;
@@ -394,6 +408,19 @@ function wrapRichText(ctx, spans, maxWidth, lineHeightScale = 1.2, elementStyle
394
408
  //#endregion
395
409
  //#region src/layout/components/stack.ts
396
410
  /**
411
+ * 安全获取元素的 margin
412
+ * Transform 元素没有 margin,返回默认 spacing
413
+ */
414
+ function getElementMargin$1(element) {
415
+ if (element.type === "transform") return {
416
+ top: 0,
417
+ right: 0,
418
+ bottom: 0,
419
+ left: 0
420
+ };
421
+ return normalizeSpacing(element.margin);
422
+ }
423
+ /**
397
424
  * 测量 Stack 元素的固有尺寸
398
425
  */
399
426
  function measureStackSize(element, ctx, availableWidth, measureChild) {
@@ -402,7 +429,7 @@ function measureStackSize(element, ctx, availableWidth, measureChild) {
402
429
  let contentHeight = 0;
403
430
  const children = element.children ?? [];
404
431
  for (const child of children) {
405
- const childMargin = normalizeSpacing(child.margin);
432
+ const childMargin = getElementMargin$1(child);
406
433
  const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
407
434
  contentWidth = Math.max(contentWidth, childSize.width + childMargin.left + childMargin.right);
408
435
  contentHeight = Math.max(contentHeight, childSize.height + childMargin.top + childMargin.bottom);
@@ -641,18 +668,79 @@ function sizeNeedsParent(size) {
641
668
 
642
669
  //#endregion
643
670
  //#region src/layout/engine.ts
671
+ /**
672
+ * 类型守卫:检查 Element 是否为 LayoutElement(非 Transform)
673
+ * 由于 Transform 元素在 computeLayoutImpl 开始时被处理,
674
+ * 此时只应处理 LayoutElement
675
+ */
676
+ function assertLayoutElement(element) {
677
+ if (element.type === "transform") throw new Error("Transform elements should be handled at entry point");
678
+ }
679
+ /**
680
+ * 安全获取元素的 margin
681
+ * Transform 元素没有 margin,返回默认 spacing
682
+ */
683
+ function getElementMargin(element) {
684
+ if (element.type === "transform") return {
685
+ top: 0,
686
+ right: 0,
687
+ bottom: 0,
688
+ left: 0
689
+ };
690
+ return normalizeSpacing(element.margin);
691
+ }
692
+ /**
693
+ * 安全获取元素的布局属性(width, height, flex等)
694
+ * Transform 元素这些属性为 undefined
695
+ */
696
+ function getElementLayoutProps(element) {
697
+ if (element.type === "transform") return {
698
+ width: void 0,
699
+ height: void 0,
700
+ flex: void 0,
701
+ minWidth: void 0,
702
+ maxWidth: void 0,
703
+ minHeight: void 0,
704
+ maxHeight: void 0,
705
+ alignSelf: void 0
706
+ };
707
+ const le = element;
708
+ return {
709
+ width: le.width,
710
+ height: le.height,
711
+ flex: le.flex,
712
+ minWidth: le.minWidth,
713
+ maxWidth: le.maxWidth,
714
+ minHeight: le.minHeight,
715
+ maxHeight: le.maxHeight,
716
+ alignSelf: le.alignSelf
717
+ };
718
+ }
719
+ /**
720
+ * 布局计算主函数
721
+ * 内部使用 Element 类型以支持 Transform,外部通过 LayoutElement 约束类型
722
+ */
644
723
  function computeLayout(element, ctx, constraints, x = 0, y = 0) {
645
- const margin = normalizeSpacing(element.margin);
646
- const padding = normalizeSpacing("padding" in element ? element.padding : void 0);
724
+ return computeLayoutImpl(element, ctx, constraints, x, y);
725
+ }
726
+ /**
727
+ * 内部实现函数,处理所有元素类型包括 Transform
728
+ */
729
+ function computeLayoutImpl(element, ctx, constraints, x = 0, y = 0) {
730
+ if (element.type === "transform") return computeLayoutImpl(element.children, ctx, constraints, x, y);
731
+ assertLayoutElement(element);
732
+ const layoutElement = element;
733
+ const margin = normalizeSpacing(layoutElement.margin);
734
+ const padding = normalizeSpacing("padding" in layoutElement ? layoutElement.padding : void 0);
647
735
  const availableWidth = constraints.maxWidth - margin.left - margin.right;
648
736
  const availableHeight = constraints.maxHeight - margin.top - margin.bottom;
649
- const intrinsic = measureIntrinsicSize(element, ctx, availableWidth);
650
- let width = constraints.minWidth === constraints.maxWidth && constraints.minWidth > 0 ? constraints.maxWidth - margin.left - margin.right : resolveSize(element.width, availableWidth, intrinsic.width);
651
- let height = constraints.minHeight === constraints.maxHeight && constraints.minHeight > 0 ? constraints.maxHeight - margin.top - margin.bottom : resolveSize(element.height, availableHeight, intrinsic.height);
652
- if (element.minWidth !== void 0) width = Math.max(width, element.minWidth);
653
- if (element.maxWidth !== void 0) width = Math.min(width, element.maxWidth);
654
- if (element.minHeight !== void 0) height = Math.max(height, element.minHeight);
655
- if (element.maxHeight !== void 0) height = Math.min(height, element.maxHeight);
737
+ const intrinsic = measureIntrinsicSize(layoutElement, ctx, availableWidth);
738
+ let width = constraints.minWidth === constraints.maxWidth && constraints.minWidth > 0 ? constraints.maxWidth - margin.left - margin.right : resolveSize(layoutElement.width, availableWidth, intrinsic.width);
739
+ let height = constraints.minHeight === constraints.maxHeight && constraints.minHeight > 0 ? constraints.maxHeight - margin.top - margin.bottom : resolveSize(layoutElement.height, availableHeight, intrinsic.height);
740
+ if (layoutElement.minWidth !== void 0) width = Math.max(width, layoutElement.minWidth);
741
+ if (layoutElement.maxWidth !== void 0) width = Math.min(width, layoutElement.maxWidth);
742
+ if (layoutElement.minHeight !== void 0) height = Math.max(height, layoutElement.minHeight);
743
+ if (layoutElement.maxHeight !== void 0) height = Math.min(height, layoutElement.maxHeight);
656
744
  const actualX = x + margin.left;
657
745
  const actualY = y + margin.top;
658
746
  const contentX = actualX + padding.left;
@@ -660,7 +748,7 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
660
748
  const contentWidth = width - padding.left - padding.right;
661
749
  const contentHeight = height - padding.top - padding.bottom;
662
750
  const node = {
663
- element,
751
+ element: layoutElement,
664
752
  layout: {
665
753
  x: actualX,
666
754
  y: actualY,
@@ -673,14 +761,14 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
673
761
  },
674
762
  children: []
675
763
  };
676
- if (element.type === "text") {
677
- const font = element.font ?? {};
678
- if (element.wrap && contentWidth > 0) {
679
- let { lines, offsets } = wrapText(ctx, element.content, contentWidth, font);
680
- if (element.maxLines && lines.length > element.maxLines) {
681
- lines = lines.slice(0, element.maxLines);
682
- offsets = offsets.slice(0, element.maxLines);
683
- if (element.ellipsis && lines.length > 0) {
764
+ if (layoutElement.type === "text") {
765
+ const font = layoutElement.font ?? {};
766
+ if (layoutElement.wrap && contentWidth > 0) {
767
+ let { lines, offsets } = wrapText(ctx, layoutElement.content, contentWidth, font);
768
+ if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
769
+ lines = lines.slice(0, layoutElement.maxLines);
770
+ offsets = offsets.slice(0, layoutElement.maxLines);
771
+ if (layoutElement.ellipsis && lines.length > 0) {
684
772
  const lastIdx = lines.length - 1;
685
773
  const truncated = truncateText(ctx, lines[lastIdx], contentWidth, font);
686
774
  lines[lastIdx] = truncated.text;
@@ -690,17 +778,17 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
690
778
  node.lines = lines;
691
779
  node.lineOffsets = offsets;
692
780
  } else {
693
- const { text, offset } = truncateText(ctx, element.content, contentWidth > 0 && element.ellipsis ? contentWidth : Infinity, font);
781
+ const { text, offset } = truncateText(ctx, layoutElement.content, contentWidth > 0 && layoutElement.ellipsis ? contentWidth : Infinity, font);
694
782
  node.lines = [text];
695
783
  node.lineOffsets = [offset];
696
784
  }
697
785
  }
698
- if (element.type === "richtext") {
699
- const lineHeight = element.lineHeight ?? 1.2;
700
- let lines = wrapRichText(ctx, element.spans, contentWidth, lineHeight);
701
- if (element.maxLines && lines.length > element.maxLines) {
702
- lines = lines.slice(0, element.maxLines);
703
- if (element.ellipsis && lines.length > 0) {
786
+ if (layoutElement.type === "richtext") {
787
+ const lineHeight = layoutElement.lineHeight ?? 1.2;
788
+ let lines = wrapRichText(ctx, layoutElement.spans, contentWidth, lineHeight);
789
+ if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
790
+ lines = lines.slice(0, layoutElement.maxLines);
791
+ if (layoutElement.ellipsis && lines.length > 0) {
704
792
  const lastLine = lines[lines.length - 1];
705
793
  if (lastLine.segments.length > 0) {
706
794
  const lastSeg = lastLine.segments[lastLine.segments.length - 1];
@@ -712,19 +800,19 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
712
800
  }
713
801
  node.richLines = lines;
714
802
  }
715
- if (element.type === "box" || element.type === "stack") {
716
- const children = element.children ?? [];
717
- if (element.type === "stack") {
718
- const stackAlign = element.align ?? "start";
719
- const stackJustify = element.justify ?? "start";
803
+ if (layoutElement.type === "box" || layoutElement.type === "stack") {
804
+ const children = layoutElement.children ?? [];
805
+ if (layoutElement.type === "stack") {
806
+ const stackAlign = layoutElement.align ?? "start";
807
+ const stackJustify = layoutElement.justify ?? "start";
720
808
  for (const child of children) {
721
- const childNode = computeLayout(child, ctx, {
809
+ const childNode = computeLayoutImpl(child, ctx, {
722
810
  minWidth: 0,
723
811
  maxWidth: contentWidth,
724
812
  minHeight: 0,
725
813
  maxHeight: contentHeight
726
814
  }, contentX, contentY);
727
- const childMargin = normalizeSpacing(child.margin);
815
+ const childMargin = getElementMargin(child);
728
816
  const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
729
817
  const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
730
818
  let offsetX = 0;
@@ -737,19 +825,21 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
737
825
  node.children.push(childNode);
738
826
  }
739
827
  } else {
740
- const direction = element.direction ?? "row";
741
- const justify = element.justify ?? "start";
742
- const align = element.align ?? "stretch";
743
- const gap = element.gap ?? 0;
744
- const wrap = element.wrap ?? false;
828
+ const boxElement = layoutElement;
829
+ const direction = boxElement.direction ?? "row";
830
+ const justify = boxElement.justify ?? "start";
831
+ const align = boxElement.align ?? "stretch";
832
+ const gap = boxElement.gap ?? 0;
833
+ const wrap = boxElement.wrap ?? false;
745
834
  const isRow = direction === "row" || direction === "row-reverse";
746
835
  const isReverse = direction === "row-reverse" || direction === "column-reverse";
747
836
  const getContentMainSize = () => isRow ? contentWidth : contentHeight;
748
837
  const getContentCrossSize = () => isRow ? contentHeight : contentWidth;
749
838
  const childInfos = [];
750
839
  for (const child of children) {
751
- const childMargin = normalizeSpacing(child.margin);
752
- const childFlex = child.flex ?? 0;
840
+ const childMargin = getElementMargin(child);
841
+ const childProps = getElementLayoutProps(child);
842
+ const childFlex = childProps.flex ?? 0;
753
843
  if (childFlex > 0) childInfos.push({
754
844
  element: child,
755
845
  width: 0,
@@ -759,10 +849,10 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
759
849
  });
760
850
  else {
761
851
  const size = measureIntrinsicSize(child, ctx, contentWidth - childMargin.left - childMargin.right);
762
- const shouldStretchWidth = !isRow && child.width === void 0 && align === "stretch";
763
- const shouldStretchHeight = isRow && child.height === void 0 && align === "stretch";
764
- let w = sizeNeedsParent(child.width) ? resolveSize(child.width, contentWidth - childMargin.left - childMargin.right, size.width) : resolveSize(child.width, 0, size.width);
765
- let h = sizeNeedsParent(child.height) ? resolveSize(child.height, contentHeight - childMargin.top - childMargin.bottom, size.height) : resolveSize(child.height, 0, size.height);
852
+ const shouldStretchWidth = !isRow && childProps.width === void 0 && align === "stretch";
853
+ const shouldStretchHeight = isRow && childProps.height === void 0 && align === "stretch";
854
+ let w = sizeNeedsParent(childProps.width) ? resolveSize(childProps.width, contentWidth - childMargin.left - childMargin.right, size.width) : resolveSize(childProps.width, 0, size.width);
855
+ let h = sizeNeedsParent(childProps.height) ? resolveSize(childProps.height, contentHeight - childMargin.top - childMargin.bottom, size.height) : resolveSize(childProps.height, 0, size.height);
766
856
  if (shouldStretchWidth && !wrap) w = contentWidth - childMargin.left - childMargin.right;
767
857
  if (shouldStretchHeight && !wrap) h = contentHeight - childMargin.top - childMargin.bottom;
768
858
  childInfos.push({
@@ -803,14 +893,15 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
803
893
  const availableForFlex = Math.max(0, mainAxisSize - totalFixed - totalGap);
804
894
  for (const info of lineInfos) if (info.flex > 0) {
805
895
  const flexSize = totalFlex > 0 ? availableForFlex * info.flex / totalFlex : 0;
896
+ const childProps = getElementLayoutProps(info.element);
806
897
  if (isRow) {
807
898
  info.width = flexSize;
808
899
  const size = measureIntrinsicSize(info.element, ctx, flexSize);
809
- info.height = sizeNeedsParent(info.element.height) ? resolveSize(info.element.height, contentHeight - info.margin.top - info.margin.bottom, size.height) : resolveSize(info.element.height, 0, size.height);
900
+ info.height = sizeNeedsParent(childProps.height) ? resolveSize(childProps.height, contentHeight - info.margin.top - info.margin.bottom, size.height) : resolveSize(childProps.height, 0, size.height);
810
901
  } else {
811
902
  info.height = flexSize;
812
903
  const size = measureIntrinsicSize(info.element, ctx, contentWidth - info.margin.left - info.margin.right);
813
- info.width = sizeNeedsParent(info.element.width) ? resolveSize(info.element.width, contentWidth - info.margin.left - info.margin.right, size.width) : resolveSize(info.element.width, 0, size.width);
904
+ info.width = sizeNeedsParent(childProps.width) ? resolveSize(childProps.width, contentWidth - info.margin.left - info.margin.right, size.width) : resolveSize(childProps.width, 0, size.width);
814
905
  }
815
906
  }
816
907
  }
@@ -861,17 +952,18 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
861
952
  const orderedInfos = isReverse ? [...lineInfos].reverse() : lineInfos;
862
953
  for (let i = 0; i < orderedInfos.length; i++) {
863
954
  const info = orderedInfos[i];
955
+ const childProps = getElementLayoutProps(info.element);
864
956
  const crossAxisSize = wrap ? lineCrossSize : getContentCrossSize();
865
957
  const childCrossSize = isRow ? info.height + info.margin.top + info.margin.bottom : info.width + info.margin.left + info.margin.right;
866
958
  let itemCrossOffset = 0;
867
- const effectiveAlign = info.element.alignSelf ?? align;
959
+ const effectiveAlign = childProps.alignSelf ?? align;
868
960
  if (effectiveAlign === "start") itemCrossOffset = 0;
869
961
  else if (effectiveAlign === "end") itemCrossOffset = crossAxisSize - childCrossSize;
870
962
  else if (effectiveAlign === "center") itemCrossOffset = (crossAxisSize - childCrossSize) / 2;
871
963
  else if (effectiveAlign === "stretch") {
872
964
  itemCrossOffset = 0;
873
- if (isRow && info.element.height === void 0) info.height = crossAxisSize - info.margin.top - info.margin.bottom;
874
- else if (!isRow && info.element.width === void 0) info.width = crossAxisSize - info.margin.left - info.margin.right;
965
+ if (isRow && childProps.height === void 0) info.height = crossAxisSize - info.margin.top - info.margin.bottom;
966
+ else if (!isRow && childProps.width === void 0) info.width = crossAxisSize - info.margin.left - info.margin.right;
875
967
  }
876
968
  const childX = isRow ? contentX + mainOffset + info.margin.left : contentX + crossOffset + itemCrossOffset + info.margin.left;
877
969
  const childY = isRow ? contentY + crossOffset + itemCrossOffset + info.margin.top : contentY + mainOffset + info.margin.top;
@@ -880,26 +972,29 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
880
972
  let minHeight = 0;
881
973
  let maxHeight = info.height;
882
974
  let shouldStretchCross = false;
883
- if (info.flex > 0) if (isRow) {
884
- minWidth = maxWidth = info.width;
885
- if (info.element.height === void 0 && align === "stretch") {
886
- minHeight = info.height;
887
- maxHeight = element.height !== void 0 ? info.height : Infinity;
888
- shouldStretchCross = true;
975
+ if (info.flex > 0) {
976
+ const childProps = getElementLayoutProps(info.element);
977
+ if (isRow) {
978
+ minWidth = maxWidth = info.width;
979
+ if (childProps.height === void 0 && align === "stretch") {
980
+ minHeight = info.height;
981
+ maxHeight = boxElement.height !== void 0 ? info.height : Infinity;
982
+ shouldStretchCross = true;
983
+ }
984
+ } else {
985
+ minHeight = maxHeight = info.height;
986
+ if (childProps.width === void 0 && align === "stretch") {
987
+ minWidth = info.width;
988
+ maxWidth = boxElement.width !== void 0 ? info.width : Infinity;
989
+ shouldStretchCross = true;
990
+ }
889
991
  }
890
992
  } else {
891
- minHeight = maxHeight = info.height;
892
- if (info.element.width === void 0 && align === "stretch") {
893
- minWidth = info.width;
894
- maxWidth = element.width !== void 0 ? info.width : Infinity;
895
- shouldStretchCross = true;
896
- }
993
+ const childProps = getElementLayoutProps(info.element);
994
+ if (!isRow && childProps.width === void 0 && align === "stretch") minWidth = maxWidth = crossAxisSize - info.margin.left - info.margin.right;
995
+ if (isRow && childProps.height === void 0 && align === "stretch") minHeight = maxHeight = crossAxisSize - info.margin.top - info.margin.bottom;
897
996
  }
898
- else {
899
- if (!isRow && info.element.width === void 0 && align === "stretch") minWidth = maxWidth = crossAxisSize - info.margin.left - info.margin.right;
900
- if (isRow && info.element.height === void 0 && align === "stretch") minHeight = maxHeight = crossAxisSize - info.margin.top - info.margin.bottom;
901
- }
902
- const childNode = computeLayout(info.element, ctx, {
997
+ const childNode = computeLayoutImpl(info.element, ctx, {
903
998
  minWidth,
904
999
  maxWidth,
905
1000
  minHeight,
@@ -922,12 +1017,12 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
922
1017
  crossOffset += lineCrossSize;
923
1018
  if (lineIndex < lines.length - 1) crossOffset += gap;
924
1019
  }
925
- if (wrap && element.height === void 0 && isRow) {
1020
+ if (wrap && boxElement.height === void 0 && isRow) {
926
1021
  const actualContentHeight = crossOffset;
927
1022
  const actualHeight = actualContentHeight + padding.top + padding.bottom;
928
1023
  node.layout.height = actualHeight;
929
1024
  node.layout.contentHeight = actualContentHeight;
930
- } else if (wrap && element.width === void 0 && !isRow) {
1025
+ } else if (wrap && boxElement.width === void 0 && !isRow) {
931
1026
  const actualContentWidth = crossOffset;
932
1027
  const actualWidth = actualContentWidth + padding.left + padding.right;
933
1028
  node.layout.width = actualWidth;
@@ -936,7 +1031,7 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
936
1031
  if (!wrap) {
937
1032
  let maxChildCrossSize = 0;
938
1033
  for (const childNode of node.children) {
939
- const childMargin = normalizeSpacing(childNode.element.margin);
1034
+ const childMargin = getElementMargin(childNode.element);
940
1035
  if (isRow) {
941
1036
  const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
942
1037
  maxChildCrossSize = Math.max(maxChildCrossSize, childOuterHeight);
@@ -945,13 +1040,13 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
945
1040
  maxChildCrossSize = Math.max(maxChildCrossSize, childOuterWidth);
946
1041
  }
947
1042
  }
948
- if (isRow && element.height === void 0) {
1043
+ if (isRow && boxElement.height === void 0) {
949
1044
  const actualHeight = maxChildCrossSize + padding.top + padding.bottom;
950
1045
  if (actualHeight > node.layout.height) {
951
1046
  node.layout.height = actualHeight;
952
1047
  node.layout.contentHeight = maxChildCrossSize;
953
1048
  }
954
- } else if (!isRow && element.width === void 0) {
1049
+ } else if (!isRow && boxElement.width === void 0) {
955
1050
  const actualWidth = maxChildCrossSize + padding.left + padding.right;
956
1051
  if (actualWidth > node.layout.width) {
957
1052
  node.layout.width = actualWidth;
@@ -961,48 +1056,24 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
961
1056
  }
962
1057
  if (isReverse) node.children.reverse();
963
1058
  }
964
- } else if (element.type === "transform") {
965
- const child = element.children;
966
- if (child) {
967
- const childMargin = normalizeSpacing(child.margin);
968
- const childNode = computeLayout(child, ctx, {
969
- minWidth: 0,
970
- maxWidth: contentWidth,
971
- minHeight: 0,
972
- maxHeight: contentHeight
973
- }, contentX, contentY);
974
- node.children.push(childNode);
975
- if (element.width === void 0) {
976
- const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
977
- const actualWidth = childOuterWidth + padding.left + padding.right;
978
- node.layout.width = actualWidth;
979
- node.layout.contentWidth = childOuterWidth;
980
- }
981
- if (element.height === void 0) {
982
- const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
983
- const actualHeight = childOuterHeight + padding.top + padding.bottom;
984
- node.layout.height = actualHeight;
985
- node.layout.contentHeight = childOuterHeight;
986
- }
987
- }
988
- } else if (element.type === "customdraw") {
989
- const child = element.children;
1059
+ } else if (layoutElement.type === "customdraw") {
1060
+ const child = layoutElement.children;
990
1061
  if (child) {
991
1062
  const childMargin = normalizeSpacing(child.margin);
992
- const childNode = computeLayout(child, ctx, {
1063
+ const childNode = computeLayoutImpl(child, ctx, {
993
1064
  minWidth: 0,
994
1065
  maxWidth: contentWidth,
995
1066
  minHeight: 0,
996
1067
  maxHeight: contentHeight
997
1068
  }, contentX, contentY);
998
1069
  node.children.push(childNode);
999
- if (element.width === void 0) {
1070
+ if (layoutElement.width === void 0) {
1000
1071
  const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
1001
1072
  const actualWidth = childOuterWidth + padding.left + padding.right;
1002
1073
  node.layout.width = actualWidth;
1003
1074
  node.layout.contentWidth = childOuterWidth;
1004
1075
  }
1005
- if (element.height === void 0) {
1076
+ if (layoutElement.height === void 0) {
1006
1077
  const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
1007
1078
  const actualHeight = childOuterHeight + padding.top + padding.bottom;
1008
1079
  node.layout.height = actualHeight;
@@ -2012,10 +2083,12 @@ function getElementType(element) {
2012
2083
  switch (element.type) {
2013
2084
  case "box": return "Box";
2014
2085
  case "text": return `Text "${element.content.slice(0, 20)}${element.content.length > 20 ? "..." : ""}"`;
2086
+ case "richtext": return "RichText";
2015
2087
  case "stack": return "Stack";
2016
2088
  case "image": return "Image";
2017
2089
  case "svg": return "Svg";
2018
- default: return element.type;
2090
+ case "transform": return "Transform";
2091
+ case "customdraw": return "CustomDraw";
2019
2092
  }
2020
2093
  }
2021
2094
  /**
@@ -363,7 +363,8 @@ interface CustomDrawProps extends LayoutProps {
363
363
  interface CustomDrawElement extends ElementBase, CustomDrawProps {
364
364
  type: "customdraw";
365
365
  }
366
- type Element = BoxElement | TextElement | RichTextElement | ImageElement | SvgElement | StackElement | TransformElement | CustomDrawElement;
366
+ type LayoutElement = BoxElement | TextElement | RichTextElement | ImageElement | SvgElement | StackElement | CustomDrawElement;
367
+ type Element = LayoutElement | TransformElement;
367
368
  //#endregion
368
369
  //#region node_modules/@napi-rs/canvas/index.d.ts
369
370
  interface CanvasRenderingContext2D$1 extends CanvasCompositing, CanvasDrawPath, CanvasFillStrokeStyles, CanvasFilters, CanvasImageData, CanvasImageSmoothing, CanvasPath, CanvasPathDrawingStyles, CanvasRect, CanvasSettings, CanvasShadowStyles, CanvasState, CanvasText, CanvasTextDrawingStyles, CanvasTransform, CanvasPDFAnnotations {}
@@ -926,7 +927,7 @@ interface DrawCallCanvas<T extends HTMLCanvasElement | OffscreenCanvas | Canvas
926
927
  readonly height: number;
927
928
  readonly pixelRatio: number;
928
929
  readonly canvas: T;
929
- render(element: Element): LayoutNode;
930
+ render(element: LayoutElement): LayoutNode;
930
931
  clear(): void;
931
932
  getContext(): CanvasRenderingContext2D;
932
933
  toDataURL(type?: string, quality?: number): string;
@@ -975,7 +976,11 @@ declare function Text(props: TextProps): TextElement;
975
976
  declare function Transform(props: TransformProps): TransformElement;
976
977
  //#endregion
977
978
  //#region src/layout/engine.d.ts
978
- declare function computeLayout(element: Element, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
979
+ /**
980
+ * 布局计算主函数
981
+ * 内部使用 Element 类型以支持 Transform,外部通过 LayoutElement 约束类型
982
+ */
983
+ declare function computeLayout(element: LayoutElement, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
979
984
  //#endregion
980
985
  //#region src/layout/utils/print.d.ts
981
986
  /**
@@ -990,4 +995,4 @@ declare function printLayout(node: LayoutNode): void;
990
995
  */
991
996
  declare function layoutToString(node: LayoutNode, _indent?: string): string;
992
997
  //#endregion
993
- export { type AlignItems, type AlignSelf, type Border, type Bounds, Box, type BoxElement, type BoxProps, type CanvasOptions, type Color, type ColorStop, type ContainerLayoutProps, CustomDraw, type CustomDrawElement, type CustomDrawProps, type DrawCallCanvas, type Element, type FlexDirection, type FontProps, type GradientDescriptor, Image, type JustifyContent, type LayoutNode, type LayoutProps, type LinearGradientDescriptor, type MeasureContext, type ProxiedCanvasContextOptions, type RadialGradientDescriptor, RichText, type RichTextElement, type RichTextProps, type RichTextSpan, type Shadow, type Size, type Spacing, Stack, type StackAlign, type StackElement, type StackProps, type StrokeProps, Svg, type SvgAlign, type SvgChild, type SvgCircleChild, type SvgElement, type SvgEllipseChild, type SvgGroupChild, type SvgLineChild, type SvgPathChild, type SvgPolygonChild, type SvgPolylineChild, type SvgProps, type SvgRectChild, type SvgStyleProps, type SvgTextChild, type SvgTransformProps, Text, type TextElement, type TextProps, Transform, type TransformElement, type TransformProps, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };
998
+ export { type AlignItems, type AlignSelf, type Border, type Bounds, Box, type BoxElement, type BoxProps, type CanvasOptions, type Color, type ColorStop, type ContainerLayoutProps, CustomDraw, type CustomDrawElement, type CustomDrawProps, type DrawCallCanvas, type Element, type FlexDirection, type FontProps, type GradientDescriptor, Image, type JustifyContent, type LayoutElement, type LayoutNode, type LayoutProps, type LinearGradientDescriptor, type MeasureContext, type ProxiedCanvasContextOptions, type RadialGradientDescriptor, RichText, type RichTextElement, type RichTextProps, type RichTextSpan, type Shadow, type Size, type Spacing, Stack, type StackAlign, type StackElement, type StackProps, type StrokeProps, Svg, type SvgAlign, type SvgChild, type SvgCircleChild, type SvgElement, type SvgEllipseChild, type SvgGroupChild, type SvgLineChild, type SvgPathChild, type SvgPolygonChild, type SvgPolylineChild, type SvgProps, type SvgRectChild, type SvgStyleProps, type SvgTextChild, type SvgTransformProps, Text, type TextElement, type TextProps, Transform, type TransformElement, type TransformProps, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };
@@ -363,7 +363,8 @@ interface CustomDrawProps extends LayoutProps {
363
363
  interface CustomDrawElement extends ElementBase, CustomDrawProps {
364
364
  type: "customdraw";
365
365
  }
366
- type Element = BoxElement | TextElement | RichTextElement | ImageElement | SvgElement | StackElement | TransformElement | CustomDrawElement;
366
+ type LayoutElement = BoxElement | TextElement | RichTextElement | ImageElement | SvgElement | StackElement | CustomDrawElement;
367
+ type Element = LayoutElement | TransformElement;
367
368
  //#endregion
368
369
  //#region node_modules/@napi-rs/canvas/index.d.ts
369
370
  interface CanvasRenderingContext2D$1 extends CanvasCompositing, CanvasDrawPath, CanvasFillStrokeStyles, CanvasFilters, CanvasImageData, CanvasImageSmoothing, CanvasPath, CanvasPathDrawingStyles, CanvasRect, CanvasSettings, CanvasShadowStyles, CanvasState, CanvasText, CanvasTextDrawingStyles, CanvasTransform, CanvasPDFAnnotations {}
@@ -926,7 +927,7 @@ interface DrawCallCanvas<T extends HTMLCanvasElement | OffscreenCanvas | Canvas
926
927
  readonly height: number;
927
928
  readonly pixelRatio: number;
928
929
  readonly canvas: T;
929
- render(element: Element): LayoutNode;
930
+ render(element: LayoutElement): LayoutNode;
930
931
  clear(): void;
931
932
  getContext(): CanvasRenderingContext2D;
932
933
  toDataURL(type?: string, quality?: number): string;
@@ -975,7 +976,11 @@ declare function Text(props: TextProps): TextElement;
975
976
  declare function Transform(props: TransformProps): TransformElement;
976
977
  //#endregion
977
978
  //#region src/layout/engine.d.ts
978
- declare function computeLayout(element: Element, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
979
+ /**
980
+ * 布局计算主函数
981
+ * 内部使用 Element 类型以支持 Transform,外部通过 LayoutElement 约束类型
982
+ */
983
+ declare function computeLayout(element: LayoutElement, ctx: MeasureContext, constraints: LayoutConstraints, x?: number, y?: number): LayoutNode;
979
984
  //#endregion
980
985
  //#region src/layout/utils/print.d.ts
981
986
  /**
@@ -990,4 +995,4 @@ declare function printLayout(node: LayoutNode): void;
990
995
  */
991
996
  declare function layoutToString(node: LayoutNode, _indent?: string): string;
992
997
  //#endregion
993
- export { type AlignItems, type AlignSelf, type Border, type Bounds, Box, type BoxElement, type BoxProps, type CanvasOptions, type Color, type ColorStop, type ContainerLayoutProps, CustomDraw, type CustomDrawElement, type CustomDrawProps, type DrawCallCanvas, type Element, type FlexDirection, type FontProps, type GradientDescriptor, Image, type JustifyContent, type LayoutNode, type LayoutProps, type LinearGradientDescriptor, type MeasureContext, type ProxiedCanvasContextOptions, type RadialGradientDescriptor, RichText, type RichTextElement, type RichTextProps, type RichTextSpan, type Shadow, type Size, type Spacing, Stack, type StackAlign, type StackElement, type StackProps, type StrokeProps, Svg, type SvgAlign, type SvgChild, type SvgCircleChild, type SvgElement, type SvgEllipseChild, type SvgGroupChild, type SvgLineChild, type SvgPathChild, type SvgPolygonChild, type SvgPolylineChild, type SvgProps, type SvgRectChild, type SvgStyleProps, type SvgTextChild, type SvgTransformProps, Text, type TextElement, type TextProps, Transform, type TransformElement, type TransformProps, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };
998
+ export { type AlignItems, type AlignSelf, type Border, type Bounds, Box, type BoxElement, type BoxProps, type CanvasOptions, type Color, type ColorStop, type ContainerLayoutProps, CustomDraw, type CustomDrawElement, type CustomDrawProps, type DrawCallCanvas, type Element, type FlexDirection, type FontProps, type GradientDescriptor, Image, type JustifyContent, type LayoutElement, type LayoutNode, type LayoutProps, type LinearGradientDescriptor, type MeasureContext, type ProxiedCanvasContextOptions, type RadialGradientDescriptor, RichText, type RichTextElement, type RichTextProps, type RichTextSpan, type Shadow, type Size, type Spacing, Stack, type StackAlign, type StackElement, type StackProps, type StrokeProps, Svg, type SvgAlign, type SvgChild, type SvgCircleChild, type SvgElement, type SvgEllipseChild, type SvgGroupChild, type SvgLineChild, type SvgPathChild, type SvgPolygonChild, type SvgPolylineChild, type SvgProps, type SvgRectChild, type SvgStyleProps, type SvgTextChild, type SvgTransformProps, Text, type TextElement, type TextProps, Transform, type TransformElement, type TransformProps, computeLayout, createCanvas, createCanvasMeasureContext, layoutToString, linearGradient, printLayout, radialGradient, svg };