pagyra-js 0.0.19 → 0.0.21
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/README.md +55 -0
- package/dist/assets/fonts/licenses/selawik/SIL Open Font License.txt +43 -0
- package/dist/assets/fonts/ttf/arimo/Arimo-Bold.ttf +0 -0
- package/dist/assets/fonts/ttf/arimo/Arimo-BoldItalic.ttf +0 -0
- package/dist/assets/fonts/ttf/arimo/Arimo-Italic.ttf +0 -0
- package/dist/assets/fonts/ttf/arimo/Arimo-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Black.ttf +0 -0
- package/dist/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Bold.ttf +0 -0
- package/dist/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/dejavu/DejaVuSans.ttf +0 -0
- package/dist/assets/fonts/ttf/firecode/FiraCode-Bold.ttf +0 -0
- package/dist/assets/fonts/ttf/firecode/FiraCode-Light.ttf +0 -0
- package/dist/assets/fonts/ttf/firecode/FiraCode-Medium.ttf +0 -0
- package/dist/assets/fonts/ttf/firecode/FiraCode-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/firecode/FiraCode-SemiBold.ttf +0 -0
- package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Bold.ttf +0 -0
- package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Light.ttf +0 -0
- package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Medium.ttf +0 -0
- package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/notoemoji/NotoEmoji-SemiBold.ttf +0 -0
- package/dist/assets/fonts/ttf/notosans/NotoSans-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/roboto/Roboto-Bold.ttf +0 -0
- package/dist/assets/fonts/ttf/roboto/Roboto-BoldItalic.ttf +0 -0
- package/dist/assets/fonts/ttf/roboto/Roboto-Italic.ttf +0 -0
- package/dist/assets/fonts/ttf/roboto/Roboto-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/selawik/selawk.ttf +0 -0
- package/dist/assets/fonts/ttf/selawik/selawkb.ttf +0 -0
- package/dist/assets/fonts/ttf/selawik/selawkl.ttf +0 -0
- package/dist/assets/fonts/ttf/selawik/selawksb.ttf +0 -0
- package/dist/assets/fonts/ttf/selawik/selawksl.ttf +0 -0
- package/dist/assets/fonts/ttf/stixtwomath/STIXTwoMath-Regular.ttf +0 -0
- package/dist/assets/fonts/ttf/tinos/Tinos-Bold.ttf +0 -0
- package/dist/assets/fonts/ttf/tinos/Tinos-BoldItalic.ttf +0 -0
- package/dist/assets/fonts/ttf/tinos/Tinos-Italic.ttf +0 -0
- package/dist/assets/fonts/ttf/tinos/Tinos-Regular.ttf +0 -0
- package/dist/assets/fonts/woff/lato/lato-latin-400-italic.woff +0 -0
- package/dist/assets/fonts/woff/lato/lato-latin-400-normal.woff +0 -0
- package/dist/assets/fonts/woff/lato/lato-latin-700-italic.woff +0 -0
- package/dist/assets/fonts/woff/lato/lato-latin-700-normal.woff +0 -0
- package/dist/assets/fonts/woff2/caveat/Caveat-Bold.woff2 +0 -0
- package/dist/assets/fonts/woff2/caveat/Caveat-Regular.woff2 +0 -0
- package/dist/assets/fonts/woff2/lato/lato-latin-400-italic.woff2 +0 -0
- package/dist/assets/fonts/woff2/lato/lato-latin-400-normal.woff2 +0 -0
- package/dist/assets/fonts/woff2/lato/lato-latin-700-italic.woff2 +0 -0
- package/dist/assets/fonts/woff2/lato/lato-latin-700-normal.woff2 +0 -0
- package/dist/browser/pagyra.min.js +34 -34
- package/dist/browser/pagyra.min.js.map +4 -4
- package/dist/playground/server.js +2 -0
- package/dist/src/css/compute-style/base-options.d.ts +7 -0
- package/dist/src/css/compute-style/base-options.js +24 -0
- package/dist/src/css/compute-style/declarations.d.ts +10 -0
- package/dist/src/css/compute-style/declarations.js +77 -0
- package/dist/src/css/compute-style/decoration.d.ts +8 -0
- package/dist/src/css/compute-style/decoration.js +55 -0
- package/dist/src/css/compute-style/defaults.d.ts +3 -0
- package/dist/src/css/compute-style/defaults.js +34 -0
- package/dist/src/css/compute-style/display.d.ts +3 -0
- package/dist/src/css/compute-style/display.js +85 -0
- package/dist/src/css/compute-style/float.d.ts +2 -0
- package/dist/src/css/compute-style/float.js +13 -0
- package/dist/src/css/compute-style/font.d.ts +12 -0
- package/dist/src/css/compute-style/font.js +57 -0
- package/dist/src/css/compute-style/overrides.d.ts +3 -0
- package/dist/src/css/compute-style/overrides.js +241 -0
- package/dist/src/css/compute-style.d.ts +2 -0
- package/dist/src/css/compute-style.js +34 -487
- package/dist/src/css/enums.d.ts +4 -0
- package/dist/src/css/enums.js +5 -0
- package/dist/src/css/layout-property-resolver.js +30 -18
- package/dist/src/css/length.d.ts +26 -2
- package/dist/src/css/length.js +48 -0
- package/dist/src/css/parsers/background-parser.js +1 -1
- package/dist/src/css/parsers/calc-parser.d.ts +2 -0
- package/dist/src/css/parsers/calc-parser.js +310 -0
- package/dist/src/css/parsers/content-parser.d.ts +2 -1
- package/dist/src/css/parsers/content-parser.js +7 -2
- package/dist/src/css/parsers/dimension-parser.js +37 -18
- package/dist/src/css/parsers/display-flex-parser.d.ts +4 -0
- package/dist/src/css/parsers/display-flex-parser.js +97 -0
- package/dist/src/css/parsers/filter-parser.d.ts +14 -0
- package/dist/src/css/parsers/filter-parser.js +255 -0
- package/dist/src/css/parsers/grid-parser-extended.d.ts +1 -0
- package/dist/src/css/parsers/grid-parser-extended.js +40 -1
- package/dist/src/css/parsers/grid-parser.d.ts +5 -2
- package/dist/src/css/parsers/grid-parser.js +71 -7
- package/dist/src/css/parsers/length-parser.d.ts +8 -3
- package/dist/src/css/parsers/length-parser.js +45 -2
- package/dist/src/css/parsers/margin-block-parser.js +3 -3
- package/dist/src/css/parsers/margin-parser.js +3 -3
- package/dist/src/css/parsers/padding-block-parser.js +3 -3
- package/dist/src/css/parsers/padding-inline-parser.js +3 -3
- package/dist/src/css/parsers/padding-parser.js +6 -6
- package/dist/src/css/parsers/position-parser.js +2 -22
- package/dist/src/css/parsers/register-parsers.js +29 -2
- package/dist/src/css/parsers/word-break-parser.d.ts +2 -0
- package/dist/src/css/parsers/word-break-parser.js +23 -0
- package/dist/src/css/properties/grid.d.ts +16 -2
- package/dist/src/css/properties/layout.d.ts +3 -1
- package/dist/src/css/properties/layout.js +1 -1
- package/dist/src/css/properties/misc.d.ts +5 -0
- package/dist/src/css/properties/typography.d.ts +3 -0
- package/dist/src/css/properties/visual.d.ts +36 -0
- package/dist/src/css/shorthands/box-shorthand.d.ts +2 -2
- package/dist/src/css/style-inheritance.d.ts +2 -1
- package/dist/src/css/style-inheritance.js +1 -0
- package/dist/src/css/style.d.ts +30 -10
- package/dist/src/css/style.js +8 -1
- package/dist/src/css/ua-defaults/base-defaults.d.ts +1 -0
- package/dist/src/css/ua-defaults/base-defaults.js +10 -1
- package/dist/src/css/ua-defaults/element-defaults.js +0 -2
- package/dist/src/html/css/parse-css.d.ts +2 -0
- package/dist/src/html/css/parse-css.js +32 -3
- package/dist/src/html/dom-converter/background-images.d.ts +3 -0
- package/dist/src/html/dom-converter/background-images.js +88 -0
- package/dist/src/html/dom-converter/convert-dom-node.d.ts +5 -0
- package/dist/src/html/dom-converter/convert-dom-node.js +81 -0
- package/dist/src/html/dom-converter/handlers/br-handler.d.ts +2 -0
- package/dist/src/html/dom-converter/handlers/br-handler.js +20 -0
- package/dist/src/html/dom-converter/handlers/form-control-handler.d.ts +2 -0
- package/dist/src/html/dom-converter/handlers/form-control-handler.js +28 -0
- package/dist/src/html/dom-converter/handlers/img-handler.d.ts +2 -0
- package/dist/src/html/dom-converter/handlers/img-handler.js +4 -0
- package/dist/src/html/dom-converter/handlers/index.d.ts +4 -0
- package/dist/src/html/dom-converter/handlers/index.js +19 -0
- package/dist/src/html/dom-converter/handlers/svg-handler.d.ts +2 -0
- package/dist/src/html/dom-converter/handlers/svg-handler.js +32 -0
- package/dist/src/html/dom-converter/handlers/types.d.ts +12 -0
- package/dist/src/html/dom-converter/handlers/types.js +2 -0
- package/dist/src/html/dom-converter/helpers.d.ts +7 -0
- package/dist/src/html/dom-converter/helpers.js +35 -0
- package/dist/src/html/dom-converter/index.d.ts +1 -0
- package/dist/src/html/dom-converter/index.js +1 -0
- package/dist/src/html/dom-converter/pseudo-elements.d.ts +6 -0
- package/dist/src/html/dom-converter/pseudo-elements.js +48 -0
- package/dist/src/html/dom-converter/text.d.ts +15 -0
- package/dist/src/html/dom-converter/text.js +170 -0
- package/dist/src/html/dom-converter.d.ts +1 -5
- package/dist/src/html/dom-converter.js +1 -412
- package/dist/src/html/image-converter.d.ts +5 -0
- package/dist/src/html/image-converter.js +8 -3
- package/dist/src/html-to-pdf/document-css.d.ts +14 -0
- package/dist/src/html-to-pdf/document-css.js +45 -0
- package/dist/src/html-to-pdf/fonts.d.ts +16 -0
- package/dist/src/html-to-pdf/fonts.js +74 -0
- package/dist/src/html-to-pdf/header-footer.d.ts +14 -0
- package/dist/src/html-to-pdf/header-footer.js +101 -0
- package/dist/src/html-to-pdf/html-parser.d.ts +6 -0
- package/dist/src/html-to-pdf/html-parser.js +81 -0
- package/dist/src/html-to-pdf/index.d.ts +3 -0
- package/dist/src/html-to-pdf/index.js +2 -0
- package/dist/src/html-to-pdf/layout-build.d.ts +37 -0
- package/dist/src/html-to-pdf/layout-build.js +73 -0
- package/dist/src/html-to-pdf/prepare-html-render.d.ts +2 -0
- package/dist/src/html-to-pdf/prepare-html-render.js +121 -0
- package/dist/src/html-to-pdf/render-finalize.d.ts +15 -0
- package/dist/src/html-to-pdf/render-finalize.js +27 -0
- package/dist/src/html-to-pdf/render-html-to-pdf.d.ts +3 -0
- package/dist/src/html-to-pdf/render-html-to-pdf.js +25 -0
- package/dist/src/html-to-pdf/resource-loader.d.ts +6 -0
- package/dist/src/html-to-pdf/resource-loader.js +120 -0
- package/dist/src/html-to-pdf/types.d.ts +38 -0
- package/dist/src/html-to-pdf/types.js +2 -0
- package/dist/src/html-to-pdf.d.ts +1 -37
- package/dist/src/html-to-pdf.js +1 -537
- package/dist/src/image/js-png-backend.d.ts +7 -0
- package/dist/src/image/js-png-backend.js +9 -0
- package/dist/src/image/png-backend.d.ts +5 -0
- package/dist/src/image/png-backend.js +1 -0
- package/dist/src/image/png-wasm-loader.d.ts +5 -0
- package/dist/src/image/png-wasm-loader.js +59 -0
- package/dist/src/image/wasm/png_decoder_wasm.d.ts +8 -0
- package/dist/src/image/wasm/png_decoder_wasm.js +24 -0
- package/dist/src/image/wasm/png_decoder_wasm_bg.js +16 -0
- package/dist/src/image/wasm-png-backend.d.ts +6 -0
- package/dist/src/image/wasm-png-backend.js +17 -0
- package/dist/src/layout/counter.d.ts +1 -2
- package/dist/src/layout/counter.js +18 -18
- package/dist/src/layout/inline/inline-utils.d.ts +1 -1
- package/dist/src/layout/inline/inline-utils.js +8 -7
- package/dist/src/layout/inline/layout.js +16 -3
- package/dist/src/layout/inline/run-placer.d.ts +1 -0
- package/dist/src/layout/inline/run-placer.js +2 -10
- package/dist/src/layout/pipeline/out-of-flow-manager.js +25 -1
- package/dist/src/layout/strategies/block.js +35 -24
- package/dist/src/layout/strategies/flex.js +305 -61
- package/dist/src/layout/strategies/form.d.ts +2 -0
- package/dist/src/layout/strategies/form.js +38 -13
- package/dist/src/layout/strategies/grid.js +166 -29
- package/dist/src/layout/strategies/image.js +53 -27
- package/dist/src/layout/strategies/inline.js +26 -21
- package/dist/src/layout/strategies/table.js +26 -18
- package/dist/src/layout/utils/content-measurer.d.ts +1 -1
- package/dist/src/layout/utils/content-measurer.js +8 -7
- package/dist/src/layout/utils/floats.d.ts +1 -0
- package/dist/src/layout/utils/floats.js +14 -12
- package/dist/src/layout/utils/margin.d.ts +4 -4
- package/dist/src/layout/utils/margin.js +20 -16
- package/dist/src/layout/utils/node-math.d.ts +12 -6
- package/dist/src/layout/utils/node-math.js +71 -41
- package/dist/src/layout/utils/sizing.js +2 -1
- package/dist/src/pdf/font-subset/font-registry.d.ts +6 -0
- package/dist/src/pdf/font-subset/font-registry.js +30 -2
- package/dist/src/pdf/header-footer-painter.d.ts +2 -0
- package/dist/src/pdf/header-footer-painter.js +52 -4
- package/dist/src/pdf/header-footer-renderer.js +12 -1
- package/dist/src/pdf/layout-tree-builder.js +5 -1
- package/dist/src/pdf/page-painter.js +13 -0
- package/dist/src/pdf/pagination.js +2 -2
- package/dist/src/pdf/renderer/box-painter.js +28 -3
- package/dist/src/pdf/renderer/page-paint.js +12 -3
- package/dist/src/pdf/renderers/radius-utils.js +31 -38
- package/dist/src/pdf/renderers/shape-renderer.js +1 -1
- package/dist/src/pdf/renderers/shape-utils.js +1 -1
- package/dist/src/pdf/renderers/text-renderer.d.ts +9 -1
- package/dist/src/pdf/renderers/text-renderer.js +36 -2
- package/dist/src/pdf/stacking/build-stacking-contexts.js +1 -2
- package/dist/src/pdf/stacking/resolve-paint-order.d.ts +5 -6
- package/dist/src/pdf/stacking/resolve-paint-order.js +29 -9
- package/dist/src/pdf/stacking/types.d.ts +14 -0
- package/dist/src/pdf/svg/shape-renderer.js +47 -20
- package/dist/src/pdf/types.d.ts +7 -1
- package/dist/src/pdf/utils/border-radius-utils.js +31 -38
- package/dist/src/pdf/utils/color-utils.js +17 -2
- package/dist/src/pdf/utils/filter-utils.d.ts +29 -0
- package/dist/src/pdf/utils/filter-utils.js +85 -0
- package/dist/src/pdf/utils/node-text-run-factory.js +1 -1
- package/dist/src/pdf/utils/text-layout-adjuster.d.ts +0 -8
- package/dist/src/pdf/utils/text-layout-adjuster.js +12 -9
- package/dist/src/shim/css-browser.d.ts +14 -9
- package/dist/src/shim/css-browser.js +50 -39
- package/dist/src/units/units.d.ts +1 -1
- package/dist/tests/css/box-sizing.spec.d.ts +1 -0
- package/dist/tests/css/box-sizing.spec.js +46 -0
- package/dist/tests/css/calc-parser.spec.d.ts +1 -0
- package/dist/tests/css/calc-parser.spec.js +68 -0
- package/dist/tests/css/container-query-units.spec.d.ts +1 -0
- package/dist/tests/css/container-query-units.spec.js +64 -0
- package/dist/tests/css/content-parser.spec.js +13 -0
- package/dist/tests/css/filter-parser.spec.d.ts +1 -0
- package/dist/tests/css/filter-parser.spec.js +116 -0
- package/dist/tests/css/flex-shorthand.spec.d.ts +1 -0
- package/dist/tests/css/flex-shorthand.spec.js +45 -0
- package/dist/tests/css/grid-clamp.spec.d.ts +1 -0
- package/dist/tests/css/grid-clamp.spec.js +82 -0
- package/dist/tests/css/parse-css-pseudo.spec.d.ts +1 -0
- package/dist/tests/css/parse-css-pseudo.spec.js +26 -0
- package/dist/tests/helpers/render-utils.d.ts +18 -2
- package/dist/tests/helpers/render-utils.js +25 -12
- package/dist/tests/html/dom-converter-pseudo-elements.spec.d.ts +1 -0
- package/dist/tests/html/dom-converter-pseudo-elements.spec.js +33 -0
- package/dist/tests/html/dom-converter-text.spec.d.ts +1 -0
- package/dist/tests/html/dom-converter-text.spec.js +67 -0
- package/dist/tests/image/png-backend.spec.d.ts +1 -0
- package/dist/tests/image/png-backend.spec.js +34 -0
- package/dist/tests/layout/box-sizing.spec.d.ts +1 -0
- package/dist/tests/layout/box-sizing.spec.js +75 -0
- package/dist/tests/layout/calc-padding.spec.d.ts +1 -0
- package/dist/tests/layout/calc-padding.spec.js +19 -0
- package/dist/tests/layout/container-query-units.spec.d.ts +1 -0
- package/dist/tests/layout/container-query-units.spec.js +24 -0
- package/dist/tests/layout/flex-auto-height.spec.d.ts +1 -0
- package/dist/tests/layout/flex-auto-height.spec.js +35 -0
- package/dist/tests/layout/flex-wrap-cards.spec.d.ts +1 -0
- package/dist/tests/layout/flex-wrap-cards.spec.js +16 -0
- package/dist/tests/layout/flex-wrap-grow-align-content.spec.d.ts +1 -0
- package/dist/tests/layout/flex-wrap-grow-align-content.spec.js +20 -0
- package/dist/tests/layout/grid-clamp-gap.spec.d.ts +1 -0
- package/dist/tests/layout/grid-clamp-gap.spec.js +22 -0
- package/dist/tests/layout/inline-fragments.spec.js +38 -0
- package/dist/tests/layout/paged-body-margin.spec.d.ts +1 -0
- package/dist/tests/layout/paged-body-margin.spec.js +92 -0
- package/dist/tests/layout/pseudo-counters-generated-content.spec.d.ts +1 -0
- package/dist/tests/layout/pseudo-counters-generated-content.spec.js +51 -0
- package/dist/tests/layout/responsive-clamp-grid-parity.spec.d.ts +1 -0
- package/dist/tests/layout/responsive-clamp-grid-parity.spec.js +75 -0
- package/dist/tests/layout/run-placer-baseline.spec.js +13 -11
- package/dist/tests/pdf/backdrop-filter-noop.spec.d.ts +1 -0
- package/dist/tests/pdf/backdrop-filter-noop.spec.js +140 -0
- package/dist/tests/pdf/filter-drop-shadow.spec.d.ts +1 -0
- package/dist/tests/pdf/filter-drop-shadow.spec.js +74 -0
- package/dist/tests/pdf/filter-opacity.spec.d.ts +1 -0
- package/dist/tests/pdf/filter-opacity.spec.js +30 -0
- package/dist/tests/pdf/font-subset-registry-key.spec.d.ts +1 -0
- package/dist/tests/pdf/font-subset-registry-key.spec.js +66 -0
- package/dist/tests/pdf/header-footer-clip-overflow.spec.d.ts +1 -0
- package/dist/tests/pdf/header-footer-clip-overflow.spec.js +45 -0
- package/dist/tests/pdf/selawik-opt-in.spec.d.ts +1 -0
- package/dist/tests/pdf/selawik-opt-in.spec.js +106 -0
- package/dist/tests/pdf/system-ui-fallback-subset-regression.spec.d.ts +1 -0
- package/dist/tests/pdf/system-ui-fallback-subset-regression.spec.js +39 -0
- package/dist/tests/pdf/text-renderer-fallback.spec.js +55 -0
- package/dist/tests/pdf/text-transform-matrix.spec.js +8 -7
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LayoutNode } from "../../dom/node.js";
|
|
2
2
|
import { AlignItems, Display, JustifyContent } from "../../css/enums.js";
|
|
3
|
-
import { containingBlock, resolveBoxMetrics } from "../utils/node-math.js";
|
|
3
|
+
import { adjustForBoxSizing, containingBlock, resolveBoxMetrics, resolveWidthBlock } from "../utils/node-math.js";
|
|
4
4
|
import { resolveLength, isAutoLength } from "../../css/length.js";
|
|
5
5
|
import { GapCalculator, calculateTotalGap } from "../utils/gap-calculator.js";
|
|
6
6
|
function blockifyFlexItemDisplay(display) {
|
|
@@ -33,6 +33,153 @@ function allowsPreferredShrink(originalDisplay, effectiveDisplay) {
|
|
|
33
33
|
}
|
|
34
34
|
return originalDisplay === Display.Inline;
|
|
35
35
|
}
|
|
36
|
+
function buildFlexLines(items, containerMainSize, mainAxisGap) {
|
|
37
|
+
if (items.length === 0) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const lines = [];
|
|
41
|
+
let current = { items: [], mainSizeWithGaps: 0, crossSize: 0 };
|
|
42
|
+
for (const item of items) {
|
|
43
|
+
const addition = current.items.length === 0 ? item.mainContribution : mainAxisGap + item.mainContribution;
|
|
44
|
+
const shouldWrap = current.items.length > 0 &&
|
|
45
|
+
containerMainSize > 0 &&
|
|
46
|
+
current.mainSizeWithGaps + addition > containerMainSize + 0.01;
|
|
47
|
+
if (shouldWrap) {
|
|
48
|
+
lines.push(current);
|
|
49
|
+
current = { items: [], mainSizeWithGaps: 0, crossSize: 0 };
|
|
50
|
+
}
|
|
51
|
+
if (current.items.length > 0) {
|
|
52
|
+
current.mainSizeWithGaps += mainAxisGap;
|
|
53
|
+
}
|
|
54
|
+
current.items.push(item);
|
|
55
|
+
current.mainSizeWithGaps += item.mainContribution;
|
|
56
|
+
current.crossSize = Math.max(current.crossSize, item.crossContribution);
|
|
57
|
+
}
|
|
58
|
+
if (current.items.length > 0) {
|
|
59
|
+
lines.push(current);
|
|
60
|
+
}
|
|
61
|
+
return lines;
|
|
62
|
+
}
|
|
63
|
+
function calculateLinesCrossSize(lines, crossAxisGap) {
|
|
64
|
+
if (lines.length === 0) {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const totalLines = lines.reduce((sum, line) => sum + line.crossSize, 0);
|
|
68
|
+
return totalLines + calculateTotalGap(crossAxisGap, lines.length);
|
|
69
|
+
}
|
|
70
|
+
function refreshFlexItemSizes(item, isRow) {
|
|
71
|
+
item.mainSize = isRow ? item.node.box.borderBoxWidth : item.node.box.borderBoxHeight;
|
|
72
|
+
item.crossSize = isRow ? item.node.box.borderBoxHeight : item.node.box.borderBoxWidth;
|
|
73
|
+
item.mainContribution = item.mainSize + item.mainMarginStart + item.mainMarginEnd;
|
|
74
|
+
item.crossContribution = item.crossSize + item.crossMarginStart + item.crossMarginEnd;
|
|
75
|
+
}
|
|
76
|
+
function recomputeLineMetrics(line, mainAxisGap) {
|
|
77
|
+
let mainSizeWithGaps = 0;
|
|
78
|
+
let crossSize = 0;
|
|
79
|
+
for (let i = 0; i < line.items.length; i++) {
|
|
80
|
+
const item = line.items[i];
|
|
81
|
+
if (i > 0) {
|
|
82
|
+
mainSizeWithGaps += mainAxisGap;
|
|
83
|
+
}
|
|
84
|
+
mainSizeWithGaps += item.mainContribution;
|
|
85
|
+
crossSize = Math.max(crossSize, item.crossContribution);
|
|
86
|
+
}
|
|
87
|
+
line.mainSizeWithGaps = mainSizeWithGaps;
|
|
88
|
+
line.crossSize = crossSize;
|
|
89
|
+
}
|
|
90
|
+
function relayoutFlexItemForMainSize(container, item, context, targetMainSize, isRow) {
|
|
91
|
+
if (!Number.isFinite(targetMainSize) || targetMainSize < 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const prevContainerWidth = container.box.contentWidth;
|
|
95
|
+
const prevContainerHeight = container.box.contentHeight;
|
|
96
|
+
const targetContribution = targetMainSize + item.mainMarginStart + item.mainMarginEnd;
|
|
97
|
+
let displayMutated = false;
|
|
98
|
+
if (item.node.style.display !== item.effectiveDisplay) {
|
|
99
|
+
item.node.style.display = item.effectiveDisplay;
|
|
100
|
+
displayMutated = true;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
if (isRow) {
|
|
104
|
+
container.box.contentWidth = Math.max(0, targetContribution);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
container.box.contentHeight = Math.max(0, targetContribution);
|
|
108
|
+
}
|
|
109
|
+
context.layoutChild(item.node);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
container.box.contentWidth = prevContainerWidth;
|
|
113
|
+
container.box.contentHeight = prevContainerHeight;
|
|
114
|
+
if (displayMutated) {
|
|
115
|
+
item.node.style.display = item.originalDisplay;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function distributeFlexGrowAcrossLines(lines, container, context, containerMainSize, mainAxisGap, isRow) {
|
|
120
|
+
if (lines.length === 0 || !(containerMainSize > 0)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
for (const line of lines) {
|
|
124
|
+
const freeSpace = containerMainSize - line.mainSizeWithGaps;
|
|
125
|
+
if (!(freeSpace > 0)) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const growItems = line.items.filter((item) => item.flexGrow > 0);
|
|
129
|
+
const totalGrow = growItems.reduce((sum, item) => sum + item.flexGrow, 0);
|
|
130
|
+
if (!(totalGrow > 0)) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
for (const item of growItems) {
|
|
134
|
+
const delta = (freeSpace * item.flexGrow) / totalGrow;
|
|
135
|
+
const targetMainSize = Math.max(0, item.mainSize + delta);
|
|
136
|
+
if (Math.abs(targetMainSize - item.mainSize) < 0.01) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
relayoutFlexItemForMainSize(container, item, context, targetMainSize, isRow);
|
|
140
|
+
refreshFlexItemSizes(item, isRow);
|
|
141
|
+
}
|
|
142
|
+
recomputeLineMetrics(line, mainAxisGap);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function resolveAlignContentLayout(lines, alignContent, containerCrossSize, crossAxisGap) {
|
|
146
|
+
const lineCrossSizes = lines.map((line) => line.crossSize);
|
|
147
|
+
if (lines.length === 0) {
|
|
148
|
+
return { lineCrossSizes, initialOffset: 0, additionalGap: 0 };
|
|
149
|
+
}
|
|
150
|
+
const naturalCross = calculateLinesCrossSize(lines, crossAxisGap);
|
|
151
|
+
const freeSpace = Math.max(0, containerCrossSize - naturalCross);
|
|
152
|
+
switch (alignContent) {
|
|
153
|
+
case "stretch":
|
|
154
|
+
if (freeSpace > 0) {
|
|
155
|
+
const extraPerLine = freeSpace / lines.length;
|
|
156
|
+
for (let i = 0; i < lineCrossSizes.length; i++) {
|
|
157
|
+
lineCrossSizes[i] += extraPerLine;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return { lineCrossSizes, initialOffset: 0, additionalGap: 0 };
|
|
161
|
+
case "flex-end":
|
|
162
|
+
return { lineCrossSizes, initialOffset: freeSpace, additionalGap: 0 };
|
|
163
|
+
case "center":
|
|
164
|
+
return { lineCrossSizes, initialOffset: freeSpace / 2, additionalGap: 0 };
|
|
165
|
+
case "space-between":
|
|
166
|
+
if (lines.length <= 1) {
|
|
167
|
+
return { lineCrossSizes, initialOffset: 0, additionalGap: 0 };
|
|
168
|
+
}
|
|
169
|
+
return { lineCrossSizes, initialOffset: 0, additionalGap: freeSpace / (lines.length - 1) };
|
|
170
|
+
case "space-around": {
|
|
171
|
+
const gap = freeSpace / lines.length;
|
|
172
|
+
return { lineCrossSizes, initialOffset: gap / 2, additionalGap: gap };
|
|
173
|
+
}
|
|
174
|
+
case "space-evenly": {
|
|
175
|
+
const gap = freeSpace / (lines.length + 1);
|
|
176
|
+
return { lineCrossSizes, initialOffset: gap, additionalGap: gap };
|
|
177
|
+
}
|
|
178
|
+
case "flex-start":
|
|
179
|
+
default:
|
|
180
|
+
return { lineCrossSizes, initialOffset: 0, additionalGap: 0 };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
36
183
|
export class FlexLayoutStrategy {
|
|
37
184
|
constructor() {
|
|
38
185
|
this.supportedDisplays = new Set([Display.Flex, Display.InlineFlex]);
|
|
@@ -42,24 +189,34 @@ export class FlexLayoutStrategy {
|
|
|
42
189
|
}
|
|
43
190
|
layout(node, context) {
|
|
44
191
|
const cb = containingBlock(node, context.env.viewport);
|
|
192
|
+
const containerRefs = { containerWidth: cb.width, containerHeight: cb.height };
|
|
45
193
|
const isRow = isRowDirection(node.style.flexDirection);
|
|
46
194
|
const cbMain = isRow ? cb.width : cb.height;
|
|
47
195
|
const cbCross = isRow ? cb.height : cb.width;
|
|
48
|
-
|
|
49
|
-
const
|
|
196
|
+
// Resolve box metrics (padding/border)
|
|
197
|
+
const boxMetrics = resolveBoxMetrics(node, cb.width, cb.height);
|
|
198
|
+
const hExtras = boxMetrics.paddingLeft + boxMetrics.paddingRight + boxMetrics.borderLeft + boxMetrics.borderRight;
|
|
199
|
+
const vExtras = boxMetrics.paddingTop + boxMetrics.paddingBottom + boxMetrics.borderTop + boxMetrics.borderBottom;
|
|
200
|
+
let specifiedMain = resolveFlexSize(isRow ? node.style.width : node.style.height, cbMain, cb.width, cb.height);
|
|
201
|
+
let specifiedCross = resolveFlexSize(isRow ? node.style.height : node.style.width, cbCross, cb.width, cb.height);
|
|
202
|
+
if (specifiedMain !== undefined) {
|
|
203
|
+
specifiedMain = adjustForBoxSizing(specifiedMain, node.style.boxSizing, isRow ? hExtras : vExtras);
|
|
204
|
+
}
|
|
205
|
+
if (specifiedCross !== undefined) {
|
|
206
|
+
specifiedCross = adjustForBoxSizing(specifiedCross, node.style.boxSizing, isRow ? vExtras : hExtras);
|
|
207
|
+
}
|
|
50
208
|
// Read gap properties for flex layout
|
|
51
209
|
const rowGap = node.style.rowGap ?? 0;
|
|
52
210
|
const columnGap = node.style.columnGap ?? 0;
|
|
53
211
|
const gapCalculator = new GapCalculator({ rowGap, columnGap });
|
|
54
212
|
const mainAxisGap = gapCalculator.getMainAxisGap(isRow);
|
|
55
|
-
|
|
56
|
-
const boxMetrics = resolveBoxMetrics(node, cb.width, cb.height);
|
|
213
|
+
const defaultContentWidth = resolveWidthBlock(node, cb.width, cb.height);
|
|
57
214
|
if (isRow) {
|
|
58
|
-
node.box.contentWidth = resolveInitialDimension(specifiedMain,
|
|
215
|
+
node.box.contentWidth = resolveInitialDimension(specifiedMain, defaultContentWidth);
|
|
59
216
|
node.box.contentHeight = resolveInitialDimension(specifiedCross, cbCross);
|
|
60
217
|
}
|
|
61
218
|
else {
|
|
62
|
-
node.box.contentWidth = resolveInitialDimension(specifiedCross,
|
|
219
|
+
node.box.contentWidth = resolveInitialDimension(specifiedCross, defaultContentWidth);
|
|
63
220
|
node.box.contentHeight = resolveInitialDimension(specifiedMain, cbMain);
|
|
64
221
|
}
|
|
65
222
|
node.box.borderBoxWidth =
|
|
@@ -90,27 +247,42 @@ export class FlexLayoutStrategy {
|
|
|
90
247
|
if (displayMutated) {
|
|
91
248
|
child.style.display = blockifiedDisplay;
|
|
92
249
|
}
|
|
250
|
+
const parentContentWidth = node.box.contentWidth;
|
|
251
|
+
const parentContentHeight = node.box.contentHeight;
|
|
93
252
|
try {
|
|
253
|
+
const basisReference = isRow ? cb.width : cb.height;
|
|
254
|
+
const basis = resolveFlexSize(child.style.flexBasis, basisReference, cb.width, cb.height);
|
|
255
|
+
if (basis !== undefined) {
|
|
256
|
+
if (isRow) {
|
|
257
|
+
node.box.contentWidth = Math.max(0, basis);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
node.box.contentHeight = Math.max(0, basis);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
94
263
|
context.layoutChild(child);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
const
|
|
264
|
+
node.box.contentWidth = parentContentWidth;
|
|
265
|
+
node.box.contentHeight = parentContentHeight;
|
|
266
|
+
const marginLeft = resolveLength(child.style.marginLeft, cb.width, { auto: "zero", ...containerRefs });
|
|
267
|
+
const marginRight = resolveLength(child.style.marginRight, cb.width, { auto: "zero", ...containerRefs });
|
|
268
|
+
const marginTop = resolveLength(child.style.marginTop, cb.height, { auto: "zero", ...containerRefs });
|
|
269
|
+
const marginBottom = resolveLength(child.style.marginBottom, cb.height, { auto: "zero", ...containerRefs });
|
|
99
270
|
const mainMarginStart = isRow ? marginLeft : marginTop;
|
|
100
271
|
const mainMarginEnd = isRow ? marginRight : marginBottom;
|
|
101
272
|
const crossMarginStart = isRow ? marginTop : marginLeft;
|
|
102
273
|
const crossMarginEnd = isRow ? marginBottom : marginRight;
|
|
103
274
|
let mainSize = isRow ? child.box.borderBoxWidth : child.box.borderBoxHeight;
|
|
275
|
+
const hasExplicitFlexBasis = resolveFlexSize(child.style.flexBasis, isRow ? cb.width : cb.height, cb.width, cb.height) !== undefined;
|
|
104
276
|
const childDisplay = blockifiedDisplay;
|
|
105
277
|
const allowPreferredShrink = allowsPreferredShrink(originalDisplay, childDisplay);
|
|
106
|
-
if (isRow && allowPreferredShrink && isAutoMainSize(child.style.width)) {
|
|
278
|
+
if (isRow && allowPreferredShrink && isAutoMainSize(child.style.width) && !hasExplicitFlexBasis) {
|
|
107
279
|
const preferredContent = computePreferredInlineWidth(child);
|
|
108
280
|
if (preferredContent !== undefined && preferredContent >= 0) {
|
|
109
281
|
const minWidth = child.style.minWidth !== undefined
|
|
110
|
-
? resolveLength(child.style.minWidth, cb.width, { auto: "zero" })
|
|
282
|
+
? resolveLength(child.style.minWidth, cb.width, { auto: "zero", ...containerRefs })
|
|
111
283
|
: undefined;
|
|
112
284
|
const maxWidth = child.style.maxWidth !== undefined
|
|
113
|
-
? resolveLength(child.style.maxWidth, cb.width, { auto: "reference" })
|
|
285
|
+
? resolveLength(child.style.maxWidth, cb.width, { auto: "reference", ...containerRefs })
|
|
114
286
|
: undefined;
|
|
115
287
|
let targetContentWidth = preferredContent;
|
|
116
288
|
if (minWidth !== undefined) {
|
|
@@ -120,15 +292,20 @@ export class FlexLayoutStrategy {
|
|
|
120
292
|
targetContentWidth = Math.min(targetContentWidth, maxWidth);
|
|
121
293
|
}
|
|
122
294
|
if (targetContentWidth < child.box.contentWidth) {
|
|
123
|
-
const paddingLeft = resolveLength(child.style.paddingLeft, cb.width, { auto: "zero" });
|
|
124
|
-
const paddingRight = resolveLength(child.style.paddingRight, cb.width, { auto: "zero" });
|
|
125
|
-
const borderLeft = resolveLength(child.style.borderLeft, cb.width, { auto: "zero" });
|
|
126
|
-
const borderRight = resolveLength(child.style.borderRight, cb.width, { auto: "zero" });
|
|
295
|
+
const paddingLeft = resolveLength(child.style.paddingLeft, cb.width, { auto: "zero", ...containerRefs });
|
|
296
|
+
const paddingRight = resolveLength(child.style.paddingRight, cb.width, { auto: "zero", ...containerRefs });
|
|
297
|
+
const borderLeft = resolveLength(child.style.borderLeft, cb.width, { auto: "zero", ...containerRefs });
|
|
298
|
+
const borderRight = resolveLength(child.style.borderRight, cb.width, { auto: "zero", ...containerRefs });
|
|
127
299
|
child.box.contentWidth = targetContentWidth;
|
|
128
300
|
child.box.borderBoxWidth = targetContentWidth + paddingLeft + paddingRight + borderLeft + borderRight;
|
|
129
301
|
child.box.marginBoxWidth = child.box.borderBoxWidth + marginLeft + marginRight;
|
|
130
302
|
child.box.scrollWidth = Math.max(child.box.scrollWidth, child.box.contentWidth);
|
|
131
303
|
mainSize = child.box.borderBoxWidth;
|
|
304
|
+
// Re-layout with corrected width so inline text positions are correct
|
|
305
|
+
const prevW = node.box.contentWidth;
|
|
306
|
+
node.box.contentWidth = child.box.borderBoxWidth + marginLeft + marginRight;
|
|
307
|
+
context.layoutChild(child);
|
|
308
|
+
node.box.contentWidth = prevW;
|
|
132
309
|
}
|
|
133
310
|
}
|
|
134
311
|
}
|
|
@@ -140,15 +317,15 @@ export class FlexLayoutStrategy {
|
|
|
140
317
|
const preferredContent = computePreferredInlineWidth(child);
|
|
141
318
|
if (preferredContent !== undefined && preferredContent > 0) {
|
|
142
319
|
const widthRef = cb.width;
|
|
143
|
-
const paddingLeft = resolveLength(child.style.paddingLeft, widthRef, { auto: "zero" });
|
|
144
|
-
const paddingRight = resolveLength(child.style.paddingRight, widthRef, { auto: "zero" });
|
|
145
|
-
const borderLeft = resolveLength(child.style.borderLeft, widthRef, { auto: "zero" });
|
|
146
|
-
const borderRight = resolveLength(child.style.borderRight, widthRef, { auto: "zero" });
|
|
320
|
+
const paddingLeft = resolveLength(child.style.paddingLeft, widthRef, { auto: "zero", ...containerRefs });
|
|
321
|
+
const paddingRight = resolveLength(child.style.paddingRight, widthRef, { auto: "zero", ...containerRefs });
|
|
322
|
+
const borderLeft = resolveLength(child.style.borderLeft, widthRef, { auto: "zero", ...containerRefs });
|
|
323
|
+
const borderRight = resolveLength(child.style.borderRight, widthRef, { auto: "zero", ...containerRefs });
|
|
147
324
|
const minWidth = child.style.minWidth !== undefined
|
|
148
|
-
? resolveLength(child.style.minWidth, widthRef, { auto: "zero" })
|
|
325
|
+
? resolveLength(child.style.minWidth, widthRef, { auto: "zero", ...containerRefs })
|
|
149
326
|
: undefined;
|
|
150
327
|
const maxWidth = child.style.maxWidth !== undefined
|
|
151
|
-
? resolveLength(child.style.maxWidth, widthRef, { auto: "reference" })
|
|
328
|
+
? resolveLength(child.style.maxWidth, widthRef, { auto: "reference", ...containerRefs })
|
|
152
329
|
: undefined;
|
|
153
330
|
let targetContentWidth = Math.min(preferredContent, child.box.contentWidth);
|
|
154
331
|
if (minWidth !== undefined) {
|
|
@@ -174,6 +351,8 @@ export class FlexLayoutStrategy {
|
|
|
174
351
|
const crossContribution = crossSize + crossMarginStart + crossMarginEnd;
|
|
175
352
|
items.push({
|
|
176
353
|
node: child,
|
|
354
|
+
originalDisplay,
|
|
355
|
+
effectiveDisplay: blockifiedDisplay,
|
|
177
356
|
mainMarginStart,
|
|
178
357
|
mainMarginEnd,
|
|
179
358
|
crossMarginStart,
|
|
@@ -182,11 +361,15 @@ export class FlexLayoutStrategy {
|
|
|
182
361
|
crossSize,
|
|
183
362
|
mainContribution,
|
|
184
363
|
crossContribution,
|
|
364
|
+
flexGrow: Math.max(0, child.style.flexGrow ?? 0),
|
|
365
|
+
flexShrink: Math.max(0, child.style.flexShrink ?? 0),
|
|
185
366
|
});
|
|
186
367
|
totalMain += mainContribution;
|
|
187
368
|
maxCrossContribution = Math.max(maxCrossContribution, crossContribution);
|
|
188
369
|
}
|
|
189
370
|
finally {
|
|
371
|
+
node.box.contentWidth = parentContentWidth;
|
|
372
|
+
node.box.contentHeight = parentContentHeight;
|
|
190
373
|
if (displayMutated) {
|
|
191
374
|
child.style.display = originalDisplay;
|
|
192
375
|
}
|
|
@@ -194,30 +377,60 @@ export class FlexLayoutStrategy {
|
|
|
194
377
|
}
|
|
195
378
|
// Account for gaps in total main size
|
|
196
379
|
const gapSpace = calculateTotalGap(mainAxisGap, items.length);
|
|
197
|
-
|
|
380
|
+
let totalMainWithGaps = totalMain + gapSpace;
|
|
381
|
+
const wrapEnabled = isRow && node.style.flexWrap;
|
|
382
|
+
const crossAxisGap = gapCalculator.getCrossAxisGap(isRow);
|
|
198
383
|
let containerMainSize;
|
|
199
384
|
if (specifiedMain !== undefined) {
|
|
200
385
|
containerMainSize = specifiedMain;
|
|
201
386
|
}
|
|
387
|
+
else if (isRow) {
|
|
388
|
+
const reference = Number.isFinite(defaultContentWidth) && defaultContentWidth > 0 ? defaultContentWidth : totalMainWithGaps;
|
|
389
|
+
containerMainSize = wrapEnabled ? reference : Math.max(reference, totalMainWithGaps);
|
|
390
|
+
}
|
|
202
391
|
else {
|
|
203
|
-
|
|
204
|
-
|
|
392
|
+
// For column flex containers with auto height, use content-based sizing.
|
|
393
|
+
// Falling back to containing block height incorrectly stretches the box
|
|
394
|
+
// to the page/viewport height in HTML->PDF flow layouts.
|
|
395
|
+
containerMainSize = totalMainWithGaps;
|
|
205
396
|
}
|
|
397
|
+
const lines = wrapEnabled ? buildFlexLines(items, containerMainSize, mainAxisGap) : [];
|
|
398
|
+
if (wrapEnabled) {
|
|
399
|
+
distributeFlexGrowAcrossLines(lines, node, context, containerMainSize, mainAxisGap, isRow);
|
|
400
|
+
}
|
|
401
|
+
else if (items.length > 0) {
|
|
402
|
+
const singleLine = {
|
|
403
|
+
items,
|
|
404
|
+
mainSizeWithGaps: totalMainWithGaps,
|
|
405
|
+
crossSize: maxCrossContribution,
|
|
406
|
+
};
|
|
407
|
+
distributeFlexGrowAcrossLines([singleLine], node, context, containerMainSize, mainAxisGap, isRow);
|
|
408
|
+
totalMain = items.reduce((sum, item) => sum + item.mainContribution, 0);
|
|
409
|
+
maxCrossContribution = items.reduce((max, item) => Math.max(max, item.crossContribution), 0);
|
|
410
|
+
totalMainWithGaps = totalMain + gapSpace;
|
|
411
|
+
}
|
|
412
|
+
const wrappedCrossContribution = wrapEnabled ? calculateLinesCrossSize(lines, crossAxisGap) : 0;
|
|
206
413
|
let containerCrossSize;
|
|
207
414
|
if (specifiedCross !== undefined) {
|
|
208
|
-
|
|
415
|
+
const measuredCross = wrapEnabled ? wrappedCrossContribution : maxCrossContribution;
|
|
416
|
+
containerCrossSize = Math.max(specifiedCross, measuredCross);
|
|
209
417
|
}
|
|
210
418
|
else if (!isRow) {
|
|
211
|
-
const referenceCross = Number.isFinite(
|
|
419
|
+
const referenceCross = Number.isFinite(defaultContentWidth) && defaultContentWidth > 0 ? defaultContentWidth : maxCrossContribution;
|
|
212
420
|
containerCrossSize = Math.max(referenceCross, maxCrossContribution);
|
|
213
421
|
}
|
|
214
422
|
else {
|
|
215
|
-
containerCrossSize = maxCrossContribution;
|
|
423
|
+
containerCrossSize = wrapEnabled ? wrappedCrossContribution : maxCrossContribution;
|
|
216
424
|
}
|
|
217
425
|
const minCrossValue = isRow ? node.style.minHeight : node.style.minWidth;
|
|
218
426
|
const maxCrossValue = isRow ? node.style.maxHeight : node.style.maxWidth;
|
|
219
|
-
const
|
|
220
|
-
const
|
|
427
|
+
const crossExtras = isRow ? vExtras : hExtras;
|
|
428
|
+
const minCross = minCrossValue !== undefined
|
|
429
|
+
? adjustForBoxSizing(resolveLength(minCrossValue, cbCross, { auto: "zero", ...containerRefs }), node.style.boxSizing, crossExtras)
|
|
430
|
+
: undefined;
|
|
431
|
+
const maxCross = maxCrossValue !== undefined
|
|
432
|
+
? adjustForBoxSizing(resolveLength(maxCrossValue, cbCross, { auto: "reference", ...containerRefs }), node.style.boxSizing, crossExtras)
|
|
433
|
+
: undefined;
|
|
221
434
|
if (minCross !== undefined) {
|
|
222
435
|
containerCrossSize = Math.max(containerCrossSize, minCross);
|
|
223
436
|
}
|
|
@@ -226,30 +439,62 @@ export class FlexLayoutStrategy {
|
|
|
226
439
|
}
|
|
227
440
|
const justify = node.style.justifyContent ?? JustifyContent.FlexStart;
|
|
228
441
|
const align = alignContainer;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
442
|
+
if (wrapEnabled) {
|
|
443
|
+
const alignContent = node.style.alignContent;
|
|
444
|
+
const crossLayout = resolveAlignContentLayout(lines, alignContent, containerCrossSize, crossAxisGap);
|
|
445
|
+
let crossCursor = crossLayout.initialOffset;
|
|
446
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
447
|
+
const line = lines[lineIndex];
|
|
448
|
+
const lineCrossSize = crossLayout.lineCrossSizes[lineIndex] ?? line.crossSize;
|
|
449
|
+
const freeSpaceAfterGaps = containerMainSize - line.mainSizeWithGaps;
|
|
450
|
+
const { offset: initialOffset, gap: justifyGap } = resolveJustifySpacing(justify, freeSpaceAfterGaps, line.items.length);
|
|
451
|
+
let mainCursor = initialOffset;
|
|
452
|
+
for (let index = 0; index < line.items.length; index++) {
|
|
453
|
+
const item = line.items[index];
|
|
454
|
+
const alignSelf = resolveItemAlignment(item.node.style.alignSelf, align);
|
|
455
|
+
const crossOffset = computeCrossOffset(alignSelf, lineCrossSize, item.crossSize, item.crossMarginStart, item.crossMarginEnd);
|
|
456
|
+
const previousX = item.node.box.x;
|
|
457
|
+
const previousY = item.node.box.y;
|
|
458
|
+
item.node.box.x = boxMetrics.contentBoxX + mainCursor + item.mainMarginStart;
|
|
459
|
+
item.node.box.y = boxMetrics.contentBoxY + crossCursor + crossOffset + item.crossMarginStart;
|
|
460
|
+
offsetLayoutSubtree(item.node, item.node.box.x - previousX, item.node.box.y - previousY);
|
|
461
|
+
mainCursor += item.mainContribution;
|
|
462
|
+
if (index < line.items.length - 1) {
|
|
463
|
+
mainCursor += mainAxisGap + justifyGap;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
crossCursor += lineCrossSize;
|
|
467
|
+
if (lineIndex < lines.length - 1) {
|
|
468
|
+
crossCursor += crossAxisGap + crossLayout.additionalGap;
|
|
469
|
+
}
|
|
247
470
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
// Calculate justify spacing based on free space AFTER accounting for gaps.
|
|
474
|
+
// This makes gap additive with justify-content spacing (per CSS Flexbox spec).
|
|
475
|
+
const freeSpaceAfterGaps = containerMainSize - totalMainWithGaps;
|
|
476
|
+
const { offset: initialOffset, gap: justifyGap } = resolveJustifySpacing(justify, freeSpaceAfterGaps, items.length);
|
|
477
|
+
let cursor = initialOffset;
|
|
478
|
+
for (let index = 0; index < items.length; index++) {
|
|
479
|
+
const item = items[index];
|
|
480
|
+
const alignSelf = resolveItemAlignment(item.node.style.alignSelf, align);
|
|
481
|
+
const crossOffset = computeCrossOffset(alignSelf, containerCrossSize, item.crossSize, item.crossMarginStart, item.crossMarginEnd);
|
|
482
|
+
const previousX = item.node.box.x;
|
|
483
|
+
const previousY = item.node.box.y;
|
|
484
|
+
if (isRow) {
|
|
485
|
+
item.node.box.x = boxMetrics.contentBoxX + cursor + item.mainMarginStart;
|
|
486
|
+
item.node.box.y = boxMetrics.contentBoxY + crossOffset + item.crossMarginStart;
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
item.node.box.x = boxMetrics.contentBoxX + crossOffset + item.crossMarginStart;
|
|
490
|
+
item.node.box.y = boxMetrics.contentBoxY + cursor + item.mainMarginStart;
|
|
491
|
+
}
|
|
492
|
+
offsetLayoutSubtree(item.node, item.node.box.x - previousX, item.node.box.y - previousY);
|
|
493
|
+
cursor += item.mainContribution;
|
|
494
|
+
if (index < items.length - 1) {
|
|
495
|
+
// Apply explicit gap PLUS justify spacing (additive per spec).
|
|
496
|
+
cursor += mainAxisGap + justifyGap;
|
|
497
|
+
}
|
|
253
498
|
}
|
|
254
499
|
}
|
|
255
500
|
if (isRow) {
|
|
@@ -285,7 +530,7 @@ function resolveInitialDimension(specified, fallback) {
|
|
|
285
530
|
}
|
|
286
531
|
return 0;
|
|
287
532
|
}
|
|
288
|
-
function resolveFlexSize(value, reference) {
|
|
533
|
+
function resolveFlexSize(value, reference, containerWidth = reference, containerHeight = reference) {
|
|
289
534
|
if (value === undefined) {
|
|
290
535
|
return undefined;
|
|
291
536
|
}
|
|
@@ -295,7 +540,7 @@ function resolveFlexSize(value, reference) {
|
|
|
295
540
|
if (value === "auto" || isAutoLength(value)) {
|
|
296
541
|
return undefined;
|
|
297
542
|
}
|
|
298
|
-
return resolveLength(value, reference, { auto: "reference" });
|
|
543
|
+
return resolveLength(value, reference, { auto: "reference", containerWidth, containerHeight });
|
|
299
544
|
}
|
|
300
545
|
function resolveItemAlignment(alignSelf, containerAlign) {
|
|
301
546
|
if (alignSelf && alignSelf !== "auto") {
|
|
@@ -393,11 +638,10 @@ function offsetLayoutSubtree(node, deltaX, deltaY) {
|
|
|
393
638
|
return;
|
|
394
639
|
}
|
|
395
640
|
node.walk((desc) => {
|
|
396
|
-
if (desc
|
|
397
|
-
|
|
641
|
+
if (desc !== node) {
|
|
642
|
+
desc.box.x += deltaX;
|
|
643
|
+
desc.box.y += deltaY;
|
|
398
644
|
}
|
|
399
|
-
desc.box.x += deltaX;
|
|
400
|
-
desc.box.y += deltaY;
|
|
401
645
|
desc.box.baseline += deltaY;
|
|
402
646
|
// Update inline runs if they exist
|
|
403
647
|
if (desc.inlineRuns && desc.inlineRuns.length > 0) {
|
|
@@ -2,6 +2,8 @@ import { LayoutNode } from "../../dom/node.js";
|
|
|
2
2
|
import type { LayoutContext, LayoutStrategy } from "../pipeline/strategy.js";
|
|
3
3
|
export declare class FormLayoutStrategy implements LayoutStrategy {
|
|
4
4
|
private readonly formTags;
|
|
5
|
+
private resolveExplicitOrAutoWidth;
|
|
6
|
+
private resolveExplicitOrAutoHeight;
|
|
5
7
|
canLayout(node: LayoutNode): boolean;
|
|
6
8
|
layout(node: LayoutNode, context: LayoutContext): void;
|
|
7
9
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LayoutNode } from "../../dom/node.js";
|
|
2
|
-
import { containingBlock } from "../utils/node-math.js";
|
|
2
|
+
import { adjustForBoxSizing, containingBlock } from "../utils/node-math.js";
|
|
3
3
|
import { resolveLength } from "../../css/length.js";
|
|
4
4
|
import { verticalNonContent, horizontalNonContent } from "../utils/node-math.js";
|
|
5
5
|
import { finalizeOverflow } from "../utils/overflow.js";
|
|
@@ -14,6 +14,30 @@ export class FormLayoutStrategy {
|
|
|
14
14
|
constructor() {
|
|
15
15
|
this.formTags = new Set(['input', 'select', 'textarea', 'button']);
|
|
16
16
|
}
|
|
17
|
+
resolveExplicitOrAutoWidth(node, cbWidth, autoValue, extras, containerHeight) {
|
|
18
|
+
const hasExplicitWidth = node.style.width !== "auto" && node.style.width !== undefined;
|
|
19
|
+
if (!hasExplicitWidth) {
|
|
20
|
+
return autoValue;
|
|
21
|
+
}
|
|
22
|
+
const specified = resolveLength(node.style.width, cbWidth, {
|
|
23
|
+
auto: autoValue,
|
|
24
|
+
containerWidth: cbWidth,
|
|
25
|
+
containerHeight,
|
|
26
|
+
});
|
|
27
|
+
return adjustForBoxSizing(specified, node.style.boxSizing, extras);
|
|
28
|
+
}
|
|
29
|
+
resolveExplicitOrAutoHeight(node, cbHeight, autoValue, extras, containerWidth) {
|
|
30
|
+
const hasExplicitHeight = node.style.height !== "auto" && node.style.height !== undefined;
|
|
31
|
+
if (!hasExplicitHeight) {
|
|
32
|
+
return autoValue;
|
|
33
|
+
}
|
|
34
|
+
const specified = resolveLength(node.style.height, cbHeight, {
|
|
35
|
+
auto: autoValue,
|
|
36
|
+
containerWidth,
|
|
37
|
+
containerHeight: cbHeight,
|
|
38
|
+
});
|
|
39
|
+
return adjustForBoxSizing(specified, node.style.boxSizing, extras);
|
|
40
|
+
}
|
|
17
41
|
canLayout(node) {
|
|
18
42
|
if (!node.tagName)
|
|
19
43
|
return false;
|
|
@@ -21,10 +45,13 @@ export class FormLayoutStrategy {
|
|
|
21
45
|
}
|
|
22
46
|
layout(node, context) {
|
|
23
47
|
const cb = containingBlock(node, context.env.viewport);
|
|
48
|
+
const containerRefs = { containerWidth: cb.width, containerHeight: cb.height };
|
|
24
49
|
const tagName = node.tagName?.toLowerCase() ?? '';
|
|
25
50
|
const formControl = node.customData?.formControl;
|
|
26
51
|
let contentWidth;
|
|
27
52
|
let contentHeight;
|
|
53
|
+
const horizontalExtras = horizontalNonContent(node, cb.width, cb.height);
|
|
54
|
+
const verticalExtras = verticalNonContent(node, cb.height, cb.width);
|
|
28
55
|
switch (tagName) {
|
|
29
56
|
case 'input': {
|
|
30
57
|
const inputType = formControl?.inputType ?? 'text';
|
|
@@ -37,24 +64,24 @@ export class FormLayoutStrategy {
|
|
|
37
64
|
contentHeight = 0;
|
|
38
65
|
}
|
|
39
66
|
else {
|
|
40
|
-
contentWidth =
|
|
41
|
-
contentHeight =
|
|
67
|
+
contentWidth = this.resolveExplicitOrAutoWidth(node, cb.width, DEFAULT_INPUT_WIDTH, horizontalExtras, cb.height);
|
|
68
|
+
contentHeight = this.resolveExplicitOrAutoHeight(node, cb.height, DEFAULT_INPUT_HEIGHT, verticalExtras, cb.width);
|
|
42
69
|
}
|
|
43
70
|
break;
|
|
44
71
|
}
|
|
45
72
|
case 'select':
|
|
46
|
-
contentWidth =
|
|
47
|
-
contentHeight =
|
|
73
|
+
contentWidth = this.resolveExplicitOrAutoWidth(node, cb.width, DEFAULT_INPUT_WIDTH, horizontalExtras, cb.height);
|
|
74
|
+
contentHeight = this.resolveExplicitOrAutoHeight(node, cb.height, DEFAULT_SELECT_HEIGHT, verticalExtras, cb.width);
|
|
48
75
|
break;
|
|
49
76
|
case 'textarea': {
|
|
50
|
-
contentWidth =
|
|
77
|
+
contentWidth = this.resolveExplicitOrAutoWidth(node, cb.width, DEFAULT_TEXTAREA_WIDTH, horizontalExtras, cb.height);
|
|
51
78
|
const rows = formControl?.rows ?? 3;
|
|
52
|
-
contentHeight =
|
|
79
|
+
contentHeight = this.resolveExplicitOrAutoHeight(node, cb.height, rows * 24, verticalExtras, cb.width);
|
|
53
80
|
break;
|
|
54
81
|
}
|
|
55
82
|
case 'button':
|
|
56
|
-
contentWidth =
|
|
57
|
-
contentHeight =
|
|
83
|
+
contentWidth = this.resolveExplicitOrAutoWidth(node, cb.width, DEFAULT_BUTTON_MIN_WIDTH, horizontalExtras, cb.height);
|
|
84
|
+
contentHeight = this.resolveExplicitOrAutoHeight(node, cb.height, DEFAULT_BUTTON_HEIGHT, verticalExtras, cb.width);
|
|
58
85
|
break;
|
|
59
86
|
default:
|
|
60
87
|
contentWidth = DEFAULT_INPUT_WIDTH;
|
|
@@ -62,14 +89,12 @@ export class FormLayoutStrategy {
|
|
|
62
89
|
}
|
|
63
90
|
node.box.contentWidth = Math.max(0, contentWidth);
|
|
64
91
|
node.box.contentHeight = Math.max(0, contentHeight);
|
|
65
|
-
const horizontalExtras = horizontalNonContent(node, contentWidth);
|
|
66
92
|
node.box.borderBoxWidth = node.box.contentWidth + horizontalExtras;
|
|
67
|
-
const verticalExtras = verticalNonContent(node, contentWidth);
|
|
68
93
|
node.box.borderBoxHeight = node.box.contentHeight + verticalExtras;
|
|
69
94
|
node.box.x = cb.x;
|
|
70
95
|
node.box.y = cb.y;
|
|
71
|
-
const marginLeft = resolveLength(node.style.marginLeft, cb.width, { auto: "zero" });
|
|
72
|
-
const marginRight = resolveLength(node.style.marginRight, cb.width, { auto: "zero" });
|
|
96
|
+
const marginLeft = resolveLength(node.style.marginLeft, cb.width, { auto: "zero", ...containerRefs });
|
|
97
|
+
const marginRight = resolveLength(node.style.marginRight, cb.width, { auto: "zero", ...containerRefs });
|
|
73
98
|
node.box.usedMarginLeft = marginLeft;
|
|
74
99
|
node.box.usedMarginRight = marginRight;
|
|
75
100
|
node.box.marginBoxWidth = node.box.borderBoxWidth + marginLeft + marginRight;
|