diff --git a/CHANGELOG.md b/CHANGELOG.md index 074bd9ed..2bbe8c2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `` as the group number plus a letter ("Figure 2a"); a `#` in a panel caption stays literal. An opener carrying a quoted title or `[label]` stays a generic container, as does a nested bare `::: figure`; both lint. HTML - renders `carve-figure-group` / `carve-figure-panels` / `carve-figure-panel`, + renders `carve-figure-group` / `carve-figure-panel` figures nested directly, and PART 11 §10g fixes the writer spelling and the non-HTML degradations. This is an observable parsing change inside 0.1.x for documents that already hold a bare `::: figure` fence: the container reclassifies from a generic diff --git a/docs/graceful-degradation.md b/docs/graceful-degradation.md index 482ebd64..ee57bbc7 100644 --- a/docs/graceful-degradation.md +++ b/docs/graceful-degradation.md @@ -48,7 +48,7 @@ The table reflects the reference engines' renderer behavior. | Footnotes | jump links | print-native footnotes; `[^id]` preserved in Markdown | degrades natively | | Links / autolinks | clickable | clickable in PDF; URL preserved in plain text | degrades natively | | Cross-references / TOC | anchor links | internal PDF links; anchors preserved in Markdown | degrades natively | -| Composite figure (`::: figure`) | one `
` with a panels `
` and a group `
`; layout hints (`columns-2`) pass through as classes | Markdown: panels in order, panel captions as `*(...)*`, group caption last as `**...**`; plain/terminal: group caption first, then each panel's caption + host degradation | normative - PART 9 §4c + the writer/degradation clause in PART 11 | +| Composite figure (`::: figure`) | one `
` holding the panel figures directly plus a group `
`; layout hints (`columns-2`) pass through as classes | Markdown: panels in order, panel captions as `*(...)*`, group caption last as `**...**`; plain/terminal: group caption first, then each panel's caption + host degradation | normative - PART 9 §4c + the writer/degradation clause in PART 11 | The composite figure's contract is the floor applied with no exceptions: every panel, every panel caption, any stray content between the panels, and the group diff --git a/docs/validation.md b/docs/validation.md index c3ef8795..47507f7f 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -118,7 +118,7 @@ the command-line and editor behavior stay aligned. | `figure-group-nested` | a `::: figure` opener inside a composite figure's body; nesting is rejected (PART 9 §4c), so the inner fence stays a generic container | | `figure-group-opener-metadata` | a `::: figure` opener carrying a quoted title or `[label]`; the figure production takes neither, so the fence stays a generic container with both preserved (PART 9 §4c) | | `figure-group-panel-number` | a `#` placeholder in a PANEL caption; panels are not sequence units, so the placeholder stays a literal `#` (PART 9 §4c) - number the group caption instead | -| `figure-group-empty` | a `::: figure` group with no captionable panel; the panels wrapper renders around the preserved content only (PART 9 §4c) | +| `figure-group-empty` | a `::: figure` group with no captionable panel; the group figure holds only the preserved content (PART 9 §4c) | | `figure-group-single-panel` | a `::: figure` group holding a single panel; a plain captioned figure renders the same content without the group wrapper (PART 9 §4c) | ### Declaring a target version diff --git a/docs/versioning.md b/docs/versioning.md index 9f57e5f9..481cf4a5 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -164,9 +164,7 @@ paragraph:

^ Figure #: A pull quote

-
-

To be

-
+

To be

