srcdev-nuxt-components 9.4.0 → 9.4.1

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.
@@ -68,21 +68,21 @@ useGoogleAnalytics();
68
68
 
69
69
  ## CSS / styling
70
70
 
71
- Public tokens (all on `.cookie-consent-banner`, `var(--cookie-consent-banner-*, fallback)` pattern):
71
+ Public tokens (all on `.privacy-notice-banner`, `var(--privacy-notice-banner-*, fallback)` pattern):
72
72
 
73
73
  | Token | Default |
74
74
  |---|---|
75
- | `--cookie-consent-banner-z-index` | `999999` |
76
- | `--cookie-consent-banner-gutter` | `1.6rem` |
77
- | `--cookie-consent-banner-max-width` | `64rem` |
78
- | `--cookie-consent-banner-border-radius` | `0.8rem` |
79
- | `--cookie-consent-banner-border` | `0.1rem solid light-dark(var(--slate-10), var(--slate-02))` |
80
- | `--cookie-consent-banner-background` | `light-dark(var(--slate-00), var(--slate-10))` |
81
- | `--cookie-consent-banner-transition-duration` | `200ms` |
75
+ | `--privacy-notice-banner-z-index` | `999999` |
76
+ | `--privacy-notice-banner-gutter` | `1.6rem` |
77
+ | `--privacy-notice-banner-max-width` | `64rem` |
78
+ | `--privacy-notice-banner-border-radius` | `0.8rem` |
79
+ | `--privacy-notice-banner-border` | `0.1rem solid light-dark(var(--slate-10), var(--slate-02))` |
80
+ | `--privacy-notice-banner-background` | `light-dark(var(--slate-00), var(--slate-10))` |
81
+ | `--privacy-notice-banner-transition-duration` | `200ms` |
82
82
 
83
83
  ## Notes
84
84
 
85
- - **Teleported to `<body>`** — like `DisplayToastProvider`, query it in tests via `document.querySelector(".cookie-consent-banner")`, not `wrapper.find(...)`.
85
+ - **Teleported to `<body>`** — like `DisplayToastProvider`, query it in tests via `document.querySelector(".privacy-notice-banner")`, not `wrapper.find(...)`.
86
86
  - **No focus trap / backdrop** — this is a dismiss-by-decision banner, not a modal. It collapses via a `grid-template-rows` transition (same mechanic as `DisplayPrompt`) once `status` leaves `"unset"`, rather than unmounting.
87
87
  - **Only ever one instance** — `useCookieConsent()`'s underlying state is a module-scope singleton, so mounting the banner twice in one app just duplicates the UI, it doesn't create separate consent state.
88
88
  - To let a visitor change their mind later (e.g. from a cookie-policy page), call `useCookieConsent().rejectAll()` or clear the `cookie-consent` cookie — the banner reappears since `status` returns to `"unset"` only once the cookie is gone; `rejectAll()` itself sets it to `"denied"`, which keeps the banner hidden but stops GA. Expose a dedicated "reset my choice" affordance if you want the banner itself to resurface.
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- `useCookieConsent` tracks the visitor's cookie-consent decision (`unset` / `granted` / `denied`), persists it in a `cookie-consent` cookie, and wraps `@nuxt/scripts`' `useScriptTriggerConsent()` gate so any consent-dependent script (Google Analytics via [[composable-google-analytics]], or anything else added later) can be wired to it.
5
+ `useCookieConsent` tracks the visitor's cookie-consent decision (`unset` / `granted` / `denied`), persists it in a `privacy-notice-consent` cookie, and wraps `@nuxt/scripts`' `useScriptTriggerConsent()` gate so any consent-dependent script (Google Analytics via [[composable-google-analytics]], or anything else added later) can be wired to it.
6
6
 
7
7
  **This composable ships inside the `srcdev-nuxt-components` layer** (`app/composables/useCookieConsent.ts`). Consuming apps get it via Nuxt's layer auto-import — **do not create a local copy** in the consuming app.
8
8
 
@@ -28,7 +28,7 @@ Source lives at `app/composables/useCookieConsent.ts` in the layer. Shown here f
28
28
  const consentTrigger = useScriptTriggerConsent(); // module-scope singleton
29
29
 
