@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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Actuate Media
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # @prenta/sections-react
2
+
3
+ Public React renderer for [Prenta CMS](https://github.com/actuate-media/prenta)
4
+ page sections — the canonical `PageSection[]` contract — with a
5
+ consumer-controlled renderer registry.
6
+
7
+ ```bash
8
+ npm install @prenta/sections-react
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { SectionList, registerSectionRenderer } from '@prenta/sections-react'
15
+
16
+ // Register renderers for your custom section types (built-ins are included)
17
+ registerSectionRenderer('my-hero', ({ section, ctx, options }) => (
18
+ <MyHero {...(section.content as MyHeroContent)} />
19
+ ))
20
+
21
+ // Render a resolved page
22
+ <SectionList sections={page.sections} ctx={{ siteUrl }} />
23
+ ```
24
+
25
+ The same custom types can be made editable in the admin via
26
+ `defineSectionTypes()` + `sections.types` in `prenta.config.ts`, and rendered
27
+ in the editor canvas via `AdminRoot`'s `sectionRenderers` prop.
28
+
29
+ ## Release notes
30
+
31
+ See [CHANGELOG.md](./CHANGELOG.md) (shipped with the package) or the
32
+ [GitHub releases](https://github.com/actuate-media/prenta/releases).
33
+
34
+ ## License
35
+
36
+ MIT
@@ -0,0 +1,22 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type PublicForm } from './forms.js';
3
+ export interface PrentaFormProps {
4
+ /** Form slug to fetch (ignored when `form` is provided). */
5
+ slug?: string;
6
+ /** A pre-fetched public form schema. Skips the network fetch when set. */
7
+ form?: PublicForm;
8
+ /**
9
+ * Origin of the CMS API, e.g. `https://cms.example.com`. Defaults to `''`
10
+ * (same-origin relative URLs), which is correct for a Next.js app that mounts
11
+ * the Prenta API at `/api/cms`.
12
+ */
13
+ baseUrl?: string;
14
+ /** Optional captcha token, when the form requires one (consumer-supplied). */
15
+ captchaToken?: string;
16
+ /** Extra class names for the form wrapper. */
17
+ className?: string;
18
+ /** Called with the API result after a successful submission. */
19
+ onSubmitted?: (result: unknown) => void;
20
+ }
21
+ export declare function PrentaForm({ slug, form: initialForm, baseUrl, captchaToken, className, onSubmitted, }: PrentaFormProps): ReactNode;
22
+ //# sourceMappingURL=PrentaForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrentaForm.d.ts","sourceRoot":"","sources":["../src/PrentaForm.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAa,SAAS,EAAE,MAAM,OAAO,CAAA;AAIjD,OAAO,EAQL,KAAK,UAAU,EAEhB,MAAM,YAAY,CAAA;AAGnB,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;CACxC;AAOD,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,IAAI,EAAE,WAAW,EACjB,OAAY,EACZ,YAAY,EACZ,SAAS,EACT,WAAW,GACZ,EAAE,eAAe,GAAG,SAAS,CAiP7B"}
@@ -0,0 +1,203 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * `<PrentaForm>` — a drop-in public form renderer for Prenta CMS.
5
+ *
6
+ * Give it a form `slug` and it fetches the published schema from
7
+ * `GET {baseUrl}/api/cms/public/forms/:slug`, renders the fields, and submits
8
+ * to the schema's `submitPath`. Spam protections are wired automatically:
9
+ * - a hidden honeypot field (key from `spam.honeypotFieldKey`),
10
+ * - an `elapsedMs` timer (cheap "too fast" bot signal),
11
+ * - an optional captcha token (pass via `captchaToken` — the consumer owns
12
+ * the provider widget; nothing is auto-loaded).
13
+ *
14
+ * It is a Client Component (it fetches + holds form state). Render it directly,
15
+ * or let the `form` section type render it for you via `@prenta/sections-react`.
16
+ *
17
+ * Pass a pre-fetched `form` schema to skip the network round-trip (useful for
18
+ * SSR/streaming or tests).
19
+ */
20
+ import { useEffect, useMemo, useRef, useState } from 'react';
21
+ import { trackFormError, trackFormStart, trackFormSubmit } from '@prenta/core/forms/analytics';
22
+ import { getAttributionForSubmission } from '@prenta/core/forms/attribution';
23
+ import { captureAttributionIfAllowed } from './attribution.js';
24
+ import { buildSubmitBody, coercePublicForm, fieldControl, firstMissingRequired, htmlInputType, initialValues, resolveSubmitOutcome, } from './forms.js';
25
+ import { webMcpFieldAttribute, webMcpFormAttributes } from './webmcp.js';
26
+ const FIELD_BASE = 'w-full rounded-lg border border-zinc-300 bg-white px-3 py-2 text-sm text-zinc-900 shadow-sm placeholder:text-zinc-400 focus:border-violet-500 focus:ring-2 focus:ring-violet-500/40 focus:outline-none disabled:cursor-not-allowed disabled:opacity-60';
27
+ export function PrentaForm({ slug, form: initialForm, baseUrl = '', captchaToken, className, onSubmitted, }) {
28
+ const [form, setForm] = useState(initialForm ?? null);
29
+ const [status, setStatus] = useState(initialForm ? 'ready' : 'loading');
30
+ const [message, setMessage] = useState('');
31
+ const [values, setValues] = useState(() => initialForm ? initialValues(initialForm) : {});
32
+ const honeypotRef = useRef('');
33
+ const startedAtRef = useRef(null);
34
+ const successRef = useRef(null);
35
+ // GA4 "form_start" must fire once per render of the form, on first interaction.
36
+ const startTrackedRef = useRef(false);
37
+ // Set once the (consent-gated) attribution capture ran, so submit can attach
38
+ // the merged first/last-touch payload without re-checking consent.
39
+ const attributionAllowedRef = useRef(false);
40
+ // Fetch the schema when only a slug is supplied.
41
+ useEffect(() => {
42
+ if (initialForm || !slug)
43
+ return;
44
+ let cancelled = false;
45
+ const controller = new AbortController();
46
+ setStatus('loading');
47
+ fetch(`${baseUrl}/api/cms/public/forms/${encodeURIComponent(slug)}`, {
48
+ headers: { accept: 'application/json' },
49
+ signal: controller.signal,
50
+ })
51
+ .then(async (res) => {
52
+ if (!res.ok)
53
+ throw new Error(`Form not available (${res.status})`);
54
+ return res.json();
55
+ })
56
+ .then((json) => {
57
+ if (cancelled)
58
+ return;
59
+ const parsed = coercePublicForm(json);
60
+ if (!parsed)
61
+ throw new Error('Form schema was malformed');
62
+ setForm(parsed);
63
+ setValues(initialValues(parsed));
64
+ setStatus('ready');
65
+ })
66
+ .catch((err) => {
67
+ if (cancelled || (err instanceof DOMException && err.name === 'AbortError'))
68
+ return;
69
+ setMessage(err instanceof Error ? err.message : 'Failed to load form');
70
+ setStatus('error');
71
+ });
72
+ return () => {
73
+ cancelled = true;
74
+ controller.abort();
75
+ };
76
+ }, [slug, baseUrl, initialForm]);
77
+ // Start the "time to submit" clock once the form is interactive.
78
+ useEffect(() => {
79
+ if (form && startedAtRef.current === null)
80
+ startedAtRef.current = Date.now();
81
+ }, [form]);
82
+ // Record this page view as a marketing attribution touch (UTMs, ad click
83
+ // IDs, referrer). Consent-gated when plugin-consent is installed.
84
+ useEffect(() => {
85
+ let cancelled = false;
86
+ void captureAttributionIfAllowed().then((allowed) => {
87
+ if (!cancelled && allowed)
88
+ attributionAllowedRef.current = true;
89
+ });
90
+ return () => {
91
+ cancelled = true;
92
+ };
93
+ }, []);
94
+ useEffect(() => {
95
+ if (status !== 'success')
96
+ return;
97
+ const el = successRef.current;
98
+ if (!el)
99
+ return;
100
+ el.focus();
101
+ el.scrollIntoView({ block: 'nearest' });
102
+ }, [status, message]);
103
+ const setValue = (key, value) => {
104
+ if (!startTrackedRef.current && form?.analytics?.enabled) {
105
+ startTrackedRef.current = true;
106
+ trackFormStart(form.name, form.id, form.analytics);
107
+ }
108
+ setValues((prev) => ({ ...prev, [key]: value }));
109
+ };
110
+ async function handleSubmit(e) {
111
+ e.preventDefault();
112
+ if (!form || status === 'submitting')
113
+ return;
114
+ const missing = firstMissingRequired(form, values);
115
+ if (missing) {
116
+ setMessage(`Please complete the “${missing}” field.`);
117
+ setStatus('error');
118
+ return;
119
+ }
120
+ setStatus('submitting');
121
+ setMessage('');
122
+ const startedAt = startedAtRef.current;
123
+ const body = buildSubmitBody({
124
+ values,
125
+ honeypotKey: form.spam.honeypotFieldKey,
126
+ honeypotValue: honeypotRef.current,
127
+ elapsedMs: startedAt !== null ? Date.now() - startedAt : null,
128
+ pageUrl: typeof window !== 'undefined' ? window.location.href : null,
129
+ captchaToken: captchaToken ?? null,
130
+ // AttributionData is a closed interface; the wire format is a plain
131
+ // JSON object, so widen it for the body builder.
132
+ attribution: attributionAllowedRef.current
133
+ ? getAttributionForSubmission()
134
+ : null,
135
+ });
136
+ try {
137
+ const res = await fetch(`${baseUrl}${form.submitPath}`, {
138
+ method: 'POST',
139
+ headers: { 'content-type': 'application/json', accept: 'application/json' },
140
+ body: JSON.stringify(body),
141
+ });
142
+ const json = (await res.json().catch(() => null));
143
+ if (!res.ok) {
144
+ throw new Error(json?.error || `Submission failed (${res.status})`);
145
+ }
146
+ onSubmitted?.(json);
147
+ if (form.analytics?.enabled) {
148
+ trackFormSubmit(form.name, form.id, form.analytics);
149
+ }
150
+ const outcome = resolveSubmitOutcome(json, form);
151
+ if (outcome.redirectUrl && typeof window !== 'undefined') {
152
+ window.location.assign(outcome.redirectUrl);
153
+ return;
154
+ }
155
+ setStatus('success');
156
+ setMessage(outcome.message);
157
+ }
158
+ catch (err) {
159
+ const errorMessage = err instanceof Error ? err.message : 'Something went wrong. Please try again.';
160
+ if (form.analytics?.enabled) {
161
+ trackFormError(form.name, form.id, errorMessage, form.analytics);
162
+ }
163
+ setMessage(errorMessage);
164
+ setStatus('error');
165
+ }
166
+ }
167
+ const honeypotKey = form?.spam.honeypotFieldKey;
168
+ const captchaNote = useMemo(() => {
169
+ if (!form?.captcha || form.captcha.provider === 'none')
170
+ return null;
171
+ if (captchaToken)
172
+ return null;
173
+ return `This form is protected by ${form.captcha.provider}. Pass a captcha token to submit.`;
174
+ }, [form?.captcha, captchaToken]);
175
+ if (status === 'loading') {
176
+ return (_jsx("div", { className: className, "aria-busy": "true", children: _jsx("p", { className: "text-sm text-zinc-500", children: "Loading form\u2026" }) }));
177
+ }
178
+ if (!form) {
179
+ return (_jsx("div", { className: className, role: "alert", children: _jsx("p", { className: "text-sm text-red-600", children: message || 'This form is unavailable.' }) }));
180
+ }
181
+ if (status === 'success') {
182
+ return (_jsx("div", { ref: successRef, tabIndex: -1, className: className, role: "status", "aria-live": "polite", children: _jsx("p", { className: "rounded-lg border border-green-200 bg-green-50 px-4 py-3 text-sm text-green-800", children: message }) }));
183
+ }
184
+ const busy = status === 'submitting';
185
+ return (_jsxs("form", { className: `flex flex-col gap-5 ${className ?? ''}`.trim(), onSubmit: handleSubmit, noValidate: true, ...webMcpFormAttributes(form), children: [form.fields.map((field) => (_jsx(Field, { field: field, value: values[field.key], disabled: busy, form: form, onChange: (v) => setValue(field.key, v) }, field.id || field.key))), honeypotKey && (_jsxs("div", { "aria-hidden": "true", className: "pointer-events-none absolute -left-[9999px] h-0 w-0 overflow-hidden", children: [_jsx("label", { htmlFor: `prenta-hp-${honeypotKey}`, children: "Leave this field empty" }), _jsx("input", { id: `prenta-hp-${honeypotKey}`, type: "text", tabIndex: -1, autoComplete: "off", name: honeypotKey, defaultValue: "", onChange: (e) => {
186
+ honeypotRef.current = e.target.value;
187
+ } })] })), captchaNote && _jsx("p", { className: "text-xs text-zinc-500", children: captchaNote }), status === 'error' && message && (_jsx("p", { role: "alert", className: "text-sm text-red-600", children: message })), _jsx("div", { children: _jsx("button", { type: "submit", disabled: busy || !!captchaNote, className: "inline-flex items-center justify-center rounded-lg bg-violet-600 px-5 py-2.5 text-sm font-medium text-white transition-colors hover:bg-violet-700 disabled:cursor-not-allowed disabled:opacity-60", children: busy ? 'Sending…' : 'Submit' }) }), _jsx("span", { className: "sr-only", "aria-live": "polite", children: busy ? 'Submitting your response' : '' })] }));
188
+ }
189
+ function Field({ field, value, disabled, onChange, form, }) {
190
+ const control = fieldControl(field.type);
191
+ const id = `prenta-field-${field.key}`;
192
+ const describedBy = field.helpText ? `${id}-help` : undefined;
193
+ const help = field.helpText ? (_jsx("p", { id: `${id}-help`, className: "text-xs text-zinc-500", children: field.helpText })) : null;
194
+ // Radio + checkbox use a group label rather than a single bound <label>.
195
+ if (control === 'radio') {
196
+ return (_jsxs("fieldset", { className: "flex flex-col gap-2", children: [_jsxs("legend", { className: "text-sm font-medium text-zinc-700", children: [field.label, field.required && _jsx("span", { className: "text-red-500", children: " *" })] }), (field.options ?? []).map((opt) => (_jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-700", children: [_jsx("input", { type: "radio", name: field.key, value: opt.value, checked: value === opt.value, required: field.required, disabled: disabled, onChange: () => onChange(opt.value), className: "h-4 w-4 text-violet-600", ...webMcpFieldAttribute(form, field) }), opt.label] }, opt.value))), help] }));
197
+ }
198
+ if (control === 'checkbox') {
199
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm text-zinc-700", children: [_jsx("input", { id: id, type: "checkbox", checked: value === true, required: field.required, disabled: disabled, "aria-describedby": describedBy, onChange: (e) => onChange(e.target.checked), className: "h-4 w-4 rounded border-zinc-300 text-violet-600", ...webMcpFieldAttribute(form, field) }), field.label, field.required && _jsx("span", { className: "text-red-500", children: " *" })] }), help] }));
200
+ }
201
+ return (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("label", { htmlFor: id, className: "text-sm font-medium text-zinc-700", children: [field.label, field.required && _jsx("span", { className: "text-red-500", children: " *" })] }), control === 'textarea' ? (_jsx("textarea", { id: id, name: field.key, required: field.required, disabled: disabled, placeholder: field.placeholder, "aria-describedby": describedBy, value: typeof value === 'string' ? value : '', onChange: (e) => onChange(e.target.value), rows: 5, className: `${FIELD_BASE} resize-y`, ...webMcpFieldAttribute(form, field) })) : control === 'select' ? (_jsxs("select", { id: id, name: field.key, required: field.required, disabled: disabled, "aria-describedby": describedBy, value: typeof value === 'string' ? value : '', onChange: (e) => onChange(e.target.value), className: FIELD_BASE, ...webMcpFieldAttribute(form, field), children: [_jsx("option", { value: "", children: field.placeholder || 'Select…' }), (field.options ?? []).map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value)))] })) : (_jsx("input", { id: id, name: field.key, type: htmlInputType(field.type), required: field.required, disabled: disabled, placeholder: field.placeholder, "aria-describedby": describedBy, value: typeof value === 'string' || typeof value === 'number' ? String(value) : '', onChange: (e) => onChange(e.target.value), className: FIELD_BASE, ...webMcpFieldAttribute(form, field) })), help] }));
202
+ }
203
+ //# sourceMappingURL=PrentaForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrentaForm.js","sourceRoot":"","sources":["../src/PrentaForm.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE5D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAC9F,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAC5E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,oBAAoB,GAGrB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAuBxE,MAAM,UAAU,GACd,wPAAwP,CAAA;AAE1P,MAAM,UAAU,UAAU,CAAC,EACzB,IAAI,EACJ,IAAI,EAAE,WAAW,EACjB,OAAO,GAAG,EAAE,EACZ,YAAY,EACZ,SAAS,EACT,WAAW,GACK;IAChB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAoB,WAAW,IAAI,IAAI,CAAC,CAAA;IACxE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAS,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC/E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC1C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA0B,GAAG,EAAE,CACjE,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAC9C,CAAA;IACD,MAAM,WAAW,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;IAC9B,MAAM,YAAY,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAA;IAChD,MAAM,UAAU,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC/C,gFAAgF;IAChF,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACrC,6EAA6E;IAC7E,mEAAmE;IACnE,MAAM,qBAAqB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAE3C,iDAAiD;IACjD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,WAAW,IAAI,CAAC,IAAI;YAAE,OAAM;QAChC,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,SAAS,CAAC,SAAS,CAAC,CAAA;QACpB,KAAK,CAAC,GAAG,OAAO,yBAAyB,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE;YACnE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC;aACC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAClB,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;YAClE,OAAO,GAAG,CAAC,IAAI,EAAE,CAAA;QACnB,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACb,IAAI,SAAS;gBAAE,OAAM;YACrB,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAA;YACrC,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;YACzD,OAAO,CAAC,MAAM,CAAC,CAAA;YACf,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAA;YAChC,SAAS,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtB,IAAI,SAAS,IAAI,CAAC,GAAG,YAAY,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;gBAAE,OAAM;YACnF,UAAU,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAA;YACtE,SAAS,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC,CAAC,CAAA;QACJ,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;YAChB,UAAU,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAA;IAEhC,iEAAiE;IACjE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,IAAI,YAAY,CAAC,OAAO,KAAK,IAAI;YAAE,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC9E,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,yEAAyE;IACzE,kEAAkE;IAClE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,KAAK,2BAA2B,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;YAClD,IAAI,CAAC,SAAS,IAAI,OAAO;gBAAE,qBAAqB,CAAC,OAAO,GAAG,IAAI,CAAA;QACjE,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;QAClB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,SAAS;YAAE,OAAM;QAChC,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAA;QAC7B,IAAI,CAAC,EAAE;YAAE,OAAM;QACf,EAAE,CAAC,KAAK,EAAE,CAAA;QACV,EAAE,CAAC,cAAc,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAA;IACzC,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAErB,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,KAAc,EAAQ,EAAE;QACrD,IAAI,CAAC,eAAe,CAAC,OAAO,IAAI,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;YACzD,eAAe,CAAC,OAAO,GAAG,IAAI,CAAA;YAC9B,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;QACpD,CAAC;QACD,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;IAClD,CAAC,CAAA;IAED,KAAK,UAAU,YAAY,CAAC,CAAY;QACtC,CAAC,CAAC,cAAc,EAAE,CAAA;QAClB,IAAI,CAAC,IAAI,IAAI,MAAM,KAAK,YAAY;YAAE,OAAM;QAE5C,MAAM,OAAO,GAAG,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,UAAU,CAAC,wBAAwB,OAAO,UAAU,CAAC,CAAA;YACrD,SAAS,CAAC,OAAO,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QAED,SAAS,CAAC,YAAY,CAAC,CAAA;QACvB,UAAU,CAAC,EAAE,CAAC,CAAA;QACd,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAA;QACtC,MAAM,IAAI,GAAG,eAAe,CAAC;YAC3B,MAAM;YACN,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB;YACvC,aAAa,EAAE,WAAW,CAAC,OAAO;YAClC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI;YAC7D,OAAO,EAAE,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;YACpE,YAAY,EAAE,YAAY,IAAI,IAAI;YAClC,oEAAoE;YACpE,iDAAiD;YACjD,WAAW,EAAE,qBAAqB,CAAC,OAAO;gBACxC,CAAC,CAAE,2BAA2B,EAAyC;gBACvE,CAAC,CAAC,IAAI;SACT,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,EAAE;gBACtD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;gBAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC3B,CAAC,CAAA;YACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAA8B,CAAA;YAC9E,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,IAAI,sBAAsB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;YACrE,CAAC;YACD,WAAW,EAAE,CAAC,IAAI,CAAC,CAAA;YACnB,IAAI,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;gBAC5B,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;YACrD,CAAC;YACD,MAAM,OAAO,GAAG,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YAChD,IAAI,OAAO,CAAC,WAAW,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;gBACzD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;gBAC3C,OAAM;YACR,CAAC;YACD,SAAS,CAAC,SAAS,CAAC,CAAA;YACpB,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC7B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,YAAY,GAChB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yCAAyC,CAAA;YAChF,IAAI,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC;gBAC5B,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,CAAA;YAClE,CAAC;YACD,UAAU,CAAC,YAAY,CAAC,CAAA;YACxB,SAAS,CAAC,OAAO,CAAC,CAAA;QACpB,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAA;IAE/C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM;YAAE,OAAO,IAAI,CAAA;QACnE,IAAI,YAAY;YAAE,OAAO,IAAI,CAAA;QAC7B,OAAO,6BAA6B,IAAI,CAAC,OAAO,CAAC,QAAQ,mCAAmC,CAAA;IAC9F,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAA;IAEjC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CACL,cAAK,SAAS,EAAE,SAAS,eAAY,MAAM,YACzC,YAAG,SAAS,EAAC,uBAAuB,mCAAkB,GAClD,CACP,CAAA;IACH,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CACL,cAAK,SAAS,EAAE,SAAS,EAAE,IAAI,EAAC,OAAO,YACrC,YAAG,SAAS,EAAC,sBAAsB,YAAE,OAAO,IAAI,2BAA2B,GAAK,GAC5E,CACP,CAAA;IACH,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CACL,cAAK,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAC,QAAQ,eAAW,QAAQ,YACxF,YAAG,SAAS,EAAC,iFAAiF,YAC3F,OAAO,GACN,GACA,CACP,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,KAAK,YAAY,CAAA;IAEpC,OAAO,CACL,gBACE,SAAS,EAAE,uBAAuB,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAC1D,QAAQ,EAAE,YAAY,EACtB,UAAU,WACN,oBAAoB,CAAC,IAAI,CAAC,aAE7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC1B,KAAC,KAAK,IAEJ,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EACxB,QAAQ,EAAE,IAAI,EACd,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,IALlC,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG,CAM1B,CACH,CAAC,EAGD,WAAW,IAAI,CACd,8BACc,MAAM,EAClB,SAAS,EAAC,qEAAqE,aAE/E,gBAAO,OAAO,EAAE,aAAa,WAAW,EAAE,uCAAgC,EAC1E,gBACE,EAAE,EAAE,aAAa,WAAW,EAAE,EAC9B,IAAI,EAAC,MAAM,EACX,QAAQ,EAAE,CAAC,CAAC,EACZ,YAAY,EAAC,KAAK,EAClB,IAAI,EAAE,WAAW,EACjB,YAAY,EAAC,EAAE,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;4BACd,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAA;wBACtC,CAAC,GACD,IACE,CACP,EAEA,WAAW,IAAI,YAAG,SAAS,EAAC,uBAAuB,YAAE,WAAW,GAAK,EAErE,MAAM,KAAK,OAAO,IAAI,OAAO,IAAI,CAChC,YAAG,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,sBAAsB,YAC7C,OAAO,GACN,CACL,EAED,wBACE,iBACE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,WAAW,EAC/B,SAAS,EAAC,mMAAmM,YAE5M,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,GACtB,GACL,EAGN,eAAM,SAAS,EAAC,SAAS,eAAW,QAAQ,YACzC,IAAI,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,EAAE,GAClC,IACF,CACR,CAAA;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EACb,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,IAAI,GAOL;IACC,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACxC,MAAM,EAAE,GAAG,gBAAgB,KAAK,CAAC,GAAG,EAAE,CAAA;IACtC,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;IAC7D,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC5B,YAAG,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAC,uBAAuB,YACnD,KAAK,CAAC,QAAQ,GACb,CACL,CAAC,CAAC,CAAC,IAAI,CAAA;IAER,yEAAyE;IACzE,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,CACL,oBAAU,SAAS,EAAC,qBAAqB,aACvC,kBAAQ,SAAS,EAAC,mCAAmC,aAClD,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,QAAQ,IAAI,eAAM,SAAS,EAAC,cAAc,mBAAU,IACpD,EACR,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAClC,iBAAuB,SAAS,EAAC,+CAA+C,aAC9E,gBACE,IAAI,EAAC,OAAO,EACZ,IAAI,EAAE,KAAK,CAAC,GAAG,EACf,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,OAAO,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAC5B,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EACnC,SAAS,EAAC,yBAAyB,KAC/B,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,GACrC,EACD,GAAG,CAAC,KAAK,KAZA,GAAG,CAAC,KAAK,CAab,CACT,CAAC,EACD,IAAI,IACI,CACZ,CAAA;IACH,CAAC;IAED,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,iBAAO,SAAS,EAAC,+CAA+C,aAC9D,gBACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAC,UAAU,EACf,OAAO,EAAE,KAAK,KAAK,IAAI,EACvB,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,QAAQ,EAAE,QAAQ,sBACA,WAAW,EAC7B,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAC3C,SAAS,EAAC,iDAAiD,KACvD,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,GACrC,EACD,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,QAAQ,IAAI,eAAM,SAAS,EAAC,cAAc,mBAAU,IACrD,EACP,IAAI,IACD,CACP,CAAA;IACH,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,qBAAqB,aAClC,iBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAC,mCAAmC,aAC9D,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,QAAQ,IAAI,eAAM,SAAS,EAAC,cAAc,mBAAU,IACrD,EACP,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,CACxB,mBACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,KAAK,CAAC,GAAG,EACf,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,KAAK,CAAC,WAAW,sBACZ,WAAW,EAC7B,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,IAAI,EAAE,CAAC,EACP,SAAS,EAAE,GAAG,UAAU,WAAW,KAC/B,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,GACrC,CACH,CAAC,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CACzB,kBACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,KAAK,CAAC,GAAG,EACf,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,QAAQ,EAAE,QAAQ,sBACA,WAAW,EAC7B,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,SAAS,EAAE,UAAU,KACjB,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,aAErC,iBAAQ,KAAK,EAAC,EAAE,YAAE,KAAK,CAAC,WAAW,IAAI,SAAS,GAAU,EACzD,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAClC,iBAAwB,KAAK,EAAE,GAAG,CAAC,KAAK,YACrC,GAAG,CAAC,KAAK,IADC,GAAG,CAAC,KAAK,CAEb,CACV,CAAC,IACK,CACV,CAAC,CAAC,CAAC,CACF,gBACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,KAAK,CAAC,GAAG,EACf,IAAI,EAAE,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAC/B,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,KAAK,CAAC,WAAW,sBACZ,WAAW,EAC7B,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAClF,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACzC,SAAS,EAAE,UAAU,KACjB,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,GACrC,CACH,EACA,IAAI,IACD,CACP,CAAA;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { PublicForm } from '@prenta/core';
3
+ export interface PrentaFormHtmlProps {
4
+ /** Pre-fetched public form schema from `GET /api/cms/public/forms/:slug`. */
5
+ form: PublicForm;
6
+ /** POST action override (defaults to `form.submitPath`). */
7
+ action?: string;
8
+ className?: string;
9
+ submitLabel?: string;
10
+ pageUrl?: string;
11
+ /** When false, omit WebMCP annotations. */
12
+ webmcp?: boolean;
13
+ }
14
+ /**
15
+ * Zero-JS public form renderer with WebMCP declarative annotations.
16
+ * Server-safe — use in React Server Components, Astro, or any SSR context.
17
+ */
18
+ export declare function PrentaFormHtml({ form, action, className, submitLabel, pageUrl, webmcp, }: PrentaFormHtmlProps): ReactNode;
19
+ //# sourceMappingURL=PrentaFormHtml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrentaFormHtml.d.ts","sourceRoot":"","sources":["../src/PrentaFormHtml.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAE9C,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,IAAI,EAAE,UAAU,CAAA;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,MAAM,EACN,SAAS,EACT,WAAW,EACX,OAAO,EACP,MAAM,GACP,EAAE,mBAAmB,GAAG,SAAS,CAUjC"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { renderPublicFormHtml } from '@prenta/core/forms/public-html';
3
+ /**
4
+ * Zero-JS public form renderer with WebMCP declarative annotations.
5
+ * Server-safe — use in React Server Components, Astro, or any SSR context.
6
+ */
7
+ export function PrentaFormHtml({ form, action, className, submitLabel, pageUrl, webmcp, }) {
8
+ const html = renderPublicFormHtml(form, {
9
+ action,
10
+ className: className ? `prenta-form ${className}`.trim() : 'prenta-form',
11
+ submitLabel,
12
+ pageUrl,
13
+ webmcp,
14
+ renderStartedAt: Date.now(),
15
+ });
16
+ return _jsx("div", { dangerouslySetInnerHTML: { __html: html } });
17
+ }
18
+ //# sourceMappingURL=PrentaFormHtml.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrentaFormHtml.js","sourceRoot":"","sources":["../src/PrentaFormHtml.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAA;AAerE;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,EAC7B,IAAI,EACJ,MAAM,EACN,SAAS,EACT,WAAW,EACX,OAAO,EACP,MAAM,GACc;IACpB,MAAM,IAAI,GAAG,oBAAoB,CAAC,IAAI,EAAE;QACtC,MAAM;QACN,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,eAAe,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,aAAa;QACxE,WAAW;QACX,OAAO;QACP,MAAM;QACN,eAAe,EAAE,IAAI,CAAC,GAAG,EAAE;KAC5B,CAAC,CAAA;IACF,OAAO,cAAK,uBAAuB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAI,CAAA;AAC3D,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `<Sections>` — render a document's canonical `PageSection[]` as a public
3
+ * page body, and `<PostHeader>` — render a post's header from its template
4
+ * config + the post's own field values.
5
+ *
6
+ * SSR-first: both are plain components safe to render in React Server
7
+ * Components. Each section is wrapped in a `<section>` carrying its background,
8
+ * padding, and optional anchor id; the inner content comes from the resolved
9
+ * renderer (see {@link getSectionRenderer}).
10
+ */
11
+ import type { ReactNode } from 'react';
12
+ import { type PostHeaderConfig } from '@prenta/core/page-sections';
13
+ import type { PostContext, PublicSection, RenderOptions, SectionRendererMap } from './types.js';
14
+ export interface SectionsProps {
15
+ /** The document's `data.sections` array. */
16
+ sections: PublicSection[];
17
+ /** Per-request post context (for post-oriented sections). */
18
+ ctx?: PostContext;
19
+ /**
20
+ * Per-render renderer overrides keyed by section type. Highest precedence —
21
+ * beats globally registered renderers and the built-in defaults.
22
+ */
23
+ renderers?: SectionRendererMap;
24
+ /** Rendering options (e.g. an HTML sanitizer). */
25
+ options?: RenderOptions;
26
+ }
27
+ /** Render the visible sections of a document as a public page body. */
28
+ export declare function Sections({ sections, ctx, renderers, options }: SectionsProps): ReactNode;
29
+ export interface PostHeaderProps {
30
+ config: PostHeaderConfig;
31
+ ctx: PostContext;
32
+ /** Rendering options (e.g. a `next/image`-backed image renderer). */
33
+ options?: RenderOptions;
34
+ }
35
+ /**
36
+ * Public post header, driven by the post type's template `header` config
37
+ * (layout + which fields to show) plus the post's own field values.
38
+ */
39
+ export declare function PostHeader({ config, ctx, options }: PostHeaderProps): ReactNode;
40
+ //# sourceMappingURL=Sections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sections.d.ts","sourceRoot":"","sources":["../src/Sections.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAKtF,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACb,aAAa,EAEb,kBAAkB,EACnB,MAAM,YAAY,CAAA;AA6BnB,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,WAAW,CAAA;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAA;IAC9B,kDAAkD;IAClD,OAAO,CAAC,EAAE,aAAa,CAAA;CACxB;AAED,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,aAAa,GAAG,SAAS,CA6BxF;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,gBAAgB,CAAA;IACxB,GAAG,EAAE,WAAW,CAAA;IAChB,qEAAqE;IACrE,OAAO,CAAC,EAAE,aAAa,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,eAAe,GAAG,SAAS,CA2E/E"}
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { computeReadingTime } from '@prenta/core/page-sections';
3
+ import { getSectionRenderer } from './registry.js';
4
+ import { defaultRenderImage } from './image.js';
5
+ import { createLcpController } from './lcp.js';
6
+ import { CONTENT_WIDTH_SIZES, FULL_WIDTH_SIZES } from './sizes.js';
7
+ import { backgroundClass, formatHeaderDate, paddingClass } from './utils.js';
8
+ const identity = (html) => html;
9
+ function resolveOptions(options) {
10
+ return {
11
+ sanitizeHtml: options?.sanitizeHtml ?? identity,
12
+ baseUrl: options?.baseUrl ?? '',
13
+ renderImage: options?.renderImage ?? defaultRenderImage,
14
+ lcp: options?.lcp ?? createLcpController(),
15
+ prefetchedForms: options?.prefetchedForms ?? {},
16
+ };
17
+ }
18
+ /** Dev-only: warn at most once per unknown section type. */
19
+ const warnedTypes = new Set();
20
+ function warnUnknown(type) {
21
+ if (process.env.NODE_ENV === 'production')
22
+ return;
23
+ if (warnedTypes.has(type))
24
+ return;
25
+ warnedTypes.add(type);
26
+ // eslint-disable-next-line no-console
27
+ console.warn(`[@prenta/sections-react] No renderer for section type "${type}". ` +
28
+ 'Register one with registerSectionRenderer() or pass it via the `renderers` prop. ' +
29
+ 'Skipping this section.');
30
+ }
31
+ /** Render the visible sections of a document as a public page body. */
32
+ export function Sections({ sections, ctx, renderers, options }) {
33
+ const resolved = resolveOptions(options);
34
+ const visible = (Array.isArray(sections) ? sections : []).filter((s) => s?.visible !== false);
35
+ return (_jsx(_Fragment, { children: visible.map((section) => {
36
+ const renderer = getSectionRenderer(section.sectionType, renderers);
37
+ if (!renderer) {
38
+ warnUnknown(section.sectionType);
39
+ return null;
40
+ }
41
+ const s = section.settings ?? {};
42
+ const anchorId = typeof s.anchorId === 'string' && s.anchorId ? s.anchorId : undefined;
43
+ const cssClass = typeof s.cssClass === 'string' ? s.cssClass : '';
44
+ return (_jsx("section", { id: anchorId, "data-cms-section-id": section.id, "data-cms-section-type": section.sectionType, className: `${backgroundClass(s)} ${paddingClass(s)} ${cssClass}`.trim(), children: renderer({ section, ctx, options: resolved }) }, section.id));
45
+ }) }));
46
+ }
47
+ /**
48
+ * Public post header, driven by the post type's template `header` config
49
+ * (layout + which fields to show) plus the post's own field values.
50
+ */
51
+ export function PostHeader({ config, ctx, options }) {
52
+ const resolved = resolveOptions(options);
53
+ const title = ctx.title || 'Untitled';
54
+ const date = config.showDate ? formatHeaderDate(ctx.publishDate) : '';
55
+ const overlay = config.layout === 'overlay' && config.showFeaturedImage && !!ctx.featuredImageUrl;
56
+ const centered = config.layout === 'centered';
57
+ const align = centered ? 'mx-auto items-center text-center' : 'text-left';
58
+ const meta = (_jsxs("div", { className: `mt-4 flex flex-wrap gap-x-3 gap-y-1 text-sm ${centered ? 'justify-center' : ''} ${overlay ? 'text-white/80' : 'text-zinc-500'}`, children: [config.showCategory && ctx.category && (_jsx("span", { className: "font-medium text-violet-500", children: ctx.category })), config.showAuthor && ctx.author?.name && _jsx("span", { children: ctx.author.name }), date && _jsx("span", { children: date }), config.showReadingTime && _jsxs("span", { children: [computeReadingTime(ctx.body), " min read"] })] }));
59
+ if (overlay) {
60
+ return (_jsxs("header", { className: "relative", children: [resolved.renderImage({
61
+ src: ctx.featuredImageUrl,
62
+ alt: '',
63
+ width: ctx.featuredImageWidth,
64
+ height: ctx.featuredImageHeight,
65
+ priority: resolved.lcp.claim(),
66
+ sizes: FULL_WIDTH_SIZES,
67
+ className: 'h-[360px] w-full object-cover sm:h-[440px]',
68
+ }), _jsx("div", { className: "absolute inset-0 bg-gradient-to-t from-black/70 to-black/10", "aria-hidden": true }), _jsx("div", { className: "absolute inset-x-0 bottom-0 px-6 pb-10", children: _jsxs("div", { className: `mx-auto flex max-w-3xl flex-col ${align}`, children: [_jsx("h1", { className: "text-3xl font-bold tracking-tight text-white sm:text-5xl", children: title }), config.showExcerpt && ctx.excerpt && (_jsx("p", { className: "mt-3 max-w-2xl text-lg text-white/90", children: ctx.excerpt })), meta] }) })] }));
69
+ }
70
+ return (_jsxs("header", { className: "border-b border-zinc-100 bg-zinc-50 py-16", children: [_jsxs("div", { className: `mx-auto flex max-w-3xl flex-col px-6 ${align}`, children: [_jsx("h1", { className: "text-4xl font-bold tracking-tight text-zinc-900 sm:text-5xl", children: title }), config.showExcerpt && ctx.excerpt && (_jsx("p", { className: `mt-4 max-w-2xl text-lg text-zinc-600 ${centered ? 'mx-auto' : ''}`, children: ctx.excerpt })), meta] }), config.showFeaturedImage && ctx.featuredImageUrl && (_jsx("div", { className: "mx-auto mt-8 max-w-4xl px-6", children: resolved.renderImage({
71
+ src: ctx.featuredImageUrl,
72
+ alt: title,
73
+ width: ctx.featuredImageWidth,
74
+ height: ctx.featuredImageHeight,
75
+ priority: resolved.lcp.claim(),
76
+ sizes: CONTENT_WIDTH_SIZES,
77
+ className: 'aspect-video w-full rounded-xl object-cover shadow-sm',
78
+ }) }))] }));
79
+ }
80
+ //# sourceMappingURL=Sections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sections.js","sourceRoot":"","sources":["../src/Sections.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * A single navigation item. Mirrors `PublicNavItem` returned by the cms-core
4
+ * `/public/navigations/:slug` endpoint — duplicated here so `sections-react`
5
+ * has no runtime dependency on `cms-core`.
6
+ */
7
+ export interface SiteNavItem {
8
+ label: string;
9
+ url: string;
10
+ target?: '_blank' | '_self';
11
+ children?: SiteNavItem[];
12
+ }
13
+ export interface SiteNavProps {
14
+ /** Top-level navigation items (typically `navigation.items`). */
15
+ items: SiteNavItem[];
16
+ /**
17
+ * Accessible label for the `<nav>` landmark. Defaults to `"Primary"`.
18
+ * Set a distinct value when rendering more than one nav (e.g. `"Footer"`).
19
+ */
20
+ ariaLabel?: string;
21
+ /** Extra classes appended to the `<nav>` element. */
22
+ className?: string;
23
+ }
24
+ /**
25
+ * Renders a public navigation menu as an accessible `<nav>` landmark.
26
+ *
27
+ * Presentational and SSR-safe — no client hooks. Submenus use native
28
+ * `<details>` disclosure so they work without JavaScript and remain
29
+ * keyboard-operable. Styling uses neutral Tailwind utilities; consumers can
30
+ * override via `className` or by mapping the menu themselves.
31
+ *
32
+ * ```tsx
33
+ * const nav = await cms.getNavigation('main')
34
+ * {nav && <SiteNav items={nav.items} />}
35
+ * ```
36
+ */
37
+ export declare function SiteNav({ items, ariaLabel, className }: SiteNavProps): ReactNode;
38
+ //# sourceMappingURL=SiteNav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteNav.d.ts","sourceRoot":"","sources":["../src/SiteNav.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC3B,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,iEAAiE;IACjE,KAAK,EAAE,WAAW,EAAE,CAAA;IACpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA8DD;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,EAAE,KAAK,EAAE,SAAqB,EAAE,SAAS,EAAE,EAAE,YAAY,GAAG,SAAS,CAW5F"}
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ function relFor(target) {
3
+ return target === '_blank' ? 'noopener noreferrer' : undefined;
4
+ }
5
+ function NavLink({ item }) {
6
+ return (_jsx("a", { href: item.url || '#', target: item.target, rel: relFor(item.target), className: "rounded-md px-3 py-2 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-100 hover:text-zinc-900", children: item.label }));
7
+ }
8
+ /**
9
+ * Render one top-level item. Items with children become a native
10
+ * `<details>`/`<summary>` disclosure — keyboard-operable and SSR-safe with no
11
+ * client JavaScript. Leaf items render a plain link.
12
+ */
13
+ function TopLevelItem({ item }) {
14
+ const children = item.children ?? [];
15
+ if (children.length === 0) {
16
+ return (_jsx("li", { children: _jsx(NavLink, { item: item }) }));
17
+ }
18
+ return (_jsx("li", { className: "relative", children: _jsxs("details", { className: "group", children: [_jsxs("summary", { className: "flex cursor-pointer list-none items-center gap-1 rounded-md px-3 py-2 text-sm font-medium text-zinc-700 transition-colors hover:bg-zinc-100 hover:text-zinc-900", children: [item.label, _jsx("span", { "aria-hidden": true, className: "text-zinc-400 transition-transform group-open:rotate-180", children: "\u25BE" })] }), _jsx("ul", { className: "mt-1 min-w-48 rounded-lg border border-zinc-200 bg-white p-1 shadow-sm md:absolute md:left-0 md:z-10", children: children.map((child, i) => (_jsx("li", { children: _jsx("a", { href: child.url || '#', target: child.target, rel: relFor(child.target), className: "block rounded-md px-3 py-2 text-sm text-zinc-700 transition-colors hover:bg-zinc-100 hover:text-zinc-900", children: child.label }) }, `${child.url}-${i}`))) })] }) }));
19
+ }
20
+ /**
21
+ * Renders a public navigation menu as an accessible `<nav>` landmark.
22
+ *
23
+ * Presentational and SSR-safe — no client hooks. Submenus use native
24
+ * `<details>` disclosure so they work without JavaScript and remain
25
+ * keyboard-operable. Styling uses neutral Tailwind utilities; consumers can
26
+ * override via `className` or by mapping the menu themselves.
27
+ *
28
+ * ```tsx
29
+ * const nav = await cms.getNavigation('main')
30
+ * {nav && <SiteNav items={nav.items} />}
31
+ * ```
32
+ */
33
+ export function SiteNav({ items, ariaLabel = 'Primary', className }) {
34
+ if (!Array.isArray(items) || items.length === 0)
35
+ return null;
36
+ return (_jsx("nav", { "aria-label": ariaLabel, className: className, children: _jsx("ul", { className: "flex flex-wrap items-center gap-1", children: items.map((item, i) => (_jsx(TopLevelItem, { item: item }, `${item.url}-${i}`))) }) }));
37
+ }
38
+ //# sourceMappingURL=SiteNav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SiteNav.js","sourceRoot":"","sources":["../src/SiteNav.tsx"],"names":[],"mappings":";AA0BA,SAAS,MAAM,CAAC,MAA6B;IAC3C,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAA;AAChE,CAAC;AAED,SAAS,OAAO,CAAC,EAAE,IAAI,EAAyB;IAC9C,OAAO,CACL,YACE,IAAI,EAAE,IAAI,CAAC,GAAG,IAAI,GAAG,EACrB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EACxB,SAAS,EAAC,gHAAgH,YAEzH,IAAI,CAAC,KAAK,GACT,CACL,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,EAAE,IAAI,EAAyB;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAA;IACpC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CACL,uBACE,KAAC,OAAO,IAAC,IAAI,EAAE,IAAI,GAAI,GACpB,CACN,CAAA;IACH,CAAC;IAED,OAAO,CACL,aAAI,SAAS,EAAC,UAAU,YACtB,mBAAS,SAAS,EAAC,OAAO,aACxB,mBAAS,SAAS,EAAC,iKAAiK,aACjL,IAAI,CAAC,KAAK,EACX,oCAAkB,SAAS,EAAC,0DAA0D,uBAE/E,IACC,EACV,aAAI,SAAS,EAAC,sGAAsG,YACjH,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAC1B,uBACE,YACE,IAAI,EAAE,KAAK,CAAC,GAAG,IAAI,GAAG,EACtB,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EACzB,SAAS,EAAC,0GAA0G,YAEnH,KAAK,CAAC,KAAK,GACV,IARG,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,EAAE,CASvB,CACN,CAAC,GACC,IACG,GACP,CACN,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,EAAE,SAAS,EAAgB;IAC/E,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5D,OAAO,CACL,4BAAiB,SAAS,EAAE,SAAS,EAAE,SAAS,YAC9C,aAAI,SAAS,EAAC,mCAAmC,YAC9C,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,KAAC,YAAY,IAA0B,IAAI,EAAE,IAAI,IAA9B,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAgB,CACtD,CAAC,GACC,GACD,CACP,CAAA;AACH,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Whether attribution may be captured under the site's consent state.
3
+ *
4
+ * - Plugin not installed → the site has no consent framework; resolve `true`.
5
+ * - Analytics already granted → resolve `true` immediately.
6
+ * - No decision yet → wait for the visitor's banner choice (the URL's UTM
7
+ * params are still intact at that point, so a late grant loses nothing).
8
+ *
9
+ * The consent plugin is an optional peer, so it is loaded with a dynamic
10
+ * import (documented exception to the no-inline-imports rule — same pattern
11
+ * as `WidgetEmbedSection`): a static import would break sites that don't
12
+ * install it.
13
+ */
14
+ export declare function attributionConsentAllowed(): Promise<boolean>;
15
+ /**
16
+ * Capture the current page as an attribution touch if consent allows.
17
+ * Resolves `true` when capture ran (callers can then attach attribution on
18
+ * submit without re-checking consent).
19
+ */
20
+ export declare function captureAttributionIfAllowed(): Promise<boolean>;
21
+ /**
22
+ * Site-wide attribution tracker. Mount once in the public site layout so
23
+ * UTMs, ad click IDs, and referrers are recorded on the page the visitor
24
+ * *lands* on — not just pages that contain a form. `<PrentaForm>` also
25
+ * captures on mount, so this is optional but improves first-touch fidelity
26
+ * for multi-page journeys (ad → landing page → contact page → submit).
27
+ *
28
+ * Renders nothing.
29
+ */
30
+ export declare function AttributionTracker(): null;
31
+ //# sourceMappingURL=attribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution.d.ts","sourceRoot":"","sources":["../src/attribution.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;GAYG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,OAAO,CAAC,CASlE;AAED;;;;GAIG;AACH,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,OAAO,CAAC,CAMpE;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}