@refrakt-md/runes 0.33.0 → 0.35.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 +218 -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.map +1 -1
- package/dist/data-emit.js.map +1 -1
- package/dist/data-pipeline.d.ts.map +1 -1
- package/dist/data-pipeline.js +45 -12
- package/dist/data-pipeline.js.map +1 -1
- package/dist/data-projection.d.ts.map +1 -1
- package/dist/data-projection.js +4 -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.map +1 -1
- package/dist/include-pipeline.js +3 -1
- package/dist/include-pipeline.js.map +1 -1
- package/dist/index.d.ts +95 -37
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +273 -60
- 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 +2 -2
- 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.map +1 -1
- package/dist/lib/component.js +7 -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 +29 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +298 -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 +42 -36
- package/dist/lib/resolver.js.map +1 -1
- package/dist/lib/schema-table.d.ts +176 -0
- package/dist/lib/schema-table.d.ts.map +1 -0
- package/dist/lib/schema-table.js +427 -0
- package/dist/lib/schema-table.js.map +1 -0
- 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 +9 -11
- 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 +33 -0
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +60 -23
- 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 +0 -2
- package/dist/rune.d.ts.map +1 -1
- package/dist/rune.js +0 -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/schema-row.d.ts +89 -0
- package/dist/schema-row.d.ts.map +1 -0
- package/dist/schema-row.js +78 -0
- package/dist/schema-row.js.map +1 -0
- package/dist/seo.d.ts +9 -0
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +88 -11
- 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 +58 -0
- package/dist/tags/accordion.d.ts.map +1 -1
- package/dist/tags/accordion.js +69 -23
- 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 +43 -10
- package/dist/tags/blog.js.map +1 -1
- package/dist/tags/breadcrumb.d.ts +30 -0
- package/dist/tags/breadcrumb.d.ts.map +1 -1
- package/dist/tags/breadcrumb.js +57 -28
- package/dist/tags/breadcrumb.js.map +1 -1
- package/dist/tags/budget.d.ts.map +1 -1
- package/dist/tags/budget.js +60 -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/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 +67 -13
- package/dist/tags/data.js.map +1 -1
- package/dist/tags/datatable.d.ts.map +1 -1
- package/dist/tags/datatable.js +27 -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 +8 -0
- package/dist/tags/embed.d.ts.map +1 -1
- package/dist/tags/embed.js +28 -10
- 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 +7 -0
- package/dist/tags/figure.d.ts.map +1 -1
- package/dist/tags/figure.js +42 -13
- 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 +33 -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.map +1 -1
- package/dist/tags/include.js +1 -1
- package/dist/tags/include.js.map +1 -1
- 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.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.map +1 -1
- package/dist/util.js +4 -4
- 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,15 +1,15 @@
|
|
|
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
|
-
import { createComponentRenderable } from './lib/index.js';
|
|
5
|
-
import { BREADCRUMB_AUTO_SENTINEL } from './tags/breadcrumb.js';
|
|
4
|
+
import { applySchemaTable, createComponentRenderable } from './lib/index.js';
|
|
5
|
+
import { BREADCRUMB_AUTO_SENTINEL, breadcrumbSchema } from './tags/breadcrumb.js';
|
|
6
6
|
import { NAV_AUTO_SENTINEL, NAV_COLLAPSED_AUTO } from './tags/nav.js';
|
|
7
7
|
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
11
|
import { preprocessIncludes } from './include-pipeline.js';
|
|
12
|
-
import { registerDrawers, resolveAutoDrawerTitleLevels, hoistPreviewDrawers } from './drawer-pipeline.js';
|
|
12
|
+
import { registerDrawers, resolveAutoDrawerTitleLevels, hoistPreviewDrawers, } from './drawer-pipeline.js';
|
|
13
13
|
import { resolveFileRefs } from './file-ref-resolve.js';
|
|
14
14
|
import { resolveXrefPreviews } from './xref-preview-resolve.js';
|
|
15
15
|
import { applyOutlineScopeWalkers, harvestHeadingsFromRenderable } from './outline-scope.js';
|
|
@@ -44,7 +44,12 @@ import { tabGroupSections } from './tags/tabs.js';
|
|
|
44
44
|
/** Read text content from a property span child */
|
|
45
45
|
function readPropText(node, prop) {
|
|
46
46
|
for (const c of node.children) {
|
|
47
|
-
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()) {
|
|
48
53
|
return c.children.filter((ch) => typeof ch === 'string').join('');
|
|
49
54
|
}
|
|
50
55
|
}
|
|
@@ -66,22 +71,35 @@ export const coreConfig = {
|
|
|
66
71
|
icons: {},
|
|
67
72
|
runes: {
|
|
68
73
|
// ─── Simple runes (block name only, engine adds BEM classes) ───
|
|
69
|
-
Accordion: {
|
|
74
|
+
Accordion: {
|
|
75
|
+
block: 'accordion',
|
|
76
|
+
defaultDensity: 'full',
|
|
77
|
+
sections: accordionSections,
|
|
78
|
+
autoLabel: pageSectionAutoLabel,
|
|
79
|
+
editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' },
|
|
80
|
+
},
|
|
70
81
|
// SPEC-125 Phase 1 — the answer panel is the item's `body` role, so
|
|
71
82
|
// `reading` / `dropcap` land on it. The header decision is recorded in
|
|
72
83
|
// `sectionRoleExceptions` so it travels with the rune.
|
|
73
84
|
AccordionItem: {
|
|
74
|
-
block: 'accordion-item',
|
|
85
|
+
block: 'accordion-item',
|
|
86
|
+
parent: 'Accordion',
|
|
87
|
+
requiresParent: 'Accordion',
|
|
75
88
|
rootAttributes: { 'data-state': 'closed' },
|
|
76
89
|
autoLabel: { name: 'header' },
|
|
77
90
|
sections: accordionItemSections,
|
|
78
91
|
provides: ['prose'],
|
|
79
92
|
sectionRoleExceptions: {
|
|
80
|
-
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`.",
|
|
81
94
|
},
|
|
82
95
|
editHints: { header: 'inline', body: 'none' },
|
|
83
96
|
},
|
|
84
|
-
Details: {
|
|
97
|
+
Details: {
|
|
98
|
+
block: 'details',
|
|
99
|
+
defaultElevation: 'flush',
|
|
100
|
+
autoLabel: { summary: 'summary' },
|
|
101
|
+
editHints: { summary: 'inline', body: 'none' },
|
|
102
|
+
},
|
|
85
103
|
Grid: {
|
|
86
104
|
block: 'grid',
|
|
87
105
|
defaultDensity: 'full',
|
|
@@ -110,7 +128,10 @@ export const coreConfig = {
|
|
|
110
128
|
interactive: true,
|
|
111
129
|
defaultDensity: 'compact',
|
|
112
130
|
defaultElevation: 'flat',
|
|
113
|
-
modifiers: {
|
|
131
|
+
modifiers: {
|
|
132
|
+
title: { source: 'meta', noBemClass: true },
|
|
133
|
+
overflow: { source: 'meta', default: 'scroll' },
|
|
134
|
+
},
|
|
114
135
|
// The window chrome (three dots) is pure decoration — drawn in CSS
|
|
115
136
|
// on `.rf-codegroup__topbar`. The only metadata is the optional
|
|
116
137
|
// filename `title`, a bare monospace field in the topbar bar.
|
|
@@ -263,7 +284,11 @@ export const coreConfig = {
|
|
|
263
284
|
separator: { prop: '--separator', template: '"{}"' },
|
|
264
285
|
},
|
|
265
286
|
},
|
|
266
|
-
BreadcrumbItem: {
|
|
287
|
+
BreadcrumbItem: {
|
|
288
|
+
block: 'breadcrumb-item',
|
|
289
|
+
parent: 'Breadcrumb',
|
|
290
|
+
requiresParent: 'Breadcrumb',
|
|
291
|
+
},
|
|
267
292
|
Blog: {
|
|
268
293
|
block: 'blog',
|
|
269
294
|
defaultDensity: 'full',
|
|
@@ -327,7 +352,7 @@ export const coreConfig = {
|
|
|
327
352
|
defaultDensity: 'compact',
|
|
328
353
|
defaultElevation: 'sunken',
|
|
329
354
|
modifiers: { hintType: { source: 'meta', default: 'note' } },
|
|
330
|
-
contextModifiers: {
|
|
355
|
+
contextModifiers: { hero: 'in-hero', feature: 'in-feature' },
|
|
331
356
|
sections: hintSections,
|
|
332
357
|
// SPEC-035 Zone 6 — the hintType value doubles as the visible title
|
|
333
358
|
// (CSS capitalizes it). Declaring it as an enum lets `core.hint.<value>`
|
|
@@ -401,7 +426,12 @@ export const coreConfig = {
|
|
|
401
426
|
modifiers: { layout: { source: 'meta', default: 'side-by-side' } },
|
|
402
427
|
editHints: { panels: 'none' },
|
|
403
428
|
},
|
|
404
|
-
Conversation: {
|
|
429
|
+
Conversation: {
|
|
430
|
+
block: 'conversation',
|
|
431
|
+
defaultDensity: 'compact',
|
|
432
|
+
defaultElevation: 'flush',
|
|
433
|
+
editHints: { messages: 'none' },
|
|
434
|
+
},
|
|
405
435
|
ConversationMessage: {
|
|
406
436
|
block: 'conversation-message',
|
|
407
437
|
parent: 'Conversation',
|
|
@@ -444,7 +474,7 @@ export const coreConfig = {
|
|
|
444
474
|
// Extract slug from span[property="slug"] child → data-slug attribute
|
|
445
475
|
// Keep slug text as visible fallback for SSR; web component replaces with <a> links
|
|
446
476
|
let slug = '';
|
|
447
|
-
const children = node.children.filter(child => {
|
|
477
|
+
const children = node.children.filter((child) => {
|
|
448
478
|
if (isTag(child) && child.name === 'span' && child.attributes['data-field'] === 'slug') {
|
|
449
479
|
slug = child.children.filter((c) => typeof c === 'string').join('');
|
|
450
480
|
return false; // remove slug span from DOM
|
|
@@ -461,10 +491,16 @@ export const coreConfig = {
|
|
|
461
491
|
};
|
|
462
492
|
}
|
|
463
493
|
// Explicit link item: add nav-item__link class to <a> tags for styling
|
|
464
|
-
const styledChildren = children.map(child => {
|
|
494
|
+
const styledChildren = children.map((child) => {
|
|
465
495
|
if (isTag(child) && child.name === 'a') {
|
|
466
496
|
const existing = child.attributes.class || '';
|
|
467
|
-
return {
|
|
497
|
+
return {
|
|
498
|
+
...child,
|
|
499
|
+
attributes: {
|
|
500
|
+
...child.attributes,
|
|
501
|
+
class: ['rf-nav-item__link', existing].filter(Boolean).join(' '),
|
|
502
|
+
},
|
|
503
|
+
};
|
|
468
504
|
}
|
|
469
505
|
return child;
|
|
470
506
|
});
|
|
@@ -474,7 +510,12 @@ export const coreConfig = {
|
|
|
474
510
|
Diff: {
|
|
475
511
|
block: 'diff',
|
|
476
512
|
modifiers: { mode: { source: 'meta', default: 'unified' } },
|
|
477
|
-
editHints: {
|
|
513
|
+
editHints: {
|
|
514
|
+
line: 'none',
|
|
515
|
+
'gutter-num': 'none',
|
|
516
|
+
'gutter-prefix': 'none',
|
|
517
|
+
'line-content': 'none',
|
|
518
|
+
},
|
|
478
519
|
},
|
|
479
520
|
Chart: {
|
|
480
521
|
block: 'chart',
|
|
@@ -550,9 +591,27 @@ export const coreConfig = {
|
|
|
550
591
|
editHints: { viewport: 'none' },
|
|
551
592
|
},
|
|
552
593
|
// ─── Interactive runes (still get BEM classes, components add behavior) ───
|
|
553
|
-
TabGroup: {
|
|
554
|
-
|
|
555
|
-
|
|
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
|
+
},
|
|
556
615
|
DataTable: {
|
|
557
616
|
block: 'datatable',
|
|
558
617
|
interactive: true,
|
|
@@ -601,7 +660,12 @@ export const coreConfig = {
|
|
|
601
660
|
autoLabel: pageSectionAutoLabel,
|
|
602
661
|
editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline', steps: 'none' },
|
|
603
662
|
},
|
|
604
|
-
RevealStep: {
|
|
663
|
+
RevealStep: {
|
|
664
|
+
block: 'reveal-step',
|
|
665
|
+
parent: 'Reveal',
|
|
666
|
+
rootAttributes: { 'data-state': 'closed' },
|
|
667
|
+
editHints: { body: 'none' },
|
|
668
|
+
},
|
|
605
669
|
Section: {
|
|
606
670
|
block: 'section',
|
|
607
671
|
modifiers: {
|
|
@@ -627,7 +691,13 @@ export const coreConfig = {
|
|
|
627
691
|
},
|
|
628
692
|
editHints: { panels: 'none' },
|
|
629
693
|
},
|
|
630
|
-
JuxtaposePanel: {
|
|
694
|
+
JuxtaposePanel: {
|
|
695
|
+
block: 'juxtapose-panel',
|
|
696
|
+
parent: 'Juxtapose',
|
|
697
|
+
requiresParent: 'Juxtapose',
|
|
698
|
+
rootAttributes: { 'data-state': 'inactive' },
|
|
699
|
+
editHints: { body: 'none' },
|
|
700
|
+
},
|
|
631
701
|
Diagram: {
|
|
632
702
|
block: 'diagram',
|
|
633
703
|
defaultDensity: 'compact',
|
|
@@ -712,7 +782,7 @@ function deriveParentUrl(url) {
|
|
|
712
782
|
function resolveAutoBreadcrumbs(renderable, pageUrl, breadcrumbPaths, pagesByUrl, ctx) {
|
|
713
783
|
if (!Tag.isTag(renderable)) {
|
|
714
784
|
if (Array.isArray(renderable)) {
|
|
715
|
-
const newChildren = renderable.map(c => resolveAutoBreadcrumbs(c, pageUrl, breadcrumbPaths, pagesByUrl, ctx));
|
|
785
|
+
const newChildren = renderable.map((c) => resolveAutoBreadcrumbs(c, pageUrl, breadcrumbPaths, pagesByUrl, ctx));
|
|
716
786
|
// Return original if nothing changed
|
|
717
787
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
718
788
|
return renderable;
|
|
@@ -744,7 +814,19 @@ function buildAutoBreadcrumb(originalTag, pageUrl, breadcrumbPaths, pagesByUrl,
|
|
|
744
814
|
// Find separator from existing meta child
|
|
745
815
|
const separatorMeta = originalTag.children?.find((c) => Tag.isTag(c) && c.name === 'meta' && !c.attributes?.['data-field']);
|
|
746
816
|
const separator = separatorMeta?.attributes?.content ?? '/';
|
|
747
|
-
// Build breadcrumb items: ancestor pages + current page (no link)
|
|
817
|
+
// Build breadcrumb items: ancestor pages + current page (no link).
|
|
818
|
+
//
|
|
819
|
+
// WORK-563 — the schema is not decoration on this path. `collectJsonLd`
|
|
820
|
+
// nests a typed node into its parent only when that node carries *both*
|
|
821
|
+
// `typeof` and `property`. Without them this hook emitted a
|
|
822
|
+
// `BreadcrumbList` with no `itemListElement` and a `ListItem` floating up
|
|
823
|
+
// beside it as a detached, empty top-level entity — while rendering a
|
|
824
|
+
// perfectly correct trail.
|
|
825
|
+
//
|
|
826
|
+
// The explicit `{% breadcrumb %}` form (tags/breadcrumb.ts) has always got
|
|
827
|
+
// this right. This path is the same output contract and must match it: the
|
|
828
|
+
// bar is that an auto trail publishes what the same trail written by hand
|
|
829
|
+
// would.
|
|
748
830
|
const listItems = [];
|
|
749
831
|
for (const ancestorUrl of ancestorUrls) {
|
|
750
832
|
const ancestorPage = pagesByUrl.get(ancestorUrl);
|
|
@@ -752,7 +834,8 @@ function buildAutoBreadcrumb(originalTag, pageUrl, breadcrumbPaths, pagesByUrl,
|
|
|
752
834
|
continue;
|
|
753
835
|
const nameSpan = new Tag('span', { hidden: true }, [ancestorPage.title]);
|
|
754
836
|
const urlLink = new Tag('a', { href: ancestorUrl }, [ancestorPage.title]);
|
|
755
|
-
listItems.push(createComponentRenderable({
|
|
837
|
+
listItems.push(createComponentRenderable({
|
|
838
|
+
rune: 'breadcrumb-item',
|
|
756
839
|
tag: 'li',
|
|
757
840
|
properties: { name: nameSpan, url: urlLink },
|
|
758
841
|
children: [nameSpan, urlLink],
|
|
@@ -762,25 +845,38 @@ function buildAutoBreadcrumb(originalTag, pageUrl, breadcrumbPaths, pagesByUrl,
|
|
|
762
845
|
const currentPage = pagesByUrl.get(pageUrl);
|
|
763
846
|
const currentTitle = currentPage?.title ?? pageUrl;
|
|
764
847
|
const currentSpan = new Tag('span', {}, [currentTitle]);
|
|
765
|
-
listItems.push(createComponentRenderable({
|
|
848
|
+
listItems.push(createComponentRenderable({
|
|
849
|
+
rune: 'breadcrumb-item',
|
|
766
850
|
tag: 'li',
|
|
767
851
|
properties: { name: currentSpan },
|
|
768
852
|
children: [currentSpan],
|
|
769
853
|
}));
|
|
770
854
|
const newSeparatorMeta = new Tag('meta', { content: separator });
|
|
771
855
|
const itemsList = new Tag('ol', {}, listItems);
|
|
772
|
-
|
|
856
|
+
const node = createComponentRenderable({
|
|
857
|
+
rune: 'breadcrumb',
|
|
773
858
|
tag: 'nav',
|
|
774
859
|
properties: { separator: newSeparatorMeta },
|
|
775
860
|
refs: { items: itemsList },
|
|
776
861
|
children: [newSeparatorMeta, itemsList],
|
|
777
862
|
});
|
|
863
|
+
// SPEC-130 D8 / WORK-571 — the hook calls the applier itself.
|
|
864
|
+
//
|
|
865
|
+
// `buildAutoBreadcrumb` runs from a `postProcess` hook, not from a Markdoc
|
|
866
|
+
// schema, so the `createContentModelSchema` wrapper that normally applies a
|
|
867
|
+
// rune's table cannot reach it. One extra call site keeps "the imperative
|
|
868
|
+
// form is fully migrated, not half of each" exceptionless rather than
|
|
869
|
+
// carving out the one emitter that happens to live in a pipeline phase —
|
|
870
|
+
// and, more to the point, it means both breadcrumb paths publish from the
|
|
871
|
+
// *same* table rather than from a declaration and a hand-written copy of it
|
|
872
|
+
// that can drift.
|
|
873
|
+
return applySchemaTable(node, breadcrumbSchema, {});
|
|
778
874
|
}
|
|
779
875
|
/** Walk a Markdoc renderable tree, resolving any auto-nav placeholders */
|
|
780
876
|
function resolveAutoNavs(renderable, pageUrl, pagesByUrl, ctx) {
|
|
781
877
|
if (!Tag.isTag(renderable)) {
|
|
782
878
|
if (Array.isArray(renderable)) {
|
|
783
|
-
const newChildren = renderable.map(c => resolveAutoNavs(c, pageUrl, pagesByUrl, ctx));
|
|
879
|
+
const newChildren = renderable.map((c) => resolveAutoNavs(c, pageUrl, pagesByUrl, ctx));
|
|
784
880
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
785
881
|
return renderable;
|
|
786
882
|
return newChildren;
|
|
@@ -808,21 +904,23 @@ function resolveAutoNavs(renderable, pageUrl, pagesByUrl, ctx) {
|
|
|
808
904
|
* declared. */
|
|
809
905
|
function buildAutoNav(pageUrl, pagesByUrl, ctx, originalTag) {
|
|
810
906
|
// Find direct children: pages whose parentUrl is this page's URL (excluding self)
|
|
811
|
-
const children = Array.from(pagesByUrl.values()).filter(p => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
907
|
+
const children = Array.from(pagesByUrl.values()).filter((p) => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
812
908
|
if (children.length === 0) {
|
|
813
909
|
ctx.warn(`Nav auto: page '${pageUrl}' has no registered child pages`, pageUrl);
|
|
814
910
|
}
|
|
815
|
-
const listItems = children.map(child => {
|
|
911
|
+
const listItems = children.map((child) => {
|
|
816
912
|
const titleSpan = new Tag('span', { 'data-field': 'slug' }, [child.title]);
|
|
817
913
|
const link = new Tag('a', { href: child.url }, [titleSpan]);
|
|
818
|
-
return createComponentRenderable({
|
|
914
|
+
return createComponentRenderable({
|
|
915
|
+
rune: 'nav-item',
|
|
819
916
|
tag: 'li',
|
|
820
917
|
properties: { slug: titleSpan },
|
|
821
918
|
children: [link],
|
|
822
919
|
});
|
|
823
920
|
});
|
|
824
921
|
const itemsList = new Tag('ul', {}, listItems);
|
|
825
|
-
const newNav = createComponentRenderable({
|
|
922
|
+
const newNav = createComponentRenderable({
|
|
923
|
+
rune: 'nav',
|
|
826
924
|
tag: 'nav',
|
|
827
925
|
properties: {
|
|
828
926
|
group: [],
|
|
@@ -832,7 +930,14 @@ function buildAutoNav(pageUrl, pagesByUrl, ctx, originalTag) {
|
|
|
832
930
|
});
|
|
833
931
|
// Preserve contextual attributes from the original nav so layout / auto /
|
|
834
932
|
// source-path survive sentinel replacement.
|
|
835
|
-
const carry = [
|
|
933
|
+
const carry = [
|
|
934
|
+
'layout',
|
|
935
|
+
'data-layout',
|
|
936
|
+
'data-auto',
|
|
937
|
+
'data-source-path',
|
|
938
|
+
'data-collapsible',
|
|
939
|
+
'data-default-open',
|
|
940
|
+
];
|
|
836
941
|
for (const k of carry) {
|
|
837
942
|
const v = originalTag?.attributes?.[k];
|
|
838
943
|
if (v !== undefined) {
|
|
@@ -920,7 +1025,7 @@ function findNavSlugSuggestions(slug, baseDir, pagesByUrl) {
|
|
|
920
1025
|
}
|
|
921
1026
|
sameSlug.sort();
|
|
922
1027
|
typoMatches.sort((a, b) => a.distance - b.distance || a.url.localeCompare(b.url));
|
|
923
|
-
const suggestions = [...sameSlug, ...typoMatches.map(t => t.url)];
|
|
1028
|
+
const suggestions = [...sameSlug, ...typoMatches.map((t) => t.url)];
|
|
924
1029
|
return suggestions.slice(0, 3);
|
|
925
1030
|
}
|
|
926
1031
|
/** SPEC-055 nav-location-relative slug resolution.
|
|
@@ -960,15 +1065,14 @@ function sharedPrefixLength(a, b) {
|
|
|
960
1065
|
* been migrated to use pre-resolved hrefs yet. SPEC-055's
|
|
961
1066
|
* `resolveNavSlug` is the canonical resolver for new code. */
|
|
962
1067
|
function resolveSlugToUrl(slug, pagesByUrl, currentUrl) {
|
|
963
|
-
const candidates = Array.from(pagesByUrl.values()).filter(p => p.url.endsWith('/' + slug) || p.url === '/' + slug);
|
|
1068
|
+
const candidates = Array.from(pagesByUrl.values()).filter((p) => p.url.endsWith('/' + slug) || p.url === '/' + slug);
|
|
964
1069
|
if (candidates.length === 0)
|
|
965
1070
|
return null;
|
|
966
1071
|
if (candidates.length === 1)
|
|
967
1072
|
return candidates[0].url;
|
|
968
1073
|
return candidates
|
|
969
1074
|
.slice()
|
|
970
|
-
.sort((a, b) => sharedPrefixLength(b.url, currentUrl) - sharedPrefixLength(a.url, currentUrl))[0]
|
|
971
|
-
.url;
|
|
1075
|
+
.sort((a, b) => sharedPrefixLength(b.url, currentUrl) - sharedPrefixLength(a.url, currentUrl))[0].url;
|
|
972
1076
|
}
|
|
973
1077
|
/** Read a NavItem's slug from either `data-slug` (post-engine) or a nested
|
|
974
1078
|
* `<span data-field="slug">` (pre-engine, e.g. layout regions). */
|
|
@@ -1084,7 +1188,7 @@ function urlMatchesGroup(currentUrl, itemUrls) {
|
|
|
1084
1188
|
function resolveCollapsibleNavs(renderable, pageUrl, pagesByUrl) {
|
|
1085
1189
|
if (!Tag.isTag(renderable)) {
|
|
1086
1190
|
if (Array.isArray(renderable)) {
|
|
1087
|
-
const newChildren = renderable.map(c => resolveCollapsibleNavs(c, pageUrl, pagesByUrl));
|
|
1191
|
+
const newChildren = renderable.map((c) => resolveCollapsibleNavs(c, pageUrl, pagesByUrl));
|
|
1088
1192
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1089
1193
|
return renderable;
|
|
1090
1194
|
return newChildren;
|
|
@@ -1092,11 +1196,13 @@ function resolveCollapsibleNavs(renderable, pageUrl, pagesByUrl) {
|
|
|
1092
1196
|
return renderable;
|
|
1093
1197
|
}
|
|
1094
1198
|
const tag = renderable;
|
|
1095
|
-
if (tag.attributes?.['data-rune'] === 'nav' &&
|
|
1096
|
-
tag.attributes?.['data-collapsible'] === 'true') {
|
|
1199
|
+
if (tag.attributes?.['data-rune'] === 'nav' && tag.attributes?.['data-collapsible'] === 'true') {
|
|
1097
1200
|
const defaultOpenRaw = String(tag.attributes?.['data-default-open'] ?? '');
|
|
1098
1201
|
const defaultOpen = defaultOpenRaw
|
|
1099
|
-
? defaultOpenRaw
|
|
1202
|
+
? defaultOpenRaw
|
|
1203
|
+
.split(',')
|
|
1204
|
+
.map((s) => s.trim())
|
|
1205
|
+
.filter(Boolean)
|
|
1100
1206
|
: [];
|
|
1101
1207
|
const groups = [];
|
|
1102
1208
|
const findGroups = (node) => {
|
|
@@ -1116,7 +1222,7 @@ function resolveCollapsibleNavs(renderable, pageUrl, pagesByUrl) {
|
|
|
1116
1222
|
const inDefault = title && defaultOpen.includes(title);
|
|
1117
1223
|
const itemUrls = collectGroupItemUrls(group, pagesByUrl, pageUrl);
|
|
1118
1224
|
const matches = urlMatchesGroup(pageUrl, itemUrls);
|
|
1119
|
-
group.attributes['data-collapsed'] =
|
|
1225
|
+
group.attributes['data-collapsed'] = inDefault || matches ? 'false' : 'true';
|
|
1120
1226
|
}
|
|
1121
1227
|
const newChildren = (tag.children ?? []).map((c) => resolveCollapsibleNavs(c, pageUrl, pagesByUrl));
|
|
1122
1228
|
if (newChildren.every((c, i) => c === tag.children[i]))
|
|
@@ -1139,7 +1245,9 @@ function enrichNavItemAsCard(item, pageMeta, itemUrl) {
|
|
|
1139
1245
|
}
|
|
1140
1246
|
linkChildren.push(new Tag('span', { 'data-name': 'title', class: 'rf-nav-item__title' }, [titleText]));
|
|
1141
1247
|
if (description) {
|
|
1142
|
-
linkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1248
|
+
linkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1249
|
+
description,
|
|
1250
|
+
]));
|
|
1143
1251
|
}
|
|
1144
1252
|
const link = href
|
|
1145
1253
|
? new Tag('a', { href, class: 'rf-nav-item__link' }, linkChildren)
|
|
@@ -1206,7 +1314,9 @@ function augmentNavItemFromFrontmatter(item, pageMeta) {
|
|
|
1206
1314
|
newLinkChildren.unshift(new Tag('rf-icon', { name: pageMeta.icon, 'data-name': 'icon', class: 'rf-nav-item__icon' }, []));
|
|
1207
1315
|
}
|
|
1208
1316
|
if (pageMeta.description && !hasDescription) {
|
|
1209
|
-
newLinkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1317
|
+
newLinkChildren.push(new Tag('span', { 'data-name': 'description', class: 'rf-nav-item__description' }, [
|
|
1318
|
+
pageMeta.description,
|
|
1319
|
+
]));
|
|
1210
1320
|
}
|
|
1211
1321
|
return { ...t, children: newLinkChildren };
|
|
1212
1322
|
});
|
|
@@ -1215,7 +1325,7 @@ function augmentNavItemFromFrontmatter(item, pageMeta) {
|
|
|
1215
1325
|
function resolveCardsNavs(renderable, pageUrl, pagesByUrl) {
|
|
1216
1326
|
if (!Tag.isTag(renderable)) {
|
|
1217
1327
|
if (Array.isArray(renderable)) {
|
|
1218
|
-
const newChildren = renderable.map(c => resolveCardsNavs(c, pageUrl, pagesByUrl));
|
|
1328
|
+
const newChildren = renderable.map((c) => resolveCardsNavs(c, pageUrl, pagesByUrl));
|
|
1219
1329
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1220
1330
|
return renderable;
|
|
1221
1331
|
return newChildren;
|
|
@@ -1291,7 +1401,13 @@ function formatNavResolutionError(slug, sourcePath, attemptedUrl, suggestions) {
|
|
|
1291
1401
|
const head = `Nav item \`${slug}\`${where} cannot be resolved (no page at \`${attemptedUrl}\`).`;
|
|
1292
1402
|
if (suggestions.length === 0)
|
|
1293
1403
|
return head;
|
|
1294
|
-
const lines = [
|
|
1404
|
+
const lines = [
|
|
1405
|
+
'',
|
|
1406
|
+
'Did you mean one of:',
|
|
1407
|
+
...suggestions.map((s) => ` - ${s}`),
|
|
1408
|
+
'',
|
|
1409
|
+
'Use a multi-segment slug (e.g. `section/page`) or an explicit `[Label](/path)` link.',
|
|
1410
|
+
];
|
|
1295
1411
|
return head + '\n' + lines.join('\n');
|
|
1296
1412
|
}
|
|
1297
1413
|
/** Walk a nav subtree, resolve every NavItem's `data-slug` to a real `<a href>`
|
|
@@ -1354,7 +1470,7 @@ function resolveNavItemsInSubtree(navTag, pagesByUrl, ctx, pageUrl) {
|
|
|
1354
1470
|
function resolveNavSlugs(renderable, pagesByUrl, ctx, pageUrl) {
|
|
1355
1471
|
if (!Tag.isTag(renderable)) {
|
|
1356
1472
|
if (Array.isArray(renderable)) {
|
|
1357
|
-
const next = renderable.map(c => resolveNavSlugs(c, pagesByUrl, ctx, pageUrl));
|
|
1473
|
+
const next = renderable.map((c) => resolveNavSlugs(c, pagesByUrl, ctx, pageUrl));
|
|
1358
1474
|
return next.every((c, i) => c === renderable[i]) ? renderable : next;
|
|
1359
1475
|
}
|
|
1360
1476
|
return renderable;
|
|
@@ -1570,10 +1686,10 @@ function getSiblingPages(currentUrl, pagesByUrl, scope) {
|
|
|
1570
1686
|
cursor = parent;
|
|
1571
1687
|
}
|
|
1572
1688
|
const prefix = sectionRoot.endsWith('/') ? sectionRoot : sectionRoot + '/';
|
|
1573
|
-
candidates = pages.filter(p => p.url === sectionRoot || p.url.startsWith(prefix));
|
|
1689
|
+
candidates = pages.filter((p) => p.url === sectionRoot || p.url.startsWith(prefix));
|
|
1574
1690
|
}
|
|
1575
1691
|
else {
|
|
1576
|
-
candidates = pages.filter(p => p.parentUrl === current.parentUrl);
|
|
1692
|
+
candidates = pages.filter((p) => p.parentUrl === current.parentUrl);
|
|
1577
1693
|
}
|
|
1578
1694
|
// Sort by frontmatter order (asc, missing → end), tie-break by URL.
|
|
1579
1695
|
candidates.sort((a, b) => {
|
|
@@ -1583,7 +1699,7 @@ function getSiblingPages(currentUrl, pagesByUrl, scope) {
|
|
|
1583
1699
|
return ao - bo;
|
|
1584
1700
|
return a.url.localeCompare(b.url);
|
|
1585
1701
|
});
|
|
1586
|
-
return candidates.map(p => ({ url: p.url, title: p.title }));
|
|
1702
|
+
return candidates.map((p) => ({ url: p.url, title: p.title }));
|
|
1587
1703
|
}
|
|
1588
1704
|
function pickPrevNextFromSequence(sequence, currentUrl, pagesByUrl) {
|
|
1589
1705
|
const idx = sequence.indexOf(currentUrl);
|
|
@@ -1620,7 +1736,7 @@ function buildPaginationLink(target, direction, label) {
|
|
|
1620
1736
|
function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable) {
|
|
1621
1737
|
if (!Tag.isTag(renderable)) {
|
|
1622
1738
|
if (Array.isArray(renderable)) {
|
|
1623
|
-
const newChildren = renderable.map(c => resolveAutoPagination(c, pageUrl, pagesByUrl, rootRenderable));
|
|
1739
|
+
const newChildren = renderable.map((c) => resolveAutoPagination(c, pageUrl, pagesByUrl, rootRenderable));
|
|
1624
1740
|
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1625
1741
|
return renderable;
|
|
1626
1742
|
return newChildren;
|
|
@@ -1638,10 +1754,14 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1638
1754
|
const scope = (scopeValue === 'section' ? 'section' : 'siblings');
|
|
1639
1755
|
const prevLabelMeta = (tag.children ?? []).find((c) => Tag.isTag(c) && c.attributes?.['data-field'] === 'prev-label');
|
|
1640
1756
|
const nextLabelMeta = (tag.children ?? []).find((c) => Tag.isTag(c) && c.attributes?.['data-field'] === 'next-label');
|
|
1641
|
-
const prevLabel = prevLabelMeta
|
|
1642
|
-
|
|
1757
|
+
const prevLabel = prevLabelMeta
|
|
1758
|
+
? String(prevLabelMeta.attributes.content ?? '')
|
|
1759
|
+
: undefined;
|
|
1760
|
+
const nextLabel = nextLabelMeta
|
|
1761
|
+
? String(nextLabelMeta.attributes.content ?? '')
|
|
1762
|
+
: undefined;
|
|
1643
1763
|
// Skip when current page is a section index (has children)
|
|
1644
|
-
const hasChildren = Array.from(pagesByUrl.values()).some(p => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
1764
|
+
const hasChildren = Array.from(pagesByUrl.values()).some((p) => p.parentUrl === pageUrl && p.url !== pageUrl);
|
|
1645
1765
|
if (hasChildren) {
|
|
1646
1766
|
return { ...tag, children: [] };
|
|
1647
1767
|
}
|
|
@@ -1662,7 +1782,7 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1662
1782
|
else {
|
|
1663
1783
|
// 2. Sibling pages by frontmatter order → directory order
|
|
1664
1784
|
const siblings = getSiblingPages(pageUrl, pagesByUrl, scope);
|
|
1665
|
-
const idx = siblings.findIndex(s => s.url === pageUrl);
|
|
1785
|
+
const idx = siblings.findIndex((s) => s.url === pageUrl);
|
|
1666
1786
|
if (idx !== -1) {
|
|
1667
1787
|
prev = idx > 0 ? siblings[idx - 1] : null;
|
|
1668
1788
|
next = idx < siblings.length - 1 ? siblings[idx + 1] : null;
|
|
@@ -1689,7 +1809,9 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1689
1809
|
const newChildren = (tag.children ?? []).map((c) => {
|
|
1690
1810
|
if (!Tag.isTag(c))
|
|
1691
1811
|
return c;
|
|
1692
|
-
if (c.name === 'a' &&
|
|
1812
|
+
if (c.name === 'a' &&
|
|
1813
|
+
typeof c.attributes?.href === 'string' &&
|
|
1814
|
+
c.attributes.href.startsWith('__slug:')) {
|
|
1693
1815
|
const slug = c.attributes.href.slice('__slug:'.length);
|
|
1694
1816
|
const resolvedUrl = resolveSlugToUrl(slug, pagesByUrl, pageUrl);
|
|
1695
1817
|
if (resolvedUrl) {
|
|
@@ -1698,14 +1820,20 @@ function resolveAutoPagination(renderable, pageUrl, pagesByUrl, rootRenderable)
|
|
|
1698
1820
|
// Replace label text if user didn't override (label child has same text as slug)
|
|
1699
1821
|
const newChildren = (c.children ?? []).map((child) => {
|
|
1700
1822
|
if (Tag.isTag(child) && child.attributes?.['data-name'] === 'label') {
|
|
1701
|
-
const currentLabel = (child.children ?? [])
|
|
1823
|
+
const currentLabel = (child.children ?? [])
|
|
1824
|
+
.filter((x) => typeof x === 'string')
|
|
1825
|
+
.join('');
|
|
1702
1826
|
if (currentLabel === slug) {
|
|
1703
1827
|
return { ...child, children: [newLabel] };
|
|
1704
1828
|
}
|
|
1705
1829
|
}
|
|
1706
1830
|
return child;
|
|
1707
1831
|
});
|
|
1708
|
-
return {
|
|
1832
|
+
return {
|
|
1833
|
+
...c,
|
|
1834
|
+
attributes: { ...c.attributes, href: resolvedUrl },
|
|
1835
|
+
children: newChildren,
|
|
1836
|
+
};
|
|
1709
1837
|
}
|
|
1710
1838
|
}
|
|
1711
1839
|
return c;
|
|
@@ -1724,7 +1852,7 @@ function walkBlogTags(node, fn) {
|
|
|
1724
1852
|
walkBlogTags(child, fn);
|
|
1725
1853
|
}
|
|
1726
1854
|
else if (Array.isArray(node)) {
|
|
1727
|
-
node.forEach(n => walkBlogTags(n, fn));
|
|
1855
|
+
node.forEach((n) => walkBlogTags(n, fn));
|
|
1728
1856
|
}
|
|
1729
1857
|
}
|
|
1730
1858
|
function mapBlogTags(node, fn) {
|
|
@@ -1732,12 +1860,12 @@ function mapBlogTags(node, fn) {
|
|
|
1732
1860
|
const mapped = fn(node);
|
|
1733
1861
|
if (mapped !== node)
|
|
1734
1862
|
return mapped;
|
|
1735
|
-
const newChildren = node.children.map(c => mapBlogTags(c, fn));
|
|
1863
|
+
const newChildren = node.children.map((c) => mapBlogTags(c, fn));
|
|
1736
1864
|
const changed = newChildren.some((c, i) => c !== node.children[i]);
|
|
1737
1865
|
return changed ? new Tag(node.name, node.attributes, newChildren) : node;
|
|
1738
1866
|
}
|
|
1739
1867
|
if (Array.isArray(node))
|
|
1740
|
-
return node.map(n => mapBlogTags(n, fn));
|
|
1868
|
+
return node.map((n) => mapBlogTags(n, fn));
|
|
1741
1869
|
return node;
|
|
1742
1870
|
}
|
|
1743
1871
|
/** Normalise folder path for prefix matching: ensure leading slash and trailing slash */
|
|
@@ -1761,7 +1889,7 @@ function isInFolder(pageUrl, folder) {
|
|
|
1761
1889
|
function parseBlogFilter(filter) {
|
|
1762
1890
|
if (!filter || !filter.trim())
|
|
1763
1891
|
return [];
|
|
1764
|
-
return filter.split(',').map(part => {
|
|
1892
|
+
return filter.split(',').map((part) => {
|
|
1765
1893
|
const colonIdx = part.indexOf(':');
|
|
1766
1894
|
if (colonIdx === -1)
|
|
1767
1895
|
return { field: part.trim(), value: '' };
|
|
@@ -1780,7 +1908,7 @@ function matchesBlogFilter(post, filters) {
|
|
|
1780
1908
|
return false;
|
|
1781
1909
|
}
|
|
1782
1910
|
else if (Array.isArray(fmValue)) {
|
|
1783
|
-
if (!fmValue.some(v => String(v).toLowerCase() === value.toLowerCase()))
|
|
1911
|
+
if (!fmValue.some((v) => String(v).toLowerCase() === value.toLowerCase()))
|
|
1784
1912
|
return false;
|
|
1785
1913
|
}
|
|
1786
1914
|
else {
|
|
@@ -1812,9 +1940,7 @@ function sortBlogPosts(posts, sort) {
|
|
|
1812
1940
|
}
|
|
1813
1941
|
/** Build an <article> Tag for a single blog post entry */
|
|
1814
1942
|
function createBlogPostTag(post) {
|
|
1815
|
-
const titleTag = new Tag('h3', {}, [
|
|
1816
|
-
new Tag('a', { href: post.url }, [post.title]),
|
|
1817
|
-
]);
|
|
1943
|
+
const titleTag = new Tag('h3', {}, [new Tag('a', { href: post.url }, [post.title])]);
|
|
1818
1944
|
const children = [titleTag];
|
|
1819
1945
|
if (post.date) {
|
|
1820
1946
|
children.push(new Tag('time', { datetime: post.date }, [post.date]));
|
|
@@ -1843,7 +1969,7 @@ function resolveBlogPosts(renderable, allPosts, ctx, pageUrl) {
|
|
|
1843
1969
|
}
|
|
1844
1970
|
const normalised = normaliseFolderPath(folder);
|
|
1845
1971
|
const filters = parseBlogFilter(filterStr);
|
|
1846
|
-
let posts = allPosts.filter(post => {
|
|
1972
|
+
let posts = allPosts.filter((post) => {
|
|
1847
1973
|
if (post.draft)
|
|
1848
1974
|
return false;
|
|
1849
1975
|
if (!isInFolder(post.url, normalised))
|
|
@@ -1890,9 +2016,7 @@ navSearchScope) {
|
|
|
1890
2016
|
result = resolveNavSlugs(result, coreData.pagesByUrl, ctx, pageUrl);
|
|
1891
2017
|
result = resolveCollapsibleNavs(result, pageUrl, coreData.pagesByUrl);
|
|
1892
2018
|
result = resolveCardsNavs(result, pageUrl, coreData.pagesByUrl);
|
|
1893
|
-
const searchRoot = navSearchScope && navSearchScope.length > 0
|
|
1894
|
-
? [result, ...navSearchScope]
|
|
1895
|
-
: result;
|
|
2019
|
+
const searchRoot = navSearchScope && navSearchScope.length > 0 ? [result, ...navSearchScope] : result;
|
|
1896
2020
|
result = resolveAutoPagination(result, pageUrl, coreData.pagesByUrl, searchRoot);
|
|
1897
2021
|
// SPEC-055 — mark aria-current / data-active="ancestor" on resolved nav
|
|
1898
2022
|
// links per page. Runs after slug + auto-pagination resolution so the
|
|
@@ -1918,9 +2042,15 @@ navSearchScope) {
|
|
|
1918
2042
|
* any custom field.
|
|
1919
2043
|
*/
|
|
1920
2044
|
const RESERVED_PAGE_FRONTMATTER = new Set([
|
|
1921
|
-
'layout',
|
|
2045
|
+
'layout',
|
|
2046
|
+
'tint',
|
|
2047
|
+
'tint-mode',
|
|
2048
|
+
'tint-lock',
|
|
2049
|
+
'slug',
|
|
2050
|
+
'redirect',
|
|
1922
2051
|
// entity-declaration keys (SPEC-092 Layer 2) — meta, not queryable content
|
|
1923
|
-
'type',
|
|
2052
|
+
'type',
|
|
2053
|
+
'id',
|
|
1924
2054
|
]);
|
|
1925
2055
|
export function createCorePipelineHooks(opts = {}) {
|
|
1926
2056
|
const xrefPatterns = opts.xrefPatterns ?? [];
|
|
@@ -1941,7 +2071,7 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
1941
2071
|
const includeChanged = preprocessIncludes(ast, page, ctx);
|
|
1942
2072
|
const snippetChanged = preprocessSnippets(ast, page, ctx);
|
|
1943
2073
|
const dataChanged = preprocessData(ast, page, ctx);
|
|
1944
|
-
return
|
|
2074
|
+
return includeChanged || snippetChanged || dataChanged ? ast : undefined;
|
|
1945
2075
|
},
|
|
1946
2076
|
register(pages, registry, ctx) {
|
|
1947
2077
|
for (const page of pages) {
|
|
@@ -1995,7 +2125,7 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
1995
2125
|
},
|
|
1996
2126
|
aggregate(registry, ctx) {
|
|
1997
2127
|
const pageEntities = registry.getAll('page');
|
|
1998
|
-
const pages = pageEntities.map(e => ({
|
|
2128
|
+
const pages = pageEntities.map((e) => ({
|
|
1999
2129
|
url: e.data.url,
|
|
2000
2130
|
title: e.data.title,
|
|
2001
2131
|
parentUrl: e.data.parentUrl,
|
|
@@ -2006,14 +2136,14 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
2006
2136
|
const pageTree = buildPageTree(pages);
|
|
2007
2137
|
const breadcrumbPaths = buildBreadcrumbPaths(pages);
|
|
2008
2138
|
// Quick lookup: url → { url, title } for postProcess use
|
|
2009
|
-
const pagesByUrl = new Map(pages.map(p => [p.url, p]));
|
|
2139
|
+
const pagesByUrl = new Map(pages.map((p) => [p.url, p]));
|
|
2010
2140
|
// Build heading index: "url#id" → heading data
|
|
2011
2141
|
const headingIndex = new Map();
|
|
2012
2142
|
for (const h of registry.getAll('heading')) {
|
|
2013
2143
|
headingIndex.set(h.id, h.data);
|
|
2014
2144
|
}
|
|
2015
2145
|
// Blog: collect all pages as potential blog posts
|
|
2016
|
-
const allPosts = pageEntities.map(e => ({
|
|
2146
|
+
const allPosts = pageEntities.map((e) => ({
|
|
2017
2147
|
title: e.data.title || '',
|
|
2018
2148
|
url: e.data.url || e.id,
|
|
2019
2149
|
date: e.data.date || '',
|
|
@@ -2021,7 +2151,18 @@ export function createCorePipelineHooks(opts = {}) {
|
|
|
2021
2151
|
draft: e.data.draft || false,
|
|
2022
2152
|
frontmatter: e.data,
|
|
2023
2153
|
}));
|
|
2024
|
-
return {
|
|
2154
|
+
return {
|
|
2155
|
+
pageTree,
|
|
2156
|
+
breadcrumbPaths,
|
|
2157
|
+
pagesByUrl,
|
|
2158
|
+
headingIndex,
|
|
2159
|
+
allPosts,
|
|
2160
|
+
registry,
|
|
2161
|
+
xrefPatterns,
|
|
2162
|
+
embedConfig,
|
|
2163
|
+
repoUrl,
|
|
2164
|
+
repoBranch,
|
|
2165
|
+
};
|
|
2025
2166
|
},
|
|
2026
2167
|
postProcess(page, aggregated, ctx) {
|
|
2027
2168
|
const coreData = aggregated['__core__'];
|