Figure 1: A pull quote
``` diff --git a/resources/engine-pin-drift.txt b/resources/engine-pin-drift.txt index 825eaa02..13fdbd87 100644 --- a/resources/engine-pin-drift.txt +++ b/resources/engine-pin-drift.txt @@ -24,3 +24,17 @@ # Emptying this file is the normal end state after `npm run bump-carve-pin`. # # Format: + +# PART 9 §4c wrapper removal (carve#1122): panels nest directly in the group +# figure; the pinned carve-js still wraps them in the withdrawn +# `
`. Clears with the engine updates and a +# pin bump. +318-composite-figures §4c wrapper removal; the pin still emits the panels div +318-composite-figures-2 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-3 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-4 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-5 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-6 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-9 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-10 §4c wrapper removal; the pin still emits the panels div +318-composite-figures-11 §4c wrapper removal; the pin still emits the panels div diff --git a/resources/examples/edge-cases.md b/resources/examples/edge-cases.md index 5cb9d817..5c52e36f 100644 --- a/resources/examples/edge-cases.md +++ b/resources/examples/edge-cases.md @@ -17696,8 +17696,10 @@ A bare `::: figure` container is ONE figure holding ordered panels (PART 9 `figure` and `table` nodes the unchanged inner caption rules build - are the panels, and the `^ ` line after the closing fence is the caption of the whole group. That closer is caption placement's sixth host (PART 9 §4), and the only -`:::` kind that takes one. The group renders class-first, the panels wrapped in -an unconditional `carve-figure-panels` div. +`:::` kind that takes one. The group renders class-first, the panels nested +directly in the group `figure` - HTML's figure content model admits flow +content beside a first-or-last `figcaption`, so no wrapper element sits +between them. :::: compare @@ -17717,16 +17719,14 @@ an unconditional `carve-figure-panels` div. ```html
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 1: Group caption
``` @@ -17766,16 +17766,14 @@ See and .
Figure 1: First
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 2: Second

See Figure 2 and Figure 2a.

@@ -17800,16 +17798,14 @@ A group without a caption is a valid, unnumbered group - no trailing ```html
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
``` @@ -17830,12 +17826,10 @@ strict profiles as `figure-group-single-panel`). ```html
-
-
- lone -
The only panel
-
-
+
+ lone +
The only panel
+
Figure 1: One panel is valid
``` @@ -17865,17 +17859,15 @@ Both panels were shot on the same day. ```html
-
-

Both panels were shot on the same day.

-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+

Both panels were shot on the same day.

+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 1: With a note between the panels
``` @@ -17900,12 +17892,10 @@ line an ordinary paragraph. ```html
-
-
- one -
(a) One
-
-
+
+ one +
(a) One
+

^ Figure #: Detached

``` @@ -17988,13 +17978,11 @@ outer group numbers. ```html
-
-
-
- one -
(a) One
-
-
+
+
+ one +
(a) One
+
Figure 1: Outer only
@@ -18036,30 +18024,28 @@ $$`E = mc^2` ````html
-
-
- - - - - -
KindN
a1
-
-
-
const x = 1
+  
+ + + + + +
KindN
a1
+
+
+
const x = 1
 
-
A listing panel
-
-
-

\[E = mc^2\]

-
An equation panel
-
-

Measured twice.

-
-

Brevity.

-
A quoted panel
-
-
+
A listing panel
+
+
+

\[E = mc^2\]

+
An equation panel
+
+

Measured twice.

+
+

Brevity.

+
A quoted panel
+
Figure 1: Mixed panels
```` @@ -18087,14 +18073,12 @@ source. ```html
-
- -
+
Figure 1: group
``` diff --git a/resources/grammar.ebnf b/resources/grammar.ebnf index 87e272ce..ae252bc6 100644 --- a/resources/grammar.ebnf +++ b/resources/grammar.ebnf @@ -3404,9 +3404,7 @@ EOF = (* end of file *) ; ^ Figure #: A pull quote
-
-

To be

-
+

To be

