@cogenta/theme-kit 0.3.2
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/LICENSE +373 -0
- package/dist/actions.d.ts +17 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +43 -0
- package/dist/actions.js.map +1 -0
- package/dist/archive.d.ts +85 -0
- package/dist/archive.d.ts.map +1 -0
- package/dist/archive.js +21 -0
- package/dist/archive.js.map +1 -0
- package/dist/chrome.d.ts +161 -0
- package/dist/chrome.d.ts.map +1 -0
- package/dist/chrome.js +198 -0
- package/dist/chrome.js.map +1 -0
- package/dist/comments.d.ts +54 -0
- package/dist/comments.d.ts.map +1 -0
- package/dist/comments.js +68 -0
- package/dist/comments.js.map +1 -0
- package/dist/contract.d.ts +97 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +31 -0
- package/dist/contract.js.map +1 -0
- package/dist/entry-header.d.ts +62 -0
- package/dist/entry-header.d.ts.map +1 -0
- package/dist/entry-header.js +65 -0
- package/dist/entry-header.js.map +1 -0
- package/dist/entry.d.ts +21 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +65 -0
- package/dist/entry.js.map +1 -0
- package/dist/heading.d.ts +14 -0
- package/dist/heading.d.ts.map +1 -0
- package/dist/heading.js +34 -0
- package/dist/heading.js.map +1 -0
- package/dist/html.d.ts +42 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +94 -0
- package/dist/html.js.map +1 -0
- package/dist/icons.d.ts +37 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +187 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/media.d.ts +45 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +70 -0
- package/dist/media.js.map +1 -0
- package/dist/page.d.ts +104 -0
- package/dist/page.d.ts.map +1 -0
- package/dist/page.js +134 -0
- package/dist/page.js.map +1 -0
- package/dist/rich-text.d.ts +5 -0
- package/dist/rich-text.d.ts.map +1 -0
- package/dist/rich-text.js +125 -0
- package/dist/rich-text.js.map +1 -0
- package/dist/strings.d.ts +30 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +124 -0
- package/dist/strings.js.map +1 -0
- package/dist/theme-toggle.d.ts +69 -0
- package/dist/theme-toggle.d.ts.map +1 -0
- package/dist/theme-toggle.js +136 -0
- package/dist/theme-toggle.js.map +1 -0
- package/package.json +43 -0
package/dist/icons.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { h } from './html.js';
|
|
2
|
+
/**
|
|
3
|
+
* Inline icons for the block vocabulary's `icon: string` fields (contract B —
|
|
4
|
+
* `featureGrid` items, and any future block that names one the same way).
|
|
5
|
+
*
|
|
6
|
+
* Contract B stores a *symbol name*, never markup (R3) — a block cannot carry
|
|
7
|
+
* its own `<svg>`, so until this module existed every theme rendered
|
|
8
|
+
* `<span data-icon="…">` with nothing inside it: the name reached the page,
|
|
9
|
+
* but nothing visible ever did. This is the shared, zero-dependency mapping
|
|
10
|
+
* from that name to a real icon, written once here rather than five times
|
|
11
|
+
* (one per theme package) the way `renderSocialLinks`/`renderBrandMark`
|
|
12
|
+
* already are for their own corner of a page's chrome.
|
|
13
|
+
*
|
|
14
|
+
* Every path is authored directly for this file — outline style, a single
|
|
15
|
+
* `stroke-width`, no copied icon-library data, no external font or sprite
|
|
16
|
+
* sheet (R9/R10). `renderIcon` returns `null` for a name outside the closed
|
|
17
|
+
* list below, which is a *theme's* signal to fall back to whatever it
|
|
18
|
+
* rendered before this module existed — never a placeholder glyph that would
|
|
19
|
+
* itself need explaining.
|
|
20
|
+
*/
|
|
21
|
+
export const ICON_NAMES = [
|
|
22
|
+
'check',
|
|
23
|
+
'star',
|
|
24
|
+
'bolt',
|
|
25
|
+
'shield',
|
|
26
|
+
'chart',
|
|
27
|
+
'users',
|
|
28
|
+
'user',
|
|
29
|
+
'globe',
|
|
30
|
+
'clock',
|
|
31
|
+
'heart',
|
|
32
|
+
'leaf',
|
|
33
|
+
'mail',
|
|
34
|
+
'phone',
|
|
35
|
+
'map-pin',
|
|
36
|
+
'calendar',
|
|
37
|
+
'book',
|
|
38
|
+
'code',
|
|
39
|
+
'cloud',
|
|
40
|
+
'lock',
|
|
41
|
+
'search',
|
|
42
|
+
'settings',
|
|
43
|
+
'sparkles',
|
|
44
|
+
'truck',
|
|
45
|
+
'credit-card',
|
|
46
|
+
'gift',
|
|
47
|
+
'coffee',
|
|
48
|
+
'utensils',
|
|
49
|
+
'wine',
|
|
50
|
+
'camera',
|
|
51
|
+
'pen',
|
|
52
|
+
'layers',
|
|
53
|
+
'rocket',
|
|
54
|
+
'trending-up',
|
|
55
|
+
'award',
|
|
56
|
+
'smile',
|
|
57
|
+
'sun',
|
|
58
|
+
'moon',
|
|
59
|
+
'arrow-right',
|
|
60
|
+
'arrow-up-right',
|
|
61
|
+
'external-link',
|
|
62
|
+
'download',
|
|
63
|
+
'play',
|
|
64
|
+
'quote',
|
|
65
|
+
'tag',
|
|
66
|
+
'briefcase',
|
|
67
|
+
'home',
|
|
68
|
+
'message',
|
|
69
|
+
'bell',
|
|
70
|
+
'refresh',
|
|
71
|
+
'image',
|
|
72
|
+
'zap',
|
|
73
|
+
];
|
|
74
|
+
const NAME_SET = new Set(ICON_NAMES);
|
|
75
|
+
/** A circle, as two path arcs — `<path>` is the only shape this module emits (see the module comment). */
|
|
76
|
+
function circle(cx, cy, r) {
|
|
77
|
+
return `M${cx - r} ${cy}a${r} ${r} 0 1 0 ${2 * r} 0a${r} ${r} 0 1 0 ${-2 * r} 0`;
|
|
78
|
+
}
|
|
79
|
+
/** One `<path>` per icon, built from the `d` strings below — most icons need only one; a few need two or three distinct strokes. */
|
|
80
|
+
const PATHS = {
|
|
81
|
+
check: ['M4 13l5 5L20 6'],
|
|
82
|
+
star: ['M12 3l2.6 5.6 6.1.6-4.6 4.1 1.3 6-5.4-3.1-5.4 3.1 1.3-6-4.6-4.1 6.1-.6z'],
|
|
83
|
+
bolt: ['M13 2 4 14h6l-1 8 9-12h-6z'],
|
|
84
|
+
shield: ['M12 2 20 5.5v5.5c0 5-3.5 9-8 11-4.5-2-8-6-8-11V5.5z'],
|
|
85
|
+
chart: ['M4 20V12M10 20V7M16 20V4M3 20h18'],
|
|
86
|
+
users: [
|
|
87
|
+
circle(9, 8, 3),
|
|
88
|
+
circle(17.5, 9.5, 2.3),
|
|
89
|
+
'M2.5 20a6.5 6.5 0 0 1 13 0M14.8 14.5c2.2.4 4 2.3 4.6 5.5',
|
|
90
|
+
],
|
|
91
|
+
user: [circle(12, 8, 3.5), 'M4.5 20a7.5 7.5 0 0 1 15 0'],
|
|
92
|
+
globe: [circle(12, 12, 9), 'M3 12h18', 'M12 3c-3.3 4-3.3 14 0 18c3.3-4 3.3-14 0-18'],
|
|
93
|
+
clock: [circle(12, 12, 9), 'M12 7v5l3.5 2'],
|
|
94
|
+
heart: [
|
|
95
|
+
'M12 20S3 14.5 3 8.5C3 5.5 5.2 3.5 8 3.5c1.8 0 3.2 1 4 2.4c.8-1.4 2.2-2.4 4-2.4c2.8 0 5 2 5 5c0 6-9 11.5-9 11.5z',
|
|
96
|
+
],
|
|
97
|
+
leaf: ['M20 4c-9 0-16 7-16 16c9 0 16-7 16-16z', 'M4 20 12 12'],
|
|
98
|
+
mail: ['M3 5h18v14H3z', 'M4 6l8 7 8-7'],
|
|
99
|
+
phone: [
|
|
100
|
+
'M5 3h4l2 5-2.5 2.4a12 12 0 0 0 6.1 6.1L17 14l5 2v4a2 2 0 0 1-2.2 2C10.6 21.6 2.4 13.4 2 4.2A2 2 0 0 1 4 2z',
|
|
101
|
+
],
|
|
102
|
+
'map-pin': ['M12 22s7-7.4 7-12.8a7 7 0 0 0-14 0C5 14.6 12 22 12 22z', circle(12, 9.2, 2.4)],
|
|
103
|
+
calendar: ['M4 5h16v16H4z', 'M4 10h16', 'M8 3v4', 'M16 3v4'],
|
|
104
|
+
book: ['M4 4h7a3 3 0 0 1 3 3v13a3 3 0 0 0-3-3H4z', 'M20 4h-7a3 3 0 0 0-3 3v13a3 3 0 0 1 3-3h7z'],
|
|
105
|
+
code: ['M8 6 2 12l6 6', 'M16 6l6 6-6 6'],
|
|
106
|
+
cloud: ['M6.5 18a4.2 4.2 0 0 1 .5-8.4A5.6 5.6 0 0 1 17.7 9.9A4.1 4.1 0 0 1 17 18z'],
|
|
107
|
+
lock: ['M5 11h14v10H5z', 'M7.5 11V7a4.5 4.5 0 0 1 9 0v4'],
|
|
108
|
+
search: [circle(11, 11, 7), 'M21 21l-5-5'],
|
|
109
|
+
settings: [circle(12, 12, 3), circle(12, 12, 8)],
|
|
110
|
+
sparkles: [
|
|
111
|
+
'M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5z',
|
|
112
|
+
'M19 14l.6 1.8 1.9.6-1.9.6L19 19l-.6-1.8-1.9-.6 1.9-.6z',
|
|
113
|
+
],
|
|
114
|
+
truck: ['M1 7h13v10H1z', 'M14 10h4l4 3.5V17h-8z', circle(6, 19, 1.8), circle(17.5, 19, 1.8)],
|
|
115
|
+
'credit-card': ['M2 5h20v14H2z', 'M2 10h20'],
|
|
116
|
+
gift: ['M3 9h18v12H3z', 'M12 9v12', 'M6 9c0-3 4.5-4 6-1c1.5-3 6-2 6 1z'],
|
|
117
|
+
coffee: ['M4 9h12v7a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4z', 'M16 11h1a2.5 2.5 0 0 1 0 5h-1', 'M8 3v5'],
|
|
118
|
+
utensils: [
|
|
119
|
+
'M6 2v9M4 2v5a2 2 0 0 0 4 0V2M6 11v11',
|
|
120
|
+
'M18 2c-1.5 3-1.5 6 0 8c0 4-1 12-1 12',
|
|
121
|
+
'M18 2v8',
|
|
122
|
+
],
|
|
123
|
+
wine: ['M7 3h10l-1 8a4 4 0 0 1-8 0z', 'M12 15v6', 'M8 21h8'],
|
|
124
|
+
camera: ['M3 8h4l2-3h6l2 3h4v12H3z', circle(12, 14, 4)],
|
|
125
|
+
pen: ['M3 21l4-1 12-12-3-3L4 17z', 'M14 5l3 3'],
|
|
126
|
+
layers: ['M12 3 3 8l9 5 9-5z', 'M3 13l9 5 9-5', 'M3 18l9 5 9-5'],
|
|
127
|
+
rocket: [
|
|
128
|
+
'M12 2c3.5 1 6 4.5 6 9c0 3-1.5 6-3 8l-3-2-3 2c-1.5-2-3-5-3-8c0-4.5 2.5-8 6-9z',
|
|
129
|
+
'M9 17l-3 4M15 17l3 4',
|
|
130
|
+
circle(12, 10, 2),
|
|
131
|
+
],
|
|
132
|
+
'trending-up': ['M3 17l6-6 4 4 8-9', 'M15 6h6v6'],
|
|
133
|
+
award: [circle(12, 8, 5), 'M9 12.5 7 22l5-3 5 3-2-9.5'],
|
|
134
|
+
smile: [circle(12, 12, 9), 'M8 14c1.2 1.5 2.6 2.2 4 2.2s2.8-.7 4-2.2', 'M8.5 9h.01M15.5 9h.01'],
|
|
135
|
+
sun: [
|
|
136
|
+
circle(12, 12, 4.5),
|
|
137
|
+
'M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1',
|
|
138
|
+
],
|
|
139
|
+
moon: ['M20 14.5A8.5 8.5 0 1 1 9.5 4a7 7 0 0 0 10.5 10.5z'],
|
|
140
|
+
'arrow-right': ['M4 12h16', 'M13 5l7 7-7 7'],
|
|
141
|
+
'arrow-up-right': ['M6 18 18 6', 'M8 6h10v10'],
|
|
142
|
+
'external-link': ['M9 5H5v14h14v-4', 'M13 3h8v8', 'M21 3 11 13'],
|
|
143
|
+
download: ['M12 3v13', 'M6 11l6 6 6-6', 'M4 21h16'],
|
|
144
|
+
play: ['M6 3l16 9-16 9z'],
|
|
145
|
+
quote: [
|
|
146
|
+
'M4 8c0-3 2-5 5-5v3c-1.5 0-2.5 1-2.5 2.5H9v6H4z',
|
|
147
|
+
'M13 8c0-3 2-5 5-5v3c-1.5 0-2.5 1-2.5 2.5H18v6h-5z',
|
|
148
|
+
],
|
|
149
|
+
tag: ['M3 12 12 3h6a3 3 0 0 1 3 3v6l-9 9z', circle(15, 9, 1.6)],
|
|
150
|
+
briefcase: ['M3 8h18v11H3z', 'M8 8V6a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2'],
|
|
151
|
+
home: ['M4 11 12 4l8 7', 'M6 10v10h12V10'],
|
|
152
|
+
message: ['M4 4h16v11H9l-5 4z'],
|
|
153
|
+
bell: ['M6 10a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6z', 'M10 20a2 2 0 0 0 4 0'],
|
|
154
|
+
refresh: ['M4 4v6h6', 'M20 20v-6h-6', 'M4.5 15a8 8 0 0 0 14.6 2.5M19.5 9A8 8 0 0 0 4.9 6.5'],
|
|
155
|
+
image: ['M3 4h18v16H3z', circle(9, 10, 2), 'M3 17l5-5 4 4 5-6 4 5'],
|
|
156
|
+
zap: ['M13 2 4 14h6l-1 8 9-12h-6z'],
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* One `<svg viewBox="0 0 24 24">` per known name, `null` for anything else —
|
|
160
|
+
* a theme's own fallback (usually the pre-icon `<span data-icon>`, kept for
|
|
161
|
+
* the page builder to key off) applies exactly as it did before this module
|
|
162
|
+
* existed.
|
|
163
|
+
*
|
|
164
|
+
* `aria-hidden`/`focusable="false"`: the icon is always beside a text label
|
|
165
|
+
* (a feature's own title) that already carries the accessible name — an icon
|
|
166
|
+
* that duplicated it would be announced twice.
|
|
167
|
+
*/
|
|
168
|
+
export function renderIcon(name, options = {}) {
|
|
169
|
+
if (!NAME_SET.has(name))
|
|
170
|
+
return null;
|
|
171
|
+
const paths = PATHS[name];
|
|
172
|
+
const size = options.size ?? 24;
|
|
173
|
+
return h('svg', {
|
|
174
|
+
class: options.className,
|
|
175
|
+
viewBox: '0 0 24 24',
|
|
176
|
+
width: size,
|
|
177
|
+
height: size,
|
|
178
|
+
fill: 'none',
|
|
179
|
+
stroke: 'currentColor',
|
|
180
|
+
'stroke-width': 1.75,
|
|
181
|
+
'stroke-linecap': 'round',
|
|
182
|
+
'stroke-linejoin': 'round',
|
|
183
|
+
'aria-hidden': 'true',
|
|
184
|
+
focusable: 'false',
|
|
185
|
+
}, paths.map((d) => h('path', { d })));
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icons.js","sourceRoot":"","sources":["../src/icons.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@cogenta/theme-kit` — the shared contract D primitives every Cogenta theme
|
|
3
|
+
* package implements against.
|
|
4
|
+
*
|
|
5
|
+
* Moved out of `@cogenta/theme-canonical` (which had carried a "temporary
|
|
6
|
+
* home, must be replaced... not duplicated" copy of most of this since L3)
|
|
7
|
+
* the day a second theme package was first written: five independent copies
|
|
8
|
+
* of the same escaping/rich-text/comments logic is exactly the drift that
|
|
9
|
+
* comment warned about, and this package is what makes "one copy, five
|
|
10
|
+
* consumers" true instead.
|
|
11
|
+
*/
|
|
12
|
+
export * from './actions.js';
|
|
13
|
+
export * from './archive.js';
|
|
14
|
+
export * from './chrome.js';
|
|
15
|
+
export * from './comments.js';
|
|
16
|
+
export * from './contract.js';
|
|
17
|
+
export * from './entry.js';
|
|
18
|
+
export * from './entry-header.js';
|
|
19
|
+
export * from './heading.js';
|
|
20
|
+
export * from './html.js';
|
|
21
|
+
export * from './icons.js';
|
|
22
|
+
export * from './media.js';
|
|
23
|
+
export * from './page.js';
|
|
24
|
+
export * from './rich-text.js';
|
|
25
|
+
export * from './strings.js';
|
|
26
|
+
export * from './theme-toggle.js';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@cogenta/theme-kit` — the shared contract D primitives every Cogenta theme
|
|
3
|
+
* package implements against.
|
|
4
|
+
*
|
|
5
|
+
* Moved out of `@cogenta/theme-canonical` (which had carried a "temporary
|
|
6
|
+
* home, must be replaced... not duplicated" copy of most of this since L3)
|
|
7
|
+
* the day a second theme package was first written: five independent copies
|
|
8
|
+
* of the same escaping/rich-text/comments logic is exactly the drift that
|
|
9
|
+
* comment warned about, and this package is what makes "one copy, five
|
|
10
|
+
* consumers" true instead.
|
|
11
|
+
*/
|
|
12
|
+
export * from './actions.js';
|
|
13
|
+
export * from './archive.js';
|
|
14
|
+
export * from './chrome.js';
|
|
15
|
+
export * from './comments.js';
|
|
16
|
+
export * from './contract.js';
|
|
17
|
+
export * from './entry.js';
|
|
18
|
+
export * from './entry-header.js';
|
|
19
|
+
export * from './heading.js';
|
|
20
|
+
export * from './html.js';
|
|
21
|
+
export * from './icons.js';
|
|
22
|
+
export * from './media.js';
|
|
23
|
+
export * from './page.js';
|
|
24
|
+
export * from './rich-text.js';
|
|
25
|
+
export * from './strings.js';
|
|
26
|
+
export * from './theme-toggle.js';
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA"}
|
package/dist/media.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ImageOptions, ImageSource, MediaReference, RenderContext } from './contract.js';
|
|
2
|
+
import { type HtmlElement } from './html.js';
|
|
3
|
+
export interface ImageRenderOptions {
|
|
4
|
+
/** The `sizes` hint. Layout knowledge, so it belongs to the theme, not the block. */
|
|
5
|
+
readonly sizes?: string;
|
|
6
|
+
/** `eager` only for what is above the fold — the hero, and nothing else. */
|
|
7
|
+
readonly loading?: 'lazy' | 'eager';
|
|
8
|
+
readonly className?: string;
|
|
9
|
+
/**
|
|
10
|
+
* An accessible name the *block* provides — a logo's organisation name, for
|
|
11
|
+
* instance. It never invents alt text: it is used only where contract B says
|
|
12
|
+
* the block already carries the name.
|
|
13
|
+
*/
|
|
14
|
+
readonly altFrom?: string;
|
|
15
|
+
readonly variant?: ImageOptions;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The image (or video) a theme emits — shared so `alt`/`kind` handling cannot
|
|
19
|
+
* drift between theme packages.
|
|
20
|
+
*
|
|
21
|
+
* `alt` is always written, never omitted: an image with no `alt` attribute is
|
|
22
|
+
* announced by its file name, while `alt=""` is announced as decorative. The
|
|
23
|
+
* difference is the whole of WCAG 1.1.1 here, and it cannot be left to whether
|
|
24
|
+
* a caller remembered.
|
|
25
|
+
*
|
|
26
|
+
* The alt text itself comes from the media entity through `ctx.image` — a
|
|
27
|
+
* theme has no business inventing one, and correcting it in the media library
|
|
28
|
+
* must fix every page at once.
|
|
29
|
+
*
|
|
30
|
+
* `kind: 'video'` (contract D `theme@1.1`) renders a `<video>` with its
|
|
31
|
+
* poster instead of a broken `<img>` — the gap the very first theme built
|
|
32
|
+
* against the pre-1.1 copy of this contract had, closed here once for every
|
|
33
|
+
* theme rather than per theme.
|
|
34
|
+
*/
|
|
35
|
+
export declare function image(ctx: RenderContext, media: MediaReference, options?: ImageRenderOptions): HtmlElement;
|
|
36
|
+
/**
|
|
37
|
+
* The same markup `image()` builds, from a source already resolved (by
|
|
38
|
+
* `entryImage`, say) rather than a raw `MediaReference` — for a caller that
|
|
39
|
+
* has an `ImageSource` in hand and no `RenderContext.image` to call again
|
|
40
|
+
* (`renderEntryHeader`'s cover, contract D `theme@1.4`).
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderImageSource(source: ImageSource, options?: Omit<ImageRenderOptions, 'variant'>): HtmlElement;
|
|
43
|
+
/** Contract B's framing values, as a CSS `aspect-ratio`. `original` means none. */
|
|
44
|
+
export declare function aspectRatio(ratio: string | undefined): string | undefined;
|
|
45
|
+
//# sourceMappingURL=media.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7F,OAAO,EAAE,KAAK,WAAW,EAAK,MAAM,WAAW,CAAA;AAE/C,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAChC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,KAAK,CACnB,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,kBAAuB,GAC/B,WAAW,CAEb;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,IAAI,CAAC,kBAAkB,EAAE,SAAS,CAAM,GAChD,WAAW,CAiCb;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKzE"}
|
package/dist/media.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { h } from './html.js';
|
|
2
|
+
/**
|
|
3
|
+
* The image (or video) a theme emits — shared so `alt`/`kind` handling cannot
|
|
4
|
+
* drift between theme packages.
|
|
5
|
+
*
|
|
6
|
+
* `alt` is always written, never omitted: an image with no `alt` attribute is
|
|
7
|
+
* announced by its file name, while `alt=""` is announced as decorative. The
|
|
8
|
+
* difference is the whole of WCAG 1.1.1 here, and it cannot be left to whether
|
|
9
|
+
* a caller remembered.
|
|
10
|
+
*
|
|
11
|
+
* The alt text itself comes from the media entity through `ctx.image` — a
|
|
12
|
+
* theme has no business inventing one, and correcting it in the media library
|
|
13
|
+
* must fix every page at once.
|
|
14
|
+
*
|
|
15
|
+
* `kind: 'video'` (contract D `theme@1.1`) renders a `<video>` with its
|
|
16
|
+
* poster instead of a broken `<img>` — the gap the very first theme built
|
|
17
|
+
* against the pre-1.1 copy of this contract had, closed here once for every
|
|
18
|
+
* theme rather than per theme.
|
|
19
|
+
*/
|
|
20
|
+
export function image(ctx, media, options = {}) {
|
|
21
|
+
return renderImageSource(ctx.image(media, options.variant), options);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The same markup `image()` builds, from a source already resolved (by
|
|
25
|
+
* `entryImage`, say) rather than a raw `MediaReference` — for a caller that
|
|
26
|
+
* has an `ImageSource` in hand and no `RenderContext.image` to call again
|
|
27
|
+
* (`renderEntryHeader`'s cover, contract D `theme@1.4`).
|
|
28
|
+
*/
|
|
29
|
+
export function renderImageSource(source, options = {}) {
|
|
30
|
+
if (source.kind === 'video') {
|
|
31
|
+
return h('video', {
|
|
32
|
+
class: options.className,
|
|
33
|
+
src: source.src,
|
|
34
|
+
poster: source.poster,
|
|
35
|
+
width: source.width,
|
|
36
|
+
height: source.height,
|
|
37
|
+
controls: true,
|
|
38
|
+
preload: 'metadata',
|
|
39
|
+
style: source.focal === null
|
|
40
|
+
? undefined
|
|
41
|
+
: `object-position:${source.focal.x * 100}% ${source.focal.y * 100}%`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return h('img', {
|
|
45
|
+
class: options.className,
|
|
46
|
+
src: source.src,
|
|
47
|
+
srcset: source.srcset === '' ? undefined : source.srcset,
|
|
48
|
+
sizes: options.sizes,
|
|
49
|
+
width: source.width,
|
|
50
|
+
height: source.height,
|
|
51
|
+
alt: source.alt !== '' ? source.alt : (options.altFrom ?? ''),
|
|
52
|
+
loading: options.loading ?? 'lazy',
|
|
53
|
+
decoding: 'async',
|
|
54
|
+
// The focal point is content data, not a style value: it says which part of
|
|
55
|
+
// the picture must survive a crop. Nothing else can carry it per-image.
|
|
56
|
+
style: source.focal === null
|
|
57
|
+
? undefined
|
|
58
|
+
: `object-position:${source.focal.x * 100}% ${source.focal.y * 100}%`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/** Contract B's framing values, as a CSS `aspect-ratio`. `original` means none. */
|
|
62
|
+
export function aspectRatio(ratio) {
|
|
63
|
+
if (ratio === undefined || ratio === 'original')
|
|
64
|
+
return undefined;
|
|
65
|
+
const [width, height] = ratio.split(':');
|
|
66
|
+
if (width === undefined || height === undefined)
|
|
67
|
+
return undefined;
|
|
68
|
+
return `${width} / ${height}`;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=media.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../src/media.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,CAAC,EAAE,MAAM,WAAW,CAAA;AAiB/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,KAAK,CACnB,GAAkB,EAClB,KAAqB,EACrB,OAAO,GAAuB,EAAE;IAEhC,OAAO,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAA;AACtE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAmB,EACnB,OAAO,GAAwC,EAAE;IAEjD,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC,OAAO,EAAE;YAChB,KAAK,EAAE,OAAO,CAAC,SAAS;YACxB,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,UAAU;YACnB,KAAK,EACH,MAAM,CAAC,KAAK,KAAK,IAAI;gBACnB,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,GAAG;SAC1E,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,CAAC,CAAC,KAAK,EAAE;QACd,KAAK,EAAE,OAAO,CAAC,SAAS;QACxB,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM;QACxD,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,GAAG,EAAE,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAC7D,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM;QAClC,QAAQ,EAAE,OAAO;QACjB,4EAA4E;QAC5E,wEAAwE;QACxE,KAAK,EACH,MAAM,CAAC,KAAK,KAAK,IAAI;YACnB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,GAAG;KAC1E,CAAC,CAAA;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,KAAyB;IACnD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,UAAU;QAAE,OAAO,SAAS,CAAA;IACjE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACxC,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACjE,OAAO,GAAG,KAAK,MAAM,MAAM,EAAE,CAAA;AAC/B,CAAC"}
|
package/dist/page.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { type BlockRegistry, type BlockVariant, type CollectionListBlock, type UnknownPlacedBlock, type VocabularyBlock } from '@cogenta/blocks';
|
|
2
|
+
import type { ContentEntry, QueryRequest } from './contract.js';
|
|
3
|
+
import type { PageEntryMeta } from './entry-header.js';
|
|
4
|
+
import type { HtmlElement } from './html.js';
|
|
5
|
+
export interface PageContent {
|
|
6
|
+
/** The entry's title. Rendered as the `h1` unless a hero already carries one. */
|
|
7
|
+
readonly title: string;
|
|
8
|
+
readonly blocks: readonly VocabularyBlock[];
|
|
9
|
+
/**
|
|
10
|
+
* The article furniture a `richText`/blocks entry carries beyond its
|
|
11
|
+
* blocks — cover image, byline, date, taxonomy terms, reading time
|
|
12
|
+
* (contract D `theme@1.4`, optional and additive). Absent means the
|
|
13
|
+
* pre-1.4 page: a bare title and nothing else, exactly as before. See
|
|
14
|
+
* `renderEntryHeader` for the one shared way a theme turns this into
|
|
15
|
+
* markup.
|
|
16
|
+
*/
|
|
17
|
+
readonly entry?: PageEntryMeta;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Entries already fetched for the `collectionList` blocks on the page, by the
|
|
21
|
+
* block's `_key`. Fetching happens before any markup is built — a renderer
|
|
22
|
+
* that could await would make the number of round trips depend on the
|
|
23
|
+
* markup, which no theme can be trusted to keep constant across edits.
|
|
24
|
+
*/
|
|
25
|
+
export type FetchedEntries = Readonly<Record<string, readonly ContentEntry[]>>;
|
|
26
|
+
/**
|
|
27
|
+
* A page has exactly one `h1`.
|
|
28
|
+
*
|
|
29
|
+
* A `hero` declares `headingLevel: 'h1'` and renders the title itself, so a
|
|
30
|
+
* theme's page layout must not render a second one; without a hero, nothing
|
|
31
|
+
* else on the page would — `prose` starts at `h2` — and the page would have
|
|
32
|
+
* no `h1` at all.
|
|
33
|
+
*/
|
|
34
|
+
export declare function pageHasOwnHeading(blocks: readonly VocabularyBlock[]): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Stamps the block's own `_key` onto the element it rendered to.
|
|
37
|
+
*
|
|
38
|
+
* The key is contract B's identity for a placed block — minted once, surviving
|
|
39
|
+
* reorder, translation and version restore — so it is the one honest way for a
|
|
40
|
+
* *reader* of the finished HTML to say "this piece of the page came from that
|
|
41
|
+
* block". The visual page builder (L16) is such a reader: it shows the real
|
|
42
|
+
* server-rendered page in an iframe and needs to map a clicked element back to
|
|
43
|
+
* the block that produced it. Shared across every theme so that mapping works
|
|
44
|
+
* identically regardless of which theme a site has installed.
|
|
45
|
+
*
|
|
46
|
+
* Emitted on every render, never only in a builder mode — a preview that is
|
|
47
|
+
* assembled differently from the published page is exactly the divergence the
|
|
48
|
+
* builder exists to rule out.
|
|
49
|
+
*/
|
|
50
|
+
export declare function withBlockKey(element: HtmlElement | null, key: string): HtmlElement | null;
|
|
51
|
+
/**
|
|
52
|
+
* Stamps a placed block's `variant` (`blocks@2.0`, RFC 0002) onto the
|
|
53
|
+
* element it rendered to, as one `data-variant-<axis>` attribute per axis
|
|
54
|
+
* actually set. A theme's CSS then selects `[data-variant-background="muted"]`
|
|
55
|
+
* and resolves it to its own token, exactly the indirection `theme.tokens.json`
|
|
56
|
+
* already uses for colour — no second place a variant value lives.
|
|
57
|
+
*
|
|
58
|
+
* An axis left unset by the author emits no attribute at all, which is what
|
|
59
|
+
* makes "unset" and "this theme's default" the same thing on the render
|
|
60
|
+
* side: a theme that implements no variant at all needs zero code changes,
|
|
61
|
+
* and one that implements only `background` can ignore the rest safely.
|
|
62
|
+
*
|
|
63
|
+
* Applied once, inside every theme's `renderBlock`, rather than by each of
|
|
64
|
+
* the seventeen block renderers — the same shared-envelope reasoning that
|
|
65
|
+
* put `variant` on `BlockIdentity` instead of on each block's own schema.
|
|
66
|
+
*/
|
|
67
|
+
export declare function withBlockVariant(element: HtmlElement | null, variant: BlockVariant | undefined): HtmlElement | null;
|
|
68
|
+
/**
|
|
69
|
+
* Resolves any placed block — one of the shared vocabulary, or a block a
|
|
70
|
+
* theme ships of its own — to something a theme's `renderBlock` (an
|
|
71
|
+
* exhaustive `switch` over `VocabularyBlock`, deliberately, so a thirteenth
|
|
72
|
+
* shared type still fails to compile until every theme handles it) can
|
|
73
|
+
* actually take.
|
|
74
|
+
*
|
|
75
|
+
* `BlockRegistry.resolveRenderable` already carries the anti-lock-in half of
|
|
76
|
+
* contract B — a theme's private block must name a `fallback`, walked until
|
|
77
|
+
* something the active theme actually implements is reached — but before
|
|
78
|
+
* this function nothing on the render path ever called it: a stored block
|
|
79
|
+
* whose exact type the active theme did not implement rendered as `null`, a
|
|
80
|
+
* silently blank slot rather than the degraded-but-present block the
|
|
81
|
+
* contract promises (fiche 43, sous-chantier C(ii)).
|
|
82
|
+
*
|
|
83
|
+
* `knownNames` is what the caller's own `renderBlock` switch actually
|
|
84
|
+
* handles — `VOCABULARY_NAMES` for every one of the five in-house themes
|
|
85
|
+
* today, since none of them ships a block of its own yet. A theme (or a
|
|
86
|
+
* theme-shipping plugin) that does passes its own, wider list.
|
|
87
|
+
*
|
|
88
|
+
* Only ever widens what a caller can *pass in*, never what contract B's
|
|
89
|
+
* closed vocabulary is: the fallback's own shape is what gets rendered, and
|
|
90
|
+
* only when the stored data actually validates as an instance of it. A
|
|
91
|
+
* private block earns real, undegraded rendering by an active theme that
|
|
92
|
+
* implements it directly; this is the safety net for every other case, not a
|
|
93
|
+
* data-mapping engine — data that does not fit the fallback's shape yields
|
|
94
|
+
* `null` for that one block, never a thrown error that would take the whole
|
|
95
|
+
* page down with it.
|
|
96
|
+
*/
|
|
97
|
+
export declare function resolveBlockForRender(block: VocabularyBlock | UnknownPlacedBlock, knownNames: readonly string[], registry?: BlockRegistry): UnknownPlacedBlock | null;
|
|
98
|
+
/**
|
|
99
|
+
* The `QueryRequest` a `collectionList` block's own fields describe — pure
|
|
100
|
+
* data derived from contract B, never an editorial choice a theme makes, so
|
|
101
|
+
* every theme resolves it identically rather than re-deriving it per layout.
|
|
102
|
+
*/
|
|
103
|
+
export declare function buildCollectionListQuery(block: CollectionListBlock): QueryRequest;
|
|
104
|
+
//# sourceMappingURL=page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EAErB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAE5C,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,CAAA;IAC3C;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAA;CAC/B;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC,CAAA;AAE9E;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAE7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAGzF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,GAAG,IAAI,EAC3B,OAAO,EAAE,YAAY,GAAG,SAAS,GAChC,WAAW,GAAG,IAAI,CASpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,eAAe,GAAG,kBAAkB,EAC3C,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,QAAQ,GAAE,aAAkC,GAC3C,kBAAkB,GAAG,IAAI,CAwB3B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CAQjF"}
|
package/dist/page.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { vocabularyRegistry, } from '@cogenta/blocks';
|
|
2
|
+
/**
|
|
3
|
+
* A page has exactly one `h1`.
|
|
4
|
+
*
|
|
5
|
+
* A `hero` declares `headingLevel: 'h1'` and renders the title itself, so a
|
|
6
|
+
* theme's page layout must not render a second one; without a hero, nothing
|
|
7
|
+
* else on the page would — `prose` starts at `h2` — and the page would have
|
|
8
|
+
* no `h1` at all.
|
|
9
|
+
*/
|
|
10
|
+
export function pageHasOwnHeading(blocks) {
|
|
11
|
+
return blocks.some((block) => block._type === 'hero');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Stamps the block's own `_key` onto the element it rendered to.
|
|
15
|
+
*
|
|
16
|
+
* The key is contract B's identity for a placed block — minted once, surviving
|
|
17
|
+
* reorder, translation and version restore — so it is the one honest way for a
|
|
18
|
+
* *reader* of the finished HTML to say "this piece of the page came from that
|
|
19
|
+
* block". The visual page builder (L16) is such a reader: it shows the real
|
|
20
|
+
* server-rendered page in an iframe and needs to map a clicked element back to
|
|
21
|
+
* the block that produced it. Shared across every theme so that mapping works
|
|
22
|
+
* identically regardless of which theme a site has installed.
|
|
23
|
+
*
|
|
24
|
+
* Emitted on every render, never only in a builder mode — a preview that is
|
|
25
|
+
* assembled differently from the published page is exactly the divergence the
|
|
26
|
+
* builder exists to rule out.
|
|
27
|
+
*/
|
|
28
|
+
export function withBlockKey(element, key) {
|
|
29
|
+
if (element === null)
|
|
30
|
+
return null;
|
|
31
|
+
return { ...element, attrs: { ...element.attrs, 'data-block-key': key } };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Stamps a placed block's `variant` (`blocks@2.0`, RFC 0002) onto the
|
|
35
|
+
* element it rendered to, as one `data-variant-<axis>` attribute per axis
|
|
36
|
+
* actually set. A theme's CSS then selects `[data-variant-background="muted"]`
|
|
37
|
+
* and resolves it to its own token, exactly the indirection `theme.tokens.json`
|
|
38
|
+
* already uses for colour — no second place a variant value lives.
|
|
39
|
+
*
|
|
40
|
+
* An axis left unset by the author emits no attribute at all, which is what
|
|
41
|
+
* makes "unset" and "this theme's default" the same thing on the render
|
|
42
|
+
* side: a theme that implements no variant at all needs zero code changes,
|
|
43
|
+
* and one that implements only `background` can ignore the rest safely.
|
|
44
|
+
*
|
|
45
|
+
* Applied once, inside every theme's `renderBlock`, rather than by each of
|
|
46
|
+
* the seventeen block renderers — the same shared-envelope reasoning that
|
|
47
|
+
* put `variant` on `BlockIdentity` instead of on each block's own schema.
|
|
48
|
+
*/
|
|
49
|
+
export function withBlockVariant(element, variant) {
|
|
50
|
+
if (element === null || variant === undefined)
|
|
51
|
+
return element;
|
|
52
|
+
const attrs = {};
|
|
53
|
+
if (variant.background !== undefined)
|
|
54
|
+
attrs['data-variant-background'] = variant.background;
|
|
55
|
+
if (variant.spacing !== undefined)
|
|
56
|
+
attrs['data-variant-spacing'] = variant.spacing;
|
|
57
|
+
if (variant.align !== undefined)
|
|
58
|
+
attrs['data-variant-align'] = variant.align;
|
|
59
|
+
if (variant.width !== undefined)
|
|
60
|
+
attrs['data-variant-width'] = variant.width;
|
|
61
|
+
if (Object.keys(attrs).length === 0)
|
|
62
|
+
return element;
|
|
63
|
+
return { ...element, attrs: { ...element.attrs, ...attrs } };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Resolves any placed block — one of the shared vocabulary, or a block a
|
|
67
|
+
* theme ships of its own — to something a theme's `renderBlock` (an
|
|
68
|
+
* exhaustive `switch` over `VocabularyBlock`, deliberately, so a thirteenth
|
|
69
|
+
* shared type still fails to compile until every theme handles it) can
|
|
70
|
+
* actually take.
|
|
71
|
+
*
|
|
72
|
+
* `BlockRegistry.resolveRenderable` already carries the anti-lock-in half of
|
|
73
|
+
* contract B — a theme's private block must name a `fallback`, walked until
|
|
74
|
+
* something the active theme actually implements is reached — but before
|
|
75
|
+
* this function nothing on the render path ever called it: a stored block
|
|
76
|
+
* whose exact type the active theme did not implement rendered as `null`, a
|
|
77
|
+
* silently blank slot rather than the degraded-but-present block the
|
|
78
|
+
* contract promises (fiche 43, sous-chantier C(ii)).
|
|
79
|
+
*
|
|
80
|
+
* `knownNames` is what the caller's own `renderBlock` switch actually
|
|
81
|
+
* handles — `VOCABULARY_NAMES` for every one of the five in-house themes
|
|
82
|
+
* today, since none of them ships a block of its own yet. A theme (or a
|
|
83
|
+
* theme-shipping plugin) that does passes its own, wider list.
|
|
84
|
+
*
|
|
85
|
+
* Only ever widens what a caller can *pass in*, never what contract B's
|
|
86
|
+
* closed vocabulary is: the fallback's own shape is what gets rendered, and
|
|
87
|
+
* only when the stored data actually validates as an instance of it. A
|
|
88
|
+
* private block earns real, undegraded rendering by an active theme that
|
|
89
|
+
* implements it directly; this is the safety net for every other case, not a
|
|
90
|
+
* data-mapping engine — data that does not fit the fallback's shape yields
|
|
91
|
+
* `null` for that one block, never a thrown error that would take the whole
|
|
92
|
+
* page down with it.
|
|
93
|
+
*/
|
|
94
|
+
export function resolveBlockForRender(block, knownNames, registry = vocabularyRegistry) {
|
|
95
|
+
if (knownNames.includes(block._type)) {
|
|
96
|
+
// A member of the closed `VocabularyBlock` union does not structurally
|
|
97
|
+
// satisfy `UnknownPlacedBlock`'s index signature (each member is built
|
|
98
|
+
// from a mapped type, which TypeScript never treats as implicitly
|
|
99
|
+
// indexable) — the cast states what is already true at the value level:
|
|
100
|
+
// every field of a placed block is `unknown` to a caller this generic.
|
|
101
|
+
return block;
|
|
102
|
+
}
|
|
103
|
+
let definition;
|
|
104
|
+
try {
|
|
105
|
+
definition = registry.resolveRenderable(block._type, knownNames);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Not registered at all, or its fallback chain loops back on itself —
|
|
109
|
+
// nothing safe to guess. The block is dropped, not the page.
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
if (definition === undefined)
|
|
113
|
+
return null;
|
|
114
|
+
const candidate = { ...block, _type: definition.name };
|
|
115
|
+
const parsed = definition.validator.safeParse(candidate);
|
|
116
|
+
if (!parsed.success)
|
|
117
|
+
return null;
|
|
118
|
+
return parsed.data;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The `QueryRequest` a `collectionList` block's own fields describe — pure
|
|
122
|
+
* data derived from contract B, never an editorial choice a theme makes, so
|
|
123
|
+
* every theme resolves it identically rather than re-deriving it per layout.
|
|
124
|
+
*/
|
|
125
|
+
export function buildCollectionListQuery(block) {
|
|
126
|
+
return {
|
|
127
|
+
collection: block.collection,
|
|
128
|
+
...(block.filter === undefined ? {} : { filter: block.filter }),
|
|
129
|
+
...(block.sort === undefined ? {} : { sort: block.sort }),
|
|
130
|
+
// Capped by contract B at 100; an absent limit still must not mean "all".
|
|
131
|
+
limit: block.limit ?? 10,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=page.js.map
|
package/dist/page.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page.js","sourceRoot":"","sources":["../src/page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RichTextDocument } from '@cogenta/blocks';
|
|
2
|
+
import type { RenderContext } from './contract.js';
|
|
3
|
+
import { type HtmlNode } from './html.js';
|
|
4
|
+
export declare function renderRichText(ctx: RenderContext, document: RichTextDocument): readonly HtmlNode[];
|
|
5
|
+
//# sourceMappingURL=rich-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rich-text.d.ts","sourceRoot":"","sources":["../src/rich-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,gBAAgB,EAAsB,MAAM,iBAAiB,CAAA;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,WAAW,CAAA;AA6HlD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,gBAAgB,GACzB,SAAS,QAAQ,EAAE,CA0CrB"}
|