@owlmeans/web-consent 0.1.18-rc.15 → 0.1.18-rc.16

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 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.20
9
+ npx @owlmeans/agent-skills@^0.1.18-rc.21
10
10
  ```
11
11
 
12
12
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/web-consent",
4
- "version": "0.1.18-rc.15",
5
- "generatedAt": "2026-09-12T14:18:54.791Z",
4
+ "version": "0.1.18-rc.16",
5
+ "generatedAt": "2026-09-15T12:21:31.925Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/web-consent
9
9
 
10
10
  **Layer:** Web (React)
11
- **Install:** `"@owlmeans/web-consent": "^0.1.18-rc.15"` in `dependencies`
11
+ **Install:** `"@owlmeans/web-consent": "^0.1.18-rc.16"` 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**
@@ -35,6 +35,7 @@ components — see below.
35
35
  | Export | Description |
36
36
  |--------|-------------|
37
37
  | `CookieConsent` | The preferences dialog **and** the persistent re-open button |
38
+ | `ConsentMenuWidget` | A plain row a HOST'S OWN menu renders to reopen the dialog, in place of (or beside) `CookieConsent`'s own floating button — see below |
38
39
  | `CookiePolicy` | The cookie-policy page, generated from the configuration in force |
39
40
  | `ConsentToggle` | One category row — locked and labelled when the category is required |
40
41
  | `useConsent(opts?)` | This document's consent state and the actions over it (`UseConsentModel`) — **it also initialises the store on mount**, see below |
@@ -78,6 +79,24 @@ precondition in `@owlmeans/client-iam` raises — it says so and relabels the pr
78
79
  twice. Word that path as an acknowledgement, never as "you must consent to essential cookies": a
79
80
  required category is disclosure, not a question.
80
81
 
82
+ ## A menu row for a host that already has one
83
+
84
+ `ConsentMenuWidget` renders one row — icon, translated label, `onClick` reopening the dialog
85
+ (`openConsent('reopen')` by default, or a caller's own `onSelect`) — for a host whose own
86
+ navigation already carries a settings menu and would rather offer cookie preferences there than as
87
+ a second floating button. It calls `openConsent` directly, never `useConsent()`, for the same
88
+ init-on-mount reason as everywhere else in this document.
89
+
90
+ **It carries no presence signalling of its own.** A host that wants `CookieConsent`'s floating
91
+ button to hide while this row is reachable needs to know that itself, from something that stays
92
+ mounted for as long as the row is reachable — never from the row's own mount. A row placed inside a
93
+ host menu's lazily-rendered content (Radix's `DropdownMenuContent`, and most headless menu
94
+ primitives, only mount their children while the menu is actually OPEN) reports "present" for a
95
+ fraction of the time the menu itself is on screen, and the floating button reappears the instant
96
+ the menu closes. `@owlmeans/web-panel/consent`'s `useConsentMenuPresence()` is the fix for a
97
+ context-aware host: call it from the menu's own always-mounted shell component, not from inside the
98
+ row. A context-free host (an Astro island with its own menu) owns that judgement itself.
99
+
81
100
  ## Reading the decision
82
101
 
83
102
  ```tsx
