@owlmeans/web-consent 0.1.18-rc.41 → 0.1.18-rc.42
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 +1 -1
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/web-consent/SKILL.md +16 -16
- package/build/consent/component.js +9 -9
- package/build/consent/component.js.map +1 -1
- package/build/consent/toggle.js +2 -2
- package/build/consent/toggle.js.map +1 -1
- package/build/consent/widget.d.ts +1 -1
- package/build/consent/widget.js +6 -6
- package/build/consent/widget.js.map +1 -1
- package/build/index.d.ts +2 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/lib/utils/types.d.ts +28 -0
- package/build/lib/utils/types.d.ts.map +1 -0
- package/build/lib/utils/types.js +2 -0
- package/build/lib/utils/types.js.map +1 -0
- package/build/lib/utils.d.ts +3 -24
- package/build/lib/utils.d.ts.map +1 -1
- package/build/lib/utils.js +8 -26
- package/build/lib/utils.js.map +1 -1
- package/build/policy/component.d.ts.map +1 -1
- package/build/policy/component.js +7 -7
- package/build/policy/component.js.map +1 -1
- package/build/policy/types.local.d.ts +3 -1
- package/build/policy/types.local.d.ts.map +1 -1
- package/build/types.d.ts +1 -1
- package/build/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/consent/component.tsx +12 -12
- package/src/consent/toggle.tsx +4 -4
- package/src/consent/widget.tsx +6 -6
- package/src/index.ts +6 -6
- package/src/lib/utils/types.ts +28 -0
- package/src/lib/utils.ts +11 -26
- package/src/policy/component.tsx +11 -12
- package/src/policy/types.local.ts +1 -1
- package/src/types.ts +1 -1
- package/tests/a11y.spec.ts +2 -2
- package/tests/consent.spec.ts +8 -10
- package/tests/context.ts +2 -2
- package/tests/linker.spec.ts +7 -7
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
6
6
|
your project's skill store (`.agents/skills/`):
|
|
7
7
|
|
|
8
8
|
```sh
|
|
9
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
9
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.49
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/web-consent",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.42",
|
|
5
|
+
"generatedAt": "2026-10-05T21:03:06.398Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,13 +8,13 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/web-consent
|
|
9
9
|
|
|
10
10
|
**Layer:** Web (React)
|
|
11
|
-
**Install:** `"@owlmeans/web-consent": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/web-consent": "^0.1.18-rc.42"` in `dependencies`
|
|
12
12
|
|
|
13
13
|
The browser components of the consent set. The model — categories, storage, migration, the store,
|
|
14
14
|
Consent Mode signalling — is `@owlmeans/consent`, and this package re-exports a **named selection**
|
|
15
|
-
of it (listed under Key Exports) so an application usually has one import.
|
|
15
|
+
of it (listed under Key Exports) so an application usually has one import. Four public
|
|
16
16
|
`@owlmeans/consent` exports are deliberately not in that list — `makeConsentStore`,
|
|
17
|
-
`
|
|
17
|
+
`CONSENT_SETUP_FLAG`, `CONSENT_SIGNAL_DEFAULTS` and the `ConsentListener` type —
|
|
18
18
|
so a caller that needs one of them imports it from `@owlmeans/consent` directly. **Read the
|
|
19
19
|
`consent` skill for the model; read this one for the components.**
|
|
20
20
|
|
|
@@ -41,7 +41,7 @@ components — see below.
|
|
|
41
41
|
| `useConsent(opts?)` | This document's consent state and the actions over it (`UseConsentModel`) — **it also initialises the store on mount**, see below |
|
|
42
42
|
| `useConsentCategory(key)` | Whether one category is granted, for a component gating a single thing |
|
|
43
43
|
| `CookieConsentProps` / `CookiePolicyProps` / `ConsentLink` | The component props |
|
|
44
|
-
| Re-exports from `@owlmeans/consent` | The complete list: `consentStore
|
|
44
|
+
| Re-exports from `@owlmeans/consent` | The complete list: `consentStore`; `consentStorageHelper` (`readConsent`, `writeConsent`, `clearConsent`, `migrateConsent`); `consentModeHelper` (`applyConsent`, `pushConsentDefaults`, `consentBootstrapScript`, `consentDefaults`, `consentUpdate`, `gtagConsent`, `trackingGranted`, `consentGateScript`); `consentI18nHelper` (`defaultConsentTranslate`, `interpolate`, `normalizeLocale`); `DEFAULT_CONSENT_CATEGORIES`, `DEFAULT_CONSENT_MESSAGES`, `CONSENT_KEY`, `CONSENT_COOKIE_DAYS`, `CONSENT_SCHEMA_VERSION`, `CONSENT_LOCALES`, `CONSENT_ESSENTIAL` / `CONSENT_ANALYTICS` / `CONSENT_MARKETING`, the plugin seam (`consentPluginHelper`: `registerConsentPlugin`, `consentPlugins`, `decorateConsentUrl`, `consentDomains`, `adoptConsent`, `startConsentPlugins`, `adoptConsentLanguage`), the linker (`consentLinkHelper`: `consentLinker`, `encodeConsentLink`, `decodeConsentLink`, `stripConsentLinkParam`, `consentLinkerScript`, `writeConsentLanguage`; `CONSENT_LANGUAGE_KEY`, `CONSENT_EVENT`, `CONSENT_LINK_PARAM`, `CONSENT_LINK_MAX_AGE`, `CONSENT_LINK_SKEW`), and the types `ConsentCategory`, `ConsentOptions`, `ConsentReason`, `ConsentRecord`, `ConsentService`, `ConsentSignal`, `ConsentState`, `ConsentStore`, `ConsentLocale`, `ConsentLinkerOptions`, `ConsentLinkerLanguage`, `ConsentPlugin`, `ConsentLinkPayload` and the five helper interfaces |
|
|
45
45
|
|
|
46
46
|
## Mounting the dialog
|
|
47
47
|
|
|
@@ -67,7 +67,7 @@ import { CookieConsent } from '@owlmeans/web-consent'
|
|
|
67
67
|
- `policyHref` is a plain string, so an app-resolved path, a framework route and a raw href all
|
|
68
68
|
work — the component must not know how its host does routing.
|
|
69
69
|
- `noReopenButton` hides the floating button for an app that offers a footer link instead; that link
|
|
70
|
-
calls `
|
|
70
|
+
calls `consentStore.open('reopen')`.
|
|
71
71
|
- **The re-open button is a bare icon in the very corner (`bottom-1 left-1`), not a card.** No
|
|
72
72
|
filled background, no border, no shadow, no hover-scale — `bg-transparent`, dimmed
|
|
73
73
|
(`opacity-70`) at rest and picked out on hover/focus — because it sits on every page of a site
|
|
@@ -76,7 +76,7 @@ import { CookieConsent } from '@owlmeans/web-consent'
|
|
|
76
76
|
(`h-11 w-11`). `[data-consent-reopen]` is what any test or CSS override keys on.
|
|
77
77
|
- **`linker` (`ConsentLinkerOptions`)** turns on cross-domain consent (see the `consent` skill's
|
|
78
78
|
plugin-seam section): `<CookieConsent linker={{ domains: ['owlmeans.com', 'owlmeans.pl'] }} />`
|
|
79
|
-
passes it straight to `useConsent`, which registers `consentLinker` on mount. With it set and
|
|
79
|
+
passes it straight to `useConsent`, which registers `consentLinkHelper.consentLinker` on mount. With it set and
|
|
80
80
|
more than just the current host to disclose, a domain line renders right after the description
|
|
81
81
|
(`[data-consent-domains]`, added to the dialog's `aria-describedby`) — computed DIRECTLY from
|
|
82
82
|
`linker.domains` plus the current host, not through the plugin registry, so it never depends on
|
|
@@ -134,9 +134,9 @@ required category is disclosure, not a question.
|
|
|
134
134
|
## A menu row for a host that already has one
|
|
135
135
|
|
|
136
136
|
`ConsentMenuWidget` renders one row — icon, translated label, `onClick` reopening the dialog
|
|
137
|
-
(`
|
|
137
|
+
(`consentStore.open('reopen')` by default, or a caller's own `onSelect`) — for a host whose own
|
|
138
138
|
navigation already carries a settings menu and would rather offer cookie preferences there than as
|
|
139
|
-
a second floating button. It calls `
|
|
139
|
+
a second floating button. It calls `consentStore.open` directly, never `useConsent()`, for the same
|
|
140
140
|
init-on-mount reason as everywhere else in this document.
|
|
141
141
|
|
|
142
142
|
**It carries no presence signalling of its own.** A host that wants `CookieConsent`'s floating
|
|
@@ -152,11 +152,11 @@ row. A context-free host (an Astro island with its own menu) owns that judgement
|
|
|
152
152
|
## Reading the decision
|
|
153
153
|
|
|
154
154
|
```tsx
|
|
155
|
-
import { useConsent, useConsentCategory
|
|
155
|
+
import { consentStore, useConsent, useConsentCategory } from '@owlmeans/web-consent'
|
|
156
156
|
|
|
157
157
|
const consent = useConsent() // { record, open, reason, granted, save, acceptAll, openDialog, close }
|
|
158
158
|
const analytics = useConsentCategory('analytics') // one category, for a component gating one thing
|
|
159
|
-
if (
|
|
159
|
+
if (consentStore.granted('analytics')) { /* outside React — a click handler, a service */ }
|
|
160
160
|
```
|
|
161
161
|
|
|
162
162
|
Both hooks subscribe through `useSyncExternalStore` over the module-singleton store, because consent
|
|
@@ -171,9 +171,9 @@ a component that only wanted to read has to plan for:
|
|
|
171
171
|
- **It opens the dialog.** `init` reads storage, and with no stored record it publishes
|
|
172
172
|
`open: true, reason: 'initial'`. So a `useConsent()` in a card that merely wanted `granted('analytics')`
|
|
173
173
|
gates the page for a first-time visitor. Read a single category with `useConsentCategory(key)` —
|
|
174
|
-
that hook subscribes and does **not** init — or `
|
|
174
|
+
that hook subscribes and does **not** init — or `consentStore.granted(key)` outside React.
|
|
175
175
|
- **The first `useConsent` to mount fixes the Consent Mode defaults.** `init` calls
|
|
176
|
-
`pushConsentDefaults`, which is idempotent through the `CONSENT_SETUP_FLAG` window flag: whoever
|
|
176
|
+
`consentModeHelper.pushConsentDefaults`, which is idempotent through the `CONSENT_SETUP_FLAG` window flag: whoever
|
|
177
177
|
gets there first declares the `consent/default` signals from *its* categories, and every later
|
|
178
178
|
call returns immediately. A bare `useConsent()` mounting before `CookieConsent` therefore declares
|
|
179
179
|
`DEFAULT_CONSENT_CATEGORIES`' signals and the app's own `categories` never declare theirs — which
|
|
@@ -191,11 +191,11 @@ why it is generated rather than written: a hand-written policy drifts the first
|
|
|
191
191
|
changes, and nobody notices because nobody reads it until it matters.
|
|
192
192
|
|
|
193
193
|
```tsx
|
|
194
|
-
import {
|
|
194
|
+
import { googleTagHelper } from '@owlmeans/web-gtm'
|
|
195
195
|
|
|
196
196
|
<CookiePolicy
|
|
197
197
|
operator="Example Sp. z o.o." privacyHref="/legal/privacy" termsHref="/legal/terms"
|
|
198
|
-
services={googleTag !== '' ? googleTagServices(googleTag) : undefined}
|
|
198
|
+
services={googleTag !== '' ? googleTagHelper.googleTagServices(googleTag) : undefined}
|
|
199
199
|
/>
|
|
200
200
|
```
|
|
201
201
|
|
|
@@ -270,7 +270,7 @@ incremental `tsc -b` — rebuild `@owlmeans/consent` with `tsc -b --force`, or c
|
|
|
270
270
|
bundle from `build/i18n`. **Once a `translate` prop is given,
|
|
271
271
|
the packaged bundle is not consulted at all**, so a wrapper that forwards a framework resolver alone
|
|
272
272
|
renders the English default for every key the application has not overridden, in every language. The
|
|
273
|
-
resolver must fall through to `defaultConsentTranslate(locale)` for the default — which is exactly
|
|
273
|
+
resolver must fall through to `consentI18nHelper.defaultConsentTranslate(locale)` for the default — which is exactly
|
|
274
274
|
what `@owlmeans/web-panel/consent` does, and why an app inside the panel family mounts
|
|
275
275
|
`PanelCookieConsent` / `PanelCookiePolicy` rather than these components directly.
|
|
276
276
|
|
|
@@ -287,7 +287,7 @@ caller's, already resolved.
|
|
|
287
287
|
- `consent` — the model: categories, `globalVar`, storage and migration, Consent Mode v2, the
|
|
288
288
|
ordering rule. Read it before changing anything a category means
|
|
289
289
|
- `web-gtm` — the head snippet that carries a stored decision to a Google tag, and
|
|
290
|
-
`googleTagServices(id)` for this page's `services`
|
|
290
|
+
`googleTagHelper.googleTagServices(id)` for this page's `services`
|
|
291
291
|
- `astro` — stamping that snippet from a static site's layout
|
|
292
292
|
- `login-methods` / `login-plugins` — the sign-in precondition that raises this dialog with
|
|
293
293
|
`reason: 'login'`
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useState } from 'react';
|
|
3
3
|
import { Cookie } from 'lucide-react';
|
|
4
|
-
import { DEFAULT_CONSENT_CATEGORIES,
|
|
5
|
-
import {
|
|
4
|
+
import { DEFAULT_CONSENT_CATEGORIES, consentI18nHelper, consentStorageHelper } from '@owlmeans/consent';
|
|
5
|
+
import { webConsentUtils } from '../lib/utils.js';
|
|
6
6
|
import { useConsent } from '../hooks.js';
|
|
7
7
|
import { ConsentToggle } from './toggle.js';
|
|
8
8
|
import { FOCUS } from './consts.local.js';
|
|
9
9
|
/** A pill button: 44px tall at minimum, full width on a phone, sharing the row above that. */
|
|
10
|
-
const PILL = cn('inline-flex min-h-11 flex-1 items-center justify-center rounded-full px-6 py-2.5 text-[15px] transition-colors motion-safe:active:scale-[0.98]', FOCUS);
|
|
10
|
+
const PILL = webConsentUtils.cn('inline-flex min-h-11 flex-1 items-center justify-center rounded-full px-6 py-2.5 text-[15px] transition-colors motion-safe:active:scale-[0.98]', FOCUS);
|
|
11
11
|
/** A text link: muted, underlined at rest (colour is never the only signal), 44px tall to tap. */
|
|
12
|
-
const LINK = cn('inline-flex min-h-11 items-center font-semibold underline decoration-1 underline-offset-4 transition-colors hover:text-foreground hover:decoration-2', FOCUS);
|
|
12
|
+
const LINK = webConsentUtils.cn('inline-flex min-h-11 items-center font-semibold underline decoration-1 underline-offset-4 transition-colors hover:text-foreground hover:decoration-2', FOCUS);
|
|
13
13
|
export const CookieConsent = props => {
|
|
14
14
|
const categories = props.categories ?? DEFAULT_CONSENT_CATEGORIES;
|
|
15
|
-
const t = props.translate ?? defaultConsentTranslate(props.locale);
|
|
15
|
+
const t = props.translate ?? consentI18nHelper.defaultConsentTranslate(props.locale);
|
|
16
16
|
const consentOpts = {
|
|
17
17
|
categories,
|
|
18
18
|
...(props.storageKey != null ? { storageKey: props.storageKey } : {}),
|
|
@@ -22,7 +22,7 @@ export const CookieConsent = props => {
|
|
|
22
22
|
...(props.linker != null ? { linker: props.linker } : {}),
|
|
23
23
|
};
|
|
24
24
|
const consent = useConsent(consentOpts);
|
|
25
|
-
const domains = disclosedDomains(props.linker);
|
|
25
|
+
const domains = webConsentUtils.disclosedDomains(props.linker);
|
|
26
26
|
const optional = categories.filter(category => category.required !== true);
|
|
27
27
|
const [draft, setDraft] = useState({});
|
|
28
28
|
// Re-seed the draft whenever the dialog opens, from what is actually stored: a visitor who opens
|
|
@@ -31,7 +31,7 @@ export const CookieConsent = props => {
|
|
|
31
31
|
if (!consent.open) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
const stored = consent.record ?? readConsent({
|
|
34
|
+
const stored = consent.record ?? consentStorageHelper.readConsent({
|
|
35
35
|
...(props.storageKey != null ? { storageKey: props.storageKey } : {}),
|
|
36
36
|
});
|
|
37
37
|
setDraft(Object.fromEntries(optional.map(category => [category.key, stored?.[category.key] === true])));
|
|
@@ -49,8 +49,8 @@ export const CookieConsent = props => {
|
|
|
49
49
|
// today. Saying so, and relabelling the primary action, is what makes the interruption make
|
|
50
50
|
// sense rather than look like the page asking twice.
|
|
51
51
|
const gated = consent.reason === 'login';
|
|
52
|
-
return _jsxs(_Fragment, { children: [consent.open && _jsx("div", { className: "fixed inset-0 z-[999998] flex items-center justify-center overflow-y-auto bg-black/70 px-4 py-6", "aria-modal": "true", role: "dialog", "aria-labelledby": "cc-title", "aria-describedby": domains.length > 1 ? 'cc-desc cc-domains' : 'cc-desc', "data-consent-dialog": true, children: _jsxs("div", { className: cn('relative z-[999999] w-full max-w-lg rounded-3xl border border-border bg-background p-6 text-foreground sm:p-8', props.className), children: [_jsxs("div", { className: "mb-4 flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-muted text-primary", children: _jsx(Cookie, { className: "h-5 w-5", "aria-hidden": "true" }) }), _jsx("h2", { id: "cc-title", className: "text-balance text-xl font-extrabold tracking-tight text-foreground sm:text-2xl", children: t('title', 'Cookie Preferences') })] }), _jsx("p", { id: "cc-desc", className: "mb-6 text-pretty text-sm leading-relaxed text-muted-foreground", children: t('description', 'We use cookies to enhance your browsing experience, serve personalized ads or content, and analyze our traffic.') }), domains.length > 1 && _jsx("p", { id: "cc-domains", "data-consent-domains": true, className: "mb-6 -mt-3 text-pretty text-xs text-muted-foreground", children: interpolate(t('domains', 'This choice applies to {{domains}}.'), { domains: domains.join(', ') }) }), _jsx("div", { className: "space-y-3", children: categories.map(category => _jsx(ConsentToggle, { id: `cc-${category.key}`, label: t(category.labelKey, category.key), description: t(category.descriptionKey, ''), checked: draft[category.key] === true, ...(category.required === true ? { required: true } : {}), requiredLabel: t('required', 'Required'), onChange: value => setDraft(current => ({ ...current, [category.key]: value })) }, category.key)) }), gated && _jsx("p", { role: "status", "data-consent-reason": true, className: "mt-4 text-sm font-semibold text-foreground", children: t('loginReason', 'Signing in stores a session cookie. Accept essential cookies to continue.') }), _jsxs("div", { className: "mt-8 flex flex-col gap-3 sm:flex-row sm:gap-4", children: [_jsx("button", { type: "button", onClick: onSave, "data-consent-save": true, className: cn(PILL, 'border-[1.5px] border-foreground bg-transparent font-semibold text-foreground hover:bg-muted'), children: t('savePreferences', 'Save Preferences') }), _jsx("button", { type: "button", onClick: onAcceptAll, "data-consent-accept-all": true, className: cn(PILL, 'bg-primary font-bold text-primary-foreground hover:bg-primary/90'), children: gated
|
|
52
|
+
return _jsxs(_Fragment, { children: [consent.open && _jsx("div", { className: "fixed inset-0 z-[999998] flex items-center justify-center overflow-y-auto bg-black/70 px-4 py-6", "aria-modal": "true", role: "dialog", "aria-labelledby": "cc-title", "aria-describedby": domains.length > 1 ? 'cc-desc cc-domains' : 'cc-desc', "data-consent-dialog": true, children: _jsxs("div", { className: webConsentUtils.cn('relative z-[999999] w-full max-w-lg rounded-3xl border border-border bg-background p-6 text-foreground sm:p-8', props.className), children: [_jsxs("div", { className: "mb-4 flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-muted text-primary", children: _jsx(Cookie, { className: "h-5 w-5", "aria-hidden": "true" }) }), _jsx("h2", { id: "cc-title", className: "text-balance text-xl font-extrabold tracking-tight text-foreground sm:text-2xl", children: t('title', 'Cookie Preferences') })] }), _jsx("p", { id: "cc-desc", className: "mb-6 text-pretty text-sm leading-relaxed text-muted-foreground", children: t('description', 'We use cookies to enhance your browsing experience, serve personalized ads or content, and analyze our traffic.') }), domains.length > 1 && _jsx("p", { id: "cc-domains", "data-consent-domains": true, className: "mb-6 -mt-3 text-pretty text-xs text-muted-foreground", children: consentI18nHelper.interpolate(t('domains', 'This choice applies to {{domains}}.'), { domains: domains.join(', ') }) }), _jsx("div", { className: "space-y-3", children: categories.map(category => _jsx(ConsentToggle, { id: `cc-${category.key}`, label: t(category.labelKey, category.key), description: t(category.descriptionKey, ''), checked: draft[category.key] === true, ...(category.required === true ? { required: true } : {}), requiredLabel: t('required', 'Required'), onChange: value => setDraft(current => ({ ...current, [category.key]: value })) }, category.key)) }), gated && _jsx("p", { role: "status", "data-consent-reason": true, className: "mt-4 text-sm font-semibold text-foreground", children: t('loginReason', 'Signing in stores a session cookie. Accept essential cookies to continue.') }), _jsxs("div", { className: "mt-8 flex flex-col gap-3 sm:flex-row sm:gap-4", children: [_jsx("button", { type: "button", onClick: onSave, "data-consent-save": true, className: webConsentUtils.cn(PILL, 'border-[1.5px] border-foreground bg-transparent font-semibold text-foreground hover:bg-muted'), children: t('savePreferences', 'Save Preferences') }), _jsx("button", { type: "button", onClick: onAcceptAll, "data-consent-accept-all": true, className: webConsentUtils.cn(PILL, 'bg-primary font-bold text-primary-foreground hover:bg-primary/90'), children: gated
|
|
53
53
|
? t('acceptAndContinue', 'Accept & continue')
|
|
54
|
-
: t('acceptAll', 'Accept All') })] }), (props.policyHref != null || props.links != null) && _jsxs("div", { className: "mt-3 flex flex-wrap justify-center gap-x-4 text-[13px] text-muted-foreground", children: [props.policyHref != null && _jsx("a", { href: props.policyHref, target: "_blank", rel: "noopener noreferrer", className: LINK, children: t('policyLink', 'Cookie Policy') }), props.links?.map(link => _jsx("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: LINK, children: t(link.labelKey, link.defaultLabel) }, link.href))] })] }) }), props.noReopenButton !== true && consent.record != null && !consent.open && _jsx("button", { type: "button", onClick: () => consent.openDialog('reopen'), "aria-label": t('openPreferences', 'Cookie preferences'), "data-consent-reopen": true, className: cn('fixed bottom-1 left-1 z-[999997] inline-flex h-11 w-11 items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground opacity-70 transition-opacity hover:opacity-100 hover:text-primary focus-visible:opacity-100', FOCUS), children: _jsx(Cookie, { className: "h-5 w-5", "aria-hidden": "true" }) })] });
|
|
54
|
+
: t('acceptAll', 'Accept All') })] }), (props.policyHref != null || props.links != null) && _jsxs("div", { className: "mt-3 flex flex-wrap justify-center gap-x-4 text-[13px] text-muted-foreground", children: [props.policyHref != null && _jsx("a", { href: props.policyHref, target: "_blank", rel: "noopener noreferrer", className: LINK, children: t('policyLink', 'Cookie Policy') }), props.links?.map(link => _jsx("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", className: LINK, children: t(link.labelKey, link.defaultLabel) }, link.href))] })] }) }), props.noReopenButton !== true && consent.record != null && !consent.open && _jsx("button", { type: "button", onClick: () => consent.openDialog('reopen'), "aria-label": t('openPreferences', 'Cookie preferences'), "data-consent-reopen": true, className: webConsentUtils.cn('fixed bottom-1 left-1 z-[999997] inline-flex h-11 w-11 items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground opacity-70 transition-opacity hover:opacity-100 hover:text-primary focus-visible:opacity-100', FOCUS), children: _jsx(Cookie, { className: "h-5 w-5", "aria-hidden": "true" }) })] });
|
|
55
55
|
};
|
|
56
56
|
//# sourceMappingURL=component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/consent/component.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAW,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,0BAA0B,
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/consent/component.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAW,MAAM,OAAO,CAAA;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,0BAA0B,EAAsB,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAC3H,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAEzC,8FAA8F;AAC9F,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,CAC7B,gJAAgJ,EAChJ,KAAK,CACN,CAAA;AAED,kGAAkG;AAClG,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,CAC7B,sJAAsJ,EACtJ,KAAK,CACN,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAA2B,KAAK,CAAC,EAAE;IAC3D,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,0BAA0B,CAAA;IACjE,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAEpF,MAAM,WAAW,GAAG;QAClB,UAAU;QACV,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,GAAG,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3E,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1D,CAAA;IACD,MAAM,OAAO,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,eAAe,CAAC,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAE9D,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAA;IAC1E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAA0B,EAAE,CAAC,CAAA;IAE/D,iGAAiG;IACjG,6FAA6F;IAC7F,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,oBAAoB,CAAC,WAAW,CAAC;YAChE,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE,CAAC,CAAA;QACF,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAClD,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACtD,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;IAElC,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,MAA+B,EAAE,EAAE;QAC9D,MAAM,MAAM,GAAkB,MAAM,CAAC,WAAW,CAAC;YAC/C,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACtE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;SACtD,CAAC,CAAA;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACtB,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAA;IAEzB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IAClE,MAAM,WAAW,GAAG,WAAW,CAC7B,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CACzF,CAAA;IAED,+FAA+F;IAC/F,4FAA4F;IAC5F,qDAAqD;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,KAAK,OAAO,CAAA;IAExC,OAAO,8BACJ,OAAO,CAAC,IAAI,IAAI,cACf,SAAS,EAAC,iGAAiG,gBAChG,MAAM,EAAC,IAAI,EAAC,QAAQ,qBAAiB,UAAU,sBACxC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,yCAGvE,eAAK,SAAS,EAAE,eAAe,CAAC,EAAE,CAChC,+GAA+G,EAC/G,KAAK,CAAC,SAAS,CAChB,aACC,eAAK,SAAS,EAAC,8BAA8B,aAC3C,cAAK,SAAS,EAAC,6FAA6F,YAC1G,KAAC,MAAM,IAAC,SAAS,EAAC,SAAS,iBAAa,MAAM,GAAG,GAC7C,EACN,aAAI,EAAE,EAAC,UAAU,EAAC,SAAS,EAAC,gFAAgF,YACzG,CAAC,CAAC,OAAO,EAAE,oBAAoB,CAAC,GAC9B,IACD,EAEN,YAAG,EAAE,EAAC,SAAS,EAAC,SAAS,EAAC,gEAAgE,YACvF,CAAC,CAAC,aAAa,EAAE,iHAAiH,CAAC,GAClI,EAEH,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,YACrB,EAAE,EAAC,YAAY,gCACf,SAAS,EAAC,sDAAsD,YAE/D,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAAE,qCAAqC,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAClH,EAEJ,cAAK,SAAS,EAAC,WAAW,YACvB,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAC,aAAa,IAExC,EAAE,EAAE,MAAM,QAAQ,CAAC,GAAG,EAAE,EACxB,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,EACzC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC,EAC3C,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI,KACjC,CAAC,QAAQ,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC1D,aAAa,EAAE,CAAC,CAAC,UAAU,EAAE,UAAU,CAAC,EACxC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAP1E,QAAQ,CAAC,GAAG,CAQjB,CAAC,GACC,EAEL,KAAK,IAAI,YAAG,IAAI,EAAC,QAAQ,+BAAqB,SAAS,EAAC,4CAA4C,YAClG,CAAC,CAAC,aAAa,EAAE,2EAA2E,CAAC,GAC5F,EAEJ,eAAK,SAAS,EAAC,+CAA+C,aAC5D,iBACE,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,MAAM,6BAC7B,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,8FAA8F,CAAC,YACnI,CAAC,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,GAAU,EACpD,iBACE,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,WAAW,mCAClC,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,kEAAkE,CAAC,YACvG,KAAK;wCACL,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;wCAC7C,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,YAAY,CAAC,GAAU,IACtC,EAEL,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,eAAK,SAAS,EAAC,8EAA8E,aAChJ,KAAK,CAAC,UAAU,IAAI,IAAI,IAAI,YAC3B,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,qBAAqB,EAAC,SAAS,EAAE,IAAI,YACjF,CAAC,CAAC,YAAY,EAAE,eAAe,CAAC,GAAK,EACtC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,YACR,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,qBAAqB,EAAC,SAAS,EAAE,IAAI,YAC1F,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,IAD9B,IAAI,CAAC,IAAI,CAC0B,CAAC,IACvC,IACF,GACF,EAUL,KAAK,CAAC,cAAc,KAAK,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,iBAC3E,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,gBAC7C,CAAC,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,+BAEtD,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC,2OAA2O,EAAE,KAAK,CAAC,YAEjR,KAAC,MAAM,IAAC,SAAS,EAAC,SAAS,iBAAa,MAAM,GAAG,GAC1C,IACR,CAAA;AACL,CAAC,CAAA"}
|
package/build/consent/toggle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { webConsentUtils } from '../lib/utils.js';
|
|
3
3
|
/**
|
|
4
4
|
* One category row: a hairline card with the label, the description and a switch.
|
|
5
5
|
*
|
|
@@ -20,6 +20,6 @@ export const ConsentToggle = ({ id, label, description, checked, required, requi
|
|
|
20
20
|
...(required === true ? [`${id}-required`] : []),
|
|
21
21
|
...(description !== '' ? [`${id}-desc`] : []),
|
|
22
22
|
];
|
|
23
|
-
return (_jsxs("div", { className: "flex items-center justify-between gap-4 rounded-2xl border border-border p-4", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-0.5 flex flex-wrap items-center gap-x-2 text-sm font-bold text-foreground", children: [_jsx("span", { id: `${id}-label`, children: label }), required === true && _jsx("span", { id: `${id}-required`, className: "text-xs font-bold uppercase tracking-wide text-muted-foreground", children: requiredLabel })] }), description !== '' && _jsx("p", { id: `${id}-desc`, className: "text-pretty text-xs leading-relaxed text-muted-foreground", children: description })] }), _jsxs("label", { className: cn('relative inline-flex h-11 w-14 flex-shrink-0 items-center justify-center', required === true ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'), children: [_jsx("input", { id: id, type: "checkbox", "aria-labelledby": `${id}-label`, ...(described.length > 0 ? { 'aria-describedby': described.join(' ') } : {}), className: "peer sr-only", checked: checked || required === true, disabled: required === true, onChange: event => onChange(event.target.checked) }), _jsx("span", { className: cn('relative h-6 w-11 rounded-full transition-colors duration-300 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-ring', checked || required === true ? 'bg-primary' : 'bg-muted-foreground/40'), children: _jsx("span", { className: cn('absolute top-0.5 left-0 h-5 w-5 rounded-full bg-white transition-transform duration-300', checked || required === true ? 'translate-x-5' : 'translate-x-0.5') }) })] })] }));
|
|
23
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-4 rounded-2xl border border-border p-4", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-0.5 flex flex-wrap items-center gap-x-2 text-sm font-bold text-foreground", children: [_jsx("span", { id: `${id}-label`, children: label }), required === true && _jsx("span", { id: `${id}-required`, className: "text-xs font-bold uppercase tracking-wide text-muted-foreground", children: requiredLabel })] }), description !== '' && _jsx("p", { id: `${id}-desc`, className: "text-pretty text-xs leading-relaxed text-muted-foreground", children: description })] }), _jsxs("label", { className: webConsentUtils.cn('relative inline-flex h-11 w-14 flex-shrink-0 items-center justify-center', required === true ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'), children: [_jsx("input", { id: id, type: "checkbox", "aria-labelledby": `${id}-label`, ...(described.length > 0 ? { 'aria-describedby': described.join(' ') } : {}), className: "peer sr-only", checked: checked || required === true, disabled: required === true, onChange: event => onChange(event.target.checked) }), _jsx("span", { className: webConsentUtils.cn('relative h-6 w-11 rounded-full transition-colors duration-300 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-ring', checked || required === true ? 'bg-primary' : 'bg-muted-foreground/40'), children: _jsx("span", { className: webConsentUtils.cn('absolute top-0.5 left-0 h-5 w-5 rounded-full bg-white transition-transform duration-300', checked || required === true ? 'translate-x-5' : 'translate-x-0.5') }) })] })] }));
|
|
24
24
|
};
|
|
25
25
|
//# sourceMappingURL=toggle.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle.js","sourceRoot":"","sources":["../../src/consent/toggle.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"toggle.js","sourceRoot":"","sources":["../../src/consent/toggle.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2B,CACnD,EAAE,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,EACtE,EAAE;IACF,MAAM,SAAS,GAAG;QAChB,GAAG,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9C,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAC,8EAA8E,aAC3F,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,8EAA8E,aAC3F,eAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,YAAG,KAAK,GAAQ,EACtC,QAAQ,KAAK,IAAI,IAAI,eACpB,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,SAAS,EAAC,iEAAiE,YACjG,aAAa,GAAQ,IACnB,EACL,WAAW,KAAK,EAAE,IAAI,YACrB,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAC,2DAA2D,YACvF,WAAW,GAAK,IACd,EACN,iBAAO,SAAS,EAAE,eAAe,CAAC,EAAE,CAClC,0EAA0E,EAC1E,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,gBAAgB,CACvE,aACC,gBACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAC,UAAU,qBACE,GAAG,EAAE,QAAQ,KAC1B,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC7E,SAAS,EAAC,cAAc,EACxB,OAAO,EAAE,OAAO,IAAI,QAAQ,KAAK,IAAI,EACrC,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAC3B,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,GACjD,EACF,eAAM,SAAS,EAAE,eAAe,CAAC,EAAE,CACjC,gKAAgK,EAChK,OAAO,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,wBAAwB,CACvE,YACC,eAAM,SAAS,EAAE,eAAe,CAAC,EAAE,CACjC,yFAAyF,EACzF,OAAO,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,iBAAiB,CACnE,GAAI,GACA,IACD,IACJ,CACP,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -11,7 +11,7 @@ import type { ConsentMenuWidgetProps } from '../types.js';
|
|
|
11
11
|
* button while this row is reachable announces that from whatever component of its own stays
|
|
12
12
|
* mounted for the menu's whole lifetime — see `useConsentMenuPresence` in `@owlmeans/web-panel/consent`.
|
|
13
13
|
*
|
|
14
|
-
* Uses `
|
|
14
|
+
* Uses `consentStore.open` directly rather than the `useConsent()` hook: that hook's mount itself
|
|
15
15
|
* triggers `consentStore.init()`, which a row that only needs to trigger a reopen must not do.
|
|
16
16
|
*/
|
|
17
17
|
export declare const ConsentMenuWidget: FC<ConsentMenuWidgetProps>;
|
package/build/consent/widget.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback } from 'react';
|
|
3
3
|
import { Cookie } from 'lucide-react';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { consentStore, consentI18nHelper } from '@owlmeans/consent';
|
|
5
|
+
import { webConsentUtils } from '../lib/utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* One row a HOST'S OWN menu can render to reopen the preferences dialog, in place of (or beside)
|
|
8
8
|
* the floating button `CookieConsent` renders itself. No outer row padding here — the host's own
|
|
@@ -14,18 +14,18 @@ import { cn } from '../lib/utils.js';
|
|
|
14
14
|
* button while this row is reachable announces that from whatever component of its own stays
|
|
15
15
|
* mounted for the menu's whole lifetime — see `useConsentMenuPresence` in `@owlmeans/web-panel/consent`.
|
|
16
16
|
*
|
|
17
|
-
* Uses `
|
|
17
|
+
* Uses `consentStore.open` directly rather than the `useConsent()` hook: that hook's mount itself
|
|
18
18
|
* triggers `consentStore.init()`, which a row that only needs to trigger a reopen must not do.
|
|
19
19
|
*/
|
|
20
20
|
export const ConsentMenuWidget = props => {
|
|
21
|
-
const t = props.translate ?? defaultConsentTranslate(props.locale);
|
|
21
|
+
const t = props.translate ?? consentI18nHelper.defaultConsentTranslate(props.locale);
|
|
22
22
|
const onClick = useCallback(() => {
|
|
23
23
|
if (props.onSelect != null) {
|
|
24
24
|
props.onSelect();
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
consentStore.open('reopen');
|
|
28
28
|
}, [props.onSelect]);
|
|
29
|
-
return _jsxs("button", { type: "button", onClick: onClick, "data-consent-menu-widget": true, className: cn('flex w-full min-w-0 items-center gap-2 rounded-md text-left text-sm text-popover-foreground transition-colors hover:bg-accent', props.className), children: [_jsx(Cookie, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }), _jsx("span", { className: "flex-1 truncate", children: props.label ?? t('openPreferences', 'Cookie preferences') })] });
|
|
29
|
+
return _jsxs("button", { type: "button", onClick: onClick, "data-consent-menu-widget": true, className: webConsentUtils.cn('flex w-full min-w-0 items-center gap-2 rounded-md text-left text-sm text-popover-foreground transition-colors hover:bg-accent', props.className), children: [_jsx(Cookie, { className: "h-4 w-4 shrink-0", "aria-hidden": "true" }), _jsx("span", { className: "flex-1 truncate", children: props.label ?? t('openPreferences', 'Cookie preferences') })] });
|
|
30
30
|
};
|
|
31
31
|
//# sourceMappingURL=widget.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../../src/consent/widget.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAEnC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../../src/consent/widget.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAEnC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAGjD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA+B,KAAK,CAAC,EAAE;IACnE,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAEpF,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;YAC3B,KAAK,CAAC,QAAQ,EAAE,CAAA;YAChB,OAAM;QACR,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC7B,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEpB,OAAO,kBACL,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,oCAC9B,SAAS,EAAE,eAAe,CAAC,EAAE,CAC3B,+HAA+H,EAC/H,KAAK,CAAC,SAAS,CAChB,aAED,KAAC,MAAM,IAAC,SAAS,EAAC,kBAAkB,iBAAa,MAAM,GAAG,EAC1D,eAAM,SAAS,EAAC,iBAAiB,YAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAQ,IAC7F,CAAA;AACX,CAAC,CAAA"}
|
package/build/index.d.ts
CHANGED
|
@@ -5,6 +5,6 @@ export * from './consent/widget.js';
|
|
|
5
5
|
export * from './consent/toggle.js';
|
|
6
6
|
export type * from './consent/types.js';
|
|
7
7
|
export * from './policy/component.js';
|
|
8
|
-
export { consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent,
|
|
9
|
-
export type { ConsentCategory, ConsentOptions, ConsentReason, ConsentRecord, ConsentService, ConsentSignal, ConsentState, ConsentStore, ConsentLocale, ConsentLinkerOptions, ConsentLinkerLanguage, ConsentPlugin, ConsentLinkPayload, } from '@owlmeans/consent';
|
|
8
|
+
export { consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent, consentBootstrapScript, DEFAULT_CONSENT_CATEGORIES, DEFAULT_CONSENT_MESSAGES, defaultConsentTranslate, CONSENT_KEY, CONSENT_COOKIE_DAYS, CONSENT_SCHEMA_VERSION, CONSENT_LOCALES, CONSENT_ESSENTIAL, CONSENT_ANALYTICS, CONSENT_MARKETING, decorateConsentUrl, CONSENT_LANGUAGE_KEY, CONSENT_EVENT, encodeConsentLink, consentLinkerScript, CONSENT_LINK_PARAM, CONSENT_LINK_MAX_AGE, CONSENT_LINK_SKEW, consentStorageHelper, consentModeHelper, consentI18nHelper, consentPluginHelper, consentLinkHelper, } from '@owlmeans/consent';
|
|
9
|
+
export type { ConsentCategory, ConsentOptions, ConsentReason, ConsentRecord, ConsentService, ConsentSignal, ConsentState, ConsentStore, ConsentLocale, ConsentLinkerOptions, ConsentLinkerLanguage, ConsentPlugin, ConsentLinkPayload, ConsentStorageHelper, ConsentModeHelper, ConsentI18nHelper, ConsentPluginHelper, ConsentLinkHelper, } from '@owlmeans/consent';
|
|
10
10
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,mBAAmB,oBAAoB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,mBAAmB,oBAAoB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,sBAAsB,EACtB,0BAA0B,EAAE,wBAAwB,EAAE,uBAAuB,EAC7E,WAAW,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EACzE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EACvD,kBAAkB,EAAE,oBAAoB,EACxC,aAAa,EACb,iBAAiB,EAAE,mBAAmB,EACtC,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAC3D,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,GACnG,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAC5F,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,kBAAkB,EACzH,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,GACnG,MAAM,mBAAmB,CAAA"}
|
package/build/index.js
CHANGED
|
@@ -3,5 +3,5 @@ export * from './consent/component.js';
|
|
|
3
3
|
export * from './consent/widget.js';
|
|
4
4
|
export * from './consent/toggle.js';
|
|
5
5
|
export * from './policy/component.js';
|
|
6
|
-
export { consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent,
|
|
6
|
+
export { consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent, consentBootstrapScript, DEFAULT_CONSENT_CATEGORIES, DEFAULT_CONSENT_MESSAGES, defaultConsentTranslate, CONSENT_KEY, CONSENT_COOKIE_DAYS, CONSENT_SCHEMA_VERSION, CONSENT_LOCALES, CONSENT_ESSENTIAL, CONSENT_ANALYTICS, CONSENT_MARKETING, decorateConsentUrl, CONSENT_LANGUAGE_KEY, CONSENT_EVENT, encodeConsentLink, consentLinkerScript, CONSENT_LINK_PARAM, CONSENT_LINK_MAX_AGE, CONSENT_LINK_SKEW, consentStorageHelper, consentModeHelper, consentI18nHelper, consentPluginHelper, consentLinkHelper, } from '@owlmeans/consent';
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AAEnC,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,sBAAsB,EACtB,0BAA0B,EAAE,wBAAwB,EAAE,uBAAuB,EAC7E,WAAW,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EACzE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,EACvD,kBAAkB,EAAE,oBAAoB,EACxC,aAAa,EACb,iBAAiB,EAAE,mBAAmB,EACtC,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAC3D,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,GACnG,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ClassValue } from 'clsx';
|
|
2
|
+
import type { ConsentLinkerOptions } from '@owlmeans/consent';
|
|
3
|
+
/** What the dialog and the policy page share: class merging and the disclosed domains. */
|
|
4
|
+
export interface WebConsentUtils {
|
|
5
|
+
/**
|
|
6
|
+
* Class-name merge, owned by this package rather than reached through the `@` alias contract.
|
|
7
|
+
*
|
|
8
|
+
* The `@` contract exists so a consumer's own THEME and shadcn primitives win over a package's
|
|
9
|
+
* copies. `cn` has neither in it — it is four lines of string merging — and requiring an alias for
|
|
10
|
+
* it would mean every consumer of a consent dialog must first adopt an OwlMeans UI contract. One
|
|
11
|
+
* of the sites that needs this dialog most is an Astro site with its own component library and no
|
|
12
|
+
* such alias, so the dialog would simply fail to build there.
|
|
13
|
+
*/
|
|
14
|
+
cn: (...inputs: ClassValue[]) => string;
|
|
15
|
+
/**
|
|
16
|
+
* The domains one document's choice is disclosed as applying to: this host plus every domain
|
|
17
|
+
* `linker` names, deduplicated, current host first.
|
|
18
|
+
*
|
|
19
|
+
* Computed directly from `linker.domains` rather than through `@owlmeans/consent`'s
|
|
20
|
+
* `consentDomains()` registry helper: `CookieConsent` and `CookiePolicy` already have the
|
|
21
|
+
* configuration in hand as a prop, and a component that reads it straight has no reason to depend
|
|
22
|
+
* on whether `consentLinker` has finished registering itself yet (`consentStore.init` runs that
|
|
23
|
+
* registration from an effect, a render tick after mount). `consentDomains()` stays the right call
|
|
24
|
+
* for a caller that does NOT have `linker` in hand.
|
|
25
|
+
*/
|
|
26
|
+
disclosedDomains: (linker: ConsentLinkerOptions | undefined) => string[];
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AACtC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAE7D,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAC9B;;;;;;;;OAQG;IACH,EAAE,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,KAAK,MAAM,CAAA;IACvC;;;;;;;;;;OAUG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,oBAAoB,GAAG,SAAS,KAAK,MAAM,EAAE,CAAA;CACzE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/utils/types.ts"],"names":[],"mappings":""}
|
package/build/lib/utils.d.ts
CHANGED
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Class-name merge, owned by this package rather than reached through the `@` alias contract.
|
|
5
|
-
*
|
|
6
|
-
* The `@` contract exists so a consumer's own THEME and shadcn primitives win over a package's
|
|
7
|
-
* copies. `cn` has neither in it — it is four lines of string merging — and requiring an alias for
|
|
8
|
-
* it would mean every consumer of a consent dialog must first adopt an OwlMeans UI contract. One
|
|
9
|
-
* of the sites that needs this dialog most is an Astro site with its own component library and no
|
|
10
|
-
* such alias, so the dialog would simply fail to build there.
|
|
11
|
-
*/
|
|
12
|
-
export declare function cn(...inputs: ClassValue[]): string;
|
|
13
|
-
/**
|
|
14
|
-
* The domains one document's choice is disclosed as applying to: this host plus every domain
|
|
15
|
-
* `linker` names, deduplicated, current host first.
|
|
16
|
-
*
|
|
17
|
-
* Computed directly from `linker.domains` rather than through `@owlmeans/consent`'s
|
|
18
|
-
* `consentDomains()` registry helper: `CookieConsent` and `CookiePolicy` already have the
|
|
19
|
-
* configuration in hand as a prop, and a component that reads it straight has no reason to depend
|
|
20
|
-
* on whether `consentLinker` has finished registering itself yet (`consentStore.init` runs that
|
|
21
|
-
* registration from an effect, a render tick after mount). `consentDomains()` stays the right call
|
|
22
|
-
* for a caller that does NOT have `linker` in hand.
|
|
23
|
-
*/
|
|
24
|
-
export declare const disclosedDomains: (linker: ConsentLinkerOptions | undefined) => string[];
|
|
1
|
+
import type { WebConsentUtils } from './utils/types.js';
|
|
2
|
+
export declare const createWebConsentUtils: () => WebConsentUtils;
|
|
3
|
+
export declare const webConsentUtils: WebConsentUtils;
|
|
25
4
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/lib/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,eAAO,MAAM,qBAAqB,QAAO,eAUxC,CAAA;AAED,eAAO,MAAM,eAAe,iBAA0B,CAAA"}
|
package/build/lib/utils.js
CHANGED
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* such alias, so the dialog would simply fail to build there.
|
|
11
|
-
*/
|
|
12
|
-
export function cn(...inputs) {
|
|
13
|
-
return twMerge(clsx(inputs));
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* The domains one document's choice is disclosed as applying to: this host plus every domain
|
|
17
|
-
* `linker` names, deduplicated, current host first.
|
|
18
|
-
*
|
|
19
|
-
* Computed directly from `linker.domains` rather than through `@owlmeans/consent`'s
|
|
20
|
-
* `consentDomains()` registry helper: `CookieConsent` and `CookiePolicy` already have the
|
|
21
|
-
* configuration in hand as a prop, and a component that reads it straight has no reason to depend
|
|
22
|
-
* on whether `consentLinker` has finished registering itself yet (`consentStore.init` runs that
|
|
23
|
-
* registration from an effect, a render tick after mount). `consentDomains()` stays the right call
|
|
24
|
-
* for a caller that does NOT have `linker` in hand.
|
|
25
|
-
*/
|
|
26
|
-
export const disclosedDomains = (linker) => {
|
|
27
|
-
const host = typeof location !== 'undefined' ? location.hostname : '';
|
|
28
|
-
return [...new Set([host, ...(linker?.domains ?? [])].filter(domain => domain !== ''))];
|
|
3
|
+
export const createWebConsentUtils = () => {
|
|
4
|
+
const cn = (...inputs) => twMerge(clsx(inputs));
|
|
5
|
+
const disclosedDomains = (linker) => {
|
|
6
|
+
const host = typeof location !== 'undefined' ? location.hostname : '';
|
|
7
|
+
return [...new Set([host, ...(linker?.domains ?? [])].filter(domain => domain !== ''))];
|
|
8
|
+
};
|
|
9
|
+
return { cn, disclosedDomains };
|
|
29
10
|
};
|
|
11
|
+
export const webConsentUtils = createWebConsentUtils();
|
|
30
12
|
//# sourceMappingURL=utils.js.map
|
package/build/lib/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAIxC,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAoB,EAAE;IACzD,MAAM,EAAE,GAAG,CAAC,GAAG,MAAoB,EAAU,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IAErE,MAAM,gBAAgB,GAAG,CAAC,MAAwC,EAAY,EAAE;QAC9E,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;QAErE,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IACzF,CAAC,CAAA;IAED,OAAO,EAAE,EAAE,EAAE,gBAAgB,EAAE,CAAA;AACjC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,qBAAqB,EAAE,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/policy/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/policy/component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAK/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAwCpD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CA+E9C,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { CONSENT_COOKIE_DAYS, CONSENT_KEY, DEFAULT_CONSENT_CATEGORIES,
|
|
3
|
-
import {
|
|
2
|
+
import { CONSENT_COOKIE_DAYS, CONSENT_KEY, DEFAULT_CONSENT_CATEGORIES, consentStore, consentI18nHelper, } from '@owlmeans/consent';
|
|
3
|
+
import { webConsentUtils } from '../lib/utils.js';
|
|
4
4
|
/**
|
|
5
5
|
* The services one category gates, as a nested list inside that category's item.
|
|
6
6
|
*
|
|
@@ -8,7 +8,7 @@ import { cn, disclosedDomains } from '../lib/utils.js';
|
|
|
8
8
|
* categories are list items, and a service heading below them would either skip a level or
|
|
9
9
|
* promote a service above the category that governs it.
|
|
10
10
|
*/
|
|
11
|
-
const ServiceList = ({ services, label, category, t }) => _jsx("ul", { "aria-label": interpolate(t('policyServicesOf', 'Services — {{category}}'), { category: label }), "data-cookie-policy-services": category ?? '', children: services.map((service, index) => _jsxs("li", { "data-cookie-policy-service": true, children: [_jsx("strong", { children: service.name }), _jsxs("dl", { children: [_jsxs("div", { children: [_jsx("dt", { children: t('policyProvider', 'Provider') }), _jsx("dd", { children: service.provider })] }), service.purpose != null && service.purpose !== '' && _jsxs("div", { children: [_jsx("dt", { children: t('policyPurpose', 'Purpose') }), _jsx("dd", { children: service.purpose })] }), service.cookies != null && service.cookies.length > 0 && _jsxs("div", { children: [_jsx("dt", { children: t('policyCookies', 'Cookies') }), _jsx("dd", { children: service.cookies.map((cookie, at) => _jsxs("span", { children: [at > 0 && ', ', _jsx("code", { children: cookie })] }, `${cookie}-${at}`)) })] })] }), service.privacyHref != null && service.privacyHref !== '' && _jsx("a", { href: service.privacyHref, target: "_blank", rel: "noopener noreferrer", children: interpolate(t('policyServicePrivacy', '{{provider}} privacy policy'), { provider: service.provider }) })] }, `${service.name}-${index}`)) });
|
|
11
|
+
const ServiceList = ({ services, label, category, t }) => _jsx("ul", { "aria-label": consentI18nHelper.interpolate(t('policyServicesOf', 'Services — {{category}}'), { category: label }), "data-cookie-policy-services": category ?? '', children: services.map((service, index) => _jsxs("li", { "data-cookie-policy-service": true, children: [_jsx("strong", { children: service.name }), _jsxs("dl", { children: [_jsxs("div", { children: [_jsx("dt", { children: t('policyProvider', 'Provider') }), _jsx("dd", { children: service.provider })] }), service.purpose != null && service.purpose !== '' && _jsxs("div", { children: [_jsx("dt", { children: t('policyPurpose', 'Purpose') }), _jsx("dd", { children: service.purpose })] }), service.cookies != null && service.cookies.length > 0 && _jsxs("div", { children: [_jsx("dt", { children: t('policyCookies', 'Cookies') }), _jsx("dd", { children: service.cookies.map((cookie, at) => _jsxs("span", { children: [at > 0 && ', ', _jsx("code", { children: cookie })] }, `${cookie}-${at}`)) })] })] }), service.privacyHref != null && service.privacyHref !== '' && _jsx("a", { href: service.privacyHref, target: "_blank", rel: "noopener noreferrer", children: consentI18nHelper.interpolate(t('policyServicePrivacy', '{{provider}} privacy policy'), { provider: service.provider }) })] }, `${service.name}-${index}`)) });
|
|
12
12
|
/**
|
|
13
13
|
* A cookie policy that states only what this application can actually assert.
|
|
14
14
|
*
|
|
@@ -29,18 +29,18 @@ const ServiceList = ({ services, label, category, t }) => _jsx("ul", { "aria-lab
|
|
|
29
29
|
*/
|
|
30
30
|
export const CookiePolicy = props => {
|
|
31
31
|
const categories = props.categories ?? DEFAULT_CONSENT_CATEGORIES;
|
|
32
|
-
const t = props.translate ?? defaultConsentTranslate(props.locale);
|
|
32
|
+
const t = props.translate ?? consentI18nHelper.defaultConsentTranslate(props.locale);
|
|
33
33
|
const storageKey = props.storageKey ?? CONSENT_KEY;
|
|
34
34
|
const days = props.cookieDays ?? CONSENT_COOKIE_DAYS;
|
|
35
35
|
const services = props.services ?? [];
|
|
36
36
|
const keys = new Set(categories.map(category => category.key));
|
|
37
37
|
const other = services.filter(service => !keys.has(service.category));
|
|
38
38
|
const otherLabel = t('policyOtherServices', 'Other services');
|
|
39
|
-
const domains = disclosedDomains(props.linker);
|
|
40
|
-
return _jsxs("article", { className: cn('prose prose-sm max-w-2xl', props.className), "data-cookie-policy": true, children: [_jsx("h1", { children: t('policyTitle', 'Cookie Policy') }), _jsx("p", { children: t('policyIntro', 'This page describes the cookies and similar storage this application uses, and how you can control them.') }), _jsxs("ul", { children: [categories.map(category => {
|
|
39
|
+
const domains = webConsentUtils.disclosedDomains(props.linker);
|
|
40
|
+
return _jsxs("article", { className: webConsentUtils.cn('prose prose-sm max-w-2xl', props.className), "data-cookie-policy": true, children: [_jsx("h1", { children: t('policyTitle', 'Cookie Policy') }), _jsx("p", { children: t('policyIntro', 'This page describes the cookies and similar storage this application uses, and how you can control them.') }), _jsxs("ul", { children: [categories.map(category => {
|
|
41
41
|
const label = t(category.labelKey, category.key);
|
|
42
42
|
const gated = services.filter(service => service.category === category.key);
|
|
43
43
|
return _jsxs("li", { "data-cookie-policy-category": category.key, children: [_jsx("strong", { children: label }), category.required === true && _jsxs(_Fragment, { children: [" \u2014 ", t('required', 'Required')] }), _jsx("br", {}), t(category.descriptionKey, ''), gated.length > 0 && _jsx(ServiceList, { services: gated, label: label, category: category.key, t: t })] }, category.key);
|
|
44
|
-
}), other.length > 0 && _jsxs("li", { "data-cookie-policy-other": true, children: [_jsx("strong", { children: otherLabel }), _jsx("br", {}), t('policyOtherServicesDesc', 'Services this application runs outside the categories above.'), _jsx(ServiceList, { services: other, label: otherLabel, t: t })] }, " other")] }), _jsx("p", { children: interpolate(t('policyStorage', 'Your choice is stored in this browser under "{{key}}", both in local storage and as a cookie.'), { key: storageKey }) }), domains.length > 1 && _jsxs(_Fragment, { children: [_jsx("p", { children: t('policyDomains', 'This choice applies across these domains:') }), _jsx("ul", { "data-cookie-policy-domains": true, children: domains.map(domain => _jsx("li", { children: domain }, domain)) })] }), _jsx("p", { children: interpolate(t('policyRetention', 'The record is kept for {{days}} days, after which you will be asked again.'), { days }) }), props.operator != null && props.operator !== '' && _jsxs("p", { children: [interpolate(t('policyOperator', 'This application is operated by {{operator}}.'), { operator: props.operator }), ' ', t('policyContact', 'See their privacy policy and terms for how they handle your data.')] }), _jsxs("p", { children: [props.privacyHref != null && props.privacyHref !== '' && _jsx("a", { href: props.privacyHref, target: "_blank", rel: "noopener noreferrer", children: t('privacy', 'Privacy Policy') }), props.privacyHref != null && props.termsHref != null && ' · ', props.termsHref != null && props.termsHref !== '' && _jsx("a", { href: props.termsHref, target: "_blank", rel: "noopener noreferrer", children: t('terms', 'Terms & Conditions') })] }), _jsx("p", { children: _jsx("button", { type: "button", onClick: () =>
|
|
44
|
+
}), other.length > 0 && _jsxs("li", { "data-cookie-policy-other": true, children: [_jsx("strong", { children: otherLabel }), _jsx("br", {}), t('policyOtherServicesDesc', 'Services this application runs outside the categories above.'), _jsx(ServiceList, { services: other, label: otherLabel, t: t })] }, " other")] }), _jsx("p", { children: consentI18nHelper.interpolate(t('policyStorage', 'Your choice is stored in this browser under "{{key}}", both in local storage and as a cookie.'), { key: storageKey }) }), domains.length > 1 && _jsxs(_Fragment, { children: [_jsx("p", { children: t('policyDomains', 'This choice applies across these domains:') }), _jsx("ul", { "data-cookie-policy-domains": true, children: domains.map(domain => _jsx("li", { children: domain }, domain)) })] }), _jsx("p", { children: consentI18nHelper.interpolate(t('policyRetention', 'The record is kept for {{days}} days, after which you will be asked again.'), { days }) }), props.operator != null && props.operator !== '' && _jsxs("p", { children: [consentI18nHelper.interpolate(t('policyOperator', 'This application is operated by {{operator}}.'), { operator: props.operator }), ' ', t('policyContact', 'See their privacy policy and terms for how they handle your data.')] }), _jsxs("p", { children: [props.privacyHref != null && props.privacyHref !== '' && _jsx("a", { href: props.privacyHref, target: "_blank", rel: "noopener noreferrer", children: t('privacy', 'Privacy Policy') }), props.privacyHref != null && props.termsHref != null && ' · ', props.termsHref != null && props.termsHref !== '' && _jsx("a", { href: props.termsHref, target: "_blank", rel: "noopener noreferrer", children: t('terms', 'Terms & Conditions') })] }), _jsx("p", { children: _jsx("button", { type: "button", onClick: () => consentStore.open('reopen'), "data-cookie-policy-manage": true, className: "not-prose inline-flex min-h-11 items-center justify-center rounded-full border-[1.5px] border-foreground bg-transparent px-6 py-2.5 text-[15px] font-semibold text-foreground transition-colors hover:bg-muted focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-ring", children: t('manage', 'Manage preferences') }) })] });
|
|
45
45
|
};
|
|
46
46
|
//# sourceMappingURL=component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/policy/component.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,mBAAmB,EAAE,WAAW,EAAE,0BAA0B,
|
|
1
|
+
{"version":3,"file":"component.js","sourceRoot":"","sources":["../../src/policy/component.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ConsentService } from '@owlmeans/consent';
|
|
2
|
-
export
|
|
2
|
+
export interface Translate {
|
|
3
|
+
(key: string, defaultValue: string): string;
|
|
4
|
+
}
|
|
3
5
|
export interface ServiceListProps {
|
|
4
6
|
services: ConsentService[];
|
|
5
7
|
/** The category's own label, already resolved — it names the list for assistive technology. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../../src/policy/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,
|
|
1
|
+
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../../src/policy/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD,MAAM,WAAW,SAAS;IAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE;AAE1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAA;IACb,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,CAAC,EAAE,SAAS,CAAA;CACb"}
|
package/build/types.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export interface ConsentMenuWidgetProps {
|
|
|
53
53
|
translate?: (key: string, defaultValue: string) => string;
|
|
54
54
|
label?: string;
|
|
55
55
|
className?: string;
|
|
56
|
-
/** Defaults to `
|
|
56
|
+
/** Defaults to `consentStore.open('reopen')` — the same call the floating button itself makes. */
|
|
57
57
|
onSelect?: () => void;
|
|
58
58
|
}
|
|
59
59
|
export interface UseConsentModel {
|
package/build/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAAE,oBAAoB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EACpF,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,uFAAuF;IACvF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wFAAwF;IACxF,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gGAAgG;IAChG,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iGAAiG;IACjG,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uFAAuF;IACvF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAAE,oBAAoB,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EACpF,MAAM,mBAAmB,CAAA;AAE1B,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,uFAAuF;IACvF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mEAAmE;IACnE,KAAK,CAAC,EAAE,WAAW,EAAE,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,wFAAwF;IACxF,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gGAAgG;IAChG,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;IAC9B,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,iGAAiG;IACjG,MAAM,CAAC,EAAE,oBAAoB,CAAA;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uFAAuF;IACvF,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,MAAM,CAAA;IACzD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;IAC5B,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;IAC5B,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IACjC,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAA;IACrC,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,aAAa,KAAK,IAAI,CAAA;IAC5C,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/web-consent",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.42",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@owlmeans/consent": "^0.1.18-rc.
|
|
25
|
+
"@owlmeans/consent": "^0.1.18-rc.11"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"clsx": "*",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@owlmeans/dep-config": "workspace:*",
|
|
36
|
-
"@owlmeans/test-ui": "^0.1.18-rc.
|
|
36
|
+
"@owlmeans/test-ui": "^0.1.18-rc.49",
|
|
37
37
|
"@tailwindcss/vite": "^4.3.3",
|
|
38
38
|
"@types/bun": "^1.4.2",
|
|
39
39
|
"@types/react": "^19.3.0",
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState, type FC } from 'react'
|
|
2
2
|
import { Cookie } from 'lucide-react'
|
|
3
|
-
import { DEFAULT_CONSENT_CATEGORIES,
|
|
4
|
-
import {
|
|
3
|
+
import { DEFAULT_CONSENT_CATEGORIES, type ConsentRecord, consentI18nHelper, consentStorageHelper } from '@owlmeans/consent'
|
|
4
|
+
import { webConsentUtils } from '../lib/utils.js'
|
|
5
5
|
import { useConsent } from '../hooks.js'
|
|
6
6
|
import { ConsentToggle } from './toggle.js'
|
|
7
7
|
import type { CookieConsentProps } from '../types.js'
|
|
8
8
|
import { FOCUS } from './consts.local.js'
|
|
9
9
|
|
|
10
10
|
/** A pill button: 44px tall at minimum, full width on a phone, sharing the row above that. */
|
|
11
|
-
const PILL = cn(
|
|
11
|
+
const PILL = webConsentUtils.cn(
|
|
12
12
|
'inline-flex min-h-11 flex-1 items-center justify-center rounded-full px-6 py-2.5 text-[15px] transition-colors motion-safe:active:scale-[0.98]',
|
|
13
13
|
FOCUS
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
/** A text link: muted, underlined at rest (colour is never the only signal), 44px tall to tap. */
|
|
17
|
-
const LINK = cn(
|
|
17
|
+
const LINK = webConsentUtils.cn(
|
|
18
18
|
'inline-flex min-h-11 items-center font-semibold underline decoration-1 underline-offset-4 transition-colors hover:text-foreground hover:decoration-2',
|
|
19
19
|
FOCUS
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
23
23
|
const categories = props.categories ?? DEFAULT_CONSENT_CATEGORIES
|
|
24
|
-
const t = props.translate ?? defaultConsentTranslate(props.locale)
|
|
24
|
+
const t = props.translate ?? consentI18nHelper.defaultConsentTranslate(props.locale)
|
|
25
25
|
|
|
26
26
|
const consentOpts = {
|
|
27
27
|
categories,
|
|
@@ -32,7 +32,7 @@ export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
|
32
32
|
...(props.linker != null ? { linker: props.linker } : {}),
|
|
33
33
|
}
|
|
34
34
|
const consent = useConsent(consentOpts)
|
|
35
|
-
const domains = disclosedDomains(props.linker)
|
|
35
|
+
const domains = webConsentUtils.disclosedDomains(props.linker)
|
|
36
36
|
|
|
37
37
|
const optional = categories.filter(category => category.required !== true)
|
|
38
38
|
const [draft, setDraft] = useState<Record<string, boolean>>({})
|
|
@@ -43,7 +43,7 @@ export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
|
43
43
|
if (!consent.open) {
|
|
44
44
|
return
|
|
45
45
|
}
|
|
46
|
-
const stored = consent.record ?? readConsent({
|
|
46
|
+
const stored = consent.record ?? consentStorageHelper.readConsent({
|
|
47
47
|
...(props.storageKey != null ? { storageKey: props.storageKey } : {}),
|
|
48
48
|
})
|
|
49
49
|
setDraft(Object.fromEntries(optional.map(category =>
|
|
@@ -75,7 +75,7 @@ export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
|
75
75
|
aria-describedby={domains.length > 1 ? 'cc-desc cc-domains' : 'cc-desc'}
|
|
76
76
|
data-consent-dialog
|
|
77
77
|
>
|
|
78
|
-
<div className={cn(
|
|
78
|
+
<div className={webConsentUtils.cn(
|
|
79
79
|
'relative z-[999999] w-full max-w-lg rounded-3xl border border-border bg-background p-6 text-foreground sm:p-8',
|
|
80
80
|
props.className
|
|
81
81
|
)}>
|
|
@@ -96,7 +96,7 @@ export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
|
96
96
|
id="cc-domains" data-consent-domains
|
|
97
97
|
className="mb-6 -mt-3 text-pretty text-xs text-muted-foreground"
|
|
98
98
|
>
|
|
99
|
-
{interpolate(t('domains', 'This choice applies to {{domains}}.'), { domains: domains.join(', ') })}
|
|
99
|
+
{consentI18nHelper.interpolate(t('domains', 'This choice applies to {{domains}}.'), { domains: domains.join(', ') })}
|
|
100
100
|
</p>}
|
|
101
101
|
|
|
102
102
|
<div className="space-y-3">
|
|
@@ -119,11 +119,11 @@ export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
|
119
119
|
<div className="mt-8 flex flex-col gap-3 sm:flex-row sm:gap-4">
|
|
120
120
|
<button
|
|
121
121
|
type="button" onClick={onSave} data-consent-save
|
|
122
|
-
className={cn(PILL, 'border-[1.5px] border-foreground bg-transparent font-semibold text-foreground hover:bg-muted')}
|
|
122
|
+
className={webConsentUtils.cn(PILL, 'border-[1.5px] border-foreground bg-transparent font-semibold text-foreground hover:bg-muted')}
|
|
123
123
|
>{t('savePreferences', 'Save Preferences')}</button>
|
|
124
124
|
<button
|
|
125
125
|
type="button" onClick={onAcceptAll} data-consent-accept-all
|
|
126
|
-
className={cn(PILL, 'bg-primary font-bold text-primary-foreground hover:bg-primary/90')}
|
|
126
|
+
className={webConsentUtils.cn(PILL, 'bg-primary font-bold text-primary-foreground hover:bg-primary/90')}
|
|
127
127
|
>{gated
|
|
128
128
|
? t('acceptAndContinue', 'Accept & continue')
|
|
129
129
|
: t('acceptAll', 'Accept All')}</button>
|
|
@@ -152,7 +152,7 @@ export const CookieConsent: FC<CookieConsentProps> = props => {
|
|
|
152
152
|
type="button" onClick={() => consent.openDialog('reopen')}
|
|
153
153
|
aria-label={t('openPreferences', 'Cookie preferences')}
|
|
154
154
|
data-consent-reopen
|
|
155
|
-
className={cn('fixed bottom-1 left-1 z-[999997] inline-flex h-11 w-11 items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground opacity-70 transition-opacity hover:opacity-100 hover:text-primary focus-visible:opacity-100', FOCUS)}
|
|
155
|
+
className={webConsentUtils.cn('fixed bottom-1 left-1 z-[999997] inline-flex h-11 w-11 items-center justify-center rounded border-0 bg-transparent p-0 text-muted-foreground opacity-70 transition-opacity hover:opacity-100 hover:text-primary focus-visible:opacity-100', FOCUS)}
|
|
156
156
|
>
|
|
157
157
|
<Cookie className="h-5 w-5" aria-hidden="true" />
|
|
158
158
|
</button>}
|
package/src/consent/toggle.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FC } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { webConsentUtils } from '../lib/utils.js'
|
|
3
3
|
import type { ConsentToggleProps } from './types.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -38,7 +38,7 @@ export const ConsentToggle: FC<ConsentToggleProps> = (
|
|
|
38
38
|
id={`${id}-desc`} className="text-pretty text-xs leading-relaxed text-muted-foreground"
|
|
39
39
|
>{description}</p>}
|
|
40
40
|
</div>
|
|
41
|
-
<label className={cn(
|
|
41
|
+
<label className={webConsentUtils.cn(
|
|
42
42
|
'relative inline-flex h-11 w-14 flex-shrink-0 items-center justify-center',
|
|
43
43
|
required === true ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'
|
|
44
44
|
)}>
|
|
@@ -52,11 +52,11 @@ export const ConsentToggle: FC<ConsentToggleProps> = (
|
|
|
52
52
|
disabled={required === true}
|
|
53
53
|
onChange={event => onChange(event.target.checked)}
|
|
54
54
|
/>
|
|
55
|
-
<span className={cn(
|
|
55
|
+
<span className={webConsentUtils.cn(
|
|
56
56
|
'relative h-6 w-11 rounded-full transition-colors duration-300 peer-focus-visible:outline-3 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-ring',
|
|
57
57
|
checked || required === true ? 'bg-primary' : 'bg-muted-foreground/40'
|
|
58
58
|
)}>
|
|
59
|
-
<span className={cn(
|
|
59
|
+
<span className={webConsentUtils.cn(
|
|
60
60
|
'absolute top-0.5 left-0 h-5 w-5 rounded-full bg-white transition-transform duration-300',
|
|
61
61
|
checked || required === true ? 'translate-x-5' : 'translate-x-0.5'
|
|
62
62
|
)} />
|
package/src/consent/widget.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useCallback } from 'react'
|
|
2
2
|
import type { FC } from 'react'
|
|
3
3
|
import { Cookie } from 'lucide-react'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { consentStore, consentI18nHelper } from '@owlmeans/consent'
|
|
5
|
+
import { webConsentUtils } from '../lib/utils.js'
|
|
6
6
|
import type { ConsentMenuWidgetProps } from '../types.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -16,23 +16,23 @@ import type { ConsentMenuWidgetProps } from '../types.js'
|
|
|
16
16
|
* button while this row is reachable announces that from whatever component of its own stays
|
|
17
17
|
* mounted for the menu's whole lifetime — see `useConsentMenuPresence` in `@owlmeans/web-panel/consent`.
|
|
18
18
|
*
|
|
19
|
-
* Uses `
|
|
19
|
+
* Uses `consentStore.open` directly rather than the `useConsent()` hook: that hook's mount itself
|
|
20
20
|
* triggers `consentStore.init()`, which a row that only needs to trigger a reopen must not do.
|
|
21
21
|
*/
|
|
22
22
|
export const ConsentMenuWidget: FC<ConsentMenuWidgetProps> = props => {
|
|
23
|
-
const t = props.translate ?? defaultConsentTranslate(props.locale)
|
|
23
|
+
const t = props.translate ?? consentI18nHelper.defaultConsentTranslate(props.locale)
|
|
24
24
|
|
|
25
25
|
const onClick = useCallback(() => {
|
|
26
26
|
if (props.onSelect != null) {
|
|
27
27
|
props.onSelect()
|
|
28
28
|
return
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
consentStore.open('reopen')
|
|
31
31
|
}, [props.onSelect])
|
|
32
32
|
|
|
33
33
|
return <button
|
|
34
34
|
type="button" onClick={onClick} data-consent-menu-widget
|
|
35
|
-
className={cn(
|
|
35
|
+
className={webConsentUtils.cn(
|
|
36
36
|
'flex w-full min-w-0 items-center gap-2 rounded-md text-left text-sm text-popover-foreground transition-colors hover:bg-accent',
|
|
37
37
|
props.className
|
|
38
38
|
)}
|
package/src/index.ts
CHANGED
|
@@ -8,18 +8,18 @@ export * from './policy/component.js'
|
|
|
8
8
|
|
|
9
9
|
export {
|
|
10
10
|
consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
DEFAULT_CONSENT_CATEGORIES, DEFAULT_CONSENT_MESSAGES, defaultConsentTranslate, interpolate,
|
|
11
|
+
consentBootstrapScript,
|
|
12
|
+
DEFAULT_CONSENT_CATEGORIES, DEFAULT_CONSENT_MESSAGES, defaultConsentTranslate,
|
|
14
13
|
CONSENT_KEY, CONSENT_COOKIE_DAYS, CONSENT_SCHEMA_VERSION, CONSENT_LOCALES,
|
|
15
14
|
CONSENT_ESSENTIAL, CONSENT_ANALYTICS, CONSENT_MARKETING,
|
|
16
|
-
|
|
17
|
-
startConsentPlugins, adoptConsentLanguage, writeConsentLanguage, CONSENT_LANGUAGE_KEY,
|
|
15
|
+
decorateConsentUrl, CONSENT_LANGUAGE_KEY,
|
|
18
16
|
CONSENT_EVENT,
|
|
19
|
-
|
|
17
|
+
encodeConsentLink, consentLinkerScript,
|
|
20
18
|
CONSENT_LINK_PARAM, CONSENT_LINK_MAX_AGE, CONSENT_LINK_SKEW,
|
|
19
|
+
consentStorageHelper, consentModeHelper, consentI18nHelper, consentPluginHelper, consentLinkHelper,
|
|
21
20
|
} from '@owlmeans/consent'
|
|
22
21
|
export type {
|
|
23
22
|
ConsentCategory, ConsentOptions, ConsentReason, ConsentRecord, ConsentService, ConsentSignal,
|
|
24
23
|
ConsentState, ConsentStore, ConsentLocale, ConsentLinkerOptions, ConsentLinkerLanguage, ConsentPlugin, ConsentLinkPayload,
|
|
24
|
+
ConsentStorageHelper, ConsentModeHelper, ConsentI18nHelper, ConsentPluginHelper, ConsentLinkHelper,
|
|
25
25
|
} from '@owlmeans/consent'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ClassValue } from 'clsx'
|
|
2
|
+
import type { ConsentLinkerOptions } from '@owlmeans/consent'
|
|
3
|
+
|
|
4
|
+
/** What the dialog and the policy page share: class merging and the disclosed domains. */
|
|
5
|
+
export interface WebConsentUtils {
|
|
6
|
+
/**
|
|
7
|
+
* Class-name merge, owned by this package rather than reached through the `@` alias contract.
|
|
8
|
+
*
|
|
9
|
+
* The `@` contract exists so a consumer's own THEME and shadcn primitives win over a package's
|
|
10
|
+
* copies. `cn` has neither in it — it is four lines of string merging — and requiring an alias for
|
|
11
|
+
* it would mean every consumer of a consent dialog must first adopt an OwlMeans UI contract. One
|
|
12
|
+
* of the sites that needs this dialog most is an Astro site with its own component library and no
|
|
13
|
+
* such alias, so the dialog would simply fail to build there.
|
|
14
|
+
*/
|
|
15
|
+
cn: (...inputs: ClassValue[]) => string
|
|
16
|
+
/**
|
|
17
|
+
* The domains one document's choice is disclosed as applying to: this host plus every domain
|
|
18
|
+
* `linker` names, deduplicated, current host first.
|
|
19
|
+
*
|
|
20
|
+
* Computed directly from `linker.domains` rather than through `@owlmeans/consent`'s
|
|
21
|
+
* `consentDomains()` registry helper: `CookieConsent` and `CookiePolicy` already have the
|
|
22
|
+
* configuration in hand as a prop, and a component that reads it straight has no reason to depend
|
|
23
|
+
* on whether `consentLinker` has finished registering itself yet (`consentStore.init` runs that
|
|
24
|
+
* registration from an effect, a render tick after mount). `consentDomains()` stays the right call
|
|
25
|
+
* for a caller that does NOT have `linker` in hand.
|
|
26
|
+
*/
|
|
27
|
+
disclosedDomains: (linker: ConsentLinkerOptions | undefined) => string[]
|
|
28
|
+
}
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
1
|
import { clsx, type ClassValue } from 'clsx'
|
|
2
2
|
import { twMerge } from 'tailwind-merge'
|
|
3
3
|
import type { ConsentLinkerOptions } from '@owlmeans/consent'
|
|
4
|
+
import type { WebConsentUtils } from './utils/types.js'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* it would mean every consumer of a consent dialog must first adopt an OwlMeans UI contract. One
|
|
11
|
-
* of the sites that needs this dialog most is an Astro site with its own component library and no
|
|
12
|
-
* such alias, so the dialog would simply fail to build there.
|
|
13
|
-
*/
|
|
14
|
-
export function cn(...inputs: ClassValue[]) {
|
|
15
|
-
return twMerge(clsx(inputs))
|
|
16
|
-
}
|
|
6
|
+
export const createWebConsentUtils = (): WebConsentUtils => {
|
|
7
|
+
const cn = (...inputs: ClassValue[]): string => twMerge(clsx(inputs))
|
|
8
|
+
|
|
9
|
+
const disclosedDomains = (linker: ConsentLinkerOptions | undefined): string[] => {
|
|
10
|
+
const host = typeof location !== 'undefined' ? location.hostname : ''
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
* `linker` names, deduplicated, current host first.
|
|
21
|
-
*
|
|
22
|
-
* Computed directly from `linker.domains` rather than through `@owlmeans/consent`'s
|
|
23
|
-
* `consentDomains()` registry helper: `CookieConsent` and `CookiePolicy` already have the
|
|
24
|
-
* configuration in hand as a prop, and a component that reads it straight has no reason to depend
|
|
25
|
-
* on whether `consentLinker` has finished registering itself yet (`consentStore.init` runs that
|
|
26
|
-
* registration from an effect, a render tick after mount). `consentDomains()` stays the right call
|
|
27
|
-
* for a caller that does NOT have `linker` in hand.
|
|
28
|
-
*/
|
|
29
|
-
export const disclosedDomains = (linker: ConsentLinkerOptions | undefined): string[] => {
|
|
30
|
-
const host = typeof location !== 'undefined' ? location.hostname : ''
|
|
12
|
+
return [...new Set([host, ...(linker?.domains ?? [])].filter(domain => domain !== ''))]
|
|
13
|
+
}
|
|
31
14
|
|
|
32
|
-
return
|
|
15
|
+
return { cn, disclosedDomains }
|
|
33
16
|
}
|
|
17
|
+
|
|
18
|
+
export const webConsentUtils = createWebConsentUtils()
|
package/src/policy/component.tsx
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { FC } from 'react'
|
|
2
2
|
import {
|
|
3
|
-
CONSENT_COOKIE_DAYS, CONSENT_KEY, DEFAULT_CONSENT_CATEGORIES,
|
|
4
|
-
defaultConsentTranslate, interpolate, openConsent,
|
|
3
|
+
CONSENT_COOKIE_DAYS, CONSENT_KEY, DEFAULT_CONSENT_CATEGORIES, consentStore, consentI18nHelper,
|
|
5
4
|
} from '@owlmeans/consent'
|
|
6
|
-
import {
|
|
5
|
+
import { webConsentUtils } from '../lib/utils.js'
|
|
7
6
|
import type { CookiePolicyProps } from '../types.js'
|
|
8
7
|
import type { ServiceListProps } from './types.local.js'
|
|
9
8
|
|
|
@@ -16,7 +15,7 @@ import type { ServiceListProps } from './types.local.js'
|
|
|
16
15
|
*/
|
|
17
16
|
const ServiceList: FC<ServiceListProps> = ({ services, label, category, t }) =>
|
|
18
17
|
<ul
|
|
19
|
-
aria-label={interpolate(t('policyServicesOf', 'Services — {{category}}'), { category: label })}
|
|
18
|
+
aria-label={consentI18nHelper.interpolate(t('policyServicesOf', 'Services — {{category}}'), { category: label })}
|
|
20
19
|
data-cookie-policy-services={category ?? ''}
|
|
21
20
|
>
|
|
22
21
|
{services.map((service, index) => <li key={`${service.name}-${index}`} data-cookie-policy-service>
|
|
@@ -39,7 +38,7 @@ const ServiceList: FC<ServiceListProps> = ({ services, label, category, t }) =>
|
|
|
39
38
|
</dl>
|
|
40
39
|
{service.privacyHref != null && service.privacyHref !== '' && <a
|
|
41
40
|
href={service.privacyHref} target="_blank" rel="noopener noreferrer"
|
|
42
|
-
>{interpolate(t('policyServicePrivacy', '{{provider}} privacy policy'),
|
|
41
|
+
>{consentI18nHelper.interpolate(t('policyServicePrivacy', '{{provider}} privacy policy'),
|
|
43
42
|
{ provider: service.provider })}</a>}
|
|
44
43
|
</li>)}
|
|
45
44
|
</ul>
|
|
@@ -64,16 +63,16 @@ const ServiceList: FC<ServiceListProps> = ({ services, label, category, t }) =>
|
|
|
64
63
|
*/
|
|
65
64
|
export const CookiePolicy: FC<CookiePolicyProps> = props => {
|
|
66
65
|
const categories = props.categories ?? DEFAULT_CONSENT_CATEGORIES
|
|
67
|
-
const t = props.translate ?? defaultConsentTranslate(props.locale)
|
|
66
|
+
const t = props.translate ?? consentI18nHelper.defaultConsentTranslate(props.locale)
|
|
68
67
|
const storageKey = props.storageKey ?? CONSENT_KEY
|
|
69
68
|
const days = props.cookieDays ?? CONSENT_COOKIE_DAYS
|
|
70
69
|
const services = props.services ?? []
|
|
71
70
|
const keys = new Set(categories.map(category => category.key))
|
|
72
71
|
const other = services.filter(service => !keys.has(service.category))
|
|
73
72
|
const otherLabel = t('policyOtherServices', 'Other services')
|
|
74
|
-
const domains = disclosedDomains(props.linker)
|
|
73
|
+
const domains = webConsentUtils.disclosedDomains(props.linker)
|
|
75
74
|
|
|
76
|
-
return <article className={cn('prose prose-sm max-w-2xl', props.className)} data-cookie-policy>
|
|
75
|
+
return <article className={webConsentUtils.cn('prose prose-sm max-w-2xl', props.className)} data-cookie-policy>
|
|
77
76
|
<h1>{t('policyTitle', 'Cookie Policy')}</h1>
|
|
78
77
|
<p>{t('policyIntro', 'This page describes the cookies and similar storage this application uses, and how you can control them.')}</p>
|
|
79
78
|
|
|
@@ -98,7 +97,7 @@ export const CookiePolicy: FC<CookiePolicyProps> = props => {
|
|
|
98
97
|
</li>}
|
|
99
98
|
</ul>
|
|
100
99
|
|
|
101
|
-
<p>{interpolate(
|
|
100
|
+
<p>{consentI18nHelper.interpolate(
|
|
102
101
|
t('policyStorage', 'Your choice is stored in this browser under "{{key}}", both in local storage and as a cookie.'),
|
|
103
102
|
{ key: storageKey }
|
|
104
103
|
)}</p>
|
|
@@ -110,13 +109,13 @@ export const CookiePolicy: FC<CookiePolicyProps> = props => {
|
|
|
110
109
|
</ul>
|
|
111
110
|
</>}
|
|
112
111
|
|
|
113
|
-
<p>{interpolate(
|
|
112
|
+
<p>{consentI18nHelper.interpolate(
|
|
114
113
|
t('policyRetention', 'The record is kept for {{days}} days, after which you will be asked again.'),
|
|
115
114
|
{ days }
|
|
116
115
|
)}</p>
|
|
117
116
|
|
|
118
117
|
{props.operator != null && props.operator !== '' && <p>
|
|
119
|
-
{interpolate(t('policyOperator', 'This application is operated by {{operator}}.'),
|
|
118
|
+
{consentI18nHelper.interpolate(t('policyOperator', 'This application is operated by {{operator}}.'),
|
|
120
119
|
{ operator: props.operator })}
|
|
121
120
|
{' '}
|
|
122
121
|
{t('policyContact', 'See their privacy policy and terms for how they handle your data.')}
|
|
@@ -134,7 +133,7 @@ export const CookiePolicy: FC<CookiePolicyProps> = props => {
|
|
|
134
133
|
|
|
135
134
|
<p>
|
|
136
135
|
<button
|
|
137
|
-
type="button" onClick={() =>
|
|
136
|
+
type="button" onClick={() => consentStore.open('reopen')} data-cookie-policy-manage
|
|
138
137
|
className="not-prose inline-flex min-h-11 items-center justify-center rounded-full border-[1.5px] border-foreground bg-transparent px-6 py-2.5 text-[15px] font-semibold text-foreground transition-colors hover:bg-muted focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-ring"
|
|
139
138
|
>
|
|
140
139
|
{t('manage', 'Manage preferences')}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ConsentService } from '@owlmeans/consent'
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export interface Translate { (key: string, defaultValue: string): string }
|
|
4
4
|
|
|
5
5
|
export interface ServiceListProps {
|
|
6
6
|
services: ConsentService[]
|
package/src/types.ts
CHANGED
|
@@ -59,7 +59,7 @@ export interface ConsentMenuWidgetProps {
|
|
|
59
59
|
translate?: (key: string, defaultValue: string) => string
|
|
60
60
|
label?: string
|
|
61
61
|
className?: string
|
|
62
|
-
/** Defaults to `
|
|
62
|
+
/** Defaults to `consentStore.open('reopen')` — the same call the floating button itself makes. */
|
|
63
63
|
onSelect?: () => void
|
|
64
64
|
}
|
|
65
65
|
|
package/tests/a11y.spec.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
3
|
import type { Page } from 'playwright'
|
|
4
|
-
import {
|
|
4
|
+
import { mountComponent, browserHelper } from '@owlmeans/test-ui'
|
|
5
5
|
import { CONSENT_KEY, CONSENT_SCHEMA_VERSION } from '@owlmeans/consent'
|
|
6
6
|
import { HARNESS_URL } from './context.js'
|
|
7
7
|
|
|
8
8
|
const TIMEOUT = 60_000
|
|
9
9
|
|
|
10
10
|
afterAll(async () => {
|
|
11
|
-
await closeBrowser()
|
|
11
|
+
await browserHelper.closeBrowser()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
const base = HARNESS_URL.replace(/\/$/, '')
|
package/tests/consent.spec.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
CONSENT_KEY, CONSENT_LOCALES, CONSENT_SCHEMA_VERSION, defaultConsentTranslate,
|
|
5
|
-
} from '@owlmeans/consent'
|
|
2
|
+
import { mountComponent, browserHelper } from '@owlmeans/test-ui'
|
|
3
|
+
import { CONSENT_KEY, CONSENT_LOCALES, CONSENT_SCHEMA_VERSION, consentI18nHelper } from '@owlmeans/consent'
|
|
6
4
|
import { HARNESS_URL } from './context.js'
|
|
7
5
|
|
|
8
6
|
// Browser work does not fit the 5s default: a cold harness compiles the app on first request.
|
|
9
7
|
const TIMEOUT = 60_000
|
|
10
8
|
|
|
11
9
|
afterAll(async () => {
|
|
12
|
-
await closeBrowser()
|
|
10
|
+
await browserHelper.closeBrowser()
|
|
13
11
|
})
|
|
14
12
|
|
|
15
13
|
const base = HARNESS_URL.replace(/\/$/, '')
|
|
@@ -275,7 +273,7 @@ describe('@owlmeans/web-consent — the dialog', () => {
|
|
|
275
273
|
expect(text).not.toContain('consent.')
|
|
276
274
|
expect(text.length).toBeGreaterThan(40)
|
|
277
275
|
// And it is genuinely THAT language's wording, not English shown seven times.
|
|
278
|
-
expect(text).toContain(defaultConsentTranslate(locale)('consent.title', ''))
|
|
276
|
+
expect(text).toContain(consentI18nHelper.defaultConsentTranslate(locale)('consent.title', ''))
|
|
279
277
|
} finally {
|
|
280
278
|
await close()
|
|
281
279
|
}
|
|
@@ -361,9 +359,9 @@ describe('@owlmeans/web-consent — the policy page', () => {
|
|
|
361
359
|
await analytics.waitFor()
|
|
362
360
|
const text = await analytics.innerText()
|
|
363
361
|
|
|
364
|
-
expect(text).toContain(defaultConsentTranslate('de')('policyProvider', ''))
|
|
365
|
-
expect(text).toContain(defaultConsentTranslate('de')('policyPurpose', ''))
|
|
366
|
-
expect(defaultConsentTranslate('de')('policyProvider', '')).not.toBe('Provider')
|
|
362
|
+
expect(text).toContain(consentI18nHelper.defaultConsentTranslate('de')('policyProvider', ''))
|
|
363
|
+
expect(text).toContain(consentI18nHelper.defaultConsentTranslate('de')('policyPurpose', ''))
|
|
364
|
+
expect(consentI18nHelper.defaultConsentTranslate('de')('policyProvider', '')).not.toBe('Provider')
|
|
367
365
|
} finally {
|
|
368
366
|
await close()
|
|
369
367
|
}
|
|
@@ -374,7 +372,7 @@ describe('@owlmeans/web-consent — the policy page', () => {
|
|
|
374
372
|
try {
|
|
375
373
|
const policy = page.locator('[data-cookie-policy]')
|
|
376
374
|
await policy.waitFor()
|
|
377
|
-
const de = defaultConsentTranslate('de')
|
|
375
|
+
const de = consentI18nHelper.defaultConsentTranslate('de')
|
|
378
376
|
|
|
379
377
|
expect(await policy.locator('a[href="https://example.test/privacy"]').innerText())
|
|
380
378
|
.toBe(de('privacy', ''))
|
package/tests/context.ts
CHANGED
|
@@ -4,7 +4,7 @@ import react from '@vitejs/plugin-react'
|
|
|
4
4
|
import tailwindcss from '@tailwindcss/vite'
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
import { dirname, resolve } from 'node:path'
|
|
7
|
-
import {
|
|
7
|
+
import { consentModeHelper } from '@owlmeans/consent'
|
|
8
8
|
|
|
9
9
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
10
10
|
|
|
@@ -19,7 +19,7 @@ const here = dirname(fileURLToPath(import.meta.url))
|
|
|
19
19
|
const consentBootstrap = (): Plugin => ({
|
|
20
20
|
name: 'owlmeans-consent-bootstrap',
|
|
21
21
|
transformIndexHtml: html =>
|
|
22
|
-
html.replace('<!--owlmeans:consent-->', `<script>${consentBootstrapScript()}</script>`),
|
|
22
|
+
html.replace('<!--owlmeans:consent-->', `<script>${consentModeHelper.consentBootstrapScript()}</script>`),
|
|
23
23
|
})
|
|
24
24
|
|
|
25
25
|
let url: string | null = null
|
package/tests/linker.spec.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { afterAll, describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import { mountComponent, browserHelper } from '@owlmeans/test-ui'
|
|
3
3
|
import type { Page } from '@owlmeans/test-ui'
|
|
4
|
-
import { CONSENT_KEY, CONSENT_LINK_MAX_AGE, CONSENT_LINK_PARAM,
|
|
4
|
+
import { CONSENT_KEY, CONSENT_LINK_MAX_AGE, CONSENT_LINK_PARAM, consentLinkHelper } from '@owlmeans/consent'
|
|
5
5
|
import { HARNESS_URL } from './context.js'
|
|
6
6
|
|
|
7
7
|
// Browser work does not fit the 5s default: a cold harness compiles the app on first request.
|
|
8
8
|
const TIMEOUT = 60_000
|
|
9
9
|
|
|
10
10
|
afterAll(async () => {
|
|
11
|
-
await closeBrowser()
|
|
11
|
+
await browserHelper.closeBrowser()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
const base = HARNESS_URL.replace(/\/$/, '')
|
|
@@ -58,7 +58,7 @@ describe('@owlmeans/web-consent — the linker: domain disclosure', () => {
|
|
|
58
58
|
|
|
59
59
|
describe('@owlmeans/web-consent — the linker: adoption', () => {
|
|
60
60
|
test('a fresh, correctly-referred link is adopted: no dialog, storage written, URL clean', async () => {
|
|
61
|
-
const owlcc = encodeConsentLink({ essential: true, analytics: true, marketing: false })
|
|
61
|
+
const owlcc = consentLinkHelper.encodeConsentLink({ essential: true, analytics: true, marketing: false })
|
|
62
62
|
const { page, close } = await mountComponent({ url: `${base}/`, waitUntil: 'commit' })
|
|
63
63
|
try {
|
|
64
64
|
await page.goto(`${base}/?linker=1&owlcc=${owlcc}`, {
|
|
@@ -83,7 +83,7 @@ describe('@owlmeans/web-consent — the linker: adoption', () => {
|
|
|
83
83
|
}, TIMEOUT)
|
|
84
84
|
|
|
85
85
|
test('no referrer at all: the dialog still shows, and the parameter is still stripped', async () => {
|
|
86
|
-
const owlcc = encodeConsentLink({ essential: true, analytics: true, marketing: true })
|
|
86
|
+
const owlcc = consentLinkHelper.encodeConsentLink({ essential: true, analytics: true, marketing: true })
|
|
87
87
|
const { page, close } = await mountComponent({
|
|
88
88
|
url: `${base}/?linker=1&owlcc=${owlcc}`, waitUntil: 'domcontentloaded',
|
|
89
89
|
})
|
|
@@ -96,7 +96,7 @@ describe('@owlmeans/web-consent — the linker: adoption', () => {
|
|
|
96
96
|
}, TIMEOUT)
|
|
97
97
|
|
|
98
98
|
test('a foreign (unlisted) referrer: refused, dialog shows', async () => {
|
|
99
|
-
const owlcc = encodeConsentLink({ essential: true, analytics: true, marketing: true })
|
|
99
|
+
const owlcc = consentLinkHelper.encodeConsentLink({ essential: true, analytics: true, marketing: true })
|
|
100
100
|
const { page, close } = await mountComponent({ url: `${base}/`, waitUntil: 'commit' })
|
|
101
101
|
try {
|
|
102
102
|
await page.goto(`${base}/?linker=1&owlcc=${owlcc}`, {
|
|
@@ -130,7 +130,7 @@ describe('@owlmeans/web-consent — the linker: adoption', () => {
|
|
|
130
130
|
([key, value]) => window.localStorage.setItem(key as string, value as string),
|
|
131
131
|
[CONSENT_KEY, JSON.stringify({ essential: true, analytics: false, marketing: false, v: 2 })]
|
|
132
132
|
)
|
|
133
|
-
const owlcc = encodeConsentLink({ essential: true, analytics: true, marketing: true })
|
|
133
|
+
const owlcc = consentLinkHelper.encodeConsentLink({ essential: true, analytics: true, marketing: true })
|
|
134
134
|
await page.goto(`${base}/?linker=1&owlcc=${owlcc}`, {
|
|
135
135
|
waitUntil: 'domcontentloaded', referer: `${PARTNER_ORIGIN}/`,
|
|
136
136
|
})
|