@openpresentation/opf 0.20.5 → 0.22.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/dist/browser.js +16 -16
- package/dist/{chunk-2M7U4WL3.js → chunk-23MOKE4B.js} +292 -104
- package/dist/{chunk-TCBEF5OY.js → chunk-2SENTA2R.js} +1 -1
- package/dist/{chunk-7PQZDC2H.js → chunk-3T7MNRBY.js} +1 -1
- package/dist/{chunk-VFMHM2IL.js → chunk-3UAVON3O.js} +28 -2
- package/dist/{chunk-IDMQWS6O.js → chunk-7XNAMCGT.js} +6 -6
- package/dist/{chunk-URUNMZFO.js → chunk-BULGAKBY.js} +2 -2
- package/dist/{chunk-WD4W7KKK.js → chunk-DY7H4RG6.js} +54 -11
- package/dist/{chunk-V66KJA3H.js → chunk-KUNXFN7B.js} +1 -1
- package/dist/{chunk-52GKVP3I.js → chunk-MAJHCGOW.js} +22 -12
- package/dist/{chunk-OIGCC6VA.js → chunk-MG34DCDB.js} +2 -2
- package/dist/{chunk-5SQ6CIWR.js → chunk-MLMTXXM4.js} +5 -5
- package/dist/{chunk-Z75YB54S.js → chunk-SBWIZSPB.js} +5 -5
- package/dist/{chunk-TZ5IZETE.js → chunk-SPCONMIY.js} +1 -1
- package/dist/{chunk-XAYMPBNE.js → chunk-VKNFZEMG.js} +403 -189
- package/dist/{chunk-S4FR7ATF.js → chunk-X3PQMMAY.js} +1 -1
- package/dist/{chunk-YOLDSF7U.js → chunk-YSJRBRHB.js} +1 -1
- package/dist/{chunk-DYGYMBBW.js → chunk-YUIEWE5B.js} +2 -2
- package/dist/{composition-QtS1rnhv.d.ts → composition-CkHn6JrM.d.ts} +139 -5
- package/dist/composition.d.ts +1 -1
- package/dist/composition.js +1 -1
- package/dist/conversion-3TTBY7OY.js +19 -0
- package/dist/{conversion-Cqwu0Ds9.d.ts → conversion-DS4OiVls.d.ts} +6 -5
- package/dist/convert.d.ts +3 -3
- package/dist/convert.js +7 -7
- package/dist/data.d.ts +1 -1
- package/dist/data.js +2 -2
- package/dist/{deck-report-BdG5H3Qj.d.ts → deck-report-vnWmXBjq.d.ts} +2 -2
- package/dist/deck.d.ts +6 -6
- package/dist/deck.js +10 -10
- package/dist/diff.d.ts +1 -1
- package/dist/diff.js +5 -5
- package/dist/docs.js +18 -12
- package/dist/examples.d.ts +1 -1
- package/dist/{finding-DqgwzUmr.d.ts → finding-l9dlQ2NF.d.ts} +4 -0
- package/dist/format.js +2 -2
- package/dist/index.d.ts +21 -15
- package/dist/index.js +20 -20
- package/dist/markdown.d.ts +4 -4
- package/dist/markdown.js +7 -7
- package/dist/node-engine.d.ts +30 -9
- package/dist/node-engine.js +20 -20
- package/dist/{pagination-CAX6mHG6.d.ts → pagination-C4jzAtFy.d.ts} +2 -2
- package/dist/pagination.d.ts +2 -2
- package/dist/pagination.js +4 -4
- package/dist/patch.d.ts +1 -1
- package/dist/patch.js +4 -4
- package/dist/{presentation-BG4QCcdB.d.ts → presentation-fN6tORPZ.d.ts} +58 -8
- package/dist/repo-readme.js +1 -1
- package/dist/schemas.js +1 -1
- package/dist/spec/schemas/finding.schema.json +6 -1
- package/dist/spec/schemas/opf.schema.json +14 -2
- package/dist/types.d.ts +2 -2
- package/dist/{validation-types-DRaNnieo.d.ts → validation-types-B21fZfb2.d.ts} +3 -3
- package/dist/{validator-BJtXHJKh.d.ts → validator-Cflv4F9e.d.ts} +4 -10
- package/dist/validator.d.ts +5 -5
- package/dist/validator.js +3 -3
- package/dist/yaml.d.ts +4 -4
- package/dist/yaml.js +7 -7
- package/package.json +1 -1
- package/dist/conversion-DRCJIMWS.js +0 -19
|
@@ -1875,6 +1875,159 @@ function tableCellDisplayValue(cell, columnFormat2) {
|
|
|
1875
1875
|
return formatDataNumber(cell, columnFormat2);
|
|
1876
1876
|
}
|
|
1877
1877
|
|
|
1878
|
+
// src/chart-axis.ts
|
|
1879
|
+
var CHART_TEXT_PX = 20;
|
|
1880
|
+
function chartTextSize(geometry) {
|
|
1881
|
+
const { width, height, scale } = geometry;
|
|
1882
|
+
const minimum = geometry.minFontSize ?? 16;
|
|
1883
|
+
if (![width, height, scale].every(Number.isFinite) || width <= 0 || height <= 0 || scale <= 0) return Math.max(CHART_TEXT_PX, minimum);
|
|
1884
|
+
return Math.max(Math.floor(Math.min(CHART_TEXT_PX, height / scale / 18, width / scale / 30)), minimum);
|
|
1885
|
+
}
|
|
1886
|
+
function clean(value) {
|
|
1887
|
+
const rounded = Number(value.toPrecision(12));
|
|
1888
|
+
return Object.is(rounded, -0) ? 0 : rounded;
|
|
1889
|
+
}
|
|
1890
|
+
function scaleFrom(min, max, step) {
|
|
1891
|
+
const ticks = [];
|
|
1892
|
+
const count = Math.round((max - min) / step);
|
|
1893
|
+
for (let index = 0; index <= count; index++) ticks.push(clean(min + index * step));
|
|
1894
|
+
return { min, max, step, ticks };
|
|
1895
|
+
}
|
|
1896
|
+
function pickStep(min, max, limit, steps) {
|
|
1897
|
+
return steps.find((step) => Math.round((max - min) / step) <= limit) ?? max - min;
|
|
1898
|
+
}
|
|
1899
|
+
function niceScale(dataMin, dataMax, maxIntervals = 10, { percent = false } = {}) {
|
|
1900
|
+
const limit = Number.isFinite(maxIntervals) ? Math.max(1, Math.floor(maxIntervals)) : 10;
|
|
1901
|
+
if (percent) {
|
|
1902
|
+
const min = dataMin < -1e-9 ? -1 : 0;
|
|
1903
|
+
const max = dataMax > 1e-9 || min === 0 ? 1 : 0;
|
|
1904
|
+
return scaleFrom(min, max, pickStep(min, max, limit, [0.1, 0.2, 0.25, 0.5, 1]));
|
|
1905
|
+
}
|
|
1906
|
+
if (!Number.isFinite(dataMin) || !Number.isFinite(dataMax)) {
|
|
1907
|
+
dataMin = 0;
|
|
1908
|
+
dataMax = 1;
|
|
1909
|
+
}
|
|
1910
|
+
let lo = Math.min(dataMin, 0);
|
|
1911
|
+
let hi = Math.max(dataMax, 0);
|
|
1912
|
+
if (dataMin > 0 && dataMax - dataMin < dataMax / 6) lo = dataMin;
|
|
1913
|
+
if (dataMax < 0 && dataMax - dataMin < -dataMin / 6) hi = dataMax;
|
|
1914
|
+
if (hi === lo) {
|
|
1915
|
+
if (hi === 0) hi = 1;
|
|
1916
|
+
else if (hi > 0) lo = 0;
|
|
1917
|
+
else hi = 0;
|
|
1918
|
+
}
|
|
1919
|
+
const span = hi - lo;
|
|
1920
|
+
const top = hi > 0 ? hi + span / 20 : hi;
|
|
1921
|
+
const bottom = lo < 0 ? lo - span / 20 : lo > 0 ? Math.max(0, lo - span / 20) : lo;
|
|
1922
|
+
const raw = (top - bottom) / limit;
|
|
1923
|
+
if (!(raw > 0) || !Number.isFinite(raw)) return normalizedScale(dataMin, dataMax, limit);
|
|
1924
|
+
let exponent = Math.floor(Math.log10(raw)) - 1;
|
|
1925
|
+
for (; exponent <= 308; exponent++) {
|
|
1926
|
+
for (const mantissa of [1, 2, 5]) {
|
|
1927
|
+
const step = mantissa * 10 ** exponent;
|
|
1928
|
+
if (!(step > 0) || !Number.isFinite(step)) continue;
|
|
1929
|
+
const min = Math.floor(bottom / step + 1e-9) * step;
|
|
1930
|
+
const max = Math.ceil(top / step - 1e-9) * step;
|
|
1931
|
+
if (Number.isFinite(min) && Number.isFinite(max) && Math.round((max - min) / step) <= limit) return scaleFrom(clean(min), clean(max), step);
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
return normalizedScale(dataMin, dataMax, limit);
|
|
1935
|
+
}
|
|
1936
|
+
function normalizedScale(dataMin, dataMax, limit) {
|
|
1937
|
+
const magnitude = Math.max(Math.abs(dataMin), Math.abs(dataMax));
|
|
1938
|
+
const unit = 10 ** Math.floor(Math.log10(magnitude)) || Number.MIN_VALUE;
|
|
1939
|
+
const normalized = niceScale(dataMin / unit, dataMax / unit, limit);
|
|
1940
|
+
const restore = (value) => {
|
|
1941
|
+
const scaled = value * unit;
|
|
1942
|
+
return Number.isFinite(scaled) ? scaled : Math.sign(value) * Number.MAX_VALUE;
|
|
1943
|
+
};
|
|
1944
|
+
const min = Math.min(restore(normalized.min), dataMin);
|
|
1945
|
+
const max = Math.max(restore(normalized.max), dataMax);
|
|
1946
|
+
const ticks = [.../* @__PURE__ */ new Set([min, ...normalized.ticks.map(restore), max])].sort((a, b) => a - b);
|
|
1947
|
+
return { min, max, step: restore(normalized.step) || Number.MIN_VALUE, ticks };
|
|
1948
|
+
}
|
|
1949
|
+
function maxIntervalsFor(length, labelExtent) {
|
|
1950
|
+
return Math.max(1, Math.min(10, Math.floor(length / Math.max(1, labelExtent))));
|
|
1951
|
+
}
|
|
1952
|
+
var bar = (horizontal, grouping) => ({ kind: "bar", horizontal, grouping });
|
|
1953
|
+
var line = (grouping) => ({ kind: "line", horizontal: false, grouping });
|
|
1954
|
+
var area = (grouping) => ({ kind: "area", horizontal: false, grouping });
|
|
1955
|
+
var CATEGORY_CHARTS = {
|
|
1956
|
+
column: bar(false, "clustered"),
|
|
1957
|
+
"stacked-column": bar(false, "stacked"),
|
|
1958
|
+
"100pct-stacked-column": bar(false, "percentStacked"),
|
|
1959
|
+
bar: bar(true, "clustered"),
|
|
1960
|
+
"stacked-bar": bar(true, "stacked"),
|
|
1961
|
+
"100pct-stacked-bar": bar(true, "percentStacked"),
|
|
1962
|
+
line: line("standard"),
|
|
1963
|
+
"line-with-markers": line("standard"),
|
|
1964
|
+
"stacked-line": line("stacked"),
|
|
1965
|
+
"stacked-line-with-markers": line("stacked"),
|
|
1966
|
+
area: area("standard"),
|
|
1967
|
+
"stacked-area": area("stacked"),
|
|
1968
|
+
"100pct-stacked-area": area("percentStacked")
|
|
1969
|
+
};
|
|
1970
|
+
function stackCategoryValues(series, count, kind2, grouping, path = "chart") {
|
|
1971
|
+
const percent = grouping === "percentStacked";
|
|
1972
|
+
const stacked = grouping === "stacked" || percent;
|
|
1973
|
+
const fail = (aggregate) => new RangeError(`Cannot render ${path}: ${aggregate} exceeds the finite numeric range. Rescale the chart values before rendering.`);
|
|
1974
|
+
const totals = Array.from({ length: count }, (_, i) => series.reduce((sum, entry) => sum + Math.abs(entry.values[i] ?? 0), 0));
|
|
1975
|
+
if (percent && totals.some((total) => !Number.isFinite(total))) throw fail("percentage total");
|
|
1976
|
+
const positive2 = new Array(count).fill(0);
|
|
1977
|
+
const negative = new Array(count).fill(0);
|
|
1978
|
+
const running = new Array(count).fill(0);
|
|
1979
|
+
return series.map(
|
|
1980
|
+
(entry) => entry.values.map((raw, i) => {
|
|
1981
|
+
if (raw === null && kind2 !== "area") return null;
|
|
1982
|
+
let value = raw ?? 0;
|
|
1983
|
+
if (percent) value = totals[i] ? value / totals[i] : 0;
|
|
1984
|
+
if (!stacked) return { value, from: 0, to: value };
|
|
1985
|
+
if (kind2 === "bar") {
|
|
1986
|
+
const base = value >= 0 ? positive2 : negative;
|
|
1987
|
+
const from2 = base[i];
|
|
1988
|
+
base[i] += value;
|
|
1989
|
+
if (!Number.isFinite(base[i])) throw fail("stacked total");
|
|
1990
|
+
return { value, from: from2, to: base[i] };
|
|
1991
|
+
}
|
|
1992
|
+
const from = running[i];
|
|
1993
|
+
running[i] += value;
|
|
1994
|
+
if (!Number.isFinite(running[i])) throw fail("stacked total");
|
|
1995
|
+
return { value, from, to: running[i] };
|
|
1996
|
+
})
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
function chartValueAxis(chart, resolved, geometry) {
|
|
2000
|
+
const type = typeof chart === "object" && chart !== null ? chart.type : void 0;
|
|
2001
|
+
const id = typeof type === "string" ? type.trim().toLowerCase() : "";
|
|
2002
|
+
const spec = Object.hasOwn(CATEGORY_CHARTS, id) ? CATEGORY_CHARTS[id] : void 0;
|
|
2003
|
+
if (!spec || !resolved.ok || resolved.combo) return void 0;
|
|
2004
|
+
const { scale, width, height } = geometry;
|
|
2005
|
+
if (![width, height, scale].every(Number.isFinite) || width <= 0 || height <= 0 || scale <= 0) return void 0;
|
|
2006
|
+
const series = resolved.columns.slice(1).map((_, offset) => ({ values: resolved.rows.map((row) => chartNumber(row[offset + 1])) }));
|
|
2007
|
+
if (!series.length || !resolved.rows.length) return void 0;
|
|
2008
|
+
const percent = spec.grouping === "percentStacked";
|
|
2009
|
+
let stacks;
|
|
2010
|
+
try {
|
|
2011
|
+
stacks = stackCategoryValues(series, resolved.rows.length, spec.kind, spec.grouping);
|
|
2012
|
+
} catch {
|
|
2013
|
+
return void 0;
|
|
2014
|
+
}
|
|
2015
|
+
const stackedGrouping = spec.grouping === "stacked" || percent;
|
|
2016
|
+
const extents = stacks.flat().flatMap((point) => point === null ? [] : spec.kind === "line" || !stackedGrouping ? [point.to] : [point.from, point.to]);
|
|
2017
|
+
const anchor = spec.kind === "bar" || spec.kind === "area" ? [0] : [];
|
|
2018
|
+
const dataMin = extents.length ? Math.min(...extents, ...anchor) : 0;
|
|
2019
|
+
const dataMax = extents.length ? Math.max(...extents, ...anchor) : 1;
|
|
2020
|
+
const pad = 10 * scale;
|
|
2021
|
+
const fontPx = chartTextSize(geometry) * scale;
|
|
2022
|
+
const lineHeight = fontPx * 1.5;
|
|
2023
|
+
const options = resolveChartOptions(chart, chartOptionTarget(id));
|
|
2024
|
+
const legendBand = options.legend === "top" || options.legend === "bottom" ? lineHeight + pad : 0;
|
|
2025
|
+
const titleBand = options.axisTitles.category ? lineHeight : 0;
|
|
2026
|
+
const length = spec.horizontal ? width * 0.7 - 2 * pad - fontPx : height - 2 * pad - lineHeight * 1.5 - legendBand - titleBand;
|
|
2027
|
+
const fitted = niceScale(dataMin, dataMax, maxIntervalsFor(Math.max(1, length), spec.horizontal ? 4 * fontPx : lineHeight * 1.2), { percent });
|
|
2028
|
+
return { min: fitted.min, max: fitted.max, majorUnit: fitted.step, ...percent ? { percent: true } : {} };
|
|
2029
|
+
}
|
|
2030
|
+
|
|
1878
2031
|
// src/image-aspect.ts
|
|
1879
2032
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1880
2033
|
function sourceOf(value) {
|
|
@@ -2170,20 +2323,20 @@ function parse(layout) {
|
|
|
2170
2323
|
if (reserved.has(name)) region(`/regions/${pointerSegment(name)}`, `'${name}' is reserved and cannot name a region (reserved: ${RESERVED_REGION_NAMES.join(", ")})`);
|
|
2171
2324
|
else if (!bounds.has(name)) region(`/regions/${pointerSegment(name)}`, `region '${name}' has no area in areas`);
|
|
2172
2325
|
}
|
|
2173
|
-
for (const
|
|
2174
|
-
if (
|
|
2175
|
-
if (reserved.has(
|
|
2176
|
-
if (!Object.hasOwn(entries,
|
|
2326
|
+
for (const area2 of list) {
|
|
2327
|
+
if (area2.heading) continue;
|
|
2328
|
+
if (reserved.has(area2.name)) {
|
|
2329
|
+
if (!Object.hasOwn(entries, area2.name)) region("/areas", `'${area2.name}' is reserved and cannot name a body area (reserved: ${RESERVED_REGION_NAMES.join(", ")})`);
|
|
2177
2330
|
continue;
|
|
2178
2331
|
}
|
|
2179
|
-
if (!Object.hasOwn(entries,
|
|
2332
|
+
if (!Object.hasOwn(entries, area2.name)) region("/regions", `body area '${area2.name}' has no entry in regions`);
|
|
2180
2333
|
}
|
|
2181
2334
|
if (bounds.has("subtitle") && !bounds.has("title")) region("/areas", "a 'subtitle' area needs a 'title' area");
|
|
2182
2335
|
for (const [name, entry] of Object.entries(entries)) {
|
|
2183
2336
|
const raw = record4(entry);
|
|
2184
2337
|
if (raw.flow === "none" && raw.max !== void 0 && raw.max !== 1) region(`/regions/${pointerSegment(name)}/max`, `a region with flow "none" holds one block; max must be 1, not ${JSON.stringify(raw.max)}`);
|
|
2185
2338
|
}
|
|
2186
|
-
const regions = list.filter((
|
|
2339
|
+
const regions = list.filter((area2) => !area2.heading && !reserved.has(area2.name) && Object.hasOwn(entries, area2.name)).map((area2) => layoutRegion(area2.name, entries[area2.name]));
|
|
2187
2340
|
for (const entry of regions) if (!entry.accepts.length) region(`/regions/${pointerSegment(entry.name)}/accepts`, `region '${entry.name}' accepts no content kind`);
|
|
2188
2341
|
if (value.overflowRegion !== void 0 && !regions.some((entry) => entry.name === value.overflowRegion)) region("/overflowRegion", `overflowRegion ${JSON.stringify(value.overflowRegion)} is not a region of this layout`);
|
|
2189
2342
|
if (issues.length) return { issues };
|
|
@@ -3406,6 +3559,8 @@ function labWithLightness(l, a, b) {
|
|
|
3406
3559
|
function labDifference(a, b) {
|
|
3407
3560
|
return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
|
|
3408
3561
|
}
|
|
3562
|
+
var CHART_SERIES_TIER_SIZE = 6;
|
|
3563
|
+
var tierOf = (index) => Math.floor(index / CHART_SERIES_TIER_SIZE);
|
|
3409
3564
|
var CHART_SERIES_SHORTFALL_WEIGHT = 8;
|
|
3410
3565
|
function chartPaletteForFill(fill, palette) {
|
|
3411
3566
|
const opaqueFill = colorContrast(fill, fill) !== void 0;
|
|
@@ -3426,7 +3581,7 @@ function chartPaletteForFill(fill, palette) {
|
|
|
3426
3581
|
const baseLab = labOf(opaqueChannels(base));
|
|
3427
3582
|
const needs = palette.flatMap((_2, other) => {
|
|
3428
3583
|
const before = preferredLab[other], lab = placedLab[other];
|
|
3429
|
-
return other !== index && before && lab && placed[other] !== void 0 ? [{ lab, adjacent: Math.abs(other - index) === 1, wide: Math.min(labDifference(before, wanted), CHART_SERIES_MIN_DIFFERENCE), step: Math.min(Math.abs(before[0] - wanted[0]), CHART_SERIES_MIN_LIGHTNESS_STEP) }] : [];
|
|
3584
|
+
return other !== index && tierOf(other) <= tierOf(index) && before && lab && placed[other] !== void 0 ? [{ lab, adjacent: Math.abs(other - index) === 1, wide: Math.min(labDifference(before, wanted), CHART_SERIES_MIN_DIFFERENCE), step: Math.min(Math.abs(before[0] - wanted[0]), CHART_SERIES_MIN_LIGHTNESS_STEP) }] : [];
|
|
3430
3585
|
});
|
|
3431
3586
|
const shortfall = (candidate) => needs.reduce((worst, need) => {
|
|
3432
3587
|
const lightness = Math.abs(need.lab[0] - candidate[0]) - need.step, difference = labDifference(need.lab, candidate) - need.wide;
|
|
@@ -3452,6 +3607,28 @@ function chartPaletteForFill(fill, palette) {
|
|
|
3452
3607
|
});
|
|
3453
3608
|
return placed;
|
|
3454
3609
|
}
|
|
3610
|
+
var CHART_SERIES_TINT_MIX = 0.4;
|
|
3611
|
+
function chartSeriesPalette(colorScheme = {}, colors, context = {}) {
|
|
3612
|
+
const accents = [1, 2, 3, 4, 5, 6].map((number) => {
|
|
3613
|
+
const slot = `accent${number}`;
|
|
3614
|
+
return normalizeHexColor(colorScheme?.[slot]) ?? normalizeHexColor(ENGINE_DEFAULT_COLOR_SCHEME[slot]) ?? "#000000";
|
|
3615
|
+
});
|
|
3616
|
+
const palette = [...accents, ...accents.map((accent) => mixChannels(opaqueChannels(accent), [255, 255, 255], CHART_SERIES_TINT_MIX))];
|
|
3617
|
+
resolveChartColors(colors, colorScheme, context).forEach((color, index) => {
|
|
3618
|
+
if (color === void 0) return;
|
|
3619
|
+
while (palette.length < index) palette.push(palette[palette.length % 12]);
|
|
3620
|
+
palette[index] = color;
|
|
3621
|
+
});
|
|
3622
|
+
return palette;
|
|
3623
|
+
}
|
|
3624
|
+
function resolveChartColors(colors, colorScheme = {}, context = {}) {
|
|
3625
|
+
if (!Array.isArray(colors)) return [];
|
|
3626
|
+
return colors.map((entry) => {
|
|
3627
|
+
if (typeof entry !== "string") return void 0;
|
|
3628
|
+
const resolved = resolveColorRef(entry.trim(), { colorScheme, roles: context.roles, variables: context.variables, fallback: "" });
|
|
3629
|
+
return normalizeHexColor(resolved);
|
|
3630
|
+
});
|
|
3631
|
+
}
|
|
3455
3632
|
var CHART_HIGHLIGHT_MUTED_MIX = 0.3;
|
|
3456
3633
|
var CHART_HIGHLIGHT_MUTED_MIN_CONTRAST = 1.6;
|
|
3457
3634
|
var mixChannels = (from, to, amount) => hexOfChannels(from.map((channel, index) => channel + (to[index] - channel) * amount));
|
|
@@ -4258,10 +4435,10 @@ function metricTrendMark(layout, options) {
|
|
|
4258
4435
|
if (!part || !part.visible || !part.fit || part.fit.sourceLines.length === 0) return void 0;
|
|
4259
4436
|
const trend = part.text.trim();
|
|
4260
4437
|
if (!Object.hasOwn(METRIC_TREND_SHAPES, trend)) return void 0;
|
|
4261
|
-
const
|
|
4262
|
-
if (!origin ||
|
|
4438
|
+
const line2 = part.fit.sourceLines[0], origin = part.linePositions[0];
|
|
4439
|
+
if (!origin || line2.width <= 0) return void 0;
|
|
4263
4440
|
const size = part.fit.fontSize * 0.72, gap = part.fit.fontSize * 0.3, left = part.box.x, right = part.box.x + part.box.width;
|
|
4264
|
-
const after = origin.x +
|
|
4441
|
+
const after = origin.x + line2.width + gap, before = origin.x - gap - size;
|
|
4265
4442
|
const fitsAfter = after + size <= right + 0.01, fitsBefore = before >= left - 0.01;
|
|
4266
4443
|
const x = layout.alignment === "left" ? fitsAfter ? after : fitsBefore ? before : void 0 : fitsBefore ? before : fitsAfter ? after : void 0;
|
|
4267
4444
|
if (x === void 0) return void 0;
|
|
@@ -4321,7 +4498,7 @@ function codeHighlightLines(highlight, source) {
|
|
|
4321
4498
|
return;
|
|
4322
4499
|
}
|
|
4323
4500
|
if (end > lineCount) issues.push({ code: "code-highlight-out-of-range", index, message: `The highlight ${start === end ? `line ${start}` : `range [${start}, ${end}]`} is past the last line (the code has ${lineCount} ${lineCount === 1 ? "line" : "lines"}); lines beyond it are ignored.` });
|
|
4324
|
-
for (let
|
|
4501
|
+
for (let line2 = start; line2 <= Math.min(end, lineCount); line2++) marked.add(line2);
|
|
4325
4502
|
});
|
|
4326
4503
|
return { lineCount, lines: [...marked].sort((a, b) => a - b), issues };
|
|
4327
4504
|
}
|
|
@@ -4336,10 +4513,10 @@ function codeHighlightList(lines) {
|
|
|
4336
4513
|
return out;
|
|
4337
4514
|
}
|
|
4338
4515
|
function codeLineNumbers(sourceLines) {
|
|
4339
|
-
let
|
|
4516
|
+
let line2 = 1;
|
|
4340
4517
|
return sourceLines.map((entry) => {
|
|
4341
|
-
const number =
|
|
4342
|
-
if (entry.boundary === "hard")
|
|
4518
|
+
const number = line2;
|
|
4519
|
+
if (entry.boundary === "hard") line2++;
|
|
4343
4520
|
return number;
|
|
4344
4521
|
});
|
|
4345
4522
|
}
|
|
@@ -4359,7 +4536,7 @@ function codeHighlightSlice(highlight, source, start, end) {
|
|
|
4359
4536
|
if (!lines.length) return void 0;
|
|
4360
4537
|
const breaks = (text2) => (text2.match(/\r\n|\r|\n/g) ?? []).length;
|
|
4361
4538
|
const before = breaks(source.slice(0, start)), count = codeLineCount(source.slice(start, end));
|
|
4362
|
-
const kept = lines.filter((
|
|
4539
|
+
const kept = lines.filter((line2) => line2 > before && line2 <= before + count).map((line2) => line2 - before);
|
|
4363
4540
|
return kept.length ? codeHighlightList(kept) : void 0;
|
|
4364
4541
|
}
|
|
4365
4542
|
var CODE_HIGHLIGHT_DIM = 0.35;
|
|
@@ -4812,24 +4989,24 @@ function placeTextLines(lines, box, alignment = "left", rasterPadding = 0, direc
|
|
|
4812
4989
|
if (!Array.isArray(lines) || !box || ![box.x, box.y, box.width, box.height, rasterPadding].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || rasterPadding < 0 || !["left", "center", "right"].includes(alignment)) throw new RangeError("Text placement requires lines, finite positive dimensions, nonnegative padding and a valid alignment.");
|
|
4813
4990
|
const placed = [];
|
|
4814
4991
|
let shift = 0, bottom = box.y, height = 0, overflow = false;
|
|
4815
|
-
for (const [lineIndex,
|
|
4992
|
+
for (const [lineIndex, line2] of lines.entries()) {
|
|
4816
4993
|
const lineAlignment = physicalAlignment(alignment, directions?.[lineIndex]), factor = lineAlignment === "right" ? 1 : lineAlignment === "center" ? 0.5 : 0;
|
|
4817
|
-
if (!
|
|
4818
|
-
const ink =
|
|
4994
|
+
if (!line2 || ![line2.width, line2.y, line2.baseline, line2.height].every(Number.isFinite) || line2.width < 0 || line2.height <= 0 || line2.y < 0 || line2.baseline < line2.y) throw new RangeError("Text lines require finite coordinates, nonnegative advances and a baseline at or below their top.");
|
|
4995
|
+
const ink = line2.outline;
|
|
4819
4996
|
if (ink !== null && (!ink || ![ink.x, ink.y, ink.width, ink.height].every(Number.isFinite) || ink.width < 0 || ink.height < 0)) throw new RangeError("Text outlines must be null or finite coordinates with nonnegative dimensions.");
|
|
4820
|
-
let x = box.x + (box.width -
|
|
4997
|
+
let x = box.x + (box.width - line2.width) * factor;
|
|
4821
4998
|
if (ink) {
|
|
4822
4999
|
const low = box.x + rasterPadding - ink.x, high = box.x + box.width - rasterPadding - ink.x - ink.width;
|
|
4823
5000
|
if (low > high + 0.01) overflow = true;
|
|
4824
5001
|
else x = Math.max(low, Math.min(x, high));
|
|
4825
|
-
shift += Math.max(0, bottom + rasterPadding - (box.y +
|
|
5002
|
+
shift += Math.max(0, bottom + rasterPadding - (box.y + line2.baseline + shift + ink.y));
|
|
4826
5003
|
}
|
|
4827
|
-
const y = box.y +
|
|
5004
|
+
const y = box.y + line2.y + shift, baseline = box.y + line2.baseline + shift;
|
|
4828
5005
|
const outline = ink ? { ...ink, x: x + ink.x, y: baseline + ink.y } : null;
|
|
4829
5006
|
if (outline) bottom = outline.y + outline.height + rasterPadding;
|
|
4830
|
-
height = Math.max(height, y +
|
|
4831
|
-
if (
|
|
4832
|
-
placed.push({ x, y, baseline, height:
|
|
5007
|
+
height = Math.max(height, y + line2.height - box.y, outline ? bottom - box.y : 0);
|
|
5008
|
+
if (line2.width > box.width + 0.01 || height > box.height + 0.01) overflow = true;
|
|
5009
|
+
placed.push({ x, y, baseline, height: line2.height, width: line2.width, outline, ...directions ? { alignment: lineAlignment } : {} });
|
|
4833
5010
|
}
|
|
4834
5011
|
return { alignment, rasterPadding, lines: placed, height, overflow };
|
|
4835
5012
|
}
|
|
@@ -4839,11 +5016,11 @@ function translateTextFit(fit, dy) {
|
|
|
4839
5016
|
...fit,
|
|
4840
5017
|
placement: {
|
|
4841
5018
|
...fit.placement,
|
|
4842
|
-
lines: fit.placement.lines.map((
|
|
4843
|
-
...
|
|
4844
|
-
y:
|
|
4845
|
-
baseline:
|
|
4846
|
-
outline:
|
|
5019
|
+
lines: fit.placement.lines.map((line2) => ({
|
|
5020
|
+
...line2,
|
|
5021
|
+
y: line2.y + dy,
|
|
5022
|
+
baseline: line2.baseline + dy,
|
|
5023
|
+
outline: line2.outline ? { ...line2.outline, y: line2.outline.y + dy } : line2.outline
|
|
4847
5024
|
}))
|
|
4848
5025
|
}
|
|
4849
5026
|
};
|
|
@@ -5012,13 +5189,14 @@ function resolveSocialProfile(platform, value, owner = "organization") {
|
|
|
5012
5189
|
return { text: display(url), href: encodeURI(url), resolved: true };
|
|
5013
5190
|
}
|
|
5014
5191
|
var FURNITURE_GAP = 12;
|
|
5192
|
+
var FURNITURE_ZONE_GUTTER = 0.02;
|
|
5015
5193
|
var FURNITURE_IMAGE_SHARE = 0.4;
|
|
5016
5194
|
var SPACED_WORD_CHARACTER = /^[\p{L}\p{N}\p{M}]$/u;
|
|
5017
5195
|
var UNSPACED_SCRIPT = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Thai}\p{Script=Lao}\p{Script=Khmer}\p{Script=Myanmar}\p{Script=Tibetan}]/u;
|
|
5018
5196
|
function breaksInsideWord(text2, fit) {
|
|
5019
|
-
return fit.sourceLines.some((
|
|
5020
|
-
if (
|
|
5021
|
-
const before = [...text2.slice(0,
|
|
5197
|
+
return fit.sourceLines.some((line2) => {
|
|
5198
|
+
if (line2.boundary !== "soft" || line2.nextStart <= 0 || line2.nextStart >= text2.length) return false;
|
|
5199
|
+
const before = [...text2.slice(0, line2.nextStart)].at(-1) ?? "", after = [...text2.slice(line2.nextStart, line2.nextStart + 2)][0] ?? "";
|
|
5022
5200
|
return SPACED_WORD_CHARACTER.test(before) && SPACED_WORD_CHARACTER.test(after) && !UNSPACED_SCRIPT.test(before) && !UNSPACED_SCRIPT.test(after);
|
|
5023
5201
|
});
|
|
5024
5202
|
}
|
|
@@ -5048,9 +5226,25 @@ function layoutFurniture(input, options = {}) {
|
|
|
5048
5226
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new TypeError("Header/footer content must be an object or false.");
|
|
5049
5227
|
configured = true;
|
|
5050
5228
|
const zones = [];
|
|
5229
|
+
const inset = Math.min((settings.padding ?? 0.08) * Math.min(width, height), width * 0.25), gutter = width * FURNITURE_ZONE_GUTTER, column = (width - 2 * inset - 2 * gutter) / 3;
|
|
5230
|
+
const slotOf = (index) => furnitureRtl && index !== 1 ? 2 - index : index;
|
|
5231
|
+
const hasContent = (zone) => {
|
|
5232
|
+
const item = record8(record8(value)[zone]);
|
|
5233
|
+
return item.image !== void 0 || (typeof item.text === "string" ? item.text.trim() !== "" : item.text !== void 0) || item.socials === true || item.date === true || typeof item.date === "string";
|
|
5234
|
+
};
|
|
5235
|
+
const slots = ["left", "center", "right"].map((zone, index) => ({ slot: slotOf(index), occupied: hasContent(zone) })).sort((a, b) => a.slot - b.slot);
|
|
5236
|
+
const first = slots.findIndex((entry) => entry.occupied);
|
|
5237
|
+
const interval = (slot) => {
|
|
5238
|
+
const start = inset + slot * (column + gutter), end = start + column;
|
|
5239
|
+
if (!slots[slot].occupied || first < 0) return { x: start, width: column };
|
|
5240
|
+
const before = slots.slice(0, slot).map((entry) => entry.occupied).lastIndexOf(true), after = slots.findIndex((entry, i) => i > slot && entry.occupied);
|
|
5241
|
+
const left = before < 0 ? start - inset : (start - (inset + before * (column + gutter) + column) - gutter) / 2, right = after < 0 ? width - inset - end : (inset + after * (column + gutter) - end - gutter) / 2;
|
|
5242
|
+
const lend = slot === 1 ? Math.min(left, right) : void 0;
|
|
5243
|
+
return { x: start - (lend ?? left), width: column + (lend ?? left) + (lend ?? right) };
|
|
5244
|
+
};
|
|
5051
5245
|
for (const [index, zone] of ["left", "center", "right"].entries()) {
|
|
5052
5246
|
const side = furnitureRtl && zone !== "center" ? zone === "left" ? "right" : "left" : zone;
|
|
5053
|
-
const content = record8(record8(value)[zone]), path = `${root}.${zone}`, x
|
|
5247
|
+
const content = record8(record8(value)[zone]), path = `${root}.${zone}`, { x, width: zoneWidth } = interval(slotOf(index));
|
|
5054
5248
|
const pending = [];
|
|
5055
5249
|
const add = (field, text2, generated = false, sourcePath, extras = {}) => {
|
|
5056
5250
|
if (text2 === void 0) return;
|
|
@@ -5101,10 +5295,10 @@ function layoutFurniture(input, options = {}) {
|
|
|
5101
5295
|
}
|
|
5102
5296
|
const fitPart = (part, boxWidth) => {
|
|
5103
5297
|
const fit = fitText(part.text, { width: Math.max(Number.MIN_VALUE, boxWidth - (outlines ? 2 * padding : 0)), height: Number.MAX_VALUE }, size, size, textWidthMeasurer(part.style, options.textMeasurement));
|
|
5104
|
-
const ink = fit.sourceLines.map((
|
|
5298
|
+
const ink = fit.sourceLines.map((line2, index2) => {
|
|
5105
5299
|
let outline = null;
|
|
5106
5300
|
if (outlines) {
|
|
5107
|
-
for (const segment2 of
|
|
5301
|
+
for (const segment2 of line2.segments) if (segment2.kind === "text") {
|
|
5108
5302
|
const bounds = measureTextOutline(part.text.slice(segment2.start, segment2.end), size, part.style, options.textMeasurement);
|
|
5109
5303
|
if (bounds) {
|
|
5110
5304
|
const next = { ...bounds, x: bounds.x + segment2.x };
|
|
@@ -5119,7 +5313,7 @@ function layoutFurniture(input, options = {}) {
|
|
|
5119
5313
|
}
|
|
5120
5314
|
}
|
|
5121
5315
|
}
|
|
5122
|
-
return { width:
|
|
5316
|
+
return { width: line2.width, y: index2 * fit.lineHeight, baseline: size + index2 * fit.lineHeight, height: fit.lineHeight, outline };
|
|
5123
5317
|
});
|
|
5124
5318
|
const natural = outlines ? placeTextLines(ink, { x: 0, y: 0, width: boxWidth, height: Number.MAX_VALUE }, side, padding) : void 0;
|
|
5125
5319
|
const partHeight = natural?.height ?? fit.sourceLines.length * fit.lineHeight;
|
|
@@ -5127,7 +5321,7 @@ function layoutFurniture(input, options = {}) {
|
|
|
5127
5321
|
return { fit, ink, height: Math.max(scale, partHeight) };
|
|
5128
5322
|
};
|
|
5129
5323
|
const gap = FURNITURE_GAP * scale, gaps = gap * Math.max(0, pending.length - 1);
|
|
5130
|
-
const widths = pending.map((part) => part.type === "image" ? pending.length > 1 ? Math.min(part.width, zoneWidth * FURNITURE_IMAGE_SHARE) : part.width : pending.length === 1 ? zoneWidth : Math.max(scale, ...fitPart(part, 1e7).ink.map((
|
|
5324
|
+
const widths = pending.map((part) => part.type === "image" ? pending.length > 1 ? Math.min(part.width, zoneWidth * FURNITURE_IMAGE_SHARE) : part.width : pending.length === 1 ? zoneWidth : Math.max(scale, ...fitPart(part, 1e7).ink.map((line2) => Math.max(line2.width + (outlines ? 2 * padding : 0), line2.outline ? line2.outline.width + 2 * padding : 0))));
|
|
5131
5325
|
if (pending.length > 1 && widths.reduce((sum, entry) => sum + entry, 0) + gaps > zoneWidth + 0.01) {
|
|
5132
5326
|
const texts = pending.map((_, index2) => index2).filter((index2) => pending[index2].type === "text").sort((a, b) => widths[a] - widths[b]);
|
|
5133
5327
|
let remaining = zoneWidth - gaps - pending.reduce((sum, part, index2) => sum + (part.type === "image" ? widths[index2] : 0), 0), count = texts.length;
|
|
@@ -5170,10 +5364,10 @@ function layoutFurniture(input, options = {}) {
|
|
|
5170
5364
|
else footerTop = top;
|
|
5171
5365
|
for (const zone of zones) for (const part of zone) {
|
|
5172
5366
|
part.box.y += top;
|
|
5173
|
-
if (part.type === "text" && part.fit.placement) for (const
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
if (
|
|
5367
|
+
if (part.type === "text" && part.fit.placement) for (const line2 of part.fit.placement.lines) {
|
|
5368
|
+
line2.y += top;
|
|
5369
|
+
line2.baseline += top;
|
|
5370
|
+
if (line2.outline) line2.outline.y += top;
|
|
5177
5371
|
}
|
|
5178
5372
|
if (part.box.y + part.box.height > height - height * 0.04 + 0.01) error(part.path, "Repeated header/footer content extends beyond the usable slide height. Change its content or design before pagination.");
|
|
5179
5373
|
parts.push(part);
|
|
@@ -5262,11 +5456,11 @@ function layoutQuote(value, box, options = {}) {
|
|
|
5262
5456
|
const diagnostics = [], parts = [];
|
|
5263
5457
|
const report = (reason, diagnosticPath, roles, message) => diagnostics.push({ code: "text-overflow", reason, path: diagnosticPath, parts: roles, message });
|
|
5264
5458
|
const source = (sourcePath, text2, outputStart) => ({ path: sourcePath, start: 0, end: text2.length, outputStart, outputEnd: outputStart + text2.length });
|
|
5265
|
-
const add = (role, text2, sources,
|
|
5459
|
+
const add = (role, text2, sources, area2, fontSize, fontFamily, fontWeight, partPath, runs) => {
|
|
5266
5460
|
const requestedStyle = { fontFamily, fontWeight, italic: false, path: partPath };
|
|
5267
5461
|
const style = resolveTextStyle({ ...requestedStyle }, options.textMeasurement);
|
|
5268
5462
|
const requestedFontSize = gridFontSize(fontSize * scale, minimum);
|
|
5269
|
-
const part = { role, path: partPath, text: text2, sources, box:
|
|
5463
|
+
const part = { role, path: partPath, text: text2, sources, box: area2, requestedFontSize, minFontSize: minimum, requestedStyle, style, ...runs ? { runs } : {} };
|
|
5270
5464
|
parts.push(part);
|
|
5271
5465
|
return part;
|
|
5272
5466
|
};
|
|
@@ -5304,8 +5498,8 @@ function layoutQuote(value, box, options = {}) {
|
|
|
5304
5498
|
path
|
|
5305
5499
|
) : void 0;
|
|
5306
5500
|
const footerRequested = attribution?.requestedFontSize ?? gridFontSize(17 * scale, minimum);
|
|
5307
|
-
const usable2 = (
|
|
5308
|
-
const fit = (part,
|
|
5501
|
+
const usable2 = (area2) => [area2.x, area2.y, area2.width, area2.height].every(Number.isFinite) && area2.width > 0 && area2.height > 0;
|
|
5502
|
+
const fit = (part, area2, size = part.requestedFontSize, floor = minimum) => !usable2(area2) ? void 0 : part.runs ? fitRichText(part.runs, area2, size, floor, { style: part.style, textMeasurement: options.textMeasurement, ...options.citationMarker ? { citationMarker: options.citationMarker } : {}, ...options.direction ? { direction: options.direction } : {} }) : fitText(part.text, area2, size, floor, textWidthMeasurer(part.style, options.textMeasurement), options.direction);
|
|
5309
5503
|
const heightOf = (fit2) => "richLines" in fit2 ? fit2.height : fit2.lines.length * fit2.lineHeight;
|
|
5310
5504
|
const inner = { x: box.x + 18, y: box.y + 18, width: box.width - 36, height: box.height - 36 };
|
|
5311
5505
|
let photo, photoFits = true;
|
|
@@ -5369,13 +5563,13 @@ function layoutQuote(value, box, options = {}) {
|
|
|
5369
5563
|
}
|
|
5370
5564
|
if (hasPhoto && !photo) photoFits = false;
|
|
5371
5565
|
for (const part of parts) {
|
|
5372
|
-
const
|
|
5566
|
+
const area2 = part.box;
|
|
5373
5567
|
if (!part.fit) {
|
|
5374
5568
|
report("invalid-part-box", part.path, [part.role], `Quote ${part.role} has no usable space after its insets; increase the cell size or change the arrangement.`);
|
|
5375
5569
|
} else if (part.fit.overflow) {
|
|
5376
5570
|
report("text-fit", part.path, [part.role], `Quote ${part.role} exceeds its available space at the readability floor; increase its space or change the arrangement.`);
|
|
5377
5571
|
}
|
|
5378
|
-
if (usable2(
|
|
5572
|
+
if (usable2(area2) && (area2.x < box.x || area2.y < box.y || area2.x + area2.width > box.x + box.width + 0.01 || area2.y + area2.height > box.y + box.height + 0.01)) {
|
|
5379
5573
|
report("part-outside-cell", part.path, [part.role], `Quote ${part.role} extends outside its cell; increase the cell size or change the arrangement.`);
|
|
5380
5574
|
}
|
|
5381
5575
|
}
|
|
@@ -5388,7 +5582,7 @@ function layoutQuote(value, box, options = {}) {
|
|
|
5388
5582
|
if (diagnostics.length && options.overflow === "error") throw new OPFCompositionError(diagnostics);
|
|
5389
5583
|
const occupiedParts = parts.filter((part) => part.fit).map((part) => ({ ...part.box, height: part.fit.placement?.height ?? heightOf(part.fit) }));
|
|
5390
5584
|
if (photo) occupiedParts.push(photo.box);
|
|
5391
|
-
const bottom = Math.max(box.y, ...occupiedParts.map((
|
|
5585
|
+
const bottom = Math.max(box.y, ...occupiedParts.map((area2) => area2.y + area2.height));
|
|
5392
5586
|
const bounds = { x: box.x, y: box.y, width: box.width, height: bottom - box.y };
|
|
5393
5587
|
return { bounds, algorithm: "quote-flow-v1", textMeasurement: options.textMeasurement ? "provided" : "estimated", parts, ...photo ? { photo } : {}, diagnostics, overflow: diagnostics.length > 0 };
|
|
5394
5588
|
}
|
|
@@ -5434,12 +5628,12 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5434
5628
|
const primary = parts[0], metadata = parts.filter((part) => part !== primary && part.visible), unit = metadata.find((part) => part.role === "unit");
|
|
5435
5629
|
const metricDirection = options.direction === "rtl" ? paragraphDirection(["label", "description", "unit"].map((role) => parts.find((part) => part.role === role)?.text).find(Boolean) ?? primary.text, "rtl") : void 0;
|
|
5436
5630
|
const alignment = physicalAlignment(requestedAlignment, metricDirection);
|
|
5437
|
-
const usable2 = (
|
|
5631
|
+
const usable2 = (area2) => [area2.x, area2.y, area2.width, area2.height, area2.x + area2.width, area2.y + area2.height].every(Number.isFinite) && area2.width > 0 && area2.height > 0;
|
|
5438
5632
|
const occupied = (fit) => fit.placement?.height ?? fit.lines.length * fit.lineHeight;
|
|
5439
5633
|
const gap = 8 * scale, primaryGap = 12 * scale;
|
|
5440
|
-
const lineInk = (part, fit) => fit.sourceLines.map((
|
|
5634
|
+
const lineInk = (part, fit) => fit.sourceLines.map((line2, index) => {
|
|
5441
5635
|
let outline = null;
|
|
5442
|
-
for (const segment2 of
|
|
5636
|
+
for (const segment2 of line2.segments) {
|
|
5443
5637
|
if (segment2.kind !== "text") continue;
|
|
5444
5638
|
const bounds2 = measureTextOutline(part.text.slice(segment2.start, segment2.end), fit.fontSize, part.style, options.textMeasurement);
|
|
5445
5639
|
if (!bounds2) continue;
|
|
@@ -5453,7 +5647,7 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5453
5647
|
outline.height = bottom2 - outline.y;
|
|
5454
5648
|
}
|
|
5455
5649
|
}
|
|
5456
|
-
return { width:
|
|
5650
|
+
return { width: line2.width, y: index * fit.lineHeight, baseline: fit.fontSize + index * fit.lineHeight, height: fit.lineHeight, outline };
|
|
5457
5651
|
});
|
|
5458
5652
|
const place = (part, fit, width) => {
|
|
5459
5653
|
if (!hasOutlines) return fit;
|
|
@@ -5461,8 +5655,8 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5461
5655
|
return { ...fit, placement, overflow: placement.overflow };
|
|
5462
5656
|
};
|
|
5463
5657
|
const naturalWidth = (part, fit) => {
|
|
5464
|
-
if (!hasOutlines) return Math.max(...fit.sourceLines.map((
|
|
5465
|
-
const width = Math.max(...lineInk(part, fit).map((
|
|
5658
|
+
if (!hasOutlines) return Math.max(...fit.sourceLines.map((line2) => line2.width));
|
|
5659
|
+
const width = Math.max(...lineInk(part, fit).map((line2) => Math.max(line2.width, line2.outline ? line2.outline.x + line2.outline.width : 0) - Math.min(0, line2.outline?.x ?? 0)));
|
|
5466
5660
|
return width > 0 ? width + 2 * rasterPadding : 0;
|
|
5467
5661
|
};
|
|
5468
5662
|
const cache2 = /* @__PURE__ */ new Map();
|
|
@@ -5477,12 +5671,12 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5477
5671
|
}
|
|
5478
5672
|
return fit;
|
|
5479
5673
|
};
|
|
5480
|
-
const fitValue = (
|
|
5481
|
-
if (!usable2(
|
|
5674
|
+
const fitValue = (area2, singleLine) => {
|
|
5675
|
+
if (!usable2(area2)) return void 0;
|
|
5482
5676
|
for (let step = 0; step <= 76; step++) {
|
|
5483
5677
|
const size = gridFontSize(primary.requestedFontSize - step * scale, minimum);
|
|
5484
|
-
const natural = measure(primary, size,
|
|
5485
|
-
const fit = { ...natural, overflow: !!natural.placement?.overflow || singleLine && natural.lines.length !== 1 || occupied(natural) >
|
|
5678
|
+
const natural = measure(primary, size, area2.width);
|
|
5679
|
+
const fit = { ...natural, overflow: !!natural.placement?.overflow || singleLine && natural.lines.length !== 1 || occupied(natural) > area2.height + 0.01 || natural.sourceLines.some((line2) => line2.width > area2.width + 0.01) };
|
|
5486
5680
|
if (!fit.overflow || size === minimum) return fit;
|
|
5487
5681
|
}
|
|
5488
5682
|
};
|
|
@@ -5499,8 +5693,8 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5499
5693
|
const tail = metadata.filter((part) => arrangement !== "inline-unit" || part !== unit);
|
|
5500
5694
|
const tailHeight = tail.reduce((sum, part) => sum + occupied(measured.get(part)), 0) + Math.max(0, tail.length - 1) * gap;
|
|
5501
5695
|
if (!Number.isFinite(tailHeight)) throw new RangeError("Metric metadata exceeds finite coordinates.");
|
|
5502
|
-
const
|
|
5503
|
-
const valueFit = fitValue(
|
|
5696
|
+
const area2 = { ...box, width: arrangement === "inline-unit" ? box.width - unitWidth - gap : box.width, height: box.height - tailHeight - (tail.length ? primaryGap : 0) };
|
|
5697
|
+
const valueFit = fitValue(area2, arrangement === "inline-unit"), valueHeight = valueFit ? occupied(valueFit) : 0;
|
|
5504
5698
|
const allocations = [];
|
|
5505
5699
|
let primaryHeight = valueHeight;
|
|
5506
5700
|
if (arrangement === "inline-unit" && unit && unitFit && valueFit) {
|
|
@@ -5508,18 +5702,18 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5508
5702
|
const unitBaseline = unitFit.placement?.lines.at(-1)?.baseline ?? occupied(unitFit) - unitFit.lineHeight + unitFit.fontSize;
|
|
5509
5703
|
const valueY = box.y + Math.max(0, unitBaseline - valueBaseline), unitY = box.y + Math.max(0, valueBaseline - unitBaseline);
|
|
5510
5704
|
const measuredWidth = naturalWidth(primary, valueFit);
|
|
5511
|
-
const valueWidth = Math.min(
|
|
5512
|
-
allocations.push({ part: primary, box: { ...
|
|
5705
|
+
const valueWidth = Math.min(area2.width, measuredWidth || valueFit.fontSize);
|
|
5706
|
+
allocations.push({ part: primary, box: { ...area2, y: valueY, width: valueWidth, height: valueHeight }, fit: place(primary, valueFit, valueWidth) });
|
|
5513
5707
|
allocations.push({ part: unit, box: { x: box.x + valueWidth + gap, y: unitY, width: unitWidth, height: occupied(unitFit) }, fit: { ...unitFit, overflow: !!unitFit.placement?.overflow } });
|
|
5514
5708
|
primaryHeight = Math.max(valueY - box.y + valueHeight, unitY - box.y + occupied(unitFit));
|
|
5515
|
-
} else allocations.push({ part: primary, box: valueFit ? { ...
|
|
5709
|
+
} else allocations.push({ part: primary, box: valueFit ? { ...area2, height: valueHeight } : area2, fit: valueFit });
|
|
5516
5710
|
let y = box.y + primaryHeight + (tail.length ? primaryGap : 0);
|
|
5517
5711
|
for (const part of tail) {
|
|
5518
5712
|
const natural = measured.get(part), height = occupied(natural);
|
|
5519
|
-
allocations.push({ part, box: { ...box, y, height }, fit: { ...natural, overflow: !!natural.placement?.overflow || natural.sourceLines.some((
|
|
5713
|
+
allocations.push({ part, box: { ...box, y, height }, fit: { ...natural, overflow: !!natural.placement?.overflow || natural.sourceLines.some((line2) => line2.width > box.width + 0.01) } });
|
|
5520
5714
|
y += height + gap;
|
|
5521
5715
|
}
|
|
5522
|
-
const overflow = !valueFit || valueFit.overflow || arrangement === "inline-unit" && valueFit.lines.length !== 1 || primaryHeight >
|
|
5716
|
+
const overflow = !valueFit || valueFit.overflow || arrangement === "inline-unit" && valueFit.lines.length !== 1 || primaryHeight > area2.height + 0.01 || allocations.some(({ box: area3, fit }) => !fit || fit.overflow || !usable2(area3) || area3.y + area3.height > box.y + box.height + 0.01);
|
|
5523
5717
|
const score = allocations.reduce((sum, { part, fit }) => sum + (part.requestedFontSize - (fit?.fontSize ?? minimum)) / scale, 0);
|
|
5524
5718
|
const candidate = { arrangement, allocations, score, overflow };
|
|
5525
5719
|
if (!selected || !overflow && (selected.overflow || score < selected.score) || overflow && selected.overflow) selected = candidate;
|
|
@@ -5538,10 +5732,10 @@ function layoutMetric(value, box, options = {}) {
|
|
|
5538
5732
|
}
|
|
5539
5733
|
for (const part of parts) if (part.fit) {
|
|
5540
5734
|
if (part.fit.placement) {
|
|
5541
|
-
part.fit = { ...part.fit, placement: { ...part.fit.placement, lines: part.fit.placement.lines.map((
|
|
5735
|
+
part.fit = { ...part.fit, placement: { ...part.fit.placement, lines: part.fit.placement.lines.map((line2) => ({ ...line2, x: line2.x + part.box.x, y: line2.y + part.box.y, baseline: line2.baseline + part.box.y, outline: line2.outline ? { ...line2.outline, x: line2.outline.x + part.box.x, y: line2.outline.y + part.box.y } : null })) } };
|
|
5542
5736
|
part.linePositions = part.fit.placement.lines.map(({ x, baseline }) => ({ x, baseline }));
|
|
5543
|
-
} else part.linePositions = part.fit.sourceLines.map((
|
|
5544
|
-
x: part.box.x + (part.box.width -
|
|
5737
|
+
} else part.linePositions = part.fit.sourceLines.map((line2, index) => ({
|
|
5738
|
+
x: part.box.x + (part.box.width - line2.width) * alignmentFactor,
|
|
5545
5739
|
baseline: part.box.y + part.fit.fontSize + index * part.fit.lineHeight
|
|
5546
5740
|
}));
|
|
5547
5741
|
}
|
|
@@ -5601,10 +5795,10 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
5601
5795
|
let measured = cache2.get(key);
|
|
5602
5796
|
if (measured) return measured;
|
|
5603
5797
|
const fit = fitText(part.text, { width: Math.max(Number.MIN_VALUE, width - (outlines ? 2 * padding : 0)), height: Number.MAX_VALUE }, size, size, textWidthMeasurer(part.style, options.textMeasurement), options.direction);
|
|
5604
|
-
const ink = fit.sourceLines.map((
|
|
5798
|
+
const ink = fit.sourceLines.map((line2, index) => {
|
|
5605
5799
|
let left = Infinity, top = Infinity, right = -Infinity, bottom = -Infinity, hasInk = false;
|
|
5606
5800
|
if (outlines) {
|
|
5607
|
-
for (const segment2 of
|
|
5801
|
+
for (const segment2 of line2.segments) if (segment2.kind === "text") {
|
|
5608
5802
|
const outline = measureTextOutline(part.text.slice(segment2.start, segment2.end), size, part.style, options.textMeasurement);
|
|
5609
5803
|
if (outline) {
|
|
5610
5804
|
hasInk = true;
|
|
@@ -5615,7 +5809,7 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
5615
5809
|
}
|
|
5616
5810
|
}
|
|
5617
5811
|
}
|
|
5618
|
-
return { width:
|
|
5812
|
+
return { width: line2.width, y: index * fit.lineHeight, baseline: size + index * fit.lineHeight, height: fit.lineHeight, outline: hasInk ? { x: left, y: top, width: right - left, height: bottom - top } : null };
|
|
5619
5813
|
});
|
|
5620
5814
|
const placement = outlines ? placeTextLines(ink, { x: 0, y: 0, width, height: Number.MAX_VALUE }, alignment, padding, fit.directions) : void 0;
|
|
5621
5815
|
const height = placement?.height ?? fit.sourceLines.length * fit.lineHeight;
|
|
@@ -5639,13 +5833,13 @@ function layoutTimeline(value, box, options = {}) {
|
|
|
5639
5833
|
};
|
|
5640
5834
|
const place = (part, x, y2, width, alignment) => {
|
|
5641
5835
|
const measured = measure(part, gridFontSize(part.requestedFontSize - reduction * scale, minimum), Math.max(scale, width), alignment);
|
|
5642
|
-
const
|
|
5836
|
+
const area2 = { x, y: y2, width: Math.max(scale, width), height: Math.max(scale, measured.height) }, placement = outlines ? placeTextLines(measured.ink, area2, alignment, padding, measured.fit.directions) : void 0;
|
|
5643
5837
|
const fit = { ...measured.fit, ...placement ? { placement } : {}, overflow: measured.fit.overflow || !!placement?.overflow };
|
|
5644
|
-
const accepted = { ...part, box:
|
|
5838
|
+
const accepted = { ...part, box: area2, alignment, fit };
|
|
5645
5839
|
parts.push(accepted);
|
|
5646
5840
|
if (fit.overflow) report(accepted, "text-fit", "Timeline field exceeds its readable width; increase its space or split the timeline.");
|
|
5647
5841
|
if (breaksInsideWord(part.text, fit)) report(accepted, "text-fit", "Timeline field would split a word; use a wider vertical arrangement or paginate events.");
|
|
5648
|
-
if (
|
|
5842
|
+
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));
|
|
5649
5843
|
return accepted;
|
|
5650
5844
|
};
|
|
5651
5845
|
let y = box.y;
|
|
@@ -5787,14 +5981,14 @@ function fitSourceText(text2, box, size, minimum, step, measure, prose = false,
|
|
|
5787
5981
|
push(end, end, "end");
|
|
5788
5982
|
const lineHeight = fontSize * 1.22;
|
|
5789
5983
|
return {
|
|
5790
|
-
lines: sourceLines.map((
|
|
5984
|
+
lines: sourceLines.map((line2) => text2.slice(line2.start, line2.end)),
|
|
5791
5985
|
sourceLines,
|
|
5792
5986
|
fontSize,
|
|
5793
5987
|
lineHeight,
|
|
5794
5988
|
tabSize: 4,
|
|
5795
5989
|
tabWidth,
|
|
5796
|
-
...directionAt ? { directions: sourceLines.map((
|
|
5797
|
-
overflow: sourceLines.length * lineHeight > box.height + 0.01 || sourceLines.some((
|
|
5990
|
+
...directionAt ? { directions: sourceLines.map((line2) => directionAt(line2.start)) } : {},
|
|
5991
|
+
overflow: sourceLines.length * lineHeight > box.height + 0.01 || sourceLines.some((line2) => line2.width > box.width + 0.01)
|
|
5798
5992
|
};
|
|
5799
5993
|
};
|
|
5800
5994
|
return fitAtSizes(layout, size, minimum, step, snap);
|
|
@@ -5832,8 +6026,8 @@ function layoutCode(value, box, options = {}) {
|
|
|
5832
6026
|
if (code.language) add("language", code.language, `${path}.language`);
|
|
5833
6027
|
if (!parts.length) add("language", "code", path, true);
|
|
5834
6028
|
const body = add("body", code.source, shorthand ? path : `${path}.source`), headers = parts.filter((part) => part !== body);
|
|
5835
|
-
const usable2 = (
|
|
5836
|
-
const fit = (part,
|
|
6029
|
+
const usable2 = (area2) => [area2.x, area2.y, area2.width, area2.height].every(Number.isFinite) && area2.width > 0 && area2.height > 0;
|
|
6030
|
+
const fit = (part, area2, size = part.requestedFontSize, floor = minimum) => usable2(area2) ? fitCodeText(part.text, area2, size, floor, scale, textWidthMeasurer(part.style, options.textMeasurement)) : void 0;
|
|
5837
6031
|
if (usable2(inner)) {
|
|
5838
6032
|
const combinations = headers.reduce((choices, part) => choices.flatMap((choice) => [.../* @__PURE__ */ new Set([part.requestedFontSize, minimum])].map((size) => [...choice, { part, size }])), [[]]);
|
|
5839
6033
|
let selected;
|
|
@@ -5842,12 +6036,12 @@ function layoutCode(value, box, options = {}) {
|
|
|
5842
6036
|
const allocations = [];
|
|
5843
6037
|
for (const [index, { part, size }] of combination.entries()) {
|
|
5844
6038
|
const measured = fitCodeText(part.text, inner, size, size, scale, textWidthMeasurer(part.style, options.textMeasurement));
|
|
5845
|
-
const
|
|
5846
|
-
allocations.push({ part, box:
|
|
5847
|
-
y +=
|
|
6039
|
+
const area3 = { ...inner, y, height: measured.lines.length * measured.lineHeight };
|
|
6040
|
+
allocations.push({ part, box: area3, fit: usable2(area3) ? { ...measured, overflow: measured.sourceLines.some((line2) => line2.width > area3.width + 0.01) } : void 0 });
|
|
6041
|
+
y += area3.height + (index < headers.length - 1 ? 8 : 12);
|
|
5848
6042
|
}
|
|
5849
|
-
const
|
|
5850
|
-
allocations.push({ part: body, box:
|
|
6043
|
+
const area2 = { ...inner, y, height: inner.y + inner.height - y };
|
|
6044
|
+
allocations.push({ part: body, box: area2, fit: fit(body, area2) });
|
|
5851
6045
|
const overflow = allocations.some(({ box: box2, fit: fit2 }) => !fit2 || fit2.overflow || !usable2(box2) || box2.y + box2.height > inner.y + inner.height + 0.01);
|
|
5852
6046
|
const score = allocations.reduce((sum, { part, fit: fit2 }) => sum + (part.requestedFontSize - (fit2?.fontSize ?? minimum)) / scale, 0);
|
|
5853
6047
|
if (!selected || !overflow && (selected.overflow || score < selected.score) || overflow && selected.overflow) selected = { allocations, score, overflow };
|
|
@@ -5861,8 +6055,8 @@ function layoutCode(value, box, options = {}) {
|
|
|
5861
6055
|
for (const part of parts) {
|
|
5862
6056
|
if (!part.fit) report("invalid-part-box", part, [part.role], `Code ${part.role} has no usable space after metadata and insets; increase the cell or change the arrangement.`);
|
|
5863
6057
|
else if (part.fit.overflow) report("text-fit", part, [part.role], `Code ${part.role} exceeds its space at the readability floor; increase its space or change the arrangement.`);
|
|
5864
|
-
const
|
|
5865
|
-
if (usable2(
|
|
6058
|
+
const area2 = part.box;
|
|
6059
|
+
if (usable2(area2) && (area2.x < box.x || area2.y < box.y || area2.x + area2.width > box.x + box.width + 0.01 || area2.y + area2.height > box.y + box.height + 0.01)) {
|
|
5866
6060
|
report("part-outside-cell", part, [part.role], `Code ${part.role} extends outside its cell; increase the cell or change the arrangement.`);
|
|
5867
6061
|
}
|
|
5868
6062
|
}
|
|
@@ -5990,27 +6184,27 @@ function richTextLayouter(input, box, requestedSize, options, minimum = 0) {
|
|
|
5990
6184
|
let y = 0;
|
|
5991
6185
|
const richLines = ranges.map((range, rangeIndex) => {
|
|
5992
6186
|
const parts = fragments(range.start, range.end), shown = hung.get(rangeIndex) ?? range.end, ascent = Math.max(fontSize, ...parts.map((part) => part.fontSize - part.baselineShift)), descent = Math.max(fontSize * 0.22, ...parts.map((part) => part.fontSize * 0.22 + part.baselineShift));
|
|
5993
|
-
const height = ascent + descent,
|
|
6187
|
+
const height = ascent + descent, line2 = { fragments: parts, width: shown === range.end ? parts.reduce((sum, p) => sum + p.width, 0) : width(range.start, shown), y, baseline: y + ascent, height };
|
|
5994
6188
|
y += height;
|
|
5995
|
-
return
|
|
6189
|
+
return line2;
|
|
5996
6190
|
});
|
|
5997
6191
|
if (options.uniformLineHeight) {
|
|
5998
|
-
const height = Math.max(...richLines.map((
|
|
6192
|
+
const height = Math.max(...richLines.map((line2) => line2.height));
|
|
5999
6193
|
y = 0;
|
|
6000
|
-
for (const
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6194
|
+
for (const line2 of richLines) {
|
|
6195
|
+
line2.baseline += y - line2.y;
|
|
6196
|
+
line2.y = y;
|
|
6197
|
+
line2.height = height;
|
|
6004
6198
|
y += height;
|
|
6005
6199
|
}
|
|
6006
6200
|
}
|
|
6007
6201
|
return {
|
|
6008
6202
|
lines: ranges.map((range) => whole.slice(range.start, range.end)),
|
|
6009
6203
|
fontSize,
|
|
6010
|
-
lineHeight: Math.max(fontSize * 1.22, ...richLines.map((
|
|
6204
|
+
lineHeight: Math.max(fontSize * 1.22, ...richLines.map((line2) => line2.height)),
|
|
6011
6205
|
richLines,
|
|
6012
6206
|
height: y,
|
|
6013
|
-
overflow: y > box.height + 0.01 || richLines.some((
|
|
6207
|
+
overflow: y > box.height + 0.01 || richLines.some((line2) => line2.width > box.width + 0.01),
|
|
6014
6208
|
...directionAt ? { directions: ranges.map((range) => directionAt(range.start)) } : {}
|
|
6015
6209
|
};
|
|
6016
6210
|
};
|
|
@@ -6107,7 +6301,7 @@ ${flatten(entry.description)}` : ""}`;
|
|
|
6107
6301
|
return void 0;
|
|
6108
6302
|
}
|
|
6109
6303
|
function layoutTable(value, box, options = {}) {
|
|
6110
|
-
const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale), requested = gridFontSize(
|
|
6304
|
+
const scale = options.scale ?? 1, minimum = snapFontSizeUp((options.minFontSize ?? 16) * scale), requested = gridFontSize(contentNominalSize("table") * scale, minimum);
|
|
6111
6305
|
if (![box.x, box.y, box.width, box.height, scale, minimum].every(Number.isFinite) || box.width <= 0 || box.height <= 0 || scale <= 0 || minimum <= 0) throw new RangeError("Table dimensions, scale and font sizes must be finite and positive.");
|
|
6112
6306
|
const inline = inlineTableData(value, options.presentation);
|
|
6113
6307
|
const grid = tableGrid(inline, options.path ?? "table");
|
|
@@ -6115,7 +6309,7 @@ function layoutTable(value, box, options = {}) {
|
|
|
6115
6309
|
const numeric = new Set(grid.rows.flat().filter((cell) => !cell.header && typeof cell.value === "number" && Number.isFinite(cell.value)));
|
|
6116
6310
|
const numericColumns = new Set(Array.from({ length: grid.columnCount }, (_, column) => column).filter((column) => {
|
|
6117
6311
|
const body = grid.rows.flat().filter((cell) => !cell.header && cell.column === column && cell.value !== null && cell.value !== void 0);
|
|
6118
|
-
return body.
|
|
6312
|
+
return body.some((cell) => numeric.has(cell)) && body.every((cell) => cell.colSpan === 1 && (numeric.has(cell) || Array.isArray(cell.value)));
|
|
6119
6313
|
}));
|
|
6120
6314
|
const formats = resolveTableData(inline).formats;
|
|
6121
6315
|
for (const row of grid.rows) for (const cell of row) {
|
|
@@ -6127,52 +6321,65 @@ function layoutTable(value, box, options = {}) {
|
|
|
6127
6321
|
const cells = grid.rows.flat().map((cell) => {
|
|
6128
6322
|
const padding = { top: 8, right: 10, bottom: 4, left: 10, ...cell.style.padding };
|
|
6129
6323
|
const width = cellWidth * cell.colSpan - (padding.left + padding.right) * scale;
|
|
6130
|
-
const style = { fontFamily: options.fontFamily ?? "sans-serif", fontWeight: cell.header ? 700 : 400, italic: false, path: cell.valuePath };
|
|
6131
|
-
const numericDefault = numeric.has(cell) || cell.header && cell.colSpan === 1 && numericColumns.has(cell.column);
|
|
6324
|
+
const style = { fontFamily: options.fontFamily ?? "sans-serif", fontWeight: cell.header || cell.style.bold ? 700 : 400, italic: false, path: cell.valuePath };
|
|
6325
|
+
const numericDefault = numeric.has(cell) || (cell.header || Array.isArray(cell.value)) && cell.colSpan === 1 && numericColumns.has(cell.column);
|
|
6132
6326
|
const alignment = cell.style.align ?? options.alignment ?? (numericDefault ? options.direction === "rtl" ? "left" : "right" : "left");
|
|
6133
6327
|
return { ...cell, padding, width, textStyle: style, alignment };
|
|
6134
6328
|
});
|
|
6135
6329
|
const cellMinimum = (cell) => Array.isArray(cell.value) ? richMinimum(cell.value, requested, minimum) : minimum;
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6330
|
+
let trial = requested;
|
|
6331
|
+
const cellSize = (cell) => {
|
|
6332
|
+
const floor = cellMinimum(cell);
|
|
6333
|
+
return gridFontSize(Math.max(trial, floor), floor);
|
|
6334
|
+
};
|
|
6335
|
+
const fitCell = (cell, height) => {
|
|
6336
|
+
const textBox = { width: Math.max(scale, cell.width), height: Math.max(scale, height) }, size = cellSize(cell);
|
|
6337
|
+
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);
|
|
6139
6338
|
};
|
|
6140
6339
|
const textHeight = (fit) => "height" in fit ? fit.height : fit.lines.length * fit.lineHeight;
|
|
6141
|
-
const required = (cell,
|
|
6142
|
-
const floor = cellMinimum(cell), size = gridFontSize(
|
|
6340
|
+
const required = (cell, natural) => {
|
|
6341
|
+
const floor = cellMinimum(cell), size = gridFontSize(natural ? Math.max(trial, floor) : floor, floor);
|
|
6143
6342
|
const textBox = { width: Math.max(scale, cell.width), height: scale };
|
|
6144
6343
|
const fit = Array.isArray(cell.value) ? richTextLayouter(cell.value, textBox, requested, { style: cell.textStyle, ...options.codeFontFamily ? { codeFontFamily: options.codeFontFamily } : {}, textMeasurement: options.textMeasurement, uniformLineHeight: true }, minimum)(size) : fitText(flatten(cell.value), textBox, size, size, textWidthMeasurer(resolveTextStyle(cell.textStyle, options.textMeasurement), options.textMeasurement));
|
|
6145
6344
|
return textHeight(fit) + (cell.padding.top + cell.padding.bottom) * scale;
|
|
6146
6345
|
};
|
|
6147
|
-
const
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
const
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
|
|
6172
|
-
|
|
6173
|
-
|
|
6174
|
-
|
|
6175
|
-
|
|
6346
|
+
const place = () => {
|
|
6347
|
+
const natural = Array(grid.rowCount).fill(0), needed = Array(grid.rowCount).fill(0);
|
|
6348
|
+
for (const cell of cells) if (cell.rowSpan === 1) {
|
|
6349
|
+
natural[cell.row] = Math.max(natural[cell.row], required(cell, true));
|
|
6350
|
+
needed[cell.row] = Math.max(needed[cell.row], required(cell, false));
|
|
6351
|
+
}
|
|
6352
|
+
for (const cell of cells) if (cell.rowSpan > 1) for (const [heights2, preferredSize] of [[natural, true], [needed, false]]) {
|
|
6353
|
+
const current = heights2.slice(cell.row, cell.row + cell.rowSpan).reduce((a, b) => a + b, 0);
|
|
6354
|
+
const extra = Math.max(0, required(cell, preferredSize) - current) / cell.rowSpan;
|
|
6355
|
+
for (let r = cell.row; r < cell.row + cell.rowSpan; r++) heights2[r] += extra;
|
|
6356
|
+
}
|
|
6357
|
+
const preferred = natural.map((height) => Math.max(54 * scale, height));
|
|
6358
|
+
for (let r = 0; r < needed.length; r++) needed[r] = Math.min(preferred[r], needed[r]);
|
|
6359
|
+
const sum = (values) => values.reduce((a, b) => a + b, 0);
|
|
6360
|
+
const preferredTotal = sum(preferred), naturalTotal = sum(natural), neededTotal = sum(needed);
|
|
6361
|
+
const heights = preferred.map((height, r) => preferredTotal <= box.height ? height : naturalTotal <= box.height ? natural[r] + (height - natural[r]) * (box.height - naturalTotal) / Math.max(Number.EPSILON, preferredTotal - naturalTotal) : neededTotal <= box.height ? needed[r] + (natural[r] - needed[r]) * (box.height - neededTotal) / Math.max(Number.EPSILON, naturalTotal - neededTotal) : needed[r] * box.height / neededTotal);
|
|
6362
|
+
const ys = [box.y];
|
|
6363
|
+
for (const height of heights) ys.push(ys.at(-1) + height);
|
|
6364
|
+
let overflow = false;
|
|
6365
|
+
const rows3 = heights.map((height, r) => ({ box: { x: box.x, y: ys[r], width: box.width, height }, cells: [] }));
|
|
6366
|
+
for (const cell of cells) {
|
|
6367
|
+
const cellBox = { x: box.x + (options.direction === "rtl" ? columnCount - cell.column - cell.colSpan : cell.column) * cellWidth, y: ys[cell.row], width: cell.colSpan * cellWidth, height: ys[cell.row + cell.rowSpan] - ys[cell.row] };
|
|
6368
|
+
const available = cellBox.height - (cell.padding.top + cell.padding.bottom) * scale;
|
|
6369
|
+
const fit = fitCell(cell, available), height = textHeight(fit);
|
|
6370
|
+
const offset = cell.style.verticalAlign === "bottom" ? Math.max(0, available - height) : cell.style.verticalAlign === "middle" ? Math.max(0, (available - height) / 2) : 0;
|
|
6371
|
+
const textBox = { x: cellBox.x + cell.padding.left * scale, y: cellBox.y + cell.padding.top * scale + offset, width: Math.max(scale, cell.width), height: Math.max(scale, available - offset) };
|
|
6372
|
+
overflow ||= cell.width <= 0 || available <= 0 || fit.overflow;
|
|
6373
|
+
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] } : {} });
|
|
6374
|
+
}
|
|
6375
|
+
return { rows: rows3, columnCount, height: sum(heights), overflow };
|
|
6376
|
+
};
|
|
6377
|
+
for (let step = 0; ; step++) {
|
|
6378
|
+
const raw = requested - step * scale, last = step === 64 || raw <= minimum;
|
|
6379
|
+
trial = last ? snapFontSizeUp(minimum) : gridFontSize(raw, minimum);
|
|
6380
|
+
const layout = place();
|
|
6381
|
+
if (last || !layout.overflow) return layout;
|
|
6382
|
+
}
|
|
6176
6383
|
}
|
|
6177
6384
|
function tableOverflows(value, box, scale, settings, options, path) {
|
|
6178
6385
|
return box.width <= 0 || box.height <= 0 || layoutTable(value, box, { scale, minFontSize: settings.minFontSize, fontFamily: options.fontFamilies?.body, ...options.fontFamilies?.code ? { codeFontFamily: options.fontFamilies.code } : {}, textMeasurement: options.textMeasurement, path, presentation: options.presentation }).overflow;
|
|
@@ -6200,15 +6407,15 @@ function regionParts(key) {
|
|
|
6200
6407
|
}
|
|
6201
6408
|
return void 0;
|
|
6202
6409
|
}
|
|
6203
|
-
function regionBox(parts,
|
|
6204
|
-
const gap = Math.min(requestedGap,
|
|
6205
|
-
const cw = (
|
|
6410
|
+
function regionBox(parts, area2, requestedGap) {
|
|
6411
|
+
const gap = Math.min(requestedGap, area2.width / 6, area2.height / 6);
|
|
6412
|
+
const cw = (area2.width - gap * 2) / 3, ch = (area2.height - gap * 2) / 3;
|
|
6206
6413
|
const [r, c] = parts;
|
|
6207
|
-
return { x:
|
|
6414
|
+
return { x: area2.x + Math.min(...c) * (cw + gap), y: area2.y + Math.min(...r) * (ch + gap), width: (Math.max(...c) - Math.min(...c) + 1) * (cw + gap) - gap, height: (Math.max(...r) - Math.min(...r) + 1) * (ch + gap) - gap };
|
|
6208
6415
|
}
|
|
6209
|
-
function gridGeometry(count,
|
|
6416
|
+
function gridGeometry(count, area2, cols, gap, weights, vertical) {
|
|
6210
6417
|
const rowCount = Math.ceil(count / cols);
|
|
6211
|
-
gap = Math.min(gap,
|
|
6418
|
+
gap = Math.min(gap, area2.width / (cols * 2), area2.height / (rowCount * 2));
|
|
6212
6419
|
const tracks = (length, total, weighted) => {
|
|
6213
6420
|
const values = Array.from({ length }, (_, i) => weighted ? weights[i] ?? 1 : 1);
|
|
6214
6421
|
const sum = values.reduce((a, b) => a + b, 0);
|
|
@@ -6220,12 +6427,12 @@ function gridGeometry(count, area, cols, gap, weights, vertical) {
|
|
|
6220
6427
|
return track;
|
|
6221
6428
|
});
|
|
6222
6429
|
};
|
|
6223
|
-
const xs = tracks(cols,
|
|
6224
|
-
const boxes = Array.from({ length: count }, (_, i) => ({ x:
|
|
6430
|
+
const xs = tracks(cols, area2.width, !vertical), ys = tracks(rowCount, area2.height, vertical);
|
|
6431
|
+
const boxes = Array.from({ length: count }, (_, i) => ({ x: area2.x + xs[i % cols].offset, y: area2.y + ys[Math.floor(i / cols)].offset, width: xs[i % cols].size, height: ys[Math.floor(i / cols)].size }));
|
|
6225
6432
|
return { boxes, columns: xs, rows: ys, gap };
|
|
6226
6433
|
}
|
|
6227
|
-
function gridBoxes(count,
|
|
6228
|
-
return gridGeometry(count,
|
|
6434
|
+
function gridBoxes(count, area2, cols, gap, weights, vertical) {
|
|
6435
|
+
return gridGeometry(count, area2, cols, gap, weights, vertical).boxes;
|
|
6229
6436
|
}
|
|
6230
6437
|
function assertComposition(value) {
|
|
6231
6438
|
if (value.mode !== void 0 && !["auto", "grid", "row", "column"].includes(value.mode)) throw new RangeError("Unknown composition mode.");
|
|
@@ -6252,13 +6459,13 @@ function composeLayoutAreas(layout, options = {}) {
|
|
|
6252
6459
|
...mirror !== void 0 ? { design: { mirror } } : {}
|
|
6253
6460
|
};
|
|
6254
6461
|
const result = composeSlide(slide, { ...compose, layout: kept, [LAYOUT_MASTER]: true });
|
|
6255
|
-
const areas = template.areas.map((
|
|
6256
|
-
if (
|
|
6257
|
-
const found = result.headingAreas?.find((entry) => entry.name ===
|
|
6258
|
-
return { name:
|
|
6462
|
+
const areas = template.areas.map((area2) => {
|
|
6463
|
+
if (area2.heading) {
|
|
6464
|
+
const found = result.headingAreas?.find((entry) => entry.name === area2.name);
|
|
6465
|
+
return { name: area2.name, heading: true, box: found ? { ...found.box } : { x: 0, y: 0, width: 0, height: 0 }, ...found?.parts ? { parts: found.parts } : {} };
|
|
6259
6466
|
}
|
|
6260
|
-
const region = result.regions.find((entry) => entry.name ===
|
|
6261
|
-
return { name:
|
|
6467
|
+
const region = result.regions.find((entry) => entry.name === area2.name);
|
|
6468
|
+
return { name: area2.name, heading: false, box: { ...!bleed && region.areaBox ? region.areaBox : region.box } };
|
|
6262
6469
|
});
|
|
6263
6470
|
return { contentBox: { ...result.contentBox }, areas };
|
|
6264
6471
|
}
|
|
@@ -6280,7 +6487,7 @@ function composeSlide(input, options = {}) {
|
|
|
6280
6487
|
const rasterPadding = (options.textRasterPadding ?? 1) * scale;
|
|
6281
6488
|
if (!Number.isFinite(rasterPadding) || rasterPadding < 0) throw new RangeError("Text raster padding must be finite and nonnegative.");
|
|
6282
6489
|
let coverGroup = false;
|
|
6283
|
-
const alignmentFor = (field) => (field === "title" ||
|
|
6490
|
+
const alignmentFor = (field) => (field === "title" || (field === "tag" || coverGroup && field === "subtitle") && hints.sources.contentAlignment !== "slide" ? hints.titleAlignment : hints.contentAlignment) ?? (field === "metric" ? "center" : "left");
|
|
6284
6491
|
const styleFor = (field, path2) => resolveTextStyle({
|
|
6285
6492
|
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"),
|
|
6286
6493
|
fontWeight: field === "title" ? 700 : 400,
|
|
@@ -6305,9 +6512,9 @@ function composeSlide(input, options = {}) {
|
|
|
6305
6512
|
const raw = start - trial * scale, last = trial === 64 || raw <= floor, fontSize = last ? floor : gridFontSize(raw, floor);
|
|
6306
6513
|
const fit = richLayout ? richLayout(fontSize) : fitText(text2, box, fontSize, fontSize, measure, textDirection);
|
|
6307
6514
|
const richLines = "richLines" in fit ? fit.richLines : void 0;
|
|
6308
|
-
const lines = richLines ? richLines.map((
|
|
6515
|
+
const lines = richLines ? richLines.map((line2) => {
|
|
6309
6516
|
let outline = null;
|
|
6310
|
-
for (const fragment of
|
|
6517
|
+
for (const fragment of line2.fragments) {
|
|
6311
6518
|
if (fragment.kind === "tab") continue;
|
|
6312
6519
|
const bounds = measureTextOutline(fragment.text, fragment.fontSize, fragment.style, options.textMeasurement);
|
|
6313
6520
|
if (!bounds) continue;
|
|
@@ -6321,10 +6528,10 @@ function composeSlide(input, options = {}) {
|
|
|
6321
6528
|
outline.height = bottom - outline.y;
|
|
6322
6529
|
}
|
|
6323
6530
|
}
|
|
6324
|
-
return { width:
|
|
6325
|
-
}) : fit.sourceLines.map((
|
|
6531
|
+
return { width: line2.width, y: line2.y, baseline: line2.baseline, height: line2.height, outline };
|
|
6532
|
+
}) : fit.sourceLines.map((line2, index) => {
|
|
6326
6533
|
let outline = null;
|
|
6327
|
-
for (const segment2 of
|
|
6534
|
+
for (const segment2 of line2.segments) {
|
|
6328
6535
|
if (segment2.kind === "tab") continue;
|
|
6329
6536
|
const bounds = measureTextOutline(text2.slice(segment2.start, segment2.end), fontSize, style, options.textMeasurement);
|
|
6330
6537
|
if (!bounds) continue;
|
|
@@ -6338,7 +6545,7 @@ function composeSlide(input, options = {}) {
|
|
|
6338
6545
|
outline.height = bottom - outline.y;
|
|
6339
6546
|
}
|
|
6340
6547
|
}
|
|
6341
|
-
return { width:
|
|
6548
|
+
return { width: line2.width, y: index * fit.lineHeight, baseline: fontSize + index * fit.lineHeight, height: fit.lineHeight, outline };
|
|
6342
6549
|
});
|
|
6343
6550
|
const placement = placeTextLines(lines, box, alignment, rasterPadding, fit.directions), result = { ...fit, placement, overflow: fit.overflow || placement.overflow };
|
|
6344
6551
|
if (!result.overflow || last) return result;
|
|
@@ -6355,7 +6562,7 @@ function composeSlide(input, options = {}) {
|
|
|
6355
6562
|
const regions = Object.keys(slide).filter((key) => regionParts(key)).sort();
|
|
6356
6563
|
const assets = record8(options.presentation).assets;
|
|
6357
6564
|
const imageContext = (placement) => ({ fit: hints.imageFit, scale, mirrorSide, diagnostics: imageDiagnostics, assets, ...placement ? { placement } : {} });
|
|
6358
|
-
const
|
|
6565
|
+
const area2 = { left: 0, top: 0, right: width, bottom: height };
|
|
6359
6566
|
const topImages = regions.length ? [] : Array.isArray(slide.blocks) ? slide.blocks.flatMap((block, index) => !Array.isArray(record8(block).blocks) && record8(block).image !== void 0 ? [{ host: record8(block), hostPath: `${path}.blocks.${index}`, block: index }] : []) : slide.image !== void 0 ? [{ host: { type: "image", image: slide.image }, hostPath: path }] : [];
|
|
6360
6567
|
const placed = [], usedEdges = /* @__PURE__ */ new Set();
|
|
6361
6568
|
topImages.forEach((node) => {
|
|
@@ -6366,13 +6573,13 @@ function composeSlide(input, options = {}) {
|
|
|
6366
6573
|
if (usedEdges.has(edge)) return;
|
|
6367
6574
|
usedEdges.add(edge);
|
|
6368
6575
|
const size = finite(value.size, 0.1, 0.9) ?? PLACEMENT_BAND;
|
|
6369
|
-
const across = edge === "left" || edge === "right" ?
|
|
6576
|
+
const across = edge === "left" || edge === "right" ? area2.right - area2.left : area2.bottom - area2.top;
|
|
6370
6577
|
const band = Math.max(0, Math.min(across, round2((edge === "left" || edge === "right" ? width : height) * size)));
|
|
6371
|
-
const region = edge === "left" ? { x:
|
|
6372
|
-
if (edge === "left")
|
|
6373
|
-
else if (edge === "right")
|
|
6374
|
-
else if (edge === "top")
|
|
6375
|
-
else
|
|
6578
|
+
const region = edge === "left" ? { x: area2.left, y: area2.top, width: band, height: area2.bottom - area2.top } : edge === "right" ? { x: round2(area2.right - band), y: area2.top, width: band, height: area2.bottom - area2.top } : edge === "top" ? { x: area2.left, y: area2.top, width: area2.right - area2.left, height: band } : { x: area2.left, y: round2(area2.bottom - band), width: area2.right - area2.left, height: band };
|
|
6579
|
+
if (edge === "left") area2.left += band;
|
|
6580
|
+
else if (edge === "right") area2.right = region.x;
|
|
6581
|
+
else if (edge === "top") area2.top += band;
|
|
6582
|
+
else area2.bottom = region.y;
|
|
6376
6583
|
const placement = { edge, size, inset: value.inset === true, path: `${node.hostPath}.placement` };
|
|
6377
6584
|
placed.push({ ...node, placement, region });
|
|
6378
6585
|
});
|
|
@@ -6382,11 +6589,11 @@ function composeSlide(input, options = {}) {
|
|
|
6382
6589
|
const measuredFurniture = layoutFurniture(slide, options);
|
|
6383
6590
|
const furniture = measuredFurniture.configured || measuredFurniture.diagnostics.length ? measuredFurniture : void 0;
|
|
6384
6591
|
if (furniture) diagnostics.push(...furniture.diagnostics);
|
|
6385
|
-
let bodyBottom = Math.min(
|
|
6386
|
-
const headingTop = Math.max(
|
|
6592
|
+
let bodyBottom = Math.min(area2.bottom - padding, furniture && furniture.footerTop < height ? furniture.footerTop - gap * 0.5 : height - padding);
|
|
6593
|
+
const headingTop = Math.max(area2.top + padding, furniture?.headerBottom ? furniture.headerBottom + gap * 0.5 : padding);
|
|
6387
6594
|
let footnotes;
|
|
6388
6595
|
if (citations) {
|
|
6389
|
-
footnotes = layoutFootnotes(citations, { ...annotationOptions, x:
|
|
6596
|
+
footnotes = layoutFootnotes(citations, { ...annotationOptions, x: area2.left + padding, width: area2.right - area2.left - padding * 2, bottom: bodyBottom, maxHeight: Math.max(minSize * 1.22 + 2 * scale, (bodyBottom - headingTop) * FOOTNOTE_MAX_RATIO), path });
|
|
6390
6597
|
diagnostics.push(...footnotes.diagnostics);
|
|
6391
6598
|
bodyBottom = footnotes.box.y - gap * 0.5;
|
|
6392
6599
|
}
|
|
@@ -6403,8 +6610,8 @@ function composeSlide(input, options = {}) {
|
|
|
6403
6610
|
const resolved = resolveLogo(options.presentation, slide, { shape: "full", onDark: options.darkBackground, slideIndex: options.slideIndex });
|
|
6404
6611
|
if (resolved) {
|
|
6405
6612
|
const logoHeight = 56 * scale;
|
|
6406
|
-
const logoWidth = Math.max(scale, Math.min(4 * logoHeight,
|
|
6407
|
-
const box = { x: round2(rtl ?
|
|
6613
|
+
const logoWidth = Math.max(scale, Math.min(4 * logoHeight, area2.right - area2.left - 2 * padding));
|
|
6614
|
+
const box = { x: round2(rtl ? area2.right - padding - logoWidth : area2.left + padding), y: round2(headingTop), width: round2(logoWidth), height: round2(logoHeight) };
|
|
6408
6615
|
logo = { box, shape: resolved.shape, path: resolved.path, source: resolved.source, variant: resolved.variant, reference: resolved.reference, anchor: rtl ? "right" : "left" };
|
|
6409
6616
|
}
|
|
6410
6617
|
}
|
|
@@ -6414,7 +6621,7 @@ function composeSlide(input, options = {}) {
|
|
|
6414
6621
|
if (!slide[field] || Array.isArray(slide[field]) && !annotationText(slide[field])) continue;
|
|
6415
6622
|
const requested = (field === "title" ? 54 : field === "tag" ? 16 : 25) * scale;
|
|
6416
6623
|
const maxHeight = Math.max(height * (field === "title" ? 0.26 : field === "subtitle" ? 0.12 : 0.045), minSize * 1.22 + 2 * rasterPadding);
|
|
6417
|
-
const box = { x:
|
|
6624
|
+
const box = { x: area2.left + padding, y, width: area2.right - area2.left - padding * 2, height: maxHeight };
|
|
6418
6625
|
const text2 = fitPlacedText(field, slide[field], annotationText(slide[field]), box, requested, minSize, `${path}.${field}`);
|
|
6419
6626
|
box.height = Math.min(maxHeight, Math.max("richLines" in text2 ? text2.height : text2.lines.length * text2.lineHeight, text2.placement?.height ?? 0));
|
|
6420
6627
|
if (furniture && box.y + box.height > bodyBottom + 0.01) diagnostics.push({ code: "text-overflow", path: `${path}.${field}`, message: "Repeated furniture leaves too little room for this heading. Change the header/footer or slide design." });
|
|
@@ -6458,7 +6665,7 @@ function composeSlide(input, options = {}) {
|
|
|
6458
6665
|
...caption ? { caption } : {}
|
|
6459
6666
|
});
|
|
6460
6667
|
}
|
|
6461
|
-
const contentBox = { x:
|
|
6668
|
+
const contentBox = { x: area2.left + padding, y, width: area2.right - area2.left - padding * 2, height: Math.max(scale, bodyBottom - y) };
|
|
6462
6669
|
const collect = (host, basePath, depth = 0, ancestors = []) => {
|
|
6463
6670
|
if (Array.isArray(host.blocks)) {
|
|
6464
6671
|
if (depth >= MAX_COMPOSITION_DEPTH || ancestors.includes(host)) throw new RangeError(`Content groups must be acyclic and nest at most ${MAX_COMPOSITION_DEPTH} levels.`);
|
|
@@ -6579,29 +6786,29 @@ function composeSlide(input, options = {}) {
|
|
|
6579
6786
|
return score;
|
|
6580
6787
|
};
|
|
6581
6788
|
const modeFor = (settings) => settings.mode ?? "auto";
|
|
6582
|
-
const defaultColumns = (count,
|
|
6789
|
+
const defaultColumns = (count, area3, settings) => {
|
|
6583
6790
|
const mode = modeFor(settings);
|
|
6584
|
-
return mode === "column" ? 1 : mode === "row" ? Math.max(1, count) : settings.columns ?? Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count *
|
|
6791
|
+
return mode === "column" ? 1 : mode === "row" ? Math.max(1, count) : settings.columns ?? Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count * area3.width / area3.height / 1.6))));
|
|
6585
6792
|
};
|
|
6586
6793
|
const scoreNode = (node, box, settings, penalties) => {
|
|
6587
6794
|
if (!node.children) return leafScore(node, box, settings, penalties);
|
|
6588
|
-
const own3 = inheritedSettings(settings, node.composition),
|
|
6589
|
-
const cols = defaultColumns(slotCount,
|
|
6590
|
-
const boxes = gridBoxes(slotCount,
|
|
6795
|
+
const own3 = inheritedSettings(settings, node.composition), area3 = inset(box, own3), slotCount = Math.max(node.children.length, 0);
|
|
6796
|
+
const cols = defaultColumns(slotCount, area3, own3);
|
|
6797
|
+
const boxes = gridBoxes(slotCount, area3, cols, (own3.gap ?? 1 / 30) * Math.min(box.width, box.height), own3.weights ?? [], modeFor(own3) === "column");
|
|
6591
6798
|
return node.children.reduce((score, child, index) => score + scoreNode(child, boxes[index], own3, penalties), 0);
|
|
6592
6799
|
};
|
|
6593
|
-
const arrange = (nodes,
|
|
6800
|
+
const arrange = (nodes, area3, settings, reserved2 = 0, gapOverride, containerPath = path, recorded = true) => {
|
|
6594
6801
|
const count = Math.max(nodes.length, reserved2);
|
|
6595
6802
|
if (!count) return;
|
|
6596
|
-
const mode = modeFor(settings), localGap = (settings.gap ?? 1 / 30) * Math.min(
|
|
6803
|
+
const mode = modeFor(settings), localGap = (settings.gap ?? 1 / 30) * Math.min(area3.width, area3.height);
|
|
6597
6804
|
const actualGap = gapOverride ?? (settings === rootSettings ? gap : localGap);
|
|
6598
|
-
let cols = defaultColumns(count,
|
|
6805
|
+
let cols = defaultColumns(count, area3, settings);
|
|
6599
6806
|
const hasRegions = nodes.some((node) => node.region);
|
|
6600
6807
|
const candidates = decisions && recorded ? [] : void 0;
|
|
6601
6808
|
if (mode === "auto" && !hasRegions) {
|
|
6602
6809
|
let best = Infinity;
|
|
6603
6810
|
for (let candidate = 1; candidate <= Math.min(count, settings.columns ?? 6); candidate++) {
|
|
6604
|
-
const boxes2 = gridBoxes(count,
|
|
6811
|
+
const boxes2 = gridBoxes(count, area3, candidate, actualGap, settings.weights ?? [], false);
|
|
6605
6812
|
const emptySlots = (Math.ceil(count / candidate) * candidate - count) * 2;
|
|
6606
6813
|
const penalties = candidates ? { cellProportions: 0, fontReduction: 0, textOverflow: 0, tableOverflow: 0, smallCells: 0, emptySlots } : void 0;
|
|
6607
6814
|
const score = nodes.reduce((sum, node, i) => sum + scoreNode(node, boxes2[i], settings, penalties), 0) + emptySlots;
|
|
@@ -6619,16 +6826,21 @@ function composeSlide(input, options = {}) {
|
|
|
6619
6826
|
...hasRegions ? {} : { selectedColumns: cols },
|
|
6620
6827
|
candidates: candidates ?? []
|
|
6621
6828
|
});
|
|
6622
|
-
const grid = gridGeometry(count,
|
|
6623
|
-
const mirrored = (box) => rtl ? { ...box, x:
|
|
6829
|
+
const grid = gridGeometry(count, area3, cols, actualGap, settings.weights ?? [], mode === "column");
|
|
6830
|
+
const mirrored = (box) => rtl ? { ...box, x: area3.x + area3.width - (box.x - area3.x) - box.width } : box;
|
|
6624
6831
|
const boxes = grid.boxes.map(mirrored);
|
|
6625
|
-
if (recorded && !hasRegions) flows.push({ path: containerPath, box: { ...
|
|
6832
|
+
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 });
|
|
6626
6833
|
nodes.forEach((node, index) => {
|
|
6627
|
-
const box = node.region ? mirrored(regionBox(node.region,
|
|
6834
|
+
const box = node.region ? mirrored(regionBox(node.region, area3, actualGap)) : boxes[index];
|
|
6628
6835
|
placeNode(node, box, settings);
|
|
6629
6836
|
});
|
|
6630
6837
|
};
|
|
6631
6838
|
let regionTag, templateCell = false;
|
|
6839
|
+
const composeChart = (node, box, settings) => {
|
|
6840
|
+
const resolved = resolveChartData(node.value, options.presentation, { path: node.path });
|
|
6841
|
+
const valueAxis = chartValueAxis(node.value, resolved, { width: box.width, height: box.height, scale, minFontSize: settings.minFontSize });
|
|
6842
|
+
return valueAxis ? { valueAxis } : void 0;
|
|
6843
|
+
};
|
|
6632
6844
|
const placeNode = (node, box, settings, cards = hasCards, listColumns, metricReferenceHeight) => {
|
|
6633
6845
|
if (node.children) {
|
|
6634
6846
|
const own3 = inheritedSettings(settings, node.composition), inner = inset(box, own3);
|
|
@@ -6653,6 +6865,7 @@ function composeSlide(input, options = {}) {
|
|
|
6653
6865
|
const columns2 = textValue !== void 0 && !internal ? listColumnsFor(node, box, settings, listColumns) : void 0;
|
|
6654
6866
|
const text2 = internal ? body?.fit : columns2 ? columns2.length > 1 ? mergeListColumns(columns2) : columns2[0].text : textValue !== void 0 ? fitContent(node.field, node.value, textValue, box, contentNominalSize(node.field) * scale, snapFontSizeUp((settings.minFontSize ?? 16) * scale), node.path, node.payload.numbering) : void 0;
|
|
6655
6867
|
const image = node.field === "image" ? composeImage(node.host ?? {}, node.hostPath ?? node.path, box, box, imageContext()) : void 0;
|
|
6868
|
+
const chart = node.field === "chart" ? composeChart(node, box, settings) : void 0;
|
|
6656
6869
|
items.push({
|
|
6657
6870
|
path: node.path,
|
|
6658
6871
|
field: node.field,
|
|
@@ -6661,6 +6874,7 @@ function composeSlide(input, options = {}) {
|
|
|
6661
6874
|
payload: node.payload,
|
|
6662
6875
|
box: internal ? acceptedBox(box) : box,
|
|
6663
6876
|
...image ? { image } : {},
|
|
6877
|
+
...chart ? { chart } : {},
|
|
6664
6878
|
...frameBox ? { frameBox } : {},
|
|
6665
6879
|
text: text2,
|
|
6666
6880
|
textStyle: body?.style ?? styleFor(node.field, node.path),
|
|
@@ -6877,9 +7091,9 @@ function composeSlide(input, options = {}) {
|
|
|
6877
7091
|
const physical = (cell) => flip ? { ...cell, x: frame.x + frame.width - (cell.x - frame.x) - cell.width } : cell;
|
|
6878
7092
|
const bleed = (cell) => {
|
|
6879
7093
|
const near = (a, b) => Math.abs(a - b) < 0.01;
|
|
6880
|
-
const left = near(cell.x, frame.x) ?
|
|
6881
|
-
const right = near(cell.x + cell.width, frame.x + frame.width) ?
|
|
6882
|
-
const bottom = near(cell.y + cell.height, frame.y + frame.height) ?
|
|
7094
|
+
const left = near(cell.x, frame.x) ? area2.left : cell.x, top = near(cell.y, frame.y) ? area2.top : cell.y;
|
|
7095
|
+
const right = near(cell.x + cell.width, frame.x + frame.width) ? area2.right : cell.x + cell.width;
|
|
7096
|
+
const bottom = near(cell.y + cell.height, frame.y + frame.height) ? area2.bottom : cell.y + cell.height;
|
|
6883
7097
|
return { x: left, y: top, width: right - left, height: bottom - top };
|
|
6884
7098
|
};
|
|
6885
7099
|
const placeHeadings = (name, fields2) => {
|
|
@@ -6915,9 +7129,9 @@ function composeSlide(input, options = {}) {
|
|
|
6915
7129
|
const slideComposition = record8(slide.composition);
|
|
6916
7130
|
const overridden = ["mode", "columns", "weights"].some((key) => slideComposition[key] !== void 0) ? plan2.regions.find((region) => region.role === "primary" && region.flow !== "none")?.name : void 0;
|
|
6917
7131
|
const settings = { ...composition };
|
|
6918
|
-
const placeRegion = (region, units,
|
|
7132
|
+
const placeRegion = (region, units, area3) => {
|
|
6919
7133
|
regionTag = region.name === BELOW ? void 0 : region.name;
|
|
6920
|
-
const cell = { ...
|
|
7134
|
+
const cell = { ...area3, width: Math.max(scale, area3.width), height: Math.max(scale, area3.height) };
|
|
6921
7135
|
templateCell = true;
|
|
6922
7136
|
try {
|
|
6923
7137
|
const cards = hasCards && !region.bleed;
|
|
@@ -7065,4 +7279,4 @@ function resolveCanvasDimensions(input) {
|
|
|
7065
7279
|
return { width, height };
|
|
7066
7280
|
}
|
|
7067
7281
|
|
|
7068
|
-
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_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, HEADING_AREAS, LANGUAGES, LAYOUT_BODY_KINDS, LOGO_SHAPES, MAX_COMPOSITION_DEPTH, MAX_NUMBERING_LEVELS, MAX_NUMBERING_VALUE, MAX_REGION_BLOCKS, MAX_ROMAN_VALUE, MAX_TEMPLATE_TRACKS, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, 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, bindRegions, blockKind, captionSettings, catalogGroupDeclared, catalogGroupSource, catalogKinds, catalogRecords, catalogReferenceSites, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, checkCatalogsOption, citationMarkerText, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, 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, isDarkColor, isDatasetRef, isLayoutTemplate, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutRegion, layoutStructure, layoutTable, layoutTemplate, layoutTemplateIssues, layoutTimeline, layoutWatermark, listBuiltinVariables, listColumnBreaks, listNumbers, listVariables, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, parseReference, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, placedImageBlocks, pointerPath, promotedRegionKeys, provenanceOf, readingRows, recordReferenceSites, referencesSlide, regionAccepts, regionRoleRank, registeredCatalog, resolveCanvasDimensions, 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, suggestChartNumberFix, surfaceAltColor, tableCellDisplayValue, tableGrid, tableRowBoundaries, textColorForFill, textWidthMeasurer, timelineMarkerShapes, timelineTextColor, toExcelNumberFormat, tokenizeCode, unresolvedReference, unusedDatasets, usesSlideBuiltin, variableDeclarations, visitContentPayloads, visualReadingOrder, walkCitationRuns, wrapText };
|
|
7282
|
+
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_ROMAN_VALUE, MAX_TEMPLATE_TRACKS, METRIC_TREND_MIN_CONTRAST, METRIC_TREND_SHAPES, 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, bindRegions, blockKind, captionSettings, catalogGroupDeclared, catalogGroupSource, catalogKinds, catalogRecords, catalogReferenceSites, chartColorForFill, chartHighlightColors, chartHighlightMarks, chartLabelText, chartNumber, chartNumberFixesByCell, chartOptionSupport, chartOptionTarget, chartPaletteForFill, chartSeriesPalette, chartTextSize, chartValueAxis, checkCatalogsOption, citationMarkerText, codeHighlightBands, codeHighlightColors, codeHighlightLines, codeHighlightSlice, codeLineNumbers, codeLineRuns, codeSyntaxPalette, codeSyntaxPaletteForScheme, coerceVariableValue, collectCitations, colorContrast, 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, isDarkColor, isDatasetRef, isLayoutTemplate, isRecord, isTemplate, isXYChartType, layoutCaption, layoutCode, layoutContent, layoutFootnotes, layoutFurniture, layoutMetric, layoutQuote, layoutRegion, layoutStructure, layoutTable, layoutTemplate, layoutTemplateIssues, layoutTimeline, layoutWatermark, listBuiltinVariables, listColumnBreaks, listNumbers, listVariables, maxIntervalsFor, measureText, measureTextOutline, metricTrendColor, metricTrendMark, metricTrendPoints, niceScale, normalizeHexColor, normalizeLanguageFamily, numberFormatError, numberingAtLevel, numberingFindings, numberingStyleDraws, paragraphDirection, paragraphDirectionAt, parseReference, pathFor, patternBitmap, patternRuns, physicalAlignment, placeTextLines, placedImageBlocks, pointerPath, promotedRegionKeys, provenanceOf, 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 };
|