Figure 1: A pull quote
@@ -3481,16 +3479,25 @@ EOF = (* end of file *) ; 318-composite-figures):
-
-
- ...panel host... -
...
-
- ... -
+
+ ...panel host... +
...
+
+ ...
Label N: group caption
+ PANELS NEST DIRECTLY, WITH NO WRAPPER ELEMENT BETWEEN. HTML's `figure` + content model is a `figcaption` first or last plus FLOW CONTENT, and + `figure` is itself flow content, so nested panel figures are exactly + what the element admits -- no intermediate `div` is needed to make the + shape valid, and none is emitted. This is also the shape Pandoc's + writers produce for its native subfigures, which keeps HTML + import/export symmetric with the Pandoc bridge. The initial draft of + this clause wrapped the panels in a `
`; + that form was revised to the flat one before any release, so no + shipped document ever carried the wrapper. + The class is FIRST on the group and on each panel, exactly the typed- container convention (`admonition note`): `carve-figure-group` leads, classes from the preceding attribute line -- layout hints such as @@ -3498,10 +3505,10 @@ EOF = (* end of file *) ; -- merge after it, then the id and remaining attributes in source order. A panel renders as the `
` its host already produces, with `carve-figure-panel` leading its classes the same way. No group - caption -> no trailing `
`. Zero panels -> the - `carve-figure-panels` div still wraps whatever content was preserved; - the panels div is unconditional so a consumer styling the shape never - branches on child count. + caption -> no trailing `
`. Zero panels -> the group + `
` holds the preserved content directly; a consumer selects + panels by the `carve-figure-panel` class, never by position, so the + shape needs no branch on child count. 5. TABLE MODEL -- OPERATIONAL SEMANTICS (cell split, row validity, header cells, span walk, continuation rows, delimiter row, row diff --git a/scripts/spec/html.mjs b/scripts/spec/html.mjs index 46ea2a44..aaeb53c3 100644 --- a/scripts/spec/html.mjs +++ b/scripts/spec/html.mjs @@ -304,9 +304,13 @@ function renderBlock(b, depth, ctx) { }) cap = numberCaption(b.caption, ctx, groupId, panelIds) } + // PANELS NEST DIRECTLY (SS4c): HTML's figure content model is a + // figcaption first or last plus flow content, and figure is itself + // flow content, so no wrapper element sits between the group and its + // panels -- the shape Pandoc's writers produce for subfigures too. const inner = b.children .map((c) => { - if (!isPanel(c)) return renderBlock(c, depth + 2, ctx) + if (!isPanel(c)) return renderBlock(c, depth + 1, ctx) const wasInPanel = ctx.inPanel ctx.inPanel = true try { @@ -314,15 +318,15 @@ function renderBlock(b, depth, ctx) { // a table does not render as a
on its own, so the // panel wrapper is explicit; the table keeps its own attrs and // its own (SS4c). - const t = renderBlock(c, depth + 3, ctx) - return `${pad2}
\n${t}\n${pad2}
` + const t = renderBlock(c, depth + 2, ctx) + return `${pad2}
\n${t}\n${pad2}
` } // a captioned para/code/quote host already renders as
; // lead its classes with the panel marker the way the group's are const prev = c.battrs c.battrs = [[['class', 'carve-figure-panel']], ...(prev ?? [])] try { - return renderBlock(c, depth + 2, ctx) + return renderBlock(c, depth + 1, ctx) } finally { c.battrs = prev } @@ -332,12 +336,12 @@ function renderBlock(b, depth, ctx) { }) .filter((x) => x !== null) .join('\n') - // the panels div is UNCONDITIONAL (SS4c): zero panels still wrap the - // preserved content, and an empty group holds an empty div. - const parts = [`${pad2}
`] + const parts = [] if (inner !== '') parts.push(inner) - parts.push(`${pad2}
`) if (cap !== undefined) parts.push(`${pad2}
${renderInline(cap)}
`) + // an EMPTY uncaptioned group keeps the bare-container empty-body line + // (the PART 10 SS4 exception the generic div takes). + if (parts.length === 0) return `${pad2}\n${pad2}
` return `${pad2}\n${parts.join('\n')}\n${pad2}
` } case 'line-block': { diff --git a/tests/corpus/318-composite-figures-10.html b/tests/corpus/318-composite-figures-10.html index e02a3686..1008561a 100644 --- a/tests/corpus/318-composite-figures-10.html +++ b/tests/corpus/318-composite-figures-10.html @@ -1,27 +1,25 @@
-
-
- - - - - -
KindN
a1
-
-
-
const x = 1
+  
+ + + + + +
KindN
a1
+
+
+
const x = 1
 
-
A listing panel
-
-
-

\[E = mc^2\]

-
An equation panel
-
-

Measured twice.

-
-

Brevity.

-
A quoted panel
-
-
+
A listing panel
+
+
+

\[E = mc^2\]

+
An equation panel
+
+

Measured twice.

+
+

Brevity.

+
A quoted panel
+
Figure 1: Mixed panels
diff --git a/tests/corpus/318-composite-figures-11.html b/tests/corpus/318-composite-figures-11.html index 4bf87716..636707af 100644 --- a/tests/corpus/318-composite-figures-11.html +++ b/tests/corpus/318-composite-figures-11.html @@ -1,11 +1,9 @@
-
- -
+
Figure 1: group
diff --git a/tests/corpus/318-composite-figures-2.html b/tests/corpus/318-composite-figures-2.html index 68742b55..edbb3382 100644 --- a/tests/corpus/318-composite-figures-2.html +++ b/tests/corpus/318-composite-figures-2.html @@ -3,16 +3,14 @@
Figure 1: First
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 2: Second

See Figure 2 and Figure 2a.

diff --git a/tests/corpus/318-composite-figures-3.html b/tests/corpus/318-composite-figures-3.html index d03e6c54..4d011099 100644 --- a/tests/corpus/318-composite-figures-3.html +++ b/tests/corpus/318-composite-figures-3.html @@ -1,12 +1,10 @@
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
diff --git a/tests/corpus/318-composite-figures-4.html b/tests/corpus/318-composite-figures-4.html index cf592a44..0454f1d6 100644 --- a/tests/corpus/318-composite-figures-4.html +++ b/tests/corpus/318-composite-figures-4.html @@ -1,9 +1,7 @@
-
-
- lone -
The only panel
-
-
+
+ lone +
The only panel
+
Figure 1: One panel is valid
diff --git a/tests/corpus/318-composite-figures-5.html b/tests/corpus/318-composite-figures-5.html index 7596a7b6..bf8fd93d 100644 --- a/tests/corpus/318-composite-figures-5.html +++ b/tests/corpus/318-composite-figures-5.html @@ -1,14 +1,12 @@
-
-

Both panels were shot on the same day.

-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+

Both panels were shot on the same day.

+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 1: With a note between the panels
diff --git a/tests/corpus/318-composite-figures-6.html b/tests/corpus/318-composite-figures-6.html index 59db5a07..36106cb5 100644 --- a/tests/corpus/318-composite-figures-6.html +++ b/tests/corpus/318-composite-figures-6.html @@ -1,9 +1,7 @@
-
-
- one -
(a) One
-
-
+
+ one +
(a) One
+

^ Figure #: Detached

diff --git a/tests/corpus/318-composite-figures-9.html b/tests/corpus/318-composite-figures-9.html index 9b2c9bf0..e94cdab6 100644 --- a/tests/corpus/318-composite-figures-9.html +++ b/tests/corpus/318-composite-figures-9.html @@ -1,11 +1,9 @@
-
-
-
- one -
(a) One
-
-
+
+
+ one +
(a) One
+
Figure 1: Outer only
diff --git a/tests/corpus/318-composite-figures.html b/tests/corpus/318-composite-figures.html index db46cfa1..9bf7286d 100644 --- a/tests/corpus/318-composite-figures.html +++ b/tests/corpus/318-composite-figures.html @@ -1,13 +1,11 @@
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 1: Group caption
diff --git a/tests/spec/318-composite-figures.test b/tests/spec/318-composite-figures.test index a0dbdafc..a08a6d81 100644 --- a/tests/spec/318-composite-figures.test +++ b/tests/spec/318-composite-figures.test @@ -14,16 +14,14 @@ Composite figures ^ Figure #: Group caption .
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 1: Group caption
``` @@ -52,16 +50,14 @@ See and .
Figure 1: First
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 2: Second

