@gardenfi/garden-book 0.3.1 → 0.3.2

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.
@@ -4,6 +4,10 @@ type BottomSheetProps = {
4
4
  children: ReactNode;
5
5
  open: boolean;
6
6
  onOpenChange?: (open: boolean) => void;
7
+ overlayClassName?: string;
8
+ dismissible?: boolean;
9
+ /** When `false`, the page behind stays interactive */
10
+ modal?: boolean;
7
11
  };
8
12
  export declare const BottomSheet: FC<BottomSheetProps>;
9
13
  export {};
@@ -1,17 +1,39 @@
1
1
  import { jsx as f, jsxs as e } from "react/jsx-runtime";
2
2
  import { Drawer as g } from "../node_modules/vaul/dist/index.js";
3
- import { ClientOnly as l } from "../ClientOnly/index.js";
4
- const s = ({
3
+ import { ClientOnly as a } from "../ClientOnly/index.js";
4
+ import { cn as s } from "../utils/index.js";
5
+ const h = ({
5
6
  children: o,
6
7
  open: r,
7
- onOpenChange: t
8
- }) => /* @__PURE__ */ f(l, { children: /* @__PURE__ */ f(g.Root, { open: r, onOpenChange: t, repositionInputs: !1, children: /* @__PURE__ */ e(g.Portal, { children: [
9
- /* @__PURE__ */ f(g.Overlay, { className: "gf-fixed gf-inset-0 gf-z-50 gf-h-screen gf-w-screen gf-bg-dark-grey gf-bg-opacity-40 gf-transition-colors gf-duration-500 gf-ease-cubic-in-out" }),
10
- /* @__PURE__ */ e(g.Content, { className: "gf-fixed gf-bottom-0 gf-left-0 gf-right-0 gf-z-50 gf-mt-24 gf-flex gf-max-h-[85vh] gf-flex-col gf-rounded-t-xl gf-bg-white/50 gf-px-4 gf-py-4 gf-outline-none gf-backdrop-blur-[20px]", children: [
11
- /* @__PURE__ */ f("div", { className: "gf-mx-auto gf-mb-3 gf-h-1 gf-w-[60px] gf-flex-shrink-0 gf-rounded-full gf-bg-white/30" }),
12
- /* @__PURE__ */ f("div", { className: "gf-scrollbar-hide gf-flex gf-flex-1 gf-flex-col gf-gap-5 gf-overflow-y-auto", children: o })
13
- ] })
14
- ] }) }) });
8
+ onOpenChange: t,
9
+ overlayClassName: l,
10
+ dismissible: i,
11
+ modal: n
12
+ }) => /* @__PURE__ */ f(a, { children: /* @__PURE__ */ f(
13
+ g.Root,
14
+ {
15
+ open: r,
16
+ onOpenChange: t,
17
+ repositionInputs: !1,
18
+ dismissible: i,
19
+ modal: n,
20
+ children: /* @__PURE__ */ e(g.Portal, { children: [
21
+ /* @__PURE__ */ f(
22
+ g.Overlay,
23
+ {
24
+ className: s(
25
+ "gf-fixed gf-inset-0 gf-z-50 gf-h-screen gf-w-screen gf-bg-dark-grey gf-bg-opacity-40 gf-transition-colors gf-duration-500 gf-ease-cubic-in-out",
26
+ l
27
+ )
28
+ }
29
+ ),
30
+ /* @__PURE__ */ e(g.Content, { className: "gf-fixed gf-bottom-0 gf-left-0 gf-right-0 gf-z-50 gf-mt-24 gf-flex gf-max-h-[85vh] gf-flex-col gf-rounded-t-xl gf-bg-white/50 gf-px-4 gf-py-4 gf-outline-none gf-backdrop-blur-[20px]", children: [
31
+ /* @__PURE__ */ f("div", { className: "gf-mx-auto gf-mb-3 gf-h-1 gf-w-[60px] gf-flex-shrink-0 gf-rounded-full gf-bg-white/30" }),
32
+ /* @__PURE__ */ f("div", { className: "gf-scrollbar-hide gf-flex gf-flex-1 gf-flex-col gf-gap-5 gf-overflow-y-auto", children: o })
33
+ ] })
34
+ ] })
35
+ }
36
+ ) });
15
37
  export {
16
- s as BottomSheet
38
+ h as BottomSheet
17
39
  };
