@prenta/sections-react 0.15.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +1037 -0
  2. package/LICENSE +21 -0
  3. package/README.md +36 -0
  4. package/dist/PrentaForm.d.ts +22 -0
  5. package/dist/PrentaForm.d.ts.map +1 -0
  6. package/dist/PrentaForm.js +203 -0
  7. package/dist/PrentaForm.js.map +1 -0
  8. package/dist/PrentaFormHtml.d.ts +19 -0
  9. package/dist/PrentaFormHtml.d.ts.map +1 -0
  10. package/dist/PrentaFormHtml.js +18 -0
  11. package/dist/PrentaFormHtml.js.map +1 -0
  12. package/dist/Sections.d.ts +40 -0
  13. package/dist/Sections.d.ts.map +1 -0
  14. package/dist/Sections.js +80 -0
  15. package/dist/Sections.js.map +1 -0
  16. package/dist/SiteNav.d.ts +38 -0
  17. package/dist/SiteNav.d.ts.map +1 -0
  18. package/dist/SiteNav.js +38 -0
  19. package/dist/SiteNav.js.map +1 -0
  20. package/dist/attribution.d.ts +31 -0
  21. package/dist/attribution.d.ts.map +1 -0
  22. package/dist/attribution.js +66 -0
  23. package/dist/attribution.js.map +1 -0
  24. package/dist/components/WidgetEmbedSection.d.ts +9 -0
  25. package/dist/components/WidgetEmbedSection.d.ts.map +1 -0
  26. package/dist/components/WidgetEmbedSection.js +113 -0
  27. package/dist/components/WidgetEmbedSection.js.map +1 -0
  28. package/dist/components/defaults.d.ts +34 -0
  29. package/dist/components/defaults.d.ts.map +1 -0
  30. package/dist/components/defaults.js +170 -0
  31. package/dist/components/defaults.js.map +1 -0
  32. package/dist/forms.d.ts +103 -0
  33. package/dist/forms.d.ts.map +1 -0
  34. package/dist/forms.js +217 -0
  35. package/dist/forms.js.map +1 -0
  36. package/dist/image.d.ts +17 -0
  37. package/dist/image.d.ts.map +1 -0
  38. package/dist/image.js +14 -0
  39. package/dist/image.js.map +1 -0
  40. package/dist/index.d.ts +51 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +44 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/lcp.d.ts +30 -0
  45. package/dist/lcp.d.ts.map +1 -0
  46. package/dist/lcp.js +34 -0
  47. package/dist/lcp.js.map +1 -0
  48. package/dist/primitives.d.ts +14 -0
  49. package/dist/primitives.d.ts.map +1 -0
  50. package/dist/primitives.js +18 -0
  51. package/dist/primitives.js.map +1 -0
  52. package/dist/registry.d.ts +40 -0
  53. package/dist/registry.d.ts.map +1 -0
  54. package/dist/registry.js +62 -0
  55. package/dist/registry.js.map +1 -0
  56. package/dist/sizes.d.ts +30 -0
  57. package/dist/sizes.d.ts.map +1 -0
  58. package/dist/sizes.js +34 -0
  59. package/dist/sizes.js.map +1 -0
  60. package/dist/testing.d.ts +95 -0
  61. package/dist/testing.d.ts.map +1 -0
  62. package/dist/testing.js +159 -0
  63. package/dist/testing.js.map +1 -0
  64. package/dist/types.d.ts +130 -0
  65. package/dist/types.d.ts.map +1 -0
  66. package/dist/types.js +2 -0
  67. package/dist/types.js.map +1 -0
  68. package/dist/utils.d.ts +21 -0
  69. package/dist/utils.d.ts.map +1 -0
  70. package/dist/utils.js +65 -0
  71. package/dist/utils.js.map +1 -0
  72. package/dist/webmcp.d.ts +6 -0
  73. package/dist/webmcp.d.ts.map +1 -0
  74. package/dist/webmcp.js +18 -0
  75. package/dist/webmcp.js.map +1 -0
  76. package/package.json +69 -0
