@codehz/draw-call 0.4.5 → 0.5.1
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 +185 -104
- package/browser/index.d.cts +11 -9
- package/browser/index.d.ts +11 -9
- package/browser/index.js +185 -104
- package/examples/demo.ts +0 -5
- package/node/index.cjs +185 -104
- package/node/index.d.cts +11 -9
- package/node/index.d.mts +11 -9
- package/node/index.mjs +185 -104
- package/package.json +1 -1
package/node/index.mjs
CHANGED
|
@@ -78,6 +78,19 @@ function normalizeBorderRadius(value) {
|
|
|
78
78
|
|
|
79
79
|
//#endregion
|
|
80
80
|
//#region src/layout/components/box.ts
|
|
81
|
+
/**
|
|
82
|
+
* 安全获取元素的 margin
|
|
83
|
+
* Transform 元素没有 margin,返回默认 spacing
|
|
84
|
+
*/
|
|
85
|
+
function getElementMargin$2(element) {
|
|
86
|
+
if (element.type === "transform") return {
|
|
87
|
+
top: 0,
|
|
88
|
+
right: 0,
|
|
89
|
+
bottom: 0,
|
|
90
|
+
left: 0
|
|
91
|
+
};
|
|
92
|
+
return normalizeSpacing(element.margin);
|
|
93
|
+
}
|
|
81
94
|
function calcEffectiveSize(element, padding, availableWidth) {
|
|
82
95
|
return {
|
|
83
96
|
width: typeof element.width === "number" ? element.width - padding.left - padding.right : availableWidth > 0 ? availableWidth : 0,
|
|
@@ -87,7 +100,7 @@ function calcEffectiveSize(element, padding, availableWidth) {
|
|
|
87
100
|
function collectChildSizes(children, ctx, availableWidth, padding, measureChild) {
|
|
88
101
|
const childSizes = [];
|
|
89
102
|
for (const child of children) {
|
|
90
|
-
const childMargin =
|
|
103
|
+
const childMargin = getElementMargin$2(child);
|
|
91
104
|
const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
|
|
92
105
|
childSizes.push({
|
|
93
106
|
width: childSize.width,
|
|
@@ -156,7 +169,7 @@ function measureBoxSize(element, ctx, availableWidth, measureChild) {
|
|
|
156
169
|
contentHeight = wrapped.height;
|
|
157
170
|
} else for (let i = 0; i < children.length; i++) {
|
|
158
171
|
const child = children[i];
|
|
159
|
-
const childMargin =
|
|
172
|
+
const childMargin = getElementMargin$2(child);
|
|
160
173
|
const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
|
|
161
174
|
if (isRow) {
|
|
162
175
|
contentWidth += childSize.width + childMargin.left + childMargin.right;
|
|
@@ -390,6 +403,19 @@ function wrapRichText(ctx, spans, maxWidth, lineHeightScale = 1.2, elementStyle
|
|
|
390
403
|
//#endregion
|
|
391
404
|
//#region src/layout/components/stack.ts
|
|
392
405
|
/**
|
|
406
|
+
* 安全获取元素的 margin
|
|
407
|
+
* Transform 元素没有 margin,返回默认 spacing
|
|
408
|
+
*/
|
|
409
|
+
function getElementMargin$1(element) {
|
|
410
|
+
if (element.type === "transform") return {
|
|
411
|
+
top: 0,
|
|
412
|
+
right: 0,
|
|
413
|
+
bottom: 0,
|
|
414
|
+
left: 0
|
|
415
|
+
};
|
|
416
|
+
return normalizeSpacing(element.margin);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
393
419
|
* 测量 Stack 元素的固有尺寸
|
|
394
420
|
*/
|
|
395
421
|
function measureStackSize(element, ctx, availableWidth, measureChild) {
|
|
@@ -398,7 +424,7 @@ function measureStackSize(element, ctx, availableWidth, measureChild) {
|
|
|
398
424
|
let contentHeight = 0;
|
|
399
425
|
const children = element.children ?? [];
|
|
400
426
|
for (const child of children) {
|
|
401
|
-
const childMargin =
|
|
427
|
+
const childMargin = getElementMargin$1(child);
|
|
402
428
|
const childSize = measureChild(child, ctx, availableWidth - padding.left - padding.right - childMargin.left - childMargin.right);
|
|
403
429
|
contentWidth = Math.max(contentWidth, childSize.width + childMargin.left + childMargin.right);
|
|
404
430
|
contentHeight = Math.max(contentHeight, childSize.height + childMargin.top + childMargin.bottom);
|
|
@@ -637,18 +663,79 @@ function sizeNeedsParent(size) {
|
|
|
637
663
|
|
|
638
664
|
//#endregion
|
|
639
665
|
//#region src/layout/engine.ts
|
|
666
|
+
/**
|
|
667
|
+
* 类型守卫:检查 Element 是否为 LayoutElement(非 Transform)
|
|
668
|
+
* 由于 Transform 元素在 computeLayoutImpl 开始时被处理,
|
|
669
|
+
* 此时只应处理 LayoutElement
|
|
670
|
+
*/
|
|
671
|
+
function assertLayoutElement(element) {
|
|
672
|
+
if (element.type === "transform") throw new Error("Transform elements should be handled at entry point");
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* 安全获取元素的 margin
|
|
676
|
+
* Transform 元素没有 margin,返回默认 spacing
|
|
677
|
+
*/
|
|
678
|
+
function getElementMargin(element) {
|
|
679
|
+
if (element.type === "transform") return {
|
|
680
|
+
top: 0,
|
|
681
|
+
right: 0,
|
|
682
|
+
bottom: 0,
|
|
683
|
+
left: 0
|
|
684
|
+
};
|
|
685
|
+
return normalizeSpacing(element.margin);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* 安全获取元素的布局属性(width, height, flex等)
|
|
689
|
+
* Transform 元素这些属性为 undefined
|
|
690
|
+
*/
|
|
691
|
+
function getElementLayoutProps(element) {
|
|
692
|
+
if (element.type === "transform") return {
|
|
693
|
+
width: void 0,
|
|
694
|
+
height: void 0,
|
|
695
|
+
flex: void 0,
|
|
696
|
+
minWidth: void 0,
|
|
697
|
+
maxWidth: void 0,
|
|
698
|
+
minHeight: void 0,
|
|
699
|
+
maxHeight: void 0,
|
|
700
|
+
alignSelf: void 0
|
|
701
|
+
};
|
|
702
|
+
const le = element;
|
|
703
|
+
return {
|
|
704
|
+
width: le.width,
|
|
705
|
+
height: le.height,
|
|
706
|
+
flex: le.flex,
|
|
707
|
+
minWidth: le.minWidth,
|
|
708
|
+
maxWidth: le.maxWidth,
|
|
709
|
+
minHeight: le.minHeight,
|
|
710
|
+
maxHeight: le.maxHeight,
|
|
711
|
+
alignSelf: le.alignSelf
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* 布局计算主函数
|
|
716
|
+
* 内部使用 Element 类型以支持 Transform,外部通过 LayoutElement 约束类型
|
|
717
|
+
*/
|
|
640
718
|
function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
641
|
-
|
|
642
|
-
|
|
719
|
+
return computeLayoutImpl(element, ctx, constraints, x, y);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* 内部实现函数,处理所有元素类型包括 Transform
|
|
723
|
+
*/
|
|
724
|
+
function computeLayoutImpl(element, ctx, constraints, x = 0, y = 0) {
|
|
725
|
+
if (element.type === "transform") return computeLayoutImpl(element.children, ctx, constraints, x, y);
|
|
726
|
+
assertLayoutElement(element);
|
|
727
|
+
const layoutElement = element;
|
|
728
|
+
const margin = normalizeSpacing(layoutElement.margin);
|
|
729
|
+
const padding = normalizeSpacing("padding" in layoutElement ? layoutElement.padding : void 0);
|
|
643
730
|
const availableWidth = constraints.maxWidth - margin.left - margin.right;
|
|
644
731
|
const availableHeight = constraints.maxHeight - margin.top - margin.bottom;
|
|
645
|
-
const intrinsic = measureIntrinsicSize(
|
|
646
|
-
let width = constraints.minWidth === constraints.maxWidth && constraints.minWidth > 0 ? constraints.maxWidth - margin.left - margin.right : resolveSize(
|
|
647
|
-
let height = constraints.minHeight === constraints.maxHeight && constraints.minHeight > 0 ? constraints.maxHeight - margin.top - margin.bottom : resolveSize(
|
|
648
|
-
if (
|
|
649
|
-
if (
|
|
650
|
-
if (
|
|
651
|
-
if (
|
|
732
|
+
const intrinsic = measureIntrinsicSize(layoutElement, ctx, availableWidth);
|
|
733
|
+
let width = constraints.minWidth === constraints.maxWidth && constraints.minWidth > 0 ? constraints.maxWidth - margin.left - margin.right : resolveSize(layoutElement.width, availableWidth, intrinsic.width);
|
|
734
|
+
let height = constraints.minHeight === constraints.maxHeight && constraints.minHeight > 0 ? constraints.maxHeight - margin.top - margin.bottom : resolveSize(layoutElement.height, availableHeight, intrinsic.height);
|
|
735
|
+
if (layoutElement.minWidth !== void 0) width = Math.max(width, layoutElement.minWidth);
|
|
736
|
+
if (layoutElement.maxWidth !== void 0) width = Math.min(width, layoutElement.maxWidth);
|
|
737
|
+
if (layoutElement.minHeight !== void 0) height = Math.max(height, layoutElement.minHeight);
|
|
738
|
+
if (layoutElement.maxHeight !== void 0) height = Math.min(height, layoutElement.maxHeight);
|
|
652
739
|
const actualX = x + margin.left;
|
|
653
740
|
const actualY = y + margin.top;
|
|
654
741
|
const contentX = actualX + padding.left;
|
|
@@ -656,7 +743,7 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
656
743
|
const contentWidth = width - padding.left - padding.right;
|
|
657
744
|
const contentHeight = height - padding.top - padding.bottom;
|
|
658
745
|
const node = {
|
|
659
|
-
element,
|
|
746
|
+
element: layoutElement,
|
|
660
747
|
layout: {
|
|
661
748
|
x: actualX,
|
|
662
749
|
y: actualY,
|
|
@@ -669,14 +756,14 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
669
756
|
},
|
|
670
757
|
children: []
|
|
671
758
|
};
|
|
672
|
-
if (
|
|
673
|
-
const font =
|
|
674
|
-
if (
|
|
675
|
-
let { lines, offsets } = wrapText(ctx,
|
|
676
|
-
if (
|
|
677
|
-
lines = lines.slice(0,
|
|
678
|
-
offsets = offsets.slice(0,
|
|
679
|
-
if (
|
|
759
|
+
if (layoutElement.type === "text") {
|
|
760
|
+
const font = layoutElement.font ?? {};
|
|
761
|
+
if (layoutElement.wrap && contentWidth > 0) {
|
|
762
|
+
let { lines, offsets } = wrapText(ctx, layoutElement.content, contentWidth, font);
|
|
763
|
+
if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
|
|
764
|
+
lines = lines.slice(0, layoutElement.maxLines);
|
|
765
|
+
offsets = offsets.slice(0, layoutElement.maxLines);
|
|
766
|
+
if (layoutElement.ellipsis && lines.length > 0) {
|
|
680
767
|
const lastIdx = lines.length - 1;
|
|
681
768
|
const truncated = truncateText(ctx, lines[lastIdx], contentWidth, font);
|
|
682
769
|
lines[lastIdx] = truncated.text;
|
|
@@ -686,17 +773,17 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
686
773
|
node.lines = lines;
|
|
687
774
|
node.lineOffsets = offsets;
|
|
688
775
|
} else {
|
|
689
|
-
const { text, offset } = truncateText(ctx,
|
|
776
|
+
const { text, offset } = truncateText(ctx, layoutElement.content, contentWidth > 0 && layoutElement.ellipsis ? contentWidth : Infinity, font);
|
|
690
777
|
node.lines = [text];
|
|
691
778
|
node.lineOffsets = [offset];
|
|
692
779
|
}
|
|
693
780
|
}
|
|
694
|
-
if (
|
|
695
|
-
const lineHeight =
|
|
696
|
-
let lines = wrapRichText(ctx,
|
|
697
|
-
if (
|
|
698
|
-
lines = lines.slice(0,
|
|
699
|
-
if (
|
|
781
|
+
if (layoutElement.type === "richtext") {
|
|
782
|
+
const lineHeight = layoutElement.lineHeight ?? 1.2;
|
|
783
|
+
let lines = wrapRichText(ctx, layoutElement.spans, contentWidth, lineHeight);
|
|
784
|
+
if (layoutElement.maxLines && lines.length > layoutElement.maxLines) {
|
|
785
|
+
lines = lines.slice(0, layoutElement.maxLines);
|
|
786
|
+
if (layoutElement.ellipsis && lines.length > 0) {
|
|
700
787
|
const lastLine = lines[lines.length - 1];
|
|
701
788
|
if (lastLine.segments.length > 0) {
|
|
702
789
|
const lastSeg = lastLine.segments[lastLine.segments.length - 1];
|
|
@@ -708,19 +795,19 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
708
795
|
}
|
|
709
796
|
node.richLines = lines;
|
|
710
797
|
}
|
|
711
|
-
if (
|
|
712
|
-
const children =
|
|
713
|
-
if (
|
|
714
|
-
const stackAlign =
|
|
715
|
-
const stackJustify =
|
|
798
|
+
if (layoutElement.type === "box" || layoutElement.type === "stack") {
|
|
799
|
+
const children = layoutElement.children ?? [];
|
|
800
|
+
if (layoutElement.type === "stack") {
|
|
801
|
+
const stackAlign = layoutElement.align ?? "start";
|
|
802
|
+
const stackJustify = layoutElement.justify ?? "start";
|
|
716
803
|
for (const child of children) {
|
|
717
|
-
const childNode =
|
|
804
|
+
const childNode = computeLayoutImpl(child, ctx, {
|
|
718
805
|
minWidth: 0,
|
|
719
806
|
maxWidth: contentWidth,
|
|
720
807
|
minHeight: 0,
|
|
721
808
|
maxHeight: contentHeight
|
|
722
809
|
}, contentX, contentY);
|
|
723
|
-
const childMargin =
|
|
810
|
+
const childMargin = getElementMargin(child);
|
|
724
811
|
const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
|
|
725
812
|
const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
|
|
726
813
|
let offsetX = 0;
|
|
@@ -733,19 +820,21 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
733
820
|
node.children.push(childNode);
|
|
734
821
|
}
|
|
735
822
|
} else {
|
|
736
|
-
const
|
|
737
|
-
const
|
|
738
|
-
const
|
|
739
|
-
const
|
|
740
|
-
const
|
|
823
|
+
const boxElement = layoutElement;
|
|
824
|
+
const direction = boxElement.direction ?? "row";
|
|
825
|
+
const justify = boxElement.justify ?? "start";
|
|
826
|
+
const align = boxElement.align ?? "stretch";
|
|
827
|
+
const gap = boxElement.gap ?? 0;
|
|
828
|
+
const wrap = boxElement.wrap ?? false;
|
|
741
829
|
const isRow = direction === "row" || direction === "row-reverse";
|
|
742
830
|
const isReverse = direction === "row-reverse" || direction === "column-reverse";
|
|
743
831
|
const getContentMainSize = () => isRow ? contentWidth : contentHeight;
|
|
744
832
|
const getContentCrossSize = () => isRow ? contentHeight : contentWidth;
|
|
745
833
|
const childInfos = [];
|
|
746
834
|
for (const child of children) {
|
|
747
|
-
const childMargin =
|
|
748
|
-
const
|
|
835
|
+
const childMargin = getElementMargin(child);
|
|
836
|
+
const childProps = getElementLayoutProps(child);
|
|
837
|
+
const childFlex = childProps.flex ?? 0;
|
|
749
838
|
if (childFlex > 0) childInfos.push({
|
|
750
839
|
element: child,
|
|
751
840
|
width: 0,
|
|
@@ -755,10 +844,10 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
755
844
|
});
|
|
756
845
|
else {
|
|
757
846
|
const size = measureIntrinsicSize(child, ctx, contentWidth - childMargin.left - childMargin.right);
|
|
758
|
-
const shouldStretchWidth = !isRow &&
|
|
759
|
-
const shouldStretchHeight = isRow &&
|
|
760
|
-
let w = sizeNeedsParent(
|
|
761
|
-
let h = sizeNeedsParent(
|
|
847
|
+
const shouldStretchWidth = !isRow && childProps.width === void 0 && align === "stretch";
|
|
848
|
+
const shouldStretchHeight = isRow && childProps.height === void 0 && align === "stretch";
|
|
849
|
+
let w = sizeNeedsParent(childProps.width) ? resolveSize(childProps.width, contentWidth - childMargin.left - childMargin.right, size.width) : resolveSize(childProps.width, 0, size.width);
|
|
850
|
+
let h = sizeNeedsParent(childProps.height) ? resolveSize(childProps.height, contentHeight - childMargin.top - childMargin.bottom, size.height) : resolveSize(childProps.height, 0, size.height);
|
|
762
851
|
if (shouldStretchWidth && !wrap) w = contentWidth - childMargin.left - childMargin.right;
|
|
763
852
|
if (shouldStretchHeight && !wrap) h = contentHeight - childMargin.top - childMargin.bottom;
|
|
764
853
|
childInfos.push({
|
|
@@ -799,14 +888,15 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
799
888
|
const availableForFlex = Math.max(0, mainAxisSize - totalFixed - totalGap);
|
|
800
889
|
for (const info of lineInfos) if (info.flex > 0) {
|
|
801
890
|
const flexSize = totalFlex > 0 ? availableForFlex * info.flex / totalFlex : 0;
|
|
891
|
+
const childProps = getElementLayoutProps(info.element);
|
|
802
892
|
if (isRow) {
|
|
803
893
|
info.width = flexSize;
|
|
804
894
|
const size = measureIntrinsicSize(info.element, ctx, flexSize);
|
|
805
|
-
info.height = sizeNeedsParent(
|
|
895
|
+
info.height = sizeNeedsParent(childProps.height) ? resolveSize(childProps.height, contentHeight - info.margin.top - info.margin.bottom, size.height) : resolveSize(childProps.height, 0, size.height);
|
|
806
896
|
} else {
|
|
807
897
|
info.height = flexSize;
|
|
808
898
|
const size = measureIntrinsicSize(info.element, ctx, contentWidth - info.margin.left - info.margin.right);
|
|
809
|
-
info.width = sizeNeedsParent(
|
|
899
|
+
info.width = sizeNeedsParent(childProps.width) ? resolveSize(childProps.width, contentWidth - info.margin.left - info.margin.right, size.width) : resolveSize(childProps.width, 0, size.width);
|
|
810
900
|
}
|
|
811
901
|
}
|
|
812
902
|
}
|
|
@@ -857,17 +947,18 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
857
947
|
const orderedInfos = isReverse ? [...lineInfos].reverse() : lineInfos;
|
|
858
948
|
for (let i = 0; i < orderedInfos.length; i++) {
|
|
859
949
|
const info = orderedInfos[i];
|
|
950
|
+
const childProps = getElementLayoutProps(info.element);
|
|
860
951
|
const crossAxisSize = wrap ? lineCrossSize : getContentCrossSize();
|
|
861
952
|
const childCrossSize = isRow ? info.height + info.margin.top + info.margin.bottom : info.width + info.margin.left + info.margin.right;
|
|
862
953
|
let itemCrossOffset = 0;
|
|
863
|
-
const effectiveAlign =
|
|
954
|
+
const effectiveAlign = childProps.alignSelf ?? align;
|
|
864
955
|
if (effectiveAlign === "start") itemCrossOffset = 0;
|
|
865
956
|
else if (effectiveAlign === "end") itemCrossOffset = crossAxisSize - childCrossSize;
|
|
866
957
|
else if (effectiveAlign === "center") itemCrossOffset = (crossAxisSize - childCrossSize) / 2;
|
|
867
958
|
else if (effectiveAlign === "stretch") {
|
|
868
959
|
itemCrossOffset = 0;
|
|
869
|
-
if (isRow &&
|
|
870
|
-
else if (!isRow &&
|
|
960
|
+
if (isRow && childProps.height === void 0) info.height = crossAxisSize - info.margin.top - info.margin.bottom;
|
|
961
|
+
else if (!isRow && childProps.width === void 0) info.width = crossAxisSize - info.margin.left - info.margin.right;
|
|
871
962
|
}
|
|
872
963
|
const childX = isRow ? contentX + mainOffset + info.margin.left : contentX + crossOffset + itemCrossOffset + info.margin.left;
|
|
873
964
|
const childY = isRow ? contentY + crossOffset + itemCrossOffset + info.margin.top : contentY + mainOffset + info.margin.top;
|
|
@@ -876,26 +967,29 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
876
967
|
let minHeight = 0;
|
|
877
968
|
let maxHeight = info.height;
|
|
878
969
|
let shouldStretchCross = false;
|
|
879
|
-
if (info.flex > 0)
|
|
880
|
-
|
|
881
|
-
if (
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
970
|
+
if (info.flex > 0) {
|
|
971
|
+
const childProps = getElementLayoutProps(info.element);
|
|
972
|
+
if (isRow) {
|
|
973
|
+
minWidth = maxWidth = info.width;
|
|
974
|
+
if (childProps.height === void 0 && align === "stretch") {
|
|
975
|
+
minHeight = info.height;
|
|
976
|
+
maxHeight = boxElement.height !== void 0 ? info.height : Infinity;
|
|
977
|
+
shouldStretchCross = true;
|
|
978
|
+
}
|
|
979
|
+
} else {
|
|
980
|
+
minHeight = maxHeight = info.height;
|
|
981
|
+
if (childProps.width === void 0 && align === "stretch") {
|
|
982
|
+
minWidth = info.width;
|
|
983
|
+
maxWidth = boxElement.width !== void 0 ? info.width : Infinity;
|
|
984
|
+
shouldStretchCross = true;
|
|
985
|
+
}
|
|
885
986
|
}
|
|
886
987
|
} else {
|
|
887
|
-
|
|
888
|
-
if (
|
|
889
|
-
|
|
890
|
-
maxWidth = element.width !== void 0 ? info.width : Infinity;
|
|
891
|
-
shouldStretchCross = true;
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
else {
|
|
895
|
-
if (!isRow && info.element.width === void 0 && align === "stretch") minWidth = maxWidth = crossAxisSize - info.margin.left - info.margin.right;
|
|
896
|
-
if (isRow && info.element.height === void 0 && align === "stretch") minHeight = maxHeight = crossAxisSize - info.margin.top - info.margin.bottom;
|
|
988
|
+
const childProps = getElementLayoutProps(info.element);
|
|
989
|
+
if (!isRow && childProps.width === void 0 && align === "stretch") minWidth = maxWidth = crossAxisSize - info.margin.left - info.margin.right;
|
|
990
|
+
if (isRow && childProps.height === void 0 && align === "stretch") minHeight = maxHeight = crossAxisSize - info.margin.top - info.margin.bottom;
|
|
897
991
|
}
|
|
898
|
-
const childNode =
|
|
992
|
+
const childNode = computeLayoutImpl(info.element, ctx, {
|
|
899
993
|
minWidth,
|
|
900
994
|
maxWidth,
|
|
901
995
|
minHeight,
|
|
@@ -918,12 +1012,12 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
918
1012
|
crossOffset += lineCrossSize;
|
|
919
1013
|
if (lineIndex < lines.length - 1) crossOffset += gap;
|
|
920
1014
|
}
|
|
921
|
-
if (wrap &&
|
|
1015
|
+
if (wrap && boxElement.height === void 0 && isRow) {
|
|
922
1016
|
const actualContentHeight = crossOffset;
|
|
923
1017
|
const actualHeight = actualContentHeight + padding.top + padding.bottom;
|
|
924
1018
|
node.layout.height = actualHeight;
|
|
925
1019
|
node.layout.contentHeight = actualContentHeight;
|
|
926
|
-
} else if (wrap &&
|
|
1020
|
+
} else if (wrap && boxElement.width === void 0 && !isRow) {
|
|
927
1021
|
const actualContentWidth = crossOffset;
|
|
928
1022
|
const actualWidth = actualContentWidth + padding.left + padding.right;
|
|
929
1023
|
node.layout.width = actualWidth;
|
|
@@ -932,7 +1026,7 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
932
1026
|
if (!wrap) {
|
|
933
1027
|
let maxChildCrossSize = 0;
|
|
934
1028
|
for (const childNode of node.children) {
|
|
935
|
-
const childMargin =
|
|
1029
|
+
const childMargin = getElementMargin(childNode.element);
|
|
936
1030
|
if (isRow) {
|
|
937
1031
|
const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
|
|
938
1032
|
maxChildCrossSize = Math.max(maxChildCrossSize, childOuterHeight);
|
|
@@ -941,13 +1035,13 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
941
1035
|
maxChildCrossSize = Math.max(maxChildCrossSize, childOuterWidth);
|
|
942
1036
|
}
|
|
943
1037
|
}
|
|
944
|
-
if (isRow &&
|
|
1038
|
+
if (isRow && boxElement.height === void 0) {
|
|
945
1039
|
const actualHeight = maxChildCrossSize + padding.top + padding.bottom;
|
|
946
1040
|
if (actualHeight > node.layout.height) {
|
|
947
1041
|
node.layout.height = actualHeight;
|
|
948
1042
|
node.layout.contentHeight = maxChildCrossSize;
|
|
949
1043
|
}
|
|
950
|
-
} else if (!isRow &&
|
|
1044
|
+
} else if (!isRow && boxElement.width === void 0) {
|
|
951
1045
|
const actualWidth = maxChildCrossSize + padding.left + padding.right;
|
|
952
1046
|
if (actualWidth > node.layout.width) {
|
|
953
1047
|
node.layout.width = actualWidth;
|
|
@@ -957,48 +1051,24 @@ function computeLayout(element, ctx, constraints, x = 0, y = 0) {
|
|
|
957
1051
|
}
|
|
958
1052
|
if (isReverse) node.children.reverse();
|
|
959
1053
|
}
|
|
960
|
-
} else if (
|
|
961
|
-
const child =
|
|
1054
|
+
} else if (layoutElement.type === "customdraw") {
|
|
1055
|
+
const child = layoutElement.children;
|
|
962
1056
|
if (child) {
|
|
963
1057
|
const childMargin = normalizeSpacing(child.margin);
|
|
964
|
-
const childNode =
|
|
1058
|
+
const childNode = computeLayoutImpl(child, ctx, {
|
|
965
1059
|
minWidth: 0,
|
|
966
1060
|
maxWidth: contentWidth,
|
|
967
1061
|
minHeight: 0,
|
|
968
1062
|
maxHeight: contentHeight
|
|
969
1063
|
}, contentX, contentY);
|
|
970
1064
|
node.children.push(childNode);
|
|
971
|
-
if (
|
|
1065
|
+
if (layoutElement.width === void 0) {
|
|
972
1066
|
const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
|
|
973
1067
|
const actualWidth = childOuterWidth + padding.left + padding.right;
|
|
974
1068
|
node.layout.width = actualWidth;
|
|
975
1069
|
node.layout.contentWidth = childOuterWidth;
|
|
976
1070
|
}
|
|
977
|
-
if (
|
|
978
|
-
const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
|
|
979
|
-
const actualHeight = childOuterHeight + padding.top + padding.bottom;
|
|
980
|
-
node.layout.height = actualHeight;
|
|
981
|
-
node.layout.contentHeight = childOuterHeight;
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
} else if (element.type === "customdraw") {
|
|
985
|
-
const child = element.children;
|
|
986
|
-
if (child) {
|
|
987
|
-
const childMargin = normalizeSpacing(child.margin);
|
|
988
|
-
const childNode = computeLayout(child, ctx, {
|
|
989
|
-
minWidth: 0,
|
|
990
|
-
maxWidth: contentWidth,
|
|
991
|
-
minHeight: 0,
|
|
992
|
-
maxHeight: contentHeight
|
|
993
|
-
}, contentX, contentY);
|
|
994
|
-
node.children.push(childNode);
|
|
995
|
-
if (element.width === void 0) {
|
|
996
|
-
const childOuterWidth = childNode.layout.width + childMargin.left + childMargin.right;
|
|
997
|
-
const actualWidth = childOuterWidth + padding.left + padding.right;
|
|
998
|
-
node.layout.width = actualWidth;
|
|
999
|
-
node.layout.contentWidth = childOuterWidth;
|
|
1000
|
-
}
|
|
1001
|
-
if (element.height === void 0) {
|
|
1071
|
+
if (layoutElement.height === void 0) {
|
|
1002
1072
|
const childOuterHeight = childNode.layout.height + childMargin.top + childMargin.bottom;
|
|
1003
1073
|
const actualHeight = childOuterHeight + padding.top + padding.bottom;
|
|
1004
1074
|
node.layout.height = actualHeight;
|
|
@@ -1829,8 +1899,17 @@ function renderNode(ctx, node) {
|
|
|
1829
1899
|
function createCanvas(options) {
|
|
1830
1900
|
const { width, height, pixelRatio = 1 } = options;
|
|
1831
1901
|
const canvas = options.canvas ?? createRawCanvas(width * pixelRatio, height * pixelRatio);
|
|
1902
|
+
if (options.canvas) {
|
|
1903
|
+
canvas.width = width * pixelRatio;
|
|
1904
|
+
canvas.height = height * pixelRatio;
|
|
1905
|
+
if ("style" in canvas && options.updateStyles !== false) {
|
|
1906
|
+
canvas.style.width = `${width}px`;
|
|
1907
|
+
canvas.style.height = `${height}px`;
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1832
1910
|
const ctx = canvas.getContext("2d");
|
|
1833
1911
|
if (!ctx) throw new Error("Failed to get 2d context");
|
|
1912
|
+
ctx.resetTransform();
|
|
1834
1913
|
if (options.imageSmoothingEnabled !== void 0) ctx.imageSmoothingEnabled = options.imageSmoothingEnabled;
|
|
1835
1914
|
if (options.imageSmoothingQuality !== void 0) ctx.imageSmoothingQuality = options.imageSmoothingQuality;
|
|
1836
1915
|
if (pixelRatio !== 1) ctx.scale(pixelRatio, pixelRatio);
|
|
@@ -1853,7 +1932,7 @@ function createCanvas(options) {
|
|
|
1853
1932
|
if (canvas.width !== contentWidth * pixelRatio || canvas.height !== contentHeight * pixelRatio) {
|
|
1854
1933
|
canvas.width = contentWidth * pixelRatio;
|
|
1855
1934
|
canvas.height = contentHeight * pixelRatio;
|
|
1856
|
-
if ("style" in canvas) {
|
|
1935
|
+
if ("style" in canvas && options.updateStyles !== false) {
|
|
1857
1936
|
canvas.style.width = `${contentWidth}px`;
|
|
1858
1937
|
canvas.style.height = `${contentHeight}px`;
|
|
1859
1938
|
}
|
|
@@ -1999,10 +2078,12 @@ function getElementType(element) {
|
|
|
1999
2078
|
switch (element.type) {
|
|
2000
2079
|
case "box": return "Box";
|
|
2001
2080
|
case "text": return `Text "${element.content.slice(0, 20)}${element.content.length > 20 ? "..." : ""}"`;
|
|
2081
|
+
case "richtext": return "RichText";
|
|
2002
2082
|
case "stack": return "Stack";
|
|
2003
2083
|
case "image": return "Image";
|
|
2004
2084
|
case "svg": return "Svg";
|
|
2005
|
-
|
|
2085
|
+
case "transform": return "Transform";
|
|
2086
|
+
case "customdraw": return "CustomDraw";
|
|
2006
2087
|
}
|
|
2007
2088
|
}
|
|
2008
2089
|
/**
|