@@ -3,6 +3,7 @@ import { FC } from 'react';
3
3
  type CheckBoxProps = React.HTMLAttributes<HTMLDivElement> & {
4
4
  checked: boolean;
5
5
  color?: string;
6
+ disabled?: boolean;
6
7
  };
7
8
  export declare const CheckBox: FC<CheckBoxProps>;
8
9
  export {};
@@ -1,7 +1,35 @@
1
- import { jsx as r } from "react/jsx-runtime";
2
- import { Checked as m } from "../Icons/Checked.js";
3
- import { Unchecked as s } from "../Icons/Unchecked.js";
4
- const p = ({ checked: o, color: e, ...c }) => /* @__PURE__ */ r("div", { ...c, children: o ? /* @__PURE__ */ r(m, { className: "gf-cursor-pointer", color: e }) : /* @__PURE__ */ r(s, { className: "gf-cursor-pointer" }) });
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { Checked as n } from "../Icons/Checked.js";
3
+ import { Unchecked as f } from "../Icons/Unchecked.js";
4
+ import { cn as a } from "../utils/index.js";
5
+ const s = ({
6
+ checked: e,
7
+ color: o,
8
+ disabled: r,
9
+ className: c,
10
+ onClick: m,
11
+ ...i
12
+ }) => /* @__PURE__ */ t(
13
+ "div",
14
+ {
15
+ role: "checkbox",
16
+ "aria-checked": e,
17
+ "aria-disabled": r,
18
+ onClick: r ? void 0 : m,
19
+ className: a(
20
+ r ? "gf-cursor-not-allowed" : "gf-cursor-pointer",
21
+ c
22
+ ),
23
+ ...i,
24
+ children: e ? /* @__PURE__ */ t(
25
+ n,
26
+ {
27
+ color: !r && o ? o : "currentColor",
28
+ className: r ? "gf-text-midGrey" : o ? void 0 : "gf-text-button-primary"
29
+ }
30
+ ) : /* @__PURE__ */ t(f, {})
31
+ }
32
+ );
5
33
  export {
6
- p as CheckBox
34
+ s as CheckBox
7
35
  };
