@peax/consent-banner-react 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -29
- package/dist/index.d.ts +20 -3
- package/dist/index.js +233 -200
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -41,29 +41,32 @@ export function CookieBanner({ initialPreferences, onCommit }: Props) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
return (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
44
|
+
<Banner
|
|
45
|
+
isOpen={open}
|
|
46
|
+
cookiePolicyUrl="/cookies"
|
|
47
|
+
preferencesContent={Object.fromEntries(
|
|
48
|
+
Object.entries(preferences).map(([id, checked]) => [id, { checked }]),
|
|
49
|
+
)}
|
|
50
|
+
onMsg={msg => {
|
|
51
|
+
switch (msg.type) {
|
|
52
|
+
case 'on_accept_all':
|
|
53
|
+
commit({ essential: true, analytics: true, marketing: true })
|
|
54
|
+
break
|
|
55
|
+
case 'on_reject_all':
|
|
56
|
+
commit({ essential: true, analytics: false, marketing: false })
|
|
57
|
+
break
|
|
58
|
+
case 'on_apply_preferences':
|
|
59
|
+
commit(msg.preferences)
|
|
60
|
+
break
|
|
61
|
+
case 'on_open_preferences':
|
|
62
|
+
if (msg.source === 'floating-button') setOpen(true)
|
|
63
|
+
break
|
|
64
|
+
case 'on_close_preferences':
|
|
65
|
+
if (msg.source === 'floating-button') setOpen(false)
|
|
66
|
+
break
|
|
67
|
+
}
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
67
70
|
)
|
|
68
71
|
}
|
|
69
72
|
```
|
|
@@ -73,13 +76,13 @@ export function CookieBanner({ initialPreferences, onCommit }: Props) {
|
|
|
73
76
|
1. Restore saved consent before initializing this wrapper; keep server and client initial props consistent.
|
|
74
77
|
2. Keep optional services blocked until the relevant consent is granted. Save and enforce decisions in `onCommit`, including later revocation.
|
|
75
78
|
3. Adapt the Accept/Reject maps if you change the selected categories or their behavior.
|
|
76
|
-
4. Keep the banner mounted and
|
|
79
|
+
4. Keep the banner mounted and set `isOpen={false}` to dismiss it immediately. The floating cookie button requests a direct opening of preferences through `onMsg`.
|
|
77
80
|
|
|
78
81
|
The banner manages UI and temporary drafts. It does not store consent, load trackers, or depend on `@peax/consent-core`.
|
|
79
82
|
|
|
80
83
|
## Props
|
|
81
84
|
|
|
82
|
-
All `BannerProps` fields are optional
|
|
85
|
+
All `BannerProps` fields are optional, but `floatingButtonPosition` requires `showFloatingButton: true`. **`isOpen` defaults to `false`**, so pass it to display the banner.
|
|
83
86
|
|
|
84
87
|
### Visibility and layout
|
|
85
88
|
|
|
@@ -87,7 +90,9 @@ All `BannerProps` fields are optional. **`isOpen` defaults to `false`**, so pass
|
|
|
87
90
|
| --- | --- | --- |
|
|
88
91
|
| `isOpen` | `false` | Show or hide the banner |
|
|
89
92
|
| `variant` | `'compact'` | `'compact'` or `'stacked'` |
|
|
90
|
-
| `showCustomizePreferences` | `true` | Show the preferences trigger
|
|
93
|
+
| `showCustomizePreferences` | `true` | Show the preferences trigger inside the collapsed banner |
|
|
94
|
+
| `showFloatingButton` | `true` | Show a floating cookie button while the banner is closed; set to `false` to hide it |
|
|
95
|
+
| `floatingButtonPosition` | Inherited | `'left'` or `'right'`; inherits `position`, with center/omitted falling back to right; requires `showFloatingButton: true` |
|
|
91
96
|
| `hasAcceptRejectEqualWeight` | `false` | Give Accept and Reject the same secondary button appearance |
|
|
92
97
|
| `position` | `'right'` | `'left'`, `'center'`, or `'right'` |
|
|
93
98
|
| `slideFrom` | `'bottom'` | Bottom, or the matching side for left/right positioning |
|
|
@@ -122,11 +127,23 @@ All interactions use `onMsg`. The three decision events leave the banner open un
|
|
|
122
127
|
| `on_reject_all` | None | Reject optional categories, save, enforce, and close |
|
|
123
128
|
| `on_apply_preferences` | `preferences: Record<string, boolean>` | Save and enforce the supplied selection, then close |
|
|
124
129
|
| `on_change_preference` | `sectionId`, `checked` | Observe a draft edit; do not treat it as applied consent |
|
|
125
|
-
| `on_open_preferences` |
|
|
126
|
-
| `on_close_preferences` |
|
|
130
|
+
| `on_open_preferences` | `source: 'banner' \| 'floating-button'` | Banner navigation opens internally; floating requests need the application to set `isOpen={true}` |
|
|
131
|
+
| `on_close_preferences` | `source: 'banner' \| 'floating-button'` | Banner navigation returns to the collapsed banner immediately; floating sessions need the application to set `isOpen={false}` |
|
|
127
132
|
|
|
128
133
|
Apply includes every selected section ID, including disabled sections. Closing preferences never grants consent. External closure through `isOpen={false}` resets the draft without emitting `on_close_preferences`.
|
|
129
134
|
|
|
135
|
+
## Floating cookie button
|
|
136
|
+
|
|
137
|
+
The floating cookie button is enabled by default. Set `showFloatingButton={false}` to hide it. It appears when `isOpen` is false and the panel is removed, including on an initially closed banner. It remains hidden while an open banner is waiting for `appearanceDelay`. React does not infer consent status; your application can control whether the button is enabled.
|
|
138
|
+
|
|
139
|
+
`floatingButtonPosition` overrides the banner's placement. Without it, left stays left, right stays right, and center or omitted placement resolves to right. The TypeScript union permits an explicit floating position only with `showFloatingButton: true`.
|
|
140
|
+
|
|
141
|
+
Clicking emits `on_open_preferences` with `source: 'floating-button'`; set `isOpen` to true to open preferences directly beside the button. That session keeps the side captured on activation. Close/Escape emits the matching close request; set `isOpen` to false to discard drafts and return to the button. Until your application accepts either request, visibility stays unchanged. Apply retains its normal save-and-close integration. Disabling the floating button cancels a pending opening without closing an active panel.
|
|
142
|
+
|
|
143
|
+
`showCustomizePreferences` independently controls the collapsed banner's trigger. The floating control uses `customizePreferencesLabel` as its accessible name, with localized fallback for blank labels. Focus returns to the floating button when it was inside the dismissed panel; focus moved elsewhere is respected.
|
|
144
|
+
|
|
145
|
+
The control is 48px square by default and grows with control/icon tokens. It uses `--pxc-radius-xl`: zero makes a square, the standard value rounds the corners, and a full-radius value makes a circle. Existing theme colors, focus styles, spacing, safe-area insets, and `--pxc-z-index` apply.
|
|
146
|
+
|
|
130
147
|
## Preferences
|
|
131
148
|
|
|
132
149
|
Select IDs, then override only the fields you need:
|
|
@@ -170,7 +187,7 @@ In compact mode, actions adapt to their actual label widths:
|
|
|
170
187
|
| Only decisions fit together | Reject + Accept, then Customize preferences |
|
|
171
188
|
| Decisions need separate rows | Accept → Reject → Customize preferences |
|
|
172
189
|
|
|
173
|
-
Both variants support wrapping labels and scrolling on short viewports. Preferences opens the same nonmodal panel, with a scrolling body and fixed header/footer. Close/Escape
|
|
190
|
+
Both variants support wrapping labels and scrolling on short viewports. Preferences opens the same nonmodal panel, with a scrolling body and fixed header/footer. Close/Escape returns banner-opened preferences to the collapsed banner immediately and restores its trigger. Floating-opened preferences request external closure through `isOpen={false}`, restoring the floating trigger when enabled. Neither path has an exit animation; opening retains its existing motion.
|
|
174
191
|
|
|
175
192
|
Keyboard order follows visual order where `reading-flow` is supported; otherwise compact controls retain Accept → Reject → Preferences DOM order. The preferences panel does not trap focus.
|
|
176
193
|
|
package/dist/index.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { NamedExoticComponent } from 'react';
|
|
|
4
4
|
|
|
5
5
|
export declare const Banner: NamedExoticComponent<BannerProps>;
|
|
6
6
|
|
|
7
|
-
export declare type BannerMsg = {
|
|
8
|
-
type: 'on_accept_all' | 'on_reject_all'
|
|
7
|
+
export declare type BannerMsg = PreferencesNavigationMsg | {
|
|
8
|
+
type: 'on_accept_all' | 'on_reject_all';
|
|
9
9
|
} | {
|
|
10
10
|
type: 'on_apply_preferences';
|
|
11
11
|
preferences: Record<string, boolean>;
|
|
@@ -15,7 +15,7 @@ export declare type BannerMsg = {
|
|
|
15
15
|
checked: boolean;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
export declare type BannerProps = Placement & {
|
|
18
|
+
export declare type BannerProps = Placement & FloatingButtonProps & {
|
|
19
19
|
isOpen?: boolean;
|
|
20
20
|
appearanceDelay?: number;
|
|
21
21
|
hasAcceptRejectEqualWeight?: boolean;
|
|
@@ -32,6 +32,16 @@ export declare type BannerProps = Placement & {
|
|
|
32
32
|
onMsg?: (msg: BannerMsg) => void;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
declare type FloatingButtonPosition = 'left' | 'right';
|
|
36
|
+
|
|
37
|
+
declare type FloatingButtonProps = {
|
|
38
|
+
showFloatingButton?: false;
|
|
39
|
+
floatingButtonPosition?: never;
|
|
40
|
+
} | {
|
|
41
|
+
showFloatingButton: true;
|
|
42
|
+
floatingButtonPosition?: FloatingButtonPosition;
|
|
43
|
+
};
|
|
44
|
+
|
|
35
45
|
declare type Placement = {
|
|
36
46
|
position?: 'right';
|
|
37
47
|
slideFrom?: 'bottom' | 'right';
|
|
@@ -43,6 +53,11 @@ declare type Placement = {
|
|
|
43
53
|
slideFrom?: 'bottom';
|
|
44
54
|
};
|
|
45
55
|
|
|
56
|
+
declare type PreferencesNavigationMsg = {
|
|
57
|
+
type: 'on_open_preferences' | 'on_close_preferences';
|
|
58
|
+
source: Source;
|
|
59
|
+
};
|
|
60
|
+
|
|
46
61
|
export declare type PreferencesSection = Readonly<{
|
|
47
62
|
title?: string;
|
|
48
63
|
text?: string;
|
|
@@ -52,4 +67,6 @@ export declare type PreferencesSection = Readonly<{
|
|
|
52
67
|
|
|
53
68
|
export declare type PreferencesSectionId = BuiltInPreferencesSectionId | (string & Record<never, never>);
|
|
54
69
|
|
|
70
|
+
declare type Source = 'banner' | 'floating-button';
|
|
71
|
+
|
|
55
72
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,95 +1,121 @@
|
|
|
1
1
|
import e from "clsx";
|
|
2
2
|
import { getMessages as t, getPreferencesMessages as n, parseMessage as r, resolveLocale as i } from "@peax/consent-banner-locales";
|
|
3
3
|
import { forwardRef as a, memo as o, useCallback as s, useEffect as c, useId as l, useMemo as u, useRef as d, useState as f } from "react";
|
|
4
|
-
import { AnimatePresence as p, LazyMotion as m, domAnimation as h, useIsPresent as g,
|
|
5
|
-
import * as
|
|
6
|
-
import { Fragment as
|
|
7
|
-
import { ScrollArea as S } from "@base-ui/react/scroll-area";
|
|
4
|
+
import { AnimatePresence as p, LazyMotion as m, domAnimation as h, useIsPresent as g, usePresenceData as _, useReducedMotion as v } from "framer-motion";
|
|
5
|
+
import * as y from "framer-motion/m";
|
|
6
|
+
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
8
7
|
import { Button as C } from "@base-ui/react/button";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import { ScrollArea as w } from "@base-ui/react/scroll-area";
|
|
9
|
+
import { Switch as T } from "@base-ui/react/switch";
|
|
10
|
+
//#region src/hooks/usePreferencesView.ts
|
|
11
|
+
function E({ isOpen: e, showFloatingButton: t, showCustomizePreferences: n, floatingPosition: r, onMsg: i }) {
|
|
12
|
+
let [a, o] = f(null), [l, u] = f(!1), p = d(null);
|
|
13
|
+
return c(() => {
|
|
14
|
+
e || o(null), (e || !t) && (p.current = null);
|
|
15
|
+
}, [e, t]), {
|
|
16
|
+
view: a,
|
|
17
|
+
hasPanel: l,
|
|
18
|
+
setHasPanel: u,
|
|
19
|
+
triggerRef: s((e) => {
|
|
20
|
+
if (!e) return;
|
|
21
|
+
let t = p.current;
|
|
22
|
+
p.current = null, t && (document.activeElement === t || document.activeElement === document.body) && e.focus();
|
|
23
|
+
}, []),
|
|
24
|
+
onExitFocus: s(() => (t && (p.current = document.activeElement), t), [t]),
|
|
25
|
+
openPreferences: (e) => {
|
|
26
|
+
o(e === "banner" ? { source: e } : {
|
|
27
|
+
source: e,
|
|
28
|
+
position: r
|
|
29
|
+
}), i?.({
|
|
30
|
+
type: "on_open_preferences",
|
|
31
|
+
source: e
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
closePreferences: () => {
|
|
35
|
+
a && (a.source === "banner" && (p.current = n ? document.activeElement : null, o(null)), i?.({
|
|
36
|
+
type: "on_close_preferences",
|
|
37
|
+
source: a.source
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
};
|
|
14
41
|
}
|
|
15
42
|
//#endregion
|
|
16
43
|
//#region src/components/Container/ContainerWrapper.tsx
|
|
17
|
-
var
|
|
18
|
-
let
|
|
19
|
-
c(() => {
|
|
20
|
-
let e =
|
|
44
|
+
var D = ({ position: t, slideFrom: n, onPresenceChange: r, children: i }) => {
|
|
45
|
+
let a = g(), o = _(), s = v(), l = d(null), u = d(null);
|
|
46
|
+
c(() => (r?.(!0), () => r?.(!1)), [r]), c(() => {
|
|
47
|
+
let e = l.current;
|
|
21
48
|
if (e) {
|
|
22
|
-
if (
|
|
49
|
+
if (a) {
|
|
23
50
|
e.removeAttribute("inert");
|
|
24
51
|
let t = document.activeElement;
|
|
25
|
-
t instanceof HTMLElement && !e.contains(t) && (
|
|
52
|
+
t instanceof HTMLElement && !e.contains(t) && (u.current = t);
|
|
26
53
|
return;
|
|
27
54
|
}
|
|
28
|
-
if (e.contains(document.activeElement)) {
|
|
29
|
-
let e =
|
|
55
|
+
if (e.contains(document.activeElement) && !o?.()) {
|
|
56
|
+
let e = u.current;
|
|
30
57
|
e?.isConnected && e.focus({ preventScroll: !0 });
|
|
31
58
|
}
|
|
32
59
|
e.setAttribute("inert", "");
|
|
33
60
|
}
|
|
34
|
-
}, [
|
|
35
|
-
let
|
|
36
|
-
return /* @__PURE__ */
|
|
37
|
-
ref:
|
|
38
|
-
exit:
|
|
39
|
-
initial:
|
|
61
|
+
}, [a, o]);
|
|
62
|
+
let f = n === t ? n : "bottom", p = { transform: s ? "none" : f === "bottom" ? "translateY(100%)" : `translateX(${f === "left" ? "-100%" : "100%"})` };
|
|
63
|
+
return /* @__PURE__ */ x(y.div, {
|
|
64
|
+
ref: l,
|
|
65
|
+
exit: { transform: "none" },
|
|
66
|
+
initial: p,
|
|
40
67
|
animate: { transform: "none" },
|
|
41
|
-
"aria-hidden": !
|
|
42
|
-
"data-state":
|
|
68
|
+
"aria-hidden": !a || void 0,
|
|
69
|
+
"data-state": a ? "open" : "closing",
|
|
43
70
|
className: e("pxc-wrapper", `pxc-wrapper--${t}`),
|
|
44
71
|
transition: {
|
|
45
|
-
duration: a
|
|
46
|
-
ease:
|
|
72
|
+
duration: a && !s ? .36 : 0,
|
|
73
|
+
ease: [
|
|
47
74
|
.16,
|
|
48
75
|
1,
|
|
49
76
|
.3,
|
|
50
77
|
1
|
|
51
|
-
] : [
|
|
52
|
-
.4,
|
|
53
|
-
0,
|
|
54
|
-
.2,
|
|
55
|
-
1
|
|
56
78
|
]
|
|
57
79
|
},
|
|
58
|
-
children:
|
|
80
|
+
children: i
|
|
59
81
|
});
|
|
60
|
-
},
|
|
61
|
-
let
|
|
82
|
+
}, O = a(function({ isOpen: t = !0, appearanceDelay: n = 0, position: r = "right", slideFrom: i = "bottom", onPresenceChange: a, onExitFocus: o, className: s, children: l, actions: u, ...d }, g) {
|
|
83
|
+
let _ = Number.isFinite(n) ? Math.max(0, n) : 0, [v, y] = f(_ === 0);
|
|
62
84
|
return c(() => {
|
|
63
|
-
if (
|
|
64
|
-
let e = window.setTimeout(() =>
|
|
85
|
+
if (v || !t) return;
|
|
86
|
+
let e = window.setTimeout(() => y(!0), _);
|
|
65
87
|
return () => window.clearTimeout(e);
|
|
66
88
|
}, [
|
|
67
|
-
|
|
89
|
+
_,
|
|
68
90
|
t,
|
|
69
|
-
|
|
70
|
-
]), /* @__PURE__ */
|
|
91
|
+
v
|
|
92
|
+
]), /* @__PURE__ */ x(m, {
|
|
71
93
|
features: h,
|
|
72
94
|
strict: !0,
|
|
73
|
-
children: /* @__PURE__ */
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
className: "pxc-
|
|
82
|
-
|
|
83
|
-
children:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
children: /* @__PURE__ */ x(p, {
|
|
96
|
+
custom: o,
|
|
97
|
+
children: t && v && /* @__PURE__ */ x(D, {
|
|
98
|
+
position: r,
|
|
99
|
+
slideFrom: i,
|
|
100
|
+
onPresenceChange: a,
|
|
101
|
+
children: /* @__PURE__ */ x("div", {
|
|
102
|
+
ref: g,
|
|
103
|
+
className: e("pxc-container", u != null && "pxc-container--with-actions", s),
|
|
104
|
+
...d,
|
|
105
|
+
children: u == null ? l : /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x("div", {
|
|
106
|
+
className: "pxc-container__content",
|
|
107
|
+
"data-container-content": !0,
|
|
108
|
+
children: l
|
|
109
|
+
}), /* @__PURE__ */ x("div", {
|
|
110
|
+
className: "pxc-container__actions",
|
|
111
|
+
"data-container-actions": !0,
|
|
112
|
+
children: u
|
|
113
|
+
})] })
|
|
114
|
+
})
|
|
115
|
+
}, "container")
|
|
116
|
+
})
|
|
91
117
|
});
|
|
92
|
-
}),
|
|
118
|
+
}), k = () => /* @__PURE__ */ S("svg", {
|
|
93
119
|
width: "24",
|
|
94
120
|
height: "24",
|
|
95
121
|
viewBox: "0 0 24 24",
|
|
@@ -102,14 +128,14 @@ var E = ({ position: t, slideFrom: n, children: r }) => {
|
|
|
102
128
|
"aria-hidden": "true",
|
|
103
129
|
focusable: "false",
|
|
104
130
|
children: [
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
/* @__PURE__ */
|
|
108
|
-
/* @__PURE__ */
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ x("path", { d: "M11 17H11.01" }),
|
|
132
|
+
/* @__PURE__ */ x("path", { d: "M12.025 2.61499C12.054 2.29199 11.82 1.98399 11.496 1.99999C9.02138 2.12561 6.68155 3.16546 4.92997 4.91799C3.0533 6.79479 1.99905 9.34023 1.99915 11.9943C1.99924 14.6484 3.05367 17.1938 4.93047 19.0705C6.80728 20.9472 9.35272 22.0014 12.0068 22.0013C14.6609 22.0012 17.2063 20.9468 19.083 19.07C20.8344 17.3179 21.8732 14.9782 21.998 12.504C22.014 12.181 21.707 11.947 21.384 11.977C20.8082 12.0311 20.2276 11.9597 19.6821 11.7677C19.1366 11.5757 18.6392 11.2678 18.2242 10.865C17.8092 10.4623 17.4864 9.97436 17.2782 9.43485C17.07 8.89535 16.9812 8.31711 17.018 7.73999C17.0244 7.63881 17.0093 7.53742 16.9734 7.44257C16.9376 7.34773 16.882 7.26161 16.8103 7.18997C16.7385 7.11833 16.6523 7.06281 16.5574 7.02712C16.4626 6.99143 16.3611 6.97638 16.26 6.98299C15.6828 7.01952 15.1046 6.93048 14.5652 6.72199C14.0258 6.51351 13.538 6.19054 13.1355 5.77535C12.7329 5.36015 12.4252 4.86261 12.2335 4.31701C12.0417 3.77141 11.9706 3.19073 12.025 2.61499Z" }),
|
|
133
|
+
/* @__PURE__ */ x("path", { d: "M12 12H12.01" }),
|
|
134
|
+
/* @__PURE__ */ x("path", { d: "M16 16H16.01" }),
|
|
135
|
+
/* @__PURE__ */ x("path", { d: "M7 14H7.01" }),
|
|
136
|
+
/* @__PURE__ */ x("path", { d: "M9 8H9.01" })
|
|
111
137
|
]
|
|
112
|
-
}),
|
|
138
|
+
}), A = () => /* @__PURE__ */ S("svg", {
|
|
113
139
|
xmlns: "http://www.w3.org/2000/svg",
|
|
114
140
|
width: "24",
|
|
115
141
|
height: "24",
|
|
@@ -122,23 +148,40 @@ var E = ({ position: t, slideFrom: n, children: r }) => {
|
|
|
122
148
|
"aria-hidden": "true",
|
|
123
149
|
focusable: "false",
|
|
124
150
|
children: [
|
|
125
|
-
/* @__PURE__ */
|
|
126
|
-
/* @__PURE__ */
|
|
127
|
-
/* @__PURE__ */
|
|
151
|
+
/* @__PURE__ */ x("path", { d: "M14 17H5" }),
|
|
152
|
+
/* @__PURE__ */ x("path", { d: "M19 7h-9" }),
|
|
153
|
+
/* @__PURE__ */ x("circle", {
|
|
128
154
|
cx: "17",
|
|
129
155
|
cy: "17",
|
|
130
156
|
r: "3"
|
|
131
157
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
158
|
+
/* @__PURE__ */ x("circle", {
|
|
133
159
|
cx: "7",
|
|
134
160
|
cy: "7",
|
|
135
161
|
r: "3"
|
|
136
162
|
})
|
|
137
163
|
]
|
|
138
|
-
}),
|
|
164
|
+
}), j = a(function({ variant: t, className: n, children: r, ...i }, a) {
|
|
165
|
+
return /* @__PURE__ */ x(C, {
|
|
166
|
+
ref: a,
|
|
167
|
+
className: (r) => e("pxc-button", `pxc-button--${t}`, typeof n == "function" ? n(r) : n),
|
|
168
|
+
...i,
|
|
169
|
+
focusableWhenDisabled: !1,
|
|
170
|
+
children: r
|
|
171
|
+
});
|
|
172
|
+
}), M = a(function({ label: e, position: t, onMsg: n }, r) {
|
|
173
|
+
return /* @__PURE__ */ x(j, {
|
|
174
|
+
ref: r,
|
|
175
|
+
variant: "iconed",
|
|
176
|
+
className: `pxc-floating-button pxc-floating-button--${t}`,
|
|
177
|
+
"aria-label": e,
|
|
178
|
+
onClick: () => n({ type: "on_open_preferences" }),
|
|
179
|
+
children: /* @__PURE__ */ x(k, {})
|
|
180
|
+
});
|
|
181
|
+
}), N = () => /* @__PURE__ */ x("div", {
|
|
139
182
|
className: "pxc-lead-icon",
|
|
140
|
-
children: /* @__PURE__ */
|
|
141
|
-
}),
|
|
183
|
+
children: /* @__PURE__ */ x(k, {})
|
|
184
|
+
}), P = () => /* @__PURE__ */ x("svg", {
|
|
142
185
|
viewBox: "0 0 24 24",
|
|
143
186
|
fill: "none",
|
|
144
187
|
stroke: "currentColor",
|
|
@@ -146,42 +189,43 @@ var E = ({ position: t, slideFrom: n, children: r }) => {
|
|
|
146
189
|
strokeLinecap: "round",
|
|
147
190
|
"aria-hidden": "true",
|
|
148
191
|
focusable: "false",
|
|
149
|
-
children: /* @__PURE__ */
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
children: /* @__PURE__ */ x("path", { d: "m6 6 12 12M6 18 18 6" })
|
|
193
|
+
});
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/utils/notReachable.ts
|
|
196
|
+
function F(e, t = { throwError: !0 }) {
|
|
197
|
+
let n = `Should not be reached ${e}`;
|
|
198
|
+
if (t.throwError) throw Error(n);
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
//#region src/components/Text/RichText.tsx
|
|
202
|
+
var I = (e) => {
|
|
159
203
|
if (e?.trim()) try {
|
|
160
204
|
let t = new URL(e, "https://consent.invalid");
|
|
161
205
|
return t.protocol === "http:" || t.protocol === "https:" ? e : void 0;
|
|
162
206
|
} catch {
|
|
163
207
|
return;
|
|
164
208
|
}
|
|
165
|
-
},
|
|
209
|
+
}, L = ({ message: e, links: t }) => u(() => r(e, Object.keys(t)), [e, t]).map((e) => {
|
|
166
210
|
if (e.type === "text") return e.value;
|
|
167
|
-
let n =
|
|
168
|
-
return n && e.value.trim() ? /* @__PURE__ */
|
|
211
|
+
let n = I(t[e.name]);
|
|
212
|
+
return n && e.value.trim() ? /* @__PURE__ */ x("a", {
|
|
169
213
|
className: "pxc-link",
|
|
170
214
|
href: n,
|
|
171
215
|
children: e.value
|
|
172
216
|
}, e.offset) : e.value;
|
|
173
|
-
}),
|
|
217
|
+
}), R = ({ section: e, checked: t, links: n, onMsg: r }) => {
|
|
174
218
|
let i = l();
|
|
175
|
-
return /* @__PURE__ */
|
|
219
|
+
return /* @__PURE__ */ S("section", {
|
|
176
220
|
className: "pxc-preferences__section",
|
|
177
221
|
"aria-labelledby": `${i}-title`,
|
|
178
|
-
children: [/* @__PURE__ */
|
|
222
|
+
children: [/* @__PURE__ */ S("div", {
|
|
179
223
|
className: "pxc-preferences__section-heading",
|
|
180
|
-
children: [/* @__PURE__ */
|
|
224
|
+
children: [/* @__PURE__ */ x("h4", {
|
|
181
225
|
id: `${i}-title`,
|
|
182
226
|
className: "pxc-text--h4",
|
|
183
227
|
children: e.title
|
|
184
|
-
}), /* @__PURE__ */
|
|
228
|
+
}), /* @__PURE__ */ x(T.Root, {
|
|
185
229
|
className: "pxc-switch",
|
|
186
230
|
checked: t,
|
|
187
231
|
disabled: e.disabled ?? !1,
|
|
@@ -192,60 +236,60 @@ var E = ({ position: t, slideFrom: n, children: r }) => {
|
|
|
192
236
|
sectionId: e.id,
|
|
193
237
|
checked: t
|
|
194
238
|
}),
|
|
195
|
-
children: /* @__PURE__ */
|
|
239
|
+
children: /* @__PURE__ */ x(T.Thumb, { className: "pxc-switch__thumb" })
|
|
196
240
|
})]
|
|
197
|
-
}), e.text && /* @__PURE__ */
|
|
241
|
+
}), e.text && /* @__PURE__ */ x("p", {
|
|
198
242
|
id: `${i}-text`,
|
|
199
243
|
className: "pxc-text--paragraph pxc-preferences__description",
|
|
200
|
-
children: /* @__PURE__ */
|
|
244
|
+
children: /* @__PURE__ */ x(L, {
|
|
201
245
|
message: e.text,
|
|
202
246
|
links: n
|
|
203
247
|
})
|
|
204
248
|
})]
|
|
205
249
|
});
|
|
206
|
-
},
|
|
250
|
+
}, z = ({ sections: e, content: t, links: n, onMsg: r }) => {
|
|
207
251
|
let i = l(), a = d(null), [o, s] = f(() => new Map(e.map((e) => [e.id, e.checked]))), u = new Map(e.map((e) => [e.id, e.disabled ? e.checked : o.get(e.id) ?? e.checked]));
|
|
208
252
|
(o.size !== u.size || [...u].some(([e, t]) => o.get(e) !== t)) && s(u), c(() => {
|
|
209
253
|
a.current?.focus({ preventScroll: !0 });
|
|
210
254
|
}, []);
|
|
211
|
-
let p =
|
|
212
|
-
return /* @__PURE__ */
|
|
255
|
+
let p = I(n.cookiePolicy);
|
|
256
|
+
return /* @__PURE__ */ S("section", {
|
|
213
257
|
className: "pxc-preferences",
|
|
214
258
|
"aria-labelledby": i,
|
|
215
259
|
onKeyDown: (e) => {
|
|
216
260
|
e.key === "Escape" && (e.preventDefault(), e.stopPropagation(), r({ type: "on_close_preferences" }));
|
|
217
261
|
},
|
|
218
262
|
children: [
|
|
219
|
-
/* @__PURE__ */
|
|
263
|
+
/* @__PURE__ */ S("header", {
|
|
220
264
|
className: "pxc-preferences__header",
|
|
221
|
-
children: [/* @__PURE__ */
|
|
265
|
+
children: [/* @__PURE__ */ x("h3", {
|
|
222
266
|
id: i,
|
|
223
267
|
ref: a,
|
|
224
268
|
tabIndex: -1,
|
|
225
269
|
className: "pxc-text--h3",
|
|
226
270
|
children: t.preferencesTitle
|
|
227
|
-
}), /* @__PURE__ */
|
|
271
|
+
}), /* @__PURE__ */ x(j, {
|
|
228
272
|
variant: "iconed",
|
|
229
273
|
"aria-label": t.closePreferencesLabel,
|
|
230
274
|
onClick: () => r({ type: "on_close_preferences" }),
|
|
231
|
-
children: /* @__PURE__ */
|
|
275
|
+
children: /* @__PURE__ */ x(P, {})
|
|
232
276
|
})]
|
|
233
277
|
}),
|
|
234
|
-
/* @__PURE__ */
|
|
278
|
+
/* @__PURE__ */ S(w.Root, {
|
|
235
279
|
className: "pxc-preferences__scroll-area",
|
|
236
|
-
children: [/* @__PURE__ */
|
|
280
|
+
children: [/* @__PURE__ */ x(w.Viewport, {
|
|
237
281
|
className: "pxc-preferences__body",
|
|
238
282
|
role: "group",
|
|
239
283
|
"aria-labelledby": i,
|
|
240
|
-
children: /* @__PURE__ */
|
|
284
|
+
children: /* @__PURE__ */ S(w.Content, {
|
|
241
285
|
className: "pxc-preferences__content",
|
|
242
|
-
children: [t.preferencesText && /* @__PURE__ */
|
|
286
|
+
children: [t.preferencesText && /* @__PURE__ */ x("p", {
|
|
243
287
|
className: "pxc-text--paragraph pxc-preferences__introduction",
|
|
244
|
-
children: /* @__PURE__ */
|
|
288
|
+
children: /* @__PURE__ */ x(L, {
|
|
245
289
|
message: t.preferencesText,
|
|
246
290
|
links: n
|
|
247
291
|
})
|
|
248
|
-
}), e.map((e) => /* @__PURE__ */
|
|
292
|
+
}), e.map((e) => /* @__PURE__ */ x(R, {
|
|
249
293
|
section: e,
|
|
250
294
|
checked: u.get(e.id) ?? e.checked,
|
|
251
295
|
links: n,
|
|
@@ -254,45 +298,45 @@ var E = ({ position: t, slideFrom: n, children: r }) => {
|
|
|
254
298
|
case "on_change_preference":
|
|
255
299
|
s((t) => new Map(t).set(e.sectionId, e.checked)), r(e);
|
|
256
300
|
break;
|
|
257
|
-
default:
|
|
301
|
+
default: F(e.type);
|
|
258
302
|
}
|
|
259
303
|
}
|
|
260
304
|
}, e.id))]
|
|
261
305
|
})
|
|
262
|
-
}), /* @__PURE__ */
|
|
306
|
+
}), /* @__PURE__ */ x(w.Scrollbar, {
|
|
263
307
|
className: "pxc-preferences__scrollbar",
|
|
264
|
-
children: /* @__PURE__ */
|
|
308
|
+
children: /* @__PURE__ */ x(w.Thumb, {
|
|
265
309
|
className: "pxc-preferences__scroll-thumb",
|
|
266
|
-
children: /* @__PURE__ */
|
|
310
|
+
children: /* @__PURE__ */ x("span", { className: "pxc-preferences__scroll-indicator" })
|
|
267
311
|
})
|
|
268
312
|
})]
|
|
269
313
|
}),
|
|
270
|
-
/* @__PURE__ */
|
|
314
|
+
/* @__PURE__ */ S("footer", {
|
|
271
315
|
className: "pxc-preferences__footer",
|
|
272
|
-
children: [/* @__PURE__ */
|
|
316
|
+
children: [/* @__PURE__ */ x(j, {
|
|
273
317
|
variant: "primary",
|
|
274
318
|
onClick: () => r({
|
|
275
319
|
type: "on_apply_preferences",
|
|
276
320
|
preferences: Object.fromEntries(u)
|
|
277
321
|
}),
|
|
278
322
|
children: t.applyPreferencesLabel
|
|
279
|
-
}), p ? /* @__PURE__ */
|
|
323
|
+
}), p ? /* @__PURE__ */ x("a", {
|
|
280
324
|
className: "pxc-link pxc-preferences__policy",
|
|
281
325
|
href: p,
|
|
282
326
|
children: t.cookiePolicyLabel
|
|
283
|
-
}) : /* @__PURE__ */
|
|
327
|
+
}) : /* @__PURE__ */ x("span", {
|
|
284
328
|
className: "pxc-preferences__policy",
|
|
285
329
|
children: t.cookiePolicyLabel
|
|
286
330
|
})]
|
|
287
331
|
})
|
|
288
332
|
]
|
|
289
333
|
});
|
|
290
|
-
},
|
|
334
|
+
}, B = [
|
|
291
335
|
"essential",
|
|
292
336
|
"analytics",
|
|
293
337
|
"marketing"
|
|
294
338
|
];
|
|
295
|
-
function
|
|
339
|
+
function V(e, t, n) {
|
|
296
340
|
let r = new Map(Object.entries(n));
|
|
297
341
|
return [...new Set(e.filter((e) => e.trim()))].map((e) => {
|
|
298
342
|
let n = r.get(e), i = t && Object.hasOwn(t, e) ? t[e] : void 0;
|
|
@@ -307,127 +351,116 @@ function R(e, t, n) {
|
|
|
307
351
|
}
|
|
308
352
|
//#endregion
|
|
309
353
|
//#region src/components/Text/Text.tsx
|
|
310
|
-
var
|
|
354
|
+
var H = ({ variant: e, tag: t, children: n }) => {
|
|
311
355
|
switch (e) {
|
|
312
|
-
case "label": return /* @__PURE__ */
|
|
356
|
+
case "label": return /* @__PURE__ */ x(t, {
|
|
313
357
|
className: "pxc-text--label",
|
|
314
358
|
children: n
|
|
315
359
|
});
|
|
316
|
-
case "heading": return /* @__PURE__ */
|
|
360
|
+
case "heading": return /* @__PURE__ */ x(t, {
|
|
317
361
|
className: `pxc-text--${t}`,
|
|
318
362
|
children: n
|
|
319
363
|
});
|
|
320
|
-
case "paragraph": return /* @__PURE__ */
|
|
364
|
+
case "paragraph": return /* @__PURE__ */ x("p", {
|
|
321
365
|
className: "pxc-text--paragraph",
|
|
322
366
|
children: n
|
|
323
367
|
});
|
|
324
|
-
default: return
|
|
368
|
+
default: return F(e);
|
|
325
369
|
}
|
|
326
|
-
},
|
|
370
|
+
}, U = ({ variant: e, content: t, equalWeight: n, showCustomizePreferences: r, preferencesRef: i, onMsg: a }) => /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ S("div", {
|
|
327
371
|
className: "pxc-banner__choices",
|
|
328
|
-
children: [/* @__PURE__ */
|
|
372
|
+
children: [/* @__PURE__ */ x(j, {
|
|
329
373
|
variant: n ? "secondary" : "primary",
|
|
330
374
|
onClick: () => a({ type: "on_accept_all" }),
|
|
331
375
|
children: t.acceptAllLabel
|
|
332
|
-
}), /* @__PURE__ */
|
|
376
|
+
}), /* @__PURE__ */ x(j, {
|
|
333
377
|
variant: "secondary",
|
|
334
378
|
onClick: () => a({ type: "on_reject_all" }),
|
|
335
379
|
children: t.rejectAllLabel
|
|
336
380
|
})]
|
|
337
|
-
}), r && /* @__PURE__ */
|
|
381
|
+
}), r && /* @__PURE__ */ x("div", {
|
|
338
382
|
className: "pxc-banner__preferences",
|
|
339
|
-
children: /* @__PURE__ */
|
|
383
|
+
children: /* @__PURE__ */ x(j, {
|
|
340
384
|
ref: i,
|
|
341
385
|
variant: "inline",
|
|
342
386
|
className: e === "compact" ? "pxc-button--iconed" : void 0,
|
|
343
387
|
"aria-label": t.customizePreferencesLabel,
|
|
344
388
|
onClick: () => a({ type: "on_open_preferences" }),
|
|
345
|
-
children: e === "compact" ? /* @__PURE__ */
|
|
389
|
+
children: e === "compact" ? /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x(A, {}), /* @__PURE__ */ x("span", { children: t.customizePreferencesLabel })] }) : t.customizePreferencesLabel
|
|
346
390
|
})
|
|
347
|
-
})] }),
|
|
348
|
-
let
|
|
349
|
-
...
|
|
350
|
-
...
|
|
351
|
-
},
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
]),
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
391
|
+
})] }), W = o(function({ bannerContent: r, cookiePolicyUrl: a, isOpen: o = !1, appearanceDelay: s = 0, preferencesSections: c = B, preferencesContent: l, hasAcceptRejectEqualWeight: d = !1, showCustomizePreferences: f = !0, showFloatingButton: p = !0, floatingButtonPosition: m, variant: h = "compact", theme: g = "auto", locale: _ = "en", onMsg: v, className: y, style: C, ...w }) {
|
|
392
|
+
let T = i(_), D = t(T), k = Object.fromEntries(Object.entries(r ?? {}).filter(([, e]) => e != null)), A = {
|
|
393
|
+
...D,
|
|
394
|
+
...k
|
|
395
|
+
}, j = u(() => ({ cookiePolicy: a }), [a]), P = u(() => V(c, l, n(T)), [
|
|
396
|
+
c,
|
|
397
|
+
l,
|
|
398
|
+
T
|
|
399
|
+
]), F = m ?? (w.position === "left" ? "left" : "right"), I = E({
|
|
400
|
+
isOpen: o,
|
|
401
|
+
showFloatingButton: p,
|
|
402
|
+
showCustomizePreferences: f,
|
|
403
|
+
floatingPosition: F,
|
|
404
|
+
onMsg: v
|
|
405
|
+
}), R = I.view !== null, W = I.view?.source === "floating-button" ? {
|
|
406
|
+
...w,
|
|
407
|
+
position: I.view.position,
|
|
408
|
+
slideFrom: "bottom"
|
|
409
|
+
} : w, G = (e) => {
|
|
410
|
+
if (e.type === "on_open_preferences") return I.openPreferences("banner");
|
|
411
|
+
if (e.type === "on_close_preferences") return I.closePreferences();
|
|
412
|
+
v?.(e);
|
|
365
413
|
};
|
|
366
|
-
return /* @__PURE__ */
|
|
367
|
-
"data-theme":
|
|
368
|
-
"data-banner-variant":
|
|
369
|
-
className: e("pxc",
|
|
414
|
+
return /* @__PURE__ */ S("div", {
|
|
415
|
+
"data-theme": g,
|
|
416
|
+
"data-banner-variant": h,
|
|
417
|
+
className: e("pxc", y),
|
|
370
418
|
style: {
|
|
371
419
|
fontFamily: "var(--pxc-font-family)",
|
|
372
|
-
...
|
|
420
|
+
...C
|
|
373
421
|
},
|
|
374
|
-
lang:
|
|
375
|
-
children: /* @__PURE__ */
|
|
376
|
-
...
|
|
377
|
-
isOpen:
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
K();
|
|
390
|
-
break;
|
|
391
|
-
case "on_accept_all":
|
|
392
|
-
case "on_reject_all":
|
|
393
|
-
C?.(e);
|
|
394
|
-
break;
|
|
395
|
-
default: T(e.type);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
422
|
+
lang: T,
|
|
423
|
+
children: [/* @__PURE__ */ x(O, {
|
|
424
|
+
...W,
|
|
425
|
+
isOpen: o,
|
|
426
|
+
onExitFocus: I.onExitFocus,
|
|
427
|
+
onPresenceChange: I.setHasPanel,
|
|
428
|
+
appearanceDelay: s,
|
|
429
|
+
className: R ? "pxc-container--preferences" : void 0,
|
|
430
|
+
actions: R ? null : /* @__PURE__ */ x(U, {
|
|
431
|
+
variant: h,
|
|
432
|
+
content: A,
|
|
433
|
+
equalWeight: d,
|
|
434
|
+
showCustomizePreferences: f,
|
|
435
|
+
preferencesRef: I.triggerRef,
|
|
436
|
+
onMsg: G
|
|
398
437
|
}),
|
|
399
|
-
children:
|
|
400
|
-
links:
|
|
401
|
-
content:
|
|
402
|
-
sections:
|
|
403
|
-
onMsg:
|
|
404
|
-
|
|
405
|
-
case "on_close_preferences":
|
|
406
|
-
q();
|
|
407
|
-
break;
|
|
408
|
-
case "on_apply_preferences":
|
|
409
|
-
case "on_change_preference":
|
|
410
|
-
C?.(e);
|
|
411
|
-
break;
|
|
412
|
-
default: T(e);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
}) : /* @__PURE__ */ x(y, { children: [_ === "stacked" ? /* @__PURE__ */ x("div", {
|
|
438
|
+
children: R ? /* @__PURE__ */ x(z, {
|
|
439
|
+
links: j,
|
|
440
|
+
content: A,
|
|
441
|
+
sections: P,
|
|
442
|
+
onMsg: G
|
|
443
|
+
}) : /* @__PURE__ */ S(b, { children: [h === "stacked" ? /* @__PURE__ */ S("div", {
|
|
416
444
|
className: "pxc-banner__heading",
|
|
417
|
-
children: [/* @__PURE__ */
|
|
445
|
+
children: [/* @__PURE__ */ x(N, {}), /* @__PURE__ */ x(H, {
|
|
418
446
|
variant: "heading",
|
|
419
447
|
tag: "h3",
|
|
420
|
-
children:
|
|
448
|
+
children: A.title
|
|
421
449
|
})]
|
|
422
|
-
}) : /* @__PURE__ */
|
|
450
|
+
}) : /* @__PURE__ */ x(N, {}), /* @__PURE__ */ x(H, {
|
|
423
451
|
variant: "paragraph",
|
|
424
|
-
children: /* @__PURE__ */
|
|
425
|
-
message:
|
|
426
|
-
links:
|
|
452
|
+
children: /* @__PURE__ */ x(L, {
|
|
453
|
+
message: A.collapsedText,
|
|
454
|
+
links: j
|
|
427
455
|
})
|
|
428
456
|
})] })
|
|
429
|
-
})
|
|
457
|
+
}), p && !o && !I.hasPanel && /* @__PURE__ */ x(M, {
|
|
458
|
+
ref: I.triggerRef,
|
|
459
|
+
position: F,
|
|
460
|
+
label: A.customizePreferencesLabel.trim() || D.customizePreferencesLabel,
|
|
461
|
+
onMsg: () => I.openPreferences("floating-button")
|
|
462
|
+
})]
|
|
430
463
|
});
|
|
431
464
|
});
|
|
432
465
|
//#endregion
|
|
433
|
-
export {
|
|
466
|
+
export { W as Banner };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peax/consent-banner-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Accessible React bindings and components for Peax Consent.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"consent-management",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@base-ui/react": "^1.7.0",
|
|
57
|
-
"@peax/consent-banner-locales": "^0.
|
|
58
|
-
"@peax/consent-banner-theme": "^0.
|
|
57
|
+
"@peax/consent-banner-locales": "^0.2.0",
|
|
58
|
+
"@peax/consent-banner-theme": "^0.2.0",
|
|
59
59
|
"clsx": "^2.1.1",
|
|
60
60
|
"framer-motion": "^13.1.1"
|
|
61
61
|
},
|