gutterpress 0.11.17-alpha.4 → 0.11.17-alpha.6
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/api/index.js +2 -2
- package/dist/{build-fam0tqg6.js → build-yswp3npj.js} +4 -4
- package/dist/{cli-8apk8571.js → cli-0wtnw98y.js} +1 -1
- package/dist/{cli-2kc34kme.js → cli-an3pxzzk.js} +77 -110
- package/dist/{cli-pqcb2nnb.js → cli-jjbeqx94.js} +1 -1
- package/dist/{cli-jyy9pqf3.js → cli-ycbg7mxk.js} +5 -5
- package/dist/cli.js +12 -12
- package/dist/{components-dhgv2sm7.yaml → components-zzqdpt3m.yaml} +1 -1
- package/dist/{doctor-zre5k5fg.js → doctor-xjgxr88y.js} +2 -2
- package/dist/{engine-3xqgm82d.js → engine-5d1rpxxq.js} +2 -2
- package/dist/{engine-zdb41ay1.js → engine-yf2w9hj7.js} +1 -1
- package/dist/{ext-hfqcg6ax.js → ext-n664e0ka.js} +4 -4
- package/dist/favicon-272ga6y0.ico +0 -0
- package/dist/{gutterpress-viewer-1n793gwd.js → gutterpress-viewer-ez7k4ha7.js} +19 -1
- package/dist/{index-hrx0gfkj.js → index-09h3n36d.js} +2 -2
- package/dist/{index-gp503ze9.js → index-2vd5b3vy.js} +76 -109
- package/dist/{index-q1xqxrh9.js → index-vmcfahe2.js} +4 -4
- package/dist/index.js +3 -3
- package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
- package/dist/lib/markdown/markers.d.ts +14 -6
- package/dist/{new-bjdf7bhg.js → new-8xwac8nd.js} +4 -4
- package/dist/{page-templates-7md4ev7d.css → page-templates-tx9ryt19.css} +4 -11
- package/dist/{preflight-gvw01661.js → preflight-62c2r37w.js} +4 -4
- package/dist/{preview-1cschq8s.js → preview-qdby30fx.js} +4 -4
- package/dist/{publish-ddqrb8s9.js → publish-v9tdq7kc.js} +4 -4
- package/dist/render.js +73 -106
- package/dist/{validate-3hjkgxrz.js → validate-9nszbckg.js} +4 -4
- package/package.json +1 -1
- package/dist/favicon-wkbm9cjn.ico +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getAssetsDir,
|
|
10
10
|
lastPageMode,
|
|
11
11
|
parseSize
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-vmcfahe2.js";
|
|
13
13
|
import {
|
|
14
14
|
INSTALL_HINTS,
|
|
15
15
|
execCapture,
|
|
@@ -1129,6 +1129,16 @@ function resolveContainerShape(name, pluginName, decl) {
|
|
|
1129
1129
|
...check
|
|
1130
1130
|
};
|
|
1131
1131
|
}
|
|
1132
|
+
function presetVariantOf(name, pluginName, rawDecl) {
|
|
1133
|
+
const preset = rawDecl.preset !== undefined ? rawDecl.preset : {};
|
|
1134
|
+
if (typeof preset !== "object" || preset === null || Array.isArray(preset)) {
|
|
1135
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`preset\` that is not a plain object.`);
|
|
1136
|
+
}
|
|
1137
|
+
if (preset.variant !== undefined && typeof preset.variant !== "string") {
|
|
1138
|
+
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`preset.variant\` that is not a string.`);
|
|
1139
|
+
}
|
|
1140
|
+
return preset.variant;
|
|
1141
|
+
}
|
|
1132
1142
|
function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
|
|
1133
1143
|
const pluginName = originOf.get(name);
|
|
1134
1144
|
if (typeof rawDecl !== "object" || rawDecl === null || Array.isArray(rawDecl)) {
|
|
@@ -1157,22 +1167,22 @@ function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
|
|
|
1157
1167
|
if (targetRaw.alias !== undefined) {
|
|
1158
1168
|
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" aliases "@${rawDecl.alias}", which is itself an alias. ` + `Chained aliases are not supported — alias the base marker directly.`);
|
|
1159
1169
|
}
|
|
1160
|
-
const preset = rawDecl.preset !== undefined ? rawDecl.preset : {};
|
|
1161
|
-
if (typeof preset !== "object" || preset === null || Array.isArray(preset)) {
|
|
1162
|
-
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`preset\` that is not a plain object.`);
|
|
1163
|
-
}
|
|
1164
|
-
if (preset.variant !== undefined && typeof preset.variant !== "string") {
|
|
1165
|
-
throw new Error(`Plugin "${pluginName}"'s marker "@${name}" has a \`preset.variant\` that is not a string.`);
|
|
1166
|
-
}
|
|
1167
1170
|
const container = resolveContainerShape(rawDecl.alias, originOf.get(rawDecl.alias), targetRaw);
|
|
1168
|
-
return { name, baseKind: rawDecl.alias, presetVariant:
|
|
1171
|
+
return { name, baseKind: rawDecl.alias, presetVariant: presetVariantOf(name, pluginName, rawDecl), ...container };
|
|
1169
1172
|
}
|
|
1170
|
-
|
|
1173
|
+
const presetVariant = presetVariantOf(name, pluginName, rawDecl);
|
|
1174
|
+
return {
|
|
1175
|
+
name,
|
|
1176
|
+
baseKind: name,
|
|
1177
|
+
...presetVariant !== undefined ? { presetVariant } : {},
|
|
1178
|
+
...resolveContainerShape(name, pluginName, rawDecl)
|
|
1179
|
+
};
|
|
1171
1180
|
}
|
|
1172
1181
|
var CORE_MARKER_OWNER = "Gutterpress";
|
|
1173
1182
|
var CORE_DECLARED_MARKERS = {
|
|
1174
1183
|
columns: {
|
|
1175
1184
|
class: "gp-columns",
|
|
1185
|
+
preset: { variant: "2" },
|
|
1176
1186
|
variants: { 1: "gp-columns-1", 2: "gp-columns-2", 3: "gp-columns-3", 4: "gp-columns-4", 5: "gp-columns-5" }
|
|
1177
1187
|
}
|
|
1178
1188
|
};
|
|
@@ -1348,20 +1358,35 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1348
1358
|
const at = declaredFrameIndex(kind);
|
|
1349
1359
|
if (at === -1)
|
|
1350
1360
|
return false;
|
|
1351
|
-
|
|
1352
|
-
const frame = declaredFrames.pop();
|
|
1353
|
-
out.push(new state.Token("layout_component_close", frame.tag, -1));
|
|
1354
|
-
}
|
|
1361
|
+
drainDeclaredFrames(at);
|
|
1355
1362
|
return true;
|
|
1356
1363
|
}
|
|
1357
|
-
function
|
|
1358
|
-
|
|
1364
|
+
function sectionAbove(length) {
|
|
1365
|
+
const section = stack.get("section");
|
|
1366
|
+
return !!section && section.inColumns && declaredFrameIndex("columns") === length - 1;
|
|
1367
|
+
}
|
|
1368
|
+
function sectionHostDepth() {
|
|
1369
|
+
const section = stack.get("section");
|
|
1370
|
+
if (section && !section.inColumns)
|
|
1371
|
+
return 0;
|
|
1372
|
+
return declaredFrameIndex("columns") + 1;
|
|
1373
|
+
}
|
|
1374
|
+
function drainDeclaredFrames(keep = 0) {
|
|
1375
|
+
while (declaredFrames.length > keep) {
|
|
1376
|
+
if (sectionAbove(declaredFrames.length)) {
|
|
1377
|
+
stack.close("section");
|
|
1378
|
+
continue;
|
|
1379
|
+
}
|
|
1359
1380
|
const frame = declaredFrames.pop();
|
|
1360
1381
|
out.push(new state.Token("layout_component_close", frame.tag, -1));
|
|
1361
1382
|
}
|
|
1362
1383
|
}
|
|
1363
1384
|
function drainDeclaredFramesAtEof() {
|
|
1364
1385
|
while (declaredFrames.length) {
|
|
1386
|
+
if (sectionAbove(declaredFrames.length)) {
|
|
1387
|
+
stack.close("section");
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1365
1390
|
const frame = declaredFrames.pop();
|
|
1366
1391
|
if (!frame.decl.autoCloseAtEof) {
|
|
1367
1392
|
warn(state.env, frame.line || 0, "declared_marker_eof_close", `An open @${frame.kind} reached end-of-document; closing it automatically. Add ` + `@end-${frame.kind} to close it explicitly, or declare autoCloseAt: ["eof"] on this ` + `marker if running to end-of-document is expected.`, null);
|
|
@@ -1505,7 +1530,7 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1505
1530
|
__component: { component: meta.kind, kind: decl.baseKind, variant, attrs }
|
|
1506
1531
|
};
|
|
1507
1532
|
}
|
|
1508
|
-
function openSection(meta) {
|
|
1533
|
+
function openSection(meta, inColumns = false) {
|
|
1509
1534
|
const t = new state.Token("layout_section_open", "div", 1);
|
|
1510
1535
|
const component = meta.__component || null;
|
|
1511
1536
|
addClasses(t, "section", meta.attrs && meta.attrs.class ? meta.attrs.class : "");
|
|
@@ -1518,25 +1543,11 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1518
1543
|
kind: "section",
|
|
1519
1544
|
classes: meta.attrs && meta.attrs.class || "",
|
|
1520
1545
|
sawContent: false,
|
|
1546
|
+
...inColumns ? { inColumns: true } : {},
|
|
1521
1547
|
meta: { name: meta.name || null, attrs: { ...meta.attrs || {} }, component },
|
|
1522
1548
|
openToken: t
|
|
1523
1549
|
}, t);
|
|
1524
1550
|
}
|
|
1525
|
-
function breakHost() {
|
|
1526
|
-
return stack.get("section") || stack.get("page") || stack.get("spread");
|
|
1527
|
-
}
|
|
1528
|
-
function gridClassOf(frame) {
|
|
1529
|
-
if (!frame || !frame.classes)
|
|
1530
|
-
return null;
|
|
1531
|
-
return frame.classes.split(/\s+/).find((c) => c.startsWith("gp-grid-")) || null;
|
|
1532
|
-
}
|
|
1533
|
-
function warnBreakInsideGrid(kind, line, meta) {
|
|
1534
|
-
const host = breakHost();
|
|
1535
|
-
const gridClass = gridClassOf(host);
|
|
1536
|
-
if (!gridClass)
|
|
1537
|
-
return;
|
|
1538
|
-
warn(state.env, line, "break_inside_grid", `@${kind} inside a grid container: the enclosing @${host.kind} carries .${gridClass}, so this break's <div> becomes a grid ITEM — it takes a cell of its own, corrupts the grid's placement, and print and the live preview then disagree about which page the content after it lands on. Move the break outside the grid @${host.kind}, or remove it — grid rows already flow and fragment across pages on their own.`, meta);
|
|
1539
|
-
}
|
|
1540
1551
|
function warnIfEmptyDecoratedSection(closingKind, closingLine) {
|
|
1541
1552
|
const sec = stack.get("section");
|
|
1542
1553
|
if (!sec || sec.sawContent)
|
|
@@ -1601,14 +1612,15 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1601
1612
|
continue;
|
|
1602
1613
|
}
|
|
1603
1614
|
if (kind === "section") {
|
|
1604
|
-
|
|
1615
|
+
const keep = sectionHostDepth();
|
|
1616
|
+
drainDeclaredFrames(keep);
|
|
1605
1617
|
warnIfEmptyDecoratedSection("section", line);
|
|
1606
1618
|
stack.close("section");
|
|
1607
1619
|
const spread = stack.get("spread");
|
|
1608
1620
|
if (spread && spread.noPagesYet) {
|
|
1609
1621
|
warn(state.env, line, "spread_without_pages", "@section inside a spread without an explicit @page. Allowed (adhoc spread), but explicit @page markers give stronger control.", meta);
|
|
1610
1622
|
}
|
|
1611
|
-
openSection(meta);
|
|
1623
|
+
openSection(meta, keep > 0);
|
|
1612
1624
|
continue;
|
|
1613
1625
|
}
|
|
1614
1626
|
if (kind === "continue") {
|
|
@@ -1617,7 +1629,8 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1617
1629
|
warn(state.env, line, "continue_without_section", "@continue used without an open @section; ignoring marker.", meta);
|
|
1618
1630
|
continue;
|
|
1619
1631
|
}
|
|
1620
|
-
|
|
1632
|
+
const keep = sectionHostDepth();
|
|
1633
|
+
drainDeclaredFrames(keep);
|
|
1621
1634
|
const contMeta = {
|
|
1622
1635
|
name: section.meta.name,
|
|
1623
1636
|
attrs: { ...section.meta.attrs || {} }
|
|
@@ -1632,11 +1645,10 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1632
1645
|
cls.push("gp-continued");
|
|
1633
1646
|
contMeta.attrs.class = cls.join(" ");
|
|
1634
1647
|
stack.close("section");
|
|
1635
|
-
openSection(contMeta);
|
|
1648
|
+
openSection(contMeta, keep > 0);
|
|
1636
1649
|
continue;
|
|
1637
1650
|
}
|
|
1638
1651
|
if (kind === "page-break") {
|
|
1639
|
-
warnBreakInsideGrid("page-break", line, meta);
|
|
1640
1652
|
const t = new state.Token("layout_page_break", "div", 0);
|
|
1641
1653
|
t.meta = { line };
|
|
1642
1654
|
t.attrSet("class", "gp-page-break");
|
|
@@ -1645,7 +1657,6 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1645
1657
|
continue;
|
|
1646
1658
|
}
|
|
1647
1659
|
if (kind === "column-break") {
|
|
1648
|
-
warnBreakInsideGrid("column-break", line, meta);
|
|
1649
1660
|
const t = new state.Token("layout_column_break", "div", 0);
|
|
1650
1661
|
t.meta = { line };
|
|
1651
1662
|
t.attrSet("class", "gp-column-break");
|
|
@@ -1654,7 +1665,7 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1654
1665
|
continue;
|
|
1655
1666
|
}
|
|
1656
1667
|
if (kind === "end-section") {
|
|
1657
|
-
drainDeclaredFrames();
|
|
1668
|
+
drainDeclaredFrames(sectionHostDepth());
|
|
1658
1669
|
warnIfEmptyDecoratedSection("end-section", line);
|
|
1659
1670
|
stack.close("section");
|
|
1660
1671
|
continue;
|
|
@@ -1752,11 +1763,20 @@ body { margin: 0; }
|
|
|
1752
1763
|
.gp-column-break { break-after: column; height: 0; font-size: 0; line-height: 0; visibility: hidden; }
|
|
1753
1764
|
|
|
1754
1765
|
:where(h1,h2,h3,h4,h5,h6) { break-after: avoid; }
|
|
1766
|
+
/* A lead-in paragraph ("**ROLL A DIE!**" above a roll table, "You will need:"
|
|
1767
|
+
above a list) stays with the table or list it introduces, the way a heading
|
|
1768
|
+
stays with what follows it -- otherwise the label can end a column or page
|
|
1769
|
+
with its table starting on the next (#370). Standard break-after; the
|
|
1770
|
+
:has() selector is Chromium's own. :where() keeps specificity at zero so an
|
|
1771
|
+
author rule such as p { break-after: auto } wins. Deliberately table/ul/ol only,
|
|
1772
|
+
also when a @section wraps it (the second rule): the lead-in then keeps with
|
|
1773
|
+
the section that opens with the table or list. */
|
|
1774
|
+
:where(p):has(+ :where(table, ul, ol)) { break-after: avoid; }
|
|
1775
|
+
:where(p):has(+ :where(.section) > :where(table, ul, ol):first-child) { break-after: avoid; }
|
|
1755
1776
|
:where(img, svg, video) { max-width: 100%; }
|
|
1756
1777
|
:where(p > img:only-child, figure > img) { width: fit-content; max-width: 100%; height: auto; vertical-align: bottom; }
|
|
1757
1778
|
:where(p) > :where(img:not([class])) { max-height: calc(var(--gp-content-h) - 4px); object-fit: contain; }
|
|
1758
1779
|
:where(figure) { break-inside: avoid; }
|
|
1759
|
-
:where(.section, figure) > :where(:first-child) { break-before: avoid; }
|
|
1760
1780
|
|
|
1761
1781
|
`;
|
|
1762
1782
|
|
|
@@ -1816,26 +1836,24 @@ var GUTTERPRESS_CSS = `
|
|
|
1816
1836
|
.gp-tight { --gp-gap: 0.5em; }
|
|
1817
1837
|
.gp-loose { --gp-gap: 2em; }
|
|
1818
1838
|
|
|
1819
|
-
/* column runs — plain CSS Multi-column,
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
every author who opens a section just to start a column run a panel they
|
|
1824
|
-
did not ask for, and the book then needs a reset rule to take it back.
|
|
1825
|
-
With a neutral primitive the author opts into columns and nothing else.
|
|
1839
|
+
/* column runs — plain CSS Multi-column, emitted by the core @columns marker
|
|
1840
|
+
(markers.js): @columns [1-5] ... @end-columns is the ONE way to lay
|
|
1841
|
+
content out in columns, and @column-break moves to the next column.
|
|
1842
|
+
The classes below are the CSS that marker emits, not author vocabulary.
|
|
1826
1843
|
|
|
1827
1844
|
Permanent vocabulary, not a shim: Chromium implements multicol natively
|
|
1828
1845
|
and these rules are the standard properties verbatim, so there is no
|
|
1829
1846
|
spec gap here to remove later. Deliberately minimal — column-fill is
|
|
1830
|
-
NOT set
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
wins because it comes later at the same specificity. */
|
|
1837
|
-
.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {
|
|
1847
|
+
NOT set (the CSS initial balance applies).
|
|
1848
|
+
Themes style a run through two tokens instead of writing column rules:
|
|
1849
|
+
--gp-column-gap default 1.5em
|
|
1850
|
+
--gp-column-rule default none (any column-rule shorthand value)
|
|
1851
|
+
Both hooks sit at zero specificity (:where), so any author rule wins.
|
|
1852
|
+
.gp-columns is two columns on its own; a count class (bare @columns
|
|
1853
|
+
emits gp-columns-2) wins because it comes later at the same specificity. */
|
|
1854
|
+
:where(.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5) {
|
|
1838
1855
|
column-gap: var(--gp-column-gap, 1.5em);
|
|
1856
|
+
column-rule: var(--gp-column-rule, none);
|
|
1839
1857
|
}
|
|
1840
1858
|
.gp-columns { columns: 2; }
|
|
1841
1859
|
.gp-columns-1 { columns: 1; }
|
|
@@ -1844,54 +1862,8 @@ var GUTTERPRESS_CSS = `
|
|
|
1844
1862
|
.gp-columns-4 { columns: 4; }
|
|
1845
1863
|
.gp-columns-5 { columns: 5; }
|
|
1846
1864
|
|
|
1847
|
-
/* the per-shape decisions the paragraph above deliberately leaves to the
|
|
1848
|
-
author, named instead of left as raw CSS every book was reinventing
|
|
1849
|
-
(CLAUDE.md §0: "behavior broadly useful to non-technical authors belongs
|
|
1850
|
-
in core").
|
|
1851
|
-
Permanent vocabulary, standard properties verbatim — same rationale as
|
|
1852
|
-
the column/grid runs above. One name each, no aliases:
|
|
1853
|
-
.gp-columns-all column-span: all a heading or block that
|
|
1854
|
-
spans every column in the
|
|
1855
|
-
run it sits inside.
|
|
1856
|
-
.gp-columns-flow column-fill: auto a run that FRAGMENTS across
|
|
1857
|
-
pages — every page's
|
|
1858
|
-
columns fill instead of
|
|
1859
|
-
only the last one
|
|
1860
|
-
balancing (the dead-column
|
|
1861
|
-
collapse the build's
|
|
1862
|
-
engine.multicol.dead-column
|
|
1863
|
-
warning names this fix
|
|
1864
|
-
for).
|
|
1865
|
-
.gp-columns-balanced column-fill: balance a run that fits on ONE
|
|
1866
|
-
page (the CSS initial
|
|
1867
|
-
value — ragged columns
|
|
1868
|
-
would be wrong here). */
|
|
1869
|
-
.gp-columns-all { column-span: all; }
|
|
1870
|
-
.gp-columns-flow { column-fill: auto; }
|
|
1871
|
-
.gp-columns-balanced { column-fill: balance; }
|
|
1872
|
-
|
|
1873
|
-
/* grid runs — the SLOTTED counterpart to the column runs above. Grid places
|
|
1874
|
-
each child into the next cell, across then down (deterministic slots: card
|
|
1875
|
-
layouts, stat blocks, image-plus-caption pairs); columns FLOW one text run
|
|
1876
|
-
down then across. Same neutral-primitive rationale as .gp-columns-*, and
|
|
1877
|
-
permanent vocabulary for the same reason: standard CSS Grid verbatim, no
|
|
1878
|
-
spec gap to remove later. MEASURED (Chromium 151, gp-grid evidence pack):
|
|
1879
|
-
grid rows fragment across sheets with EXACT print/viewer parity — 2- and
|
|
1880
|
-
3-col, unequal item heights, mid-row cuts, multi-sheet overflow,
|
|
1881
|
-
break-inside:avoid, gap geometry — so a grid taller than the page is safe,
|
|
1882
|
-
no fit-one-page constraint. Two things to know, not fix:
|
|
1883
|
-
- on a min-height page root (MARKER_CSS), default align-content
|
|
1884
|
-
stretches rows apart to fill the page — identically in both engines.
|
|
1885
|
-
Authors wanting packed rows set align-content: start.
|
|
1886
|
-
- a @page-break / @column-break marker DIRECTLY inside a grid container
|
|
1887
|
-
becomes a grid item and corrupts placement (the one measured parity
|
|
1888
|
-
break); markers.js diagnoses it (break_inside_grid).
|
|
1889
|
-
--gp-grid-gap is author-settable. */
|
|
1890
|
-
.gp-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gp-grid-gap, 1.5em); }
|
|
1891
|
-
.gp-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gp-grid-gap, 1.5em); }
|
|
1892
|
-
|
|
1893
1865
|
/* fragmentation controls — generic pagination utilities for any element,
|
|
1894
|
-
independent of the column
|
|
1866
|
+
independent of the column vocabulary above (a book reached for
|
|
1895
1867
|
these just as often outside a multicol run: keeping a card whole,
|
|
1896
1868
|
forcing a section to start a fresh page). Standard properties only —
|
|
1897
1869
|
this project is Chromium-only (CLAUDE.md), so there are no legacy
|
|
@@ -2049,13 +2021,8 @@ var GP_CLASSES = new Set([
|
|
|
2049
2021
|
"gp-columns-3",
|
|
2050
2022
|
"gp-columns-4",
|
|
2051
2023
|
"gp-columns-5",
|
|
2052
|
-
"gp-columns-all",
|
|
2053
|
-
"gp-columns-flow",
|
|
2054
|
-
"gp-columns-balanced",
|
|
2055
2024
|
"gp-no-break",
|
|
2056
2025
|
"gp-break-before",
|
|
2057
|
-
"gp-grid-2",
|
|
2058
|
-
"gp-grid-3",
|
|
2059
2026
|
"gp-shape",
|
|
2060
2027
|
"gp-pin",
|
|
2061
2028
|
"gp-top",
|
|
@@ -5674,7 +5641,7 @@ import git from "isomorphic-git";
|
|
|
5674
5641
|
// package.json
|
|
5675
5642
|
var package_default = {
|
|
5676
5643
|
name: "gutterpress",
|
|
5677
|
-
version: "0.11.17-alpha.
|
|
5644
|
+
version: "0.11.17-alpha.6",
|
|
5678
5645
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5679
5646
|
author: "itlackey",
|
|
5680
5647
|
license: "MPL-2.0",
|
|
@@ -10230,7 +10197,7 @@ class PdfOutput {
|
|
|
10230
10197
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
10231
10198
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
10232
10199
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
10233
|
-
const { buildNativePdf } = await import("./engine-
|
|
10200
|
+
const { buildNativePdf } = await import("./engine-5d1rpxxq.js");
|
|
10234
10201
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
10235
10202
|
title: config.title,
|
|
10236
10203
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -145,7 +145,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
145
145
|
import { fileURLToPath } from "node:url";
|
|
146
146
|
|
|
147
147
|
// src/assets/favicon.ico
|
|
148
|
-
var favicon_default = "./favicon-
|
|
148
|
+
var favicon_default = "./favicon-272ga6y0.ico";
|
|
149
149
|
|
|
150
150
|
// src/assets/manifest.schema.json
|
|
151
151
|
var manifest_schema_default = "./manifest.schema-gh0jjve9.json";
|
|
@@ -163,7 +163,7 @@ var preview_shell_default = "./preview-shell-xwn84kqr.js";
|
|
|
163
163
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
164
164
|
|
|
165
165
|
// src/assets/engine/gutterpress-viewer.js
|
|
166
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
166
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-ez7k4ha7.js";
|
|
167
167
|
|
|
168
168
|
// src/assets/engine/gutterpress-agent.js
|
|
169
169
|
var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
|
|
@@ -217,7 +217,7 @@ var package_default2 = "./package-aenwjew3.json";
|
|
|
217
217
|
var README_default2 = "./README-3nj919rm.md";
|
|
218
218
|
|
|
219
219
|
// src/assets/extension-templates/theme/components.yaml
|
|
220
|
-
var components_default = "./components-
|
|
220
|
+
var components_default = "./components-zzqdpt3m.yaml";
|
|
221
221
|
|
|
222
222
|
// src/assets/extension-templates/theme/snippets/callout.md
|
|
223
223
|
var callout_default = "./callout-hv56m16h.md";
|
|
@@ -232,7 +232,7 @@ var base_default = "./base-ypqh9n7f.css";
|
|
|
232
232
|
var components_default2 = "./components-aam0fe2z.css";
|
|
233
233
|
|
|
234
234
|
// src/assets/extension-templates/theme/styles/page-templates.css
|
|
235
|
-
var page_templates_default = "./page-templates-
|
|
235
|
+
var page_templates_default = "./page-templates-tx9ryt19.css";
|
|
236
236
|
|
|
237
237
|
// src/assets/extension-templates/theme/styles/page-rules.css
|
|
238
238
|
var page_rules_default = "./page-rules-nsj3aw42.css";
|
package/dist/index.js
CHANGED
|
@@ -152,14 +152,14 @@ import {
|
|
|
152
152
|
testRemoteAccess,
|
|
153
153
|
updateExtensions,
|
|
154
154
|
validateProjectExtensions
|
|
155
|
-
} from "./index-
|
|
155
|
+
} from "./index-2vd5b3vy.js";
|
|
156
156
|
import"./index-ht1bcqdd.js";
|
|
157
157
|
import {
|
|
158
158
|
BUILD_DIAGNOSTIC_CODES
|
|
159
|
-
} from "./index-
|
|
159
|
+
} from "./index-09h3n36d.js";
|
|
160
160
|
import {
|
|
161
161
|
BuildError
|
|
162
|
-
} from "./index-
|
|
162
|
+
} from "./index-vmcfahe2.js";
|
|
163
163
|
import {
|
|
164
164
|
DEFAULT_PRINT_OPTS,
|
|
165
165
|
assertMilestone,
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
* carrying gp-left could start shifting; that is standards-tracking per
|
|
134
134
|
* CLAUDE.md ("Chrome wins once it ships"), not a bug in the author's book.
|
|
135
135
|
*/
|
|
136
|
-
export declare const GUTTERPRESS_CSS = "\n/* gp-* author image/block vocabulary. One vocabulary, gp-* only \u2014 the\n pre-vocabulary utility names (.center/.float-left/.float-right/\n .full-width/.full-bleed) were REMOVED when gp-* shipped; books rename\n the classes in their markdown (see the migration note). Source ORDER is\n the contract \u2014 see the doctrine comment above. */\n\n/* flow positions */\n.gp-left {\n float: left;\n margin: 0 var(--gp-gap, 1em) var(--gp-gap, 1em) 0;\n max-width: 50%;\n}\n.gp-right {\n float: right;\n margin: 0 0 var(--gp-gap, 1em) var(--gp-gap, 1em);\n max-width: 50%;\n}\n.gp-center {\n display: block;\n float: none;\n margin-left: auto;\n margin-right: auto;\n max-width: 100%;\n}\n.gp-full {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n@page gp-full-bleed { margin-left: 0; margin-right: 0; }\n.gp-bleed {\n display: block;\n float: none;\n break-before: page;\n page: gp-full-bleed;\n max-width: none;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n/* sizes \u2014 AFTER the flow positions so max-width:100% lifts the floats' 50%\n cap at equal specificity */\n.gp-small { width: 25%; max-width: 100%; }\n.gp-medium { width: 50%; max-width: 100%; }\n.gp-large { width: 75%; max-width: 100%; }\n\n/* float clearance presets \u2014 consumed by var(--gp-gap) in the float rules\n above and by .gp-shape's shape-margin below; --gp-gap itself is\n author-settable CSS */\n.gp-tight { --gp-gap: 0.5em; }\n.gp-loose { --gp-gap: 2em; }\n\n/* column runs \u2014 plain CSS Multi-column, exposed as author vocabulary so\n \"put this in two columns\" does not require borrowing a styled container\n from the book's own component layer. That borrowing is what this exists\n to prevent: a book whose theme paints .section chrome by default gives\n every author who opens a section just to start a column run a panel they\n did not ask for, and the book then needs a reset rule to take it back.\n With a neutral primitive the author opts into columns and nothing else.\n\n Permanent vocabulary, not a shim: Chromium implements multicol natively\n and these rules are the standard properties verbatim, so there is no\n spec gap here to remove later. Deliberately minimal \u2014 column-fill is\n NOT set, because the correct value depends on whether the run fragments\n across pages (auto packs each page's columns; the CSS initial balance is\n right for a run that fits on one page) and only the author knows which.\n --gp-column-gap is author-settable.\n .gp-columns is what the core @columns marker emits (markers.js); on its\n own it is two columns, and @columns 1 to 5 add the matching count, which\n wins because it comes later at the same specificity. */\n.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {\n column-gap: var(--gp-column-gap, 1.5em);\n}\n.gp-columns { columns: 2; }\n.gp-columns-1 { columns: 1; }\n.gp-columns-2 { columns: 2; }\n.gp-columns-3 { columns: 3; }\n.gp-columns-4 { columns: 4; }\n.gp-columns-5 { columns: 5; }\n\n/* the per-shape decisions the paragraph above deliberately leaves to the\n author, named instead of left as raw CSS every book was reinventing\n (CLAUDE.md \u00A70: \"behavior broadly useful to non-technical authors belongs\n in core\").\n Permanent vocabulary, standard properties verbatim \u2014 same rationale as\n the column/grid runs above. One name each, no aliases:\n .gp-columns-all column-span: all a heading or block that\n spans every column in the\n run it sits inside.\n .gp-columns-flow column-fill: auto a run that FRAGMENTS across\n pages \u2014 every page's\n columns fill instead of\n only the last one\n balancing (the dead-column\n collapse the build's\n engine.multicol.dead-column\n warning names this fix\n for).\n .gp-columns-balanced column-fill: balance a run that fits on ONE\n page (the CSS initial\n value \u2014 ragged columns\n would be wrong here). */\n.gp-columns-all { column-span: all; }\n.gp-columns-flow { column-fill: auto; }\n.gp-columns-balanced { column-fill: balance; }\n\n/* grid runs \u2014 the SLOTTED counterpart to the column runs above. Grid places\n each child into the next cell, across then down (deterministic slots: card\n layouts, stat blocks, image-plus-caption pairs); columns FLOW one text run\n down then across. Same neutral-primitive rationale as .gp-columns-*, and\n permanent vocabulary for the same reason: standard CSS Grid verbatim, no\n spec gap to remove later. MEASURED (Chromium 151, gp-grid evidence pack):\n grid rows fragment across sheets with EXACT print/viewer parity \u2014 2- and\n 3-col, unequal item heights, mid-row cuts, multi-sheet overflow,\n break-inside:avoid, gap geometry \u2014 so a grid taller than the page is safe,\n no fit-one-page constraint. Two things to know, not fix:\n - on a min-height page root (MARKER_CSS), default align-content\n stretches rows apart to fill the page \u2014 identically in both engines.\n Authors wanting packed rows set align-content: start.\n - a @page-break / @column-break marker DIRECTLY inside a grid container\n becomes a grid item and corrupts placement (the one measured parity\n break); markers.js diagnoses it (break_inside_grid).\n --gp-grid-gap is author-settable. */\n.gp-grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gp-grid-gap, 1.5em); }\n.gp-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gp-grid-gap, 1.5em); }\n\n/* fragmentation controls \u2014 generic pagination utilities for any element,\n independent of the column/grid vocabulary above (a book reached for\n these just as often outside a multicol run: keeping a card whole,\n forcing a section to start a fresh page). Standard properties only \u2014\n this project is Chromium-only (CLAUDE.md), so there are no legacy\n page-break-* twins to also emit. One name each. */\n.gp-no-break { break-inside: avoid; }\n.gp-break-before { break-before: page; }\n\n/* shape wrap \u2014 text follows the image's alpha silhouette instead of its\n rectangular box. shape-outside only applies to floats, so this is inert\n without .gp-left/.gp-right (and under .gp-pin, which un-floats). The\n shape URL cannot be written in CSS (url() contexts can't read attr()),\n so the image renderer rule (images.ts) mirrors the src into an inline\n --gp-shape:url(...) custom property whenever it sees this class --\n authors only ever type the class. threshold 0.2 ignores near-transparent\n anti-aliasing halos; shape-margin shares the float-gap vocabulary. */\nimg.gp-shape {\n shape-outside: var(--gp-shape);\n shape-image-threshold: 0.2;\n shape-margin: var(--gp-gap, 1em);\n}\n\n/* pin \u2014 within the nearest positioned ancestor (.page/.spread, rule above).\n inset:0 and the explicit centers are load-bearing; see doctrine comment. */\n.gp-pin {\n position: absolute;\n inset: 0;\n align-self: center;\n justify-self: center;\n margin: 0;\n max-width: 100%;\n}\n\n/* pin edge modifiers \u2014 AFTER .gp-pin to beat its center defaults;\n justify-self is inert on in-flow floats, so gp-left/gp-right safely do\n double duty as flow float + pin edge */\n.gp-top { align-self: start; }\n.gp-bottom { align-self: end; }\n.gp-left { justify-self: start; }\n.gp-right { justify-self: end; }\n\n/* wrapper-margin neutralization (same pattern and rationale as the\n .gp-bleed paragraph-margin note in the doctrine comment; for pin, the\n emptied paragraph would otherwise leave a phantom margin gap in flow) */\n:where(p:has(> img.gp-bleed:only-child)) { margin: 0; }\n:where(p:has(> img.gp-pin:only-child)) { margin: 0; }\n\n/* depth \u2014 a named ladder for z-index, so books stop hand-tuning bare\n integers. A real book measured 21 z-index declarations using only four\n distinct values (-1, 0, 1, 2), each written literally at its use site.\n The custom properties are the author-settable surface (a book needing a\n deeper stack raises them once); the classes are the shorthand.\n\n NOT named \"layer\": CSS Paged Media 3 \u00A73.1 already defines \"page layers\"\n (page background, canvas, borders, contents, margin boxes) and those are\n parts of the PAGE BOX, not a z-ladder for content. Reusing the word for a\n different concept would collide with the spec vocabulary this project\n tracks. The pin EDGE modifiers already own .gp-top/.gp-bottom, so the\n ladder avoids those words too.\n\n .gp-behind is the one that earns its place: it puts a pinned image UNDER\n the page's text, which is otherwise impossible to express without a bare\n negative z-index. \"Above\" needs no class \u2014 an out-of-flow pin already\n paints above in-flow content.\n\n Two things silently defeat .gp-behind, neither visible at the use site:\n - a stacking context on the .page/.spread ancestor (z-index, isolation,\n opacity, filter, transform on it traps the negative layer inside).\n Core keeps .page/.spread at 'position: relative; z-index: auto'\n precisely so they are not stacking contexts.\n - a clipping ancestor (overflow other than visible) \u2014 but only where\n the art actually overhangs that ancestor's clip box on a clipped\n axis: the overhang is cut off, the same mechanism that clips a\n .gp-bleed plate back to the wrapper's width. Clipping never reorders\n layers \u2014 within-bounds art under a clipping .page prints whole and\n still behind (measured; see the build audit's comment in\n engine/compiler/build.ts), and a static wrapper's overflow never\n binds an abspos .gp-pin at all.\n The build-time engine.layer.trapped audit reports both against the live\n ancestor chain. printsafe/page-containment is only an early source hint for\n declarations written directly on .page/.spread. */\n:root {\n --gp-z-behind: -1;\n --gp-z-base: 0;\n --gp-z-raised: 1;\n --gp-z-front: 2;\n}\n.gp-behind { z-index: var(--gp-z-behind); }\n.gp-base { z-index: var(--gp-z-base); }\n.gp-raised { z-index: var(--gp-z-raised); }\n.gp-front { z-index: var(--gp-z-front); }\n\n/* GFM-style alert/callout boxes (#237) \u2014 the DOM gfm-alerts.ts emits from\n \"> [!TYPE]\" blockquote syntax when a project opts into the bundled\n gutterpress-gfm-alerts feature (BUILTIN_OPTIONAL_PLUGINS, renderer.ts).\n The plugin is optional and inert by default; these rules are equally\n inert wherever the classes never appear, exactly like every other\n utility above, so shipping them costs nothing to a book that has not\n turned the feature on.\n\n This is authored-COMPONENT vocabulary, not the @marker structural family\n (markers.js/MARKER_CSS) \u2014 CLAUDE.md \u00A76 splits the two core CSS blocks by\n ROLE, and an author-facing box an author invokes via inline syntax is the\n same role as every other gp-* utility here, not page/chapter/section DOM.\n\n Deliberately minimal (CLAUDE.md \"thin over capable\" / the issue's own\n \"a rule and a label\"): a left border plus a bold label, :where()'d to\n zero specificity so a theme's own (unlayered) rule for any of these\n classes wins outright regardless of selector weight \u2014 see the\n cascade-layers note atop this file. Five semantic accent colors (the same\n NOTE/TIP/IMPORTANT/WARNING/CAUTION hues GitHub's own alerts use \u2014 a\n long-established, non-proprietary convention, not DC branding) are\n exposed as :root custom properties, the same author-settable-surface\n pattern as the --gp-z-* ladder above: a book retints every alert of one\n type by overriding a single property, no specificity fight required.\n --gp-alert-color cascades from the type modifier down to .gp-alert-title\n through ordinary CSS inheritance (the title is always a DOM descendant of\n the box), so it is set in exactly five places, not ten. */\n:root {\n --gp-alert-note-color: #0969da;\n --gp-alert-tip-color: #1a7f37;\n --gp-alert-important-color: #8250df;\n --gp-alert-warning-color: #9a6700;\n --gp-alert-caution-color: #cf222e;\n}\n:where(.gp-alert) {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 0.25em solid var(--gp-alert-color, currentColor);\n}\n:where(.gp-alert-title) {\n margin: 0 0 0.5em;\n font-weight: bold;\n color: var(--gp-alert-color, inherit);\n}\n:where(.gp-alert-note) { --gp-alert-color: var(--gp-alert-note-color); }\n:where(.gp-alert-tip) { --gp-alert-color: var(--gp-alert-tip-color); }\n:where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }\n:where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }\n:where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }\n";
|
|
136
|
+
export declare const GUTTERPRESS_CSS = "\n/* gp-* author image/block vocabulary. One vocabulary, gp-* only \u2014 the\n pre-vocabulary utility names (.center/.float-left/.float-right/\n .full-width/.full-bleed) were REMOVED when gp-* shipped; books rename\n the classes in their markdown (see the migration note). Source ORDER is\n the contract \u2014 see the doctrine comment above. */\n\n/* flow positions */\n.gp-left {\n float: left;\n margin: 0 var(--gp-gap, 1em) var(--gp-gap, 1em) 0;\n max-width: 50%;\n}\n.gp-right {\n float: right;\n margin: 0 0 var(--gp-gap, 1em) var(--gp-gap, 1em);\n max-width: 50%;\n}\n.gp-center {\n display: block;\n float: none;\n margin-left: auto;\n margin-right: auto;\n max-width: 100%;\n}\n.gp-full {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n@page gp-full-bleed { margin-left: 0; margin-right: 0; }\n.gp-bleed {\n display: block;\n float: none;\n break-before: page;\n page: gp-full-bleed;\n max-width: none;\n width: 100%;\n margin-left: 0;\n margin-right: 0;\n}\n\n/* sizes \u2014 AFTER the flow positions so max-width:100% lifts the floats' 50%\n cap at equal specificity */\n.gp-small { width: 25%; max-width: 100%; }\n.gp-medium { width: 50%; max-width: 100%; }\n.gp-large { width: 75%; max-width: 100%; }\n\n/* float clearance presets \u2014 consumed by var(--gp-gap) in the float rules\n above and by .gp-shape's shape-margin below; --gp-gap itself is\n author-settable CSS */\n.gp-tight { --gp-gap: 0.5em; }\n.gp-loose { --gp-gap: 2em; }\n\n/* column runs \u2014 plain CSS Multi-column, emitted by the core @columns marker\n (markers.js): @columns [1-5] ... @end-columns is the ONE way to lay\n content out in columns, and @column-break moves to the next column.\n The classes below are the CSS that marker emits, not author vocabulary.\n\n Permanent vocabulary, not a shim: Chromium implements multicol natively\n and these rules are the standard properties verbatim, so there is no\n spec gap here to remove later. Deliberately minimal \u2014 column-fill is\n NOT set (the CSS initial balance applies).\n Themes style a run through two tokens instead of writing column rules:\n --gp-column-gap default 1.5em\n --gp-column-rule default none (any column-rule shorthand value)\n Both hooks sit at zero specificity (:where), so any author rule wins.\n .gp-columns is two columns on its own; a count class (bare @columns\n emits gp-columns-2) wins because it comes later at the same specificity. */\n:where(.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5) {\n column-gap: var(--gp-column-gap, 1.5em);\n column-rule: var(--gp-column-rule, none);\n}\n.gp-columns { columns: 2; }\n.gp-columns-1 { columns: 1; }\n.gp-columns-2 { columns: 2; }\n.gp-columns-3 { columns: 3; }\n.gp-columns-4 { columns: 4; }\n.gp-columns-5 { columns: 5; }\n\n/* fragmentation controls \u2014 generic pagination utilities for any element,\n independent of the column vocabulary above (a book reached for\n these just as often outside a multicol run: keeping a card whole,\n forcing a section to start a fresh page). Standard properties only \u2014\n this project is Chromium-only (CLAUDE.md), so there are no legacy\n page-break-* twins to also emit. One name each. */\n.gp-no-break { break-inside: avoid; }\n.gp-break-before { break-before: page; }\n\n/* shape wrap \u2014 text follows the image's alpha silhouette instead of its\n rectangular box. shape-outside only applies to floats, so this is inert\n without .gp-left/.gp-right (and under .gp-pin, which un-floats). The\n shape URL cannot be written in CSS (url() contexts can't read attr()),\n so the image renderer rule (images.ts) mirrors the src into an inline\n --gp-shape:url(...) custom property whenever it sees this class --\n authors only ever type the class. threshold 0.2 ignores near-transparent\n anti-aliasing halos; shape-margin shares the float-gap vocabulary. */\nimg.gp-shape {\n shape-outside: var(--gp-shape);\n shape-image-threshold: 0.2;\n shape-margin: var(--gp-gap, 1em);\n}\n\n/* pin \u2014 within the nearest positioned ancestor (.page/.spread, rule above).\n inset:0 and the explicit centers are load-bearing; see doctrine comment. */\n.gp-pin {\n position: absolute;\n inset: 0;\n align-self: center;\n justify-self: center;\n margin: 0;\n max-width: 100%;\n}\n\n/* pin edge modifiers \u2014 AFTER .gp-pin to beat its center defaults;\n justify-self is inert on in-flow floats, so gp-left/gp-right safely do\n double duty as flow float + pin edge */\n.gp-top { align-self: start; }\n.gp-bottom { align-self: end; }\n.gp-left { justify-self: start; }\n.gp-right { justify-self: end; }\n\n/* wrapper-margin neutralization (same pattern and rationale as the\n .gp-bleed paragraph-margin note in the doctrine comment; for pin, the\n emptied paragraph would otherwise leave a phantom margin gap in flow) */\n:where(p:has(> img.gp-bleed:only-child)) { margin: 0; }\n:where(p:has(> img.gp-pin:only-child)) { margin: 0; }\n\n/* depth \u2014 a named ladder for z-index, so books stop hand-tuning bare\n integers. A real book measured 21 z-index declarations using only four\n distinct values (-1, 0, 1, 2), each written literally at its use site.\n The custom properties are the author-settable surface (a book needing a\n deeper stack raises them once); the classes are the shorthand.\n\n NOT named \"layer\": CSS Paged Media 3 \u00A73.1 already defines \"page layers\"\n (page background, canvas, borders, contents, margin boxes) and those are\n parts of the PAGE BOX, not a z-ladder for content. Reusing the word for a\n different concept would collide with the spec vocabulary this project\n tracks. The pin EDGE modifiers already own .gp-top/.gp-bottom, so the\n ladder avoids those words too.\n\n .gp-behind is the one that earns its place: it puts a pinned image UNDER\n the page's text, which is otherwise impossible to express without a bare\n negative z-index. \"Above\" needs no class \u2014 an out-of-flow pin already\n paints above in-flow content.\n\n Two things silently defeat .gp-behind, neither visible at the use site:\n - a stacking context on the .page/.spread ancestor (z-index, isolation,\n opacity, filter, transform on it traps the negative layer inside).\n Core keeps .page/.spread at 'position: relative; z-index: auto'\n precisely so they are not stacking contexts.\n - a clipping ancestor (overflow other than visible) \u2014 but only where\n the art actually overhangs that ancestor's clip box on a clipped\n axis: the overhang is cut off, the same mechanism that clips a\n .gp-bleed plate back to the wrapper's width. Clipping never reorders\n layers \u2014 within-bounds art under a clipping .page prints whole and\n still behind (measured; see the build audit's comment in\n engine/compiler/build.ts), and a static wrapper's overflow never\n binds an abspos .gp-pin at all.\n The build-time engine.layer.trapped audit reports both against the live\n ancestor chain. printsafe/page-containment is only an early source hint for\n declarations written directly on .page/.spread. */\n:root {\n --gp-z-behind: -1;\n --gp-z-base: 0;\n --gp-z-raised: 1;\n --gp-z-front: 2;\n}\n.gp-behind { z-index: var(--gp-z-behind); }\n.gp-base { z-index: var(--gp-z-base); }\n.gp-raised { z-index: var(--gp-z-raised); }\n.gp-front { z-index: var(--gp-z-front); }\n\n/* GFM-style alert/callout boxes (#237) \u2014 the DOM gfm-alerts.ts emits from\n \"> [!TYPE]\" blockquote syntax when a project opts into the bundled\n gutterpress-gfm-alerts feature (BUILTIN_OPTIONAL_PLUGINS, renderer.ts).\n The plugin is optional and inert by default; these rules are equally\n inert wherever the classes never appear, exactly like every other\n utility above, so shipping them costs nothing to a book that has not\n turned the feature on.\n\n This is authored-COMPONENT vocabulary, not the @marker structural family\n (markers.js/MARKER_CSS) \u2014 CLAUDE.md \u00A76 splits the two core CSS blocks by\n ROLE, and an author-facing box an author invokes via inline syntax is the\n same role as every other gp-* utility here, not page/chapter/section DOM.\n\n Deliberately minimal (CLAUDE.md \"thin over capable\" / the issue's own\n \"a rule and a label\"): a left border plus a bold label, :where()'d to\n zero specificity so a theme's own (unlayered) rule for any of these\n classes wins outright regardless of selector weight \u2014 see the\n cascade-layers note atop this file. Five semantic accent colors (the same\n NOTE/TIP/IMPORTANT/WARNING/CAUTION hues GitHub's own alerts use \u2014 a\n long-established, non-proprietary convention, not DC branding) are\n exposed as :root custom properties, the same author-settable-surface\n pattern as the --gp-z-* ladder above: a book retints every alert of one\n type by overriding a single property, no specificity fight required.\n --gp-alert-color cascades from the type modifier down to .gp-alert-title\n through ordinary CSS inheritance (the title is always a DOM descendant of\n the box), so it is set in exactly five places, not ten. */\n:root {\n --gp-alert-note-color: #0969da;\n --gp-alert-tip-color: #1a7f37;\n --gp-alert-important-color: #8250df;\n --gp-alert-warning-color: #9a6700;\n --gp-alert-caution-color: #cf222e;\n}\n:where(.gp-alert) {\n margin: 1em 0;\n padding: 0.5em 1em;\n border-left: 0.25em solid var(--gp-alert-color, currentColor);\n}\n:where(.gp-alert-title) {\n margin: 0 0 0.5em;\n font-weight: bold;\n color: var(--gp-alert-color, inherit);\n}\n:where(.gp-alert-note) { --gp-alert-color: var(--gp-alert-note-color); }\n:where(.gp-alert-tip) { --gp-alert-color: var(--gp-alert-tip-color); }\n:where(.gp-alert-important) { --gp-alert-color: var(--gp-alert-important-color); }\n:where(.gp-alert-warning) { --gp-alert-color: var(--gp-alert-warning-color); }\n:where(.gp-alert-caution) { --gp-alert-color: var(--gp-alert-caution-color); }\n";
|
|
137
137
|
/**
|
|
138
138
|
* GP_CLASSES — every class an author may legitimately write with a `gp-`
|
|
139
139
|
* prefix: the `.gp-*` selectors in `GUTTERPRESS_CSS` above, the two
|
|
@@ -91,11 +91,20 @@ export default function plugin(md: any, pluginOptions?: {}): void;
|
|
|
91
91
|
* pinned foot up by less than a point and absorbs sub-pixel rounding in the
|
|
92
92
|
* published value. Do not "clean it up" — the sheet it costs is silent.
|
|
93
93
|
*
|
|
94
|
-
* The break/orphan rules below (`break-after` on headings, image sizing
|
|
95
|
-
*
|
|
94
|
+
* The break/orphan rules below (`break-after` on headings, image sizing)
|
|
95
|
+
* are all `:where()` so they carry zero specificity —
|
|
96
96
|
* author CSS at any specificity wins outright, reusing this same
|
|
97
97
|
* after-author injection point.
|
|
98
98
|
*
|
|
99
|
+
* There is deliberately NO `.section > :first-child { break-before: avoid }`
|
|
100
|
+
* "glue". A first child's break-before propagates to its parent's start
|
|
101
|
+
* edge, so it made the break BEFORE every section `avoid`: a section after
|
|
102
|
+
* other content could not move whole to the next page, and Chromium split it
|
|
103
|
+
* instead, ignoring its own `break-inside: avoid`. Measured with and without
|
|
104
|
+
* (marker-css-section-break.test.ts): it never prevented a stranded top edge
|
|
105
|
+
* or heading. Its one useful side effect, a lead-in paragraph travelling with
|
|
106
|
+
* a following @section that wraps a table, is the explicit rule below.
|
|
107
|
+
*
|
|
99
108
|
* `vertical-align: bottom` on a lone image is a print-correctness rule, not
|
|
100
109
|
* cosmetics. An `<img>` in a `<p>` is inline-level, so its line box adds
|
|
101
110
|
* half-leading/descender space UNDER the image: an image sized to exactly the
|
|
@@ -158,8 +167,7 @@ export default function plugin(md: any, pluginOptions?: {}): void;
|
|
|
158
167
|
* break-inside rule, at ANY specificity, still wins outright.
|
|
159
168
|
*
|
|
160
169
|
* The companion "spanner + unbreakable box" glue pattern (`column-span: all`
|
|
161
|
-
* followed by a `break-inside: avoid` box
|
|
162
|
-
* §5) was measured for this same adoption pass and DELIBERATELY NOT
|
|
170
|
+
* followed by a `break-inside: avoid` box) was measured for this same adoption pass and DELIBERATELY NOT
|
|
163
171
|
* adopted: a `:where()`-zero-specificity override can never win against
|
|
164
172
|
* whatever real-specificity rule gave the box its `break-inside: avoid` in
|
|
165
173
|
* the first place (a synthetic 2-column fixture with the candidate
|
|
@@ -169,7 +177,7 @@ export default function plugin(md: any, pluginOptions?: {}): void;
|
|
|
169
177
|
* a context-blind version of the same idea is actively wrong for at least
|
|
170
178
|
* one real, shipped case (a short, non-fragmenting instance that needed its
|
|
171
179
|
* `avoid` restored after a general fragmenting-context rule took it away).
|
|
172
|
-
*
|
|
180
|
+
* Core ships no spanner class: a spanning heading is the end of one @columns run and the start of the next.
|
|
173
181
|
*
|
|
174
182
|
*/
|
|
175
|
-
export const MARKER_CSS: "\n/* The UA default of 8px body margin is a screen affordance with no meaning\n in paged media, and engines disagree about it: a polyfill that treats the\n page div as the page box drops it, native print keeps it. Left in place it\n insets EVERY page's content by 8px per side, and -- measured, 300dpi,\n 6x4in sheet -- it is what stops a full-width block from reaching the\n paper: it lands at 0.080..5.917in of a 6in sheet instead of\n 0.000..6.000in, because width:100% resolves against the BODY content box,\n not the page's. Zeroing it here (first in the cascade) makes the two\n agree. Authors who want a body margin still just declare one. */\nbody { margin: 0; }\n\n.gp-page-break { break-before: page; }\n.page { break-before: page; }\n.spread { break-before: page; }\n:where(.page, .spread) { position: relative; display: flow-root; box-sizing: border-box; min-height: calc(var(--gp-content-h, 1px) - 1px); }\n.gp-column-break { break-after: column; height: 0; font-size: 0; line-height: 0; visibility: hidden; }\n\n:where(h1,h2,h3,h4,h5,h6) { break-after: avoid; }\n:where(img, svg, video) { max-width: 100%; }\n:where(p > img:only-child, figure > img) { width: fit-content; max-width: 100%; height: auto; vertical-align: bottom; }\n:where(p) > :where(img:not([class])) { max-height: calc(var(--gp-content-h) - 4px); object-fit: contain; }\n:where(figure) { break-inside: avoid; }\n
|
|
183
|
+
export const MARKER_CSS: "\n/* The UA default of 8px body margin is a screen affordance with no meaning\n in paged media, and engines disagree about it: a polyfill that treats the\n page div as the page box drops it, native print keeps it. Left in place it\n insets EVERY page's content by 8px per side, and -- measured, 300dpi,\n 6x4in sheet -- it is what stops a full-width block from reaching the\n paper: it lands at 0.080..5.917in of a 6in sheet instead of\n 0.000..6.000in, because width:100% resolves against the BODY content box,\n not the page's. Zeroing it here (first in the cascade) makes the two\n agree. Authors who want a body margin still just declare one. */\nbody { margin: 0; }\n\n.gp-page-break { break-before: page; }\n.page { break-before: page; }\n.spread { break-before: page; }\n:where(.page, .spread) { position: relative; display: flow-root; box-sizing: border-box; min-height: calc(var(--gp-content-h, 1px) - 1px); }\n.gp-column-break { break-after: column; height: 0; font-size: 0; line-height: 0; visibility: hidden; }\n\n:where(h1,h2,h3,h4,h5,h6) { break-after: avoid; }\n/* A lead-in paragraph (\"**ROLL A DIE!**\" above a roll table, \"You will need:\"\n above a list) stays with the table or list it introduces, the way a heading\n stays with what follows it -- otherwise the label can end a column or page\n with its table starting on the next (#370). Standard break-after; the\n :has() selector is Chromium's own. :where() keeps specificity at zero so an\n author rule such as p { break-after: auto } wins. Deliberately table/ul/ol only,\n also when a @section wraps it (the second rule): the lead-in then keeps with\n the section that opens with the table or list. */\n:where(p):has(+ :where(table, ul, ol)) { break-after: avoid; }\n:where(p):has(+ :where(.section) > :where(table, ul, ol):first-child) { break-after: avoid; }\n:where(img, svg, video) { max-width: 100%; }\n:where(p > img:only-child, figure > img) { width: fit-content; max-width: 100%; height: auto; vertical-align: bottom; }\n:where(p) > :where(img:not([class])) { max-height: calc(var(--gp-content-h) - 4px); object-fit: contain; }\n:where(figure) { break-inside: avoid; }\n\n";
|
|
@@ -7,17 +7,17 @@ import {
|
|
|
7
7
|
TARGET_IDS,
|
|
8
8
|
scaffoldExtension,
|
|
9
9
|
scaffoldProject
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-an3pxzzk.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveGhostscript
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-0wtnw98y.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
rejectExtraPositionals,
|
|
17
17
|
rejectUnknownFlags
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-jjbeqx94.js";
|
|
19
19
|
import"./cli-ht1bcqdd.js";
|
|
20
|
-
import"./cli-
|
|
20
|
+
import"./cli-ycbg7mxk.js";
|
|
21
21
|
import {
|
|
22
22
|
EXIT_CODES
|
|
23
23
|
} from "./cli-46ycxe6r.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* OWNS
|
|
5
5
|
* The layout of a `@page .name` wrapper — how content is arranged WITHIN
|
|
6
|
-
* one page of the book.
|
|
6
|
+
* one page of the book. Full-bleed art, a centred opener.
|
|
7
7
|
*
|
|
8
8
|
* Authored as:
|
|
9
9
|
*
|
|
@@ -43,17 +43,10 @@
|
|
|
43
43
|
max-width: 24em;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/* A
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.page.{{PREFIX}}reference {
|
|
50
|
-
columns: 2;
|
|
51
|
-
column-gap: var(--{{PREFIX}}space-4);
|
|
52
|
-
column-rule: 1px solid var(--{{PREFIX}}rule);
|
|
53
|
-
}
|
|
54
|
-
|
|
46
|
+
/* A reference page. Columns are not a template concern: put the content in
|
|
47
|
+
core's `@columns 2` ... `@end-columns` (and `@column-break`) and core owns
|
|
48
|
+
the column geometry. This template only styles what sits around them. */
|
|
55
49
|
.page.{{PREFIX}}reference h2 {
|
|
56
|
-
column-span: all;
|
|
57
50
|
border-block-end: 1px solid var(--{{PREFIX}}rule);
|
|
58
51
|
padding-block-end: var(--{{PREFIX}}space-1);
|
|
59
52
|
}
|
|
@@ -2,17 +2,17 @@ import {
|
|
|
2
2
|
executeValidation,
|
|
3
3
|
publishTargetFor,
|
|
4
4
|
reportMissingTools
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-an3pxzzk.js";
|
|
6
6
|
import {
|
|
7
7
|
log
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-0wtnw98y.js";
|
|
9
9
|
import {
|
|
10
10
|
UsageError,
|
|
11
11
|
rejectExtraPositionals,
|
|
12
12
|
rejectUnknownFlags
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-jjbeqx94.js";
|
|
14
14
|
import"./cli-ht1bcqdd.js";
|
|
15
|
-
import"./cli-
|
|
15
|
+
import"./cli-ycbg7mxk.js";
|
|
16
16
|
import {
|
|
17
17
|
BuildError,
|
|
18
18
|
EXIT_CODES
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
runBuild,
|
|
8
8
|
splitOutPath,
|
|
9
9
|
startPreviewServer
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-an3pxzzk.js";
|
|
11
11
|
import {
|
|
12
12
|
log
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-0wtnw98y.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
parseFormat,
|
|
@@ -18,9 +18,9 @@ import {
|
|
|
18
18
|
rejectExtraPositionals,
|
|
19
19
|
rejectUnknownFlags,
|
|
20
20
|
resolvePort
|
|
21
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-jjbeqx94.js";
|
|
22
22
|
import"./cli-ht1bcqdd.js";
|
|
23
|
-
import"./cli-
|
|
23
|
+
import"./cli-ycbg7mxk.js";
|
|
24
24
|
import {
|
|
25
25
|
BuildError
|
|
26
26
|
} from "./cli-46ycxe6r.js";
|
|
@@ -11,18 +11,18 @@ import {
|
|
|
11
11
|
publishProviderFor,
|
|
12
12
|
resolvePublishFormat,
|
|
13
13
|
runPublish
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-an3pxzzk.js";
|
|
15
15
|
import {
|
|
16
16
|
FileTokenStore,
|
|
17
17
|
log
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-0wtnw98y.js";
|
|
19
19
|
import {
|
|
20
20
|
UsageError,
|
|
21
21
|
rejectExtraPositionals,
|
|
22
22
|
rejectUnknownFlags
|
|
23
|
-
} from "./cli-
|
|
23
|
+
} from "./cli-jjbeqx94.js";
|
|
24
24
|
import"./cli-ht1bcqdd.js";
|
|
25
|
-
import"./cli-
|
|
25
|
+
import"./cli-ycbg7mxk.js";
|
|
26
26
|
import {
|
|
27
27
|
EXIT_CODES
|
|
28
28
|
} from "./cli-46ycxe6r.js";
|