@@ -0,0 +1,18 @@
1
+ import { FC } from 'react';
2
+ import { ConsentChoice, CookieCategory, UseCookieConsentOptions } from './utils';
3
+
4
+ export type CookieConsentProps = {
5
+ /** Privacy Policy link shown on the notice screen. */
6
+ privacyPolicyUrl: string;
7
+ /** Categories rendered on the preferences screen (defaults to the three Garden categories). */
8
+ categories?: CookieCategory[];
9
+ /** Initial tick state for the two non-essential categories. */
10
+ defaultChecked?: boolean;
11
+ /** Called after a choice is persisted. */
12
+ onChange?: (choice: ConsentChoice) => void;
13
+ /** Override cookie domain / version / expiry. */
14
+ config?: UseCookieConsentOptions;
15
+ };
16
+ /** Orchestrator: owns the consent store + responsive modal, and switches between
17
+ * the two presentational screens. */
18
+ export declare const CookieConsent: FC<CookieConsentProps>;
@@ -0,0 +1,52 @@
1
+ import { jsx as t } from "react/jsx-runtime";
2
+ import { ResponsiveModal as A } from "../ResponsiveModal/index.js";
3
+ import { useCookieConsent as v } from "./useCookieConsent.js";
4
+ import { CookieConsentNotice as g } from "./CookieConsentNotice.js";
5
+ import { CookieConsentPreferences as k } from "./CookieConsentPreferences.js";
6
+ import { DEFAULT_COOKIE_CATEGORIES as S } from "./utils.js";
7
+ const I = ({
8
+ privacyPolicyUrl: n,
9
+ categories: s = S,
10
+ defaultChecked: l = !0,
11
+ onChange: e,
12
+ config: i
13
+ }) => {
14
+ const { isOpen: c, view: f, ready: p, setView: a, close: m, acceptAll: u, save: d } = v(i);
15
+ if (!p) return null;
16
+ const o = () => {
17
+ u(), e == null || e({ analytics: !0, functional: !0 });
18
+ };
19
+ return /* @__PURE__ */ t(
20
+ A,
21
+ {
22
+ open: c,
23
+ onClose: m,
24
+ hideCloseBtn: !0,
25
+ bottomSheetAllowBackgroundInteraction: !0,
26
+ disableScrollLock: !0,
27
+ overlayClassName: "!gf-items-end !gf-justify-start gf-pl-[40px] !gf-bg-transparent !gf-pointer-events-none",
28
+ className: "!gf-pointer-events-auto gf-w-[420px] gf-gap-0 gf-px-3 gf-py-4 gf-rounded-t-4 gf-rounded-b-none",
29
+ children: f === "notice" ? /* @__PURE__ */ t(
30
+ g,
31
+ {
32
+ privacyPolicyUrl: n,
33
+ onChangePreferences: () => a("preferences"),
34
+ onAcceptAll: o
35
+ }
36
+ ) : /* @__PURE__ */ t(
37
+ k,
38
+ {
39
+ categories: s,
40
+ defaultChecked: l,
41
+ onAcceptAll: o,
42
+ onSave: (r) => {
43
+ d(r), e == null || e(r);
44
+ }
45
+ }
46
+ )
47
+ }
48
+ );
49
+ };
50
+ export {
51
+ I as CookieConsent
52
+ };
@@ -0,0 +1,8 @@
1
+ import { FC } from 'react';
2
+
3
+ export type CookieConsentNoticeProps = {
4
+ privacyPolicyUrl: string;
5
+ onChangePreferences: () => void;
6
+ onAcceptAll: () => void;
7
+ };
8
+ export declare const CookieConsentNotice: FC<CookieConsentNoticeProps>;
@@ -0,0 +1,55 @@
1
+ import { jsxs as a, jsx as e } from "react/jsx-runtime";
2
+ import { Typography as r } from "../Typography/index.js";
3
+ import { Button as l } from "../Button/index.js";
4
+ const g = ({
5
+ privacyPolicyUrl: i,
6
+ onChangePreferences: s,
7
+ onAcceptAll: o
8
+ }) => /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-9", children: [
9
+ /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-3 gf-px-1", children: [
10
+ /* @__PURE__ */ e(r, { as: "p", size: "h5", weight: "medium", className: "!gf-leading-5", children: "Manage cookies" }),
11
+ /* @__PURE__ */ a(r, { as: "p", size: "h4", children: [
12
+ "We use cookies and analytics to improve Garden. ",
13
+ /* @__PURE__ */ e("br", {}),
14
+ "Learn more in our",
15
+ " ",
16
+ /* @__PURE__ */ e(
17
+ "a",
18
+ {
19
+ href: i,
20
+ target: "_blank",
21
+ rel: "noreferrer",
22
+ className: "gf-font-medium",
23
+ children: "Privacy Policy"
24
+ }
25
+ ),
26
+ "."
27
+ ] })
28
+ ] }),
29
+ /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-3", children: [
30
+ /* @__PURE__ */ e(
31
+ l,
32
+ {
33
+ variant: "ternary",
34
+ size: "sm",
35
+ colors: { ternary: "rgba(255,255,255,0.5)" },
36
+ className: "gf-w-full",
37
+ onClick: s,
38
+ children: "Change preferences"
39
+ }
40
+ ),
41
+ /* @__PURE__ */ e(
42
+ l,
43
+ {
44
+ variant: "primary",
45
+ size: "sm",
46
+ className: "gf-w-full",
47
+ onClick: o,
48
+ children: "Accept all"
49
+ }
50
+ )
51
+ ] })
52
+ ] });
53
+ export {
54
+ g as CookieConsentNotice
55
+ };
@@ -0,0 +1,10 @@
1
+ import { FC } from 'react';
2
+ import { ConsentChoice, CookieCategory } from './utils';
3
+
4
+ export type CookieConsentPreferencesProps = {
5
+ categories: CookieCategory[];
6
+ defaultChecked: boolean;
7
+ onAcceptAll: () => void;
8
+ onSave: (choice: ConsentChoice) => void;
9
+ };
10
+ export declare const CookieConsentPreferences: FC<CookieConsentPreferencesProps>;
@@ -0,0 +1,75 @@
1
+ import { jsxs as a, jsx as l } from "react/jsx-runtime";
2
+ import { useState as p } from "react";
3
+ import { Typography as s } from "../Typography/index.js";
4
+ import { Button as c } from "../Button/index.js";
5
+ import { CheckBox as h } from "../Checkbox/Checkbox.js";
6
+ const v = ({
7
+ categories: n,
8
+ defaultChecked: r,
9
+ onAcceptAll: t,
10
+ onSave: o
11
+ }) => {
12
+ const [f, m] = p({
13
+ analytics: r,
14
+ functional: r
15
+ });
16
+ return /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-9", children: [
17
+ /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-3 gf-px-1", children: [
18
+ /* @__PURE__ */ l(s, { as: "p", size: "h5", weight: "medium", className: "!gf-leading-5", children: "Manage cookies" }),
19
+ /* @__PURE__ */ l("div", { className: "gf-flex gf-flex-col gf-gap-4", children: n.map((e) => {
20
+ const i = e.id, d = e.locked ? !0 : f[i];
21
+ return /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-1", children: [
22
+ /* @__PURE__ */ a("div", { className: "gf-flex gf-items-center gf-justify-between gf-gap-4", children: [
23
+ /* @__PURE__ */ l(s, { as: "p", size: "h4", weight: "medium", children: e.title }),
24
+ /* @__PURE__ */ l(
25
+ h,
26
+ {
27
+ checked: d,
28
+ disabled: e.locked,
29
+ "aria-label": e.title,
30
+ className: "gf-shrink-0 gf-text-dark-grey",
31
+ onClick: () => m((g) => ({ ...g, [i]: !g[i] }))
32
+ }
33
+ )
34
+ ] }),
35
+ /* @__PURE__ */ l(
36
+ s,
37
+ {
38
+ as: "p",
39
+ size: "h4",
40
+ weight: "regular",
41
+ className: "gf-max-w-[340px]",
42
+ children: e.description
43
+ }
44
+ )
45
+ ] }, e.id);
46
+ }) })
47
+ ] }),
48
+ /* @__PURE__ */ a("div", { className: "gf-flex gf-flex-col gf-gap-3", children: [
49
+ /* @__PURE__ */ l(
50
+ c,
51
+ {
52
+ variant: "ternary",
53
+ size: "sm",
54
+ colors: { ternary: "rgba(255,255,255,0.5)" },
55
+ className: "gf-w-full",
56
+ onClick: t,
57
+ children: "Accept all"
58
+ }
59
+ ),
60
+ /* @__PURE__ */ l(
61
+ c,
62
+ {
63
+ variant: "primary",
64
+ size: "sm",
65
+ className: "gf-w-full",
66
+ onClick: () => o(f),
67
+ children: "Save"
68
+ }
69
+ )
70
+ ] })
71
+ ] });
72
+ };
73
+ export {
74
+ v as CookieConsentPreferences
75
+ };
@@ -0,0 +1,5 @@
1
+ export * from './CookieConsent';
2
+ export { useCookieConsent } from './useCookieConsent';
3
+ export type { UseCookieConsentReturn } from './useCookieConsent';
4
+ export { CONSENT_EVENT } from './utils';
5
+ export type { ConsentChoice, StoredConsent, ConsentView, UseCookieConsentOptions, } from './utils';
@@ -0,0 +1,8 @@
1
+ import { CookieConsent as r } from "./CookieConsent.js";
2
+ import { useCookieConsent as C } from "./useCookieConsent.js";
3
+ import { CONSENT_EVENT as f } from "./utils.js";
4
+ export {
5
+ f as CONSENT_EVENT,
6
+ r as CookieConsent,
7
+ C as useCookieConsent
8
+ };
@@ -0,0 +1,19 @@
1
+ import { ConsentView, StoredConsent } from './utils';
2
+
3
+ /**
4
+ * Module-level store shared across all `useCookieConsent` instances,
5
+ * so the modal control one source of truth even though they call the
6
+ * hook independently. Subscribed via `useSyncExternalStore`.
7
+ */
8
+ type State = {
9
+ isOpen: boolean;
10
+ view: ConsentView;
11
+ consent: StoredConsent | null;
12
+ ready: boolean;
13
+ };
14
+ export declare const setState: (patch: Partial<State>) => void;
15
+ export declare const subscribe: (l: () => void) => () => boolean;
16
+ export declare const getSnapshot: () => State;
17
+ export declare const getServerSnapshot: () => State;
18
+ export declare function boot(): void;
19
+ export {};
@@ -0,0 +1,42 @@
1
+ import { readRaw as c, isValidConsent as l, applyConsent as t, hasTrackingCookies as u, isWithinAutoConsentWindow as f, writeConsent as d } from "./utils.js";
2
+ let s = {
3
+ isOpen: !1,
4
+ view: "notice",
5
+ consent: null,
6
+ ready: !1
7
+ };
8
+ const p = {
9
+ isOpen: !1,
10
+ view: "notice",
11
+ consent: null,
12
+ ready: !1
13
+ }, o = /* @__PURE__ */ new Set(), w = () => o.forEach((e) => e()), n = (e) => {
14
+ s = { ...s, ...e }, w();
15
+ }, S = (e) => (o.add(e), () => o.delete(e)), O = () => s, h = () => p, a = { analytics: !1, functional: !1 };
16
+ let i = !1;
17
+ function v() {
18
+ if (i) return;
19
+ i = !0;
20
+ const e = c();
21
+ if (l(e)) {
22
+ t(e), n({ consent: e, ready: !0, isOpen: !1 });
23
+ return;
24
+ }
25
+ if (e) {
26
+ t(a), n({ consent: null, ready: !0, isOpen: !0, view: "notice" });
27
+ return;
28
+ }
29
+ if (u() && f()) {
30
+ const r = d({ analytics: !0, functional: !0 });
31
+ t(r), n({ consent: r, ready: !0, isOpen: !1 });
32
+ return;
33
+ }
34
+ t(a), n({ consent: null, ready: !0, isOpen: !0, view: "notice" });
35
+ }
36
+ export {
37
+ v as boot,
38
+ h as getServerSnapshot,
39
+ O as getSnapshot,
40
+ n as setState,
41
+ S as subscribe
42
+ };
@@ -0,0 +1,23 @@
1
+ import { ConsentChoice, ConsentView, StoredConsent, UseCookieConsentOptions } from './utils';
2
+
3
+ export type UseCookieConsentReturn = {
4
+ /** The stored choice, or null if none/expired. */
5
+ consent: StoredConsent | null;
6
+ /** Whether the banner/modal is open. */
7
+ isOpen: boolean;
8
+ /** Which screen to show when open. */
9
+ view: ConsentView;
10
+ /** True once boot has run on the client (avoids SSR flash). */
11
+ ready: boolean;
12
+ /** Open the banner at a given screen (default the notice; pass "preferences" for a footer link). */
13
+ open: (view?: ConsentView) => void;
14
+ /** Switch screen without closing (e.g. notice → preferences). */
15
+ setView: (view: ConsentView) => void;
16
+ /** Close without recording a choice (banner reappears next load). */
17
+ close: () => void;
18
+ /** Grant everything and persist. */
19
+ acceptAll: () => void;
20
+ /** Persist a specific choice. */
21
+ save: (choice: ConsentChoice) => void;
22
+ };
23
+ export declare function useCookieConsent(options?: UseCookieConsentOptions): UseCookieConsentReturn;
@@ -0,0 +1,31 @@
1
+ import { useSyncExternalStore as a, useEffect as i, useCallback as c } from "react";
2
+ import { subscribe as p, getSnapshot as l, getServerSnapshot as u, boot as f, setState as n } from "./store.js";
3
+ import { configure as m, writeConsent as C, applyConsent as S, clearDeniedCookies as y } from "./utils.js";
4
+ function v(o) {
5
+ const t = a(
6
+ p,
7
+ l,
8
+ u
9
+ );
10
+ i(() => {
11
+ m(o), f();
12
+ }, []);
13
+ const s = c((e) => {
14
+ const r = C(e);
15
+ S(e), y(e), n({ consent: r, isOpen: !1 });
16
+ }, []);
17
+ return {
18
+ consent: t.consent,
19
+ isOpen: t.isOpen,
20
+ view: t.view,
21
+ ready: t.ready,
22
+ open: (e = "notice") => n({ isOpen: !0, view: e }),
23
+ setView: (e) => n({ view: e }),
24
+ close: () => n({ isOpen: !1 }),
25
+ acceptAll: () => s({ analytics: !0, functional: !0 }),
26
+ save: (e) => s(e)
27
+ };
28
+ }
29
+ export {
30
+ v as useCookieConsent
31
+ };
@@ -0,0 +1,58 @@
1
+ export type CookieCategory = {
2
+ id: "essential" | "analytics" | "functional";
3
+ title: string;
4
+ description: string;
5
+ /** Always on, no toggle (Essential). */
6
+ locked?: boolean;
7
+ };
8
+ /** Default Garden categories for the preferences UI. */
9
+ export declare const DEFAULT_COOKIE_CATEGORIES: CookieCategory[];
10
+ export type ConsentView = "notice" | "preferences";
11
+ export type ConsentChoice = {
12
+ analytics: boolean;
13
+ functional: boolean;
14
+ };
15
+ export type StoredConsent = ConsentChoice & {
16
+ /** Always true — Essential is locked on. Stored explicitly so external readers
17
+ * (proof-of-consent record, audits) see the full picture, even though we never mutate it. */
18
+ essential: true;
19
+ timestamp: number;
20
+ version: number;
21
+ };
22
+ /** Window event the telemetry scripts (loaded separately) listen on to react without a reload. */
23
+ export declare const CONSENT_EVENT = "garden:consentchange";
24
+ type Config = {
25
+ /** Cookie domain — `.garden.finance` shares the choice across www + app. */
26
+ cookieDomain: string;
27
+ /** Bump to force re-consent after a policy/category change. */
28
+ storageVersion: number;
29
+ /** Consent *validity* — re-prompt after this many months (checked via timestamp). */
30
+ expiryMonths: number;
31
+ /** Cookie *lifetime* in days — kept longer than validity (and refreshed each visit)
32
+ * so a stale-but-present cookie can be told apart from an absent one. Browser caps at 400. */
33
+ cookieMaxAgeDays: number;
34
+ };
35
+ export type UseCookieConsentOptions = Partial<Config>;
36
+ export declare const config: Config;
37
+ /**
38
+ * Patch the module config in place. Callers can't reassign the imported `config`
39
+ * binding (ES module imports are read-only), so mutate its properties instead.
40
+ */
41
+ export declare function configure(options?: UseCookieConsentOptions): void;
42
+ export declare function isWithinAutoConsentWindow(): boolean;
43
+ /** Parse the cookie. Returns the record if present and parseable, else null. */
44
+ export declare function readRaw(): StoredConsent | null;
45
+ /** A record is valid if it matches the current policy version and is within the
46
+ * 13-month validity window. */
47
+ export declare function isValidConsent(data: StoredConsent | null): data is StoredConsent;
48
+ /** Record a new choice (stamps a fresh timestamp + current version). */
49
+ export declare function writeConsent(choice: ConsentChoice): StoredConsent;
50
+ /** True if any pre-existing analytics/functional cookie is present. Used to
51
+ * detect a pre-deploy "existing user" (Essential cookies are excluded). */
52
+ export declare function hasTrackingCookies(): boolean;
53
+ /** Delete the cookies of any category the choice denies. Idempotent (deleting an
54
+ * absent cookie is a no-op), so safe to call on every consent update. Tool-native
55
+ * clears (posthog.reset / Clarity consentv2) happen in the GTM tags. */
56
+ export declare function clearDeniedCookies(choice: ConsentChoice): void;
57
+ export declare function applyConsent(choice: ConsentChoice): void;
58
+ export {};
@@ -0,0 +1,134 @@
1
+ const p = [
2
+ {
3
+ id: "essential",
4
+ title: "Essential",
5
+ description: "Blocks DDoS attacks and prevents abuse.",
6
+ locked: !0
7
+ },
8
+ {
9
+ id: "analytics",
10
+ title: "Analytics & Customization",
11
+ description: "Session behaviour and product analytics to help us improve the app."
12
+ },
13
+ {
14
+ id: "functional",
15
+ title: "Performance & Functional",
16
+ description: "Traffic sources to help us understand how people discover Garden."
17
+ }
18
+ ], d = "garden:consentchange", i = "garden_consent", a = {
19
+ cookieDomain: ".garden.finance",
20
+ storageVersion: 1,
21
+ expiryMonths: 13,
22
+ cookieMaxAgeDays: 400
23
+ };
24
+ function g(n) {
25
+ n && Object.assign(a, n);
26
+ }
27
+ const u = "2026-06-12", l = 60;
28
+ function _() {
29
+ const n = new Date(u).getTime();
30
+ return Number.isNaN(n) ? !1 : Date.now() < n + l * 24 * 60 * 60 * 1e3;
31
+ }
32
+ function y() {
33
+ try {
34
+ const n = document.cookie.match(
35
+ new RegExp("(?:^|; )" + i + "=([^;]*)")
36
+ );
37
+ return n ? JSON.parse(decodeURIComponent(n[1])) : null;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+ function h(n) {
43
+ return !n || n.version !== a.storageVersion ? !1 : Date.now() - (n.timestamp || 0) <= a.expiryMonths * 30 * 24 * 60 * 60 * 1e3;
44
+ }
45
+ function f(n) {
46
+ const t = encodeURIComponent(JSON.stringify(n)), e = a.cookieMaxAgeDays * 24 * 60 * 60;
47
+ document.cookie = i + "=" + t + "; domain=" + a.cookieDomain + "; path=/; max-age=" + e + "; SameSite=Lax; Secure";
48
+ }
49
+ function C(n) {
50
+ const t = {
51
+ essential: !0,
52
+ analytics: !!n.analytics,
53
+ functional: !!n.functional,
54
+ timestamp: Date.now(),
55
+ version: a.storageVersion
56
+ };
57
+ return f(t), t;
58
+ }
59
+ const s = [
60
+ /^_ga(_.*)?$/,
61
+ // GA4: _ga and _ga_<measurementId>
62
+ /^original_referrer$/,
63
+ // Garden telemetry
64
+ /^original_landing_url$/
65
+ // Garden telemetry
66
+ ], c = [
67
+ /^ph_.*$/,
68
+ // PostHog
69
+ /^_clck$/,
70
+ // MS Clarity
71
+ /^_clsk$/
72
+ // MS Clarity
73
+ ];
74
+ function r() {
75
+ return typeof document > "u" || !document.cookie ? [] : document.cookie.split(";").map((n) => n.split("=")[0].trim());
76
+ }
77
+ function E() {
78
+ const n = [
79
+ ...s,
80
+ ...c
81
+ ];
82
+ return r().some((t) => n.some((e) => e.test(t)));
83
+ }
84
+ function m(n) {
85
+ [
86
+ "",
87
+ "; domain=" + a.cookieDomain,
88
+ typeof location < "u" ? "; domain=" + location.hostname : ""
89
+ ].forEach((e) => {
90
+ document.cookie = n + "=; path=/; max-age=0" + e;
91
+ });
92
+ }
93
+ function k(n) {
94
+ const t = [];
95
+ n.analytics || t.push(...s), n.functional || t.push(...c), t.length && r().forEach((e) => {
96
+ t.some((o) => o.test(e)) && m(e);
97
+ });
98
+ }
99
+ function O(n) {
100
+ const t = n.analytics ? "granted" : "denied", e = n.functional ? "granted" : "denied", o = window;
101
+ typeof o.gtag == "function" && o.gtag("consent", "update", {
102
+ analytics_storage: t,
103
+ personalization_storage: t,
104
+ functionality_storage: e,
105
+ ad_storage: "denied",
106
+ ad_user_data: "denied",
107
+ ad_personalization: "denied"
108
+ }), o.dataLayer = o.dataLayer || [], o.dataLayer.push({
109
+ event: "consent_update",
110
+ analytics_consent: t,
111
+ functional_consent: e
112
+ });
113
+ try {
114
+ window.dispatchEvent(
115
+ new CustomEvent(d, {
116
+ detail: { analytics: n.analytics, functional: n.functional }
117
+ })
118
+ );
119
+ } catch {
120
+ }
121
+ }
122
+ export {
123
+ d as CONSENT_EVENT,
124
+ p as DEFAULT_COOKIE_CATEGORIES,
125
+ O as applyConsent,
126
+ k as clearDeniedCookies,
127
+ a as config,
128
+ g as configure,
129
+ E as hasTrackingCookies,
130
+ h as isValidConsent,
131
+ _ as isWithinAutoConsentWindow,
132
+ y as readRaw,
133
+ C as writeConsent
134
+ };