@@ -0,0 +1,18 @@
1
+ import type { FC } from 'react';
2
+ import type { ConsentMenuWidgetProps } from '../types.js';
3
+ /**
4
+ * One row a HOST'S OWN menu can render to reopen the preferences dialog, in place of (or beside)
5
+ * the floating button `CookieConsent` renders itself. No outer row padding here — the host's own
6
+ * menu-row wrapper supplies that, the same way it does for any other widget row it renders.
7
+ *
8
+ * Carries no presence signalling of its own: a host whose menu only mounts this row while its
9
+ * dropdown/menu content is actually open (Radix's `DropdownMenuContent`, for one) would report
10
+ * "present" only for that brief window. A host that wants to hide `CookieConsent`'s floating
11
+ * button while this row is reachable announces that from whatever component of its own stays
12
+ * mounted for the menu's whole lifetime — see `useConsentMenuPresence` in `@owlmeans/web-panel/consent`.
13
+ *
14
+ * Uses `openConsent` directly rather than the `useConsent()` hook: that hook's mount itself
15
+ * triggers `consentStore.init()`, which a row that only needs to trigger a reopen must not do.
16
+ */
17
+ export declare const ConsentMenuWidget: FC<ConsentMenuWidgetProps>;
18
+ //# sourceMappingURL=widget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.d.ts","sourceRoot":"","sources":["../../src/consent/widget.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAI/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAEzD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAqBxD,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback } from 'react';
3
+ import { Cookie } from 'lucide-react';
4
+ import { defaultConsentTranslate, openConsent } from '@owlmeans/consent';
5
+ import { cn } from '../lib/utils.js';
6
+ /**
7
+ * One row a HOST'S OWN menu can render to reopen the preferences dialog, in place of (or beside)
8
+ * the floating button `CookieConsent` renders itself. No outer row padding here — the host's own
9
+ * menu-row wrapper supplies that, the same way it does for any other widget row it renders.
10
+ *
11
+ * Carries no presence signalling of its own: a host whose menu only mounts this row while its
12
+ * dropdown/menu content is actually open (Radix's `DropdownMenuContent`, for one) would report
13
+ * "present" only for that brief window. A host that wants to hide `CookieConsent`'s floating
14
+ * button while this row is reachable announces that from whatever component of its own stays
15
+ * mounted for the menu's whole lifetime — see `useConsentMenuPresence` in `@owlmeans/web-panel/consent`.
16
+ *
17
+ * Uses `openConsent` directly rather than the `useConsent()` hook: that hook's mount itself
18
+ * triggers `consentStore.init()`, which a row that only needs to trigger a reopen must not do.
19
+ */
20
+ export const ConsentMenuWidget = props => {
21
+ const t = props.translate ?? defaultConsentTranslate(props.locale);
22
+ const onClick = useCallback(() => {
23
+ if (props.onSelect != null) {
24
+ props.onSelect();
25
+ return;
26
+ }
27
+ openConsent('reopen');
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') })] });
30
+ };
31
+ //# sourceMappingURL=widget.js.map
@@ -0,0 +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,uBAAuB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACxE,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAA;AAGpC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA+B,KAAK,CAAC,EAAE;IACnE,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,IAAI,uBAAuB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAElE,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,WAAW,CAAC,QAAQ,CAAC,CAAA;IACvB,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEpB,OAAO,kBACL,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,oCAC9B,SAAS,EAAE,EAAE,CACX,+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
@@ -1,6 +1,7 @@
1
1
  export type * from './types.js';
2
2
  export * from './hooks.js';
3
3
  export * from './consent/component.js';
4
+ export * from './consent/widget.js';
4
5
  export * from './consent/toggle.js';
5
6
  export * from './policy/component.js';
6
7
  export { consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent, migrateConsent, applyConsent, pushConsentDefaults, consentBootstrapScript, consentDefaults, consentUpdate, gtagConsent, DEFAULT_CONSENT_CATEGORIES, DEFAULT_CONSENT_MESSAGES, defaultConsentTranslate, interpolate, CONSENT_KEY, CONSENT_COOKIE_DAYS, CONSENT_SCHEMA_VERSION, CONSENT_LOCALES, CONSENT_ESSENTIAL, CONSENT_ANALYTICS, CONSENT_MARKETING, } from '@owlmeans/consent';
@@ -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,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EACzE,eAAe,EAAE,aAAa,EAAE,WAAW,EAC3C,0BAA0B,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,WAAW,EAC1F,WAAW,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EACzE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,GACxD,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAC1F,YAAY,EAAE,aAAa,GAC5B,MAAM,mBAAmB,CAAA"}
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,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EACzE,eAAe,EAAE,aAAa,EAAE,WAAW,EAC3C,0BAA0B,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,WAAW,EAC1F,WAAW,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EACzE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,GACxD,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAC1F,YAAY,EAAE,aAAa,GAC5B,MAAM,mBAAmB,CAAA"}
package/build/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './hooks.js';
2
2
  export * from './consent/component.js';
3
+ export * from './consent/widget.js';
3
4
  export * from './consent/toggle.js';
4
5
  export * from './policy/component.js';
5
6
  export { consentStore, openConsent, isConsented, readConsent, writeConsent, clearConsent, migrateConsent, applyConsent, pushConsentDefaults, consentBootstrapScript, consentDefaults, consentUpdate, gtagConsent, DEFAULT_CONSENT_CATEGORIES, DEFAULT_CONSENT_MESSAGES, defaultConsentTranslate, interpolate, CONSENT_KEY, CONSENT_COOKIE_DAYS, CONSENT_SCHEMA_VERSION, CONSENT_LOCALES, CONSENT_ESSENTIAL, CONSENT_ANALYTICS, CONSENT_MARKETING, } from '@owlmeans/consent';
@@ -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,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EACzE,eAAe,EAAE,aAAa,EAAE,WAAW,EAC3C,0BAA0B,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,WAAW,EAC1F,WAAW,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EACzE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,GACxD,MAAM,mBAAmB,CAAA"}
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;AACnC,cAAc,uBAAuB,CAAA;AAErC,OAAO,EACL,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAC/E,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,sBAAsB,EACzE,eAAe,EAAE,aAAa,EAAE,WAAW,EAC3C,0BAA0B,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,WAAW,EAC1F,WAAW,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,eAAe,EACzE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB,GACxD,MAAM,mBAAmB,CAAA"}
package/build/types.d.ts CHANGED
@@ -36,6 +36,15 @@ export interface CookiePolicyProps {
36
36
  cookieDays?: number;
37
37
  className?: string;
38
38
  }
39
+ export interface ConsentMenuWidgetProps {
40
+ locale?: string;
41
+ /** `(key, defaultValue) => string`. Defaults to the built-in seven-language bundle. */
42
+ translate?: (key: string, defaultValue: string) => string;
43
+ label?: string;
44
+ className?: string;
45
+ /** Defaults to `openConsent('reopen')` — the same call the floating button itself makes. */
46
+ onSelect?: () => void;
47
+ }
39
48
  export interface UseConsentModel {
40
49
  record: ConsentRecord | null;
41
50
  open: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAAE,aAAa,EAAE,aAAa,EAC9C,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;CACnB;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,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAAE,aAAa,EAAE,aAAa,EAC9C,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;CACnB;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,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;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,4FAA4F;IAC5F,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.15",
3
+ "version": "0.1.18-rc.16",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@owlmeans/dep-config": "workspace:*",
36
- "@owlmeans/test-ui": "^0.1.18-rc.23",
36
+ "@owlmeans/test-ui": "^0.1.18-rc.24",
37
37
  "@tailwindcss/vite": "^4.0.0",
38
38
  "@types/bun": "^1.4.0",
39
39
  "@types/react": "^19.2.17",
@@ -0,0 +1,43 @@
1
+ import { useCallback } from 'react'
2
+ import type { FC } from 'react'
3
+ import { Cookie } from 'lucide-react'
4
+ import { defaultConsentTranslate, openConsent } from '@owlmeans/consent'
5
+ import { cn } from '../lib/utils.js'
6
+ import type { ConsentMenuWidgetProps } from '../types.js'
7
+
8
+ /**
9
+ * One row a HOST'S OWN menu can render to reopen the preferences dialog, in place of (or beside)
10
+ * the floating button `CookieConsent` renders itself. No outer row padding here — the host's own
11
+ * menu-row wrapper supplies that, the same way it does for any other widget row it renders.
12
+ *
13
+ * Carries no presence signalling of its own: a host whose menu only mounts this row while its
14
+ * dropdown/menu content is actually open (Radix's `DropdownMenuContent`, for one) would report
15
+ * "present" only for that brief window. A host that wants to hide `CookieConsent`'s floating
16
+ * button while this row is reachable announces that from whatever component of its own stays
17
+ * mounted for the menu's whole lifetime — see `useConsentMenuPresence` in `@owlmeans/web-panel/consent`.
18
+ *
19
+ * Uses `openConsent` directly rather than the `useConsent()` hook: that hook's mount itself
20
+ * triggers `consentStore.init()`, which a row that only needs to trigger a reopen must not do.
21
+ */
22
+ export const ConsentMenuWidget: FC<ConsentMenuWidgetProps> = props => {
23
+ const t = props.translate ?? defaultConsentTranslate(props.locale)
24
+
25
+ const onClick = useCallback(() => {
26
+ if (props.onSelect != null) {
27
+ props.onSelect()
28
+ return
29
+ }
30
+ openConsent('reopen')
31
+ }, [props.onSelect])
32
+
33
+ return <button
34
+ type="button" onClick={onClick} data-consent-menu-widget
35
+ className={cn(
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
+ props.className
38
+ )}
39
+ >
40
+ <Cookie className="h-4 w-4 shrink-0" aria-hidden="true" />
41
+ <span className="flex-1 truncate">{props.label ?? t('openPreferences', 'Cookie preferences')}</span>
42
+ </button>
43
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export type * from './types.js'
2
2
  export * from './hooks.js'
3
3
  export * from './consent/component.js'
4
+ export * from './consent/widget.js'
4
5
  export * from './consent/toggle.js'
5
6
  export * from './policy/component.js'
6
7
 
package/src/types.ts CHANGED
@@ -42,6 +42,16 @@ export interface CookiePolicyProps {
42
42
  className?: string
43
43
  }
44
44
 
45
+ export interface ConsentMenuWidgetProps {
46
+ locale?: string
47
+ /** `(key, defaultValue) => string`. Defaults to the built-in seven-language bundle. */
48
+ translate?: (key: string, defaultValue: string) => string
49
+ label?: string
50
+ className?: string
51
+ /** Defaults to `openConsent('reopen')` — the same call the floating button itself makes. */
52
+ onSelect?: () => void
53
+ }
54
+
45
55
  export interface UseConsentModel {
46
56
  record: ConsentRecord | null
47
57
  open: boolean