See Figure 2 and Figure 2a.

@@ -77,16 +73,14 @@ See and . ::: .
-
-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+
+ one +
(a) One
+
+
+ two +
(b) Two
+
``` @@ -98,12 +92,10 @@ See and . ^ Figure #: One panel is valid .
-
-
- lone -
The only panel
-
-
+
+ lone +
The only panel
+
Figure 1: One panel is valid
``` @@ -123,17 +115,15 @@ Both panels were shot on the same day. ^ Figure #: With a note between the panels .
-
-

Both panels were shot on the same day.

-
- one -
(a) One
-
-
- two -
(b) Two
-
-
+

Both panels were shot on the same day.

+
+ one +
(a) One
+
+
+ two +
(b) Two
+
Figure 1: With a note between the panels
``` @@ -148,12 +138,10 @@ Both panels were shot on the same day. ^ Figure #: Detached .
-
-
- one -
(a) One
-
-
+
+ one +
(a) One
+

^ Figure #: Detached

``` @@ -205,13 +193,11 @@ Body. ^ Figure #: Outer only .
-
-
-
- one -
(a) One
-
-
+
+
+ one +
(a) One
+
Figure 1: Outer only
@@ -240,30 +226,28 @@ $$`E = mc^2` ^ Figure #: Mixed panels .
-
-
- - - - - -
KindN
a1
-
-
-
const x = 1
+  
+ + + + + +
KindN
a1
+
+
+
const x = 1
 
-
A listing panel
-
-
-

\[E = mc^2\]

-
An equation panel
-
-

Measured twice.

-
-

Brevity.

-
A quoted panel
-
-
+
A listing panel
+
+
+

\[E = mc^2\]

+
An equation panel
+
+

Measured twice.

+
+

Brevity.

+
A quoted panel
+
Figure 1: Mixed panels
```` @@ -278,14 +262,12 @@ $$`E = mc^2` ^ Figure #: group .
-
- -
+
Figure 1: group
```