@refrakt-md/runes 0.8.4 → 0.9.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/config.d.ts +2 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +387 -23
- package/dist/config.js.map +1 -1
- package/dist/fence-escape.d.ts +19 -0
- package/dist/fence-escape.d.ts.map +1 -0
- package/dist/fence-escape.js +53 -0
- package/dist/fence-escape.js.map +1 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +94 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +1 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +2 -1
- package/dist/nodes.js.map +1 -1
- package/dist/registry.d.ts +8 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +8 -0
- package/dist/registry.js.map +1 -1
- package/dist/rune.d.ts +7 -0
- package/dist/rune.d.ts.map +1 -1
- package/dist/rune.js +2 -0
- package/dist/rune.js.map +1 -1
- package/dist/sandbox-sources.d.ts +34 -0
- package/dist/sandbox-sources.d.ts.map +1 -0
- package/dist/sandbox-sources.js +204 -0
- package/dist/sandbox-sources.js.map +1 -0
- package/dist/schema/blog.d.ts +16 -0
- package/dist/schema/blog.d.ts.map +1 -0
- package/dist/schema/blog.js +21 -0
- package/dist/schema/blog.js.map +1 -0
- package/dist/schema/juxtapose.d.ts +7 -0
- package/dist/schema/juxtapose.d.ts.map +1 -0
- package/dist/schema/juxtapose.js +11 -0
- package/dist/schema/juxtapose.js.map +1 -0
- package/dist/schema/xref.d.ts +5 -0
- package/dist/schema/xref.d.ts.map +1 -0
- package/dist/schema/xref.js +7 -0
- package/dist/schema/xref.js.map +1 -0
- package/dist/tags/blog.d.ts +3 -0
- package/dist/tags/blog.d.ts.map +1 -0
- package/dist/tags/blog.js +67 -0
- package/dist/tags/blog.js.map +1 -0
- package/dist/tags/common.d.ts +27 -0
- package/dist/tags/common.d.ts.map +1 -1
- package/dist/tags/common.js +53 -0
- package/dist/tags/common.js.map +1 -1
- package/dist/tags/juxtapose.d.ts +3 -0
- package/dist/tags/juxtapose.d.ts.map +1 -0
- package/dist/tags/juxtapose.js +71 -0
- package/dist/tags/juxtapose.js.map +1 -0
- package/dist/tags/sandbox.d.ts.map +1 -1
- package/dist/tags/sandbox.js +56 -9
- package/dist/tags/sandbox.js.map +1 -1
- package/dist/tags/xref.d.ts +18 -0
- package/dist/tags/xref.d.ts.map +1 -0
- package/dist/tags/xref.js +54 -0
- package/dist/tags/xref.js.map +1 -0
- package/package.json +3 -3
package/dist/config.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export interface PageTreeNode {
|
|
|
14
14
|
/**
|
|
15
15
|
* Core cross-page pipeline hooks.
|
|
16
16
|
* Run for every site, before any community package hooks.
|
|
17
|
-
* Registers page and heading entities, aggregates the page tree and breadcrumb paths
|
|
17
|
+
* Registers page and heading entities, aggregates the page tree and breadcrumb paths,
|
|
18
|
+
* and resolves blog post listings.
|
|
18
19
|
*/
|
|
19
20
|
export declare const corePipelineHooks: PackagePipelineHooks;
|
|
20
21
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA+B,MAAM,uBAAuB,CAAC;AAEtF,OAAO,KAAK,EAAE,oBAAoB,EAAoE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA+B,MAAM,uBAAuB,CAAC;AAEtF,OAAO,KAAK,EAAE,oBAAoB,EAAoE,MAAM,mBAAmB,CAAC;AAgFhI;gFACgF;AAChF,eAAO,MAAM,UAAU,EAAE,WAqrBxB,CAAC;AAEF,sGAAsG;AACtG,eAAO,MAAM,UAAU,aAAa,CAAC;AAIrC,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,EAAE,CAAC;CACzB;AA4kBD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,oBA8H/B,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createComponentRenderable } from './lib/index.js';
|
|
|
5
5
|
import { schema } from './registry.js';
|
|
6
6
|
import { BREADCRUMB_AUTO_SENTINEL } from './tags/breadcrumb.js';
|
|
7
7
|
import { NAV_AUTO_SENTINEL } from './tags/nav.js';
|
|
8
|
+
import { XREF_RUNE_MARKER } from './tags/xref.js';
|
|
8
9
|
// ─── Budget postTransform helpers ───
|
|
9
10
|
const BUDGET_CURRENCY_SYMBOLS = {
|
|
10
11
|
USD: '$', EUR: '€', GBP: '£', JPY: '¥', CNY: '¥',
|
|
@@ -68,7 +69,7 @@ function readPropText(node, prop) {
|
|
|
68
69
|
}
|
|
69
70
|
/** autoLabel entries shared by all PageSection-based runes */
|
|
70
71
|
const pageSectionAutoLabel = {
|
|
71
|
-
header: '
|
|
72
|
+
header: 'preamble', // <header> wrapper element → data-name="preamble"
|
|
72
73
|
eyebrow: 'eyebrow', // property="eyebrow"
|
|
73
74
|
headline: 'headline', // property="headline"
|
|
74
75
|
blurb: 'blurb', // property="blurb"
|
|
@@ -82,11 +83,12 @@ export const coreConfig = {
|
|
|
82
83
|
icons: {},
|
|
83
84
|
runes: {
|
|
84
85
|
// ─── Simple runes (block name only, engine adds BEM classes) ───
|
|
85
|
-
Accordion: { block: 'accordion', autoLabel: pageSectionAutoLabel, editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' } },
|
|
86
|
-
AccordionItem: { block: 'accordion-item', parent: 'Accordion', autoLabel: { name: 'header' }, editHints: { header: 'inline', body: 'none' } },
|
|
87
|
-
Details: { block: 'details', autoLabel: { summary: 'summary' }, editHints: { summary: 'inline', body: 'none' } },
|
|
86
|
+
Accordion: { block: 'accordion', defaultDensity: 'full', sections: { preamble: 'preamble', headline: 'title', blurb: 'description' }, autoLabel: pageSectionAutoLabel, editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' } },
|
|
87
|
+
AccordionItem: { block: 'accordion-item', parent: 'Accordion', rootAttributes: { 'data-state': 'closed' }, autoLabel: { name: 'header' }, editHints: { header: 'inline', body: 'none' } },
|
|
88
|
+
Details: { block: 'details', defaultDensity: 'compact', sections: { summary: 'title' }, autoLabel: { summary: 'summary' }, editHints: { summary: 'inline', body: 'none' } },
|
|
88
89
|
Grid: {
|
|
89
90
|
block: 'grid',
|
|
91
|
+
defaultDensity: 'full',
|
|
90
92
|
modifiers: {
|
|
91
93
|
mode: { source: 'meta', default: 'columns' },
|
|
92
94
|
collapse: { source: 'meta', noBemClass: true },
|
|
@@ -108,6 +110,7 @@ export const coreConfig = {
|
|
|
108
110
|
},
|
|
109
111
|
CodeGroup: {
|
|
110
112
|
block: 'codegroup',
|
|
113
|
+
defaultDensity: 'compact',
|
|
111
114
|
modifiers: { title: { source: 'meta' }, overflow: { source: 'meta', default: 'scroll' } },
|
|
112
115
|
structure: {
|
|
113
116
|
topbar: {
|
|
@@ -120,12 +123,14 @@ export const coreConfig = {
|
|
|
120
123
|
],
|
|
121
124
|
},
|
|
122
125
|
},
|
|
126
|
+
sections: { topbar: 'header', title: 'title' },
|
|
123
127
|
editHints: { panel: 'code', title: 'none' },
|
|
124
128
|
},
|
|
125
129
|
PageSection: { block: 'page-section' },
|
|
126
130
|
TableOfContents: { block: 'toc' },
|
|
127
131
|
Embed: {
|
|
128
132
|
block: 'embed',
|
|
133
|
+
defaultDensity: 'compact',
|
|
129
134
|
editHints: { fallback: 'none' },
|
|
130
135
|
postTransform(node) {
|
|
131
136
|
const block = node.attributes.class?.split(' ')[0] || 'rf-embed';
|
|
@@ -166,10 +171,27 @@ export const coreConfig = {
|
|
|
166
171
|
};
|
|
167
172
|
},
|
|
168
173
|
},
|
|
169
|
-
Breadcrumb: { block: 'breadcrumb', editHints: { items: 'none' } },
|
|
174
|
+
Breadcrumb: { block: 'breadcrumb', defaultDensity: 'minimal', sections: { items: 'body' }, editHints: { items: 'none' } },
|
|
170
175
|
BreadcrumbItem: { block: 'breadcrumb-item', parent: 'Breadcrumb' },
|
|
176
|
+
Blog: {
|
|
177
|
+
block: 'blog',
|
|
178
|
+
defaultDensity: 'full',
|
|
179
|
+
sections: { preamble: 'preamble', headline: 'title', blurb: 'description', content: 'body' },
|
|
180
|
+
contentWrapper: { tag: 'div', ref: 'content' },
|
|
181
|
+
modifiers: {
|
|
182
|
+
layout: { source: 'meta', default: 'list' },
|
|
183
|
+
sort: { source: 'meta', default: 'date-desc', noBemClass: true },
|
|
184
|
+
filter: { source: 'meta', noBemClass: true },
|
|
185
|
+
limit: { source: 'meta', noBemClass: true },
|
|
186
|
+
folder: { source: 'meta', noBemClass: true },
|
|
187
|
+
},
|
|
188
|
+
autoLabel: pageSectionAutoLabel,
|
|
189
|
+
editHints: { headline: 'inline', blurb: 'inline' },
|
|
190
|
+
},
|
|
171
191
|
Budget: {
|
|
172
192
|
block: 'budget',
|
|
193
|
+
defaultDensity: 'full',
|
|
194
|
+
sections: { header: 'header', title: 'title', footer: 'footer' },
|
|
173
195
|
editHints: { title: 'none', meta: 'none', 'meta-item': 'none' },
|
|
174
196
|
modifiers: {
|
|
175
197
|
title: { source: 'meta' },
|
|
@@ -189,9 +211,9 @@ export const coreConfig = {
|
|
|
189
211
|
{
|
|
190
212
|
tag: 'div', ref: 'meta',
|
|
191
213
|
children: [
|
|
192
|
-
{ tag: 'span', ref: 'meta-item', metaText: 'currency', condition: 'currency' },
|
|
193
|
-
{ tag: 'span', ref: 'meta-item', metaText: 'travelers',
|
|
194
|
-
{ tag: 'span', ref: 'meta-item', metaText: 'duration',
|
|
214
|
+
{ tag: 'span', ref: 'meta-item', metaText: 'currency', condition: 'currency', metaType: 'category', metaRank: 'primary' },
|
|
215
|
+
{ tag: 'span', ref: 'meta-item', metaText: 'travelers', label: 'Travelers:', condition: 'travelers', metaType: 'quantity', metaRank: 'primary' },
|
|
216
|
+
{ tag: 'span', ref: 'meta-item', metaText: 'duration', label: 'Duration:', condition: 'duration', metaType: 'temporal', metaRank: 'secondary' },
|
|
195
217
|
],
|
|
196
218
|
},
|
|
197
219
|
],
|
|
@@ -269,8 +291,10 @@ export const coreConfig = {
|
|
|
269
291
|
// ─── Runes with modifier meta tags ───
|
|
270
292
|
Hint: {
|
|
271
293
|
block: 'hint',
|
|
294
|
+
defaultDensity: 'compact',
|
|
272
295
|
modifiers: { hintType: { source: 'meta', default: 'note' } },
|
|
273
296
|
contextModifiers: { 'hero': 'in-hero', 'feature': 'in-feature' },
|
|
297
|
+
sections: { header: 'header' },
|
|
274
298
|
editHints: { icon: 'none', title: 'none' },
|
|
275
299
|
structure: {
|
|
276
300
|
header: {
|
|
@@ -284,14 +308,17 @@ export const coreConfig = {
|
|
|
284
308
|
},
|
|
285
309
|
Figure: {
|
|
286
310
|
block: 'figure',
|
|
311
|
+
defaultDensity: 'compact',
|
|
287
312
|
modifiers: {
|
|
288
313
|
size: { source: 'meta', default: 'default' },
|
|
289
314
|
align: { source: 'meta', default: 'center' },
|
|
290
315
|
},
|
|
316
|
+
sections: { caption: 'description' },
|
|
291
317
|
editHints: { caption: 'inline' },
|
|
292
318
|
},
|
|
293
319
|
Gallery: {
|
|
294
320
|
block: 'gallery',
|
|
321
|
+
defaultDensity: 'full',
|
|
295
322
|
modifiers: {
|
|
296
323
|
layout: { source: 'meta', default: 'grid' },
|
|
297
324
|
lightbox: { source: 'meta', default: 'true', noBemClass: true },
|
|
@@ -306,15 +333,18 @@ export const coreConfig = {
|
|
|
306
333
|
},
|
|
307
334
|
Sidenote: {
|
|
308
335
|
block: 'sidenote',
|
|
336
|
+
defaultDensity: 'minimal',
|
|
309
337
|
modifiers: { variant: { source: 'meta', default: 'sidenote' } },
|
|
338
|
+
sections: { body: 'body' },
|
|
310
339
|
editHints: { body: 'inline' },
|
|
311
340
|
},
|
|
312
341
|
Compare: {
|
|
313
342
|
block: 'compare',
|
|
343
|
+
defaultDensity: 'full',
|
|
314
344
|
modifiers: { layout: { source: 'meta', default: 'side-by-side' } },
|
|
315
345
|
editHints: { panels: 'none' },
|
|
316
346
|
},
|
|
317
|
-
Conversation: { block: 'conversation', editHints: { messages: 'none' } },
|
|
347
|
+
Conversation: { block: 'conversation', defaultDensity: 'compact', editHints: { messages: 'none' } },
|
|
318
348
|
ConversationMessage: {
|
|
319
349
|
block: 'conversation-message',
|
|
320
350
|
parent: 'Conversation',
|
|
@@ -323,12 +353,15 @@ export const coreConfig = {
|
|
|
323
353
|
},
|
|
324
354
|
Annotate: {
|
|
325
355
|
block: 'annotate',
|
|
356
|
+
defaultDensity: 'full',
|
|
326
357
|
modifiers: { variant: { source: 'meta', default: 'margin' } },
|
|
358
|
+
sections: { body: 'body' },
|
|
327
359
|
editHints: { body: 'none', notes: 'none' },
|
|
328
360
|
},
|
|
329
361
|
AnnotateNote: { block: 'annotate-note', parent: 'Annotate', editHints: { body: 'inline' } },
|
|
330
362
|
Nav: {
|
|
331
363
|
block: 'nav',
|
|
364
|
+
defaultDensity: 'compact',
|
|
332
365
|
postTransform(node) {
|
|
333
366
|
return { ...node, name: 'rf-nav' };
|
|
334
367
|
},
|
|
@@ -364,11 +397,13 @@ export const coreConfig = {
|
|
|
364
397
|
},
|
|
365
398
|
Diff: {
|
|
366
399
|
block: 'diff',
|
|
400
|
+
defaultDensity: 'compact',
|
|
367
401
|
modifiers: { mode: { source: 'meta', default: 'unified' } },
|
|
368
402
|
editHints: { line: 'none', 'gutter-num': 'none', 'gutter-prefix': 'none', 'line-content': 'none' },
|
|
369
403
|
},
|
|
370
404
|
Chart: {
|
|
371
405
|
block: 'chart',
|
|
406
|
+
defaultDensity: 'compact',
|
|
372
407
|
editHints: { data: 'none' },
|
|
373
408
|
postTransform(node) {
|
|
374
409
|
const block = node.attributes.class?.split(' ')[0] || 'rf-chart';
|
|
@@ -482,33 +517,42 @@ export const coreConfig = {
|
|
|
482
517
|
// ─── Text formatting & layout runes ───
|
|
483
518
|
PullQuote: {
|
|
484
519
|
block: 'pullquote',
|
|
520
|
+
defaultDensity: 'compact',
|
|
485
521
|
modifiers: {
|
|
486
522
|
align: { source: 'meta', default: 'center' },
|
|
487
523
|
variant: { source: 'meta', default: 'default' },
|
|
488
524
|
},
|
|
525
|
+
sections: { body: 'body' },
|
|
489
526
|
editHints: { body: 'inline' },
|
|
490
527
|
},
|
|
491
528
|
TextBlock: {
|
|
492
529
|
block: 'textblock',
|
|
530
|
+
defaultDensity: 'full',
|
|
493
531
|
modifiers: {
|
|
494
532
|
dropcap: { source: 'meta' },
|
|
495
533
|
columns: { source: 'meta' },
|
|
496
534
|
lead: { source: 'meta' },
|
|
497
535
|
align: { source: 'meta', default: 'left' },
|
|
498
536
|
},
|
|
537
|
+
sections: { body: 'body' },
|
|
499
538
|
editHints: { body: 'none' },
|
|
500
539
|
},
|
|
501
540
|
MediaText: {
|
|
502
541
|
block: 'mediatext',
|
|
542
|
+
defaultDensity: 'full',
|
|
503
543
|
modifiers: {
|
|
504
544
|
align: { source: 'meta', default: 'left' },
|
|
505
545
|
ratio: { source: 'meta', default: '1:1' },
|
|
506
546
|
wrap: { source: 'meta' },
|
|
507
547
|
},
|
|
548
|
+
sections: { body: 'body', media: 'media' },
|
|
549
|
+
mediaSlots: { media: 'cover' },
|
|
508
550
|
editHints: { media: 'image', body: 'none' },
|
|
509
551
|
},
|
|
510
552
|
Showcase: {
|
|
511
553
|
block: 'showcase',
|
|
554
|
+
defaultDensity: 'compact',
|
|
555
|
+
sections: { viewport: 'body' },
|
|
512
556
|
modifiers: {
|
|
513
557
|
shadow: { source: 'meta', default: 'none' },
|
|
514
558
|
bleed: { source: 'meta', default: 'none' },
|
|
@@ -534,11 +578,13 @@ export const coreConfig = {
|
|
|
534
578
|
},
|
|
535
579
|
},
|
|
536
580
|
// ─── Interactive runes (still get BEM classes, components add behavior) ───
|
|
537
|
-
TabGroup: { block: 'tabs', autoLabel: pageSectionAutoLabel, editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' } },
|
|
538
|
-
Tab: { block: 'tab', parent: 'TabGroup', editHints: { name: 'inline' } },
|
|
539
|
-
TabPanel: { block: 'tab-panel', parent: 'TabGroup' },
|
|
581
|
+
TabGroup: { block: 'tabs', defaultDensity: 'full', sections: { preamble: 'preamble', headline: 'title', blurb: 'description' }, autoLabel: pageSectionAutoLabel, editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline' } },
|
|
582
|
+
Tab: { block: 'tab', parent: 'TabGroup', rootAttributes: { 'data-state': 'inactive' }, editHints: { name: 'inline' } },
|
|
583
|
+
TabPanel: { block: 'tab-panel', parent: 'TabGroup', rootAttributes: { 'data-state': 'inactive' } },
|
|
540
584
|
DataTable: {
|
|
541
585
|
block: 'datatable',
|
|
586
|
+
defaultDensity: 'compact',
|
|
587
|
+
sections: { table: 'body' },
|
|
542
588
|
modifiers: {
|
|
543
589
|
searchable: { source: 'meta', default: 'false' },
|
|
544
590
|
sortable: { source: 'meta' },
|
|
@@ -549,6 +595,8 @@ export const coreConfig = {
|
|
|
549
595
|
},
|
|
550
596
|
Form: {
|
|
551
597
|
block: 'form',
|
|
598
|
+
defaultDensity: 'full',
|
|
599
|
+
sections: { body: 'body' },
|
|
552
600
|
modifiers: {
|
|
553
601
|
variant: { source: 'meta', default: 'stacked' },
|
|
554
602
|
action: { source: 'meta' },
|
|
@@ -568,15 +616,34 @@ export const coreConfig = {
|
|
|
568
616
|
},
|
|
569
617
|
Reveal: {
|
|
570
618
|
block: 'reveal',
|
|
619
|
+
defaultDensity: 'full',
|
|
571
620
|
modifiers: {
|
|
572
621
|
mode: { source: 'meta', default: 'click' },
|
|
573
622
|
},
|
|
623
|
+
sections: { preamble: 'preamble', headline: 'title', blurb: 'description' },
|
|
574
624
|
autoLabel: pageSectionAutoLabel,
|
|
575
625
|
editHints: { headline: 'inline', eyebrow: 'inline', blurb: 'inline', steps: 'none' },
|
|
576
626
|
},
|
|
577
|
-
RevealStep: { block: 'reveal-step', parent: 'Reveal', editHints: { body: 'none' } },
|
|
627
|
+
RevealStep: { block: 'reveal-step', parent: 'Reveal', rootAttributes: { 'data-state': 'closed' }, editHints: { body: 'none' } },
|
|
628
|
+
Juxtapose: {
|
|
629
|
+
block: 'juxtapose',
|
|
630
|
+
defaultDensity: 'compact',
|
|
631
|
+
modifiers: {
|
|
632
|
+
variant: { source: 'meta', default: 'slider' },
|
|
633
|
+
orientation: { source: 'meta', default: 'vertical', noBemClass: true },
|
|
634
|
+
position: { source: 'meta', default: '50', noBemClass: true },
|
|
635
|
+
duration: { source: 'meta', default: '1000', noBemClass: true },
|
|
636
|
+
},
|
|
637
|
+
styles: {
|
|
638
|
+
position: '--jx-position',
|
|
639
|
+
duration: '--jx-duration',
|
|
640
|
+
},
|
|
641
|
+
editHints: { panels: 'none' },
|
|
642
|
+
},
|
|
643
|
+
JuxtaposePanel: { block: 'juxtapose-panel', parent: 'Juxtapose', rootAttributes: { 'data-state': 'inactive' }, editHints: { body: 'none' } },
|
|
578
644
|
Diagram: {
|
|
579
645
|
block: 'diagram',
|
|
646
|
+
defaultDensity: 'compact',
|
|
580
647
|
editHints: { source: 'code' },
|
|
581
648
|
postTransform(node) {
|
|
582
649
|
const block = node.attributes.class?.split(' ')[0] || 'rf-diagram';
|
|
@@ -605,8 +672,12 @@ export const coreConfig = {
|
|
|
605
672
|
};
|
|
606
673
|
},
|
|
607
674
|
},
|
|
675
|
+
Tint: { block: 'tint', parent: '*' },
|
|
676
|
+
Bg: { block: 'bg', parent: '*' },
|
|
677
|
+
Region: { block: 'region', parent: 'Layout' },
|
|
608
678
|
Sandbox: {
|
|
609
679
|
block: 'sandbox',
|
|
680
|
+
defaultDensity: 'compact',
|
|
610
681
|
editHints: { source: 'code' },
|
|
611
682
|
postTransform(node) {
|
|
612
683
|
// Read meta values
|
|
@@ -616,14 +687,23 @@ export const coreConfig = {
|
|
|
616
687
|
const label = readMeta(node, 'label') || '';
|
|
617
688
|
const height = readMeta(node, 'height') || 'auto';
|
|
618
689
|
const designTokens = readMeta(node, 'design-tokens') || '';
|
|
619
|
-
// Keep non-meta children (fallback pre
|
|
620
|
-
const fallbackChildren =
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
if (child
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
690
|
+
// Keep non-meta children (fallback pre) and extract source panels
|
|
691
|
+
const fallbackChildren = [];
|
|
692
|
+
const sourcePanelOrigins = [];
|
|
693
|
+
for (const child of node.children) {
|
|
694
|
+
if (!isTag(child)) {
|
|
695
|
+
fallbackChildren.push(child);
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
if (child.name === 'meta') {
|
|
699
|
+
// Collect origin data from source panels
|
|
700
|
+
if (child.attributes?.['data-field'] === 'source-panel' && child.attributes?.['data-origin']) {
|
|
701
|
+
sourcePanelOrigins.push(`${child.attributes['data-label'] || ''}\t${child.attributes['data-origin']}`);
|
|
702
|
+
}
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
fallbackChildren.push(child);
|
|
706
|
+
}
|
|
627
707
|
// Add hidden content div for web component
|
|
628
708
|
const children = [
|
|
629
709
|
...fallbackChildren,
|
|
@@ -640,6 +720,7 @@ export const coreConfig = {
|
|
|
640
720
|
...(label ? { 'data-label': label } : {}),
|
|
641
721
|
'data-height': height,
|
|
642
722
|
...(designTokens ? { 'data-design-tokens': designTokens } : {}),
|
|
723
|
+
...(sourcePanelOrigins.length > 0 ? { 'data-source-origins': sourcePanelOrigins.join('\n') } : {}),
|
|
643
724
|
},
|
|
644
725
|
children,
|
|
645
726
|
};
|
|
@@ -821,10 +902,282 @@ function buildAutoNav(pageUrl, pagesByUrl, ctx) {
|
|
|
821
902
|
children: [itemsList],
|
|
822
903
|
});
|
|
823
904
|
}
|
|
905
|
+
function walkBlogTags(node, fn) {
|
|
906
|
+
if (Tag.isTag(node)) {
|
|
907
|
+
fn(node);
|
|
908
|
+
for (const child of node.children)
|
|
909
|
+
walkBlogTags(child, fn);
|
|
910
|
+
}
|
|
911
|
+
else if (Array.isArray(node)) {
|
|
912
|
+
node.forEach(n => walkBlogTags(n, fn));
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
function mapBlogTags(node, fn) {
|
|
916
|
+
if (Tag.isTag(node)) {
|
|
917
|
+
const mapped = fn(node);
|
|
918
|
+
if (mapped !== node)
|
|
919
|
+
return mapped;
|
|
920
|
+
const newChildren = node.children.map(c => mapBlogTags(c, fn));
|
|
921
|
+
const changed = newChildren.some((c, i) => c !== node.children[i]);
|
|
922
|
+
return changed ? new Tag(node.name, node.attributes, newChildren) : node;
|
|
923
|
+
}
|
|
924
|
+
if (Array.isArray(node))
|
|
925
|
+
return node.map(n => mapBlogTags(n, fn));
|
|
926
|
+
return node;
|
|
927
|
+
}
|
|
928
|
+
/** Normalise folder path for prefix matching: ensure leading slash and trailing slash */
|
|
929
|
+
function normaliseFolderPath(folder) {
|
|
930
|
+
let f = folder.trim();
|
|
931
|
+
if (!f.startsWith('/'))
|
|
932
|
+
f = '/' + f;
|
|
933
|
+
if (!f.endsWith('/'))
|
|
934
|
+
f += '/';
|
|
935
|
+
return f;
|
|
936
|
+
}
|
|
937
|
+
/** Check if a page URL is a direct child of the given folder */
|
|
938
|
+
function isInFolder(pageUrl, folder) {
|
|
939
|
+
if (!pageUrl.startsWith(folder))
|
|
940
|
+
return false;
|
|
941
|
+
const rest = pageUrl.slice(folder.length);
|
|
942
|
+
const segments = rest.replace(/\/$/, '').split('/').filter(Boolean);
|
|
943
|
+
return segments.length === 1;
|
|
944
|
+
}
|
|
945
|
+
/** Parse a simple filter expression like "tag:javascript" into field/value pairs */
|
|
946
|
+
function parseBlogFilter(filter) {
|
|
947
|
+
if (!filter || !filter.trim())
|
|
948
|
+
return [];
|
|
949
|
+
return filter.split(',').map(part => {
|
|
950
|
+
const colonIdx = part.indexOf(':');
|
|
951
|
+
if (colonIdx === -1)
|
|
952
|
+
return { field: part.trim(), value: '' };
|
|
953
|
+
return {
|
|
954
|
+
field: part.slice(0, colonIdx).trim(),
|
|
955
|
+
value: part.slice(colonIdx + 1).trim(),
|
|
956
|
+
};
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
/** Check if a post's frontmatter matches all filter conditions */
|
|
960
|
+
function matchesBlogFilter(post, filters) {
|
|
961
|
+
for (const { field, value } of filters) {
|
|
962
|
+
const fmValue = post.frontmatter[field];
|
|
963
|
+
if (value === '') {
|
|
964
|
+
if (fmValue === undefined || fmValue === null)
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
else if (Array.isArray(fmValue)) {
|
|
968
|
+
if (!fmValue.some(v => String(v).toLowerCase() === value.toLowerCase()))
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
if (String(fmValue ?? '').toLowerCase() !== value.toLowerCase())
|
|
973
|
+
return false;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
return true;
|
|
977
|
+
}
|
|
978
|
+
/** Sort blog posts by the specified order */
|
|
979
|
+
function sortBlogPosts(posts, sort) {
|
|
980
|
+
const sorted = [...posts];
|
|
981
|
+
switch (sort) {
|
|
982
|
+
case 'date-asc':
|
|
983
|
+
sorted.sort((a, b) => (a.date || '').localeCompare(b.date || ''));
|
|
984
|
+
break;
|
|
985
|
+
case 'title-asc':
|
|
986
|
+
sorted.sort((a, b) => a.title.localeCompare(b.title));
|
|
987
|
+
break;
|
|
988
|
+
case 'title-desc':
|
|
989
|
+
sorted.sort((a, b) => b.title.localeCompare(a.title));
|
|
990
|
+
break;
|
|
991
|
+
case 'date-desc':
|
|
992
|
+
default:
|
|
993
|
+
sorted.sort((a, b) => (b.date || '').localeCompare(a.date || ''));
|
|
994
|
+
break;
|
|
995
|
+
}
|
|
996
|
+
return sorted;
|
|
997
|
+
}
|
|
998
|
+
/** Build an <article> Tag for a single blog post entry */
|
|
999
|
+
function createBlogPostTag(post) {
|
|
1000
|
+
const titleTag = new Tag('h3', {}, [
|
|
1001
|
+
new Tag('a', { href: post.url }, [post.title]),
|
|
1002
|
+
]);
|
|
1003
|
+
const children = [titleTag];
|
|
1004
|
+
if (post.date) {
|
|
1005
|
+
children.push(new Tag('time', { datetime: post.date }, [post.date]));
|
|
1006
|
+
}
|
|
1007
|
+
if (post.description) {
|
|
1008
|
+
children.push(new Tag('p', {}, [post.description]));
|
|
1009
|
+
}
|
|
1010
|
+
return new Tag('article', { 'data-name': 'post' }, children);
|
|
1011
|
+
}
|
|
1012
|
+
/** Resolve blog runes in a renderable tree by injecting matching posts */
|
|
1013
|
+
function resolveBlogPosts(renderable, allPosts, ctx, pageUrl) {
|
|
1014
|
+
let modified = false;
|
|
1015
|
+
const result = mapBlogTags(renderable, (tag) => {
|
|
1016
|
+
if (tag.attributes['data-rune'] !== 'blog')
|
|
1017
|
+
return tag;
|
|
1018
|
+
const folderMeta = tag.children.find((c) => Tag.isTag(c) && c.attributes['data-field'] === 'folder');
|
|
1019
|
+
const sortMeta = tag.children.find((c) => Tag.isTag(c) && c.attributes['data-field'] === 'sort');
|
|
1020
|
+
const filterMeta = tag.children.find((c) => Tag.isTag(c) && c.attributes['data-field'] === 'filter');
|
|
1021
|
+
const limitMeta = tag.children.find((c) => Tag.isTag(c) && c.attributes['data-field'] === 'limit');
|
|
1022
|
+
const folder = Tag.isTag(folderMeta) ? folderMeta.attributes.content : '';
|
|
1023
|
+
const sort = Tag.isTag(sortMeta) ? sortMeta.attributes.content : 'date-desc';
|
|
1024
|
+
const filterStr = Tag.isTag(filterMeta) ? filterMeta.attributes.content : '';
|
|
1025
|
+
const limitStr = Tag.isTag(limitMeta) ? limitMeta.attributes.content : '';
|
|
1026
|
+
const limit = limitStr ? parseInt(limitStr, 10) : undefined;
|
|
1027
|
+
if (!folder) {
|
|
1028
|
+
ctx.warn('Blog rune missing folder attribute', pageUrl);
|
|
1029
|
+
return tag;
|
|
1030
|
+
}
|
|
1031
|
+
const normalised = normaliseFolderPath(folder);
|
|
1032
|
+
const filters = parseBlogFilter(filterStr);
|
|
1033
|
+
let posts = allPosts.filter(post => {
|
|
1034
|
+
if (post.draft)
|
|
1035
|
+
return false;
|
|
1036
|
+
if (!isInFolder(post.url, normalised))
|
|
1037
|
+
return false;
|
|
1038
|
+
if (filters.length > 0 && !matchesBlogFilter(post, filters))
|
|
1039
|
+
return false;
|
|
1040
|
+
return true;
|
|
1041
|
+
});
|
|
1042
|
+
posts = sortBlogPosts(posts, sort);
|
|
1043
|
+
if (limit && limit > 0) {
|
|
1044
|
+
posts = posts.slice(0, limit);
|
|
1045
|
+
}
|
|
1046
|
+
const postsContainer = tag.children.find((c) => Tag.isTag(c) && c.attributes['data-name'] === 'posts');
|
|
1047
|
+
if (!Tag.isTag(postsContainer))
|
|
1048
|
+
return tag;
|
|
1049
|
+
const postTags = posts.map(createBlogPostTag);
|
|
1050
|
+
modified = true;
|
|
1051
|
+
const newPostsContainer = new Tag(postsContainer.name, postsContainer.attributes, postTags);
|
|
1052
|
+
const newChildren = tag.children.map((c) => c === postsContainer ? newPostsContainer : c);
|
|
1053
|
+
return new Tag(tag.name, tag.attributes, newChildren);
|
|
1054
|
+
});
|
|
1055
|
+
return modified ? result : renderable;
|
|
1056
|
+
}
|
|
1057
|
+
// ─── Xref resolution helpers ───
|
|
1058
|
+
/**
|
|
1059
|
+
* Find an entity by exact ID across all types in the registry.
|
|
1060
|
+
* If typeHint is provided, only search that type.
|
|
1061
|
+
*/
|
|
1062
|
+
function findEntityById(registry, id, typeHint) {
|
|
1063
|
+
const types = typeHint ? [typeHint] : registry.getTypes();
|
|
1064
|
+
for (const type of types) {
|
|
1065
|
+
const entity = registry.getById(type, id);
|
|
1066
|
+
if (entity)
|
|
1067
|
+
return { entity, ambiguous: false };
|
|
1068
|
+
}
|
|
1069
|
+
return undefined;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Find entities by name/title match (case-insensitive) across all types.
|
|
1073
|
+
* If typeHint is provided, only search that type.
|
|
1074
|
+
*/
|
|
1075
|
+
function findEntitiesByName(registry, name, typeHint) {
|
|
1076
|
+
const nameLower = name.toLowerCase();
|
|
1077
|
+
const types = typeHint ? [typeHint] : registry.getTypes();
|
|
1078
|
+
const matches = [];
|
|
1079
|
+
for (const type of types) {
|
|
1080
|
+
for (const entity of registry.getAll(type)) {
|
|
1081
|
+
const entityName = entity.data.name ?? '';
|
|
1082
|
+
const entityTitle = entity.data.title ?? '';
|
|
1083
|
+
if (entityName.toLowerCase() === nameLower || entityTitle.toLowerCase() === nameLower) {
|
|
1084
|
+
matches.push(entity);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return matches;
|
|
1089
|
+
}
|
|
1090
|
+
/** Resolve an entity's URL for use as an href */
|
|
1091
|
+
function resolveEntityHref(entity) {
|
|
1092
|
+
const baseUrl = entity.data.url || entity.sourceUrl;
|
|
1093
|
+
const headingId = entity.data.headingId;
|
|
1094
|
+
if (headingId)
|
|
1095
|
+
return `${baseUrl}#${headingId}`;
|
|
1096
|
+
return baseUrl;
|
|
1097
|
+
}
|
|
1098
|
+
/** Walk a Markdoc renderable tree, resolving any xref placeholders */
|
|
1099
|
+
function resolveXrefs(renderable, pageUrl, registry, ctx) {
|
|
1100
|
+
if (!Tag.isTag(renderable)) {
|
|
1101
|
+
if (Array.isArray(renderable)) {
|
|
1102
|
+
const newChildren = renderable.map(c => resolveXrefs(c, pageUrl, registry, ctx));
|
|
1103
|
+
if (newChildren.every((c, i) => c === renderable[i]))
|
|
1104
|
+
return renderable;
|
|
1105
|
+
return newChildren;
|
|
1106
|
+
}
|
|
1107
|
+
return renderable;
|
|
1108
|
+
}
|
|
1109
|
+
const tag = renderable;
|
|
1110
|
+
// Check if this is an xref placeholder
|
|
1111
|
+
if (tag.attributes?.['data-rune'] === XREF_RUNE_MARKER) {
|
|
1112
|
+
const id = tag.attributes['data-xref-id'];
|
|
1113
|
+
const label = tag.attributes['data-xref-label'];
|
|
1114
|
+
const typeHint = tag.attributes['data-xref-type'];
|
|
1115
|
+
// Try exact ID match first
|
|
1116
|
+
const idMatch = findEntityById(registry, id, typeHint);
|
|
1117
|
+
if (idMatch) {
|
|
1118
|
+
const entity = idMatch.entity;
|
|
1119
|
+
const href = resolveEntityHref(entity);
|
|
1120
|
+
const text = label || entity.data.title || entity.data.name || entity.data.text || id;
|
|
1121
|
+
if (entity.sourceUrl === pageUrl) {
|
|
1122
|
+
ctx.info(`xref "${id}" on ${pageUrl} — references itself`, pageUrl);
|
|
1123
|
+
}
|
|
1124
|
+
return new Tag('a', {
|
|
1125
|
+
class: `rf-xref rf-xref--${entity.type}`,
|
|
1126
|
+
href,
|
|
1127
|
+
'data-entity-type': entity.type,
|
|
1128
|
+
'data-entity-id': entity.id,
|
|
1129
|
+
}, [text]);
|
|
1130
|
+
}
|
|
1131
|
+
// Try name/title match
|
|
1132
|
+
const nameMatches = findEntitiesByName(registry, id, typeHint);
|
|
1133
|
+
if (nameMatches.length === 1) {
|
|
1134
|
+
const entity = nameMatches[0];
|
|
1135
|
+
const href = resolveEntityHref(entity);
|
|
1136
|
+
const text = label || entity.data.title || entity.data.name || entity.data.text || id;
|
|
1137
|
+
if (entity.sourceUrl === pageUrl) {
|
|
1138
|
+
ctx.info(`xref "${id}" on ${pageUrl} — references itself`, pageUrl);
|
|
1139
|
+
}
|
|
1140
|
+
return new Tag('a', {
|
|
1141
|
+
class: `rf-xref rf-xref--${entity.type}`,
|
|
1142
|
+
href,
|
|
1143
|
+
'data-entity-type': entity.type,
|
|
1144
|
+
'data-entity-id': entity.id,
|
|
1145
|
+
}, [text]);
|
|
1146
|
+
}
|
|
1147
|
+
if (nameMatches.length > 1) {
|
|
1148
|
+
const matchList = nameMatches
|
|
1149
|
+
.map(e => `${e.type} "${e.data.title || e.data.name || e.id}" on ${e.sourceUrl}`)
|
|
1150
|
+
.join(', ');
|
|
1151
|
+
ctx.warn(`xref "${id}" on ${pageUrl} — matches ${nameMatches.length} entities (${matchList}). Add type hint to disambiguate.`, pageUrl);
|
|
1152
|
+
// Use first match
|
|
1153
|
+
const entity = nameMatches[0];
|
|
1154
|
+
const href = resolveEntityHref(entity);
|
|
1155
|
+
const text = label || entity.data.title || entity.data.name || entity.data.text || id;
|
|
1156
|
+
return new Tag('a', {
|
|
1157
|
+
class: `rf-xref rf-xref--${entity.type}`,
|
|
1158
|
+
href,
|
|
1159
|
+
'data-entity-type': entity.type,
|
|
1160
|
+
'data-entity-id': entity.id,
|
|
1161
|
+
}, [text]);
|
|
1162
|
+
}
|
|
1163
|
+
// No match — unresolved
|
|
1164
|
+
ctx.warn(`xref "${id}" on ${pageUrl} — entity not found`, pageUrl);
|
|
1165
|
+
return new Tag('span', {
|
|
1166
|
+
class: 'rf-xref rf-xref--unresolved',
|
|
1167
|
+
'data-entity-id': id,
|
|
1168
|
+
}, [label || id]);
|
|
1169
|
+
}
|
|
1170
|
+
// Recurse into children
|
|
1171
|
+
const newChildren = (tag.children ?? []).map((c) => resolveXrefs(c, pageUrl, registry, ctx));
|
|
1172
|
+
if (newChildren.every((c, i) => c === tag.children[i]))
|
|
1173
|
+
return tag;
|
|
1174
|
+
return { ...tag, children: newChildren };
|
|
1175
|
+
}
|
|
824
1176
|
/**
|
|
825
1177
|
* Core cross-page pipeline hooks.
|
|
826
1178
|
* Run for every site, before any community package hooks.
|
|
827
|
-
* Registers page and heading entities, aggregates the page tree and breadcrumb paths
|
|
1179
|
+
* Registers page and heading entities, aggregates the page tree and breadcrumb paths,
|
|
1180
|
+
* and resolves blog post listings.
|
|
828
1181
|
*/
|
|
829
1182
|
export const corePipelineHooks = {
|
|
830
1183
|
register(pages, registry, ctx) {
|
|
@@ -879,7 +1232,16 @@ export const corePipelineHooks = {
|
|
|
879
1232
|
for (const h of registry.getAll('heading')) {
|
|
880
1233
|
headingIndex.set(h.id, h.data);
|
|
881
1234
|
}
|
|
882
|
-
|
|
1235
|
+
// Blog: collect all pages as potential blog posts
|
|
1236
|
+
const allPosts = pageEntities.map(e => ({
|
|
1237
|
+
title: e.data.title || '',
|
|
1238
|
+
url: e.data.url || e.id,
|
|
1239
|
+
date: e.data.date || '',
|
|
1240
|
+
description: e.data.description || '',
|
|
1241
|
+
draft: e.data.draft || false,
|
|
1242
|
+
frontmatter: e.data,
|
|
1243
|
+
}));
|
|
1244
|
+
return { pageTree, breadcrumbPaths, pagesByUrl, headingIndex, allPosts, registry };
|
|
883
1245
|
},
|
|
884
1246
|
postProcess(page, aggregated, ctx) {
|
|
885
1247
|
const coreData = aggregated['__core__'];
|
|
@@ -887,6 +1249,8 @@ export const corePipelineHooks = {
|
|
|
887
1249
|
return page;
|
|
888
1250
|
let renderable = resolveAutoBreadcrumbs(page.renderable, page.url, coreData.breadcrumbPaths, coreData.pagesByUrl, ctx);
|
|
889
1251
|
renderable = resolveAutoNavs(renderable, page.url, coreData.pagesByUrl, ctx);
|
|
1252
|
+
renderable = resolveBlogPosts(renderable, coreData.allPosts, ctx, page.url);
|
|
1253
|
+
renderable = resolveXrefs(renderable, page.url, coreData.registry, ctx);
|
|
890
1254
|
if (renderable === page.renderable)
|
|
891
1255
|
return page;
|
|
892
1256
|
return { ...page, renderable };
|