@c15t/dev-tools 0.0.1-rc.3

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 (89) hide show
  1. package/.turbo/turbo-build.log +56 -0
  2. package/.turbo/turbo-fmt.log +6 -0
  3. package/.turbo/turbo-lint.log +73 -0
  4. package/CHANGELOG.md +23 -0
  5. package/LICENSE.md +595 -0
  6. package/README.md +47 -0
  7. package/dist/components/error-state.cjs +126 -0
  8. package/dist/components/error-state.d.ts +6 -0
  9. package/dist/components/error-state.d.ts.map +1 -0
  10. package/dist/components/error-state.js +110 -0
  11. package/dist/components/header.cjs +88 -0
  12. package/dist/components/header.d.ts +8 -0
  13. package/dist/components/header.d.ts.map +1 -0
  14. package/dist/components/header.js +56 -0
  15. package/dist/components/ui/accordion.cjs +119 -0
  16. package/dist/components/ui/accordion.d.ts +34 -0
  17. package/dist/components/ui/accordion.d.ts.map +1 -0
  18. package/dist/components/ui/accordion.js +84 -0
  19. package/dist/components/ui/alert.cjs +104 -0
  20. package/dist/components/ui/alert.d.ts +25 -0
  21. package/dist/components/ui/alert.d.ts.map +1 -0
  22. package/dist/components/ui/alert.js +67 -0
  23. package/dist/components/ui/button.cjs +95 -0
  24. package/dist/components/ui/button.d.ts +28 -0
  25. package/dist/components/ui/button.d.ts.map +1 -0
  26. package/dist/components/ui/button.js +55 -0
  27. package/dist/components/ui/card.cjs +120 -0
  28. package/dist/components/ui/card.d.ts +30 -0
  29. package/dist/components/ui/card.d.ts.map +1 -0
  30. package/dist/components/ui/card.js +99 -0
  31. package/dist/components/ui/expandable-tabs.cjs +201 -0
  32. package/dist/components/ui/expandable-tabs.d.ts +29 -0
  33. package/dist/components/ui/expandable-tabs.d.ts.map +1 -0
  34. package/dist/components/ui/expandable-tabs.js +170 -0
  35. package/dist/components/ui/overlay.cjs +69 -0
  36. package/dist/components/ui/overlay.d.ts +7 -0
  37. package/dist/components/ui/overlay.d.ts.map +1 -0
  38. package/dist/components/ui/overlay.js +28 -0
  39. package/dist/components/ui/scroll-area.cjs +105 -0
  40. package/dist/components/ui/scroll-area.d.ts +19 -0
  41. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  42. package/dist/components/ui/scroll-area.js +74 -0
  43. package/dist/components/ui/switch.cjs +71 -0
  44. package/dist/components/ui/switch.d.ts +11 -0
  45. package/dist/components/ui/switch.d.ts.map +1 -0
  46. package/dist/components/ui/switch.js +33 -0
  47. package/dist/components/ui/tooltip.cjs +75 -0
  48. package/dist/components/ui/tooltip.d.ts +16 -0
  49. package/dist/components/ui/tooltip.d.ts.map +1 -0
  50. package/dist/components/ui/tooltip.js +38 -0
  51. package/dist/components/wrapper.cjs +197 -0
  52. package/dist/components/wrapper.d.ts +24 -0
  53. package/dist/components/wrapper.d.ts.map +1 -0
  54. package/dist/components/wrapper.js +165 -0
  55. package/dist/dev-tool.cjs +164 -0
  56. package/dist/dev-tool.d.ts +14 -0
  57. package/dist/dev-tool.d.ts.map +1 -0
  58. package/dist/dev-tool.js +110 -0
  59. package/dist/index.cjs +46 -0
  60. package/dist/index.d.ts +3 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +4 -0
  63. package/dist/libs/utils.cjs +69 -0
  64. package/dist/libs/utils.d.ts +3 -0
  65. package/dist/libs/utils.d.ts.map +1 -0
  66. package/dist/libs/utils.js +8 -0
  67. package/dist/router/router.cjs +278 -0
  68. package/dist/router/router.d.ts +8 -0
  69. package/dist/router/router.d.ts.map +1 -0
  70. package/dist/router/router.js +261 -0
  71. package/package.json +48 -0
  72. package/rslib.config.ts +28 -0
  73. package/src/components/error-state.tsx +44 -0
  74. package/src/components/header.tsx +28 -0
  75. package/src/components/ui/accordion.tsx +64 -0
  76. package/src/components/ui/alert.tsx +59 -0
  77. package/src/components/ui/button.tsx +56 -0
  78. package/src/components/ui/card.tsx +81 -0
  79. package/src/components/ui/expandable-tabs.tsx +174 -0
  80. package/src/components/ui/overlay.tsx +21 -0
  81. package/src/components/ui/scroll-area.tsx +52 -0
  82. package/src/components/ui/switch.tsx +28 -0
  83. package/src/components/ui/tooltip.tsx +32 -0
  84. package/src/components/wrapper.tsx +103 -0
  85. package/src/dev-tool.tsx +117 -0
  86. package/src/index.ts +3 -0
  87. package/src/libs/utils.ts +6 -0
  88. package/src/router/router.tsx +164 -0
  89. package/tsconfig.json +12 -0