30
30
  export function useCookieConsent() {
31
- const stored = useCookie<"granted" | "denied" | null>("cookie-consent", {
31
+ const stored = useCookie<"granted" | "denied" | null>("privacy-notice-consent", {
32
32
  maxAge: 60 * 60 * 24 * 365,
33
33
  sameSite: "lax",
34
34
  default: () => null,
@@ -70,9 +70,9 @@ if (status.value === "unset") {
70
70
  }
71
71
  ```
72
72
 
73
- To let a user change their mind later (e.g. a "cookie preferences" link in the footer or a cookie-policy page), call `rejectAll()` or clear the `cookie-consent` cookie to bring the banner back.
73
+ To let a user change their mind later (e.g. a "cookie preferences" link in the footer or a cookie-policy page), call `rejectAll()` or clear the `privacy-notice-consent` cookie to bring the banner back.
74
74
 
75
75
  ## Notes
76
76
 
77
- - Cookie name `cookie-consent` is fixed by the layer, not configurable per app.
77
+ - Cookie name `privacy-notice-consent` is fixed by the layer, not configurable per app.
78
78
  - This composable only tracks the yes/no decision — it does not itself load any script. See [[composable-google-analytics]] for the GA4 integration that consumes `trigger`.
@@ -1,28 +1,28 @@
1
1
  <template>
2
2
  <Teleport to="body">
3
3
  <div
4
- class="cookie-consent-banner"
4
+ class="privacy-notice-banner"
5
5
  :class="[{ closed: status !== 'unset' }, elementClasses]"
6
6
  :data-theme="resolved.theme"
7
- data-test-id="cookie-consent-banner"
7
+ data-test-id="privacy-notice-banner"
8
8
  >
9
- <div class="cookie-consent-banner-inner" role="region" :aria-label="ariaLabel">
10
- <div class="cookie-consent-banner-message">
9
+ <div class="privacy-notice-banner-inner" role="region" :aria-label="ariaLabel">
10
+ <div class="privacy-notice-banner-message">
11
11
  <slot name="message">This site uses cookies to understand how it's used. You can accept or reject them.</slot>
12
12
  </div>
13
- <div class="cookie-consent-banner-actions">
13
+ <div class="privacy-notice-banner-actions">
14
14
  <button
15
15
  type="button"
16
- class="cookie-consent-banner-reject"
17
- data-test-id="cookie-consent-banner-reject"
16
+ class="privacy-notice-banner-reject"
17
+ data-test-id="privacy-notice-banner-reject"
18
18
  @click="rejectAll()"
19
19
  >
20
20
  <slot name="rejectLabel">Reject</slot>
21
21
  </button>
22
22
  <button
23
23
  type="button"
24
- class="cookie-consent-banner-accept"
25
- data-test-id="cookie-consent-banner-accept"
24
+ class="privacy-notice-banner-accept"
25
+ data-test-id="privacy-notice-banner-accept"
26
26
  @click="acceptAll()"
27
27
  >
28
28
  <slot name="acceptLabel">Accept</slot>
@@ -57,17 +57,17 @@ const ariaLabel = "Cookie consent";
57
57
 
58
58
  <style lang="css">
59
59
  @layer components {
60
- .cookie-consent-banner {
60
+ .privacy-notice-banner {
61
61
  /* Matches DisplayToastProvider/DisplayDialog's z-index convention so
62
62
  this clears ordinary page chrome (and a consumer's sticky header) but
63
63
  still sits below an active modal dialog if one somehow overlaps. */
64
- --_z-index: var(--cookie-consent-banner-z-index, 999999);
65
- --_gutter: var(--cookie-consent-banner-gutter, 1.6rem);
66
- --_max-width: var(--cookie-consent-banner-max-width, 64rem);
67
- --_border-radius: var(--cookie-consent-banner-border-radius, 0.8rem);
68
- --_border: var(--cookie-consent-banner-border, 0.1rem solid light-dark(var(--slate-10), var(--slate-02)));
69
- --_background: var(--cookie-consent-banner-background, light-dark(var(--slate-00), var(--slate-10)));
70
- --_transition-duration: var(--cookie-consent-banner-transition-duration, 200ms);
64
+ --_z-index: var(--privacy-notice-banner-z-index, 999999);
65
+ --_gutter: var(--privacy-notice-banner-gutter, 1.6rem);
66
+ --_max-width: var(--privacy-notice-banner-max-width, 64rem);
67
+ --_border-radius: var(--privacy-notice-banner-border-radius, 0.8rem);
68
+ --_border: var(--privacy-notice-banner-border, 0.1rem solid light-dark(var(--slate-10), var(--slate-02)));
69
+ --_background: var(--privacy-notice-banner-background, light-dark(var(--slate-00), var(--slate-10)));
70
+ --_transition-duration: var(--privacy-notice-banner-transition-duration, 200ms);
71
71
 
72
72
  position: fixed;
73
73
  inset-inline: var(--_gutter);
@@ -87,7 +87,7 @@ const ariaLabel = "Cookie consent";
87
87
  pointer-events: none;
88
88
  }
89
89
 
90
- .cookie-consent-banner-inner {
90
+ .privacy-notice-banner-inner {
91
91
  overflow: hidden;
92
92
  display: flex;
93
93
  flex-wrap: wrap;
@@ -103,18 +103,18 @@ const ariaLabel = "Cookie consent";
103
103
  }
104
104
  }
105
105
 
106
- .cookie-consent-banner-message {
106
+ .privacy-notice-banner-message {
107
107
  flex: 1 1 24rem;
108
108
  }
109
109
 
110
- .cookie-consent-banner-actions {
110
+ .privacy-notice-banner-actions {
111
111
  display: flex;
112
112
  gap: 0.8rem;
113
113
  margin-inline-start: auto;
114
114
  }
115
115
 
116
- .cookie-consent-banner-reject,
117
- .cookie-consent-banner-accept {
116
+ .privacy-notice-banner-reject,
117
+ .privacy-notice-banner-accept {
118
118
  padding: 0.8rem 1.6rem;
119
119
  border-radius: 0.4rem;
120
120
  border: 0.1rem solid transparent;
@@ -124,7 +124,7 @@ const ariaLabel = "Cookie consent";
124
124
  background-color var(--_transition-duration);
125
125
  }
126
126
 
127
- .cookie-consent-banner-reject {
127
+ .privacy-notice-banner-reject {
128
128
  background-color: transparent;
129
129
  border: 0.1rem solid light-dark(var(--slate-08), var(--slate-04));
130
130
 
@@ -134,7 +134,7 @@ const ariaLabel = "Cookie consent";
134
134
  }
135
135
  }
136
136
 
137
- .cookie-consent-banner-accept {
137
+ .privacy-notice-banner-accept {
138
138
  background-color: var(--theme-accent);
139
139
  color: light-dark(var(--slate-00), var(--slate-12));
140
140
 
@@ -29,18 +29,18 @@ export default {
29
29
  // reloads. Each story below has "Show banner again" (resets state
30
30
  // in-place) and "Delete cookie" (clears document.cookie directly, for
31
31
  // verifying the cookie itself is actually gone, e.g. in devtools).
32
- component: "Reads/writes a real 'cookie-consent' cookie via useCookieConsent(). Use the story's reset controls to bring the banner back.",
32
+ component: "Reads/writes a real 'privacy-notice-consent' cookie via useCookieConsent(). Use the story's reset controls to bring the banner back.",
33
33
  },
34
34
  },
35
35
  },
36
36
  } as Meta<typeof StorybookComponent>;
37
37
 
38
- // Resets the same "cookie-consent" cookie useCookieConsent() reads, so the
38
+ // Resets the same "privacy-notice-consent" cookie useCookieConsent() reads, so the
39
39
  // banner's status goes back to "unset" and reappears without a page reload
40
40
  // (Nuxt dedupes useCookie() by key, so this shares the ref CookieConsentBanner
41
41
  // itself reads).
42
42
  function useResetConsent() {
43
- const consentCookie = useCookie<"granted" | "denied" | null>("cookie-consent");
43
+ const consentCookie = useCookie<"granted" | "denied" | null>("privacy-notice-consent");
44
44
  const showAgain = () => {
45
45
  consentCookie.value = null;
46
46
  };
@@ -48,7 +48,7 @@ function useResetConsent() {
48
48
  // rather than just the in-memory ref, so devtools/Application tab reflects
49
49
  // it too, not only the story's live re-render.
50
50
  const deleteCookie = () => {
51
- document.cookie = "cookie-consent=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
51
+ document.cookie = "privacy-notice-consent=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
52
52
  consentCookie.value = null;
53
53
  };
54
54
  return { showAgain, deleteCookie };
@@ -23,15 +23,15 @@ mockNuxtImport("useCookieConsent", () => () => ({
23
23
  }));
24
24
 
25
25
  function banner() {
26
- return document.querySelector(".cookie-consent-banner");
26
+ return document.querySelector(".privacy-notice-banner");
27
27
  }
28
28
 
29
29
  function acceptButton() {
30
- return document.querySelector("[data-test-id='cookie-consent-banner-accept']") as HTMLElement;
30
+ return document.querySelector("[data-test-id='privacy-notice-banner-accept']") as HTMLElement;
31
31
  }
32
32
 
33
33
  function rejectButton() {
34
- return document.querySelector("[data-test-id='cookie-consent-banner-reject']") as HTMLElement;
34
+ return document.querySelector("[data-test-id='privacy-notice-banner-reject']") as HTMLElement;
35
35
  }
36
36
 
37
37
  describe("CookieConsentBanner", () => {
@@ -18,7 +18,7 @@ export function useCookieConsent() {
18
18
  // Persists the decision across visits. Read fresh on every call so this
19
19
  // stays request-safe during SSR (Nuxt dedupes useCookie() by key within a
20
20
  // request, so this is cheap to call repeatedly).
21
- const stored = useCookie<"granted" | "denied" | null>("cookie-consent", {
21
+ const stored = useCookie<"granted" | "denied" | null>("privacy-notice-consent", {
22
22
  maxAge: 60 * 60 * 24 * 365,
23
23
  sameSite: "lax",
24
24
  default: () => null,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.4.0",
4
+ "version": "9.4.1",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",