package/dist/forms.js ADDED
@@ -0,0 +1,217 @@
1
+ function isObj(v) {
2
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
3
+ }
4
+ /**
5
+ * Coerce a raw JSON value into a {@link PublicForm}, or `null` when it is not a
6
+ * usable form schema. Accepts either the bare form object or the API's
7
+ * `{ data: form }` envelope.
8
+ */
9
+ export function coercePublicForm(raw) {
10
+ const root = isObj(raw) && isObj(raw.data) ? raw.data : raw;
11
+ if (!isObj(root))
12
+ return null;
13
+ if (typeof root.slug !== 'string' || typeof root.submitPath !== 'string')
14
+ return null;
15
+ if (!Array.isArray(root.fields))
16
+ return null;
17
+ const fields = root.fields.filter(isObj).map((f) => ({
18
+ id: typeof f.id === 'string' ? f.id : '',
19
+ key: typeof f.key === 'string' ? f.key : '',
20
+ label: typeof f.label === 'string' ? f.label : '',
21
+ type: typeof f.type === 'string' ? f.type : 'text',
22
+ required: f.required === true,
23
+ placeholder: typeof f.placeholder === 'string' ? f.placeholder : undefined,
24
+ helpText: typeof f.helpText === 'string' ? f.helpText : undefined,
25
+ defaultValue: f.defaultValue,
26
+ options: Array.isArray(f.options)
27
+ ? f.options
28
+ .filter(isObj)
29
+ .map((o) => ({ label: String(o.label ?? o.value ?? ''), value: String(o.value ?? '') }))
30
+ : undefined,
31
+ width: typeof f.width === 'string' ? f.width : undefined,
32
+ sortOrder: typeof f.sortOrder === 'number' ? f.sortOrder : 0,
33
+ }));
34
+ const spam = isObj(root.spam) ? root.spam : {};
35
+ const captcha = isObj(root.captcha) &&
36
+ typeof root.captcha.provider === 'string' &&
37
+ typeof root.captcha.siteKey === 'string'
38
+ ? { provider: root.captcha.provider, siteKey: root.captcha.siteKey }
39
+ : undefined;
40
+ const analytics = coerceAnalytics(root.analytics);
41
+ return {
42
+ id: typeof root.id === 'string' ? root.id : '',
43
+ name: typeof root.name === 'string' ? root.name : '',
44
+ slug: root.slug,
45
+ description: typeof root.description === 'string' ? root.description : undefined,
46
+ fields: fields.filter((f) => f.key),
47
+ submitPath: root.submitPath,
48
+ successMessage: typeof root.successMessage === 'string' ? root.successMessage : undefined,
49
+ redirectUrl: typeof root.redirectUrl === 'string' ? root.redirectUrl : undefined,
50
+ spam: {
51
+ honeypotFieldKey: typeof spam.honeypotFieldKey === 'string' ? spam.honeypotFieldKey : undefined,
52
+ minSubmitSeconds: typeof spam.minSubmitSeconds === 'number' ? spam.minSubmitSeconds : undefined,
53
+ },
54
+ captcha,
55
+ analytics,
56
+ schemaVersionId: typeof root.schemaVersionId === 'string' || root.schemaVersionId === null
57
+ ? root.schemaVersionId
58
+ : undefined,
59
+ webmcp: isObj(root.webmcp) && root.webmcp.enabled === true
60
+ ? {
61
+ enabled: true,
62
+ toolName: String(root.webmcp.toolName ?? ''),
63
+ toolDescription: String(root.webmcp.toolDescription ?? ''),
64
+ autoSubmit: root.webmcp.autoSubmit === true,
65
+ fieldParams: isObj(root.webmcp.fieldParams)
66
+ ? root.webmcp.fieldParams
67
+ : {},
68
+ }
69
+ : undefined,
70
+ };
71
+ }
72
+ /** Coerce the (already server-sanitized) analytics block, if present and enabled. */
73
+ function coerceAnalytics(raw) {
74
+ if (!isObj(raw) || raw.enabled !== true)
75
+ return undefined;
76
+ const out = { enabled: true };
77
+ if (typeof raw.measurementId === 'string')
78
+ out.measurementId = raw.measurementId;
79
+ if (typeof raw.submitEventName === 'string')
80
+ out.submitEventName = raw.submitEventName;
81
+ if (typeof raw.startEventName === 'string')
82
+ out.startEventName = raw.startEventName;
83
+ if (raw.trackAsConversion === true)
84
+ out.trackAsConversion = true;
85
+ if (typeof raw.conversionValue === 'number')
86
+ out.conversionValue = raw.conversionValue;
87
+ if (typeof raw.conversionCurrency === 'string')
88
+ out.conversionCurrency = raw.conversionCurrency;
89
+ if (isObj(raw.customParameters)) {
90
+ const params = {};
91
+ for (const [key, v] of Object.entries(raw.customParameters)) {
92
+ if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
93
+ params[key] = v;
94
+ }
95
+ if (Object.keys(params).length > 0)
96
+ out.customParameters = params;
97
+ }
98
+ return out;
99
+ }
100
+ const DEFAULT_SUBMIT_MESSAGE = 'Thanks — your response was sent.';
101
+ /**
102
+ * Resolve the post-submit behaviour from the API response.
103
+ *
104
+ * The submit endpoint returns `data.confirmation` as an *object*
105
+ * (`{ type, message?, redirectUrl? }` — cms-core's `SubmissionConfirmation`).
106
+ * A legacy string form is tolerated. Falls back to the schema's
107
+ * `redirectUrl` / `successMessage`, then a generic message.
108
+ */
109
+ export function resolveSubmitOutcome(raw, form) {
110
+ const data = isObj(raw) && isObj(raw.data) ? raw.data : undefined;
111
+ const confirmation = data?.confirmation;
112
+ if (isObj(confirmation)) {
113
+ if (confirmation.type === 'redirect' && typeof confirmation.redirectUrl === 'string') {
114
+ return { redirectUrl: confirmation.redirectUrl, message: '' };
115
+ }
116
+ if (typeof confirmation.message === 'string' && confirmation.message.trim()) {
117
+ return { message: confirmation.message };
118
+ }
119
+ }
120
+ if (typeof confirmation === 'string' && confirmation.trim()) {
121
+ return { message: confirmation };
122
+ }
123
+ if (form.redirectUrl)
124
+ return { redirectUrl: form.redirectUrl, message: '' };
125
+ return { message: form.successMessage || DEFAULT_SUBMIT_MESSAGE };
126
+ }
127
+ /** Decide which control a field type maps to. */
128
+ export function fieldControl(type) {
129
+ switch (type) {
130
+ case 'textarea':
131
+ case 'richtext':
132
+ case 'richText':
133
+ return 'textarea';
134
+ case 'select':
135
+ case 'dropdown':
136
+ return 'select';
137
+ case 'checkbox':
138
+ case 'boolean':
139
+ return 'checkbox';
140
+ case 'radio':
141
+ return 'radio';
142
+ default:
143
+ return 'input';
144
+ }
145
+ }
146
+ /** Map a field type to an `<input type="...">` value (control === 'input' only). */
147
+ export function htmlInputType(type) {
148
+ switch (type) {
149
+ case 'email':
150
+ return 'email';
151
+ case 'url':
152
+ return 'url';
153
+ case 'tel':
154
+ case 'phone':
155
+ return 'tel';
156
+ case 'number':
157
+ return 'number';
158
+ case 'date':
159
+ return 'date';
160
+ case 'time':
161
+ return 'time';
162
+ default:
163
+ return 'text';
164
+ }
165
+ }
166
+ /** The initial value map for a form (honeypot excluded — it is a hidden field). */
167
+ export function initialValues(form) {
168
+ const out = {};
169
+ for (const f of form.fields) {
170
+ if (f.defaultValue !== undefined)
171
+ out[f.key] = f.defaultValue;
172
+ else if (fieldControl(f.type) === 'checkbox')
173
+ out[f.key] = false;
174
+ else
175
+ out[f.key] = '';
176
+ }
177
+ return out;
178
+ }
179
+ /** Label of the first required field left empty, or `null` when all are filled. */
180
+ export function firstMissingRequired(form, values) {
181
+ for (const f of form.fields) {
182
+ if (!f.required)
183
+ continue;
184
+ const v = values[f.key];
185
+ const empty = v === undefined ||
186
+ v === null ||
187
+ v === '' ||
188
+ v === false ||
189
+ (Array.isArray(v) && v.length === 0);
190
+ if (empty)
191
+ return f.label || f.key;
192
+ }
193
+ return null;
194
+ }
195
+ /**
196
+ * Build the JSON body for `POST {submitPath}`. The honeypot value is merged
197
+ * into `fields` under its key (it must NOT be a top-level property), matching
198
+ * `parseSubmissionRequest` in cms-core.
199
+ */
200
+ export function buildSubmitBody(args) {
201
+ const fields = { ...args.values };
202
+ if (args.honeypotKey)
203
+ fields[args.honeypotKey] = args.honeypotValue ?? '';
204
+ const body = { fields };
205
+ if (typeof args.elapsedMs === 'number' && Number.isFinite(args.elapsedMs)) {
206
+ body.elapsedMs = args.elapsedMs;
207
+ }
208
+ if (args.pageUrl)
209
+ body.pageUrl = args.pageUrl;
210
+ if (args.captchaToken)
211
+ body.captchaToken = args.captchaToken;
212
+ if (args.attribution && typeof args.attribution === 'object') {
213
+ body.attribution = args.attribution;
214
+ }
215
+ return body;
216
+ }
217
+ //# sourceMappingURL=forms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.js","sourceRoot":"","sources":["../src/forms.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Default image renderer + a thin `<Img>` wrapper the built-in section
3
+ * renderers use. The default emits a plain `<img>` with native lazy-loading and
4
+ * `decoding="async"`, forwarding intrinsic `width`/`height` when the CMS knows
5
+ * them (set by the `/resolve` media enrichment) to reduce layout shift.
6
+ *
7
+ * Consumers swap in an optimized renderer (e.g. `next/image`) via the
8
+ * `renderImage` option on `<Sections>` — this package stays React-only.
9
+ */
10
+ import type { ReactNode } from 'react';
11
+ import type { RenderImage, RenderImageProps, ResolvedRenderOptions } from './types.js';
12
+ export declare const defaultRenderImage: RenderImage;
13
+ /** Render an image through the resolved options' image renderer. */
14
+ export declare function Img({ options, ...props }: RenderImageProps & {
15
+ options: ResolvedRenderOptions;
16
+ }): ReactNode;
17
+ //# sourceMappingURL=image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEtF,eAAO,MAAM,kBAAkB,EAAE,WAyBhC,CAAA;AAED,oEAAoE;AACpE,wBAAgB,GAAG,CAAC,EAClB,OAAO,EACP,GAAG,KAAK,EACT,EAAE,gBAAgB,GAAG;IAAE,OAAO,EAAE,qBAAqB,CAAA;CAAE,GAAG,SAAS,CAEnE"}
package/dist/image.js ADDED
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const defaultRenderImage = ({ src, alt, width, height, className, priority, sizes, }) => {
3
+ return (
4
+ // eslint-disable-next-line @next/next/no-img-element
5
+ _jsx("img", { src: src, alt: alt, width: typeof width === 'number' ? width : undefined, height: typeof height === 'number' ? height : undefined, loading: priority ? 'eager' : 'lazy',
6
+ // The LCP image hints high priority; everything else defers so it never
7
+ // steals bandwidth from the largest contentful paint.
8
+ fetchPriority: priority ? 'high' : undefined, decoding: "async", sizes: sizes, className: className }));
9
+ };
10
+ /** Render an image through the resolved options' image renderer. */
11
+ export function Img({ options, ...props }) {
12
+ return options.renderImage(props);
13
+ }
14
+ //# sourceMappingURL=image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../src/image.tsx"],"names":[],"mappings":";AAYA,MAAM,CAAC,MAAM,kBAAkB,GAAgB,CAAC,EAC9C,GAAG,EACH,GAAG,EACH,KAAK,EACL,MAAM,EACN,SAAS,EACT,QAAQ,EACR,KAAK,GACY,EAAa,EAAE;IAChC,OAAO;IACL,qDAAqD;IACrD,cACE,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EACpD,MAAM,EAAE,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EACvD,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;QACpC,wEAAwE;QACxE,sDAAsD;QACtD,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAC5C,QAAQ,EAAC,OAAO,EAChB,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,GACpB,CACH,CAAA;AACH,CAAC,CAAA;AAED,oEAAoE;AACpE,MAAM,UAAU,GAAG,CAAC,EAClB,OAAO,EACP,GAAG,KAAK,EAC8C;IACtD,OAAO,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;AACnC,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `@prenta/sections-react` — the public renderer for Prenta's
3
+ * canonical page-content contract (ADR 0001): a document's ordered
4
+ * `PageSection[]` (`data.sections`).
5
+ *
6
+ * Quick start (a Next.js Server Component):
7
+ *
8
+ * ```tsx
9
+ * import { Sections } from '@prenta/sections-react'
10
+ *
11
+ * export default async function Page() {
12
+ * const doc = await client.resolve('/about')
13
+ * return <Sections sections={doc?.data?.sections ?? []} />
14
+ * }
15
+ * ```
16
+ *
17
+ * Override a built-in section type for a custom design — either per render:
18
+ *
19
+ * ```tsx
20
+ * <Sections sections={sections} renderers={{ hero: MyHero }} />
21
+ * ```
22
+ *
23
+ * …or globally at app startup:
24
+ *
25
+ * ```ts
26
+ * import { registerSectionRenderer } from '@prenta/sections-react'
27
+ * registerSectionRenderer('hero', MyHero)
28
+ * ```
29
+ */
30
+ export { Sections, PostHeader } from './Sections.js';
31
+ export type { SectionsProps, PostHeaderProps } from './Sections.js';
32
+ export { registerSectionRenderer, registerSectionRenderers, unregisterSectionRenderer, resetSectionRenderers, getSectionRenderer, registeredSectionTypes, DEFAULT_SECTION_RENDERERS, } from './registry.js';
33
+ export { HeroSection, TextSection, FeatureSection, StatsSection, CtaSection, FormSection, ArticleBodySection, QuoteSection, AuthorBioSection, RelatedPostsSection, GallerySection, EmbedSection, } from './components/defaults.js';
34
+ export { WidgetEmbedSection } from './components/WidgetEmbedSection.js';
35
+ export { PrentaForm } from './PrentaForm.js';
36
+ export type { PrentaFormProps } from './PrentaForm.js';
37
+ export { AttributionTracker, attributionConsentAllowed, captureAttributionIfAllowed, } from './attribution.js';
38
+ export { PrentaFormHtml } from './PrentaFormHtml.js';
39
+ export type { PrentaFormHtmlProps } from './PrentaFormHtml.js';
40
+ export { webMcpFormAttributes, webMcpFieldAttribute } from './webmcp.js';
41
+ export { SiteNav } from './SiteNav.js';
42
+ export type { SiteNavProps, SiteNavItem } from './SiteNav.js';
43
+ export { coercePublicForm, fieldControl, htmlInputType, initialValues, firstMissingRequired, buildSubmitBody, } from './forms.js';
44
+ export type { PublicForm, PublicFormField, FieldControl, SubmitBodyArgs } from './forms.js';
45
+ export { Button } from './primitives.js';
46
+ export { defaultRenderImage, Img } from './image.js';
47
+ export { createLcpController } from './lcp.js';
48
+ export type { LcpController } from './lcp.js';
49
+ export { FULL_WIDTH_SIZES, CONTENT_WIDTH_SIZES, FEATURE_SIZES, gallerySizes } from './sizes.js';
50
+ export type { PublicSection, PostContext, RenderOptions, ResolvedRenderOptions, RenderImage, RenderImageProps, SectionRenderer, SectionRendererProps, SectionRendererMap, } from './types.js';
51
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AACpD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAEnE,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,YAAY,GACb,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAE9D,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE7D,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3F,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAC9C,YAAY,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE/F,YAAY,EACV,aAAa,EACb,WAAW,EACX,aAAa,EACb,qBAAqB,EACrB,WAAW,EACX,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * `@prenta/sections-react` — the public renderer for Prenta's
3
+ * canonical page-content contract (ADR 0001): a document's ordered
4
+ * `PageSection[]` (`data.sections`).
5
+ *
6
+ * Quick start (a Next.js Server Component):
7
+ *
8
+ * ```tsx
9
+ * import { Sections } from '@prenta/sections-react'
10
+ *
11
+ * export default async function Page() {
12
+ * const doc = await client.resolve('/about')
13
+ * return <Sections sections={doc?.data?.sections ?? []} />
14
+ * }
15
+ * ```
16
+ *
17
+ * Override a built-in section type for a custom design — either per render:
18
+ *
19
+ * ```tsx
20
+ * <Sections sections={sections} renderers={{ hero: MyHero }} />
21
+ * ```
22
+ *
23
+ * …or globally at app startup:
24
+ *
25
+ * ```ts
26
+ * import { registerSectionRenderer } from '@prenta/sections-react'
27
+ * registerSectionRenderer('hero', MyHero)
28
+ * ```
29
+ */
30
+ export { Sections, PostHeader } from './Sections.js';
31
+ export { registerSectionRenderer, registerSectionRenderers, unregisterSectionRenderer, resetSectionRenderers, getSectionRenderer, registeredSectionTypes, DEFAULT_SECTION_RENDERERS, } from './registry.js';
32
+ export { HeroSection, TextSection, FeatureSection, StatsSection, CtaSection, FormSection, ArticleBodySection, QuoteSection, AuthorBioSection, RelatedPostsSection, GallerySection, EmbedSection, } from './components/defaults.js';
33
+ export { WidgetEmbedSection } from './components/WidgetEmbedSection.js';
34
+ export { PrentaForm } from './PrentaForm.js';
35
+ export { AttributionTracker, attributionConsentAllowed, captureAttributionIfAllowed, } from './attribution.js';
36
+ export { PrentaFormHtml } from './PrentaFormHtml.js';
37
+ export { webMcpFormAttributes, webMcpFieldAttribute } from './webmcp.js';
38
+ export { SiteNav } from './SiteNav.js';
39
+ export { coercePublicForm, fieldControl, htmlInputType, initialValues, firstMissingRequired, buildSubmitBody, } from './forms.js';
40
+ export { Button } from './primitives.js';
41
+ export { defaultRenderImage, Img } from './image.js';
42
+ export { createLcpController } from './lcp.js';
43
+ export { FULL_WIDTH_SIZES, CONTENT_WIDTH_SIZES, FEATURE_SIZES, gallerySizes } from './sizes.js';
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAGpD,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,eAAe,CAAA;AAEtB,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,YAAY,GACb,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG5C,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAGpD,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAEpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
package/dist/lcp.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * LCP (Largest Contentful Paint) coordination for the section renderer.
3
+ *
4
+ * Core Web Vitals best practice: exactly ONE image per page should be eagerly
5
+ * loaded with `fetchpriority="high"` — the Largest Contentful Paint candidate,
6
+ * almost always the first image in the document. Every other image must lazy-
7
+ * load so it never competes with the LCP resource for bandwidth.
8
+ *
9
+ * The renderer can't know which image is "first" without coordinating across
10
+ * independent renderers (`PostHeader` + each section). An {@link LcpController}
11
+ * is a tiny single-claim allocator: the first renderer to call `claim()` wins
12
+ * the page's one priority slot; everyone else gets `false` and lazy-loads.
13
+ *
14
+ * Pass ONE controller to both `PostHeader` and `Sections` (via `options.lcp`)
15
+ * so a post's featured image and its body sections share a single budget. When
16
+ * omitted, each component creates its own — correct for the common case of
17
+ * rendering only one of them.
18
+ */
19
+ export interface LcpController {
20
+ /**
21
+ * Returns `true` exactly once — for the page's single LCP (priority) image —
22
+ * and `false` for every subsequent call. Safe to call during render.
23
+ */
24
+ claim(): boolean;
25
+ /** True once the priority slot has been claimed. */
26
+ readonly claimed: boolean;
27
+ }
28
+ /** Create a fresh single-claim LCP controller (one per rendered page). */
29
+ export declare function createLcpController(): LcpController;
30
+ //# sourceMappingURL=lcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lcp.d.ts","sourceRoot":"","sources":["../src/lcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,KAAK,IAAI,OAAO,CAAA;IAChB,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAC1B;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,IAAI,aAAa,CAYnD"}
package/dist/lcp.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * LCP (Largest Contentful Paint) coordination for the section renderer.
3
+ *
4
+ * Core Web Vitals best practice: exactly ONE image per page should be eagerly
5
+ * loaded with `fetchpriority="high"` — the Largest Contentful Paint candidate,
6
+ * almost always the first image in the document. Every other image must lazy-
7
+ * load so it never competes with the LCP resource for bandwidth.
8
+ *
9
+ * The renderer can't know which image is "first" without coordinating across
10
+ * independent renderers (`PostHeader` + each section). An {@link LcpController}
11
+ * is a tiny single-claim allocator: the first renderer to call `claim()` wins
12
+ * the page's one priority slot; everyone else gets `false` and lazy-loads.
13
+ *
14
+ * Pass ONE controller to both `PostHeader` and `Sections` (via `options.lcp`)
15
+ * so a post's featured image and its body sections share a single budget. When
16
+ * omitted, each component creates its own — correct for the common case of
17
+ * rendering only one of them.
18
+ */
19
+ /** Create a fresh single-claim LCP controller (one per rendered page). */
20
+ export function createLcpController() {
21
+ let claimed = false;
22
+ return {
23
+ claim() {
24
+ if (claimed)
25
+ return false;
26
+ claimed = true;
27
+ return true;
28
+ },
29
+ get claimed() {
30
+ return claimed;
31
+ },
32
+ };
33
+ }
34
+ //# sourceMappingURL=lcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lcp.js","sourceRoot":"","sources":["../src/lcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAYH,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB;IACjC,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,OAAO;QACL,KAAK;YACH,IAAI,OAAO;gBAAE,OAAO,KAAK,CAAA;YACzB,OAAO,GAAG,IAAI,CAAA;YACd,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,OAAO;YACT,OAAO,OAAO,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * A link-styled button used by the hero/feature/cta default renderers.
4
+ * Renders nothing when there is no label, so optional secondary buttons
5
+ * collapse cleanly. Empty hrefs fall back to `#`.
6
+ */
7
+ export declare function Button({ label, href, tone, fieldPath, }: {
8
+ label: string;
9
+ href: string;
10
+ tone?: 'primary' | 'onDark' | 'ghost';
11
+ /** Visual-editing annotation — dotted path from section content root. */
12
+ fieldPath?: string;
13
+ }): ReactNode;
14
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,IAAI,EACJ,IAAgB,EAChB,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;IACrC,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,SAAS,CAeZ"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * A link-styled button used by the hero/feature/cta default renderers.
4
+ * Renders nothing when there is no label, so optional secondary buttons
5
+ * collapse cleanly. Empty hrefs fall back to `#`.
6
+ */
7
+ export function Button({ label, href, tone = 'primary', fieldPath, }) {
8
+ if (!label)
9
+ return null;
10
+ const base = 'inline-flex items-center justify-center rounded-lg px-5 py-2.5 text-sm font-medium transition-colors';
11
+ const toneClass = tone === 'onDark'
12
+ ? 'bg-white text-violet-700 hover:bg-violet-50'
13
+ : tone === 'ghost'
14
+ ? 'border border-zinc-300 text-zinc-700 hover:bg-zinc-50'
15
+ : 'bg-violet-600 text-white hover:bg-violet-700';
16
+ return (_jsx("a", { href: href || '#', className: `${base} ${toneClass}`, "data-cms-field": fieldPath, children: label }));
17
+ }
18
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../src/primitives.tsx"],"names":[],"mappings":";AAEA;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,EACrB,KAAK,EACL,IAAI,EACJ,IAAI,GAAG,SAAS,EAChB,SAAS,GAOV;IACC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,IAAI,GACR,sGAAsG,CAAA;IACxG,MAAM,SAAS,GACb,IAAI,KAAK,QAAQ;QACf,CAAC,CAAC,6CAA6C;QAC/C,CAAC,CAAC,IAAI,KAAK,OAAO;YAChB,CAAC,CAAC,uDAAuD;YACzD,CAAC,CAAC,8CAA8C,CAAA;IACtD,OAAO,CACL,YAAG,IAAI,EAAE,IAAI,IAAI,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,IAAI,SAAS,EAAE,oBAAkB,SAAS,YAC/E,KAAK,GACJ,CACL,CAAA;AACH,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Consumer-controlled section renderer registry (ADR 0001).
3
+ *
4
+ * Resolution precedence when `<Sections>` renders a section:
5
+ * 1. a renderer passed via the `renderers` prop (per-render override)
6
+ * 2. a globally registered renderer (`registerSectionRenderer`)
7
+ * 3. the built-in default renderer
8
+ * 4. the fallback (renders nothing; warns once in development)
9
+ *
10
+ * The global registry is a module-level map intended to be populated ONCE at
11
+ * application start (an import side-effect), mirroring how cms-core's runtime
12
+ * config is set once per process. For per-request or test-scoped overrides,
13
+ * prefer the `renderers` prop, which never mutates global state.
14
+ */
15
+ import { DEFAULT_SECTION_RENDERERS } from './components/defaults.js';
16
+ import type { SectionRenderer, SectionRendererMap } from './types.js';
17
+ /**
18
+ * Register (or replace) the renderer for a section type, application-wide.
19
+ * Call at module top-level during app startup. Returns nothing.
20
+ */
21
+ export declare function registerSectionRenderer(type: string, renderer: SectionRenderer): void;
22
+ /** Register many renderers at once. */
23
+ export declare function registerSectionRenderers(map: SectionRendererMap): void;
24
+ /** Remove a global override (falls back to the built-in default, if any). */
25
+ export declare function unregisterSectionRenderer(type: string): void;
26
+ /** Clear ALL global overrides. Primarily for tests. */
27
+ export declare function resetSectionRenderers(): void;
28
+ /**
29
+ * Resolve the renderer for a section type, honoring (in order) an explicit
30
+ * per-render map, the global overrides, then the built-in defaults. Returns
31
+ * `undefined` for unknown types so the caller can apply its fallback.
32
+ */
33
+ export declare function getSectionRenderer(type: string, perRender?: SectionRendererMap): SectionRenderer | undefined;
34
+ /**
35
+ * The section-type ids that currently have a renderer (defaults + overrides).
36
+ * Used by the registry-drift guard to compare against the cms-core registry.
37
+ */
38
+ export declare function registeredSectionTypes(): string[];
39
+ export { DEFAULT_SECTION_RENDERERS };
40
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAKrE;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,CAQrF;AAED,uCAAuC;AACvC,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAItE;AAED,6EAA6E;AAC7E,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,kBAAkB,GAC7B,eAAe,GAAG,SAAS,CAE7B;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAIjD;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAA"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Consumer-controlled section renderer registry (ADR 0001).
3
+ *
4
+ * Resolution precedence when `<Sections>` renders a section:
5
+ * 1. a renderer passed via the `renderers` prop (per-render override)
6
+ * 2. a globally registered renderer (`registerSectionRenderer`)
7
+ * 3. the built-in default renderer
8
+ * 4. the fallback (renders nothing; warns once in development)
9
+ *
10
+ * The global registry is a module-level map intended to be populated ONCE at
11
+ * application start (an import side-effect), mirroring how cms-core's runtime
12
+ * config is set once per process. For per-request or test-scoped overrides,
13
+ * prefer the `renderers` prop, which never mutates global state.
14
+ */
15
+ import { DEFAULT_SECTION_RENDERERS } from './components/defaults.js';
16
+ /** App-wide overrides registered via {@link registerSectionRenderer}. */
17
+ const overrides = {};
18
+ /**
19
+ * Register (or replace) the renderer for a section type, application-wide.
20
+ * Call at module top-level during app startup. Returns nothing.
21
+ */
22
+ export function registerSectionRenderer(type, renderer) {
23
+ if (!type || typeof type !== 'string') {
24
+ throw new Error('registerSectionRenderer: `type` must be a non-empty string');
25
+ }
26
+ if (typeof renderer !== 'function') {
27
+ throw new Error(`registerSectionRenderer("${type}"): renderer must be a function`);
28
+ }
29
+ overrides[type] = renderer;
30
+ }
31
+ /** Register many renderers at once. */
32
+ export function registerSectionRenderers(map) {
33
+ for (const [type, renderer] of Object.entries(map)) {
34
+ registerSectionRenderer(type, renderer);
35
+ }
36
+ }
37
+ /** Remove a global override (falls back to the built-in default, if any). */
38
+ export function unregisterSectionRenderer(type) {
39
+ delete overrides[type];
40
+ }
41
+ /** Clear ALL global overrides. Primarily for tests. */
42
+ export function resetSectionRenderers() {
43
+ for (const key of Object.keys(overrides))
44
+ delete overrides[key];
45
+ }
46
+ /**
47
+ * Resolve the renderer for a section type, honoring (in order) an explicit
48
+ * per-render map, the global overrides, then the built-in defaults. Returns
49
+ * `undefined` for unknown types so the caller can apply its fallback.
50
+ */
51
+ export function getSectionRenderer(type, perRender) {
52
+ return perRender?.[type] ?? overrides[type] ?? DEFAULT_SECTION_RENDERERS[type];
53
+ }
54
+ /**
55
+ * The section-type ids that currently have a renderer (defaults + overrides).
56
+ * Used by the registry-drift guard to compare against the cms-core registry.
57
+ */
58
+ export function registeredSectionTypes() {
59
+ return Array.from(new Set([...Object.keys(DEFAULT_SECTION_RENDERERS), ...Object.keys(overrides)])).sort();
60
+ }
61
+ export { DEFAULT_SECTION_RENDERERS };
62
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAA;AAGpE,yEAAyE;AACzE,MAAM,SAAS,GAAuB,EAAE,CAAA;AAExC;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,QAAyB;IAC7E,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAA;IAC/E,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,iCAAiC,CAAC,CAAA;IACpF,CAAC;IACD,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAA;AAC5B,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,wBAAwB,CAAC,GAAuB;IAC9D,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,uBAAuB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACzC,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAA;AACxB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,qBAAqB;IACnC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC,GAAG,CAAC,CAAA;AACjE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,SAA8B;IAE9B,OAAO,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,yBAAyB,CAAC,IAAI,CAAC,CAAA;AAChF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,KAAK,CAAC,IAAI,CACf,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAChF,CAAC,IAAI,EAAE,CAAA;AACV,CAAC;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAA"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Responsive `sizes` helpers.
3
+ *
4
+ * The `sizes` attribute tells the browser how wide an image will render at each
5
+ * breakpoint so it can pick the smallest sufficient `srcset` candidate. Getting
6
+ * it wrong (or omitting it) makes mobile silently over-download the desktop-
7
+ * sized image — one of the most common, invisible LCP regressions.
8
+ *
9
+ * These constants/helpers encode the layout each built-in section renders at, so
10
+ * the right `sizes` ships by default without each renderer hand-rolling it.
11
+ */
12
+ /** Full-bleed image (hero, overlay header): one column at every width. */
13
+ export declare const FULL_WIDTH_SIZES = "100vw";
14
+ /**
15
+ * Centered content image capped at a max width (e.g. the standard post header
16
+ * featured image, rendered inside `max-w-4xl` = 896px).
17
+ */
18
+ export declare const CONTENT_WIDTH_SIZES = "(max-width: 896px) 100vw, 896px";
19
+ /**
20
+ * Feature section image: stacks full-width on mobile, ~half the row on `md+`
21
+ * (two-column grid).
22
+ */
23
+ export declare const FEATURE_SIZES = "(max-width: 768px) 100vw, 50vw";
24
+ /**
25
+ * Gallery cell `sizes` for a given column count: full-width on small screens,
26
+ * an even fraction of the viewport at the grid breakpoint. Clamps the column
27
+ * count to a sane range so a bad value can't produce a nonsense hint.
28
+ */
29
+ export declare function gallerySizes(columns: number): string;
30
+ //# sourceMappingURL=sizes.d.ts.map