@grainql/analytics-web 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/activity.d.ts +59 -0
  2. package/dist/activity.d.ts.map +1 -0
  3. package/dist/cjs/activity.d.ts +59 -0
  4. package/dist/cjs/activity.d.ts.map +1 -0
  5. package/dist/cjs/activity.js +131 -0
  6. package/dist/cjs/activity.js.map +1 -0
  7. package/dist/cjs/consent.d.ts +68 -0
  8. package/dist/cjs/consent.d.ts.map +1 -0
  9. package/dist/cjs/consent.js +191 -0
  10. package/dist/cjs/consent.js.map +1 -0
  11. package/dist/cjs/cookies.d.ts +28 -0
  12. package/dist/cjs/cookies.d.ts.map +1 -0
  13. package/dist/cjs/cookies.js +95 -0
  14. package/dist/cjs/cookies.js.map +1 -0
  15. package/dist/cjs/heartbeat.d.ts +42 -0
  16. package/dist/cjs/heartbeat.d.ts.map +1 -0
  17. package/dist/cjs/heartbeat.js +92 -0
  18. package/dist/cjs/heartbeat.js.map +1 -0
  19. package/dist/cjs/index.d.ts +100 -3
  20. package/dist/cjs/index.d.ts.map +1 -1
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/page-tracking.d.ts +60 -0
  23. package/dist/cjs/page-tracking.d.ts.map +1 -0
  24. package/dist/cjs/page-tracking.js +180 -0
  25. package/dist/cjs/page-tracking.js.map +1 -0
  26. package/dist/cjs/react/components/ConsentBanner.d.ts +16 -0
  27. package/dist/cjs/react/components/ConsentBanner.d.ts.map +1 -0
  28. package/dist/cjs/react/components/ConsentBanner.js +112 -0
  29. package/dist/cjs/react/components/ConsentBanner.js.map +1 -0
  30. package/dist/cjs/react/components/CookieNotice.d.ts +12 -0
  31. package/dist/cjs/react/components/CookieNotice.d.ts.map +1 -0
  32. package/dist/cjs/react/components/CookieNotice.js +62 -0
  33. package/dist/cjs/react/components/CookieNotice.js.map +1 -0
  34. package/dist/cjs/react/components/PrivacyPreferenceCenter.d.ts +12 -0
  35. package/dist/cjs/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
  36. package/dist/cjs/react/components/PrivacyPreferenceCenter.js +120 -0
  37. package/dist/cjs/react/components/PrivacyPreferenceCenter.js.map +1 -0
  38. package/dist/cjs/react/hooks/useConsent.d.ts +13 -0
  39. package/dist/cjs/react/hooks/useConsent.d.ts.map +1 -0
  40. package/dist/cjs/react/hooks/useConsent.js +84 -0
  41. package/dist/cjs/react/hooks/useConsent.js.map +1 -0
  42. package/dist/cjs/react/hooks/useDataDeletion.d.ts +17 -0
  43. package/dist/cjs/react/hooks/useDataDeletion.d.ts.map +1 -0
  44. package/dist/cjs/react/hooks/useDataDeletion.js +117 -0
  45. package/dist/cjs/react/hooks/useDataDeletion.js.map +1 -0
  46. package/dist/cjs/react/hooks/usePrivacyPreferences.d.ts +15 -0
  47. package/dist/cjs/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
  48. package/dist/cjs/react/hooks/usePrivacyPreferences.js +82 -0
  49. package/dist/cjs/react/hooks/usePrivacyPreferences.js.map +1 -0
  50. package/dist/cjs/react/index.d.ts +11 -0
  51. package/dist/cjs/react/index.d.ts.map +1 -1
  52. package/dist/cjs/react/index.js +15 -1
  53. package/dist/cjs/react/index.js.map +1 -1
  54. package/dist/consent.d.ts +68 -0
  55. package/dist/consent.d.ts.map +1 -0
  56. package/dist/cookies.d.ts +28 -0
  57. package/dist/cookies.d.ts.map +1 -0
  58. package/dist/esm/activity.d.ts +59 -0
  59. package/dist/esm/activity.d.ts.map +1 -0
  60. package/dist/esm/activity.js +127 -0
  61. package/dist/esm/activity.js.map +1 -0
  62. package/dist/esm/consent.d.ts +68 -0
  63. package/dist/esm/consent.d.ts.map +1 -0
  64. package/dist/esm/consent.js +187 -0
  65. package/dist/esm/consent.js.map +1 -0
  66. package/dist/esm/cookies.d.ts +28 -0
  67. package/dist/esm/cookies.d.ts.map +1 -0
  68. package/dist/esm/cookies.js +89 -0
  69. package/dist/esm/cookies.js.map +1 -0
  70. package/dist/esm/heartbeat.d.ts +42 -0
  71. package/dist/esm/heartbeat.d.ts.map +1 -0
  72. package/dist/esm/heartbeat.js +88 -0
  73. package/dist/esm/heartbeat.js.map +1 -0
  74. package/dist/esm/index.d.ts +100 -3
  75. package/dist/esm/index.d.ts.map +1 -1
  76. package/dist/esm/index.js.map +1 -1
  77. package/dist/esm/page-tracking.d.ts +60 -0
  78. package/dist/esm/page-tracking.d.ts.map +1 -0
  79. package/dist/esm/page-tracking.js +176 -0
  80. package/dist/esm/page-tracking.js.map +1 -0
  81. package/dist/esm/react/components/ConsentBanner.d.ts +16 -0
  82. package/dist/esm/react/components/ConsentBanner.d.ts.map +1 -0
  83. package/dist/esm/react/components/ConsentBanner.js +76 -0
  84. package/dist/esm/react/components/ConsentBanner.js.map +1 -0
  85. package/dist/esm/react/components/CookieNotice.d.ts +12 -0
  86. package/dist/esm/react/components/CookieNotice.d.ts.map +1 -0
  87. package/dist/esm/react/components/CookieNotice.js +26 -0
  88. package/dist/esm/react/components/CookieNotice.js.map +1 -0
  89. package/dist/esm/react/components/PrivacyPreferenceCenter.d.ts +12 -0
  90. package/dist/esm/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
  91. package/dist/esm/react/components/PrivacyPreferenceCenter.js +84 -0
  92. package/dist/esm/react/components/PrivacyPreferenceCenter.js.map +1 -0
  93. package/dist/esm/react/hooks/useConsent.d.ts +13 -0
  94. package/dist/esm/react/hooks/useConsent.d.ts.map +1 -0
  95. package/dist/esm/react/hooks/useConsent.js +48 -0
  96. package/dist/esm/react/hooks/useConsent.js.map +1 -0
  97. package/dist/esm/react/hooks/useDataDeletion.d.ts +17 -0
  98. package/dist/esm/react/hooks/useDataDeletion.d.ts.map +1 -0
  99. package/dist/esm/react/hooks/useDataDeletion.js +81 -0
  100. package/dist/esm/react/hooks/useDataDeletion.js.map +1 -0
  101. package/dist/esm/react/hooks/usePrivacyPreferences.d.ts +15 -0
  102. package/dist/esm/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
  103. package/dist/esm/react/hooks/usePrivacyPreferences.js +46 -0
  104. package/dist/esm/react/hooks/usePrivacyPreferences.js.map +1 -0
  105. package/dist/esm/react/index.d.ts +11 -0
  106. package/dist/esm/react/index.d.ts.map +1 -1
  107. package/dist/esm/react/index.js +8 -0
  108. package/dist/esm/react/index.js.map +1 -1
  109. package/dist/heartbeat.d.ts +42 -0
  110. package/dist/heartbeat.d.ts.map +1 -0
  111. package/dist/index.d.ts +100 -3
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.global.dev.js +903 -12
  114. package/dist/index.global.dev.js.map +3 -3
  115. package/dist/index.global.js +2 -2
  116. package/dist/index.global.js.map +4 -4
  117. package/dist/index.js +321 -11
  118. package/dist/index.mjs +321 -11
  119. package/dist/page-tracking.d.ts +60 -0
  120. package/dist/page-tracking.d.ts.map +1 -0
  121. package/dist/react/activity.d.ts +59 -0
  122. package/dist/react/activity.d.ts.map +1 -0
  123. package/dist/react/activity.js +130 -0
  124. package/dist/react/activity.mjs +126 -0
  125. package/dist/react/consent.d.ts +68 -0
  126. package/dist/react/consent.d.ts.map +1 -0
  127. package/dist/react/consent.js +190 -0
  128. package/dist/react/consent.mjs +186 -0
  129. package/dist/react/cookies.d.ts +28 -0
  130. package/dist/react/cookies.d.ts.map +1 -0
  131. package/dist/react/cookies.js +94 -0
  132. package/dist/react/cookies.mjs +88 -0
  133. package/dist/react/heartbeat.d.ts +42 -0
  134. package/dist/react/heartbeat.d.ts.map +1 -0
  135. package/dist/react/heartbeat.js +91 -0
  136. package/dist/react/heartbeat.mjs +87 -0
  137. package/dist/react/index.d.ts +100 -3
  138. package/dist/react/index.d.ts.map +1 -1
  139. package/dist/react/index.js +321 -11
  140. package/dist/react/index.mjs +321 -11
  141. package/dist/react/page-tracking.d.ts +60 -0
  142. package/dist/react/page-tracking.d.ts.map +1 -0
  143. package/dist/react/page-tracking.js +179 -0
  144. package/dist/react/page-tracking.mjs +175 -0
  145. package/dist/react/react/components/ConsentBanner.d.ts +16 -0
  146. package/dist/react/react/components/ConsentBanner.d.ts.map +1 -0
  147. package/dist/react/react/components/ConsentBanner.js +78 -0
  148. package/dist/react/react/components/ConsentBanner.mjs +75 -0
  149. package/dist/react/react/components/CookieNotice.d.ts +12 -0
  150. package/dist/react/react/components/CookieNotice.d.ts.map +1 -0
  151. package/dist/react/react/components/CookieNotice.js +28 -0
  152. package/dist/react/react/components/CookieNotice.mjs +25 -0
  153. package/dist/react/react/components/PrivacyPreferenceCenter.d.ts +12 -0
  154. package/dist/react/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
  155. package/dist/react/react/components/PrivacyPreferenceCenter.js +86 -0
  156. package/dist/react/react/components/PrivacyPreferenceCenter.mjs +83 -0
  157. package/dist/react/react/hooks/useConsent.d.ts +13 -0
  158. package/dist/react/react/hooks/useConsent.d.ts.map +1 -0
  159. package/dist/react/react/hooks/useConsent.js +50 -0
  160. package/dist/react/react/hooks/useConsent.mjs +47 -0
  161. package/dist/react/react/hooks/useDataDeletion.d.ts +17 -0
  162. package/dist/react/react/hooks/useDataDeletion.d.ts.map +1 -0
  163. package/dist/react/react/hooks/useDataDeletion.js +83 -0
  164. package/dist/react/react/hooks/useDataDeletion.mjs +80 -0
  165. package/dist/react/react/hooks/usePrivacyPreferences.d.ts +15 -0
  166. package/dist/react/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
  167. package/dist/react/react/hooks/usePrivacyPreferences.js +48 -0
  168. package/dist/react/react/hooks/usePrivacyPreferences.mjs +45 -0
  169. package/dist/react/react/index.d.ts +11 -0
  170. package/dist/react/react/index.d.ts.map +1 -1
  171. package/dist/react/react/index.js +15 -1
  172. package/dist/react/react/index.mjs +8 -0
  173. package/package.json +1 -1
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ /**
3
+ * Page Tracking for Grain Analytics
4
+ * Automatically tracks page views with consent-aware behavior
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PageTrackingManager = void 0;
8
+ class PageTrackingManager {
9
+ constructor(tracker, config) {
10
+ this.isDestroyed = false;
11
+ this.currentPath = null;
12
+ this.originalPushState = null;
13
+ this.originalReplaceState = null;
14
+ /**
15
+ * Handle popstate event (back/forward navigation)
16
+ */
17
+ this.handlePopState = () => {
18
+ if (this.isDestroyed)
19
+ return;
20
+ this.trackCurrentPage();
21
+ };
22
+ /**
23
+ * Handle hash change event
24
+ */
25
+ this.handleHashChange = () => {
26
+ if (this.isDestroyed)
27
+ return;
28
+ this.trackCurrentPage();
29
+ };
30
+ this.tracker = tracker;
31
+ this.config = config;
32
+ // Track initial page load
33
+ this.trackCurrentPage();
34
+ // Setup listeners
35
+ this.setupHistoryListeners();
36
+ this.setupHashChangeListener();
37
+ }
38
+ /**
39
+ * Setup History API listeners (pushState, replaceState, popstate)
40
+ */
41
+ setupHistoryListeners() {
42
+ if (typeof window === 'undefined' || typeof history === 'undefined')
43
+ return;
44
+ // Wrap pushState
45
+ this.originalPushState = history.pushState;
46
+ history.pushState = (state, title, url) => {
47
+ this.originalPushState?.call(history, state, title, url);
48
+ this.trackCurrentPage();
49
+ };
50
+ // Wrap replaceState
51
+ this.originalReplaceState = history.replaceState;
52
+ history.replaceState = (state, title, url) => {
53
+ this.originalReplaceState?.call(history, state, title, url);
54
+ this.trackCurrentPage();
55
+ };
56
+ // Listen to popstate (back/forward buttons)
57
+ window.addEventListener('popstate', this.handlePopState);
58
+ }
59
+ /**
60
+ * Setup hash change listener
61
+ */
62
+ setupHashChangeListener() {
63
+ if (typeof window === 'undefined')
64
+ return;
65
+ window.addEventListener('hashchange', this.handleHashChange);
66
+ }
67
+ /**
68
+ * Track the current page
69
+ */
70
+ trackCurrentPage() {
71
+ if (this.isDestroyed || typeof window === 'undefined')
72
+ return;
73
+ const page = this.extractPath(window.location.href);
74
+ // Don't track if it's the same page
75
+ if (page === this.currentPath) {
76
+ return;
77
+ }
78
+ this.currentPath = page;
79
+ const hasConsent = this.tracker.hasConsent('analytics');
80
+ // Base properties (always included)
81
+ const properties = {
82
+ page,
83
+ timestamp: Date.now(),
84
+ };
85
+ // Enhanced properties when consent is granted
86
+ if (hasConsent) {
87
+ properties.referrer = document.referrer || '';
88
+ properties.title = document.title || '';
89
+ properties.full_url = window.location.href;
90
+ }
91
+ // Track the page view event
92
+ this.tracker.trackSystemEvent('page_view', properties);
93
+ if (this.config.debug) {
94
+ console.log('[Page Tracking] Tracked page view:', properties);
95
+ }
96
+ }
97
+ /**
98
+ * Extract path from URL, optionally stripping query parameters
99
+ */
100
+ extractPath(url) {
101
+ try {
102
+ const urlObj = new URL(url);
103
+ let path = urlObj.pathname + urlObj.hash;
104
+ if (!this.config.stripQueryParams && urlObj.search) {
105
+ path += urlObj.search;
106
+ }
107
+ return path;
108
+ }
109
+ catch (error) {
110
+ // If URL parsing fails, return the raw string
111
+ if (this.config.debug) {
112
+ console.warn('[Page Tracking] Failed to parse URL:', url, error);
113
+ }
114
+ return url;
115
+ }
116
+ }
117
+ /**
118
+ * Get the current page path
119
+ */
120
+ getCurrentPage() {
121
+ return this.currentPath;
122
+ }
123
+ /**
124
+ * Manually track a page view (for custom navigation)
125
+ */
126
+ trackPage(page, properties) {
127
+ if (this.isDestroyed)
128
+ return;
129
+ const hasConsent = this.tracker.hasConsent('analytics');
130
+ // Base properties
131
+ const baseProperties = {
132
+ page,
133
+ timestamp: Date.now(),
134
+ ...properties,
135
+ };
136
+ // Enhanced properties when consent is granted
137
+ if (hasConsent && typeof document !== 'undefined') {
138
+ if (!baseProperties.referrer) {
139
+ baseProperties.referrer = document.referrer || '';
140
+ }
141
+ if (!baseProperties.title) {
142
+ baseProperties.title = document.title || '';
143
+ }
144
+ if (!baseProperties.full_url && typeof window !== 'undefined') {
145
+ baseProperties.full_url = window.location.href;
146
+ }
147
+ }
148
+ this.tracker.trackSystemEvent('page_view', baseProperties);
149
+ if (this.config.debug) {
150
+ console.log('[Page Tracking] Manually tracked page:', baseProperties);
151
+ }
152
+ }
153
+ /**
154
+ * Destroy the page tracker
155
+ */
156
+ destroy() {
157
+ if (this.isDestroyed)
158
+ return;
159
+ // Restore original history methods
160
+ if (typeof history !== 'undefined') {
161
+ if (this.originalPushState) {
162
+ history.pushState = this.originalPushState;
163
+ }
164
+ if (this.originalReplaceState) {
165
+ history.replaceState = this.originalReplaceState;
166
+ }
167
+ }
168
+ // Remove event listeners
169
+ if (typeof window !== 'undefined') {
170
+ window.removeEventListener('popstate', this.handlePopState);
171
+ window.removeEventListener('hashchange', this.handleHashChange);
172
+ }
173
+ this.isDestroyed = true;
174
+ if (this.config.debug) {
175
+ console.log('[Page Tracking] Destroyed');
176
+ }
177
+ }
178
+ }
179
+ exports.PageTrackingManager = PageTrackingManager;
180
+ //# sourceMappingURL=page-tracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-tracking.js","sourceRoot":"","sources":["../../src/page-tracking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * ConsentBanner - Glassmorphic consent popup for GDPR compliance
3
+ * Follows Grain Design System specifications
4
+ */
5
+ import * as React from 'react';
6
+ export interface ConsentBannerProps {
7
+ position?: 'top' | 'bottom' | 'center';
8
+ theme?: 'light' | 'dark' | 'glass';
9
+ customText?: string;
10
+ onAccept?: () => void;
11
+ onDecline?: () => void;
12
+ showPreferences?: boolean;
13
+ privacyPolicyUrl?: string;
14
+ }
15
+ export declare function ConsentBanner({ position, theme, customText, onAccept, onDecline, showPreferences, privacyPolicyUrl, }: ConsentBannerProps): React.JSX.Element | null;
16
+ //# sourceMappingURL=ConsentBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsentBanner.d.ts","sourceRoot":"","sources":["../../../../src/react/components/ConsentBanner.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,aAAa,CAAC,EAC5B,QAAmB,EACnB,KAAe,EACf,UAAU,EACV,QAAQ,EACR,SAAS,EACT,eAAuB,EACvB,gBAAgB,GACjB,EAAE,kBAAkB,4BA8HpB"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * ConsentBanner - Glassmorphic consent popup for GDPR compliance
4
+ * Follows Grain Design System specifications
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.ConsentBanner = ConsentBanner;
41
+ const React = __importStar(require("react"));
42
+ const useGrainAnalytics_1 = require("../hooks/useGrainAnalytics");
43
+ function ConsentBanner({ position = 'bottom', theme = 'glass', customText, onAccept, onDecline, showPreferences = false, privacyPolicyUrl, }) {
44
+ const client = (0, useGrainAnalytics_1.useGrainAnalytics)();
45
+ const [visible, setVisible] = React.useState(false);
46
+ const [showPreferencesModal, setShowPreferencesModal] = React.useState(false);
47
+ React.useEffect(() => {
48
+ if (!client)
49
+ return;
50
+ // Check if user has already made a consent decision
51
+ const consentState = client.getConsentState();
52
+ if (!consentState) {
53
+ setVisible(true);
54
+ }
55
+ }, [client]);
56
+ const handleAccept = () => {
57
+ if (client) {
58
+ client.grantConsent(['necessary', 'analytics', 'functional']);
59
+ }
60
+ setVisible(false);
61
+ onAccept?.();
62
+ };
63
+ const handleDecline = () => {
64
+ if (client) {
65
+ client.revokeConsent();
66
+ }
67
+ setVisible(false);
68
+ onDecline?.();
69
+ };
70
+ const handleEscape = (e) => {
71
+ if (e.key === 'Escape') {
72
+ handleDecline();
73
+ }
74
+ };
75
+ if (!visible)
76
+ return null;
77
+ const defaultText = customText ||
78
+ "We use cookies and similar technologies to improve your experience. By accepting, you consent to our use of analytics and functional cookies.";
79
+ // Position styles
80
+ const positionStyles = {
81
+ top: 'top-4 left-4 right-4',
82
+ bottom: 'bottom-4 left-4 right-4',
83
+ center: 'top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
84
+ };
85
+ // Theme styles (glassmorphic by default)
86
+ const themeStyles = {
87
+ light: 'bg-white/95 border-gray-200 text-gray-900',
88
+ dark: 'bg-zinc-900/95 border-zinc-800 text-zinc-100',
89
+ glass: 'bg-zinc-950/40 backdrop-blur-xl border-zinc-800/40 text-zinc-100',
90
+ };
91
+ const buttonAcceptStyles = {
92
+ light: 'bg-blue-600 hover:bg-blue-700 text-white',
93
+ dark: 'bg-emerald-600 hover:bg-emerald-700 text-white',
94
+ glass: 'bg-emerald-600 hover:bg-emerald-700 text-white',
95
+ };
96
+ const buttonDeclineStyles = {
97
+ light: 'bg-gray-200 hover:bg-gray-300 text-gray-800',
98
+ dark: 'bg-zinc-800 hover:bg-zinc-700 text-zinc-200',
99
+ glass: 'bg-zinc-900/60 hover:bg-zinc-800/60 text-zinc-300 border border-zinc-800/60',
100
+ };
101
+ return (React.createElement("div", { className: `fixed z-50 max-w-2xl ${positionStyles[position]}`, onKeyDown: handleEscape, role: "dialog", "aria-labelledby": "consent-title", "aria-describedby": "consent-description" },
102
+ React.createElement("div", { className: `rounded-lg shadow-2xl border p-6 transition-all ${themeStyles[theme]}` },
103
+ React.createElement("h2", { id: "consent-title", className: "text-lg font-semibold mb-2" }, "Cookie Consent"),
104
+ React.createElement("p", { id: "consent-description", className: "text-sm opacity-80 mb-4" }, defaultText),
105
+ privacyPolicyUrl && (React.createElement("a", { href: privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", className: "text-sm underline opacity-70 hover:opacity-100 transition-opacity block mb-4" }, "Read our Privacy Policy")),
106
+ React.createElement("div", { className: "flex flex-wrap gap-2" },
107
+ React.createElement("button", { onClick: handleAccept, className: `px-4 py-2 rounded-lg font-medium transition-all ${buttonAcceptStyles[theme]}`, "aria-label": "Accept cookies" }, "Accept All"),
108
+ React.createElement("button", { onClick: handleDecline, className: `px-4 py-2 rounded-lg font-medium transition-all ${buttonDeclineStyles[theme]}`, "aria-label": "Decline cookies" }, "Decline"),
109
+ showPreferences && (React.createElement("button", { onClick: () => setShowPreferencesModal(true), className: `px-4 py-2 rounded-lg font-medium transition-all ${buttonDeclineStyles[theme]}`, "aria-label": "Manage preferences" }, "Manage Preferences")),
110
+ React.createElement("kbd", { className: "ml-auto px-2 py-1 bg-zinc-900/50 border border-zinc-800 rounded text-[10px] font-mono self-center" }, "ESC")))));
111
+ }
112
+ //# sourceMappingURL=ConsentBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsentBanner.js","sourceRoot":"","sources":["../../../../src/react/components/ConsentBanner.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CookieNotice - Simple cookie notification banner
3
+ */
4
+ import * as React from 'react';
5
+ export interface CookieNoticeProps {
6
+ message?: string;
7
+ privacyPolicyUrl?: string;
8
+ onDismiss?: () => void;
9
+ position?: 'top' | 'bottom';
10
+ }
11
+ export declare function CookieNotice({ message, privacyPolicyUrl, onDismiss, position, }: CookieNoticeProps): React.JSX.Element | null;
12
+ //# sourceMappingURL=CookieNotice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookieNotice.d.ts","sourceRoot":"","sources":["../../../../src/react/components/CookieNotice.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,QAAmB,GACpB,EAAE,iBAAiB,4BA6CnB"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * CookieNotice - Simple cookie notification banner
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.CookieNotice = CookieNotice;
40
+ const React = __importStar(require("react"));
41
+ function CookieNotice({ message, privacyPolicyUrl, onDismiss, position = 'bottom', }) {
42
+ const [visible, setVisible] = React.useState(true);
43
+ const defaultMessage = message ||
44
+ "This website uses cookies to enhance your experience.";
45
+ const handleDismiss = () => {
46
+ setVisible(false);
47
+ onDismiss?.();
48
+ };
49
+ if (!visible)
50
+ return null;
51
+ const positionStyles = position === 'top' ? 'top-0' : 'bottom-0';
52
+ return (React.createElement("div", { className: `fixed ${positionStyles} left-0 right-0 z-40` },
53
+ React.createElement("div", { className: "bg-zinc-950/90 backdrop-blur-sm border-t border-zinc-800/40 px-4 py-3" },
54
+ React.createElement("div", { className: "max-w-7xl mx-auto flex items-center justify-between gap-4" },
55
+ React.createElement("p", { className: "text-sm text-zinc-300" },
56
+ defaultMessage,
57
+ privacyPolicyUrl && (React.createElement(React.Fragment, null,
58
+ ' ',
59
+ React.createElement("a", { href: privacyPolicyUrl, target: "_blank", rel: "noopener noreferrer", className: "underline opacity-70 hover:opacity-100 transition-opacity" }, "Learn more")))),
60
+ React.createElement("button", { onClick: handleDismiss, className: "px-3 py-1 bg-zinc-800/60 hover:bg-zinc-700/60 text-zinc-300 rounded text-sm font-medium transition-all flex-shrink-0" }, "Dismiss")))));
61
+ }
62
+ //# sourceMappingURL=CookieNotice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CookieNotice.js","sourceRoot":"","sources":["../../../../src/react/components/CookieNotice.tsx"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWH,oCAkDC;AA3DD,6CAA+B;AAS/B,SAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,QAAQ,GAAG,QAAQ,GACD;IAClB,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEnD,MAAM,cAAc,GAAG,OAAO;QAC5B,uDAAuD,CAAC;IAE1D,MAAM,aAAa,GAAG,GAAG,EAAE;QACzB,UAAU,CAAC,KAAK,CAAC,CAAC;QAClB,SAAS,EAAE,EAAE,CAAC;IAChB,CAAC,CAAC;IAEF,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,cAAc,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC;IAEjE,OAAO,CACL,6BAAK,SAAS,EAAE,SAAS,cAAc,sBAAsB;QAC3D,6BAAK,SAAS,EAAC,uEAAuE;YACpF,6BAAK,SAAS,EAAC,2DAA2D;gBACxE,2BAAG,SAAS,EAAC,uBAAuB;oBACjC,cAAc;oBACd,gBAAgB,IAAI,CACnB;wBACG,GAAG;wBACJ,2BACE,IAAI,EAAE,gBAAgB,EACtB,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,qBAAqB,EACzB,SAAS,EAAC,2DAA2D,iBAGnE,CACH,CACJ,CACC;gBACJ,gCACE,OAAO,EAAE,aAAa,EACtB,SAAS,EAAC,sHAAsH,cAGzH,CACL,CACF,CACF,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * PrivacyPreferenceCenter - Detailed preference management modal
3
+ * Follows Grain Design System specifications
4
+ */
5
+ import * as React from 'react';
6
+ export interface PrivacyPreferenceCenterProps {
7
+ isOpen: boolean;
8
+ onClose: () => void;
9
+ onSave?: (categories: string[]) => void;
10
+ }
11
+ export declare function PrivacyPreferenceCenter({ isOpen, onClose, onSave, }: PrivacyPreferenceCenterProps): React.JSX.Element | null;
12
+ //# sourceMappingURL=PrivacyPreferenceCenter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrivacyPreferenceCenter.d.ts","sourceRoot":"","sources":["../../../../src/react/components/PrivacyPreferenceCenter.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACzC;AA8BD,wBAAgB,uBAAuB,CAAC,EACtC,MAAM,EACN,OAAO,EACP,MAAM,GACP,EAAE,4BAA4B,4BAkH9B"}
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ /**
3
+ * PrivacyPreferenceCenter - Detailed preference management modal
4
+ * Follows Grain Design System specifications
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.PrivacyPreferenceCenter = PrivacyPreferenceCenter;
41
+ const React = __importStar(require("react"));
42
+ const useGrainAnalytics_1 = require("../hooks/useGrainAnalytics");
43
+ const CATEGORIES = [
44
+ {
45
+ id: 'necessary',
46
+ name: 'Necessary',
47
+ description: 'Essential for the website to function properly. Cannot be disabled.',
48
+ required: true,
49
+ },
50
+ {
51
+ id: 'analytics',
52
+ name: 'Analytics',
53
+ description: 'Help us understand how visitors interact with our website.',
54
+ required: false,
55
+ },
56
+ {
57
+ id: 'functional',
58
+ name: 'Functional',
59
+ description: 'Enable enhanced functionality and personalization.',
60
+ required: false,
61
+ },
62
+ ];
63
+ function PrivacyPreferenceCenter({ isOpen, onClose, onSave, }) {
64
+ const client = (0, useGrainAnalytics_1.useGrainAnalytics)();
65
+ const [selectedCategories, setSelectedCategories] = React.useState(['necessary']);
66
+ React.useEffect(() => {
67
+ if (!client)
68
+ return;
69
+ const consentState = client.getConsentState();
70
+ if (consentState) {
71
+ setSelectedCategories(consentState.categories);
72
+ }
73
+ }, [client, isOpen]);
74
+ const handleToggle = (categoryId, required) => {
75
+ if (required)
76
+ return; // Cannot toggle required categories
77
+ setSelectedCategories((prev) => prev.includes(categoryId)
78
+ ? prev.filter((id) => id !== categoryId)
79
+ : [...prev, categoryId]);
80
+ };
81
+ const handleSave = () => {
82
+ if (client) {
83
+ if (selectedCategories.length > 0) {
84
+ client.grantConsent(selectedCategories);
85
+ }
86
+ else {
87
+ client.revokeConsent();
88
+ }
89
+ }
90
+ onSave?.(selectedCategories);
91
+ onClose();
92
+ };
93
+ const handleEscape = (e) => {
94
+ if (e.key === 'Escape') {
95
+ onClose();
96
+ }
97
+ };
98
+ if (!isOpen)
99
+ return null;
100
+ return (React.createElement("div", { className: "fixed inset-0 z-50 flex items-center justify-center", onKeyDown: handleEscape, role: "dialog", "aria-labelledby": "preferences-title", "aria-modal": "true" },
101
+ React.createElement("div", { className: "fixed inset-0 bg-zinc-950/80 backdrop-blur-sm", onClick: onClose }),
102
+ React.createElement("div", { className: "relative bg-zinc-950/95 border border-zinc-800/60 backdrop-blur-xl rounded-lg shadow-2xl max-w-2xl w-full mx-4 p-6" },
103
+ React.createElement("h2", { id: "preferences-title", className: "text-xl font-semibold text-zinc-100 mb-4" }, "Privacy Preferences"),
104
+ React.createElement("div", { className: "space-y-4 mb-6" }, CATEGORIES.map((category) => (React.createElement("div", { key: category.id, className: "p-4 bg-zinc-900/40 border border-zinc-800/40 rounded-lg" },
105
+ React.createElement("div", { className: "flex items-start justify-between" },
106
+ React.createElement("div", { className: "flex-1" },
107
+ React.createElement("h3", { className: "font-medium text-zinc-200 mb-1" },
108
+ category.name,
109
+ category.required && (React.createElement("span", { className: "ml-2 text-xs text-emerald-500" }, "(Required)"))),
110
+ React.createElement("p", { className: "text-sm text-zinc-400" }, category.description)),
111
+ React.createElement("label", { className: "relative inline-flex items-center cursor-pointer" },
112
+ React.createElement("input", { type: "checkbox", checked: selectedCategories.includes(category.id), onChange: () => handleToggle(category.id, category.required), disabled: category.required, className: "sr-only peer" }),
113
+ React.createElement("div", { className: "w-11 h-6 bg-zinc-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-600" }))))))),
114
+ React.createElement("div", { className: "flex justify-end gap-2" },
115
+ React.createElement("button", { onClick: onClose, className: "px-4 py-2 bg-zinc-900/60 hover:bg-zinc-800/60 text-zinc-300 border border-zinc-800/60 rounded-lg font-medium transition-all" },
116
+ "Cancel",
117
+ React.createElement("kbd", { className: "ml-2 px-2 py-0.5 bg-zinc-900/50 border border-zinc-800 rounded text-[10px] font-mono" }, "ESC")),
118
+ React.createElement("button", { onClick: handleSave, className: "px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg font-medium transition-all" }, "Save Preferences")))));
119
+ }
120
+ //# sourceMappingURL=PrivacyPreferenceCenter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrivacyPreferenceCenter.js","sourceRoot":"","sources":["../../../../src/react/components/PrivacyPreferenceCenter.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * useConsent - Hook for managing user consent
3
+ */
4
+ import type { ConsentState } from '../../consent';
5
+ export declare function useConsent(): {
6
+ consentState: ConsentState | null;
7
+ grantConsent: (categories?: string[]) => void;
8
+ revokeConsent: (categories?: string[]) => void;
9
+ hasConsent: (category?: string) => boolean;
10
+ isGranted: boolean;
11
+ categories: string[];
12
+ };
13
+ //# sourceMappingURL=useConsent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConsent.d.ts","sourceRoot":"","sources":["../../../../src/react/hooks/useConsent.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,wBAAgB,UAAU;;gCAwBR,MAAM,EAAE;iCASR,MAAM,EAAE;4BASV,MAAM;;;EAerB"}