@openpresentation/opf 0.26.10 → 0.28.0
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 +6 -0
- package/dist/browser.js +20 -17
- package/dist/{catalog-refs-BSfGELpt.d.ts → catalog-refs-kAefsZWT.d.ts} +2 -1
- package/dist/{catalog-schemas-DoxA2BgY.d.ts → catalog-schemas-CC1d_h8s.d.ts} +3 -2
- package/dist/{chart-data-BnNqgnC-.d.ts → chart-data-Ci9s_NDN.d.ts} +2 -1
- package/dist/{chunk-XRMV2GMB.js → chunk-2CUCYENF.js} +758 -232
- package/dist/chunk-43JWUIGF.js +8 -0
- package/dist/{chunk-F4HFDP6I.js → chunk-5Q4IYLMW.js} +31 -15
- package/dist/{chunk-GIWNHRTX.js → chunk-BQUWRXTR.js} +4 -4
- package/dist/chunk-CR72ZJ6W.js +236 -0
- package/dist/{chunk-L52N5FZZ.js → chunk-F6DCEGB3.js} +6 -6
- package/dist/chunk-GM7WFPGG.js +10 -0
- package/dist/chunk-JBARNYFR.js +23 -0
- package/dist/{chunk-EQ6S5SEZ.js → chunk-KELC4K62.js} +1 -1
- package/dist/{chunk-77KL2PMM.js → chunk-KXKN3W5Z.js} +3 -3
- package/dist/{chunk-D25BNPTW.js → chunk-LLEXM7TQ.js} +4 -4
- package/dist/{chunk-3S2XVDPN.js → chunk-MTFK7QEY.js} +6 -6
- package/dist/{chunk-TKQ2VFV5.js → chunk-N77N4AOD.js} +1 -1
- package/dist/{chunk-NVT2YDVC.js → chunk-OAIAFXMS.js} +2 -2
- package/dist/{chunk-PHP45MO7.js → chunk-P6PKYJTS.js} +1 -1
- package/dist/{chunk-H7XMO36O.js → chunk-PCU4XGKV.js} +5 -5
- package/dist/{chunk-Y4TZCE7R.js → chunk-SEZ4EPW6.js} +2 -2
- package/dist/{chunk-Y25DYRME.js → chunk-TNUTRV6E.js} +1 -1
- package/dist/{chunk-G5WJMJV3.js → chunk-UOHWG4OS.js} +1 -1
- package/dist/{chunk-A54NGT2K.js → chunk-VGGPAMP7.js} +2 -2
- package/dist/{chunk-IVPA6NG6.js → chunk-WPKCWQ6W.js} +494 -120
- package/dist/{chunk-VZBFQLCA.js → chunk-XZ23FORL.js} +6 -6
- package/dist/chunk-ZROVYWGU.js +1 -0
- package/dist/{composition-DIftf6iP.d.ts → composition-C-hd_Ci3.d.ts} +134 -14
- package/dist/composition.d.ts +3 -3
- package/dist/composition.js +2 -1
- package/dist/conversion-XJTDWQ5W.js +24 -0
- package/dist/{conversion-ChmGA8Ul.d.ts → conversion-hbZeS5kD.d.ts} +8 -7
- package/dist/convert.d.ts +6 -5
- package/dist/convert.js +9 -7
- package/dist/data.d.ts +4 -3
- package/dist/data.js +3 -2
- package/dist/{deck-report-5vwMGcQz.d.ts → deck-report-DQMsvyBI.d.ts} +5 -4
- package/dist/deck.d.ts +9 -8
- package/dist/deck.js +13 -11
- package/dist/diff.d.ts +3 -2
- package/dist/diff.js +6 -4
- package/dist/docs.d.ts +2 -1
- package/dist/docs.js +33 -19
- package/dist/examples.d.ts +3 -2
- package/dist/examples.js +92 -50
- package/dist/{explain-JSuESV-Y.d.ts → explain-iZeNOUc6.d.ts} +2 -1
- package/dist/font-policy.d.ts +2 -1
- package/dist/font-policy.js +1 -0
- package/dist/format.d.ts +2 -1
- package/dist/format.js +3 -2
- package/dist/ids.d.ts +114 -0
- package/dist/ids.js +6 -0
- package/dist/index.d.ts +40 -16
- package/dist/index.js +24 -21
- package/dist/markdown.d.ts +8 -7
- package/dist/markdown.js +10 -8
- package/dist/node-engine.d.ts +33 -10
- package/dist/node-engine.js +37 -28
- package/dist/{pagination-D_kJe4jH.d.ts → pagination-DyAKYpXu.d.ts} +4 -3
- package/dist/pagination.d.ts +4 -4
- package/dist/pagination.js +6 -4
- package/dist/patch.d.ts +89 -4
- package/dist/patch.js +5 -3
- package/dist/precompiled.d.ts +2 -0
- package/dist/precompiled.js +7 -0
- package/dist/{presentation-Bwo8Ko6D.d.ts → presentation-8jLSTFqL.d.ts} +11 -11
- package/dist/repo-readme.js +3 -1
- package/dist/schema-engine-ajv.js +37 -0
- package/dist/schema-engine-precompiled.js +3 -0
- package/dist/schema.d.ts +4 -3
- package/dist/schema.js +5 -3
- package/dist/schemas.d.ts +2 -1
- package/dist/schemas.js +2 -1
- package/dist/source.d.ts +5 -4
- package/dist/source.js +12 -10
- package/dist/spec/README.md +1 -1
- package/dist/spec/schemas/audience.schema.json +1 -0
- package/dist/spec/schemas/catalog-index.schema.json +1 -0
- package/dist/spec/schemas/catalog-manifest.schema.json +1 -0
- package/dist/spec/schemas/chart-type.schema.json +1 -0
- package/dist/spec/schemas/color-scheme.schema.json +1 -0
- package/dist/spec/schemas/finding.schema.json +1 -0
- package/dist/spec/schemas/font-scheme.schema.json +1 -0
- package/dist/spec/schemas/language.schema.json +1 -0
- package/dist/spec/schemas/layout-preview-index.schema.json +1 -0
- package/dist/spec/schemas/layout.schema.json +8 -6
- package/dist/spec/schemas/narrative.schema.json +1 -0
- package/dist/spec/schemas/opf.schema.json +9 -8
- package/dist/spec/schemas/purpose.schema.json +1 -0
- package/dist/spec/schemas/social-platform.schema.json +1 -0
- package/dist/spec/schemas/theme.schema.json +3 -1
- package/dist/spec/schemas/tone.schema.json +1 -0
- package/dist/spec-files.d.ts +2 -1
- package/dist/spec-files.js +1 -0
- package/dist/symbol-font-encodings.d.ts +2 -1
- package/dist/symbol-font-encodings.js +2 -0
- package/dist/types.d.ts +9 -9
- package/dist/{validation-types-3ARvTsB0.d.ts → validation-types-mNmfcY9A.d.ts} +4 -3
- package/dist/validator.d.ts +8 -8
- package/dist/validator.js +5 -3
- package/dist/yaml.d.ts +8 -7
- package/dist/yaml.js +9 -7
- package/package.json +30 -9
- package/dist/conversion-IVKCKMCN.js +0 -21
|
@@ -1877,11 +1877,18 @@ function tableCellDisplayValue(cell, columnFormat2) {
|
|
|
1877
1877
|
|
|
1878
1878
|
// src/chart-axis.ts
|
|
1879
1879
|
var CHART_TEXT_PX = 20;
|
|
1880
|
+
var CHART_TEXT_FLOOR_PX = 18;
|
|
1881
|
+
var CHART_FLOOR_MIN_HEIGHT = 12 * CHART_TEXT_FLOOR_PX;
|
|
1882
|
+
var CHART_FLOOR_MIN_WIDTH = 16 * CHART_TEXT_FLOOR_PX;
|
|
1883
|
+
var CHART_MIN_TICK_SPACING_PX = 48;
|
|
1884
|
+
var CHART_MAX_INTERVALS = 8;
|
|
1880
1885
|
function chartTextSize(geometry) {
|
|
1881
1886
|
const { width, height, scale: scale2 } = geometry;
|
|
1882
1887
|
const minimum = geometry.minFontSize ?? 16;
|
|
1883
1888
|
if (![width, height, scale2].every(Number.isFinite) || width <= 0 || height <= 0 || scale2 <= 0) return Math.max(CHART_TEXT_PX, minimum);
|
|
1884
|
-
|
|
1889
|
+
const roomy = Math.floor(Math.min(CHART_TEXT_PX, height / scale2 / 18, width / scale2 / 30));
|
|
1890
|
+
const roomForFloor = height / scale2 >= CHART_FLOOR_MIN_HEIGHT && width / scale2 >= CHART_FLOOR_MIN_WIDTH;
|
|
1891
|
+
return Math.max(roomy, minimum, roomForFloor ? CHART_TEXT_FLOOR_PX : 0);
|
|
1885
1892
|
}
|
|
1886
1893
|
function clean(value) {
|
|
1887
1894
|
const rounded = Number(value.toPrecision(12));
|
|
@@ -1949,6 +1956,10 @@ function normalizedScale(dataMin, dataMax, limit) {
|
|
|
1949
1956
|
function maxIntervalsFor(length, labelExtent) {
|
|
1950
1957
|
return Math.max(1, Math.min(10, Math.floor(length / Math.max(1, labelExtent))));
|
|
1951
1958
|
}
|
|
1959
|
+
function chartIntervalsFor(length, labelExtent, scale2) {
|
|
1960
|
+
const spacing = CHART_MIN_TICK_SPACING_PX * (Number.isFinite(scale2) && scale2 > 0 ? scale2 : 1);
|
|
1961
|
+
return Math.min(CHART_MAX_INTERVALS, maxIntervalsFor(length, Math.max(labelExtent, spacing)));
|
|
1962
|
+
}
|
|
1952
1963
|
var bar = (horizontal, grouping) => ({ kind: "bar", horizontal, grouping });
|
|
1953
1964
|
var line = (grouping) => ({ kind: "line", horizontal: false, grouping });
|
|
1954
1965
|
var area = (grouping) => ({ kind: "area", horizontal: false, grouping });
|
|
@@ -2024,7 +2035,7 @@ function chartValueAxis(chart, resolved, geometry) {
|
|
|
2024
2035
|
const legendBand = options.legend === "top" || options.legend === "bottom" ? lineHeight + pad : 0;
|
|
2025
2036
|
const titleBand = options.axisTitles.category ? lineHeight : 0;
|
|
2026
2037
|
const length = spec.horizontal ? width * 0.7 - 2 * pad - fontPx : height - 2 * pad - lineHeight * 1.5 - legendBand - titleBand;
|
|
2027
|
-
const fitted = niceScale(dataMin, dataMax,
|
|
2038
|
+
const fitted = niceScale(dataMin, dataMax, chartIntervalsFor(Math.max(1, length), spec.horizontal ? 4 * fontPx : lineHeight * 1.2, scale2), { percent });
|
|
2028
2039
|
return { min: fitted.min, max: fitted.max, majorUnit: fitted.step, ...percent ? { percent: true } : {} };
|
|
2029
2040
|
}
|
|
2030
2041
|
|
|
@@ -2057,11 +2068,28 @@ var u32be = (b, i) => (at2(b, i) << 24 | at2(b, i + 1) << 16 | at2(b, i + 2) <<
|
|
|
2057
2068
|
var u16le = (b, i) => at2(b, i) | at2(b, i + 1) << 8;
|
|
2058
2069
|
var u24le = (b, i) => at2(b, i) | at2(b, i + 1) << 8 | at2(b, i + 2) << 16;
|
|
2059
2070
|
var ascii = (b, i, n) => String.fromCharCode(...b.subarray(i, i + n));
|
|
2071
|
+
function exifOrientation(b, start, end) {
|
|
2072
|
+
if (end > b.length || ascii(b, start, 4) !== "Exif" || at2(b, start + 4) !== 0) return void 0;
|
|
2073
|
+
const tiff = start + 6, little = ascii(b, tiff, 2) === "II";
|
|
2074
|
+
if (!little && ascii(b, tiff, 2) !== "MM") return void 0;
|
|
2075
|
+
const u16 = (index) => little ? u16le(b, index) : u16be(b, index);
|
|
2076
|
+
const u32 = (index) => little ? (u16le(b, index) | u16le(b, index + 2) << 16) >>> 0 : u32be(b, index);
|
|
2077
|
+
const directory = tiff + u32(tiff + 4);
|
|
2078
|
+
if (directory + 2 > end) return void 0;
|
|
2079
|
+
for (let entry = 0, count = u16(directory); entry < count && directory + 2 + entry * 12 + 12 <= end; entry++) {
|
|
2080
|
+
const at12 = directory + 2 + entry * 12;
|
|
2081
|
+
if (u16(at12) === 274) {
|
|
2082
|
+
const value = u16(at12 + 8);
|
|
2083
|
+
return value >= 1 && value <= 8 ? value : void 0;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
return void 0;
|
|
2087
|
+
}
|
|
2060
2088
|
function rasterDimensions(b) {
|
|
2061
2089
|
if (b.length >= 24 && u32be(b, 0) === 2303741511 && ascii(b, 12, 4) === "IHDR") return { width: u32be(b, 16), height: u32be(b, 20) };
|
|
2062
2090
|
if (b.length >= 10 && (ascii(b, 0, 6) === "GIF87a" || ascii(b, 0, 6) === "GIF89a")) return { width: u16le(b, 6), height: u16le(b, 8) };
|
|
2063
2091
|
if (b.length >= 4 && b[0] === 255 && b[1] === 216) {
|
|
2064
|
-
let i = 2;
|
|
2092
|
+
let i = 2, orientation = 1;
|
|
2065
2093
|
while (i + 9 < b.length) {
|
|
2066
2094
|
if (at2(b, i) !== 255) {
|
|
2067
2095
|
i++;
|
|
@@ -2076,7 +2104,11 @@ function rasterDimensions(b) {
|
|
|
2076
2104
|
i += 2;
|
|
2077
2105
|
continue;
|
|
2078
2106
|
}
|
|
2079
|
-
if (marker
|
|
2107
|
+
if (marker === 225) orientation = exifOrientation(b, i + 4, i + 2 + u16be(b, i + 2)) ?? orientation;
|
|
2108
|
+
if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) {
|
|
2109
|
+
const height = u16be(b, i + 5), width = u16be(b, i + 7);
|
|
2110
|
+
return orientation >= 5 ? { width: height, height: width } : { width, height };
|
|
2111
|
+
}
|
|
2080
2112
|
i += 2 + u16be(b, i + 2);
|
|
2081
2113
|
}
|
|
2082
2114
|
return void 0;
|
|
@@ -2156,7 +2188,7 @@ var VALUES = {
|
|
|
2156
2188
|
contentDirection: ["horizontal", "vertical"],
|
|
2157
2189
|
chartPrimary: ["none", "top", "bottom", "left", "right"],
|
|
2158
2190
|
imageFit: ["cover", "contain", "stretch"],
|
|
2159
|
-
listBullet: ["character", "image"],
|
|
2191
|
+
listBullet: ["character", "image", "none"],
|
|
2160
2192
|
mirror: "boolean"
|
|
2161
2193
|
};
|
|
2162
2194
|
var themeKeys = new Set(THEME_DESIGN_KEYS);
|
|
@@ -2384,6 +2416,8 @@ function parse(layout) {
|
|
|
2384
2416
|
}
|
|
2385
2417
|
};
|
|
2386
2418
|
order(children);
|
|
2419
|
+
const stackAnchor = anchorOf(value.anchor);
|
|
2420
|
+
const stack = direction === "column" && children.length > 0 && children.every((node) => node.size === "auto") && stackAnchor !== void 0 && stackAnchor !== "top" ? stackAnchor : void 0;
|
|
2387
2421
|
const overflowRegion = typeof value.overflowRegion === "string" ? value.overflowRegion : regions.find((entry) => entry.role === "primary" && entry.flow !== "none")?.name;
|
|
2388
2422
|
return {
|
|
2389
2423
|
issues,
|
|
@@ -2395,7 +2429,8 @@ function parse(layout) {
|
|
|
2395
2429
|
regions,
|
|
2396
2430
|
...overflowRegion !== void 0 ? { overflowRegion } : {},
|
|
2397
2431
|
title: names.has("title"),
|
|
2398
|
-
subtitle: names.has("subtitle")
|
|
2432
|
+
subtitle: names.has("subtitle"),
|
|
2433
|
+
...stack ? { stack } : {}
|
|
2399
2434
|
}
|
|
2400
2435
|
};
|
|
2401
2436
|
}
|
|
@@ -2744,19 +2779,32 @@ function listColumnBreaks(heights, levels, count) {
|
|
|
2744
2779
|
return solve(0, count).breaks;
|
|
2745
2780
|
}
|
|
2746
2781
|
function allocateRows(rows3, total, gap) {
|
|
2747
|
-
const auto = rows3.map((row) => row.size === "auto" ? Math.max(0, Math.min(row.need, row.kind === "
|
|
2782
|
+
const auto = rows3.map((row) => row.size === "auto" ? Math.max(0, Math.min(row.need, row.kind === "heading" ? total / 2 : total)) : 0);
|
|
2748
2783
|
const visible = rows3.filter((row, index) => row.size !== "auto" || auto[index] > 0).length;
|
|
2749
2784
|
const headings2 = rows3.reduce((sum, row, index) => sum + (row.kind === "heading" ? auto[index] : 0), 0);
|
|
2750
2785
|
const space = Math.max(0, total - headings2 - Math.max(0, visible - 1) * gap);
|
|
2751
2786
|
const numeric = rows3.reduce((sum, row) => sum + (row.size === "auto" ? 0 : row.size), 0);
|
|
2752
2787
|
const numericNeed = rows3.reduce((sum, row) => sum + (row.size === "auto" ? 0 : Math.max(0, row.need)), 0);
|
|
2753
2788
|
const reserve = numeric > 0 ? Math.min(numericNeed, space / 2) : 0;
|
|
2754
|
-
const
|
|
2755
|
-
const
|
|
2756
|
-
const heights = rows3.map((row, index) => row.size === "auto" ? row.kind === "heading" ? auto[index] :
|
|
2789
|
+
const bodyRows = rows3.flatMap((row, index) => row.size === "auto" && row.kind !== "heading" ? [index] : []);
|
|
2790
|
+
const fitted = shareHeights(bodyRows.map((index) => auto[index]), bodyRows.map((index) => rows3[index].floor ?? 0), Math.max(0, space - reserve));
|
|
2791
|
+
const heights = rows3.map((row, index) => row.size === "auto" ? row.kind === "heading" ? auto[index] : fitted[bodyRows.indexOf(index)] : 0);
|
|
2757
2792
|
const rest = Math.max(0, space - heights.reduce((sum, height, index) => sum + (rows3[index].kind === "heading" ? 0 : height), 0));
|
|
2758
2793
|
return rows3.map((row, index) => row.size === "auto" ? heights[index] : numeric > 0 ? rest * row.size / numeric : 0);
|
|
2759
2794
|
}
|
|
2795
|
+
function shareHeights(needs, floors, total) {
|
|
2796
|
+
const space = Math.max(0, total);
|
|
2797
|
+
const need = needs.map((value) => Number.isFinite(value) ? Math.max(0, value) : 0);
|
|
2798
|
+
const floor = need.map((value, index) => Math.min(value, Math.max(0, Number.isFinite(floors[index]) ? floors[index] : 0)));
|
|
2799
|
+
const sum = (values) => values.reduce((a, b) => a + b, 0);
|
|
2800
|
+
const needed = sum(need), lowest = sum(floor);
|
|
2801
|
+
if (needed <= space) return need;
|
|
2802
|
+
if (lowest < space) {
|
|
2803
|
+
const give = (needed - space) / (needed - lowest);
|
|
2804
|
+
return need.map((value, index) => value - give * (value - floor[index]));
|
|
2805
|
+
}
|
|
2806
|
+
return lowest > 0 ? floor.map((value) => value * space / lowest) : need.map(() => 0);
|
|
2807
|
+
}
|
|
2760
2808
|
|
|
2761
2809
|
// src/direction.ts
|
|
2762
2810
|
var strongRtl = /[\u200F\u061C]|(?=\p{L})[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Adlam}\p{Script=Hanifi_Rohingya}\p{Script=Mandaic}\p{Script=Samaritan}\p{Script=Mende_Kikakui}\p{Script=Imperial_Aramaic}\p{Script=Phoenician}\p{Script=Kharoshthi}\p{Script=Old_South_Arabian}\p{Script=Old_North_Arabian}\p{Script=Avestan}\p{Script=Inscriptional_Parthian}\p{Script=Inscriptional_Pahlavi}\p{Script=Psalter_Pahlavi}\p{Script=Old_Turkic}\p{Script=Old_Hungarian}\p{Script=Nabataean}\p{Script=Palmyrene}\p{Script=Hatran}\p{Script=Manichaean}\p{Script=Sogdian}\p{Script=Old_Sogdian}\p{Script=Elymaic}\p{Script=Chorasmian}\p{Script=Yezidi}\p{Script=Cypriot}\p{Script=Lydian}\p{Script=Meroitic_Cursive}\p{Script=Meroitic_Hieroglyphs}\u{10F70}-\u{10FAF}\u{10D40}-\u{10D8F}]/u;
|
|
@@ -3343,6 +3391,93 @@ function resolveSlideDirection(presentation, slideIndex) {
|
|
|
3343
3391
|
}
|
|
3344
3392
|
}
|
|
3345
3393
|
|
|
3394
|
+
// src/quote-marks.ts
|
|
3395
|
+
var marks = (open, close) => ({ open, close });
|
|
3396
|
+
var ENGLISH = marks("\u201C", "\u201D");
|
|
3397
|
+
var GUILLEMETS = marks("\xAB", "\xBB");
|
|
3398
|
+
var LOW_HIGH = marks("\u201E", "\u201C");
|
|
3399
|
+
var LOW_RIGHT = marks("\u201E", "\u201D");
|
|
3400
|
+
var RIGHT_ONLY = marks("\u201D", "\u201D");
|
|
3401
|
+
var CORNER = marks("\u300C", "\u300D");
|
|
3402
|
+
var REVERSED = marks("\xBB", "\xAB");
|
|
3403
|
+
var QUOTE_MARKS = {
|
|
3404
|
+
en: ENGLISH,
|
|
3405
|
+
es: GUILLEMETS,
|
|
3406
|
+
fr: GUILLEMETS,
|
|
3407
|
+
de: LOW_HIGH,
|
|
3408
|
+
it: GUILLEMETS,
|
|
3409
|
+
pt: ENGLISH,
|
|
3410
|
+
nl: ENGLISH,
|
|
3411
|
+
ca: GUILLEMETS,
|
|
3412
|
+
gl: GUILLEMETS,
|
|
3413
|
+
eu: GUILLEMETS,
|
|
3414
|
+
sv: RIGHT_ONLY,
|
|
3415
|
+
fi: RIGHT_ONLY,
|
|
3416
|
+
da: REVERSED,
|
|
3417
|
+
nb: GUILLEMETS,
|
|
3418
|
+
nn: GUILLEMETS,
|
|
3419
|
+
no: GUILLEMETS,
|
|
3420
|
+
is: LOW_HIGH,
|
|
3421
|
+
pl: LOW_RIGHT,
|
|
3422
|
+
hu: LOW_RIGHT,
|
|
3423
|
+
ro: LOW_RIGHT,
|
|
3424
|
+
cs: LOW_HIGH,
|
|
3425
|
+
sk: LOW_HIGH,
|
|
3426
|
+
sl: LOW_HIGH,
|
|
3427
|
+
hr: LOW_HIGH,
|
|
3428
|
+
sr: LOW_HIGH,
|
|
3429
|
+
bg: LOW_HIGH,
|
|
3430
|
+
lt: LOW_HIGH,
|
|
3431
|
+
lv: LOW_HIGH,
|
|
3432
|
+
et: LOW_HIGH,
|
|
3433
|
+
ru: GUILLEMETS,
|
|
3434
|
+
uk: GUILLEMETS,
|
|
3435
|
+
el: GUILLEMETS,
|
|
3436
|
+
tr: ENGLISH,
|
|
3437
|
+
ga: ENGLISH,
|
|
3438
|
+
cy: ENGLISH,
|
|
3439
|
+
ja: CORNER,
|
|
3440
|
+
zh: ENGLISH,
|
|
3441
|
+
"zh-tw": CORNER,
|
|
3442
|
+
"zh-hk": CORNER,
|
|
3443
|
+
"zh-hant": CORNER,
|
|
3444
|
+
ko: ENGLISH,
|
|
3445
|
+
ar: GUILLEMETS,
|
|
3446
|
+
fa: GUILLEMETS,
|
|
3447
|
+
he: ENGLISH,
|
|
3448
|
+
ur: ENGLISH,
|
|
3449
|
+
hi: ENGLISH,
|
|
3450
|
+
th: ENGLISH,
|
|
3451
|
+
vi: ENGLISH,
|
|
3452
|
+
id: ENGLISH,
|
|
3453
|
+
ms: ENGLISH,
|
|
3454
|
+
"de-ch": GUILLEMETS,
|
|
3455
|
+
"fr-ch": GUILLEMETS,
|
|
3456
|
+
"pt-pt": GUILLEMETS
|
|
3457
|
+
};
|
|
3458
|
+
var ASCII_QUOTE_MARKS = marks('"', '"');
|
|
3459
|
+
function quoteMarksFor(tag) {
|
|
3460
|
+
if (tag === void 0 || tag === "") return ENGLISH;
|
|
3461
|
+
const lower = tag.toLowerCase().replaceAll("_", "-"), primary = lower.split("-")[0];
|
|
3462
|
+
return QUOTE_MARKS[lower] ?? QUOTE_MARKS[primary] ?? ASCII_QUOTE_MARKS;
|
|
3463
|
+
}
|
|
3464
|
+
function quoteLanguage(presentation, slideIndex) {
|
|
3465
|
+
if (presentation === null || typeof presentation !== "object" || presentation.language === void 0) return void 0;
|
|
3466
|
+
try {
|
|
3467
|
+
const resolved = resolveScriptFonts(presentation, Number.isInteger(slideIndex) ? { slideIndex } : {});
|
|
3468
|
+
return resolved.languageSource === "document" ? resolved.bcp47 : void 0;
|
|
3469
|
+
} catch {
|
|
3470
|
+
return void 0;
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
var PAIRS = new Set(Object.values(QUOTE_MARKS).concat(ASCII_QUOTE_MARKS).map((entry) => entry.open + entry.close));
|
|
3474
|
+
function isWrappedInQuoteMarks(text2) {
|
|
3475
|
+
return text2.length >= 2 && PAIRS.has(text2[0] + text2.at(-1));
|
|
3476
|
+
}
|
|
3477
|
+
function unwrapQuoteMarks(text2) {
|
|
3478
|
+
return isWrappedInQuoteMarks(text2) ? text2.slice(1, -1) : text2;
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3346
3481
|
// src/numbering.ts
|
|
3347
3482
|
var NUMBERING_STYLES = ["arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"];
|
|
3348
3483
|
var NUMBERING_SUFFIXES = ["period", "paren", "paren-both"];
|
|
@@ -3458,6 +3593,54 @@ function numberingFindings(payload) {
|
|
|
3458
3593
|
return { errors, warnings };
|
|
3459
3594
|
}
|
|
3460
3595
|
|
|
3596
|
+
// src/legible-color.ts
|
|
3597
|
+
var channels = (hex) => [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
|
|
3598
|
+
var toHex = (values) => `#${values.map((value) => Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
|
|
3599
|
+
var linear = (value) => {
|
|
3600
|
+
const n = value / 255;
|
|
3601
|
+
return n <= 0.04045 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
|
|
3602
|
+
};
|
|
3603
|
+
var luminance = (hex) => {
|
|
3604
|
+
const [r, g, b] = channels(hex);
|
|
3605
|
+
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
|
|
3606
|
+
};
|
|
3607
|
+
var contrast = (a, b) => {
|
|
3608
|
+
const x = luminance(a), y = luminance(b);
|
|
3609
|
+
return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
|
|
3610
|
+
};
|
|
3611
|
+
var normalize = (value) => {
|
|
3612
|
+
if (typeof value !== "string") return void 0;
|
|
3613
|
+
const text2 = value.trim();
|
|
3614
|
+
if (/^#[0-9a-f]{3}$/i.test(text2)) return `#${[...text2.slice(1)].map((c) => c + c).join("")}`.toUpperCase();
|
|
3615
|
+
return /^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(text2) ? text2.slice(0, 7).toUpperCase() : void 0;
|
|
3616
|
+
};
|
|
3617
|
+
function toHsl(hex) {
|
|
3618
|
+
const [r, g, b] = channels(hex).map((value) => value / 255);
|
|
3619
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min;
|
|
3620
|
+
if (d === 0) return [0, 0, l];
|
|
3621
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
3622
|
+
const h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
3623
|
+
return [h * 60, s, l];
|
|
3624
|
+
}
|
|
3625
|
+
function fromHsl(h, s, l) {
|
|
3626
|
+
const hue = (h % 360 + 360) % 360, c = (1 - Math.abs(2 * l - 1)) * s, x = c * (1 - Math.abs(hue / 60 % 2 - 1)), m = l - c / 2;
|
|
3627
|
+
const [r, g, b] = hue < 60 ? [c, x, 0] : hue < 120 ? [x, c, 0] : hue < 180 ? [0, c, x] : hue < 240 ? [0, x, c] : hue < 300 ? [x, 0, c] : [c, 0, x];
|
|
3628
|
+
return toHex([(r + m) * 255, (g + m) * 255, (b + m) * 255]);
|
|
3629
|
+
}
|
|
3630
|
+
function legible(foreground, background, minimum) {
|
|
3631
|
+
if (contrast(foreground, background) >= minimum) return foreground;
|
|
3632
|
+
const [h, s, l] = toHsl(foreground), preferred = luminance(background) < 0.5 ? 1 : -1;
|
|
3633
|
+
for (const direction of [preferred, -preferred]) {
|
|
3634
|
+
for (let step = 1; step <= 100; step++) {
|
|
3635
|
+
const lightness = l + direction * step / 100;
|
|
3636
|
+
if (lightness < 0 || lightness > 1) break;
|
|
3637
|
+
const candidate = fromHsl(h, s, lightness);
|
|
3638
|
+
if (contrast(candidate, background) >= minimum) return candidate;
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
return contrast("#FFFFFF", background) >= contrast("#000000", background) ? "#FFFFFF" : "#000000";
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3461
3644
|
// src/color.ts
|
|
3462
3645
|
var schemeColorSlots = /* @__PURE__ */ new Set([
|
|
3463
3646
|
"accent1",
|
|
@@ -3539,7 +3722,7 @@ function resolveColorRef(reference, options) {
|
|
|
3539
3722
|
var DARK_BACKGROUND_LUMINANCE = 0.179;
|
|
3540
3723
|
function isDarkColor(color) {
|
|
3541
3724
|
const hex = normalizeHexColor(color);
|
|
3542
|
-
const value = hex ?
|
|
3725
|
+
const value = hex ? luminance2(hex) : void 0;
|
|
3543
3726
|
return value !== void 0 && value < DARK_BACKGROUND_LUMINANCE;
|
|
3544
3727
|
}
|
|
3545
3728
|
function defaultSlideBackground(colorScheme) {
|
|
@@ -3697,7 +3880,7 @@ function readableSchemeColor(fill, roles) {
|
|
|
3697
3880
|
const ink = { slot: "tx1", hex: normalizeHexColor(roles.text) ?? roles.text };
|
|
3698
3881
|
return (colorContrast(light.hex, fill) ?? 0) >= (colorContrast(ink.hex, fill) ?? 0) ? light : ink;
|
|
3699
3882
|
}
|
|
3700
|
-
function
|
|
3883
|
+
function luminance2(value) {
|
|
3701
3884
|
if (typeof value !== "string") return void 0;
|
|
3702
3885
|
let hex = value.trim();
|
|
3703
3886
|
if (/^#[0-9a-f]{3}$/i.test(hex)) hex = `#${[...hex.slice(1)].map((c) => c + c).join("")}`;
|
|
@@ -3710,11 +3893,11 @@ function luminance(value) {
|
|
|
3710
3893
|
}, 0);
|
|
3711
3894
|
}
|
|
3712
3895
|
function colorContrast(foreground, background) {
|
|
3713
|
-
const a =
|
|
3896
|
+
const a = luminance2(foreground), b = luminance2(background);
|
|
3714
3897
|
return a === void 0 || b === void 0 ? void 0 : (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);
|
|
3715
3898
|
}
|
|
3716
3899
|
function textColorForFill(fill, preferred) {
|
|
3717
|
-
const background =
|
|
3900
|
+
const background = luminance2(fill), contrast2 = colorContrast(preferred, fill);
|
|
3718
3901
|
if (background === void 0 || contrast2 === void 0 || contrast2 >= 4.5) return preferred;
|
|
3719
3902
|
return (background + 0.05) / 0.05 >= 1.05 / (background + 0.05) ? "#000000" : "#FFFFFF";
|
|
3720
3903
|
}
|
|
@@ -3738,7 +3921,7 @@ var CHART_SERIES_MIN_LIGHTNESS_STEP = 11;
|
|
|
3738
3921
|
var CHART_SERIES_MIN_DIFFERENCE = 12;
|
|
3739
3922
|
var D65 = [0.95047, 1, 1.08883];
|
|
3740
3923
|
function opaqueChannels(value) {
|
|
3741
|
-
if (
|
|
3924
|
+
if (luminance2(value) === void 0) return void 0;
|
|
3742
3925
|
let hex = value.trim();
|
|
3743
3926
|
if (hex.length === 4) hex = `#${[...hex.slice(1)].map((c) => c + c).join("")}`;
|
|
3744
3927
|
return [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
|
|
@@ -3787,8 +3970,13 @@ function labDifference(a, b) {
|
|
|
3787
3970
|
var CHART_SERIES_TIER_SIZE = 6;
|
|
3788
3971
|
var tierOf = (index) => Math.floor(index / CHART_SERIES_TIER_SIZE);
|
|
3789
3972
|
var CHART_SERIES_SHORTFALL_WEIGHT = 8;
|
|
3790
|
-
|
|
3973
|
+
var CHART_LEAD_MIN_CONTRAST = 4.5;
|
|
3974
|
+
function chartPaletteForFill(fill, palette, options = {}) {
|
|
3791
3975
|
const opaqueFill = colorContrast(fill, fill) !== void 0;
|
|
3976
|
+
if (options.legibleLead && opaqueFill && isDarkColor(fill) && palette.length > 0) {
|
|
3977
|
+
const lead = normalizeHexColor(palette[0]);
|
|
3978
|
+
if (lead) palette = [legible(lead, normalizeHexColor(fill), CHART_LEAD_MIN_CONTRAST), ...palette.slice(1)];
|
|
3979
|
+
}
|
|
3792
3980
|
const preferredLab = palette.map((color) => {
|
|
3793
3981
|
const channels2 = opaqueChannels(color);
|
|
3794
3982
|
return channels2 ? labOf(channels2) : void 0;
|
|
@@ -3846,6 +4034,9 @@ function chartSeriesPalette(colorScheme = {}, colors, context = {}) {
|
|
|
3846
4034
|
});
|
|
3847
4035
|
return palette;
|
|
3848
4036
|
}
|
|
4037
|
+
function chartLeadFromScheme(colors, colorScheme = {}, context = {}) {
|
|
4038
|
+
return resolveChartColors(colors, colorScheme, context)[0] === void 0;
|
|
4039
|
+
}
|
|
3849
4040
|
function resolveChartColors(colors, colorScheme = {}, context = {}) {
|
|
3850
4041
|
if (!Array.isArray(colors)) return [];
|
|
3851
4042
|
return colors.map((entry) => {
|
|
@@ -3882,7 +4073,7 @@ function surfaceAltColor(surface, text2) {
|
|
|
3882
4073
|
if (!readable(band)) break;
|
|
3883
4074
|
if (step(band)) return band;
|
|
3884
4075
|
}
|
|
3885
|
-
const away = (
|
|
4076
|
+
const away = (luminance2(ink) ?? 0) > (luminance2(fill) ?? 0) ? [0, 0, 0] : [255, 255, 255];
|
|
3886
4077
|
for (let amount = SURFACE_ALT_MIX; amount <= 1 + 1e-9; amount += 0.02) {
|
|
3887
4078
|
const band = mixChannels(from, away, Math.min(1, amount));
|
|
3888
4079
|
if (step(band)) return band;
|
|
@@ -3890,54 +4081,6 @@ function surfaceAltColor(surface, text2) {
|
|
|
3890
4081
|
return mixChannels(from, toText, SURFACE_ALT_MIX);
|
|
3891
4082
|
}
|
|
3892
4083
|
|
|
3893
|
-
// src/legible-color.ts
|
|
3894
|
-
var channels = (hex) => [1, 3, 5].map((offset) => Number.parseInt(hex.slice(offset, offset + 2), 16));
|
|
3895
|
-
var toHex = (values) => `#${values.map((value) => Math.max(0, Math.min(255, Math.round(value))).toString(16).padStart(2, "0")).join("").toUpperCase()}`;
|
|
3896
|
-
var linear = (value) => {
|
|
3897
|
-
const n = value / 255;
|
|
3898
|
-
return n <= 0.04045 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;
|
|
3899
|
-
};
|
|
3900
|
-
var luminance2 = (hex) => {
|
|
3901
|
-
const [r, g, b] = channels(hex);
|
|
3902
|
-
return 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b);
|
|
3903
|
-
};
|
|
3904
|
-
var contrast = (a, b) => {
|
|
3905
|
-
const x = luminance2(a), y = luminance2(b);
|
|
3906
|
-
return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);
|
|
3907
|
-
};
|
|
3908
|
-
var normalize = (value) => {
|
|
3909
|
-
if (typeof value !== "string") return void 0;
|
|
3910
|
-
const text2 = value.trim();
|
|
3911
|
-
if (/^#[0-9a-f]{3}$/i.test(text2)) return `#${[...text2.slice(1)].map((c) => c + c).join("")}`.toUpperCase();
|
|
3912
|
-
return /^#[0-9a-f]{6}([0-9a-f]{2})?$/i.test(text2) ? text2.slice(0, 7).toUpperCase() : void 0;
|
|
3913
|
-
};
|
|
3914
|
-
function toHsl(hex) {
|
|
3915
|
-
const [r, g, b] = channels(hex).map((value) => value / 255);
|
|
3916
|
-
const max = Math.max(r, g, b), min = Math.min(r, g, b), l = (max + min) / 2, d = max - min;
|
|
3917
|
-
if (d === 0) return [0, 0, l];
|
|
3918
|
-
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
3919
|
-
const h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
3920
|
-
return [h * 60, s, l];
|
|
3921
|
-
}
|
|
3922
|
-
function fromHsl(h, s, l) {
|
|
3923
|
-
const hue = (h % 360 + 360) % 360, c = (1 - Math.abs(2 * l - 1)) * s, x = c * (1 - Math.abs(hue / 60 % 2 - 1)), m = l - c / 2;
|
|
3924
|
-
const [r, g, b] = hue < 60 ? [c, x, 0] : hue < 120 ? [x, c, 0] : hue < 180 ? [0, c, x] : hue < 240 ? [0, x, c] : hue < 300 ? [x, 0, c] : [c, 0, x];
|
|
3925
|
-
return toHex([(r + m) * 255, (g + m) * 255, (b + m) * 255]);
|
|
3926
|
-
}
|
|
3927
|
-
function legible(foreground, background, minimum) {
|
|
3928
|
-
if (contrast(foreground, background) >= minimum) return foreground;
|
|
3929
|
-
const [h, s, l] = toHsl(foreground), preferred = luminance2(background) < 0.5 ? 1 : -1;
|
|
3930
|
-
for (const direction of [preferred, -preferred]) {
|
|
3931
|
-
for (let step = 1; step <= 100; step++) {
|
|
3932
|
-
const lightness = l + direction * step / 100;
|
|
3933
|
-
if (lightness < 0 || lightness > 1) break;
|
|
3934
|
-
const candidate = fromHsl(h, s, lightness);
|
|
3935
|
-
if (contrast(candidate, background) >= minimum) return candidate;
|
|
3936
|
-
}
|
|
3937
|
-
}
|
|
3938
|
-
return contrast("#FFFFFF", background) >= contrast("#000000", background) ? "#FFFFFF" : "#000000";
|
|
3939
|
-
}
|
|
3940
|
-
|
|
3941
4084
|
// src/code-syntax.ts
|
|
3942
4085
|
var CODE_HIGHLIGHT_MAX_LENGTH = 2e5;
|
|
3943
4086
|
var CODE_SYNTAX_MIN_CONTRAST = 4.5;
|
|
@@ -4637,6 +4780,12 @@ function metricEffectiveSentiment(trend, sentiment) {
|
|
|
4637
4780
|
}
|
|
4638
4781
|
var METRIC_TREND_SHAPES = Object.freeze({ up: "upArrow", down: "downArrow", flat: "rightArrow" });
|
|
4639
4782
|
var METRIC_TREND_MIN_CONTRAST = 4.5;
|
|
4783
|
+
var METRIC_VALUE_MIN_CONTRAST = 4.5;
|
|
4784
|
+
function metricValueColor(color, background) {
|
|
4785
|
+
const foreground = normalize(color), surface = normalize(background);
|
|
4786
|
+
if (!foreground || !surface || !isDarkColor(surface)) return color;
|
|
4787
|
+
return legible(foreground, surface, METRIC_VALUE_MIN_CONTRAST);
|
|
4788
|
+
}
|
|
4640
4789
|
var SEMANTIC = {
|
|
4641
4790
|
positive: { light: "#15803D", dark: "#4ADE80" },
|
|
4642
4791
|
negative: { light: "#B91C1C", dark: "#F87171" }
|
|
@@ -4644,9 +4793,9 @@ var SEMANTIC = {
|
|
|
4644
4793
|
function metricTrendColor(trend, options) {
|
|
4645
4794
|
const background = normalize(options.background) ?? "#FFFFFF";
|
|
4646
4795
|
const sentiment = metricEffectiveSentiment(trend, options.sentiment);
|
|
4647
|
-
if (sentiment === "neutral") return legible(normalize(options.neutral) ?? (
|
|
4796
|
+
if (sentiment === "neutral") return legible(normalize(options.neutral) ?? (luminance(background) < 0.5 ? "#CBD5E1" : "#475569"), background, METRIC_TREND_MIN_CONTRAST);
|
|
4648
4797
|
const pair = SEMANTIC[sentiment];
|
|
4649
|
-
return legible(
|
|
4798
|
+
return legible(luminance(background) < 0.5 ? pair.dark : pair.light, background, METRIC_TREND_MIN_CONTRAST);
|
|
4650
4799
|
}
|
|
4651
4800
|
function metricTrendPoints(shape, box) {
|
|
4652
4801
|
const { x: l, y: t, width: w, height: h } = box, r = l + w, b = t + h, hc = l + w / 2, vc = t + h / 2, ss = Math.min(w, h);
|
|
@@ -5315,7 +5464,7 @@ function fitImage(frame, fit, aspect, focus = { x: 0.5, y: 0.5 }) {
|
|
|
5315
5464
|
right: round2((image.x + width - frame.x - frame.width) / width),
|
|
5316
5465
|
bottom: round2((image.y + height - frame.y - frame.height) / height)
|
|
5317
5466
|
};
|
|
5318
|
-
for (const key of ["left", "top", "right", "bottom"]) if (
|
|
5467
|
+
for (const key of ["left", "top", "right", "bottom"]) if (Math.abs(crop[key]) < 1e-9) crop[key] = 0;
|
|
5319
5468
|
return { image: roundBox(image), crop };
|
|
5320
5469
|
}
|
|
5321
5470
|
function imageBackground(value) {
|
|
@@ -5350,17 +5499,29 @@ function composeOverlay(value, frame, shape, path, mirrorSide, diagnostics) {
|
|
|
5350
5499
|
const box = !edge ? frame : edge === "top" ? { ...frame, height: round2(frame.height * part) } : edge === "bottom" ? { ...frame, y: round2(frame.y + frame.height * (1 - part)), height: round2(frame.height * part) } : edge === "left" ? { ...frame, width: round2(frame.width * part) } : { ...frame, x: round2(frame.x + frame.width * (1 - part)), width: round2(frame.width * part) };
|
|
5351
5500
|
return { path, color: overlay.color, opacity, ...edge ? { edge } : {}, box, shape: edge ? imageShape("rectangle", box) : shape };
|
|
5352
5501
|
}
|
|
5502
|
+
function anchoredOffset(spare, anchor) {
|
|
5503
|
+
return Math.max(0, anchor === "middle" ? spare / 2 : anchor === "bottom" ? spare : 0);
|
|
5504
|
+
}
|
|
5505
|
+
function containedBox(cell, aspect, anchor) {
|
|
5506
|
+
const width = Math.min(cell.width, cell.height * aspect), height = width / aspect;
|
|
5507
|
+
return { x: cell.x + (cell.width - width) / 2, y: cell.y + anchoredOffset(cell.height - height, anchor), width, height };
|
|
5508
|
+
}
|
|
5353
5509
|
function composeImage(host, hostPath, region, frameArea, context) {
|
|
5354
5510
|
const kindName = Object.hasOwn(IMAGE_SHAPES, host.shape) ? host.shape : "rectangle";
|
|
5355
5511
|
const { scale: scale2 } = context;
|
|
5512
|
+
const fit = IMAGE_FITS.includes(host.fit) ? host.fit : context.fit ?? "cover";
|
|
5513
|
+
const pictureAspect = intrinsicImageAspect(host.image, context.assets);
|
|
5356
5514
|
let box = { ...frameArea };
|
|
5357
5515
|
const aspect = kindName === "circle" ? 1 : finite(host.aspectRatio, Number.MIN_VALUE, 10);
|
|
5358
5516
|
if (aspect) {
|
|
5359
5517
|
const frameWidth = Math.min(box.width, box.height * aspect), frameHeight = frameWidth / aspect;
|
|
5360
5518
|
box = { x: box.x + (box.width - frameWidth) / 2, y: box.y + (box.height - frameHeight) / 2, width: frameWidth, height: frameHeight };
|
|
5519
|
+
} else if (context.anchor && fit === "contain" && pictureAspect) {
|
|
5520
|
+
const frameWidth = Math.min(box.width, box.height * pictureAspect);
|
|
5521
|
+
box = { x: box.x + (box.width - frameWidth) / 2, y: box.y, width: frameWidth, height: frameWidth / pictureAspect };
|
|
5361
5522
|
}
|
|
5523
|
+
if (context.anchor && fit === "contain" && !aspect && box.height < frameArea.height) box.y = frameArea.y + anchoredOffset(frameArea.height - box.height, context.anchor);
|
|
5362
5524
|
box = roundBox(box);
|
|
5363
|
-
const fit = IMAGE_FITS.includes(host.fit) ? host.fit : context.fit ?? "cover";
|
|
5364
5525
|
const focus = imageFocus(host.focus);
|
|
5365
5526
|
const shape = imageShape(kindName, box, finite(host.cornerRadius, 0, 0.5));
|
|
5366
5527
|
const result = { region: roundBox(region), box, fit, focus, shape };
|
|
@@ -5373,7 +5534,6 @@ function composeImage(host, hostPath, region, frameArea, context) {
|
|
|
5373
5534
|
const overlay = composeOverlay(host.overlay, box, shape, `${hostPath}.overlay`, context.mirrorSide, context.diagnostics);
|
|
5374
5535
|
if (overlay) result.overlay = overlay;
|
|
5375
5536
|
if (context.placement) result.placement = context.placement;
|
|
5376
|
-
const pictureAspect = intrinsicImageAspect(host.image, context.assets);
|
|
5377
5537
|
if (pictureAspect) result.picture = fitImage(box, fit, pictureAspect, focus);
|
|
5378
5538
|
return result;
|
|
5379
5539
|
}
|
|
@@ -5597,7 +5757,72 @@ function layoutFurniture(input, options = {}) {
|
|
|
5597
5757
|
return { algorithm: "furniture-flow-v2", configured, textMeasurement: options.textMeasurement ? "provided" : "estimated", textOutlines: outlines ? "provided" : "unavailable", parts, headerBottom, footerTop, diagnostics, overflow: diagnostics.length > 0 };
|
|
5598
5758
|
}
|
|
5599
5759
|
var textSegments = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
5760
|
+
var PROSE_NOMINAL_SIZE = 28;
|
|
5761
|
+
var LIST_NOMINAL_SIZE = 32;
|
|
5762
|
+
var LEAD_NOMINAL_SIZE = 32;
|
|
5763
|
+
var TABLE_NOMINAL_SIZE = 25;
|
|
5764
|
+
var QUOTE_NOMINAL_SIZE = 40;
|
|
5765
|
+
var CODE_NOMINAL_SIZE = 22;
|
|
5766
|
+
var LEGACY_CODE_NOMINAL_SIZE = 18;
|
|
5767
|
+
var QUOTE_SOURCE_SEPARATOR = " \u2013 ";
|
|
5768
|
+
var PROSE_MEASURE_CHARS = 70;
|
|
5769
|
+
var AVERAGE_CHARACTER_EM = 0.5;
|
|
5600
5770
|
var WRAP_TOLERANCE = 0.01;
|
|
5771
|
+
var SENTENCE_END = /[.!?\u2026\u3002\uff01\uff1f]["'\u201d\u2019)\]\u00bb]*$/u;
|
|
5772
|
+
var CLAUSE_END = /[,;:\u2013\u2014\u060c\u061b\uff0c\u3001\uff1b\uff1a]["'\u201d\u2019)\]\u00bb]*$/u;
|
|
5773
|
+
var BALANCE_MAX_WORDS = 48;
|
|
5774
|
+
function balancedBreaks(text2, lines, widthOf, boxWidth) {
|
|
5775
|
+
const forced = /* @__PURE__ */ new Set();
|
|
5776
|
+
const paragraph = (group2) => {
|
|
5777
|
+
const count = group2.length;
|
|
5778
|
+
if (count < 2) return;
|
|
5779
|
+
const from = group2[0].start, to = group2.at(-1).end;
|
|
5780
|
+
const words = [...text2.slice(from, to).matchAll(/(?:[^\s]|\u00a0|\u202f|\ufeff)+/gu)].map((match) => ({ start: from + match.index, end: from + match.index + match[0].length, text: match[0] }));
|
|
5781
|
+
const total = words.length;
|
|
5782
|
+
if (total < count || total > BALANCE_MAX_WORDS) return;
|
|
5783
|
+
const cache2 = /* @__PURE__ */ new Map(), span = (first, last) => {
|
|
5784
|
+
const key = first * (BALANCE_MAX_WORDS + 1) + last;
|
|
5785
|
+
let value = cache2.get(key);
|
|
5786
|
+
if (value === void 0) {
|
|
5787
|
+
value = widthOf(words[first].start, words[last - 1].end);
|
|
5788
|
+
cache2.set(key, value);
|
|
5789
|
+
}
|
|
5790
|
+
return value;
|
|
5791
|
+
};
|
|
5792
|
+
const target = span(0, total) / count;
|
|
5793
|
+
if (!(target > 0)) return;
|
|
5794
|
+
const credit = (last) => last >= total ? 0 : SENTENCE_END.test(words[last - 1].text) ? 0.02 : CLAUSE_END.test(words[last - 1].text) ? 0.01 : 0;
|
|
5795
|
+
const best = Array.from({ length: count + 1 }, () => Array(total + 1).fill(Infinity)), from_ = Array.from({ length: count + 1 }, () => Array(total + 1).fill(-1));
|
|
5796
|
+
best[0][0] = 0;
|
|
5797
|
+
for (let line2 = 1; line2 <= count; line2++) for (let last = line2; last <= total - (count - line2); last++) for (let first = line2 - 1; first < last; first++) {
|
|
5798
|
+
const before = best[line2 - 1][first];
|
|
5799
|
+
if (before === Infinity) continue;
|
|
5800
|
+
const width = span(first, last);
|
|
5801
|
+
if (width > boxWidth + WRAP_TOLERANCE) continue;
|
|
5802
|
+
const cost = before + ((width - target) / target) ** 2 - credit(last);
|
|
5803
|
+
if (cost < best[line2][last]) {
|
|
5804
|
+
best[line2][last] = cost;
|
|
5805
|
+
from_[line2][last] = first;
|
|
5806
|
+
}
|
|
5807
|
+
}
|
|
5808
|
+
if (best[count][total] === Infinity) return;
|
|
5809
|
+
for (let line2 = count, last = total; line2 > 1; line2--) {
|
|
5810
|
+
const first = from_[line2][last];
|
|
5811
|
+
forced.add(words[first].start);
|
|
5812
|
+
last = first;
|
|
5813
|
+
}
|
|
5814
|
+
};
|
|
5815
|
+
let group = [];
|
|
5816
|
+
for (const line2 of lines) {
|
|
5817
|
+
group.push(line2);
|
|
5818
|
+
if (line2.hard) {
|
|
5819
|
+
paragraph(group);
|
|
5820
|
+
group = [];
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
paragraph(group);
|
|
5824
|
+
return forced.size ? forced : void 0;
|
|
5825
|
+
}
|
|
5601
5826
|
var HANGING_SPACE = /[^\S\r\n\u00a0\u202f\ufeff]/u;
|
|
5602
5827
|
var SCRIPT_WIDTH_FACTORS = [
|
|
5603
5828
|
[/\p{Script=Tamil}/u, 1.53],
|
|
@@ -5621,11 +5846,11 @@ function measureText(text2, fontSize) {
|
|
|
5621
5846
|
function wrapText(text2, width, fontSize, measure = measureText) {
|
|
5622
5847
|
return fitSourceText(text2, { width, height: Number.MAX_VALUE }, fontSize, fontSize, 1, measure, true, false).lines;
|
|
5623
5848
|
}
|
|
5624
|
-
function fitText(text2, box, requestedSize =
|
|
5849
|
+
function fitText(text2, box, requestedSize = PROSE_NOMINAL_SIZE, minFontSize = 16, measure = measureText, direction, balance = false) {
|
|
5625
5850
|
if (![box.width, box.height, requestedSize, minFontSize].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || requestedSize <= 0 || minFontSize <= 0) {
|
|
5626
5851
|
throw new RangeError("Text dimensions and font sizes must be finite and positive.");
|
|
5627
5852
|
}
|
|
5628
|
-
return fitSourceText(text2, box, Math.max(requestedSize, minFontSize), minFontSize, 1, measure, true, true, direction);
|
|
5853
|
+
return fitSourceText(text2, box, Math.max(requestedSize, minFontSize), minFontSize, 1, measure, true, true, direction, balance);
|
|
5629
5854
|
}
|
|
5630
5855
|
var FONT_SIZE_GRID_PER_PX = 75;
|
|
5631
5856
|
var FONT_GRID_EPSILON = 1e-6;
|
|
@@ -5650,11 +5875,11 @@ function fitAtSizes(layout, requested, minimum, step = 1, snap = true) {
|
|
|
5650
5875
|
}
|
|
5651
5876
|
var PHOTO_RATIO = 3;
|
|
5652
5877
|
var PHOTO_GAP = 0.75;
|
|
5653
|
-
function quoteBodyRuns(runs) {
|
|
5654
|
-
if (!runs.length) return [
|
|
5878
|
+
function quoteBodyRuns(runs, marks2) {
|
|
5879
|
+
if (!runs.length) return [marks2.open + marks2.close];
|
|
5655
5880
|
const last = runs.length - 1;
|
|
5656
5881
|
return runs.map((run, index) => {
|
|
5657
|
-
const before = index === 0 ?
|
|
5882
|
+
const before = index === 0 ? marks2.open : "", after = index === last ? marks2.close : "";
|
|
5658
5883
|
return typeof run === "string" ? before + run + after : { ...run, text: before + run.text + after };
|
|
5659
5884
|
});
|
|
5660
5885
|
}
|
|
@@ -5689,23 +5914,24 @@ function layoutQuote(value, box, options = {}) {
|
|
|
5689
5914
|
for (const field of ["attribution", "role", "source"]) {
|
|
5690
5915
|
const text2 = quote[field];
|
|
5691
5916
|
if (!text2) continue;
|
|
5692
|
-
if (footer) footer += field === "role" ? "\n" :
|
|
5917
|
+
if (footer) footer += field === "role" ? "\n" : QUOTE_SOURCE_SEPARATOR;
|
|
5693
5918
|
footerSources.push(source(`${path}.${field}`, text2, footer.length));
|
|
5694
5919
|
footer += text2;
|
|
5695
5920
|
}
|
|
5696
5921
|
const hasPhoto = photoValue !== void 0, hasFooter = footer !== "", hasBlock = hasPhoto || hasFooter;
|
|
5697
5922
|
const photoPath = `${path}.photo`, rtl = options.direction === "rtl";
|
|
5698
5923
|
const bodyPath = shorthand ? path : `${path}.text`;
|
|
5924
|
+
const marks2 = quoteMarksFor(options.language);
|
|
5699
5925
|
const body = add(
|
|
5700
5926
|
"body",
|
|
5701
|
-
|
|
5702
|
-
[source(bodyPath, quoteText,
|
|
5927
|
+
`${marks2.open}${quoteText}${marks2.close}`,
|
|
5928
|
+
[source(bodyPath, quoteText, marks2.open.length)],
|
|
5703
5929
|
{ x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - (hasBlock ? 94 : 36) },
|
|
5704
|
-
|
|
5930
|
+
QUOTE_NOMINAL_SIZE,
|
|
5705
5931
|
options.fontFamilies?.accent ?? options.fontFamilies?.heading ?? "sans-serif",
|
|
5706
5932
|
600,
|
|
5707
5933
|
bodyPath,
|
|
5708
|
-
richBody ? quoteBodyRuns(richBody) : void 0
|
|
5934
|
+
richBody ? quoteBodyRuns(richBody, marks2) : void 0
|
|
5709
5935
|
);
|
|
5710
5936
|
const attribution = hasFooter ? add(
|
|
5711
5937
|
"footer",
|
|
@@ -5827,7 +6053,7 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5827
6053
|
const sourceValue = metric[role];
|
|
5828
6054
|
if (sourceValue === void 0) continue;
|
|
5829
6055
|
const text2 = String(sourceValue), path = scalar ? sourcePath : `${sourcePath}.${role}`;
|
|
5830
|
-
const nominal = role === "value" ?
|
|
6056
|
+
const nominal = (role === "value" ? 76 : role === "description" ? 20 : role === "trend" ? 18 : 23) * scale2;
|
|
5831
6057
|
const requestedStyle = { fontFamily: (role === "value" ? options.fontFamilies?.heading : options.fontFamilies?.body) ?? "sans-serif", fontWeight: role === "value" ? 800 : role === "description" ? 400 : 500, italic: false, path };
|
|
5832
6058
|
const part = {
|
|
5833
6059
|
role,
|
|
@@ -5979,6 +6205,8 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5979
6205
|
return { bounds, algorithm: "metric-flow-v1", alignment, textMeasurement: options.textMeasurement ? "provided" : "estimated", arrangement: selected.arrangement, ...metric.sentiment === void 0 ? {} : { sentiment: metric.sentiment }, attempts, parts, diagnostics, overflow: diagnostics.length > 0 };
|
|
5980
6206
|
}
|
|
5981
6207
|
var TIMELINE_STATUS_VALUES = ["done", "current", "planned"];
|
|
6208
|
+
var TIMELINE_NARROW_EM = 8;
|
|
6209
|
+
var TIMELINE_NARROW_REDUCTIONS = 4;
|
|
5982
6210
|
var TIMELINE_RING_RATIO = 1.6;
|
|
5983
6211
|
function layoutTimeline(value, box, options = {}) {
|
|
5984
6212
|
const shorthand = Array.isArray(value), timeline = shorthand ? { events: value } : value;
|
|
@@ -6042,87 +6270,96 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
6042
6270
|
let reductionLimit = 0;
|
|
6043
6271
|
for (const part of source) reductionLimit = Math.max(reductionLimit, (part.requestedFontSize - minimum) / scale2);
|
|
6044
6272
|
const reductions = Math.min(24, Math.ceil(reductionLimit));
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
};
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
});
|
|
6096
|
-
} else {
|
|
6097
|
-
const outlined = timeline.events.some((event) => event.status === "planned");
|
|
6098
|
-
const lead = hasRing ? ringRadius + strokeWidth / 2 : radius + (outlined ? strokeWidth / 2 : 0), gap = 2 * lead + 12 * scale2;
|
|
6099
|
-
const x = rtl ? box.x + box.width - lead : box.x + lead, textX = rtl ? box.x : box.x + gap, width = box.width - gap;
|
|
6100
|
-
events.forEach((fields2, index) => {
|
|
6101
|
-
const top = y;
|
|
6102
|
-
let first2;
|
|
6103
|
-
for (const [fieldIndex, part] of fields2.entries()) {
|
|
6104
|
-
const placed = place(part, textX, y, width, "left");
|
|
6105
|
-
first2 ??= placed;
|
|
6106
|
-
y += placed.box.height;
|
|
6107
|
-
if (fieldIndex < fields2.length - 1) y += 4 * scale2;
|
|
6108
|
-
}
|
|
6109
|
-
markers.push(marker(index, x, top + Math.min(first2?.box.height ?? 2 * radius, 2 * radius) / 2));
|
|
6110
|
-
y += 16 * scale2;
|
|
6111
|
-
});
|
|
6112
|
-
}
|
|
6113
|
-
for (const marker2 of markers) {
|
|
6114
|
-
const extent = (marker2.ring?.radius ?? marker2.radius) + (marker2.strokeWidth ?? 0) / 2;
|
|
6115
|
-
if (marker2.x - extent < box.x - 0.01 || marker2.y - extent < box.y - 0.01 || marker2.x + extent > box.x + box.width + 0.01 || marker2.y + extent > box.y + box.height + 0.01) {
|
|
6116
|
-
diagnostics.push({ code: "text-overflow", reason: "event-space", path: marker2.path, message: "Timeline marker has no usable space; increase the cell or paginate events." });
|
|
6117
|
-
score2 += 1;
|
|
6273
|
+
const labelSize = source.find((part) => part.role === "what")?.requestedFontSize ?? gridFontSize(22 * scale2, minimum);
|
|
6274
|
+
const narrow = timeline.events.length > 1 && box.width / Math.max(2, timeline.events.length) < TIMELINE_NARROW_EM * labelSize;
|
|
6275
|
+
const tryArrangement = (arrangement, reduction) => {
|
|
6276
|
+
attempts++;
|
|
6277
|
+
const parts = [], markers = [], diagnostics = [];
|
|
6278
|
+
let score2 = 0;
|
|
6279
|
+
const report = (part, reason, message, excess = 1) => {
|
|
6280
|
+
diagnostics.push({ code: "text-overflow", reason, path: part.path, message });
|
|
6281
|
+
score2 += Math.max(1, excess);
|
|
6282
|
+
};
|
|
6283
|
+
const place = (part, x, y2, width, alignment) => {
|
|
6284
|
+
const measured = measure(part, gridFontSize(part.requestedFontSize - reduction * scale2, minimum), Math.max(scale2, width), alignment);
|
|
6285
|
+
const area2 = { x, y: y2, width: Math.max(scale2, width), height: Math.max(scale2, measured.height) }, placement = outlines ? placeTextLines(measured.ink, area2, alignment, padding, measured.fit.directions) : void 0;
|
|
6286
|
+
const fit = { ...measured.fit, ...placement ? { placement } : {}, overflow: measured.fit.overflow || !!placement?.overflow };
|
|
6287
|
+
const accepted = { ...part, box: area2, alignment, fit };
|
|
6288
|
+
parts.push(accepted);
|
|
6289
|
+
if (fit.overflow) report(accepted, "text-fit", "Timeline field exceeds its readable width; increase its space or split the timeline.");
|
|
6290
|
+
if (breaksInsideWord(part.text, fit)) report(accepted, "text-fit", "Timeline field would split a word; use a wider vertical arrangement or paginate events.");
|
|
6291
|
+
if (area2.x < box.x - 0.01 || area2.y < box.y - 0.01 || area2.x + area2.width > box.x + box.width + 0.01 || area2.y + area2.height > box.y + box.height + 0.01) report(accepted, "part-outside-cell", "Timeline field extends outside its cell; increase the cell or paginate events.", Math.max(area2.x + area2.width - box.x - box.width, area2.y + area2.height - box.y - box.height));
|
|
6292
|
+
return accepted;
|
|
6293
|
+
};
|
|
6294
|
+
let y = box.y;
|
|
6295
|
+
for (const part of metadata) {
|
|
6296
|
+
const placed = place(part, box.x, y, box.width, "center");
|
|
6297
|
+
y += placed.box.height + 8 * scale2;
|
|
6298
|
+
}
|
|
6299
|
+
const available = box.y + box.height - y, count = events.length, radius = Math.min(9 * scale2, box.width / Math.max(2, count) / 5, Math.max(scale2, available) * 0.04);
|
|
6300
|
+
const statusOf = (index) => timeline.events[index].status, ringRadius = radius * TIMELINE_RING_RATIO, strokeWidth = Math.min(2 * scale2, radius / 2);
|
|
6301
|
+
const hasRing = timeline.events.some((event) => event.status === "current");
|
|
6302
|
+
const marker = (index, x, y2) => {
|
|
6303
|
+
const status = statusOf(index);
|
|
6304
|
+
return { path: eventPath(index), eventIndex: index, x, y: y2, radius, ...status ? { status } : {}, ...status === "current" ? { ring: { radius: ringRadius } } : {}, ...status === "current" || status === "planned" ? { strokeWidth } : {} };
|
|
6305
|
+
};
|
|
6306
|
+
if (arrangement === "alternating") {
|
|
6307
|
+
const width = box.width / Math.max(2, count), step = (box.width - width) / Math.max(1, count - 1), start = count === 1 ? box.x + box.width / 2 : box.x + width / 2;
|
|
6308
|
+
const fieldGap = 4 * scale2, clearance = 24 * scale2;
|
|
6309
|
+
const heights = events.map((fields2) => fields2.reduce((height, part) => height + measure(part, gridFontSize(part.requestedFontSize - reduction * scale2, minimum), width, "center").height, 0) + Math.max(0, fields2.length - 1) * fieldGap);
|
|
6310
|
+
const markerExtent = hasRing ? ringRadius + strokeWidth / 2 : radius;
|
|
6311
|
+
const upper = Math.max(markerExtent, ...heights.filter((_, index) => index % 2 === 0).map((height) => height + clearance));
|
|
6312
|
+
const lower = Math.max(markerExtent, ...heights.filter((_, index) => index % 2 === 1).map((height) => height + clearance));
|
|
6313
|
+
const lineY = y + Math.max(0, (available - upper - lower) / 2) + upper;
|
|
6314
|
+
events.forEach((fields2, index) => {
|
|
6315
|
+
const x = start + (rtl ? count - 1 - index : index) * step, top = index % 2 === 0 ? lineY - clearance - heights[index] : lineY + clearance, bottom = index % 2 === 0 ? lineY - clearance : box.y + box.height;
|
|
6316
|
+
markers.push(marker(index, x, lineY));
|
|
6317
|
+
let cursor = top;
|
|
6318
|
+
for (const [fieldIndex, part] of fields2.entries()) {
|
|
6319
|
+
const placed = place(part, x - width / 2, cursor, width, "center");
|
|
6320
|
+
cursor += placed.box.height;
|
|
6321
|
+
if (cursor > bottom + 0.01) report(placed, "event-space", "Timeline event labels exceed their side of the connector; change the arrangement or paginate events.", cursor - bottom);
|
|
6322
|
+
if (fieldIndex < fields2.length - 1) cursor += fieldGap;
|
|
6118
6323
|
}
|
|
6324
|
+
});
|
|
6325
|
+
} else {
|
|
6326
|
+
const outlined = timeline.events.some((event) => event.status === "planned");
|
|
6327
|
+
const lead = hasRing ? ringRadius + strokeWidth / 2 : radius + (outlined ? strokeWidth / 2 : 0), gap = 2 * lead + 12 * scale2;
|
|
6328
|
+
const x = rtl ? box.x + box.width - lead : box.x + lead, textX = rtl ? box.x : box.x + gap, width = box.width - gap;
|
|
6329
|
+
events.forEach((fields2, index) => {
|
|
6330
|
+
const top = y;
|
|
6331
|
+
let first2;
|
|
6332
|
+
for (const [fieldIndex, part] of fields2.entries()) {
|
|
6333
|
+
const placed = place(part, textX, y, width, "left");
|
|
6334
|
+
first2 ??= placed;
|
|
6335
|
+
y += placed.box.height;
|
|
6336
|
+
if (fieldIndex < fields2.length - 1) y += 4 * scale2;
|
|
6337
|
+
}
|
|
6338
|
+
markers.push(marker(index, x, top + Math.min(first2?.box.height ?? 2 * radius, 2 * radius) / 2));
|
|
6339
|
+
y += 16 * scale2;
|
|
6340
|
+
});
|
|
6341
|
+
}
|
|
6342
|
+
for (const marker2 of markers) {
|
|
6343
|
+
const extent = (marker2.ring?.radius ?? marker2.radius) + (marker2.strokeWidth ?? 0) / 2;
|
|
6344
|
+
if (marker2.x - extent < box.x - 0.01 || marker2.y - extent < box.y - 0.01 || marker2.x + extent > box.x + box.width + 0.01 || marker2.y + extent > box.y + box.height + 0.01) {
|
|
6345
|
+
diagnostics.push({ code: "text-overflow", reason: "event-space", path: marker2.path, message: "Timeline marker has no usable space; increase the cell or paginate events." });
|
|
6346
|
+
score2 += 1;
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6349
|
+
const first = markers[0], last = markers.at(-1), connector = rtl ? { x1: Math.min(first.x, last.x), y1: first.y, x2: Math.max(first.x, last.x), y2: last.y } : { x1: first.x, y1: first.y, x2: last.x, y2: last.y };
|
|
6350
|
+
const candidate = { arrangement, parts, markers, connector, diagnostics, score: score2 };
|
|
6351
|
+
if (!selected || score2 < selected.score) selected = candidate;
|
|
6352
|
+
return !diagnostics.length;
|
|
6353
|
+
};
|
|
6354
|
+
let settled = false;
|
|
6355
|
+
if (narrow) for (let reduction = 0; reduction <= Math.min(reductions, TIMELINE_NARROW_REDUCTIONS) && !settled; reduction++) settled = tryArrangement("vertical", reduction);
|
|
6356
|
+
for (let reduction = 0; reduction <= reductions && !settled; reduction++) {
|
|
6357
|
+
for (const arrangement of ["alternating", "vertical"]) {
|
|
6358
|
+
if (tryArrangement(arrangement, reduction)) {
|
|
6359
|
+
settled = true;
|
|
6360
|
+
break;
|
|
6119
6361
|
}
|
|
6120
|
-
const first = markers[0], last = markers.at(-1), connector = rtl ? { x1: Math.min(first.x, last.x), y1: first.y, x2: Math.max(first.x, last.x), y2: last.y } : { x1: first.x, y1: first.y, x2: last.x, y2: last.y };
|
|
6121
|
-
const candidate = { arrangement, parts, markers, connector, diagnostics, score: score2 };
|
|
6122
|
-
if (!selected || score2 < selected.score) selected = candidate;
|
|
6123
|
-
if (!diagnostics.length) break;
|
|
6124
6362
|
}
|
|
6125
|
-
if (!selected.diagnostics.length) break;
|
|
6126
6363
|
}
|
|
6127
6364
|
const { score, ...result } = selected;
|
|
6128
6365
|
if (result.diagnostics.length && options.overflow === "error") throw new OPFCompositionError(result.diagnostics);
|
|
@@ -6131,9 +6368,9 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
6131
6368
|
function fitCodeText(text2, box, size, minimum, step, measure, direction) {
|
|
6132
6369
|
return fitSourceText(text2, box, size, minimum, step, measure, false, true, direction);
|
|
6133
6370
|
}
|
|
6134
|
-
function fitSourceText(text2, box, size, minimum, step, measure, prose = false, snap = true, direction) {
|
|
6371
|
+
function fitSourceText(text2, box, size, minimum, step, measure, prose = false, snap = true, direction, balance = false) {
|
|
6135
6372
|
const directionAt = direction === "rtl" ? paragraphDirectionAt(text2, "rtl") : void 0;
|
|
6136
|
-
const layout = (fontSize) => {
|
|
6373
|
+
const layout = (fontSize, forced) => {
|
|
6137
6374
|
const tabWidth = measure(" ", fontSize) * 4;
|
|
6138
6375
|
if (!Number.isFinite(tabWidth) || text2.includes(" ") && tabWidth <= 0) throw new RangeError("Text tabs require a positive finite measured space advance.");
|
|
6139
6376
|
const measureLine = (start2, end2, record8 = false) => {
|
|
@@ -6174,6 +6411,7 @@ function fitSourceText(text2, box, size, minimum, step, measure, prose = false,
|
|
|
6174
6411
|
push(a, b, "hard");
|
|
6175
6412
|
continue;
|
|
6176
6413
|
}
|
|
6414
|
+
if (forced?.has(a) && end > start && /\S/u.test(text2.slice(start, end))) push(a, a, "soft");
|
|
6177
6415
|
if (width(start, b) <= box.width + WRAP_TOLERANCE) {
|
|
6178
6416
|
end = b;
|
|
6179
6417
|
continue;
|
|
@@ -6211,7 +6449,22 @@ function fitSourceText(text2, box, size, minimum, step, measure, prose = false,
|
|
|
6211
6449
|
overflow: sourceLines.length * lineHeight > box.height + 0.01 || sourceLines.some((line2) => line2.width > box.width + 0.01)
|
|
6212
6450
|
};
|
|
6213
6451
|
};
|
|
6214
|
-
|
|
6452
|
+
const balanced = (fontSize) => {
|
|
6453
|
+
const greedy = layout(fontSize);
|
|
6454
|
+
if (!balance || greedy.overflow || greedy.sourceLines.length < 2) return greedy;
|
|
6455
|
+
const widthOf = (start, end) => {
|
|
6456
|
+
let x = 0;
|
|
6457
|
+
for (const [index, segment2] of text2.slice(start, end).split(" ").entries()) {
|
|
6458
|
+
if (index) x = (Math.floor(x / (measure(" ", fontSize) * 4) + 1e-9) + 1) * measure(" ", fontSize) * 4;
|
|
6459
|
+
if (segment2) x += measure(segment2, fontSize);
|
|
6460
|
+
}
|
|
6461
|
+
return x;
|
|
6462
|
+
};
|
|
6463
|
+
const forced = balancedBreaks(text2, greedy.sourceLines.map((line2) => ({ start: line2.start, end: line2.end, hard: line2.boundary !== "soft" })), widthOf, box.width);
|
|
6464
|
+
const result = forced ? layout(fontSize, forced) : greedy;
|
|
6465
|
+
return result.sourceLines.length === greedy.sourceLines.length && !result.overflow ? result : greedy;
|
|
6466
|
+
};
|
|
6467
|
+
return fitAtSizes(balance ? balanced : layout, size, minimum, step, snap);
|
|
6215
6468
|
}
|
|
6216
6469
|
function layoutCode(value, box, options = {}) {
|
|
6217
6470
|
const shorthand = typeof value === "string", code = shorthand ? { source: value } : value;
|
|
@@ -6234,7 +6487,7 @@ function layoutCode(value, box, options = {}) {
|
|
|
6234
6487
|
sources: generated ? [] : [{ path: partPath, start: 0, end: text2.length }],
|
|
6235
6488
|
generated,
|
|
6236
6489
|
box: { ...inner },
|
|
6237
|
-
requestedFontSize: gridFontSize((role === "body" ?
|
|
6490
|
+
requestedFontSize: gridFontSize((role === "body" ? CODE_NOMINAL_SIZE : 14) * scale2, minimum),
|
|
6238
6491
|
minFontSize: minimum,
|
|
6239
6492
|
requestedStyle,
|
|
6240
6493
|
style: resolveTextStyle({ ...requestedStyle }, options.textMeasurement)
|
|
@@ -6247,7 +6500,16 @@ function layoutCode(value, box, options = {}) {
|
|
|
6247
6500
|
if (!parts.length) add("language", "code", path, true);
|
|
6248
6501
|
const body = add("body", code.source, shorthand ? path : `${path}.source`), headers = parts.filter((part) => part !== body);
|
|
6249
6502
|
const usable2 = (area2) => [area2.x, area2.y, area2.width, area2.height].every(Number.isFinite) && area2.width > 0 && area2.height > 0;
|
|
6250
|
-
const
|
|
6503
|
+
const measureCode = textWidthMeasurer(body.style, options.textMeasurement);
|
|
6504
|
+
const fit = (part, area2, size = part.requestedFontSize, floor = minimum) => {
|
|
6505
|
+
if (!usable2(area2)) return void 0;
|
|
6506
|
+
const wanted = fitCodeText(part.text, area2, size, floor, scale2, textWidthMeasurer(part.style, options.textMeasurement));
|
|
6507
|
+
const wraps = (value2) => value2.sourceLines.filter((line2) => line2.boundary === "soft").length;
|
|
6508
|
+
const legacy = gridFontSize(LEGACY_CODE_NOMINAL_SIZE * scale2, minimum);
|
|
6509
|
+
if (part.role !== "body" || part.requestedFontSize <= legacy || !wraps(wanted)) return wanted;
|
|
6510
|
+
const earlier = fitCodeText(part.text, area2, legacy, floor, scale2, measureCode);
|
|
6511
|
+
return !earlier.overflow && wraps(earlier) < wraps(wanted) ? earlier : wanted;
|
|
6512
|
+
};
|
|
6251
6513
|
if (usable2(inner)) {
|
|
6252
6514
|
const combinations = headers.reduce((choices, part) => choices.flatMap((choice) => [.../* @__PURE__ */ new Set([part.requestedFontSize, minimum])].map((size) => [...choice, { part, size }])), [[]]);
|
|
6253
6515
|
let selected;
|
|
@@ -6270,6 +6532,7 @@ function layoutCode(value, box, options = {}) {
|
|
|
6270
6532
|
part.box = box2;
|
|
6271
6533
|
part.fit = fit2;
|
|
6272
6534
|
}
|
|
6535
|
+
if (selected && !selected.overflow && body.fit) body.box = { ...body.box, height: Math.min(body.box.height, body.fit.lines.length * body.fit.lineHeight) };
|
|
6273
6536
|
}
|
|
6274
6537
|
const report = (reason, part, roles, message) => diagnostics.push({ code: "text-overflow", reason, path: part.path, parts: roles, message });
|
|
6275
6538
|
for (const part of parts) {
|
|
@@ -6287,9 +6550,11 @@ function layoutCode(value, box, options = {}) {
|
|
|
6287
6550
|
}
|
|
6288
6551
|
}
|
|
6289
6552
|
if (diagnostics.length && options.overflow === "error") throw new OPFCompositionError(diagnostics);
|
|
6290
|
-
|
|
6553
|
+
const bottom = body.fit && !body.fit.overflow ? body.box.y + body.box.height + 18 : box.y + box.height;
|
|
6554
|
+
const bounds = { x: box.x, y: box.y, width: box.width, height: Math.min(box.height, Math.max(bottom - box.y, 0)) };
|
|
6555
|
+
return { bounds, algorithm: "code-flow-v1", textMeasurement: options.textMeasurement ? "provided" : "estimated", parts, diagnostics, overflow: diagnostics.length > 0 };
|
|
6291
6556
|
}
|
|
6292
|
-
function fitRichText(input, box, requestedSize =
|
|
6557
|
+
function fitRichText(input, box, requestedSize = PROSE_NOMINAL_SIZE, minFontSize = 16, options = { style: { fontFamily: "sans-serif", fontWeight: 400 } }) {
|
|
6293
6558
|
if (![box.width, box.height, requestedSize, minFontSize].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("Rich text dimensions and font sizes must be finite and positive.");
|
|
6294
6559
|
const layout = richTextLayouter(input, box, requestedSize, options, minFontSize);
|
|
6295
6560
|
return fitAtSizes(layout, requestedSize, richMinimum(input, requestedSize, minFontSize));
|
|
@@ -6306,7 +6571,7 @@ function richMinimum(input, requested, minimum) {
|
|
|
6306
6571
|
return visible ? floor : minimum;
|
|
6307
6572
|
}
|
|
6308
6573
|
function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
6309
|
-
let offset = 0;
|
|
6574
|
+
let offset = 0, lastWidth = () => 0, lastRanges = [];
|
|
6310
6575
|
const source = input.map((value, runIndex) => {
|
|
6311
6576
|
const run = typeof value === "string" ? { text: value } : value;
|
|
6312
6577
|
if (typeof run?.text !== "string" || run.fontSize !== void 0 && (!Number.isFinite(run.fontSize) || run.fontSize <= 0)) throw new RangeError("Rich text runs need text and a positive finite font size.");
|
|
@@ -6320,7 +6585,7 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
|
6320
6585
|
const whole = source.map((entry) => entry.run.text).join("");
|
|
6321
6586
|
const paint = (raw) => raw >= minimum - 1e-6 ? gridFontSize(raw, minimum) : snapFontSizeDown(raw);
|
|
6322
6587
|
const directionAt = options.direction === "rtl" ? paragraphDirectionAt(whole, "rtl") : void 0;
|
|
6323
|
-
const
|
|
6588
|
+
const build = (rawFontSize, forced) => {
|
|
6324
6589
|
const fontSize = paint(rawFontSize), ratio = rawFontSize / requestedSize;
|
|
6325
6590
|
const fragments = (start, end) => {
|
|
6326
6591
|
let x = 0;
|
|
@@ -6375,6 +6640,7 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
|
6375
6640
|
lineEnd = end;
|
|
6376
6641
|
continue;
|
|
6377
6642
|
}
|
|
6643
|
+
if (forced?.has(start) && lineEnd > lineStart && /\S/u.test(whole.slice(lineStart, lineEnd))) push(start);
|
|
6378
6644
|
if (width(lineStart, end) <= box.width + WRAP_TOLERANCE) {
|
|
6379
6645
|
lineEnd = end;
|
|
6380
6646
|
continue;
|
|
@@ -6418,7 +6684,7 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
|
6418
6684
|
y += height;
|
|
6419
6685
|
}
|
|
6420
6686
|
}
|
|
6421
|
-
|
|
6687
|
+
const fit = {
|
|
6422
6688
|
lines: ranges.map((range) => whole.slice(range.start, range.end)),
|
|
6423
6689
|
fontSize,
|
|
6424
6690
|
lineHeight: Math.max(fontSize * 1.22, ...richLines.map((line2) => line2.height)),
|
|
@@ -6427,12 +6693,22 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
|
6427
6693
|
overflow: y > box.height + 0.01 || richLines.some((line2) => line2.width > box.width + 0.01),
|
|
6428
6694
|
...directionAt ? { directions: ranges.map((range) => directionAt(range.start)) } : {}
|
|
6429
6695
|
};
|
|
6696
|
+
lastWidth = width;
|
|
6697
|
+
lastRanges = ranges;
|
|
6698
|
+
return fit;
|
|
6699
|
+
};
|
|
6700
|
+
const layout = (rawFontSize) => {
|
|
6701
|
+
const greedy = build(rawFontSize);
|
|
6702
|
+
if (!options.balance || greedy.overflow || greedy.richLines.length < 2) return greedy;
|
|
6703
|
+
const forced = balancedBreaks(whole, lastRanges.map((range) => ({ start: range.start, end: range.end, hard: /^[\r\n]/.test(whole.slice(range.end, range.end + 1)) || range.end >= whole.length })), lastWidth, box.width);
|
|
6704
|
+
const result = forced ? build(rawFontSize, forced) : greedy;
|
|
6705
|
+
return result.richLines.length === greedy.richLines.length && !result.overflow ? result : greedy;
|
|
6430
6706
|
};
|
|
6431
6707
|
return layout;
|
|
6432
6708
|
}
|
|
6433
6709
|
var PICTURE_BULLET_SCALE = 0.65;
|
|
6434
6710
|
function contentNominalSize(field) {
|
|
6435
|
-
return field === "items" || field === "bullets" ?
|
|
6711
|
+
return field === "items" || field === "bullets" ? LIST_NOMINAL_SIZE : field === "table" ? TABLE_NOMINAL_SIZE : PROSE_NOMINAL_SIZE;
|
|
6436
6712
|
}
|
|
6437
6713
|
function fitList(input, box, requestedSize = contentNominalSize("items"), minFontSize = 16, options = { style: { fontFamily: "sans-serif", fontWeight: 400 } }) {
|
|
6438
6714
|
if (!Array.isArray(input) || ![box.width, box.height, requestedSize, minFontSize].every((value) => Number.isFinite(value) && value > 0)) throw new RangeError("List content, dimensions and font sizes must be valid.");
|
|
@@ -6457,10 +6733,11 @@ function fitList(input, box, requestedSize = contentNominalSize("items"), minFon
|
|
|
6457
6733
|
const entries = [], lines = [], directions = [];
|
|
6458
6734
|
const markerStyles = numbers ? source.map((item) => resolveTextStyle(markerStyleFor(item), options.textMeasurement)) : [];
|
|
6459
6735
|
const markerWidths = numbers ? numbers.map((number, index) => textWidthMeasurer(markerStyles[index], options.textMeasurement)(number.text, fontSize)) : [];
|
|
6736
|
+
const none = options.bullet === "none" && !numbers;
|
|
6460
6737
|
const hanging = numbers ? Math.max(fontSize * 1.1, Math.max(0, ...markerWidths) + fontSize * 0.3) : fontSize * 1.1;
|
|
6461
6738
|
for (const item of source) {
|
|
6462
6739
|
const rtl = item.direction === "rtl";
|
|
6463
|
-
const indent = hanging, offset = Math.min(box.width, item.level *
|
|
6740
|
+
const indent = none ? 0 : hanging, offset = Math.min(box.width, item.level * hanging), x = rtl ? box.x : box.x + offset + indent, width = Math.max(1, rtl ? box.width - offset - indent : box.x + box.width - x);
|
|
6464
6741
|
if (offset + indent >= box.width) overflow = true;
|
|
6465
6742
|
const textBox = { x, y, width, height: box.height };
|
|
6466
6743
|
const style = { ...options.style, path: item.textPath };
|
|
@@ -6481,7 +6758,7 @@ function fitList(input, box, requestedSize = contentNominalSize("items"), minFon
|
|
|
6481
6758
|
}
|
|
6482
6759
|
overflow ||= text2.overflow || !!description?.overflow;
|
|
6483
6760
|
const number = numbers?.[item.index];
|
|
6484
|
-
const marker = { text: number ? number.text : ["\u2022", "\u25E6", "\u25AA"][item.level % 3], x: rtl ? box.x + box.width - offset : box.x + offset, y: textBox.y + (text2.richLines[0]?.baseline ?? fontSize), fontSize, style: number ? markerStyles[item.index] : resolveTextStyle(style, options.textMeasurement), indent, ...number ? { number, width: markerWidths[item.index] } : {}, ...rtl ? { anchor: "end" } : {} }, side = fontSize * PICTURE_BULLET_SCALE;
|
|
6761
|
+
const marker = { text: number ? number.text : none ? "" : ["\u2022", "\u25E6", "\u25AA"][item.level % 3], x: rtl ? box.x + box.width - offset : box.x + offset, y: textBox.y + (text2.richLines[0]?.baseline ?? fontSize), fontSize, style: number ? markerStyles[item.index] : resolveTextStyle(style, options.textMeasurement), indent, ...number ? { number, width: markerWidths[item.index] } : {}, ...none ? { none: true } : {}, ...rtl ? { anchor: "end" } : {} }, side = fontSize * PICTURE_BULLET_SCALE;
|
|
6485
6762
|
entries.push({
|
|
6486
6763
|
index: item.index,
|
|
6487
6764
|
level: item.level,
|
|
@@ -6495,7 +6772,7 @@ function fitList(input, box, requestedSize = contentNominalSize("items"), minFon
|
|
|
6495
6772
|
descriptionBox,
|
|
6496
6773
|
marker,
|
|
6497
6774
|
...item.direction ? { direction: item.direction } : {},
|
|
6498
|
-
...options.bulletImage && !number ? { bulletImage: options.bulletImage, bulletBox: { x: rtl ? marker.x - side : marker.x, y: marker.y - side, width: side, height: side } } : {}
|
|
6775
|
+
...options.bulletImage && !number && !none ? { bulletImage: options.bulletImage, bulletBox: { x: rtl ? marker.x - side : marker.x, y: marker.y - side, width: side, height: side } } : {}
|
|
6499
6776
|
});
|
|
6500
6777
|
if (item.index < source.length - 1) y += fontSize * 0.28;
|
|
6501
6778
|
}
|
|
@@ -6537,15 +6814,16 @@ function layoutTable(value, box, options = {}) {
|
|
|
6537
6814
|
const shown = tableCellDisplayValue(cell.input, formats[cell.column]);
|
|
6538
6815
|
if (shown !== cell.input) cell.value = typeof shown === "object" && shown !== null && !Array.isArray(shown) ? shown.value : shown;
|
|
6539
6816
|
}
|
|
6540
|
-
const columnCount = grid.columnCount
|
|
6817
|
+
const columnCount = grid.columnCount;
|
|
6541
6818
|
const cells = grid.rows.flat().map((cell) => {
|
|
6542
6819
|
const padding = { top: 8, right: 10, bottom: 4, left: 10, ...cell.style.padding };
|
|
6543
|
-
const width =
|
|
6820
|
+
const width = 0;
|
|
6544
6821
|
const style = { fontFamily: options.fontFamily ?? "sans-serif", fontWeight: cell.header || cell.style.bold ? 700 : 400, italic: false, path: cell.valuePath };
|
|
6545
6822
|
const numericDefault = numeric.has(cell) || (cell.header || Array.isArray(cell.value)) && cell.colSpan === 1 && numericColumns.has(cell.column);
|
|
6546
6823
|
const alignment = cell.style.align ?? options.alignment ?? (numericDefault ? options.direction === "rtl" ? "left" : "right" : "left");
|
|
6547
6824
|
return { ...cell, padding, width, textStyle: style, alignment };
|
|
6548
6825
|
});
|
|
6826
|
+
const columnWidths2 = Array(columnCount).fill(box.width / columnCount);
|
|
6549
6827
|
const cellMinimum = (cell) => Array.isArray(cell.value) ? richMinimum(cell.value, requested, minimum) : minimum;
|
|
6550
6828
|
let trial = requested;
|
|
6551
6829
|
const cellSize = (cell) => {
|
|
@@ -6556,6 +6834,59 @@ function layoutTable(value, box, options = {}) {
|
|
|
6556
6834
|
const textBox = { width: Math.max(scale2, cell.width), height: Math.max(scale2, height) }, size = cellSize(cell);
|
|
6557
6835
|
return Array.isArray(cell.value) ? richTextLayouter(cell.value, textBox, requested, { style: cell.textStyle, ...options.codeFontFamily ? { codeFontFamily: options.codeFontFamily } : {}, textMeasurement: options.textMeasurement, uniformLineHeight: true, direction: options.direction }, minimum)(size) : fitText(flatten(cell.value), textBox, size, size, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement), options.direction);
|
|
6558
6836
|
};
|
|
6837
|
+
const horizontalPadding = (cell) => (cell.padding.left + cell.padding.right) * scale2;
|
|
6838
|
+
const measureText2 = (cell) => textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement);
|
|
6839
|
+
const wordSplit = /[^\S\u00a0\u202f\ufeff]+/u;
|
|
6840
|
+
const demand = (cell) => {
|
|
6841
|
+
const measure = measureText2(cell), size = cellSize(cell);
|
|
6842
|
+
let widest = 0, longest = 0;
|
|
6843
|
+
for (const line2 of flatten(cell.value).split(/\r\n|\r|\n/)) {
|
|
6844
|
+
longest = Math.max(longest, measure(line2.replace(/\t/g, " "), size));
|
|
6845
|
+
for (const word of line2.split(wordSplit)) {
|
|
6846
|
+
if (!word) continue;
|
|
6847
|
+
widest = Math.max(widest, UNSPACED_SCRIPT.test(word) ? Math.max(...[...word].map((character) => measure(character, size))) : measure(word, size));
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
const padding = horizontalPadding(cell), slack = 0.5 * scale2;
|
|
6851
|
+
return { min: widest > 0 ? widest + padding + slack : padding, max: Math.max(longest + padding + slack, padding) };
|
|
6852
|
+
};
|
|
6853
|
+
const sizeColumns = () => {
|
|
6854
|
+
const min = Array(columnCount).fill(0), max = Array(columnCount).fill(0), demands = cells.map(demand);
|
|
6855
|
+
cells.forEach((cell, index) => {
|
|
6856
|
+
if (cell.colSpan === 1) {
|
|
6857
|
+
min[cell.column] = Math.max(min[cell.column], demands[index].min);
|
|
6858
|
+
max[cell.column] = Math.max(max[cell.column], demands[index].max);
|
|
6859
|
+
}
|
|
6860
|
+
});
|
|
6861
|
+
cells.forEach((cell, index) => {
|
|
6862
|
+
if (cell.colSpan > 1) for (const [need, target] of [[demands[index].min, min], [demands[index].max, max]]) {
|
|
6863
|
+
const columns2 = Array.from({ length: cell.colSpan }, (_, offset) => cell.column + offset), have = columns2.reduce((sum2, column) => sum2 + target[column], 0);
|
|
6864
|
+
if (need > have) for (const column of columns2) target[column] += (need - have) / cell.colSpan;
|
|
6865
|
+
}
|
|
6866
|
+
});
|
|
6867
|
+
const total = box.width, sum = (values) => values.reduce((a, b) => a + b, 0);
|
|
6868
|
+
for (let column = 0; column < columnCount; column++) max[column] = Math.max(max[column], min[column], 1);
|
|
6869
|
+
const minTotal = sum(min), maxTotal = sum(max);
|
|
6870
|
+
let widths;
|
|
6871
|
+
if (maxTotal <= total) widths = max.map((value2) => value2 + (total - maxTotal) * value2 / maxTotal);
|
|
6872
|
+
else if (minTotal <= total) {
|
|
6873
|
+
let low = 0, high = total;
|
|
6874
|
+
for (let step = 0; step < 60; step++) {
|
|
6875
|
+
const level = (low + high) / 2;
|
|
6876
|
+
if (sum(min.map((value2, column) => Math.min(max[column], Math.max(value2, level)))) > total) high = level;
|
|
6877
|
+
else low = level;
|
|
6878
|
+
}
|
|
6879
|
+
widths = min.map((value2, column) => Math.min(max[column], Math.max(value2, low)));
|
|
6880
|
+
const rest = total - sum(widths), open = widths.map((value2, column) => value2 > min[column] + 1e-9 && value2 < max[column] - 1e-9);
|
|
6881
|
+
const target = open.indexOf(true);
|
|
6882
|
+
if (target >= 0) widths[target] += rest;
|
|
6883
|
+
else widths[widths.indexOf(Math.max(...widths))] += rest;
|
|
6884
|
+
} else widths = min.map((value2) => value2 * total / Math.max(minTotal, Number.EPSILON));
|
|
6885
|
+
columnWidths2.splice(0, columnCount, ...widths);
|
|
6886
|
+
for (const cell of cells) cell.width = sum(columnWidths2.slice(cell.column, cell.column + cell.colSpan)) - horizontalPadding(cell);
|
|
6887
|
+
return min;
|
|
6888
|
+
};
|
|
6889
|
+
const splitsWords = () => cells.some((cell) => demand(cell).min - 0.5 * scale2 > cell.width + horizontalPadding(cell) + 0.01);
|
|
6559
6890
|
const textHeight = (fit) => "height" in fit ? fit.height : fit.lines.length * fit.lineHeight;
|
|
6560
6891
|
const required = (cell, natural) => {
|
|
6561
6892
|
const floor = cellMinimum(cell), size = gridFontSize(natural ? Math.max(trial, floor) : floor, floor);
|
|
@@ -6584,7 +6915,8 @@ function layoutTable(value, box, options = {}) {
|
|
|
6584
6915
|
let overflow = false;
|
|
6585
6916
|
const rows3 = heights.map((height, r) => ({ box: { x: box.x, y: ys[r], width: box.width, height }, cells: [] }));
|
|
6586
6917
|
for (const cell of cells) {
|
|
6587
|
-
const
|
|
6918
|
+
const before = options.direction === "rtl" ? columnWidths2.slice(cell.column + cell.colSpan) : columnWidths2.slice(0, cell.column);
|
|
6919
|
+
const cellBox = { x: box.x + before.reduce((a, b) => a + b, 0), y: ys[cell.row], width: columnWidths2.slice(cell.column, cell.column + cell.colSpan).reduce((a, b) => a + b, 0), height: ys[cell.row + cell.rowSpan] - ys[cell.row] };
|
|
6588
6920
|
const available = cellBox.height - (cell.padding.top + cell.padding.bottom) * scale2;
|
|
6589
6921
|
const fit = fitCell(cell, available), height = textHeight(fit);
|
|
6590
6922
|
const offset = cell.style.verticalAlign === "bottom" ? Math.max(0, available - height) : cell.style.verticalAlign === "middle" ? Math.max(0, (available - height) / 2) : 0;
|
|
@@ -6592,13 +6924,14 @@ function layoutTable(value, box, options = {}) {
|
|
|
6592
6924
|
overflow ||= cell.width <= 0 || available <= 0 || fit.overflow;
|
|
6593
6925
|
rows3[cell.row].cells.push({ value: cell.value, input: cell.input, path: cell.valuePath, sourcePath: cell.path, style: cell.style, alignment: cell.alignment, row: cell.row, column: cell.column, rowSpan: cell.rowSpan, colSpan: cell.colSpan, header: cell.header, rich: Array.isArray(cell.value), box: cellBox, textBox, textStyle: resolveTextStyle(cell.textStyle, options.textMeasurement), fit, ...fit.directions ? { direction: fit.directions[0] } : {} });
|
|
6594
6926
|
}
|
|
6595
|
-
return { rows: rows3, columnCount, height: sum(heights), overflow };
|
|
6927
|
+
return { rows: rows3, columnCount, height: sum(heights), overflow, columnWidths: [...columnWidths2], splitsWords: false };
|
|
6596
6928
|
};
|
|
6597
6929
|
for (let step = 0; ; step++) {
|
|
6598
6930
|
const raw = requested - step * scale2, last = step === 64 || raw <= minimum;
|
|
6599
6931
|
trial = last ? snapFontSizeUp(minimum) : gridFontSize(raw, minimum);
|
|
6600
|
-
|
|
6601
|
-
|
|
6932
|
+
sizeColumns();
|
|
6933
|
+
const layout = place(), splits = splitsWords();
|
|
6934
|
+
if (last || !layout.overflow && !splits) return { ...layout, splitsWords: splits };
|
|
6602
6935
|
}
|
|
6603
6936
|
}
|
|
6604
6937
|
function tableOverflows(value, box, scale2, settings, options, path) {
|
|
@@ -6706,14 +7039,15 @@ function composeSlide(input, options = {}) {
|
|
|
6706
7039
|
const minSize = snapFontSizeUp((composition.minFontSize ?? 16) * scale2);
|
|
6707
7040
|
const rasterPadding = (options.textRasterPadding ?? 1) * scale2;
|
|
6708
7041
|
if (!Number.isFinite(rasterPadding) || rasterPadding < 0) throw new RangeError("Text raster padding must be finite and nonnegative.");
|
|
6709
|
-
let
|
|
6710
|
-
const alignmentFor = (field) => (field === "title" || (field === "tag" ||
|
|
7042
|
+
let subtitleInGroup = true;
|
|
7043
|
+
const alignmentFor = (field) => (field === "title" || (field === "tag" || subtitleInGroup && field === "subtitle") && hints.sources.contentAlignment !== "slide" ? hints.titleAlignment : hints.contentAlignment) ?? (field === "metric" ? "center" : "left");
|
|
6711
7044
|
const styleFor = (field, path2) => resolveTextStyle({
|
|
6712
7045
|
fontFamily: (field === "title" ? options.fontFamilies?.heading : field === "code" ? options.fontFamilies?.code : field === "tag" ? options.fontFamilies?.accent ?? options.fontFamilies?.body : options.fontFamilies?.body) ?? (field === "code" ? "monospace" : "sans-serif"),
|
|
6713
7046
|
fontWeight: field === "title" ? 700 : 400,
|
|
6714
7047
|
path: path2
|
|
6715
7048
|
}, options.textMeasurement);
|
|
6716
7049
|
const listBullet = hints.listBullet !== void 0 ? { value: hints.listBullet, path: hints.paths.listBullet } : void 0;
|
|
7050
|
+
const noListBullet = listBullet?.value === "none";
|
|
6717
7051
|
const bulletImage = listBullet?.value === "image" ? (() => {
|
|
6718
7052
|
const resolved = resolveLogo(options.presentation, slide, { shape: "icon", onDark: options.darkBackground, slideIndex: options.slideIndex });
|
|
6719
7053
|
return resolved ? { source: resolved.source, path: resolved.path } : void 0;
|
|
@@ -6724,13 +7058,14 @@ function composeSlide(input, options = {}) {
|
|
|
6724
7058
|
const richOptions = (style) => ({ style, textMeasurement: options.textMeasurement, ...options.fontFamilies?.code ? { codeFontFamily: options.fontFamilies.code } : {}, ...citationMarker ? { citationMarker } : {}, ...rtl ? { direction: "rtl" } : {} });
|
|
6725
7059
|
const fitPlacedText = (field, value, text2, box, size, minimum, path2, explicitAlignment) => {
|
|
6726
7060
|
const style = styleFor(field, path2), rich = (field === "text" || headings.has(field)) && Array.isArray(value);
|
|
6727
|
-
|
|
7061
|
+
const balance = field === "title" || field === "subtitle", textOptions = balance ? { ...richOptions(style), balance } : richOptions(style);
|
|
7062
|
+
if (!options.textMeasurement?.outlineBounds) return rich ? fitRichText(value, box, size, minimum, textOptions) : fitText(text2, box, size, minimum, textWidthMeasurer(style, options.textMeasurement), textDirection, balance);
|
|
6728
7063
|
const alignment = explicitAlignment ?? alignmentFor(field);
|
|
6729
|
-
const richLayout = rich ? richTextLayouter(value, box, size,
|
|
7064
|
+
const richLayout = rich ? richTextLayouter(value, box, size, textOptions, minimum) : void 0;
|
|
6730
7065
|
const measure = textWidthMeasurer(style, options.textMeasurement), floor = snapFontSizeUp(rich ? richMinimum(value, size, minimum) : minimum), start = Math.max(size, floor);
|
|
6731
7066
|
for (let trial = 0; trial <= 64; trial++) {
|
|
6732
7067
|
const raw = start - trial * scale2, last = trial === 64 || raw <= floor, fontSize = last ? floor : gridFontSize(raw, floor);
|
|
6733
|
-
const fit = richLayout ? richLayout(fontSize) : fitText(text2, box, fontSize, fontSize, measure, textDirection);
|
|
7068
|
+
const fit = richLayout ? richLayout(fontSize) : fitText(text2, box, fontSize, fontSize, measure, textDirection, balance);
|
|
6734
7069
|
const richLines = "richLines" in fit ? fit.richLines : void 0;
|
|
6735
7070
|
const lines = richLines ? richLines.map((line2) => {
|
|
6736
7071
|
let outline = null;
|
|
@@ -6772,7 +7107,7 @@ function composeSlide(input, options = {}) {
|
|
|
6772
7107
|
}
|
|
6773
7108
|
throw new Error("Text placement did not evaluate its bounded floor trial.");
|
|
6774
7109
|
};
|
|
6775
|
-
const fitContent = (field, value, text2, box, size, minimum, path2, numbering) => field === "text" ? fitPlacedText(field, value, text2, box, size, minimum, path2) : field === "items" || field === "bullets" ? fitList(value, box, size, minimum, { ...richOptions(styleFor(field, path2)), ...numbering !== void 0 ? { numbering } : bulletImage ? { bulletImage } : {} }) : fitText(text2, box, size, minimum, widthFor(field, path2), field === "code" ? void 0 : textDirection);
|
|
7110
|
+
const fitContent = (field, value, text2, box, size, minimum, path2, numbering) => field === "text" ? fitPlacedText(field, value, text2, box, size, minimum, path2) : field === "items" || field === "bullets" ? fitList(value, box, size, minimum, { ...richOptions(styleFor(field, path2)), ...numbering !== void 0 ? { numbering } : bulletImage ? { bulletImage } : noListBullet ? { bullet: "none" } : {} }) : fitText(text2, box, size, minimum, widthFor(field, path2), field === "code" ? void 0 : textDirection);
|
|
6776
7111
|
const path = `slides.${options.slideIndex ?? 0}`;
|
|
6777
7112
|
const annotationFit = (value, box, requestedSize, minFontSize, fitPath, alignment) => fitPlacedText("text", value, annotationText(value), box, requestedSize, minFontSize, fitPath, alignment);
|
|
6778
7113
|
const annotationOptions = { scale: scale2, minFontSize: minSize, fit: annotationFit, textStyle: (fitPath) => styleFor("text", fitPath) };
|
|
@@ -6781,7 +7116,7 @@ function composeSlide(input, options = {}) {
|
|
|
6781
7116
|
const backgroundImage = resolveBackgroundImage(slide, options.presentation, options.themeBackground, width, height, path, mirrorSide, imageDiagnostics);
|
|
6782
7117
|
const regions = Object.keys(slide).filter((key) => regionParts(key)).sort();
|
|
6783
7118
|
const assets = record7(options.presentation).assets;
|
|
6784
|
-
const imageContext = (placement) => ({ fit: hints.imageFit, scale: scale2, mirrorSide, diagnostics: imageDiagnostics, assets, ...placement ? { placement } : {} });
|
|
7119
|
+
const imageContext = (placement, anchor) => ({ fit: hints.imageFit ?? (!placement && autoComposition() ? "contain" : void 0), scale: scale2, mirrorSide, diagnostics: imageDiagnostics, assets, ...placement ? { placement } : {}, ...anchor ? { anchor } : {} });
|
|
6785
7120
|
const area2 = { left: 0, top: 0, right: width, bottom: height };
|
|
6786
7121
|
const topImages = regions.length ? [] : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index) => !Array.isArray(record7(block).blocks) && record7(block).image !== void 0 ? [{ host: record7(block), hostPath: `${path}.blocks.${index}`, block: index }] : []) : slide.image !== void 0 ? [{ host: { type: "image", image: slide.image }, hostPath: path }] : [];
|
|
6787
7122
|
const placed = [], usedEdges = /* @__PURE__ */ new Set();
|
|
@@ -6823,8 +7158,9 @@ function composeSlide(input, options = {}) {
|
|
|
6823
7158
|
const flowBlocks = Array.isArray(slide.blocks) ? slide.blocks.filter((_, index) => !placedBlocks.has(index)) : slide.blocks;
|
|
6824
7159
|
const hasBodyPayload = regions.some((key) => !emptyHost(record7(slide[key]))) || !emptyPayload(flowBlocks) || fields.some((field) => !(placedRoot && field === "image") && !emptyPayload(slide[field]));
|
|
6825
7160
|
const useTemplate = template !== void 0 && !regions.length;
|
|
7161
|
+
const autoComposition = () => !hasLayoutRecord && !regions.length;
|
|
6826
7162
|
const isCover = !hasBodyPayload && (useTemplate || !hasLayoutRecord);
|
|
6827
|
-
|
|
7163
|
+
subtitleInGroup = !(useTemplate && template?.subtitle === true);
|
|
6828
7164
|
let logo;
|
|
6829
7165
|
if (isCover && options[LAYOUT_MASTER] !== true) {
|
|
6830
7166
|
const resolved = resolveLogo(options.presentation, slide, { shape: "full", onDark: options.darkBackground, slideIndex: options.slideIndex });
|
|
@@ -6839,7 +7175,7 @@ function composeSlide(input, options = {}) {
|
|
|
6839
7175
|
const headingItems = [];
|
|
6840
7176
|
for (const field of useTemplate ? [] : ["tag", "title", "subtitle"]) {
|
|
6841
7177
|
if (!slide[field] || Array.isArray(slide[field]) && !annotationText(slide[field])) continue;
|
|
6842
|
-
const requested = (field === "title" ? 54 : field === "tag" ? 16 :
|
|
7178
|
+
const requested = (field === "title" ? 54 : field === "tag" ? 16 : PROSE_NOMINAL_SIZE) * scale2;
|
|
6843
7179
|
const maxHeight = Math.max(height * (field === "title" ? 0.26 : field === "subtitle" ? 0.12 : 0.045), minSize * 1.22 + 2 * rasterPadding);
|
|
6844
7180
|
const box = { x: area2.left + padding, y, width: area2.right - area2.left - padding * 2, height: maxHeight };
|
|
6845
7181
|
const text2 = fitPlacedText(field, slide[field], annotationText(slide[field]), box, requested, minSize, `${path}.${field}`);
|
|
@@ -6916,6 +7252,8 @@ function composeSlide(input, options = {}) {
|
|
|
6916
7252
|
const regionsInReadingOrder = visualReadingOrder(regions.map((key) => ({ key, box: regionBox(regionParts(key), contentBox, gap) }))).map((entry) => entry.key);
|
|
6917
7253
|
const pending = regions.length ? regionsInReadingOrder.flatMap((key) => collect(record7(slide[key]), `${path}.${key}`).map((item) => ({ ...item, region: regionParts(key) }))) : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index) => placedBlocks.has(index) ? [] : collect(record7(block), `${path}.blocks.${index}`)) : collect(placedRoot ? { ...slide, image: void 0 } : slide, path);
|
|
6918
7254
|
const groups = [], flows = [];
|
|
7255
|
+
const peerSets = [];
|
|
7256
|
+
const range = (from, to) => Array.from({ length: to - from }, (_, index) => from + index);
|
|
6919
7257
|
const decisions = options.explain ? [] : void 0;
|
|
6920
7258
|
const inheritedSettings = (parent, own3 = {}) => ({
|
|
6921
7259
|
minFontSize: parent.minFontSize,
|
|
@@ -6932,6 +7270,11 @@ function composeSlide(input, options = {}) {
|
|
|
6932
7270
|
const frame = acceptedBox(box), padding2 = Math.min(12 * scale2, frame.width / 4, frame.height / 4);
|
|
6933
7271
|
return acceptedBox({ x: frame.x + padding2, y: frame.y + padding2, width: frame.width - 2 * padding2, height: frame.height - 2 * padding2 });
|
|
6934
7272
|
};
|
|
7273
|
+
let languageTag = null;
|
|
7274
|
+
const deckLanguage = () => {
|
|
7275
|
+
if (languageTag === null) languageTag = quoteLanguage(options.presentation, options.slideIndex);
|
|
7276
|
+
return languageTag;
|
|
7277
|
+
};
|
|
6935
7278
|
const measureQuote = (node, box, settings) => layoutQuote(node.value, acceptedBox(box), {
|
|
6936
7279
|
fontFamilies: options.fontFamilies,
|
|
6937
7280
|
textMeasurement: options.textMeasurement,
|
|
@@ -6939,7 +7282,8 @@ function composeSlide(input, options = {}) {
|
|
|
6939
7282
|
minFontSize: settings.minFontSize,
|
|
6940
7283
|
path: node.path,
|
|
6941
7284
|
direction: textDirection,
|
|
6942
|
-
...citationMarker ? { citationMarker } : {}
|
|
7285
|
+
...citationMarker ? { citationMarker } : {},
|
|
7286
|
+
...deckLanguage() !== void 0 ? { language: deckLanguage() } : {}
|
|
6943
7287
|
});
|
|
6944
7288
|
const measureCode = (node, box, settings) => layoutCode(node.value, acceptedBox(box), {
|
|
6945
7289
|
fontFamilies: options.fontFamilies,
|
|
@@ -6968,14 +7312,21 @@ function composeSlide(input, options = {}) {
|
|
|
6968
7312
|
direction: textDirection
|
|
6969
7313
|
});
|
|
6970
7314
|
const captionOf = (node, box) => node.caption !== void 0 && node.captionPath ? layoutCaption(node.caption, box, node.captionPath, annotationOptions) : void 0;
|
|
7315
|
+
const wholePictureAspect = (node) => {
|
|
7316
|
+
const host = node.host;
|
|
7317
|
+
if (node.field !== "image" || !host || !autoComposition() || host.aspectRatio !== void 0 || host.shape === "circle") return void 0;
|
|
7318
|
+
const fit = IMAGE_FITS.includes(host.fit) ? host.fit : hints.imageFit ?? "contain";
|
|
7319
|
+
return fit === "contain" ? intrinsicImageAspect(host.image, assets) : void 0;
|
|
7320
|
+
};
|
|
6971
7321
|
const leafScore = (node, box, settings, penalties) => {
|
|
6972
7322
|
box = payloadBox(box);
|
|
6973
7323
|
const captioned = captionOf(node, box);
|
|
6974
7324
|
if (captioned) box = captioned.mediaBox;
|
|
6975
7325
|
const text2 = contentText(node.field, node.value);
|
|
6976
|
-
|
|
7326
|
+
const proportions = Math.abs(Math.log(box.width / box.height / (wholePictureAspect(node) ?? 1.6)));
|
|
7327
|
+
let score = proportions + (captioned?.overflow ? 1e3 : 0);
|
|
6977
7328
|
if (penalties) {
|
|
6978
|
-
penalties.cellProportions +=
|
|
7329
|
+
penalties.cellProportions += proportions;
|
|
6979
7330
|
if (captioned?.overflow) penalties.textOverflow += 1e3;
|
|
6980
7331
|
}
|
|
6981
7332
|
if (node.field === "quote" || node.field === "code" || node.field === "metric" || node.field === "timeline") {
|
|
@@ -6987,8 +7338,9 @@ function composeSlide(input, options = {}) {
|
|
|
6987
7338
|
penalties.textOverflow += internal.overflow ? 1e3 : 0;
|
|
6988
7339
|
}
|
|
6989
7340
|
} else if (text2) {
|
|
6990
|
-
const
|
|
6991
|
-
const
|
|
7341
|
+
const prose = proseMeasure(node, box.width);
|
|
7342
|
+
const fit = fitContent(node.field, node.value, text2, { ...box, width: prose.width }, prose.size, snapFontSizeUp((settings.minFontSize ?? 16) * scale2), node.path, node.payload.numbering);
|
|
7343
|
+
const reduction = Math.max(0, snapFontSizeDown(prose.size) - fit.fontSize) / scale2;
|
|
6992
7344
|
score += reduction + (fit.overflow ? 1e3 : 0);
|
|
6993
7345
|
if (penalties) {
|
|
6994
7346
|
penalties.fontReduction += reduction;
|
|
@@ -7017,6 +7369,74 @@ function composeSlide(input, options = {}) {
|
|
|
7017
7369
|
const boxes = gridBoxes(slotCount, area3, cols, (own3.gap ?? 1 / 30) * Math.min(box.width, box.height), own3.weights ?? [], modeFor(own3) === "column");
|
|
7018
7370
|
return node.children.reduce((score, child, index) => score + scoreNode(child, boxes[index], own3, penalties), 0);
|
|
7019
7371
|
};
|
|
7372
|
+
const contentSized = /* @__PURE__ */ new WeakSet();
|
|
7373
|
+
const stackedBoxes = (nodes, area3, requestedGap, settings, cards = hasCards, anchor = "top") => {
|
|
7374
|
+
const between = Math.max(0, Math.min(requestedGap, area3.width / 2, area3.height / (nodes.length * 2)));
|
|
7375
|
+
const space = Math.max(0, area3.height - between * (nodes.length - 1)), share = space / nodes.length;
|
|
7376
|
+
const elastic = nodes.map((node) => !measuredNode(node)), stretch = elastic.filter(Boolean).length;
|
|
7377
|
+
const needs = nodes.map((node, index) => elastic[index] ? share : naturalHeight(node, area3.width, cards, void 0, settings));
|
|
7378
|
+
const floors = nodes.map((node, index) => elastic[index] ? share : naturalHeight(node, area3.width, cards, void 0, settings, true));
|
|
7379
|
+
let heights = shareHeights(needs, floors, space);
|
|
7380
|
+
const textual = nodes.every((node) => !node.children && node.caption === void 0 && (node.field === "text" || node.field === "items" || node.field === "bullets"));
|
|
7381
|
+
if (textual && nodes.length > 1 && needs.reduce((sum, size) => sum + size, 0) > space + 1e-6) {
|
|
7382
|
+
const floor = snapFontSizeUp((settings.minFontSize ?? 16) * scale2), start = Math.max(...nodes.map((node) => proseMeasure(node, area3.width).size));
|
|
7383
|
+
for (let size = start; ; size -= scale2) {
|
|
7384
|
+
const trial = Math.max(floor, snapFontSizeDown(size));
|
|
7385
|
+
const natural = nodes.map((node) => naturalHeight(node, area3.width, cards, void 0, settings, false, Math.min(trial, proseMeasure(node, area3.width).size)));
|
|
7386
|
+
if (natural.reduce((sum, height2) => sum + height2, 0) <= space + 1e-6) {
|
|
7387
|
+
heights = natural;
|
|
7388
|
+
break;
|
|
7389
|
+
}
|
|
7390
|
+
if (trial <= floor) break;
|
|
7391
|
+
}
|
|
7392
|
+
}
|
|
7393
|
+
if (stretch && heights.some((size, index) => elastic[index] && size < share - 1e-9)) {
|
|
7394
|
+
const measured = nodes.flatMap((_, index) => elastic[index] ? [] : [index]);
|
|
7395
|
+
const rest = shareHeights(measured.map((index) => needs[index]), measured.map((index) => floors[index]), space - stretch * share);
|
|
7396
|
+
heights = nodes.map((_, index) => elastic[index] ? share : rest[measured.indexOf(index)]);
|
|
7397
|
+
}
|
|
7398
|
+
const spare = space - heights.reduce((sum, size) => sum + size, 0);
|
|
7399
|
+
if (stretch && spare > 0) heights = heights.map((size, index) => elastic[index] ? size + spare / stretch : size);
|
|
7400
|
+
const used = heights.reduce((sum, size) => sum + size, 0) + between * (nodes.length - 1);
|
|
7401
|
+
nodes.forEach((node, index) => {
|
|
7402
|
+
if (!node.children && !elastic[index] && heights[index] >= needs[index] - 1e-6) contentSized.add(node);
|
|
7403
|
+
});
|
|
7404
|
+
let y2 = area3.y + Math.max(0, anchor === "middle" ? (area3.height - used) / 2 : anchor === "bottom" ? area3.height - used : 0);
|
|
7405
|
+
return heights.map((size) => {
|
|
7406
|
+
const box = { x: area3.x, y: y2, width: area3.width, height: size };
|
|
7407
|
+
y2 += size + between;
|
|
7408
|
+
return box;
|
|
7409
|
+
});
|
|
7410
|
+
};
|
|
7411
|
+
const WEIGHTED_DEMAND_RATIO = 2.5, WEIGHTED_SHARES = [0.55, 0.6, 0.65, 0.7];
|
|
7412
|
+
const autoRowWeights = (nodes, count, cols, area3, rowGap, settings) => {
|
|
7413
|
+
if (!autoComposition() || settings.weights?.length || count < 2 || count > 3 || cols !== count || nodes.length !== count) return void 0;
|
|
7414
|
+
const equal = gridGeometry(count, area3, cols, rowGap, [], false).boxes;
|
|
7415
|
+
const wholeWidths = nodes.map((node, index) => {
|
|
7416
|
+
const aspect = node.caption === void 0 ? wholePictureAspect(node) : void 0;
|
|
7417
|
+
return aspect === void 0 ? void 0 : Math.min(equal[index].width, equal[index].height * aspect);
|
|
7418
|
+
});
|
|
7419
|
+
const media = wholeWidths.flatMap((width2, index) => width2 !== void 0 && width2 < equal[index].width - scale2 ? [index] : []);
|
|
7420
|
+
const others = nodes.flatMap((_, index) => wholeWidths[index] === void 0 ? [index] : []);
|
|
7421
|
+
if (media.length && others.length) {
|
|
7422
|
+
const freed = media.reduce((sum, index) => sum + equal[index].width - wholeWidths[index], 0);
|
|
7423
|
+
return nodes.map((_, index) => media.includes(index) ? wholeWidths[index] : equal[index].width + freed / others.length);
|
|
7424
|
+
}
|
|
7425
|
+
const prose = (node) => !node.children && node.caption === void 0 && (node.field === "text" || node.field === "items" || node.field === "bullets");
|
|
7426
|
+
if (count !== 2 || !nodes.every(prose)) return void 0;
|
|
7427
|
+
const need = (node, width2) => naturalHeight(node, width2, hasCards, void 0, settings);
|
|
7428
|
+
const heights = nodes.map((node, index) => need(node, equal[index].width));
|
|
7429
|
+
const long = heights[0] >= heights[1] ? 0 : 1, short = 1 - long;
|
|
7430
|
+
if (heights[long] < WEIGHTED_DEMAND_RATIO * heights[short]) return void 0;
|
|
7431
|
+
const total = equal[0].width + equal[1].width, line2 = contentNominalSize(nodes[short].field) * scale2 * 1.3;
|
|
7432
|
+
let best;
|
|
7433
|
+
for (const share of WEIGHTED_SHARES) {
|
|
7434
|
+
const longHeight = need(nodes[long], total * share), shortHeight = need(nodes[short], total * (1 - share));
|
|
7435
|
+
if (shortHeight > heights[short] + line2 || longHeight > heights[long] - line2 * 0.5) continue;
|
|
7436
|
+
if (!best || longHeight < best.height - 1e-6) best = { share, height: longHeight };
|
|
7437
|
+
}
|
|
7438
|
+
return best ? long === 0 ? [best.share, 1 - best.share] : [1 - best.share, best.share] : void 0;
|
|
7439
|
+
};
|
|
7020
7440
|
const arrange = (nodes, area3, settings, reserved2 = 0, gapOverride, containerPath = path, recorded = true) => {
|
|
7021
7441
|
const count = Math.max(nodes.length, reserved2);
|
|
7022
7442
|
if (!count) return;
|
|
@@ -7024,7 +7444,12 @@ function composeSlide(input, options = {}) {
|
|
|
7024
7444
|
const actualGap = gapOverride ?? (settings === rootSettings ? gap : localGap);
|
|
7025
7445
|
let cols = defaultColumns(count, area3, settings);
|
|
7026
7446
|
const hasRegions = nodes.some((node) => node.region);
|
|
7447
|
+
if (!hasRegions && (mode === "auto" || nodes.length === 1)) for (const node of nodes) {
|
|
7448
|
+
node.auto = true;
|
|
7449
|
+
node.lone = nodes.length === 1 && reserved2 === 0;
|
|
7450
|
+
}
|
|
7027
7451
|
const candidates = decisions && recorded ? [] : void 0;
|
|
7452
|
+
const stacks = !hasRegions && count === nodes.length && count > 1 && !(mode === "column" && settings.weights?.length);
|
|
7028
7453
|
if (mode === "auto" && !hasRegions) {
|
|
7029
7454
|
let best = Infinity;
|
|
7030
7455
|
for (let candidate = 1; candidate <= Math.min(count, settings.columns ?? 6); candidate++) {
|
|
@@ -7046,14 +7471,24 @@ function composeSlide(input, options = {}) {
|
|
|
7046
7471
|
...hasRegions ? {} : { selectedColumns: cols },
|
|
7047
7472
|
candidates: candidates ?? []
|
|
7048
7473
|
});
|
|
7049
|
-
const grid = gridGeometry(count, area3, cols, actualGap, settings.weights ?? [], mode === "column");
|
|
7474
|
+
const grid = gridGeometry(count, area3, cols, actualGap, (mode === "auto" && !hasRegions ? autoRowWeights(nodes, count, cols, area3, actualGap, settings) : void 0) ?? settings.weights ?? [], mode === "column");
|
|
7475
|
+
if (cols === 1 && stacks) {
|
|
7476
|
+
grid.boxes = stackedBoxes(nodes, area3, actualGap, settings);
|
|
7477
|
+
grid.rows = grid.boxes.map((box) => ({ offset: box.y - area3.y, size: box.height }));
|
|
7478
|
+
}
|
|
7050
7479
|
const mirrored = (box) => rtl ? { ...box, x: area3.x + area3.width - (box.x - area3.x) - box.width } : box;
|
|
7051
7480
|
const boxes = grid.boxes.map(mirrored);
|
|
7052
7481
|
if (recorded && !hasRegions) flows.push({ path: containerPath, box: { ...area3 }, composition: { ...settings }, columns: rtl ? grid.columns.map((track) => ({ offset: area3.width - track.offset - track.size, size: track.size })) : grid.columns, rows: grid.rows, gap: grid.gap, itemCount: nodes.length, slotCount: count });
|
|
7482
|
+
const rowItems = /* @__PURE__ */ new Map(), stack = [];
|
|
7053
7483
|
nodes.forEach((node, index) => {
|
|
7054
7484
|
const box = node.region ? mirrored(regionBox(node.region, area3, actualGap)) : boxes[index];
|
|
7485
|
+
const first = items.length;
|
|
7055
7486
|
placeNode(node, box, settings);
|
|
7487
|
+
if (!hasRegions && cols > 1 && !node.children) rowItems.set(Math.floor(index / cols), [...rowItems.get(Math.floor(index / cols)) ?? [], ...range(first, items.length)]);
|
|
7488
|
+
else if (!hasRegions && cols === 1 && stacks && !node.children) stack.push(...range(first, items.length));
|
|
7056
7489
|
});
|
|
7490
|
+
for (const set2 of rowItems.values()) peerSets.push(set2);
|
|
7491
|
+
if (stack.length > 1) peerSets.push(stack);
|
|
7057
7492
|
};
|
|
7058
7493
|
let regionTag, templateCell = false;
|
|
7059
7494
|
const composeChart = (node, box, settings) => {
|
|
@@ -7061,7 +7496,15 @@ function composeSlide(input, options = {}) {
|
|
|
7061
7496
|
const valueAxis = chartValueAxis(node.value, resolved, { width: box.width, height: box.height, scale: scale2, minFontSize: settings.minFontSize });
|
|
7062
7497
|
return valueAxis ? { valueAxis } : void 0;
|
|
7063
7498
|
};
|
|
7064
|
-
const
|
|
7499
|
+
const VIDEO_ASPECT = 16 / 9, CHART_MAX_ASPECT_RATIO = 3 / 4;
|
|
7500
|
+
const settleCaption = (caption, frame, anchor) => {
|
|
7501
|
+
if (caption.position === "above" || anchor !== "top") return;
|
|
7502
|
+
const target = round2(frame.y + frame.height + caption.fontSize * 0.4), dy = target - caption.box.y;
|
|
7503
|
+
if (dy >= -0.01) return;
|
|
7504
|
+
caption.box = { ...caption.box, y: target };
|
|
7505
|
+
caption.fit = translateTextFit(caption.fit, dy);
|
|
7506
|
+
};
|
|
7507
|
+
const placeNode = (node, box, settings, cards = hasCards, listColumns, metricReferenceHeight, anchor = "top") => {
|
|
7065
7508
|
if (node.children) {
|
|
7066
7509
|
const own3 = inheritedSettings(settings, node.composition), inner = inset(box, own3);
|
|
7067
7510
|
if (!node.synthetic) groups.push({ path: node.path, box, contentBox: inner, composition: own3 });
|
|
@@ -7083,8 +7526,24 @@ function composeSlide(input, options = {}) {
|
|
|
7083
7526
|
const timelineLayout = node.field === "timeline" ? measureTimeline(node, box, settings) : void 0;
|
|
7084
7527
|
const internal = quoteLayout ?? codeLayout ?? metricLayout ?? timelineLayout, body = internal?.parts.find((part) => part.role === "body" || part.role === "value");
|
|
7085
7528
|
const columns2 = textValue !== void 0 && !internal ? listColumnsFor(node, box, settings, listColumns) : void 0;
|
|
7086
|
-
const
|
|
7087
|
-
const
|
|
7529
|
+
const floorSize = snapFontSizeUp((settings.minFontSize ?? 16) * scale2);
|
|
7530
|
+
const prose = textValue !== void 0 && !internal ? proseMeasure(node, box.width) : void 0, wholeBox = box;
|
|
7531
|
+
if (prose && prose.width < box.width - 0.5) {
|
|
7532
|
+
const side = alignmentFor(node.field), atEnd = rtl ? side === "left" : side === "right";
|
|
7533
|
+
box = { ...box, x: side === "center" ? box.x + (box.width - prose.width) / 2 : atEnd ? box.x + box.width - prose.width : box.x, width: prose.width };
|
|
7534
|
+
}
|
|
7535
|
+
let text2 = internal ? body?.fit : columns2 ? columns2.length > 1 ? mergeListColumns(columns2) : columns2[0].text : textValue !== void 0 ? fitContent(node.field, node.value, textValue, box, prose?.size ?? contentNominalSize(node.field) * scale2, floorSize, node.path, node.payload.numbering) : void 0;
|
|
7536
|
+
if (prose && box !== wholeBox && text2 && textValue !== void 0) {
|
|
7537
|
+
const wide = fitContent(node.field, node.value, textValue, wholeBox, prose.size, floorSize, node.path, node.payload.numbering);
|
|
7538
|
+
if (wide.fontSize > text2.fontSize + 1e-9 || text2.overflow && !wide.overflow) {
|
|
7539
|
+
text2 = wide;
|
|
7540
|
+
box = wholeBox;
|
|
7541
|
+
}
|
|
7542
|
+
}
|
|
7543
|
+
if (node.field === "video") box = roundBox(containedBox(box, VIDEO_ASPECT, anchor));
|
|
7544
|
+
else if (node.field === "chart" && !templateCell && modeFor(settings) === "auto" && box.height > box.width * CHART_MAX_ASPECT_RATIO) box = roundBox({ ...box, height: box.width * CHART_MAX_ASPECT_RATIO });
|
|
7545
|
+
const image = node.field === "image" ? composeImage(node.host ?? {}, node.hostPath ?? node.path, box, box, imageContext(void 0, anchor)) : void 0;
|
|
7546
|
+
if (caption) settleCaption(caption, image?.box ?? box, anchor);
|
|
7088
7547
|
const chart = node.field === "chart" ? composeChart(node, box, settings) : void 0;
|
|
7089
7548
|
items.push({
|
|
7090
7549
|
path: node.path,
|
|
@@ -7092,7 +7551,7 @@ function composeSlide(input, options = {}) {
|
|
|
7092
7551
|
type: node.type,
|
|
7093
7552
|
value: node.value,
|
|
7094
7553
|
payload: node.payload,
|
|
7095
|
-
box: internal ? acceptedBox(box) : box,
|
|
7554
|
+
box: codeLayout && !codeLayout.overflow ? { ...acceptedBox(box), height: Math.min(acceptedBox(box).height, round2(codeLayout.bounds.height)) } : internal ? acceptedBox(box) : box,
|
|
7096
7555
|
...image ? { image } : {},
|
|
7097
7556
|
...chart ? { chart } : {},
|
|
7098
7557
|
...frameBox ? { frameBox } : {},
|
|
@@ -7109,7 +7568,7 @@ function composeSlide(input, options = {}) {
|
|
|
7109
7568
|
...regionTag !== void 0 ? { region: regionTag } : {},
|
|
7110
7569
|
...columns2 && columns2.length > 1 ? { listColumns: columns2 } : {}
|
|
7111
7570
|
});
|
|
7112
|
-
if (box.width < 100 * scale2 || !templateCell && box.height < 60 * scale2) diagnostics.push({ code: "small-cell", path: node.path, message: "Content cell is too small for comfortable reading; use fewer blocks or a different composition." });
|
|
7571
|
+
if (box.width < 100 * scale2 || !templateCell && !contentSized.has(node) && box.height < 60 * scale2) diagnostics.push({ code: "small-cell", path: node.path, message: "Content cell is too small for comfortable reading; use fewer blocks or a different composition." });
|
|
7113
7572
|
};
|
|
7114
7573
|
const listColumnsFor = (node, box, settings, regionMode) => {
|
|
7115
7574
|
if (node.field !== "items" && node.field !== "bullets") return void 0;
|
|
@@ -7120,7 +7579,7 @@ function composeSlide(input, options = {}) {
|
|
|
7120
7579
|
if (mode === void 0 || mode === 1) return void 0;
|
|
7121
7580
|
const start = contentNominalSize(node.field) * scale2, floor = snapFontSizeUp((settings.minFontSize ?? 16) * scale2);
|
|
7122
7581
|
const numbering = node.payload.numbering;
|
|
7123
|
-
const listOptions = { ...richOptions(styleFor(node.field, node.path)), ...numbering !== void 0 ? { numbering } : bulletImage ? { bulletImage } : {} };
|
|
7582
|
+
const listOptions = { ...richOptions(styleFor(node.field, node.path)), ...numbering !== void 0 ? { numbering } : bulletImage ? { bulletImage } : noListBullet ? { bullet: "none" } : {} };
|
|
7124
7583
|
const columnGap = (count2) => Math.min(gap, box.width / (count2 * 2));
|
|
7125
7584
|
const columnBoxes = (count2) => {
|
|
7126
7585
|
const between = columnGap(count2), columnWidth = (box.width - between * (count2 - 1)) / count2;
|
|
@@ -7156,7 +7615,7 @@ function composeSlide(input, options = {}) {
|
|
|
7156
7615
|
const size = Math.min(...shrunk.map((column) => column.text.fontSize));
|
|
7157
7616
|
return shrunk.map((column) => ({ ...column, text: renumber(fitList(chunk(column.start, column.end), column.box, size, size, listOptions), column.start) }));
|
|
7158
7617
|
};
|
|
7159
|
-
const LONG_LINES = 6, LONG_CODE_LINES = 12, startSize =
|
|
7618
|
+
const LONG_LINES = 6, LONG_CODE_LINES = 12, startSize = PROSE_NOMINAL_SIZE * scale2;
|
|
7160
7619
|
const estimatedLines = (value, cellWidth, size) => flatten(value).split("\n").reduce((sum, paragraph) => sum + Math.max(1, wrapText(paragraph, Math.max(1, cellWidth), size).length), 0);
|
|
7161
7620
|
const isLong = (node, cellWidth) => {
|
|
7162
7621
|
if (node.children) return node.children.some((child) => isLong(child, cellWidth));
|
|
@@ -7180,22 +7639,37 @@ function composeSlide(input, options = {}) {
|
|
|
7180
7639
|
if (node.field === "code") return String(typeof node.value === "string" ? node.value : record7(node.value).source ?? "").split("\n").length > LONG_CODE_LINES;
|
|
7181
7640
|
return false;
|
|
7182
7641
|
};
|
|
7183
|
-
const
|
|
7642
|
+
const proseMeasure = (node, cellWidth) => {
|
|
7643
|
+
const role = contentNominalSize(node.field) * scale2;
|
|
7644
|
+
if (node.field !== "text" || node.children || !node.auto) return { size: role, width: cellWidth };
|
|
7645
|
+
const linesAt = (width2, size) => estimatedLines(node.value, width2, size);
|
|
7646
|
+
const measureAt = (size) => Math.min(cellWidth, PROSE_MEASURE_CHARS * AVERAGE_CHARACTER_EM * size);
|
|
7647
|
+
const lead = LEAD_NOMINAL_SIZE * scale2;
|
|
7648
|
+
if (node.lone && lead > role && linesAt(measureAt(lead), lead) <= 2) return { size: lead, width: linesAt(cellWidth, lead) <= 1 ? cellWidth : measureAt(lead) };
|
|
7649
|
+
return { size: role, width: linesAt(cellWidth, role) <= 1 ? cellWidth : measureAt(role) };
|
|
7650
|
+
};
|
|
7651
|
+
const MEASURED_FIELDS = /* @__PURE__ */ new Set(["text", "items", "bullets", "quote", "metric", "code"]);
|
|
7652
|
+
const measuredNode = (node) => node.children ? node.children.length > 0 && node.children.every(measuredNode) : MEASURED_FIELDS.has(node.field);
|
|
7653
|
+
const naturalHeight = (node, cellWidth, cards, metricReferenceHeight, naturalSettings = composition, atFloor = false, sizeOverride) => {
|
|
7184
7654
|
const pad = cards ? 2 * Math.min(12 * scale2, cellWidth / 4) : 0, inner = Math.max(scale2, cellWidth - pad);
|
|
7185
|
-
if (node.children) return node.children.reduce((sum, child) => sum + naturalHeight(child, cellWidth, false), 0) + gap * Math.max(0, node.children.length - 1) + pad;
|
|
7655
|
+
if (node.children) return node.children.reduce((sum, child) => sum + naturalHeight(child, cellWidth, false, void 0, naturalSettings, atFloor), 0) + gap * Math.max(0, node.children.length - 1) + pad;
|
|
7656
|
+
const floorSize = snapFontSizeUp((naturalSettings.minFontSize ?? 16) * scale2);
|
|
7186
7657
|
let content;
|
|
7187
7658
|
if (node.field === "text" || node.field === "items" || node.field === "bullets") {
|
|
7188
|
-
const
|
|
7189
|
-
const fit = fitContent(node.field, node.value, contentText(node.field, node.value) ?? "", { x: 0, y: 0, width: inner, height: 1e6 }, size, size, node.path, node.payload.numbering);
|
|
7190
|
-
content = "height" in fit && typeof fit.height === "number" ? fit.height : fit.lines.length * fit.lineHeight;
|
|
7659
|
+
const prose = proseMeasure(node, inner), size = sizeOverride ?? (atFloor ? floorSize : prose.size);
|
|
7660
|
+
const fit = fitContent(node.field, node.value, contentText(node.field, node.value) ?? "", { x: 0, y: 0, width: atFloor || sizeOverride !== void 0 ? inner : prose.width, height: 1e6 }, size, size, node.path, node.payload.numbering);
|
|
7661
|
+
content = Math.max("height" in fit && typeof fit.height === "number" ? fit.height : fit.lines.length * fit.lineHeight, fit.placement?.height ?? 0);
|
|
7191
7662
|
} else if (node.field === "quote") content = measureQuote(node, { x: 0, y: 0, width: inner, height: 1e6 }, naturalSettings).bounds.height + 18;
|
|
7192
|
-
else if (node.field === "code")
|
|
7193
|
-
|
|
7663
|
+
else if (node.field === "code") {
|
|
7664
|
+
const code = measureCode(node, { x: 0, y: 0, width: inner, height: 1e6 }, naturalSettings), source = code.parts.find((part) => part.role === "body");
|
|
7665
|
+
content = source?.fit ? source.box.y + source.fit.lines.length * source.fit.lineHeight + 18 : 1e6;
|
|
7666
|
+
} else if (node.field === "metric") content = measureMetric(node, { x: 0, y: 0, width: inner, height: metricReferenceHeight === void 0 ? 1e6 : Math.max(scale2, metricReferenceHeight - pad) }, naturalSettings).bounds.height;
|
|
7194
7667
|
else if (node.field === "timeline") content = 170 * scale2;
|
|
7195
7668
|
else if (node.field === "table") {
|
|
7196
7669
|
const value = record7(node.value);
|
|
7197
7670
|
content = ((Array.isArray(value.rows) ? value.rows.length : 4) + 1) * 36 * scale2;
|
|
7198
7671
|
} else content = inner / 1.6;
|
|
7672
|
+
if (atFloor && !(node.field === "text" || node.field === "items" || node.field === "bullets")) content *= Math.min(1, floorSize / startSize);
|
|
7199
7673
|
return content + (node.caption !== void 0 ? 32 * scale2 : 0) + pad;
|
|
7200
7674
|
};
|
|
7201
7675
|
const templateRegions = [], headingAreas = [];
|
|
@@ -7210,6 +7684,13 @@ function composeSlide(input, options = {}) {
|
|
|
7210
7684
|
return parts.length === 1 ? parts[0] : { field: "blocks", type: "group", value: parts.map((part) => part.payload), path: bound.path, payload: {}, children: parts, composition: { mode: "column" }, synthetic: true };
|
|
7211
7685
|
};
|
|
7212
7686
|
const contents = new Map(binding.regions.map((entry) => [entry.name, [...entry.blocks, ...entry.overflow].map(unitOf)]));
|
|
7687
|
+
for (const region of plan2.regions) {
|
|
7688
|
+
const units = contents.get(region.name) ?? [];
|
|
7689
|
+
if (region.flow === "auto") for (const unit of units) {
|
|
7690
|
+
unit.auto = true;
|
|
7691
|
+
unit.lone = units.length === 1;
|
|
7692
|
+
}
|
|
7693
|
+
}
|
|
7213
7694
|
const BELOW = "(below)";
|
|
7214
7695
|
const belowUnits = binding.below.map(unitOf);
|
|
7215
7696
|
const belowRegion = { name: BELOW, accepts: [], role: "supporting", flow: "auto", max: belowUnits.length, bleed: false, listColumns: 1, anchor: "top", empty: "collapse" };
|
|
@@ -7248,7 +7729,7 @@ function composeSlide(input, options = {}) {
|
|
|
7248
7729
|
const list = [];
|
|
7249
7730
|
let top = y2;
|
|
7250
7731
|
for (const field of fields2) {
|
|
7251
|
-
const requested = (field === "title" ? 54 : field === "tag" ? 16 :
|
|
7732
|
+
const requested = (field === "title" ? 54 : field === "tag" ? 16 : PROSE_NOMINAL_SIZE) * scale2;
|
|
7252
7733
|
const maxHeight = Math.max(height * (field === "title" ? 0.26 : field === "subtitle" ? 0.12 : 0.045), minSize * 1.22 + 2 * rasterPadding);
|
|
7253
7734
|
const box = { x, y: top, width: areaWidth, height: maxHeight };
|
|
7254
7735
|
const text2 = fitPlacedText(field, slide[field], annotationText(slide[field]), box, requested, minSize, `${path}.${field}`);
|
|
@@ -7269,33 +7750,35 @@ function composeSlide(input, options = {}) {
|
|
|
7269
7750
|
const cellWidth = (cell.width - gap2 * (shape.columns - 1)) / shape.columns - (cards ? 2 * Math.min(12 * scale2, cell.width / 4) : 0);
|
|
7270
7751
|
return units.some((unit) => isLong(unit, cellWidth)) ? "column" : "grid";
|
|
7271
7752
|
};
|
|
7272
|
-
const regionNeed = (name, areaWidth) => {
|
|
7753
|
+
const regionNeed = (name, areaWidth, atFloor = false) => {
|
|
7273
7754
|
const units = unitsOf(name), region = name === BELOW ? belowRegion : regionOf.get(name);
|
|
7274
|
-
if (!units.length) return region.empty === "keep" ? 2 * startSize * 1.22 + (hasCards && !region.bleed ? 2 * Math.min(12 * scale2, areaWidth / 4) : 0) : 0;
|
|
7755
|
+
if (!units.length) return region.empty === "keep" && !atFloor ? 2 * (region.flow === "auto" ? LEAD_NOMINAL_SIZE * scale2 : startSize) * 1.22 + (hasCards && !region.bleed ? 2 * Math.min(12 * scale2, areaWidth / 4) : 0) : 0;
|
|
7275
7756
|
const shape = flowShape(arrangementOf(region, units, { width: areaWidth, height: areaWidth / 4 }), units.length, true);
|
|
7276
7757
|
const cellWidth = (areaWidth - gap2 * (shape.columns - 1)) / shape.columns, cards = hasCards && !region.bleed;
|
|
7277
7758
|
let total = 0, index = 0;
|
|
7278
7759
|
for (const count of shape.perRow) {
|
|
7279
7760
|
let row = 0;
|
|
7280
|
-
for (let k = 0; k < count; k++) row = Math.max(row, naturalHeight(units[index++], cellWidth, cards));
|
|
7761
|
+
for (let k = 0; k < count; k++) row = Math.max(row, naturalHeight(units[index++], cellWidth, cards, void 0, composition, atFloor));
|
|
7281
7762
|
total += row;
|
|
7282
7763
|
}
|
|
7283
7764
|
return total + gap2 * Math.max(0, shape.rows - 1);
|
|
7284
7765
|
};
|
|
7285
7766
|
const areaNeed = (name, rect) => name === "title" ? groupHeight(headingItemsAt(titleFields, 0, 0, spanWidth(rect))) : name === "subtitle" ? groupHeight(headingItemsAt(subtitleFields, 0, 0, spanWidth(rect))) : regionNeed(name, spanWidth(rect));
|
|
7286
7767
|
const demands = rowSizes.map((size, row) => {
|
|
7287
|
-
let need = 0, heading = false, below = false;
|
|
7768
|
+
let need = 0, floor = 0, heading = false, below = false;
|
|
7288
7769
|
for (const [name, rect] of rects) {
|
|
7289
|
-
|
|
7770
|
+
const autoSpan = size === "auto" && rect.rowSpan > 1 && rect.row === row && rowSizes.slice(rect.row, rect.row + rect.rowSpan).every((entry) => entry === "auto");
|
|
7771
|
+
if (size === "auto" ? rect.row !== row || rect.rowSpan !== 1 && !autoSpan : row < rect.row || row >= rect.row + rect.rowSpan) continue;
|
|
7290
7772
|
if (size !== "auto" && rect.rowSpan > 1 && rowSizes.slice(rect.row, rect.row + rect.rowSpan).some((entry) => entry === "auto")) continue;
|
|
7291
|
-
const value = areaNeed(name, rect) / rect.rowSpan;
|
|
7773
|
+
const value = areaNeed(name, rect) / (autoSpan ? 1 : rect.rowSpan);
|
|
7774
|
+
if (size === "auto" && name !== "title" && name !== "subtitle") floor = Math.max(floor, regionNeed(name, spanWidth(rect), true));
|
|
7292
7775
|
if (value > need) {
|
|
7293
7776
|
need = value;
|
|
7294
7777
|
heading = name === "title" || name === "subtitle";
|
|
7295
7778
|
below = name === BELOW;
|
|
7296
7779
|
}
|
|
7297
7780
|
}
|
|
7298
|
-
return { size, need, kind: heading ? "heading" : below ? "below" : "body" };
|
|
7781
|
+
return { size, need, ...size === "auto" && !heading ? { floor } : {}, kind: heading ? "heading" : below ? "below" : "body" };
|
|
7299
7782
|
});
|
|
7300
7783
|
const heights = allocateRows(demands, frame.height, gap2);
|
|
7301
7784
|
const rowY = [];
|
|
@@ -7303,9 +7786,11 @@ function composeSlide(input, options = {}) {
|
|
|
7303
7786
|
rowY.push(size > 0 || !heights.slice(0, row).some((above) => above > 0) ? y2 : y2 - gap2);
|
|
7304
7787
|
return size > 0 ? y2 + size + gap2 : y2;
|
|
7305
7788
|
}, 0);
|
|
7789
|
+
const stackUsed = heights.reduce((sum, size) => sum + size, 0) + gap2 * Math.max(0, heights.filter((size) => size > 0).length - 1);
|
|
7790
|
+
const stackShift = plan2.stack === void 0 ? 0 : Math.max(0, frame.height - stackUsed) * (plan2.stack === "middle" ? 0.5 : 1);
|
|
7306
7791
|
const logical = (rect) => {
|
|
7307
|
-
const last = rect.row + rect.rowSpan - 1, y2 = frame.y + rowY[rect.row];
|
|
7308
|
-
return { x: frame.x + columnX[rect.column], y: y2, width: spanWidth(rect), height: Math.max(0, frame.y + rowY[last] + heights[last] - y2) };
|
|
7792
|
+
const last = rect.row + rect.rowSpan - 1, y2 = frame.y + stackShift + rowY[rect.row];
|
|
7793
|
+
return { x: frame.x + columnX[rect.column], y: y2, width: spanWidth(rect), height: Math.max(0, frame.y + stackShift + rowY[last] + heights[last] - y2) };
|
|
7309
7794
|
};
|
|
7310
7795
|
const flip = hints.mirror === true !== rtl;
|
|
7311
7796
|
const physical = (cell) => flip ? { ...cell, x: frame.x + frame.width - (cell.x - frame.x) - cell.width } : cell;
|
|
@@ -7362,18 +7847,8 @@ function composeSlide(input, options = {}) {
|
|
|
7362
7847
|
const arrangement = arrangementOf(region, units, cell);
|
|
7363
7848
|
let boxes = flowCells(flowShape(arrangement, units.length, cell.width >= cell.height), cell, gap2).cells;
|
|
7364
7849
|
const referenceHeights = boxes.map((box) => box.height);
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
const used = naturals.reduce((a, b) => a + b, 0) + gap2 * (units.length - 1);
|
|
7368
|
-
if (used < cell.height) {
|
|
7369
|
-
let y2 = cell.y + (region.anchor === "middle" ? (cell.height - used) / 2 : cell.height - used);
|
|
7370
|
-
boxes = naturals.map((size) => {
|
|
7371
|
-
const next = { x: cell.x, y: y2, width: cell.width, height: size };
|
|
7372
|
-
y2 += size + gap2;
|
|
7373
|
-
return next;
|
|
7374
|
-
});
|
|
7375
|
-
}
|
|
7376
|
-
}
|
|
7850
|
+
const stacked = arrangement === "column" && !(units.length === 1 && region.anchor === "top");
|
|
7851
|
+
if (stacked) boxes = stackedBoxes(units, cell, gap2, settings, cards, region.anchor);
|
|
7377
7852
|
if ((arrangement === "grid" || arrangement === "row") && region.anchor !== "top") {
|
|
7378
7853
|
const naturals = boxes.map((box, index) => {
|
|
7379
7854
|
const unit = units[index];
|
|
@@ -7388,22 +7863,44 @@ function composeSlide(input, options = {}) {
|
|
|
7388
7863
|
});
|
|
7389
7864
|
}
|
|
7390
7865
|
if (rtl) boxes = boxes.map((box) => ({ ...box, x: cell.x + cell.width - (box.x - cell.x) - box.width }));
|
|
7866
|
+
const shape = flowShape(arrangement, units.length, cell.width >= cell.height), rowItems = shape.perRow.map(() => []);
|
|
7867
|
+
const rowOf = (index) => {
|
|
7868
|
+
let row = 0;
|
|
7869
|
+
for (let seen = shape.perRow[0] ?? 0; index >= seen; seen += shape.perRow[++row] ?? Infinity) ;
|
|
7870
|
+
return row;
|
|
7871
|
+
};
|
|
7872
|
+
const stack = [];
|
|
7391
7873
|
units.forEach((unit, index) => {
|
|
7392
|
-
|
|
7874
|
+
const first = items.length;
|
|
7875
|
+
placeNode(unit, boxes[index], settings, cards, region.listColumns, region.anchor === "top" || stacked ? void 0 : referenceHeights[index], region.anchor);
|
|
7876
|
+
if (!unit.children) {
|
|
7877
|
+
rowItems[rowOf(index)]?.push(...range(first, items.length));
|
|
7878
|
+
leafItems.push(...range(first, items.length));
|
|
7879
|
+
stack.push(...range(first, items.length));
|
|
7880
|
+
}
|
|
7393
7881
|
});
|
|
7882
|
+
if (arrangement !== "column") peerSets.push(...rowItems.filter((_, row) => (shape.perRow[row] ?? 0) > 1));
|
|
7883
|
+
else if (stacked && stack.length > 1) peerSets.push(stack);
|
|
7394
7884
|
return arrangement;
|
|
7395
7885
|
} finally {
|
|
7396
7886
|
regionTag = void 0;
|
|
7397
7887
|
templateCell = false;
|
|
7398
7888
|
}
|
|
7399
7889
|
};
|
|
7890
|
+
const bands = /* @__PURE__ */ new Map();
|
|
7891
|
+
let leafItems = [];
|
|
7400
7892
|
for (const region of plan2.regions) {
|
|
7401
7893
|
const units = unitsOf(region.name), bound = binding.regions.find((entry) => entry.name === region.name);
|
|
7402
7894
|
const rect = rects.get(region.name);
|
|
7403
7895
|
let cell = physical(logical(rect ?? ownRects.get(region.name)));
|
|
7404
7896
|
const areaBox = region.bleed && rect ? roundBox(cell) : void 0;
|
|
7405
7897
|
if (region.bleed && rect) cell = bleed(cell);
|
|
7898
|
+
leafItems = [];
|
|
7406
7899
|
const arrangement = units.length && rect ? placeRegion(region, units, cell) : void 0;
|
|
7900
|
+
if (arrangement && rect) {
|
|
7901
|
+
const band = `${rect.row}:${rect.rowSpan}:${region.role}`;
|
|
7902
|
+
bands.set(band, [...bands.get(band) ?? [], leafItems]);
|
|
7903
|
+
}
|
|
7407
7904
|
templateRegions.push({
|
|
7408
7905
|
name: region.name,
|
|
7409
7906
|
box: roundBox(cell),
|
|
@@ -7420,8 +7917,36 @@ function composeSlide(input, options = {}) {
|
|
|
7420
7917
|
...areaBox ? { areaBox } : {}
|
|
7421
7918
|
});
|
|
7422
7919
|
}
|
|
7920
|
+
for (const members of bands.values()) if (members.length > 1) peerSets.push(members.flat());
|
|
7423
7921
|
if (belowUnits.length) placeRegion(belowRegion, belowUnits, physical(logical(rects.get(BELOW))));
|
|
7424
7922
|
};
|
|
7923
|
+
const sharePeerSizes = () => {
|
|
7924
|
+
const parent = /* @__PURE__ */ new Map();
|
|
7925
|
+
const find = (index) => {
|
|
7926
|
+
let root = index;
|
|
7927
|
+
while (parent.has(root) && parent.get(root) !== root) root = parent.get(root);
|
|
7928
|
+
parent.set(index, root);
|
|
7929
|
+
return root;
|
|
7930
|
+
};
|
|
7931
|
+
for (const set2 of peerSets) for (const index of set2) parent.set(find(index), find(set2[0]));
|
|
7932
|
+
const kindOf = (item) => !item.text || item.quoteLayout || item.codeLayout || item.metricLayout || item.timelineLayout || item.listColumns ? void 0 : item.field === "text" ? "text" : item.field === "items" || item.field === "bullets" ? "list" : void 0;
|
|
7933
|
+
const sets = /* @__PURE__ */ new Map();
|
|
7934
|
+
for (const index of parent.keys()) {
|
|
7935
|
+
const item = items[index], kind2 = item && kindOf(item);
|
|
7936
|
+
if (kind2) sets.set(`${find(index)}:${kind2}`, [...sets.get(`${find(index)}:${kind2}`) ?? [], index]);
|
|
7937
|
+
}
|
|
7938
|
+
for (const members of sets.values()) {
|
|
7939
|
+
if (members.length < 2) continue;
|
|
7940
|
+
const size = Math.min(...members.map((index) => items[index].text.fontSize));
|
|
7941
|
+
for (const index of members) {
|
|
7942
|
+
const item = items[index];
|
|
7943
|
+
if (item.text.fontSize <= size + 1e-9) continue;
|
|
7944
|
+
const text2 = contentText(item.field, item.value) ?? "";
|
|
7945
|
+
const refit = fitContent(item.field, item.value, text2, item.box, size, snapFontSizeUp((item.composition.minFontSize ?? 16) * scale2), item.path, item.payload.numbering);
|
|
7946
|
+
if (!refit.overflow && Math.abs(refit.fontSize - size) < 1e-9) item.text = refit;
|
|
7947
|
+
}
|
|
7948
|
+
}
|
|
7949
|
+
};
|
|
7425
7950
|
const ownMode = record7(slide.composition).mode;
|
|
7426
7951
|
const direction = hints.contentDirection;
|
|
7427
7952
|
const directionMode = direction === "vertical" ? "column" : direction === "horizontal" ? "row" : "auto";
|
|
@@ -7437,6 +7962,7 @@ function composeSlide(input, options = {}) {
|
|
|
7437
7962
|
const support = { field: "blocks", type: "group", value: rest.map((node) => node.payload), path, payload: {}, children: rest, composition: {}, synthetic: true };
|
|
7438
7963
|
arrange(firstChart ? [primary, support] : [support, primary], contentBox, rootSettings, 0);
|
|
7439
7964
|
} else arrange(pending, contentBox, rootSettings, 0);
|
|
7965
|
+
sharePeerSizes();
|
|
7440
7966
|
if (listBullet?.value === "image" && !bulletImage && items.some((item) => (item.field === "items" || item.field === "bullets") && item.payload.numbering === void 0)) {
|
|
7441
7967
|
diagnostics.push({ code: "unresolved-content", path: listBullet.path, message: "Picture bullets (listBullet: image) need an organization logo (the primary organization, or the one design.logo names); the marker glyph is drawn instead." });
|
|
7442
7968
|
}
|
|
@@ -7499,4 +8025,4 @@ function resolveCanvasDimensions(input) {
|
|
|
7499
8025
|
return { width, height };
|
|
7500
8026
|
}
|
|
7501
8027
|
|
|
7502
|
-
export { AUTO_LAYOUT, CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CATALOG_GROUP_PATTERN, CATALOG_REFERENCE_PATTERN, CHART_HIGHLIGHT_MUTED_MIN_CONTRAST, CHART_HIGHLIGHT_MUTED_MIX, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CHART_SERIES_TIER_SIZE, CHART_SERIES_TINT_MIX, CHART_TEXT_PX, CHART_TYPES, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, CODE_HIGHLIGHT_LANGUAGES, CODE_HIGHLIGHT_MAX_LENGTH, CODE_PANEL_BACKGROUND, CODE_PANEL_FOREGROUND, CODE_SYNTAX_MIN_CONTRAST, DARK_BACKGROUND_LUMINANCE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, DESIGN_HINT_KEYS, ENGINE_DEFAULT_CHART_TYPES, ENGINE_DEFAULT_COLOR_SCHEME, ENGINE_DEFAULT_FONT_SCHEME, ENGINE_DEFAULT_THEME, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, FURNITURE_GAP, FURNITURE_IMAGE_SHARE, FURNITURE_ZONE_GUTTER, HEADING_AREAS, LANGUAGES, LAYOUT_BODY_KINDS, LOGO_SHAPES, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_REGION_BLOCKS, MAX_REGION_DEPTH, MAX_REGION_ENTRIES, MAX_ROMAN_VALUE, MAX_TEMPLATE_TRACKS, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, NEUTRAL_SHARES, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCatalogsOptionError, OPFCompositionError, OPFLayoutTemplateError, OPFUnresolvedReferenceError, OPFVariableError, PATTERN_PRESETS, PATTERN_PRESET_ALIASES, PATTERN_TILE_SIZE, PICTURE_BULLET_SCALE, PROMOTED_REGION_KEY, REGION_ANCHORS, REGION_FLOWS, REGION_KINDS, REGION_ROLES, RESERVED_REGION_NAMES, SLIDE_SCOPED_BUILTINS, SOCIAL_PLATFORMS, SURFACE_ALT_MIN_CONTRAST, SURFACE_ALT_MIX, THEME_DESIGN_KEYS, TIMELINE_OUTLINE_MIN_CONTRAST, TIMELINE_STATUSES, TIMELINE_TEXT_MIN_CONTRAST, VARIABLE_KINDS, allocateRows, annotationText, applyLuminance, bindRegions, blockKind, captionSettings, catalogGroupDeclared, catalogGroupSource, catalogKinds, catalogRecords, catalogReferenceSites, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, chartSeriesPalette, chartTextSize, chartValueAxis, checkCatalogsOption, citationMarkerText, clrMapAttributes, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForRoles, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, colorMapFor, composeLayoutAreas, composeSlide, datasetDiagnostics, defaultSlideBackground, dottedPath, embeddedCopy, fitImage, fitList, fitRichText, fitText, formatChartLabelNumber, formatChartLabelPercent, formatDataNumber, formatFurnitureDate, formatListNumber, formatVariableNumber, fromExcelNumberFormat, gridFlowShape, hasContentVariables, imageBackground, imageShape, inlineChartData, inlineDatasets, inlineTableData, instantiateForValidation, intrinsicImageAspect, intrinsicImageSize, isColorVariant, isDarkColor, isDatasetRef, isLayoutTemplate, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutEntries, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutRegion, layoutStructure, layoutTable, layoutTemplate, layoutTemplateIssues, layoutTimeline, layoutWatermark, listBuiltinVariables, listColumnBreaks, listNumbers, listVariables, maxIntervalsFor, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, niceScale, normalizeColorVariant, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, parseReference, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, placedImageBlocks, pointerPath, promotedRegionKeys, provenanceOf, readableSchemeColor, readingRows, recordReferenceSites, referencesSlide, regionAccepts, regionRoleRank, registeredCatalog, resolveCanvasDimensions, resolveChartColors, resolveChartData, resolveChartOptions, resolveCodeLanguage, resolveColorRef, resolveColorRoles, resolveDesignHints, resolveDesignRecords, resolveFontFamilies, resolveFontScheme, resolveLogo, resolveNumbering, resolvePatternPreset, resolveReference, resolveScriptFonts, resolveSlideDirection, resolveSlideVariables, resolveSocialProfile, resolveTableData, resolveTextStyle, resolveVariables, rootNodes, scriptFontRole, sliceNumberedItems, slideCitations, slideTokenSpans, snapFontSizeDown, snapFontSizeUp, stackCategoryValues, suggestChartNumberFix, surfaceAltColor, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, timelineMarkerShapes, timelineTextColor, toExcelNumberFormat, tokenizeCode, unresolvedReference, unusedDatasets, usesSlideBuiltin, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };
|
|
8028
|
+
export { ASCII_QUOTE_MARKS, AUTO_LAYOUT, CAPTIONABLE_FIELDS, CAPTION_FONT_RATIO, CAPTION_MAX_RATIO, CATALOG_GROUP_PATTERN, CATALOG_REFERENCE_PATTERN, CHART_HIGHLIGHT_MUTED_MIN_CONTRAST, CHART_HIGHLIGHT_MUTED_MIX, CHART_LEAD_MIN_CONTRAST, CHART_MAX_INTERVALS, CHART_MIN_TICK_SPACING_PX, CHART_SERIES_MIN_DIFFERENCE, CHART_SERIES_MIN_LIGHTNESS_STEP, CHART_SERIES_TIER_SIZE, CHART_SERIES_TINT_MIX, CHART_TEXT_FLOOR_PX, CHART_TEXT_PX, CHART_TYPES, CITATION_MARKER_RAISE, CITATION_MARKER_SCALE, CODE_HIGHLIGHT_LANGUAGES, CODE_HIGHLIGHT_MAX_LENGTH, CODE_NOMINAL_SIZE, CODE_PANEL_BACKGROUND, CODE_PANEL_FOREGROUND, CODE_SYNTAX_MIN_CONTRAST, DARK_BACKGROUND_LUMINANCE, DEFAULT_CHART_LABEL_SEPARATOR, DEFAULT_FURNITURE_DATE_FORMAT, DEFAULT_VARIABLE_DATE_FORMAT, DESIGN_HINT_KEYS, ENGINE_DEFAULT_CHART_TYPES, ENGINE_DEFAULT_COLOR_SCHEME, ENGINE_DEFAULT_FONT_SCHEME, ENGINE_DEFAULT_THEME, FONT_SIZE_GRID_PER_PX, FOOTNOTE_MAX_RATIO, FURNITURE_GAP, FURNITURE_IMAGE_SHARE, FURNITURE_ZONE_GUTTER, HEADING_AREAS, LANGUAGES, LAYOUT_BODY_KINDS, LEAD_NOMINAL_SIZE, LIST_NOMINAL_SIZE, LOGO_SHAPES, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_REGION_BLOCKS, MAX_REGION_DEPTH, MAX_REGION_ENTRIES, MAX_ROMAN_VALUE, MAX_TEMPLATE_TRACKS, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, METRIC_VALUE_MIN_CONTRAST, NEUTRAL_SHARES, NUMBERING_STYLES, NUMBERING_SUFFIXES, OPFCatalogsOptionError, OPFCompositionError, OPFLayoutTemplateError, OPFUnresolvedReferenceError, OPFVariableError, PATTERN_PRESETS, PATTERN_PRESET_ALIASES, PATTERN_TILE_SIZE, PICTURE_BULLET_SCALE, PROMOTED_REGION_KEY, PROSE_NOMINAL_SIZE, QUOTE_MARKS, QUOTE_NOMINAL_SIZE, QUOTE_SOURCE_SEPARATOR, REGION_ANCHORS, REGION_FLOWS, REGION_KINDS, REGION_ROLES, RESERVED_REGION_NAMES, SLIDE_SCOPED_BUILTINS, SOCIAL_PLATFORMS, SURFACE_ALT_MIN_CONTRAST, SURFACE_ALT_MIX, TABLE_NOMINAL_SIZE, THEME_DESIGN_KEYS, TIMELINE_OUTLINE_MIN_CONTRAST, TIMELINE_STATUSES, TIMELINE_TEXT_MIN_CONTRAST, VARIABLE_KINDS, allocateRows, annotationText, applyLuminance, bindRegions, blockKind, captionSettings, catalogGroupDeclared, catalogGroupSource, catalogKinds, catalogRecords, catalogReferenceSites, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartIntervalsFor, chartLabelText, chartLeadFromScheme, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, chartSeriesPalette, chartTextSize, chartValueAxis, checkCatalogsOption, citationMarkerText, clrMapAttributes, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForRoles, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, colorMapFor, composeLayoutAreas, composeSlide, datasetDiagnostics, defaultSlideBackground, dottedPath, embeddedCopy, fitImage, fitList, fitRichText, fitText, formatChartLabelNumber, formatChartLabelPercent, formatDataNumber, formatFurnitureDate, formatListNumber, formatVariableNumber, fromExcelNumberFormat, gridFlowShape, hasContentVariables, imageBackground, imageShape, inlineChartData, inlineDatasets, inlineTableData, instantiateForValidation, intrinsicImageAspect, intrinsicImageSize, isColorVariant, isDarkColor, isDatasetRef, isLayoutTemplate, isRecord, isTemplate, isWrappedInQuoteMarks, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutEntries, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutRegion, layoutStructure, layoutTable, layoutTemplate, layoutTemplateIssues, layoutTimeline, layoutWatermark, listBuiltinVariables, listColumnBreaks, listNumbers, listVariables, maxIntervalsFor, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, metricValueColor, niceScale, normalizeColorVariant, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, parseReference, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, placedImageBlocks, pointerPath, promotedRegionKeys, provenanceOf, quoteLanguage, quoteMarksFor, readableSchemeColor, readingRows, recordReferenceSites, referencesSlide, regionAccepts, regionRoleRank, registeredCatalog, resolveCanvasDimensions, resolveChartColors, resolveChartData, resolveChartOptions, resolveCodeLanguage, resolveColorRef, resolveColorRoles, resolveDesignHints, resolveDesignRecords, resolveFontFamilies, resolveFontScheme, resolveLogo, resolveNumbering, resolvePatternPreset, resolveReference, resolveScriptFonts, resolveSlideDirection, resolveSlideVariables, resolveSocialProfile, resolveTableData, resolveTextStyle, resolveVariables, rootNodes, scriptFontRole, shareHeights, sliceNumberedItems, slideCitations, slideTokenSpans, snapFontSizeDown, snapFontSizeUp, stackCategoryValues, suggestChartNumberFix, surfaceAltColor, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, timelineMarkerShapes, timelineTextColor, toExcelNumberFormat, tokenizeCode, unresolvedReference, unusedDatasets, unwrapQuoteMarks, usesSlideBuiltin, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };
|