@reblu/site-next 1.8.0 → 1.10.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.
@@ -0,0 +1,172 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { c as ConsentCategoryState, b as ConsentCategory } from './consent-shared-DbdhEXW2.cjs';
4
+ import { AnalyticsScriptsProps } from './analytics.cjs';
5
+
6
+ /**
7
+ * `<ConsentProvider>` / `useConsent()` — the client half of cookie consent
8
+ * (REB-642). See `../consent-shared` for the fail-closed parsing this relies
9
+ * on (imported from there, not `../consent-server`, to keep `node:crypto` out
10
+ * of this client entry), and `docs/architecture/cookie-consent.md` for the
11
+ * full design.
12
+ *
13
+ * `status: 'unknown'` is the DEFAULT-DENIED state and the value every
14
+ * `<ConsentGate>` treats as "not granted" — see `./gate.tsx`. It covers three
15
+ * cases identically, on purpose: no cookie yet, a cookie that failed
16
+ * `parseConsentCookie`, and a cookie recorded under a `policyVersion` that no
17
+ * longer matches (the tenant edited the cookie policy — REB-642's "re-ask when
18
+ * the version changes"). None of the three may ever resolve to granted.
19
+ */
20
+ /** Whether the visitor's choice for the CURRENT policy version is known. */
21
+ type ConsentStatus = 'unknown' | 'resolved';
22
+ interface ConsentContextValue {
23
+ status: ConsentStatus;
24
+ categories: ConsentCategoryState;
25
+ /** True only when `status === 'resolved'` AND the category was explicitly granted. */
26
+ isGranted: (category: ConsentCategory) => boolean;
27
+ /** Grants every category and persists immediately. */
28
+ acceptAll: () => void;
29
+ /** Denies every category and persists immediately — the denial persists across reloads. */
30
+ rejectAll: () => void;
31
+ /** Persists exactly the categories passed — no category is granted implicitly. */
32
+ savePreferences: (categories: ConsentCategoryState) => void;
33
+ preferencesOpen: boolean;
34
+ openPreferences: () => void;
35
+ closePreferences: () => void;
36
+ /**
37
+ * Refocuses whatever element had focus immediately before `openPreferences`
38
+ * was called. The preferences dialog is openable from more than one place
39
+ * (the banner's "Configure" button, `<CookiePreferencesTrigger>` elsewhere
40
+ * in the tree) with no single `<Dialog.Trigger>` for Radix's own
41
+ * focus-restore to key off, so this is tracked explicitly here — the one
42
+ * funnel every opener already goes through.
43
+ */
44
+ restoreLastFocus: () => void;
45
+ }
46
+ interface ConsentProviderProps {
47
+ children: ReactNode;
48
+ /**
49
+ * `cookiePolicyVersion(tenant.cookiePolicy)` from the SITE's analytics
50
+ * config, or `null` when no cookie policy is stored. A stored consent
51
+ * recorded under a DIFFERENT version is treated as unresolved.
52
+ */
53
+ policyVersion: string | null;
54
+ }
55
+ declare function ConsentProvider({ children, policyVersion }: ConsentProviderProps): react_jsx_runtime.JSX.Element;
56
+ /** Throws outside a `<ConsentProvider>` — a silent default would be a silent consent bypass. */
57
+ declare function useConsent(): ConsentContextValue;
58
+
59
+ interface ConsentGateProps {
60
+ category: ConsentCategory;
61
+ children: ReactNode;
62
+ }
63
+ /**
64
+ * `<ConsentGate>` — the allowlist enforced by construction that REB-642's
65
+ * design settles on: a third party is never rendered except through a
66
+ * component that names a consent category, and a denied or UNRESOLVED
67
+ * category renders `null`.
68
+ *
69
+ * The `status !== 'resolved'` branch matters as much as the denied branch: a
70
+ * gate that rendered children while consent is still `'unknown'` would load
71
+ * the third party on every fresh visitor for the split second before their
72
+ * cookie is read, which is exactly the race `docs/architecture/cookie-consent.md`
73
+ * §6.1 designs around by building tags inside a client component instead of
74
+ * passing a server-rendered `<AnalyticsScripts>` through as `children`.
75
+ */
76
+ declare function ConsentGate({ category, children }: ConsentGateProps): react_jsx_runtime.JSX.Element | null;
77
+
78
+ /**
79
+ * `<ConsentedAnalytics>` — the `'analytics'`-gated replacement for rendering
80
+ * `<AnalyticsScripts>` directly in a SITE layout (REB-642 Slice 1).
81
+ *
82
+ * Reuses the REB-617 validation + escaping builders verbatim via
83
+ * `<AnalyticsScripts>` — this component adds NOTHING to the sink-safety
84
+ * argument in `../analytics.tsx`, it only decides WHETHER that already-safe
85
+ * renderer mounts at all. A SITE layout that still imports
86
+ * `@reblu/site-next/analytics` directly bypasses consent entirely, which is
87
+ * exactly what the source-scanning guard (REB-642 Slice 1, demo-site) exists
88
+ * to catch — this component is the mechanism that guard enforces.
89
+ */
90
+ declare function ConsentedAnalytics(props: AnalyticsScriptsProps): react_jsx_runtime.JSX.Element;
91
+
92
+ /**
93
+ * Copy for `<CookieBanner>`. SDK-owned defaults in Spanish (every Reblu SITE
94
+ * renders `<html lang='es'>` today).
95
+ *
96
+ * REB-642 §7.1 recommends tenant-editable copy be limited to a TITLE/BODY
97
+ * override for v1 — the per-category descriptions, the "necessary" copy and
98
+ * every button label stay fixed, because the copy is a compliance surface: a
99
+ * tenant writing "we use cookies — OK" with no reject option is the exact
100
+ * misconfiguration this design exists to prevent. This type is intentionally
101
+ * a `Partial<ConsentBannerTexts>` at the call site (see `CookieBanner`), so a
102
+ * later tenant-configuration slice can override `title`/`description` without
103
+ * touching this component's contract.
104
+ */
105
+ interface ConsentBannerTexts {
106
+ title: string;
107
+ description: string;
108
+ acceptLabel: string;
109
+ rejectLabel: string;
110
+ manageLabel: string;
111
+ policyLinkLabel: string;
112
+ preferencesTitle: string;
113
+ preferencesDescription: string;
114
+ saveLabel: string;
115
+ necessaryLabel: string;
116
+ necessaryDescription: string;
117
+ categoryLabels: Record<ConsentCategory, string>;
118
+ categoryDescriptions: Record<ConsentCategory, string>;
119
+ }
120
+ declare const DEFAULT_CONSENT_BANNER_TEXTS: ConsentBannerTexts;
121
+
122
+ /**
123
+ * `<CookieBanner>` + `<CookiePreferencesTrigger>` — the visible layer of
124
+ * REB-642's consent mechanism.
125
+ *
126
+ * ─────────────────────────────────────────────────────────────────────────────
127
+ * ARCHITECTURE: ONE DIALOG, TWO OPENERS
128
+ * ─────────────────────────────────────────────────────────────────────────────
129
+ *
130
+ * `<CookieBanner>` owns rendering the preferences dialog (mount it ONCE, at
131
+ * the root of the SITE layout — it portals to `<body>` regardless of where it
132
+ * is mounted). `<CookiePreferencesTrigger>` is a small, unstyled-by-default
133
+ * button usable ANYWHERE ELSE in the tree (a footer link, a settings page) that
134
+ * opens the SAME dialog via `useConsent().openPreferences()`. Both read the
135
+ * single `preferencesOpen` boolean the `<ConsentProvider>` owns, so there is
136
+ * never more than one dialog instance and never two focus traps competing.
137
+ *
138
+ * This is what REB-642 calls "permanent withdrawal" — a visitor's route back
139
+ * to their preferences does not depend on the first-layer banner still being
140
+ * on screen; the banner disappears once resolved, the trigger does not.
141
+ *
142
+ * ─────────────────────────────────────────────────────────────────────────────
143
+ * THE THREE-BUTTON RULE (owner decision, not configurable)
144
+ * ─────────────────────────────────────────────────────────────────────────────
145
+ *
146
+ * Reject / Configure / Accept render as three same-variant, same-size buttons
147
+ * in that visual order — no button is styled as more prominent than another.
148
+ * A tenant can override `title`/`description` text (REB-642 §7.1 recommends
149
+ * v1 ship with NO tenant-editable copy at all, but the prop exists so a later
150
+ * slice can add it without touching this component's contract); the buttons,
151
+ * their order, and the category taxonomy are fixed.
152
+ */
153
+ interface CookieBannerProps {
154
+ /** Overrides merged onto `DEFAULT_CONSENT_BANNER_TEXTS`. */
155
+ texts?: Partial<ConsentBannerTexts>;
156
+ /** Where "Política de cookies" links to. */
157
+ policyHref?: string;
158
+ }
159
+ declare function CookieBanner({ texts: textsOverride, policyHref }: CookieBannerProps): react_jsx_runtime.JSX.Element;
160
+ interface CookiePreferencesTriggerProps {
161
+ children?: ReactNode;
162
+ className?: string;
163
+ texts?: Partial<ConsentBannerTexts>;
164
+ }
165
+ /**
166
+ * A persistent "configure cookies" entry point, safe to place anywhere in the
167
+ * tree (typically a footer link) once `<CookieBanner>` is mounted at the root.
168
+ * Opens the same preferences dialog `<CookieBanner>` owns.
169
+ */
170
+ declare function CookiePreferencesTrigger({ children, className, texts: textsOverride, }: CookiePreferencesTriggerProps): react_jsx_runtime.JSX.Element;
171
+
172
+ export { type ConsentBannerTexts, type ConsentContextValue, ConsentGate, type ConsentGateProps, ConsentProvider, type ConsentProviderProps, type ConsentStatus, ConsentedAnalytics, CookieBanner, type CookieBannerProps, CookiePreferencesTrigger, type CookiePreferencesTriggerProps, DEFAULT_CONSENT_BANNER_TEXTS, useConsent };
@@ -0,0 +1,172 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { c as ConsentCategoryState, b as ConsentCategory } from './consent-shared-DbdhEXW2.js';
4
+ import { AnalyticsScriptsProps } from './analytics.js';
5
+
6
+ /**
7
+ * `<ConsentProvider>` / `useConsent()` — the client half of cookie consent
8
+ * (REB-642). See `../consent-shared` for the fail-closed parsing this relies
9
+ * on (imported from there, not `../consent-server`, to keep `node:crypto` out
10
+ * of this client entry), and `docs/architecture/cookie-consent.md` for the
11
+ * full design.
12
+ *
13
+ * `status: 'unknown'` is the DEFAULT-DENIED state and the value every
14
+ * `<ConsentGate>` treats as "not granted" — see `./gate.tsx`. It covers three
15
+ * cases identically, on purpose: no cookie yet, a cookie that failed
16
+ * `parseConsentCookie`, and a cookie recorded under a `policyVersion` that no
17
+ * longer matches (the tenant edited the cookie policy — REB-642's "re-ask when
18
+ * the version changes"). None of the three may ever resolve to granted.
19
+ */
20
+ /** Whether the visitor's choice for the CURRENT policy version is known. */
21
+ type ConsentStatus = 'unknown' | 'resolved';
22
+ interface ConsentContextValue {
23
+ status: ConsentStatus;
24
+ categories: ConsentCategoryState;
25
+ /** True only when `status === 'resolved'` AND the category was explicitly granted. */
26
+ isGranted: (category: ConsentCategory) => boolean;
27
+ /** Grants every category and persists immediately. */
28
+ acceptAll: () => void;
29
+ /** Denies every category and persists immediately — the denial persists across reloads. */
30
+ rejectAll: () => void;
31
+ /** Persists exactly the categories passed — no category is granted implicitly. */
32
+ savePreferences: (categories: ConsentCategoryState) => void;
33
+ preferencesOpen: boolean;
34
+ openPreferences: () => void;
35
+ closePreferences: () => void;
36
+ /**
37
+ * Refocuses whatever element had focus immediately before `openPreferences`
38
+ * was called. The preferences dialog is openable from more than one place
39
+ * (the banner's "Configure" button, `<CookiePreferencesTrigger>` elsewhere
40
+ * in the tree) with no single `<Dialog.Trigger>` for Radix's own
41
+ * focus-restore to key off, so this is tracked explicitly here — the one
42
+ * funnel every opener already goes through.
43
+ */
44
+ restoreLastFocus: () => void;
45
+ }
46
+ interface ConsentProviderProps {
47
+ children: ReactNode;
48
+ /**
49
+ * `cookiePolicyVersion(tenant.cookiePolicy)` from the SITE's analytics
50
+ * config, or `null` when no cookie policy is stored. A stored consent
51
+ * recorded under a DIFFERENT version is treated as unresolved.
52
+ */
53
+ policyVersion: string | null;
54
+ }
55
+ declare function ConsentProvider({ children, policyVersion }: ConsentProviderProps): react_jsx_runtime.JSX.Element;
56
+ /** Throws outside a `<ConsentProvider>` — a silent default would be a silent consent bypass. */
57
+ declare function useConsent(): ConsentContextValue;
58
+
59
+ interface ConsentGateProps {
60
+ category: ConsentCategory;
61
+ children: ReactNode;
62
+ }
63
+ /**
64
+ * `<ConsentGate>` — the allowlist enforced by construction that REB-642's
65
+ * design settles on: a third party is never rendered except through a
66
+ * component that names a consent category, and a denied or UNRESOLVED
67
+ * category renders `null`.
68
+ *
69
+ * The `status !== 'resolved'` branch matters as much as the denied branch: a
70
+ * gate that rendered children while consent is still `'unknown'` would load
71
+ * the third party on every fresh visitor for the split second before their
72
+ * cookie is read, which is exactly the race `docs/architecture/cookie-consent.md`
73
+ * §6.1 designs around by building tags inside a client component instead of
74
+ * passing a server-rendered `<AnalyticsScripts>` through as `children`.
75
+ */
76
+ declare function ConsentGate({ category, children }: ConsentGateProps): react_jsx_runtime.JSX.Element | null;
77
+
78
+ /**
79
+ * `<ConsentedAnalytics>` — the `'analytics'`-gated replacement for rendering
80
+ * `<AnalyticsScripts>` directly in a SITE layout (REB-642 Slice 1).
81
+ *
82
+ * Reuses the REB-617 validation + escaping builders verbatim via
83
+ * `<AnalyticsScripts>` — this component adds NOTHING to the sink-safety
84
+ * argument in `../analytics.tsx`, it only decides WHETHER that already-safe
85
+ * renderer mounts at all. A SITE layout that still imports
86
+ * `@reblu/site-next/analytics` directly bypasses consent entirely, which is
87
+ * exactly what the source-scanning guard (REB-642 Slice 1, demo-site) exists
88
+ * to catch — this component is the mechanism that guard enforces.
89
+ */
90
+ declare function ConsentedAnalytics(props: AnalyticsScriptsProps): react_jsx_runtime.JSX.Element;
91
+
92
+ /**
93
+ * Copy for `<CookieBanner>`. SDK-owned defaults in Spanish (every Reblu SITE
94
+ * renders `<html lang='es'>` today).
95
+ *
96
+ * REB-642 §7.1 recommends tenant-editable copy be limited to a TITLE/BODY
97
+ * override for v1 — the per-category descriptions, the "necessary" copy and
98
+ * every button label stay fixed, because the copy is a compliance surface: a
99
+ * tenant writing "we use cookies — OK" with no reject option is the exact
100
+ * misconfiguration this design exists to prevent. This type is intentionally
101
+ * a `Partial<ConsentBannerTexts>` at the call site (see `CookieBanner`), so a
102
+ * later tenant-configuration slice can override `title`/`description` without
103
+ * touching this component's contract.
104
+ */
105
+ interface ConsentBannerTexts {
106
+ title: string;
107
+ description: string;
108
+ acceptLabel: string;
109
+ rejectLabel: string;
110
+ manageLabel: string;
111
+ policyLinkLabel: string;
112
+ preferencesTitle: string;
113
+ preferencesDescription: string;
114
+ saveLabel: string;
115
+ necessaryLabel: string;
116
+ necessaryDescription: string;
117
+ categoryLabels: Record<ConsentCategory, string>;
118
+ categoryDescriptions: Record<ConsentCategory, string>;
119
+ }
120
+ declare const DEFAULT_CONSENT_BANNER_TEXTS: ConsentBannerTexts;
121
+
122
+ /**
123
+ * `<CookieBanner>` + `<CookiePreferencesTrigger>` — the visible layer of
124
+ * REB-642's consent mechanism.
125
+ *
126
+ * ─────────────────────────────────────────────────────────────────────────────
127
+ * ARCHITECTURE: ONE DIALOG, TWO OPENERS
128
+ * ─────────────────────────────────────────────────────────────────────────────
129
+ *
130
+ * `<CookieBanner>` owns rendering the preferences dialog (mount it ONCE, at
131
+ * the root of the SITE layout — it portals to `<body>` regardless of where it
132
+ * is mounted). `<CookiePreferencesTrigger>` is a small, unstyled-by-default
133
+ * button usable ANYWHERE ELSE in the tree (a footer link, a settings page) that
134
+ * opens the SAME dialog via `useConsent().openPreferences()`. Both read the
135
+ * single `preferencesOpen` boolean the `<ConsentProvider>` owns, so there is
136
+ * never more than one dialog instance and never two focus traps competing.
137
+ *
138
+ * This is what REB-642 calls "permanent withdrawal" — a visitor's route back
139
+ * to their preferences does not depend on the first-layer banner still being
140
+ * on screen; the banner disappears once resolved, the trigger does not.
141
+ *
142
+ * ─────────────────────────────────────────────────────────────────────────────
143
+ * THE THREE-BUTTON RULE (owner decision, not configurable)
144
+ * ─────────────────────────────────────────────────────────────────────────────
145
+ *
146
+ * Reject / Configure / Accept render as three same-variant, same-size buttons
147
+ * in that visual order — no button is styled as more prominent than another.
148
+ * A tenant can override `title`/`description` text (REB-642 §7.1 recommends
149
+ * v1 ship with NO tenant-editable copy at all, but the prop exists so a later
150
+ * slice can add it without touching this component's contract); the buttons,
151
+ * their order, and the category taxonomy are fixed.
152
+ */
153
+ interface CookieBannerProps {
154
+ /** Overrides merged onto `DEFAULT_CONSENT_BANNER_TEXTS`. */
155
+ texts?: Partial<ConsentBannerTexts>;
156
+ /** Where "Política de cookies" links to. */
157
+ policyHref?: string;
158
+ }
159
+ declare function CookieBanner({ texts: textsOverride, policyHref }: CookieBannerProps): react_jsx_runtime.JSX.Element;
160
+ interface CookiePreferencesTriggerProps {
161
+ children?: ReactNode;
162
+ className?: string;
163
+ texts?: Partial<ConsentBannerTexts>;
164
+ }
165
+ /**
166
+ * A persistent "configure cookies" entry point, safe to place anywhere in the
167
+ * tree (typically a footer link) once `<CookieBanner>` is mounted at the root.
168
+ * Opens the same preferences dialog `<CookieBanner>` owns.
169
+ */
170
+ declare function CookiePreferencesTrigger({ children, className, texts: textsOverride, }: CookiePreferencesTriggerProps): react_jsx_runtime.JSX.Element;
171
+
172
+ export { type ConsentBannerTexts, type ConsentContextValue, ConsentGate, type ConsentGateProps, ConsentProvider, type ConsentProviderProps, type ConsentStatus, ConsentedAnalytics, CookieBanner, type CookieBannerProps, CookiePreferencesTrigger, type CookiePreferencesTriggerProps, DEFAULT_CONSENT_BANNER_TEXTS, useConsent };