@@ -0,0 +1,117 @@
1
+ 'use client';
2
+ import type { NamespaceProps, PrivacyConsentState } from 'c15t';
3
+
4
+ import {
5
+ type FC,
6
+ createContext,
7
+ useCallback,
8
+ useContext,
9
+ useEffect,
10
+ useState,
11
+ } from 'react';
12
+ import type { StoreApi } from 'zustand/vanilla';
13
+ import { ErrorState } from './components/error-state';
14
+ import { Header } from './components/header';
15
+ import DevToolWrapper from './components/wrapper';
16
+ import { Router } from './router/router';
17
+
18
+ const PrivacyConsentContext = createContext<{
19
+ state: PrivacyConsentState | null;
20
+ store: StoreApi<PrivacyConsentState> | null;
21
+ } | null>(null);
22
+
23
+ export const getStore = () => {
24
+ const context = useContext(PrivacyConsentContext);
25
+ if (context === null) {
26
+ throw new Error(
27
+ 'useConsentManagerContext must be used within a ConsentManagerProvider'
28
+ );
29
+ }
30
+
31
+ // Create a subscription to the store updates
32
+ const [localState, setLocalState] = useState(context.state);
33
+
34
+ useEffect(() => {
35
+ if (!context.store) {
36
+ return;
37
+ }
38
+
39
+ // Update local state when context state changes
40
+ setLocalState(context.state);
41
+
42
+ // Subscribe to store updates
43
+ const unsubscribe = context.store.subscribe(
44
+ (newState: PrivacyConsentState) => {
45
+ setLocalState(newState);
46
+ }
47
+ );
48
+
49
+ return () => {
50
+ unsubscribe();
51
+ };
52
+ }, [context.store, context.state]);
53
+
54
+ return localState;
55
+ };
56
+
57
+ export default PrivacyConsentContext;
58
+
59
+ interface ConsentManagerProviderProps extends NamespaceProps {
60
+ position?: 'bottom-right' | 'top-right' | 'bottom-left' | 'top-left';
61
+ }
62
+
63
+ export const ConsentManagerDevTool: FC<ConsentManagerProviderProps> = ({
64
+ namespace = 'c15tStore',
65
+ position = 'bottom-right',
66
+ }) => {
67
+ const [state, setState] = useState<PrivacyConsentState | null>(null);
68
+ const [store, setStore] = useState<StoreApi<PrivacyConsentState> | null>(
69
+ null
70
+ );
71
+ const [isOpen, setIsOpen] = useState(false);
72
+ const toggleOpen = useCallback(() => setIsOpen((prev) => !prev), []);
73
+
74
+ useEffect(() => {
75
+ const storeInstance =
76
+ (typeof window !== 'undefined' &&
77
+ (window as Window)[namespace as keyof Window]) ||
78
+ null;
79
+
80
+ if (storeInstance) {
81
+ setStore(storeInstance);
82
+ const currentState = storeInstance.getState() as PrivacyConsentState;
83
+ setState(currentState);
84
+
85
+ // Subscribe to store updates
86
+ const unsubscribe = storeInstance.subscribe(
87
+ (newState: PrivacyConsentState) => {
88
+ setState(newState);
89
+ }
90
+ );
91
+
92
+ return () => {
93
+ unsubscribe();
94
+ };
95
+ }
96
+ // biome-ignore lint/suspicious/noConsoleLog: needed for dev tools
97
+ // biome-ignore lint/suspicious/noConsole: needed for dev tools
98
+ console.log(`${namespace} is not available on the window object.`);
99
+ }, [namespace]);
100
+
101
+ return (
102
+ <PrivacyConsentContext.Provider value={{ state, store }}>
103
+ <DevToolWrapper
104
+ isOpen={isOpen}
105
+ toggleOpen={toggleOpen}
106
+ position={position}
107
+ >
108
+ <Header onClose={() => setIsOpen(false)} />
109
+ {state ? (
110
+ <Router onClose={() => setIsOpen(false)} />
111
+ ) : (
112
+ <ErrorState namespace={namespace} />
113
+ )}
114
+ </DevToolWrapper>
115
+ </PrivacyConsentContext.Provider>
116
+ );
117
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { ConsentManagerDevTool } from './dev-tool';
2
+
3
+ export default ConsentManagerDevTool;
@@ -0,0 +1,6 @@
1
+ import clsx, { type ClassValue } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,164 @@
1
+ 'use client';
2
+
3
+ import {
4
+ Cookie,
5
+ FileText,
6
+ GanttChartSquare,
7
+ RefreshCw,
8
+ ToggleLeft,
9
+ } from 'lucide-react';
10
+ import { motion } from 'motion/react';
11
+ import { useCallback, useState } from 'react';
12
+
13
+ import type { PrivacyConsentState } from 'c15t';
14
+ import { Button } from '../components/ui/button';
15
+ import { ExpandableTabs } from '../components/ui/expandable-tabs';
16
+ import { ScrollArea } from '../components/ui/scroll-area';
17
+ import { getStore } from '../dev-tool';
18
+ import { cn } from '../libs/utils';
19
+
20
+ type TabSection = 'Consents' | 'Compliance' | 'Scripts' | 'Conditional';
21
+
22
+ const tabs = [
23
+ { title: 'Consents' as const, icon: ToggleLeft },
24
+ { title: 'Compliance' as const, icon: GanttChartSquare },
25
+ ] as const;
26
+
27
+ interface ContentItem {
28
+ title: string;
29
+ status: string;
30
+ details?: string;
31
+ }
32
+
33
+ interface RouterProps {
34
+ onClose: () => void;
35
+ }
36
+
37
+ export function Router({ onClose }: RouterProps) {
38
+ const privacyConsent = getStore() as PrivacyConsentState;
39
+ const { clearAllData, setIsPrivacyDialogOpen, setShowPopup } = privacyConsent;
40
+
41
+ const [activeSection, setActiveSection] = useState<TabSection>('Consents');
42
+
43
+ // Handle tab change locally
44
+ const handleTabChange = useCallback((index: number | null) => {
45
+ if (index !== null) {
46
+ //@ts-expect-error
47
+ setActiveSection(tabs[index].title);
48
+ }
49
+ }, []);
50
+
51
+ // Compute rendering state without conditions
52
+ const renderingState = [
53
+ { componentName: 'MarketingContent', consentType: 'marketing' as const },
54
+ { componentName: 'AnalyticsContent', consentType: 'measurement' as const },
55
+ {
56
+ componentName: 'PersonalizationComponent',
57
+ consentType: 'ad_personalization' as const,
58
+ },
59
+ ];
60
+
61
+ // Compute content items based on active section
62
+ const contentItems: ContentItem[] =
63
+ activeSection === 'Consents'
64
+ ? Object.entries(privacyConsent.consents).map(([name, value]) => ({
65
+ title: name,
66
+ status: value ? 'Enabled' : 'Disabled',
67
+ }))
68
+ : activeSection === 'Compliance'
69
+ ? Object.entries(privacyConsent.complianceSettings).map(
70
+ ([region, settings]) => ({
71
+ title: region,
72
+ status: settings.enabled ? 'Active' : 'Inactive',
73
+ })
74
+ )
75
+ : activeSection === 'Conditional'
76
+ ? renderingState.map((item) => ({
77
+ title: item.componentName,
78
+ status: 'Rendered',
79
+ details: `Requires: ${item.consentType}`,
80
+ }))
81
+ : [];
82
+
83
+ const handleResetConsent = useCallback(() => {
84
+ clearAllData();
85
+ onClose();
86
+ }, [clearAllData, onClose]);
87
+
88
+ const handleOpenPrivacyModal = useCallback(() => {
89
+ setIsPrivacyDialogOpen(true);
90
+ }, [setIsPrivacyDialogOpen]);
91
+
92
+ const handleOpenCookiePopup = useCallback(() => {
93
+ setShowPopup(true);
94
+ }, [setShowPopup]);
95
+
96
+ return (
97
+ <>
98
+ <div className="border-b p-4">
99
+ <ExpandableTabs
100
+ tabs={Array.from(tabs)}
101
+ activeColor="text-primary"
102
+ className="border-muted"
103
+ onChange={handleTabChange}
104
+ />
105
+ </div>
106
+ <ScrollArea className="h-[300px]">
107
+ <motion.div
108
+ className="space-y-2 p-4"
109
+ initial={{ opacity: 0 }}
110
+ animate={{ opacity: 1 }}
111
+ exit={{ opacity: 0 }}
112
+ >
113
+ {contentItems.map((item, index) => (
114
+ <motion.div
115
+ key={`${activeSection}-${item.title}`}
116
+ className="flex items-center justify-between rounded-lg border bg-card p-3"
117
+ initial={{ opacity: 0, y: 20 }}
118
+ animate={{ opacity: 1, y: 0 }}
119
+ transition={{ delay: index * 0.05 }}
120
+ >
121
+ <div className="flex flex-col">
122
+ <span className="font-medium text-sm">{item.title}</span>
123
+ {item.details && (
124
+ <span className="text-muted-foreground text-xs">
125
+ {item.details}
126
+ </span>
127
+ )}
128
+ </div>
129
+ <span
130
+ className={cn(
131
+ 'rounded-full px-2 py-1 text-xs',
132
+ item.status === 'Enabled' ||
133
+ item.status === 'Active' ||
134
+ item.status === 'active' ||
135
+ item.status === 'Rendered'
136
+ ? 'bg-green-100 text-green-800'
137
+ : 'bg-red-100 text-red-800'
138
+ )}
139
+ >
140
+ {item.status}
141
+ </span>
142
+ </motion.div>
143
+ ))}
144
+ </motion.div>
145
+ </ScrollArea>
146
+ <div className="border-t p-4">
147
+ <div className="flex flex-col gap-2">
148
+ <Button variant="outline" size="sm" onClick={handleResetConsent}>
149
+ <RefreshCw className="mr-2 h-4 w-4" />
150
+ Reset Local Storage Consent
151
+ </Button>
152
+ <Button variant="outline" size="sm" onClick={handleOpenPrivacyModal}>
153
+ <FileText className="mr-2 h-4 w-4" />
154
+ Open Privacy Settings
155
+ </Button>
156
+ <Button variant="outline" size="sm" onClick={handleOpenCookiePopup}>
157
+ <Cookie className="mr-2 h-4 w-4" />
158
+ Open Cookie Popup
159
+ </Button>
160
+ </div>
161
+ </div>
162
+ </>
163
+ );
164
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "@c15t/typescript-config/react-library.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "lib": ["dom", "dom.iterable", "esnext"],
6
+ "paths": {
7
+ "~/*": ["./src/*"]
8
+ }
9
+ },
10
+ "include": ["src"],
11
+ "exclude": ["node_modules"]
12
+ }