@refrakt-md/runes 0.32.0 → 0.34.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/aggregate-resolve.d.ts.map +1 -1
- package/dist/aggregate-resolve.js +18 -4
- package/dist/aggregate-resolve.js.map +1 -1
- package/dist/attributes.d.ts +15 -0
- package/dist/attributes.d.ts.map +1 -1
- package/dist/attributes.js +22 -7
- package/dist/attributes.js.map +1 -1
- package/dist/collection-helpers.d.ts.map +1 -1
- package/dist/collection-helpers.js +1 -1
- package/dist/collection-helpers.js.map +1 -1
- package/dist/collection-resolve.d.ts.map +1 -1
- package/dist/collection-resolve.js +31 -8
- package/dist/collection-resolve.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +214 -77
- package/dist/config.js.map +1 -1
- package/dist/data-adapters.d.ts.map +1 -1
- package/dist/data-adapters.js +28 -11
- package/dist/data-adapters.js.map +1 -1
- package/dist/data-emit.d.ts +1 -0
- package/dist/data-emit.d.ts.map +1 -1
- package/dist/data-emit.js +40 -0
- package/dist/data-emit.js.map +1 -1
- package/dist/data-pipeline.d.ts +10 -4
- package/dist/data-pipeline.d.ts.map +1 -1
- package/dist/data-pipeline.js +331 -32
- package/dist/data-pipeline.js.map +1 -1
- package/dist/data-projection.d.ts +21 -0
- package/dist/data-projection.d.ts.map +1 -1
- package/dist/data-projection.js +41 -3
- package/dist/data-projection.js.map +1 -1
- package/dist/data-resolve.d.ts.map +1 -1
- package/dist/data-resolve.js +5 -2
- package/dist/data-resolve.js.map +1 -1
- package/dist/documents/page.d.ts.map +1 -1
- package/dist/documents/page.js.map +1 -1
- package/dist/drawer-pipeline.d.ts.map +1 -1
- package/dist/drawer-pipeline.js +3 -2
- package/dist/drawer-pipeline.js.map +1 -1
- package/dist/expand-pipeline.d.ts.map +1 -1
- package/dist/expand-pipeline.js +3 -3
- package/dist/expand-pipeline.js.map +1 -1
- package/dist/fence-escape.d.ts.map +1 -1
- package/dist/fence-escape.js +1 -3
- package/dist/fence-escape.js.map +1 -1
- package/dist/field-match.d.ts.map +1 -1
- package/dist/field-match.js.map +1 -1
- package/dist/file-ref-resolve.js +6 -4
- package/dist/file-ref-resolve.js.map +1 -1
- package/dist/fixtures.js +2 -2
- package/dist/fixtures.js.map +1 -1
- package/dist/functions.d.ts.map +1 -1
- package/dist/functions.js +16 -3
- package/dist/functions.js.map +1 -1
- package/dist/include-pipeline.d.ts +52 -0
- package/dist/include-pipeline.d.ts.map +1 -0
- package/dist/include-pipeline.js +206 -0
- package/dist/include-pipeline.js.map +1 -0
- package/dist/index.d.ts +94 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +298 -59
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/layouts/grid.d.ts +1 -1
- package/dist/layouts/grid.d.ts.map +1 -1
- package/dist/layouts/grid.js +4 -6
- package/dist/layouts/grid.js.map +1 -1
- package/dist/lib/component.d.ts +20 -0
- package/dist/lib/component.d.ts.map +1 -1
- package/dist/lib/component.js +42 -7
- package/dist/lib/component.js.map +1 -1
- package/dist/lib/icon-resolve.d.ts.map +1 -1
- package/dist/lib/icon-resolve.js.map +1 -1
- package/dist/lib/image-schemes.js +2 -2
- package/dist/lib/image-schemes.js.map +1 -1
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +252 -51
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/node.d.ts.map +1 -1
- package/dist/lib/node.js +3 -2
- package/dist/lib/node.js.map +1 -1
- package/dist/lib/placeholder.d.ts.map +1 -1
- package/dist/lib/placeholder.js +6 -9
- package/dist/lib/placeholder.js.map +1 -1
- package/dist/lib/read-file.d.ts.map +1 -1
- package/dist/lib/read-file.js.map +1 -1
- package/dist/lib/renderable.d.ts.map +1 -1
- package/dist/lib/renderable.js +5 -5
- package/dist/lib/renderable.js.map +1 -1
- package/dist/lib/resolver.d.ts.map +1 -1
- package/dist/lib/resolver.js +26 -35
- package/dist/lib/resolver.js.map +1 -1
- package/dist/lib/svg.d.ts.map +1 -1
- package/dist/lib/svg.js.map +1 -1
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +24 -22
- package/dist/nodes.js.map +1 -1
- package/dist/outline-scope.js +1 -3
- package/dist/outline-scope.js.map +1 -1
- package/dist/plugins.d.ts.map +1 -1
- package/dist/plugins.js +13 -10
- package/dist/plugins.js.map +1 -1
- package/dist/reference.d.ts +27 -2
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +58 -25
- package/dist/reference.js.map +1 -1
- package/dist/relationships-resolve.d.ts.map +1 -1
- package/dist/relationships-resolve.js +31 -7
- package/dist/relationships-resolve.js.map +1 -1
- package/dist/rune.d.ts.map +1 -1
- package/dist/rune.js.map +1 -1
- package/dist/sandbox-sources.js +6 -6
- package/dist/sandbox-sources.js.map +1 -1
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +4 -4
- package/dist/seo.js.map +1 -1
- package/dist/snippet-pipeline.d.ts.map +1 -1
- package/dist/snippet-pipeline.js +1 -1
- package/dist/snippet-pipeline.js.map +1 -1
- package/dist/tags/accordion.d.ts.map +1 -1
- package/dist/tags/accordion.js +43 -11
- package/dist/tags/accordion.js.map +1 -1
- package/dist/tags/aggregate.d.ts.map +1 -1
- package/dist/tags/aggregate.js +65 -10
- package/dist/tags/aggregate.js.map +1 -1
- package/dist/tags/annotate.d.ts.map +1 -1
- package/dist/tags/annotate.js +12 -9
- package/dist/tags/annotate.js.map +1 -1
- package/dist/tags/badge.d.ts.map +1 -1
- package/dist/tags/badge.js.map +1 -1
- package/dist/tags/bar.d.ts.map +1 -1
- package/dist/tags/bar.js +3 -7
- package/dist/tags/bar.js.map +1 -1
- package/dist/tags/bg.d.ts.map +1 -1
- package/dist/tags/bg.js +60 -12
- package/dist/tags/bg.js.map +1 -1
- package/dist/tags/blog.d.ts.map +1 -1
- package/dist/tags/blog.js +35 -10
- package/dist/tags/blog.js.map +1 -1
- package/dist/tags/breadcrumb.d.ts.map +1 -1
- package/dist/tags/breadcrumb.js +33 -11
- package/dist/tags/breadcrumb.js.map +1 -1
- package/dist/tags/budget.d.ts.map +1 -1
- package/dist/tags/budget.js +54 -16
- package/dist/tags/budget.js.map +1 -1
- package/dist/tags/card.d.ts.map +1 -1
- package/dist/tags/card.js +24 -6
- package/dist/tags/card.js.map +1 -1
- package/dist/tags/chart.d.ts.map +1 -1
- package/dist/tags/chart.js +33 -11
- package/dist/tags/chart.js.map +1 -1
- package/dist/tags/code.d.ts +25 -0
- package/dist/tags/code.d.ts.map +1 -0
- package/dist/tags/code.js +36 -0
- package/dist/tags/code.js.map +1 -0
- package/dist/tags/codegroup.d.ts.map +1 -1
- package/dist/tags/codegroup.js +39 -21
- package/dist/tags/codegroup.js.map +1 -1
- package/dist/tags/collection.d.ts.map +1 -1
- package/dist/tags/collection.js +55 -9
- package/dist/tags/collection.js.map +1 -1
- package/dist/tags/common.d.ts.map +1 -1
- package/dist/tags/common.js +34 -9
- package/dist/tags/common.js.map +1 -1
- package/dist/tags/compare.d.ts.map +1 -1
- package/dist/tags/compare.js +26 -14
- package/dist/tags/compare.js.map +1 -1
- package/dist/tags/conversation.d.ts.map +1 -1
- package/dist/tags/conversation.js +19 -17
- package/dist/tags/conversation.js.map +1 -1
- package/dist/tags/data.d.ts.map +1 -1
- package/dist/tags/data.js +91 -15
- package/dist/tags/data.js.map +1 -1
- package/dist/tags/datatable.d.ts.map +1 -1
- package/dist/tags/datatable.js +22 -8
- package/dist/tags/datatable.js.map +1 -1
- package/dist/tags/deflist.d.ts.map +1 -1
- package/dist/tags/deflist.js +5 -11
- package/dist/tags/deflist.js.map +1 -1
- package/dist/tags/details.d.ts.map +1 -1
- package/dist/tags/details.js +8 -5
- package/dist/tags/details.js.map +1 -1
- package/dist/tags/diagram.d.ts.map +1 -1
- package/dist/tags/diagram.js +9 -5
- package/dist/tags/diagram.js.map +1 -1
- package/dist/tags/diff.d.ts.map +1 -1
- package/dist/tags/diff.js +43 -24
- package/dist/tags/diff.js.map +1 -1
- package/dist/tags/drawer.d.ts.map +1 -1
- package/dist/tags/drawer.js +4 -6
- package/dist/tags/drawer.js.map +1 -1
- package/dist/tags/embed.d.ts.map +1 -1
- package/dist/tags/embed.js +10 -5
- package/dist/tags/embed.js.map +1 -1
- package/dist/tags/expand.d.ts.map +1 -1
- package/dist/tags/expand.js.map +1 -1
- package/dist/tags/figure.d.ts.map +1 -1
- package/dist/tags/figure.js +29 -9
- package/dist/tags/figure.js.map +1 -1
- package/dist/tags/file-ref.d.ts.map +1 -1
- package/dist/tags/file-ref.js.map +1 -1
- package/dist/tags/form.d.ts.map +1 -1
- package/dist/tags/form.js +52 -25
- package/dist/tags/form.js.map +1 -1
- package/dist/tags/gallery.d.ts.map +1 -1
- package/dist/tags/gallery.js +26 -12
- package/dist/tags/gallery.js.map +1 -1
- package/dist/tags/grid.d.ts.map +1 -1
- package/dist/tags/grid.js +57 -14
- package/dist/tags/grid.js.map +1 -1
- package/dist/tags/hint.d.ts.map +1 -1
- package/dist/tags/hint.js +9 -5
- package/dist/tags/hint.js.map +1 -1
- package/dist/tags/icon.d.ts.map +1 -1
- package/dist/tags/icon.js +5 -1
- package/dist/tags/icon.js.map +1 -1
- package/dist/tags/include.d.ts +24 -0
- package/dist/tags/include.d.ts.map +1 -0
- package/dist/tags/include.js +46 -0
- package/dist/tags/include.js.map +1 -0
- package/dist/tags/juxtapose.d.ts.map +1 -1
- package/dist/tags/juxtapose.js +32 -14
- package/dist/tags/juxtapose.js.map +1 -1
- package/dist/tags/layout.d.ts.map +1 -1
- package/dist/tags/layout.js +7 -4
- package/dist/tags/layout.js.map +1 -1
- package/dist/tags/mediatext.d.ts.map +1 -1
- package/dist/tags/mediatext.js +19 -8
- package/dist/tags/mediatext.js.map +1 -1
- package/dist/tags/nav.d.ts.map +1 -1
- package/dist/tags/nav.js +43 -23
- package/dist/tags/nav.js.map +1 -1
- package/dist/tags/pagination.d.ts.map +1 -1
- package/dist/tags/pagination.js +27 -5
- package/dist/tags/pagination.js.map +1 -1
- package/dist/tags/progress.d.ts.map +1 -1
- package/dist/tags/progress.js +25 -5
- package/dist/tags/progress.js.map +1 -1
- package/dist/tags/pullquote.d.ts.map +1 -1
- package/dist/tags/pullquote.js +16 -9
- package/dist/tags/pullquote.js.map +1 -1
- package/dist/tags/region.d.ts.map +1 -1
- package/dist/tags/region.js +9 -4
- package/dist/tags/region.js.map +1 -1
- package/dist/tags/relationships.d.ts.map +1 -1
- package/dist/tags/relationships.js +55 -9
- package/dist/tags/relationships.js.map +1 -1
- package/dist/tags/reveal.d.ts.map +1 -1
- package/dist/tags/reveal.js +16 -7
- package/dist/tags/reveal.js.map +1 -1
- package/dist/tags/sandbox.d.ts.map +1 -1
- package/dist/tags/sandbox.js +104 -44
- package/dist/tags/sandbox.js.map +1 -1
- package/dist/tags/section.d.ts.map +1 -1
- package/dist/tags/section.js +13 -3
- package/dist/tags/section.js.map +1 -1
- package/dist/tags/showcase.d.ts.map +1 -1
- package/dist/tags/showcase.js +33 -11
- package/dist/tags/showcase.js.map +1 -1
- package/dist/tags/sidenote.d.ts.map +1 -1
- package/dist/tags/sidenote.js +9 -5
- package/dist/tags/sidenote.js.map +1 -1
- package/dist/tags/snippet.d.ts.map +1 -1
- package/dist/tags/snippet.js +14 -6
- package/dist/tags/snippet.js.map +1 -1
- package/dist/tags/tabs.d.ts.map +1 -1
- package/dist/tags/tabs.js +16 -9
- package/dist/tags/tabs.js.map +1 -1
- package/dist/tags/textblock.d.ts.map +1 -1
- package/dist/tags/textblock.js +9 -5
- package/dist/tags/textblock.js.map +1 -1
- package/dist/tags/tint.d.ts +1 -1
- package/dist/tags/tint.d.ts.map +1 -1
- package/dist/tags/tint.js +14 -2
- package/dist/tags/tint.js.map +1 -1
- package/dist/tags/toc.d.ts.map +1 -1
- package/dist/tags/toc.js +16 -7
- package/dist/tags/toc.js.map +1 -1
- package/dist/tags/xref.d.ts.map +1 -1
- package/dist/tags/xref.js.map +1 -1
- package/dist/universal-attributes.d.ts.map +1 -1
- package/dist/universal-attributes.js +28 -5
- package/dist/universal-attributes.js.map +1 -1
- package/dist/util.d.ts +41 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +72 -14
- package/dist/util.js.map +1 -1
- package/dist/xref-patterns.js +1 -1
- package/dist/xref-patterns.js.map +1 -1
- package/dist/xref-preview-resolve.js +3 -4
- package/dist/xref-preview-resolve.js.map +1 -1
- package/dist/xref-resolve.d.ts.map +1 -1
- package/dist/xref-resolve.js +4 -4
- package/dist/xref-resolve.js.map +1 -1
- package/i18n/de.json +67 -67
- package/i18n/en.json +67 -67
- package/package.json +3 -3
- package/dist/tags/error.d.ts +0 -3
- package/dist/tags/error.d.ts.map +0 -1
- package/dist/tags/error.js +0 -34
- package/dist/tags/error.js.map +0 -1
package/dist/config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isTag, readField, resolveGap, ratioToFr, resolveValign } from '@refrakt-md/transform';
|
|
1
|
+
import { isTag, readField, resolveGap, ratioToFr, resolveValign, } from '@refrakt-md/transform';
|
|
2
2
|
import Markdoc from '@markdoc/markdoc';
|
|
3
3
|
const { Tag } = Markdoc;
|
|
4
4
|
import { createComponentRenderable } from './lib/index.js';
|
|
@@ -8,7 +8,8 @@ import { PAGINATION_AUTO_SENTINEL } from './tags/pagination.js';
|
|
|
8
8
|
import { resolveXrefs } from './xref-resolve.js';
|
|
9
9
|
import { preprocessSnippets, wrapStandaloneSnippets } from './snippet-pipeline.js';
|
|
10
10
|
import { preprocessData } from './data-pipeline.js';
|
|
11
|
-
import {
|
|
11
|
+
import { preprocessIncludes } from './include-pipeline.js';
|
|
12
|
+
import { registerDrawers, resolveAutoDrawerTitleLevels, hoistPreviewDrawers, } from './drawer-pipeline.js';
|
|
12
13
|
import { resolveFileRefs } from './file-ref-resolve.js';
|
|
13
14
|
import { resolveXrefPreviews } from './xref-preview-resolve.js';
|
|
14
15
|
import { applyOutlineScopeWalkers, harvestHeadingsFromRenderable } from './outline-scope.js';
|
|
@@ -43,7 +44,12 @@ import { tabGroupSections } from './tags/tabs.js';
|
|
|
43
44
|
/** Read text content from a property span child */
|
|
44
45
|
function readPropText(node, prop) {
|
|
45
46
|
for (const c of node.children) {
|
|
46
|
-
if (isTag(c) &&
|
|
47
|
+
if (isTag(c) &&
|
|
48
|
+
c.attributes?.['data-field'] ===
|
|
49
|
+
prop
|
|
50
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
51
|
+
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
52
|
+
.toLowerCase()) {
|
|
47
53
|
return c.children.filter((ch) => typeof ch === 'string').join('');
|
|
48
54
|
}
|
|
49
55
|
}
|
|
@@ -65,22 +71,35 @@ export const coreConfig = {
|
|
|
65
71
|
icons: {},
|
|
66
72
|
runes: {
|
|
67
73
|
// ─── Simple runes (block name only, engine adds BEM classes) ───
|
|
68
|
-
Accordion: {
|
|
74
|
+
Accordion: {
|
|
75
|
+
block: 'accordion',
|
|
76
|
+
defaultDensity: 'full',
|
|
77
|
+
sections: accordionSections,
|
|
78
|
+
autoLabel: pageSectionAutoLabel,
|
|
79
|
+
editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' },
|
|
80
|
+
},
|
|
69
81
|
// SPEC-125 Phase 1 — the answer panel is the item's `body` role, so
|
|
70
82
|
// `reading` / `dropcap` land on it. The header decision is recorded in
|
|
71
83
|
// `sectionRoleExceptions` so it travels with the rune.
|
|
72
84
|
AccordionItem: {
|
|
73
|
-
block: 'accordion-item',
|
|
85
|
+
block: 'accordion-item',
|
|
86
|
+
parent: 'Accordion',
|
|
87
|
+
requiresParent: 'Accordion',
|
|
74
88
|
rootAttributes: { 'data-state': 'closed' },
|
|
75
89
|
autoLabel: { name: 'header' },
|
|
76
90
|
sections: accordionItemSections,
|
|
77
91
|
provides: ['prose'],
|
|
78
92
|
sectionRoleExceptions: {
|
|
79
|
-
header:
|
|
93
|
+
header: "The `header` slot is the <summary> disclosure control, not a page-section header. `header` would inherit the chrome-row rhythm (a 3rem margin under every summary); `title` would tighten every summary's line-height while leaving `prominence` inert anyway, since `.rf-accordion-item__header` pins the control's font size on purpose. The parent Accordion already holds `title`.",
|
|
80
94
|
},
|
|
81
95
|
editHints: { header: 'inline', body: 'none' },
|
|
82
96
|
},
|
|
83
|
-
Details: {
|
|
97
|
+
Details: {
|
|
98
|
+
block: 'details',
|
|
99
|
+
defaultElevation: 'flush',
|
|
100
|
+
autoLabel: { summary: 'summary' },
|
|
101
|
+
editHints: { summary: 'inline', body: 'none' },
|
|
102
|
+
},
|
|
84
103
|
Grid: {
|
|
85
104
|
block: 'grid',
|
|
86
105
|
defaultDensity: 'full',
|
|
@@ -109,7 +128,10 @@ export const coreConfig = {
|
|
|
109
128
|
interactive: true,
|
|
110
129
|
defaultDensity: 'compact',
|
|
111
130
|
defaultElevation: 'flat',
|
|
112
|
-
modifiers: {
|
|
131
|
+
modifiers: {
|
|
132
|
+
title: { source: 'meta', noBemClass: true },
|
|
133
|
+
overflow: { source: 'meta', default: 'scroll' },
|
|
134
|
+
},
|
|
113
135
|
// The window chrome (three dots) is pure decoration — drawn in CSS
|
|
114
136
|
// on `.rf-codegroup__topbar`. The only metadata is the optional
|
|
115
137
|
// filename `title`, a bare monospace field in the topbar bar.
|
|
@@ -147,6 +169,14 @@ export const coreConfig = {
|
|
|
147
169
|
* table renders through the standard `table` node (no `data`-specific
|
|
148
170
|
* block CSS). */
|
|
149
171
|
Data: { block: 'data' },
|
|
172
|
+
/* Include leaves nothing behind at all — its preprocess hook splices the
|
|
173
|
+
* tag away and pastes the partial's AST in its place, so the engine never
|
|
174
|
+
* sees an `Include` tag and there is no `include` block to style. The
|
|
175
|
+
* entry exists so the rune is known to inspect/contracts tooling. */
|
|
176
|
+
Include: { block: 'include' },
|
|
177
|
+
/* An inline `<code>`, styled by the same rule as a backtick code span so a
|
|
178
|
+
* page mixing the two is not visibly inconsistent (WORK-551). */
|
|
179
|
+
Code: { block: 'code', universalAttributes: 'inline' },
|
|
150
180
|
/* Expand emits a placeholder during transform; the postProcess hook
|
|
151
181
|
* substitutes the entity content wrapped in `<section
|
|
152
182
|
* class="rf-expand" data-rune="expand">`. Engine config provides the
|
|
@@ -254,7 +284,11 @@ export const coreConfig = {
|
|
|
254
284
|
separator: { prop: '--separator', template: '"{}"' },
|
|
255
285
|
},
|
|
256
286
|
},
|
|
257
|
-
BreadcrumbItem: {
|
|
287
|
+
BreadcrumbItem: {
|
|
288
|
+
block: 'breadcrumb-item',
|
|
289
|
+
parent: 'Breadcrumb',
|
|
290
|
+
requiresParent: 'Breadcrumb',
|
|
291
|
+
},
|
|
258
292
|
Blog: {
|
|
259
293
|
block: 'blog',
|
|
260
294
|
defaultDensity: 'full',
|
|
@@ -318,7 +352,7 @@ export const coreConfig = {
|
|
|
318
352
|
defaultDensity: 'compact',
|
|
319
353
|
defaultElevation: 'sunken',
|
|
320
354
|
modifiers: { hintType: { source: 'meta', default: 'note' } },
|
|
321
|
-
contextModifiers: {
|
|
355
|
+
contextModifiers: { hero: 'in-hero', feature: 'in-feature' },
|
|
322
356
|
sections: hintSections,
|
|
323
357
|
// SPEC-035 Zone 6 — the hintType value doubles as the visible title
|
|
324
358
|
// (CSS capitalizes it). Declaring it as an enum lets `core.hint.<value>`
|
|
@@ -392,7 +426,12 @@ export const coreConfig = {
|
|
|
392
426
|
modifiers: { layout: { source: 'meta', default: 'side-by-side' } },
|
|
393
427
|
editHints: { panels: 'none' },
|
|
394
428
|
},
|
|
395
|
-
Conversation: {
|
|
429
|
+
Conversation: {
|
|
430
|
+
block: 'conversation',
|
|
431
|
+
defaultDensity: 'compact',
|
|
432
|
+
defaultElevation: 'flush',
|
|
433
|
+
editHints: { messages: 'none' },
|
|
434
|
+
},
|
|
396
435
|
ConversationMessage: {
|
|
397
436
|
block: 'conversation-message',
|
|
398
437
|
parent: 'Conversation',
|
|
@@ -435,7 +474,7 @@ export const coreConfig = {
|
|
|
435
474
|
// Extract slug from span[property="slug"] child → data-slug attribute
|
|
436
475
|
// Keep slug text as visible fallback for SSR; web component replaces with <a> links
|
|
437
476
|
let slug = '';
|
|
438
|
-
const children = node.children.filter(child => {
|
|
477
|
+
const children = node.children.filter((child) => {
|
|
439
478
|
if (isTag(child) && child.name === 'span' && child.attributes['data-field'] === 'slug') {
|
|
440
479
|
slug = child.children.filter((c) => typeof c === 'string').join('');
|
|
441
480
|
return false; // remove slug span from DOM
|
|
@@ -452,10 +491,16 @@ export const coreConfig = {
|
|
|
452
491
|
};
|
|
453
492
|
}
|
|
454
493
|
// Explicit link item: add nav-item__link class to <a> tags for styling
|
|
455
|
-
const styledChildren = children.map(child => {
|
|
494
|
+
const styledChildren = children.map((child) => {
|
|
456
495
|
if (isTag(child) && child.name === 'a') {
|
|
457
496
|
const existing = child.attributes.class || '';
|
|
458
|
-
return {
|
|
497
|
+
return {
|
|
498
|
+
...child,
|
|
499
|
+
attributes: {
|
|
500
|
+
...child.attributes,
|
|
501
|
+
class: ['rf-nav-item__link', existing].filter(Boolean).join(' '),
|
|
502
|
+
},
|
|
503
|
+
};
|
|
459
504
|
}
|
|
460
505
|
return child;
|
|
461
506
|
});
|
|
@@ -465,7 +510,12 @@ export const coreConfig = {
|
|
|
465
510
|
Diff: {
|
|
466
511
|
block: 'diff',
|
|
467
512
|
modifiers: { mode: { source: 'meta', default: 'unified' } },
|
|
468
|
-
editHints: {
|
|
513
|
+
editHints: {
|
|
514
|
+
line: 'none',
|
|
515
|
+
'gutter-num': 'none',
|
|
516
|
+
'gutter-prefix': 'none',
|
|
517
|
+
'line-content': 'none',
|
|
518
|
+
},
|
|
469
519
|
},
|
|
470
520
|
Chart: {
|
|
471
521
|
block: 'chart',
|
|
@@ -541,9 +591,27 @@ export const coreConfig = {
|
|
|
541
591
|
editHints: { viewport: 'none' },
|
|
542
592
|
},
|
|
543
593
|
// ─── Interactive runes (still get BEM classes, components add behavior) ───
|
|
544
|
-
TabGroup: {
|
|
545
|
-
|
|
546
|
-
|
|
594
|
+
TabGroup: {
|
|
595
|
+
block: 'tabs',
|
|
596
|
+
interactive: true,
|
|
597
|
+
defaultDensity: 'full',
|
|
598
|
+
sections: tabGroupSections,
|
|
599
|
+
autoLabel: pageSectionAutoLabel,
|
|
600
|
+
editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' },
|
|
601
|
+
},
|
|
602
|
+
Tab: {
|
|
603
|
+
block: 'tab',
|
|
604
|
+
parent: 'TabGroup',
|
|
605
|
+
requiresParent: 'TabGroup',
|
|
606
|
+
rootAttributes: { 'data-state': 'inactive' },
|
|
607
|
+
editHints: { name: 'inline' },
|
|
608
|
+
},
|
|
609
|
+
TabPanel: {
|
|
610
|
+
block: 'tab-panel',
|
|
611
|
+
parent: 'TabGroup',
|
|
612
|
+
requiresParent: 'TabGroup',
|
|
613
|
+
rootAttributes: { 'data-state': 'inactive' },
|
|
614
|
+
},
|
|
547
615
|
DataTable: {
|
|
548
616
|
block: 'datatable',
|
|
549
617
|
interactive: true,
|
|
@@ -592,7 +660,12 @@ export const coreConfig = {
|
|
|
592
660
|
autoLabel: pageSectionAutoLabel,
|
|
593
661
|
editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline', steps: 'none' },
|
|
594
662
|
},
|
|
595
|
-
RevealStep: {
|
|
663
|
+
RevealStep: {
|
|
664
|
+
block: 'reveal-step',
|
|
665
|
+
parent: 'Reveal',
|
|
666
|
+
rootAttributes: { 'data-state': 'closed' },
|
|
667
|
+
editHints: { body: 'none' },
|
|
668
|
+
},
|
|
596
669
|
Section: {
|
|
597
670
|
block: 'section',
|
|
598
671
|
modifiers: {
|
|
@@ -618,7 +691,13 @@ export const coreConfig = {
|
|
|
618
691
|
},
|
|
619
692
|
editHints: { panels: 'none' },
|
|
620
693
|
},
|
|
621
|
-
JuxtaposePanel: {
|
|
694
|
+
JuxtaposePanel: {
|
|
695
|
+
block: 'juxtapose-panel',
|
|
696
|
+
parent: 'Juxtapose',
|
|
697
|
+
requiresParent: 'Juxtapose',
|
|
698
|
+
rootAttributes: { 'data-state': 'inactive' },
|
|
699
|
+
editHints: { body: 'none' },
|
|
700
|
+
},
|
|
622
701
|
Diagram: {
|
|
623
702
|
block: 'diagram',
|
|
624
703
|
defaultDensity: 'compact',
|
|
@@ -703,7 +782,7 @@ function deriveParentUrl(url) {
|
|
|
703
782
|
function resolveAutoBreadcrumbs(renderable, pageUrl, breadcrumbPaths, pagesByUrl, ctx) {
|
|
704
783
|
if (!Tag.isTag(renderable)) {
|
|
705
784
|
if (Array.isArray(renderable)) {
|
|
706
|
-
const newChildren = renderable.map(c => resolveAutoBreadcrumbs(c, pageUrl, breadcrumbPaths, pagesByUrl, ctx));
|
|
785
|
+
const newChildren = renderable.map((c) => resolveAutoBreadcrumbs(c, pageUrl, breadcrumbPaths, pagesByUrl, ctx));
|
|
707
786
|
// Return original if nothing changed
|
|
708
787
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
709
788
|
return renderable;
|
|
@@ -743,7 +822,9 @@ function buildAutoBreadcrumb(originalTag, pageUrl, breadcrumbPaths, pagesByUrl,
|
|
|
743
822
|
continue;
|
|
744
823
|
const nameSpan = new Tag('span', { hidden: true }, [ancestorPage.title]);
|
|
745
824
|
const urlLink = new Tag('a', { href: ancestorUrl }, [ancestorPage.title]);
|
|
746
|
-
listItems.push(createComponentRenderable({
|
|
825
|
+
listItems.push(createComponentRenderable({
|
|
826
|
+
rune: 'breadcrumb-item',
|
|
827
|
+
schemaOrgType: 'ListItem',
|
|
747
828
|
tag: 'li',
|
|
748
829
|
properties: { name: nameSpan, url: urlLink },
|
|
749
830
|
children: [nameSpan, urlLink],
|
|
@@ -753,14 +834,18 @@ function buildAutoBreadcrumb(originalTag, pageUrl, breadcrumbPaths, pagesByUrl,
|
|
|
753
834
|
const currentPage = pagesByUrl.get(pageUrl);
|
|
754
835
|
const currentTitle = currentPage?.title ?? pageUrl;
|
|
755
836
|
const currentSpan = new Tag('span', {}, [currentTitle]);
|
|
756
|
-
listItems.push(createComponentRenderable({
|
|
837
|
+
listItems.push(createComponentRenderable({
|
|
838
|
+
rune: 'breadcrumb-item',
|
|
839
|
+
schemaOrgType: 'ListItem',
|
|
757
840
|
tag: 'li',
|
|
758
841
|
properties: { name: currentSpan },
|
|
759
842
|
children: [currentSpan],
|
|
760
843
|
}));
|
|
761
844
|
const newSeparatorMeta = new Tag('meta', { content: separator });
|
|
762
845
|
const itemsList = new Tag('ol', {}, listItems);
|
|
763
|
-
return createComponentRenderable({
|
|
846
|
+
return createComponentRenderable({
|
|
847
|
+
rune: 'breadcrumb',
|
|
848
|
+
schemaOrgType: 'BreadcrumbList',
|
|
764
849
|
tag: 'nav',
|
|
765
850
|
properties: { separator: newSeparatorMeta },
|
|
766
851
|
refs: { items: itemsList },
|
|
@@ -771,7 +856,7 @@ function buildAutoBreadcrumb(originalTag, pageUrl, breadcrumbPaths, pagesByUrl,
|
|
|
771
856
|
function resolveAutoNavs(renderable, pageUrl, pagesByUrl, ctx) {
|
|
772
857
|
if (!Tag.isTag(renderable)) {
|
|
773
858
|
if (Array.isArray(renderable)) {
|
|
774
|
-
const newChildren = renderable.map(c => resolveAutoNavs(c, pageUrl, pagesByUrl, ctx));
|
|
859
|
+
const newChildren = renderable.map((c) => resolveAutoNavs(c, pageUrl, pagesByUrl, ctx));
|
|
775
860
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
776
861
|
return renderable;
|
|
777
862
|
return newChildren;
|
|
@@ -799,21 +884,23 @@ function resolveAutoNavs(renderable, pageUrl, pagesByUrl, ctx) {
|
|
|
799
884
|
* declared. */
|
|
800
885
|
function buildAutoNav(pageUrl, pagesByUrl, ctx, originalTag) {
|
|
801
886
|
// Find direct children: pages whose parentUrl is this page's URL (excluding self)
|
|
802
|
-
const children = Array.from(pagesByUrl.values()).filter(p => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
887
|
+
const children = Array.from(pagesByUrl.values()).filter((p) => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
803
888
|
if (children.length === 0) {
|
|
804
889
|
ctx.warn(`Nav auto: page '${pageUrl}' has no registered child pages`, pageUrl);
|
|
805
890
|
}
|
|
806
|
-
const listItems = children.map(child => {
|
|
891
|
+
const listItems = children.map((child) => {
|
|
807
892
|
const titleSpan = new Tag('span', { 'data-field': 'slug' }, [child.title]);
|
|
808
893
|
const link = new Tag('a', { href: child.url }, [titleSpan]);
|
|
809
|
-
return createComponentRenderable({
|
|
894
|
+
return createComponentRenderable({
|
|
895
|
+
rune: 'nav-item',
|
|
810
896
|
tag: 'li',
|
|
811
897
|
properties: { slug: titleSpan },
|
|
812
898
|
children: [link],
|
|
813
899
|
});
|
|
814
900
|
});
|
|
815
901
|
const itemsList = new Tag('ul', {}, listItems);
|
|
816
|
-
const newNav = createComponentRenderable({
|
|
902
|
+
const newNav = createComponentRenderable({
|
|
903
|
+
rune: 'nav',
|
|
817
904
|
tag: 'nav',
|
|
818
905
|
properties: {
|
|
819
906
|
group: [],
|
|
@@ -823,7 +910,14 @@ function buildAutoNav(pageUrl, pagesByUrl, ctx, originalTag) {
|
|
|
823
910
|
});
|
|
824
911
|
// Preserve contextual attributes from the original nav so layout / auto /
|
|
825
912
|
// source-path survive sentinel replacement.
|
|
826
|
-
const carry = [
|
|
913
|
+
const carry = [
|
|
914
|
+
'layout',
|
|
915
|
+
'data-layout',
|
|
916
|
+
'data-auto',
|
|
917
|
+
'data-source-path',
|
|
918
|
+
'data-collapsible',
|
|
919
|
+
'data-default-open',
|
|
920
|
+
];
|
|
827
921
|
for (const k of carry) {
|
|
828
922
|
const v = originalTag?.attributes?.[k];
|
|
829
923
|
if (v !== undefined) {
|
|
@@ -911,7 +1005,7 @@ function findNavSlugSuggestions(slug, baseDir, pagesByUrl) {
|
|
|
911
1005
|
}
|
|
912
1006
|
sameSlug.sort();
|
|
913
1007
|
typoMatches.sort((a, b) => a.distance - b.distance || a.url.localeCompare(b.url));
|
|
914
|
-
const suggestions = [...sameSlug, ...typoMatches.map(t => t.url)];
|
|
1008
|
+
const suggestions = [...sameSlug, ...typoMatches.map((t) => t.url)];
|
|
915
1009
|
return suggestions.slice(0, 3);
|
|
916
1010
|
}
|
|
917
1011
|
/** SPEC-055 nav-location-relative slug resolution.
|
|
@@ -951,15 +1045,14 @@ function sharedPrefixLength(a, b) {
|
|
|
951
1045
|
* been migrated to use pre-resolved hrefs yet. SPEC-055's
|
|
952
1046
|
* `resolveNavSlug` is the canonical resolver for new code. */
|
|
953
1047
|
function resolveSlugToUrl(slug, pagesByUrl, currentUrl) {
|
|
954
|
-
const candidates = Array.from(pagesByUrl.values()).filter(p => p.url.endsWith('/' + slug) || p.url === '/' + slug);
|
|
1048
|
+
const candidates = Array.from(pagesByUrl.values()).filter((p) => p.url.endsWith('/' + slug) || p.url === '/' + slug);
|
|
955
1049
|
if (candidates.length === 0)
|
|
956
1050
|
return null;
|
|
957
1051
|
if (candidates.length === 1)
|
|
958
1052
|
return candidates[0].url;
|
|
959
1053
|
return candidates
|
|
960
1054
|
.slice()
|
|
961
|
-
.sort((a, b) => sharedPrefixLength(b.url, currentUrl) - sharedPrefixLength(a.url, currentUrl))[0]
|
|
962
|
-
.url;
|
|
1055
|
+
.sort((a, b) => sharedPrefixLength(b.url, currentUrl) - sharedPrefixLength(a.url, currentUrl))[0].url;
|
|
963
1056
|
}
|
|
964
1057
|
/** Read a NavItem's slug from either `data-slug` (post-engine) or a nested
|
|
965
1058
|
* `<span data-field="slug">` (pre-engine, e.g. layout regions). */
|
|
@@ -1075,7 +1168,7 @@ function urlMatchesGroup(currentUrl, itemUrls) {
|
|
|
1075
1168
|
function resolveCollapsibleNavs(renderable, pageUrl, pagesByUrl) {
|
|
1076
1169
|
if (!Tag.isTag(renderable)) {
|
|
1077
1170
|
if (Array.isArray(renderable)) {
|
|
1078
|
-
const newChildren = renderable.map(c => resolveCollapsibleNavs(c, pageUrl, pagesByUrl));
|
|
1171
|
+
const newChildren = renderable.map((c) => resolveCollapsibleNavs(c, pageUrl, pagesByUrl));
|
|
1079
1172
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1080
1173
|
return renderable;
|
|
1081
1174
|
return newChildren;
|
|
@@ -1083,11 +1176,13 @@ function resolveCollapsibleNavs(renderable, pageUrl, pagesByUrl) {
|
|
|
1083
1176
|
return renderable;
|
|
1084
1177
|
}
|
|
1085
1178
|
const tag = renderable;
|
|
1086
|
-
if (tag.attributes?.['data-rune'] === 'nav' &&
|
|
1087
|
-
tag.attributes?.['data-collapsible'] === 'true') {
|
|
1179
|
+
if (tag.attributes?.['data-rune'] === 'nav' && tag.attributes?.['data-collapsible'] === 'true') {
|
|
1088
1180
|
const defaultOpenRaw = String(tag.attributes?.['data-default-open'] ?? '');
|
|
1089
1181
|
const defaultOpen = defaultOpenRaw
|
|
1090
|
-
? defaultOpenRaw
|
|
1182
|
+
? defaultOpenRaw
|
|
1183
|
+
.split(',')
|
|
1184
|
+
.map((s) => s.trim())
|
|
1185
|
+
.filter(Boolean)
|
|
1091
1186
|
: [];
|
|
1092
1187
|
const groups = [];
|
|
1093
1188
|
const findGroups = (node) => {
|
|
@@ -1107,7 +1202,7 @@ function resolveCollapsibleNavs(renderable, pageUrl, pagesByUrl) {
|
|
|
1107
1202
|
const inDefault = title && defaultOpen.includes(title);
|
|
1108
1203
|
const itemUrls = collectGroupItemUrls(group, pagesByUrl, pageUrl);
|
|
1109
1204
|
const matches = urlMatchesGroup(pageUrl, itemUrls);
|
|
1110
|
-
group.attributes['data-collapsed'] =
|
|
1205
|
+
group.attributes['data-collapsed'] = inDefault || matches ? 'false' : 'true';
|
|
1111
1206
|
}
|
|
1112
1207
|
const newChildren = (tag.children ?? []).map((c) => resolveCollapsibleNavs(c, pageUrl, pagesByUrl));
|
|
1113
1208
|
if (newChildren.every((c, i) => c === tag.children[i]))
|
|
@@ -1130,7 +1225,9 @@ function enrichNavItemAsCard(item, pageMeta, itemUrl) {
|
|
|
1130
1225
|
}
|
|
1131
1226
|
linkChildren.push(new Tag('span', { 'data-name': 'title', class: 'rf-nav-item__title' }, [titleText]));
|
|
1132
1227
|
if (description) {
|
|
1133
|
-
linkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1228
|
+
linkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1229
|
+
description,
|
|
1230
|
+
]));
|
|
1134
1231
|
}
|
|
1135
1232
|
const link = href
|
|
1136
1233
|
? new Tag('a', { href, class: 'rf-nav-item__link' }, linkChildren)
|
|
@@ -1197,7 +1294,9 @@ function augmentNavItemFromFrontmatter(item, pageMeta) {
|
|
|
1197
1294
|
newLinkChildren.unshift(new Tag('rf-icon', { name: pageMeta.icon, 'data-name': 'icon', class: 'rf-nav-item__icon' }, []));
|
|
1198
1295
|
}
|
|
1199
1296
|
if (pageMeta.description && !hasDescription) {
|
|
1200
|
-
newLinkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1297
|
+
newLinkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1298
|
+
pageMeta.description,
|
|
1299
|
+
]));
|
|
1201
1300
|
}
|
|
1202
1301
|
return { ...t, children: newLinkChildren };
|
|
1203
1302
|
});
|
|
@@ -1206,7 +1305,7 @@ function augmentNavItemFromFrontmatter(item, pageMeta) {
|
|
|
1206
1305
|
function resolveCardsNavs(renderable, pageUrl, pagesByUrl) {
|
|
1207
1306
|
if (!Tag.isTag(renderable)) {
|
|
1208
1307
|
if (Array.isArray(renderable)) {
|
|
1209
|
-
const newChildren = renderable.map(c => resolveCardsNavs(c, pageUrl, pagesByUrl));
|
|
1308
|
+
const newChildren = renderable.map((c) => resolveCardsNavs(c, pageUrl, pagesByUrl));
|
|
1210
1309
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1211
1310
|
return renderable;
|
|
1212
1311
|
return newChildren;
|
|
@@ -1282,7 +1381,13 @@ function formatNavResolutionError(slug, sourcePath, attemptedUrl, suggestions) {
|
|
|
1282
1381
|
const head = `Nav item \`${slug}\`${where} cannot be resolved (no page at \`${attemptedUrl}\`).`;
|
|
1283
1382
|
if (suggestions.length === 0)
|
|
1284
1383
|
return head;
|
|
1285
|
-
const lines = [
|
|
1384
|
+
const lines = [
|
|
1385
|
+
'',
|
|
1386
|
+
'Did you mean one of:',
|
|
1387
|
+
...suggestions.map((s) => ` - ${s}`),
|
|
1388
|
+
'',
|
|
1389
|
+
'Use a multi-segment slug (e.g. `section/page`) or an explicit `[Label](/path)` link.',
|
|
1390
|
+
];
|
|
1286
1391
|
return head + '\n' + lines.join('\n');
|
|
1287
1392
|
}
|
|
1288
1393
|
/** Walk a nav subtree, resolve every NavItem's `data-slug` to a real `<a href>`
|
|
@@ -1345,7 +1450,7 @@ function resolveNavItemsInSubtree(navTag, pagesByUrl, ctx, pageUrl) {
|
|
|
1345
1450
|
function resolveNavSlugs(renderable, pagesByUrl, ctx, pageUrl) {
|
|
1346
1451
|
if (!Tag.isTag(renderable)) {
|
|
1347
1452
|
if (Array.isArray(renderable)) {
|
|
1348
|
-
const next = renderable.map(c => resolveNavSlugs(c, pagesByUrl, ctx, pageUrl));
|
|
1453
|
+
const next = renderable.map((c) => resolveNavSlugs(c, pagesByUrl, ctx, pageUrl));
|
|
1349
1454
|
return next.every((c, i) => c === renderable[i]) ? renderable : next;
|
|
1350
1455
|
}
|
|
1351
1456
|
return renderable;
|
|
@@ -1561,10 +1666,10 @@ function getSiblingPages(currentUrl, pagesByUrl, scope) {
|
|
|
1561
1666
|
cursor = parent;
|
|
1562
1667
|
}
|
|
1563
1668
|
const prefix = sectionRoot.endsWith('/') ? sectionRoot : sectionRoot + '/';
|
|
1564
|
-
candidates = pages.filter(p => p.url === sectionRoot || p.url.startsWith(prefix));
|
|
1669
|
+
candidates = pages.filter((p) => p.url === sectionRoot || p.url.startsWith(prefix));
|
|
1565
1670
|
}
|
|
1566
1671
|
else {
|
|
1567
|
-
candidates = pages.filter(p => p.parentUrl === current.parentUrl);
|
|
1672
|
+
candidates = pages.filter((p) => p.parentUrl === current.parentUrl);
|
|
1568
1673
|
}
|
|
1569
1674
|
// Sort by frontmatter order (asc, missing → end), tie-break by URL.
|
|
1570
1675
|
candidates.sort((a, b) => {
|
|
@@ -1574,7 +1679,7 @@ function getSiblingPages(currentUrl, pagesByUrl, scope) {
|
|
|
1574
1679
|
return ao - bo;
|
|
1575
1680
|
return a.url.localeCompare(b.url);
|
|
1576
1681
|
});
|
|
1577
|
-
return candidates.map(p => ({ url: p.url, title: p.title }));
|
|
1682
|
+
return candidates.map((p) => ({ url: p.url, title: p.title }));
|
|
1578
1683
|
}
|
|
1579
1684
|
function pickPrevNextFromSequence(sequence, currentUrl, pagesByUrl) {
|
|
1580
1685
|
const idx = sequence.indexOf(currentUrl);
|
|
@@ -1611,7 +1716,7 @@ function buildPaginationLink(target, direction, label) {
|
|
|
1611
1716
|
function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable) {
|
|
1612
1717
|
if (!Tag.isTag(renderable)) {
|
|
1613
1718
|
if (Array.isArray(renderable)) {
|
|
1614
|
-
const newChildren = renderable.map(c => resolveAutoPagination(c, pageUrl, pagesByUrl, rootRenderable));
|
|
1719
|
+
const newChildren = renderable.map((c) => resolveAutoPagination(c, pageUrl, pagesByUrl, rootRenderable));
|
|
1615
1720
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1616
1721
|
return renderable;
|
|
1617
1722
|
return newChildren;
|
|
@@ -1629,10 +1734,14 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1629
1734
|
const scope = (scopeValue === 'section' ? 'section' : 'siblings');
|
|
1630
1735
|
const prevLabelMeta = (tag.children ?? []).find((c) => Tag.isTag(c) && c.attributes?.['data-field'] === 'prev-label');
|
|
1631
1736
|
const nextLabelMeta = (tag.children ?? []).find((c) => Tag.isTag(c) && c.attributes?.['data-field'] === 'next-label');
|
|
1632
|
-
const prevLabel = prevLabelMeta
|
|
1633
|
-
|
|
1737
|
+
const prevLabel = prevLabelMeta
|
|
1738
|
+
? String(prevLabelMeta.attributes.content ?? '')
|
|
1739
|
+
: undefined;
|
|
1740
|
+
const nextLabel = nextLabelMeta
|
|
1741
|
+
? String(nextLabelMeta.attributes.content ?? '')
|
|
1742
|
+
: undefined;
|
|
1634
1743
|
// Skip when current page is a section index (has children)
|
|
1635
|
-
const hasChildren = Array.from(pagesByUrl.values()).some(p => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
1744
|
+
const hasChildren = Array.from(pagesByUrl.values()).some((p) => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
1636
1745
|
if (hasChildren) {
|
|
1637
1746
|
return { ...tag, children: [] };
|
|
1638
1747
|
}
|
|
@@ -1653,7 +1762,7 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1653
1762
|
else {
|
|
1654
1763
|
// 2. Sibling pages by frontmatter order → directory order
|
|
1655
1764
|
const siblings = getSiblingPages(pageUrl, pagesByUrl, scope);
|
|
1656
|
-
const idx = siblings.findIndex(s => s.url === pageUrl);
|
|
1765
|
+
const idx = siblings.findIndex((s) => s.url === pageUrl);
|
|
1657
1766
|
if (idx !== -1) {
|
|
1658
1767
|
prev = idx > 0 ? siblings[idx - 1] : null;
|
|
1659
1768
|
next = idx < siblings.length - 1 ? siblings[idx + 1] : null;
|
|
@@ -1680,7 +1789,9 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1680
1789
|
const newChildren = (tag.children ?? []).map((c) => {
|
|
1681
1790
|
if (!Tag.isTag(c))
|
|
1682
1791
|
return c;
|
|
1683
|
-
if (c.name === 'a' &&
|
|
1792
|
+
if (c.name === 'a' &&
|
|
1793
|
+
typeof c.attributes?.href === 'string' &&
|
|
1794
|
+
c.attributes.href.startsWith('__slug:')) {
|
|
1684
1795
|
const slug = c.attributes.href.slice('__slug:'.length);
|
|
1685
1796
|
const resolvedUrl = resolveSlugToUrl(slug, pagesByUrl, pageUrl);
|
|
1686
1797
|
if (resolvedUrl) {
|
|
@@ -1689,14 +1800,20 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1689
1800
|
// Replace label text if user didn't override (label child has same text as slug)
|
|
1690
1801
|
const newChildren = (c.children ?? []).map((child) => {
|
|
1691
1802
|
if (Tag.isTag(child) && child.attributes?.['data-name'] === 'label') {
|
|
1692
|
-
const currentLabel = (child.children ?? [])
|
|
1803
|
+
const currentLabel = (child.children ?? [])
|
|
1804
|
+
.filter((x) => typeof x === 'string')
|
|
1805
|
+
.join('');
|
|
1693
1806
|
if (currentLabel === slug) {
|
|
1694
1807
|
return { ...child, children: [newLabel] };
|
|
1695
1808
|
}
|
|
1696
1809
|
}
|
|
1697
1810
|
return child;
|
|
1698
1811
|
});
|
|
1699
|
-
return {
|
|
1812
|
+
return {
|
|
1813
|
+
...c,
|
|
1814
|
+
attributes: { ...c.attributes, href: resolvedUrl },
|
|
1815
|
+
children: newChildren,
|
|
1816
|
+
};
|
|
1700
1817
|
}
|
|
1701
1818
|
}
|
|
1702
1819
|
return c;
|
|
@@ -1715,7 +1832,7 @@ function walkBlogTags(node, fn) {
|
|
|
1715
1832
|
walkBlogTags(child, fn);
|
|
1716
1833
|
}
|
|
1717
1834
|
else if (Array.isArray(node)) {
|
|
1718
|
-
node.forEach(n => walkBlogTags(n, fn));
|
|
1835
|
+
node.forEach((n) => walkBlogTags(n, fn));
|
|
1719
1836
|
}
|
|
1720
1837
|
}
|
|
1721
1838
|
function mapBlogTags(node, fn) {
|
|
@@ -1723,12 +1840,12 @@ function mapBlogTags(node, fn) {
|
|
|
1723
1840
|
const mapped = fn(node);
|
|
1724
1841
|
if (mapped !== node)
|
|
1725
1842
|
return mapped;
|
|
1726
|
-
const newChildren = node.children.map(c => mapBlogTags(c, fn));
|
|
1843
|
+
const newChildren = node.children.map((c) => mapBlogTags(c, fn));
|
|
1727
1844
|
const changed = newChildren.some((c, i) => c !== node.children[i]);
|
|
1728
1845
|
return changed ? new Tag(node.name, node.attributes, newChildren) : node;
|
|
1729
1846
|
}
|
|
1730
1847
|
if (Array.isArray(node))
|
|
1731
|
-
return node.map(n => mapBlogTags(n, fn));
|
|
1848
|
+
return node.map((n) => mapBlogTags(n, fn));
|
|
1732
1849
|
return node;
|
|
1733
1850
|
}
|
|
1734
1851
|
/** Normalise folder path for prefix matching: ensure leading slash and trailing slash */
|
|
@@ -1752,7 +1869,7 @@ function isInFolder(pageUrl, folder) {
|
|
|
1752
1869
|
function parseBlogFilter(filter) {
|
|
1753
1870
|
if (!filter || !filter.trim())
|
|
1754
1871
|
return [];
|
|
1755
|
-
return filter.split(',').map(part => {
|
|
1872
|
+
return filter.split(',').map((part) => {
|
|
1756
1873
|
const colonIdx = part.indexOf(':');
|
|
1757
1874
|
if (colonIdx === -1)
|
|
1758
1875
|
return { field: part.trim(), value: '' };
|
|
@@ -1771,7 +1888,7 @@ function matchesBlogFilter(post, filters) {
|
|
|
1771
1888
|
return false;
|
|
1772
1889
|
}
|
|
1773
1890
|
else if (Array.isArray(fmValue)) {
|
|
1774
|
-
if (!fmValue.some(v => String(v).toLowerCase() === value.toLowerCase()))
|
|
1891
|
+
if (!fmValue.some((v) => String(v).toLowerCase() === value.toLowerCase()))
|
|
1775
1892
|
return false;
|
|
1776
1893
|
}
|
|
1777
1894
|
else {
|
|
@@ -1803,9 +1920,7 @@ function sortBlogPosts(posts, sort) {
|
|
|
1803
1920
|
}
|
|
1804
1921
|
/** Build an <article> Tag for a single blog post entry */
|
|
1805
1922
|
function createBlogPostTag(post) {
|
|
1806
|
-
const titleTag = new Tag('h3', {}, [
|
|
1807
|
-
new Tag('a', { href: post.url }, [post.title]),
|
|
1808
|
-
]);
|
|
1923
|
+
const titleTag = new Tag('h3', {}, [new Tag('a', { href: post.url }, [post.title])]);
|
|
1809
1924
|
const children = [titleTag];
|
|
1810
1925
|
if (post.date) {
|
|
1811
1926
|
children.push(new Tag('time', { datetime: post.date }, [post.date]));
|
|
@@ -1834,7 +1949,7 @@ function resolveBlogPosts(renderable, allPosts, ctx, pageUrl) {
|
|
|
1834
1949
|
}
|
|
1835
1950
|
const normalised = normaliseFolderPath(folder);
|
|
1836
1951
|
const filters = parseBlogFilter(filterStr);
|
|
1837
|
-
let posts = allPosts.filter(post => {
|
|
1952
|
+
let posts = allPosts.filter((post) => {
|
|
1838
1953
|
if (post.draft)
|
|
1839
1954
|
return false;
|
|
1840
1955
|
if (!isInFolder(post.url, normalised))
|
|
@@ -1881,9 +1996,7 @@ navSearchScope) {
|
|
|
1881
1996
|
result = resolveNavSlugs(result, coreData.pagesByUrl, ctx, pageUrl);
|
|
1882
1997
|
result = resolveCollapsibleNavs(result, pageUrl, coreData.pagesByUrl);
|
|
1883
1998
|
result = resolveCardsNavs(result, pageUrl, coreData.pagesByUrl);
|
|
1884
|
-
const searchRoot = navSearchScope && navSearchScope.length > 0
|
|
1885
|
-
? [result, ...navSearchScope]
|
|
1886
|
-
: result;
|
|
1999
|
+
const searchRoot = navSearchScope && navSearchScope.length > 0 ? [result, ...navSearchScope] : result;
|
|
1887
2000
|
result = resolveAutoPagination(result, pageUrl, coreData.pagesByUrl, searchRoot);
|
|
1888
2001
|
// SPEC-055 — mark aria-current / data-active="ancestor" on resolved nav
|
|
1889
2002
|
// links per page. Runs after slug + auto-pagination resolution so the
|
|
@@ -1909,9 +2022,15 @@ navSearchScope) {
|
|
|
1909
2022
|
* any custom field.
|
|
1910
2023
|
*/
|
|
1911
2024
|
const RESERVED_PAGE_FRONTMATTER = new Set([
|
|
1912
|
-
'layout',
|
|
2025
|
+
'layout',
|
|
2026
|
+
'tint',
|
|
2027
|
+
'tint-mode',
|
|
2028
|
+
'tint-lock',
|
|
2029
|
+
'slug',
|
|
2030
|
+
'redirect',
|
|
1913
2031
|
// entity-declaration keys (SPEC-092 Layer 2) — meta, not queryable content
|
|
1914
|
-
'type',
|
|
2032
|
+
'type',
|
|
2033
|
+
'id',
|
|
1915
2034
|
]);
|
|
1916
2035
|
export function createCorePipelineHooks(opts = {}) {
|
|
1917
2036
|
const xrefPatterns = opts.xrefPatterns ?? [];
|
|
@@ -1919,13 +2038,20 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
1919
2038
|
const repoUrl = opts.repoUrl;
|
|
1920
2039
|
const repoBranch = opts.repoBranch;
|
|
1921
2040
|
return {
|
|
1922
|
-
// Compose the core preprocess steps:
|
|
1923
|
-
//
|
|
1924
|
-
//
|
|
2041
|
+
// Compose the core preprocess steps: include (→ pasted AST), then snippet
|
|
2042
|
+
// (→ fence), then data (→ table). All three mutate the AST in place, so a
|
|
2043
|
+
// single pass over the same tree applies them; any one mutating means the
|
|
2044
|
+
// caller takes the returned AST.
|
|
2045
|
+
//
|
|
2046
|
+
// **Include runs first, and the order is load-bearing** (SPEC-129): the
|
|
2047
|
+
// whole point of the rune is that the pasted content is in the tree when the
|
|
2048
|
+
// later preprocessors walk it. Anything added to this phase that authors may
|
|
2049
|
+
// want inside an included file belongs after include, not before.
|
|
1925
2050
|
preprocess(ast, page, ctx) {
|
|
2051
|
+
const includeChanged = preprocessIncludes(ast, page, ctx);
|
|
1926
2052
|
const snippetChanged = preprocessSnippets(ast, page, ctx);
|
|
1927
2053
|
const dataChanged = preprocessData(ast, page, ctx);
|
|
1928
|
-
return
|
|
2054
|
+
return includeChanged || snippetChanged || dataChanged ? ast : undefined;
|
|
1929
2055
|
},
|
|
1930
2056
|
register(pages, registry, ctx) {
|
|
1931
2057
|
for (const page of pages) {
|
|
@@ -1979,7 +2105,7 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
1979
2105
|
},
|
|
1980
2106
|
aggregate(registry, ctx) {
|
|
1981
2107
|
const pageEntities = registry.getAll('page');
|
|
1982
|
-
const pages = pageEntities.map(e => ({
|
|
2108
|
+
const pages = pageEntities.map((e) => ({
|
|
1983
2109
|
url: e.data.url,
|
|
1984
2110
|
title: e.data.title,
|
|
1985
2111
|
parentUrl: e.data.parentUrl,
|
|
@@ -1990,14 +2116,14 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
1990
2116
|
const pageTree = buildPageTree(pages);
|
|
1991
2117
|
const breadcrumbPaths = buildBreadcrumbPaths(pages);
|
|
1992
2118
|
// Quick lookup: url → { url, title } for postProcess use
|
|
1993
|
-
const pagesByUrl = new Map(pages.map(p => [p.url, p]));
|
|
2119
|
+
const pagesByUrl = new Map(pages.map((p) => [p.url, p]));
|
|
1994
2120
|
// Build heading index: "url#id" → heading data
|
|
1995
2121
|
const headingIndex = new Map();
|
|
1996
2122
|
for (const h of registry.getAll('heading')) {
|
|
1997
2123
|
headingIndex.set(h.id, h.data);
|
|
1998
2124
|
}
|
|
1999
2125
|
// Blog: collect all pages as potential blog posts
|
|
2000
|
-
const allPosts = pageEntities.map(e => ({
|
|
2126
|
+
const allPosts = pageEntities.map((e) => ({
|
|
2001
2127
|
title: e.data.title || '',
|
|
2002
2128
|
url: e.data.url || e.id,
|
|
2003
2129
|
date: e.data.date || '',
|
|
@@ -2005,7 +2131,18 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
2005
2131
|
draft: e.data.draft || false,
|
|
2006
2132
|
frontmatter: e.data,
|
|
2007
2133
|
}));
|
|
2008
|
-
return {
|
|
2134
|
+
return {
|
|
2135
|
+
pageTree,
|
|
2136
|
+
breadcrumbPaths,
|
|
2137
|
+
pagesByUrl,
|
|
2138
|
+
headingIndex,
|
|
2139
|
+
allPosts,
|
|
2140
|
+
registry,
|
|
2141
|
+
xrefPatterns,
|
|
2142
|
+
embedConfig,
|
|
2143
|
+
repoUrl,
|
|
2144
|
+
repoBranch,
|
|
2145
|
+
};
|
|
2009
2146
|
},
|
|
2010
2147
|
postProcess(page, aggregated, ctx) {
|
|
2011
2148
|
const coreData = aggregated['__core__'];
|