@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.js CHANGED
@@ -81,6 +81,19 @@ function normalizeBorderRadius(value) {
81
81
 
82
82
  //#endregion
83
83
  //#region src/layout/components/box.ts
84
+ /**
85
+ * 安全获取元素的 margin
86
+ * Transform 元素没有 margin,返回默认 spacing
87
+ */
88
+ function getElementMargin$2(element) {
89
+ if (element.type === "transform") return {
90
+ top: 0,
91
+ right: 0,
92
+ bottom: 0,
93
+ left: 0
94
+ };
95
+ return normalizeSpacing(element.margin);
96
+ }
84
97
  function calcEffectiveSize(element, padding, availableWidth) {
85
98
  return {
86
99
  width: typeof element.width === "number" ? element.width - padding.left - padding.right : availableWidth > 0 ? availableWidth : 0,
@@ -90,7 +103,7 @@ function calcEffectiveSize(element, padding, availableWidth) {
90
103
  function collectChildSizes(children, ctx, availableWidth, padding, measureChild) {
91
104
  const childSizes = [];
92
105
  for (const child of children) {
93
- const childMargin = normalizeSpacing(child.margin);
106
+ const childMargin = getElementMargin$2(child);
94
107
  const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
95
108
  childSizes.push({
96
109
  width: childSize.width,
@@ -159,7 +172,7 @@ function measureBoxSize(element, ctx, availableWidth, measureChild) {
159
172
  contentHeight = wrapped.height;
160
173
  } else for (let i = 0; i < children.length; i++) {
161
174
  const child = children[i];
162
- const childMargin = normalizeSpacing(child.margin);
175
+ const childMargin = getElementMargin$2(child);
163
176
  const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
164
177
  if (isRow) {
165
178
  contentWidth += childSize.width + childMargin.left + childMargin.right;
@@ -393,6 +406,19 @@ function wrapRichText(ctx, spans, maxWidth, lineHeightScale = 1.2, elementStyle
393
406
  //#endregion
394
407
  //#region src/layout/components/stack.ts
395
408
  /**
409
+ * 安全获取元素的 margin
410
+ * Transform 元素没有 margin,返回默认 spacing
411
+ */
412
+ function getElementMargin$1(element) {
413
+ if (element.type === "transform") return {
414
+ top: 0,
415
+ right: 0,
416
+ bottom: 0,
417
+ left: 0
418
+ };
419
+ return normalizeSpacing(element.margin);
420
+ }
421
+ /**
396
422
  * 测量 Stack 元素的固有尺寸
397
423
  */
398
424
  function measureStackSize(element, ctx, availableWidth, measureChild) {
@@ -401,7 +427,7 @@ function measureStackSize(element, ctx, availableWidth, measureChild) {
401
427
  let contentHeight = 0;
402
428
  const children = element.children ?? [];
403
429
  for (const child of children) {
404
- const childMargin = normalizeSpacing(child.margin);
430
+ const childMargin = getElementMargin$1(child);
405
431
  const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
406
432
  contentWidth = Math.max(contentWidth, childSize.width + childMargin.left + childMargin.right);
407
433
  contentHeight = Math.max(contentHeight, childSize.height + childMargin.top + childMargin.bottom);
@@ -640,18 +666,79 @@ function sizeNeedsParent(size) {
640
666
 
641
667
  //#endregion
642
668
  //#region src/layout/engine.ts
669
+ /**
670
+ * 类型守卫:检查 Element 是否为 LayoutElement(非 Transform)
671
+ * 由于 Transform 元素在 computeLayoutImpl 开始时被处理,
672
+ * 此时只应处理 LayoutElement
673
+ */
674
+ function assertLayoutElement(element) {
675
+ if (element.type === "transform") throw new Error("Transform elements should be handled at entry point");
676
+ }
677
+ /**
678
+ * 安全获取元素的 margin
679
+ * Transform 元素没有 margin,返回默认 spacing
680
+ */
681
+ function getElementMargin(element) {
682
+ if (element.type === "transform") return {
683
+ top: 0,
684
+ right: 0,
685
+ bottom: 0,
686
+ left: 0
687
+ };
688
+ return normalizeSpacing(element.margin);
689
+ }
690
+ /**
691
+ * 安全获取元素的布局属性(width, height, flex等)
692
+ * Transform 元素这些属性为 undefined
693
+ */
694
+ function getElementLayoutProps(element) {
695
+ if (element.type === "transform") return {
696
+ width: void 0,
697
+ height: void 0,
698
+ flex: void 0,
699
+ minWidth: void 0,
700
+ maxWidth: void 0,
701
+ minHeight: void 0,
702
+ maxHeight: void 0,
703
+ alignSelf: void 0
704
+ };
705
+ const le = element;
706
+ return {
707
+ width: le.width,
708
+ height: le.height,
709
+ flex: le.flex,
710
+ minWidth: le.minWidth,
711
+ maxWidth: le.maxWidth,
712
+ minHeight: le.minHeight,
713
+ maxHeight: le.maxHeight,
714
+ alignSelf: le.alignSelf
715
+ };
716
+ }
717
+ /**
718
+ * 布局计算主函数
719
+ * 内部使用 Element 类型以支持 Transform,外部通过 LayoutElement 约束类型
720
+ */
643
721
  function computeLayout(element, ctx, constraints, x = 0, y = 0) {
644
- const margin = normalizeSpacing(element.margin);
645
- const padding = normalizeSpacing("padding" in element ? element.padding : void 0);
722
+ return computeLayoutImpl(element, ctx, constraints, x, y);
723
+ }
724
+ /**
725
+ * 内部实现函数,处理所有元素类型包括 Transform
726
+ */
727
+ function computeLayoutImpl(element, ctx, constraints, x = 0, y = 0) {
728
+ if (element.type === "transform") return computeLayoutImpl(element.children, ctx, constraints, x, y);
729
+ assertLayoutElement(element);
730
+ const layoutElement = element;
731
+ const margin = normalizeSpacing(layoutElement.margin);
732
+ const padding = normalizeSpacing("padding" in layoutElement ? layoutElement.padding : void 0);
646
733
  const availableWidth = constraints.maxWidth - margin.left - margin.right;
647
734
  const availableHeight = constraints.maxHeight - margin.top - margin.bottom;
648
- const intrinsic = measureIntrinsicSize(element, ctx, availableWidth);
649
- let width = constraints.minWidth === constraints.maxWidth && constraints.minWidth > 0 ? constraints.maxWidth - margin.left - margin.right : resolveSize(element.width, availableWidth, intrinsic.width);
650
- let height = constraints.minHeight === constraints.maxHeight && constraints.minHeight > 0 ? constraints.maxHeight - margin.top - margin.bottom : resolveSize(element.height, availableHeight, intrinsic.height);
651
- if (element.minWidth !== void 0) width = Math.max(width, element.minWidth);
652
- if (element.maxWidth !== void 0) width = Math.min(width, element.maxWidth);
653
- if (element.minHeight !== void 0) height = Math.max(height, element.minHeight);
654
- if (element.maxHeight !== void 0) height = Math.min(height, element.maxHeight);
735
+ const intrinsic = measureIntrinsicSize(layoutElement, ctx, availableWidth);
736
+ let width = constraints.minWidth === constraints.maxWidth && constraints.minWidth > 0 ? constraints.maxWidth - margin.left - margin.right : resolveSize(layoutElement.width, availableWidth, intrinsic.width);
737
+ let height = constraints.minHeight === constraints.maxHeight && constraints.minHeight > 0 ? constraints.maxHeight - margin.top - margin.bottom : resolveSize(layoutElement.height, availableHeight, intrinsic.height);
738
+ if (layoutElement.minWidth !== void 0) width = Math.max(width, layoutElement.minWidth);
739
+ if (layoutElement.maxWidth !== void 0) width = Math.min(width, layoutElement.maxWidth);
740
+ if (layoutElement.minHeight !== void 0) height = Math.max(height, layoutElement.minHeight);
741
+ if (layoutElement.maxHeight !== void 0) height = Math.min(height, layoutElement.maxHeight);
655
742
  const actualX = x + margin.left;
656
743
  const actualY = y + margin.top;
657
744
  const contentX = actualX + padding.left;
@@ -659,7 +746,7 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
659
746
  const contentWidth = width - padding.left - padding.right;
660
747
  const contentHeight = height - padding.top - padding.bottom;
661
748
  const node = {
662
- element,
749
+ element: layoutElement,
663
750
  layout: {
664
751
  x: actualX,
665
752
  y: actualY,
@@ -672,14 +759,14 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
672
759
  },
673
760
  children: []
674
761
  };
675
- if (element.type === "text") {
676
- const font = element.font ?? {};
677
- if (element.wrap && contentWidth > 0) {
678
- let { lines, offsets } = wrapText(ctx, element.content, contentWidth, font);
679
- if (element.maxLines && lines.length > element.maxLines) {
680
- lines = lines.slice(0, element.maxLines);
681
- offsets = offsets.slice(0, element.maxLines);
682
- if (element.ellipsis && lines.length > 0) {
762
+ if (layoutElement.type === "text") {
763
+ const font = layoutElement.font ?? {};
764
+ if (layoutElement.wrap && contentWidth > 0) {
765
+ let { lines, offsets } = wrapText(ctx, layoutElement.content, contentWidth, font);
766
+ if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
767
+ lines = lines.slice(0, layoutElement.maxLines);
768
+ offsets = offsets.slice(0, layoutElement.maxLines);
769
+ if (layoutElement.ellipsis && lines.length > 0) {
683
770
  const lastIdx = lines.length - 1;
684
771
  const truncated = truncateText(ctx, lines[lastIdx], contentWidth, font);
685
772
  lines[lastIdx] = truncated.text;
@@ -689,17 +776,17 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
689
776
  node.lines = lines;
690
777
  node.lineOffsets = offsets;
691
778
  } else {
692
- const { text, offset } = truncateText(ctx, element.content, contentWidth > 0 && element.ellipsis ? contentWidth : Infinity, font);
779
+ const { text, offset } = truncateText(ctx, layoutElement.content, contentWidth > 0 && layoutElement.ellipsis ? contentWidth : Infinity, font);
693
780
  node.lines = [text];
694
781
  node.lineOffsets = [offset];
695
782
  }
696
783
  }
697
- if (element.type === "richtext") {
698
- const lineHeight = element.lineHeight ?? 1.2;
699
- let lines = wrapRichText(ctx, element.spans, contentWidth, lineHeight);
700
- if (element.maxLines && lines.length > element.maxLines) {
701
- lines = lines.slice(0, element.maxLines);
702
- if (element.ellipsis && lines.length > 0) {
784
+ if (layoutElement.type === "richtext") {
785
+ const lineHeight = layoutElement.lineHeight ?? 1.2;
786
+ let lines = wrapRichText(ctx, layoutElement.spans, contentWidth, lineHeight);
787
+ if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
788
+ lines = lines.slice(0, layoutElement.maxLines);
789
+ if (layoutElement.ellipsis && lines.length > 0) {
703
790
  const lastLine = lines[lines.length - 1];
704
791
  if (lastLine.segments.length > 0) {
705
792
  const lastSeg = lastLine.segments[lastLine.segments.length - 1];
@@ -711,19 +798,19 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
711
798
  }
712
799
  node.richLines = lines;
713
800
  }
714
- if (element.type === "box" || element.type === "stack") {
715
- const children = element.children ?? [];
716
- if (element.type === "stack") {
717
- const stackAlign = element.align ?? "start";
718
- const stackJustify = element.justify ?? "start";
801
+ if (layoutElement.type === "box" || layoutElement.type === "stack") {
802
+ const children = layoutElement.children ?? [];
803
+ if (layoutElement.type === "stack") {
804
+ const stackAlign = layoutElement.align ?? "start";
805
+ const stackJustify = layoutElement.justify ?? "start";
719
806
  for (const child of children) {
720
- const childNode = computeLayout(child, ctx, {
807
+ const childNode = computeLayoutImpl(child, ctx, {
721
808
  minWidth: 0,
722
809
  maxWidth: contentWidth,
723
810
  minHeight: 0,
724
811
  maxHeight: contentHeight
725
812
  }, contentX, contentY);
726
- const childMargin = normalizeSpacing(child.margin);
813
+ const childMargin = getElementMargin(child);
727
814
  const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
728
815
  const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
729
816
  let offsetX = 0;
@@ -736,19 +823,21 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
736
823
  node.children.push(childNode);
737
824
  }
738
825
  } else {
739
- const direction = element.direction ?? "row";
740
- const justify = element.justify ?? "start";
741
- const align = element.align ?? "stretch";
742
- const gap = element.gap ?? 0;
743
- const wrap = element.wrap ?? false;
826
+ const boxElement = layoutElement;
827
+ const direction = boxElement.direction ?? "row";
828
+ const justify = boxElement.justify ?? "start";
829
+ const align = boxElement.align ?? "stretch";
830
+ const gap = boxElement.gap ?? 0;
831
+ const wrap = boxElement.wrap ?? false;
744
832
  const isRow = direction === "row" || direction === "row-reverse";
745
833
  const isReverse = direction === "row-reverse" || direction === "column-reverse";
746
834
  const getContentMainSize = () => isRow ? contentWidth : contentHeight;
747
835
  const getContentCrossSize = () => isRow ? contentHeight : contentWidth;
748
836
  const childInfos = [];
749
837
  for (const child of children) {
750
- const childMargin = normalizeSpacing(child.margin);
751
- const childFlex = child.flex ?? 0;
838
+ const childMargin = getElementMargin(child);
839
+ const childProps = getElementLayoutProps(child);
840
+ const childFlex = childProps.flex ?? 0;
752
841
  if (childFlex > 0) childInfos.push({
753
842
  element: child,
754
843
  width: 0,
@@ -758,10 +847,10 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
758
847
  });
759
848
  else {
760
849
  const size = measureIntrinsicSize(child, ctx, contentWidth - childMargin.left - childMargin.right);
761
- const shouldStretchWidth = !isRow && child.width === void 0 && align === "stretch";
762
- const shouldStretchHeight = isRow && child.height === void 0 && align === "stretch";
763
- let w = sizeNeedsParent(child.width) ? resolveSize(child.width, contentWidth - childMargin.left - childMargin.right, size.width) : resolveSize(child.width, 0, size.width);
764
- let h = sizeNeedsParent(child.height) ? resolveSize(child.height, contentHeight - childMargin.top - childMargin.bottom, size.height) : resolveSize(child.height, 0, size.height);
850
+ const shouldStretchWidth = !isRow && childProps.width === void 0 && align === "stretch";
851
+ const shouldStretchHeight = isRow && childProps.height === void 0 && align === "stretch";
852
+ let w = sizeNeedsParent(childProps.width) ? resolveSize(childProps.width, contentWidth - childMargin.left - childMargin.right, size.width) : resolveSize(childProps.width, 0, size.width);
853
+ let h = sizeNeedsParent(childProps.height) ? resolveSize(childProps.height, contentHeight - childMargin.top - childMargin.bottom, size.height) : resolveSize(childProps.height, 0, size.height);
765
854
  if (shouldStretchWidth && !wrap) w = contentWidth - childMargin.left - childMargin.right;
766
855
  if (shouldStretchHeight && !wrap) h = contentHeight - childMargin.top - childMargin.bottom;
767
856
  childInfos.push({
@@ -802,14 +891,15 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
802
891
  const availableForFlex = Math.max(0, mainAxisSize - totalFixed - totalGap);
803
892
  for (const info of lineInfos) if (info.flex > 0) {
804
893
  const flexSize = totalFlex > 0 ? availableForFlex * info.flex / totalFlex : 0;
894
+ const childProps = getElementLayoutProps(info.element);
805
895
  if (isRow) {
806
896
  info.width = flexSize;
807
897
  const size = measureIntrinsicSize(info.element, ctx, flexSize);
808
- 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);
898
+ info.height = sizeNeedsParent(childProps.height) ? resolveSize(childProps.height, contentHeight - info.margin.top - info.margin.bottom, size.height) : resolveSize(childProps.height, 0, size.height);
809
899
  } else {
810
900
  info.height = flexSize;
811
901
  const size = measureIntrinsicSize(info.element, ctx, contentWidth - info.margin.left - info.margin.right);
812
- 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);
902
+ info.width = sizeNeedsParent(childProps.width) ? resolveSize(childProps.width, contentWidth - info.margin.left - info.margin.right, size.width) : resolveSize(childProps.width, 0, size.width);
813
903
  }
814
904
  }
815
905
  }
@@ -860,17 +950,18 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
860
950
  const orderedInfos = isReverse ? [...lineInfos].reverse() : lineInfos;
861
951
  for (let i = 0; i < orderedInfos.length; i++) {
862
952
  const info = orderedInfos[i];
953
+ const childProps = getElementLayoutProps(info.element);
863
954
  const crossAxisSize = wrap ? lineCrossSize : getContentCrossSize();
864
955
  const childCrossSize = isRow ? info.height + info.margin.top + info.margin.bottom : info.width + info.margin.left + info.margin.right;
865
956
  let itemCrossOffset = 0;
866
- const effectiveAlign = info.element.alignSelf ?? align;
957
+ const effectiveAlign = childProps.alignSelf ?? align;
867
958
  if (effectiveAlign === "start") itemCrossOffset = 0;
868
959
  else if (effectiveAlign === "end") itemCrossOffset = crossAxisSize - childCrossSize;
869
960
  else if (effectiveAlign === "center") itemCrossOffset = (crossAxisSize - childCrossSize) / 2;
870
961
  else if (effectiveAlign === "stretch") {
871
962
  itemCrossOffset = 0;
872
- if (isRow && info.element.height === void 0) info.height = crossAxisSize - info.margin.top - info.margin.bottom;
873
- else if (!isRow && info.element.width === void 0) info.width = crossAxisSize - info.margin.left - info.margin.right;
963
+ if (isRow && childProps.height === void 0) info.height = crossAxisSize - info.margin.top - info.margin.bottom;
964
+ else if (!isRow && childProps.width === void 0) info.width = crossAxisSize - info.margin.left - info.margin.right;
874
965
  }
875
966
  const childX = isRow ? contentX + mainOffset + info.margin.left : contentX + crossOffset + itemCrossOffset + info.margin.left;
876
967
  const childY = isRow ? contentY + crossOffset + itemCrossOffset + info.margin.top : contentY + mainOffset + info.margin.top;
@@ -879,26 +970,29 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
879
970
  let minHeight = 0;
880
971
  let maxHeight = info.height;
881
972
  let shouldStretchCross = false;
882
- if (info.flex > 0) if (isRow) {
883
- minWidth = maxWidth = info.width;
884
- if (info.element.height === void 0 && align === "stretch") {
885
- minHeight = info.height;
886
- maxHeight = element.height !== void 0 ? info.height : Infinity;
887
- shouldStretchCross = true;
973
+ if (info.flex > 0) {
974
+ const childProps = getElementLayoutProps(info.element);
975
+ if (isRow) {
976
+ minWidth = maxWidth = info.width;
977
+ if (childProps.height === void 0 && align === "stretch") {
978
+ minHeight = info.height;
979
+ maxHeight = boxElement.height !== void 0 ? info.height : Infinity;
980
+ shouldStretchCross = true;
981
+ }
982
+ } else {
983
+ minHeight = maxHeight = info.height;
984
+ if (childProps.width === void 0 && align === "stretch") {
985
+ minWidth = info.width;
986
+ maxWidth = boxElement.width !== void 0 ? info.width : Infinity;
987
+ shouldStretchCross = true;
988
+ }
888
989
  }
889
990
  } else {
890
- minHeight = maxHeight = info.height;
891
- if (info.element.width === void 0 && align === "stretch") {
892
- minWidth = info.width;
893
- maxWidth = element.width !== void 0 ? info.width : Infinity;
894
- shouldStretchCross = true;
895
- }
991
+ const childProps = getElementLayoutProps(info.element);
992
+ if (!isRow && childProps.width === void 0 && align === "stretch") minWidth = maxWidth = crossAxisSize - info.margin.left - info.margin.right;
993
+ if (isRow && childProps.height === void 0 && align === "stretch") minHeight = maxHeight = crossAxisSize - info.margin.top - info.margin.bottom;
896
994
  }
897
- else {
898
- if (!isRow && info.element.width === void 0 && align === "stretch") minWidth = maxWidth = crossAxisSize - info.margin.left - info.margin.right;
899
- if (isRow && info.element.height === void 0 && align === "stretch") minHeight = maxHeight = crossAxisSize - info.margin.top - info.margin.bottom;
900
- }
901
- const childNode = computeLayout(info.element, ctx, {
995
+ const childNode = computeLayoutImpl(info.element, ctx, {
902
996
  minWidth,
903
997
  maxWidth,
904
998
  minHeight,
@@ -921,12 +1015,12 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
921
1015
  crossOffset += lineCrossSize;
922
1016
  if (lineIndex < lines.length - 1) crossOffset += gap;
923
1017
  }
924
- if (wrap && element.height === void 0 && isRow) {
1018
+ if (wrap && boxElement.height === void 0 && isRow) {
925
1019
  const actualContentHeight = crossOffset;
926
1020
  const actualHeight = actualContentHeight + padding.top + padding.bottom;
927
1021
  node.layout.height = actualHeight;
928
1022
  node.layout.contentHeight = actualContentHeight;
929
- } else if (wrap && element.width === void 0 && !isRow) {
1023
+ } else if (wrap && boxElement.width === void 0 && !isRow) {
930
1024
  const actualContentWidth = crossOffset;
931
1025
  const actualWidth = actualContentWidth + padding.left + padding.right;
932
1026
  node.layout.width = actualWidth;
@@ -935,7 +1029,7 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
935
1029
  if (!wrap) {
936
1030
  let maxChildCrossSize = 0;
937
1031
  for (const childNode of node.children) {
938
- const childMargin = normalizeSpacing(childNode.element.margin);
1032
+ const childMargin = getElementMargin(childNode.element);
939
1033
  if (isRow) {
940
1034
  const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
941
1035
  maxChildCrossSize = Math.max(maxChildCrossSize, childOuterHeight);
@@ -944,13 +1038,13 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
944
1038
  maxChildCrossSize = Math.max(maxChildCrossSize, childOuterWidth);
945
1039
  }
946
1040
  }
947
- if (isRow && element.height === void 0) {
1041
+ if (isRow && boxElement.height === void 0) {
948
1042
  const actualHeight = maxChildCrossSize + padding.top + padding.bottom;
949
1043
  if (actualHeight > node.layout.height) {
950
1044
  node.layout.height = actualHeight;
951
1045
  node.layout.contentHeight = maxChildCrossSize;
952
1046
  }
953
- } else if (!isRow && element.width === void 0) {
1047
+ } else if (!isRow && boxElement.width === void 0) {
954
1048
  const actualWidth = maxChildCrossSize + padding.left + padding.right;
955
1049
  if (actualWidth > node.layout.width) {
956
1050
  node.layout.width = actualWidth;
@@ -960,48 +1054,24 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
960
1054
  }
961
1055
  if (isReverse) node.children.reverse();
962
1056
  }
963
- } else if (element.type === "transform") {
964
- const child = element.children;
965
- if (child) {
966
- const childMargin = normalizeSpacing(child.margin);
967
- const childNode = computeLayout(child, ctx, {
968
- minWidth: 0,
969
- maxWidth: contentWidth,
970
- minHeight: 0,
971
- maxHeight: contentHeight
972
- }, contentX, contentY);
973
- node.children.push(childNode);
974
- if (element.width === void 0) {
975
- const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
976
- const actualWidth = childOuterWidth + padding.left + padding.right;
977
- node.layout.width = actualWidth;
978
- node.layout.contentWidth = childOuterWidth;
979
- }
980
- if (element.height === void 0) {
981
- const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
982
- const actualHeight = childOuterHeight + padding.top + padding.bottom;
983
- node.layout.height = actualHeight;
984
- node.layout.contentHeight = childOuterHeight;
985
- }
986
- }
987
- } else if (element.type === "customdraw") {
988
- const child = element.children;
1057
+ } else if (layoutElement.type === "customdraw") {
1058
+ const child = layoutElement.children;
989
1059
  if (child) {
990
1060
  const childMargin = normalizeSpacing(child.margin);
991
- const childNode = computeLayout(child, ctx, {
1061
+ const childNode = computeLayoutImpl(child, ctx, {
992
1062
  minWidth: 0,
993
1063
  maxWidth: contentWidth,
994
1064
  minHeight: 0,
995
1065
  maxHeight: contentHeight
996
1066
  }, contentX, contentY);
997
1067
  node.children.push(childNode);
998
- if (element.width === void 0) {
1068
+ if (layoutElement.width === void 0) {
999
1069
  const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
1000
1070
  const actualWidth = childOuterWidth + padding.left + padding.right;
1001
1071
  node.layout.width = actualWidth;
1002
1072
  node.layout.contentWidth = childOuterWidth;
1003
1073
  }
1004
- if (element.height === void 0) {
1074
+ if (layoutElement.height === void 0) {
1005
1075
  const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
1006
1076
  const actualHeight = childOuterHeight + padding.top + padding.bottom;
1007
1077
  node.layout.height = actualHeight;
@@ -2011,10 +2081,12 @@ function getElementType(element) {
2011
2081
  switch (element.type) {
2012
2082
  case "box": return "Box";
2013
2083
  case "text": return `Text "${element.content.slice(0, 20)}${element.content.length > 20 ? "..." : ""}"`;
2084
+ case "richtext": return "RichText";
2014
2085
  case "stack": return "Stack";
2015
2086
  case "image": return "Image";
2016
2087
  case "svg": return "Svg";
2017
- default: return element.type;
2088
+ case "transform": return "Transform";
2089
+ case "customdraw": return "CustomDraw";
2018
2090
  }
2019
2091
  }
2020
2092
  /**