@srcroot/ui 0.0.54 → 0.0.56

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 (107) hide show
  1. package/README.md +151 -151
  2. package/dist/index.d.ts +0 -0
  3. package/dist/index.js +55 -1
  4. package/package.json +7 -2
  5. package/src/registry/analytics/google-analytics.tsx +36 -39
  6. package/src/registry/analytics/google-tag-manager.tsx +62 -65
  7. package/src/registry/analytics/meta-pixel.tsx +44 -47
  8. package/src/registry/analytics/microsoft-clarity.tsx +31 -34
  9. package/src/registry/analytics/tiktok-pixel.tsx +34 -37
  10. package/src/registry/lib/utils.ts +0 -0
  11. package/src/registry/themes/v3/blue.css +157 -157
  12. package/src/registry/themes/v3/glass.css +153 -153
  13. package/src/registry/themes/v3/gray.css +157 -157
  14. package/src/registry/themes/v3/green.css +157 -157
  15. package/src/registry/themes/v3/neutral.css +157 -157
  16. package/src/registry/themes/v3/orange.css +157 -157
  17. package/src/registry/themes/v3/rose.css +157 -157
  18. package/src/registry/themes/v3/slate.css +157 -157
  19. package/src/registry/themes/v3/stone.css +157 -157
  20. package/src/registry/themes/v3/violet.css +186 -186
  21. package/src/registry/themes/v3/zinc.css +157 -157
  22. package/src/registry/themes/v4/blue.css +184 -184
  23. package/src/registry/themes/v4/glass.css +180 -180
  24. package/src/registry/themes/v4/gray.css +184 -184
  25. package/src/registry/themes/v4/green.css +184 -184
  26. package/src/registry/themes/v4/neutral.css +184 -184
  27. package/src/registry/themes/v4/orange.css +184 -184
  28. package/src/registry/themes/v4/rose.css +184 -184
  29. package/src/registry/themes/v4/slate.css +184 -184
  30. package/src/registry/themes/v4/stone.css +184 -184
  31. package/src/registry/themes/v4/violet.css +184 -184
  32. package/src/registry/themes/v4/zinc.css +184 -184
  33. package/src/registry/ui/accordion.tsx +164 -165
  34. package/src/registry/ui/alert-dialog.tsx +213 -214
  35. package/src/registry/ui/alert.tsx +73 -76
  36. package/src/registry/ui/aspect-ratio.tsx +44 -47
  37. package/src/registry/ui/avatar.tsx +96 -97
  38. package/src/registry/ui/badge.tsx +52 -55
  39. package/src/registry/ui/breadcrumb.tsx +147 -150
  40. package/src/registry/ui/button-group.tsx +64 -67
  41. package/src/registry/ui/button.tsx +71 -72
  42. package/src/registry/ui/calendar.tsx +514 -515
  43. package/src/registry/ui/card.tsx +88 -91
  44. package/src/registry/ui/carousel.tsx +214 -214
  45. package/src/registry/ui/chart.tsx +373 -373
  46. package/src/registry/ui/chatbot.tsx +86 -13
  47. package/src/registry/ui/checkbox.tsx +93 -94
  48. package/src/registry/ui/collapsible.tsx +107 -108
  49. package/src/registry/ui/combobox.tsx +171 -171
  50. package/src/registry/ui/command.tsx +300 -300
  51. package/src/registry/ui/container.tsx +44 -47
  52. package/src/registry/ui/context-menu.tsx +221 -221
  53. package/src/registry/ui/date-picker.tsx +228 -228
  54. package/src/registry/ui/dialog.tsx +269 -270
  55. package/src/registry/ui/drawer.tsx +10 -4
  56. package/src/registry/ui/dropdown-menu.tsx +529 -530
  57. package/src/registry/ui/empty-state.tsx +0 -2
  58. package/src/registry/ui/file-upload.tsx +0 -0
  59. package/src/registry/ui/floating-dock.tsx +0 -0
  60. package/src/registry/ui/form-field.tsx +91 -94
  61. package/src/registry/ui/google-analytics.tsx +38 -0
  62. package/src/registry/ui/google-tag-manager.tsx +64 -0
  63. package/src/registry/ui/hover-card.tsx +223 -223
  64. package/src/registry/ui/image.tsx +144 -147
  65. package/src/registry/ui/input-group.tsx +82 -85
  66. package/src/registry/ui/input.tsx +125 -125
  67. package/src/registry/ui/kbd.tsx +60 -63
  68. package/src/registry/ui/label.tsx +36 -37
  69. package/src/registry/ui/loading-spinner.tsx +108 -111
  70. package/src/registry/ui/map.tsx +0 -0
  71. package/src/registry/ui/marquee.tsx +2 -0
  72. package/src/registry/ui/menubar.tsx +246 -246
  73. package/src/registry/ui/meta-pixel.tsx +46 -0
  74. package/src/registry/ui/microsoft-clarity.tsx +33 -0
  75. package/src/registry/ui/native-select.tsx +49 -52
  76. package/src/registry/ui/otp-input.tsx +152 -155
  77. package/src/registry/ui/pagination.tsx +149 -152
  78. package/src/registry/ui/patterns.tsx +28 -0
  79. package/src/registry/ui/popover.tsx +226 -227
  80. package/src/registry/ui/progress.tsx +51 -52
  81. package/src/registry/ui/radio.tsx +99 -102
  82. package/src/registry/ui/resizable.tsx +314 -314
  83. package/src/registry/ui/scroll-animation.tsx +45 -0
  84. package/src/registry/ui/scroll-area.tsx +121 -122
  85. package/src/registry/ui/scroll-to-top.tsx +0 -0
  86. package/src/registry/ui/search.tsx +147 -150
  87. package/src/registry/ui/select.tsx +292 -293
  88. package/src/registry/ui/separator.tsx +46 -47
  89. package/src/registry/ui/sheet.tsx +6 -3
  90. package/src/registry/ui/sidebar.tsx +628 -628
  91. package/src/registry/ui/skeleton.tsx +26 -29
  92. package/src/registry/ui/slider.tsx +196 -197
  93. package/src/registry/ui/slot.tsx +69 -72
  94. package/src/registry/ui/star-rating.tsx +131 -134
  95. package/src/registry/ui/switch.tsx +72 -73
  96. package/src/registry/ui/table-of-contents.tsx +96 -96
  97. package/src/registry/ui/table.tsx +138 -139
  98. package/src/registry/ui/tabs.tsx +124 -125
  99. package/src/registry/ui/text.tsx +61 -64
  100. package/src/registry/ui/textarea.tsx +41 -42
  101. package/src/registry/ui/theme-switcher.tsx +66 -66
  102. package/src/registry/ui/tiktok-pixel.tsx +36 -0
  103. package/src/registry/ui/toast.tsx +97 -98
  104. package/src/registry/ui/toggle-group.tsx +129 -129
  105. package/src/registry/ui/toggle.tsx +72 -72
  106. package/src/registry/ui/tooltip.tsx +143 -144
  107. package/src/registry/ui/whatsapp.tsx +0 -0
@@ -1,246 +1,246 @@
1
- "use client"
2
-
3
- import * as React from "react"
4
- import { cn } from "@/lib/utils"
5
-
6
- // Menubar Context
7
- interface MenubarContextValue {
8
- activeMenu: string | null
9
- setActiveMenu: (menu: string | null) => void
10
- }
11
-
12
- const MenubarContext = React.createContext<MenubarContextValue | null>(null)
13
-
14
- function useMenubar() {
15
- const context = React.useContext(MenubarContext)
16
- if (!context) {
17
- throw new Error("useMenubar must be used within a Menubar")
18
- }
19
- return context
20
- }
21
-
22
- // MenubarMenu Context
23
- interface MenubarMenuContextValue {
24
- menuId: string
25
- triggerRef: React.RefObject<HTMLButtonElement | null>
26
- }
27
-
28
- const MenubarMenuContext = React.createContext<MenubarMenuContextValue | null>(null)
29
-
30
- function useMenubarMenu() {
31
- const context = React.useContext(MenubarMenuContext)
32
- if (!context) {
33
- throw new Error("useMenubarMenu must be used within a MenubarMenu")
34
- }
35
- return context
36
- }
37
-
38
- // Menubar Root
39
- const Menubar = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
40
- ({ className, children, ...props }, ref) => {
41
- const [activeMenu, setActiveMenu] = React.useState<string | null>(null)
42
-
43
- // Close on outside click
44
- React.useEffect(() => {
45
- if (!activeMenu) return
46
- const handleClick = (e: MouseEvent) => {
47
- const target = e.target as Element
48
- if (!target.closest('[data-menubar]')) {
49
- setActiveMenu(null)
50
- }
51
- }
52
- document.addEventListener("click", handleClick)
53
- return () => document.removeEventListener("click", handleClick)
54
- }, [activeMenu])
55
-
56
- return (
57
- <MenubarContext.Provider value={{ activeMenu, setActiveMenu }}>
58
- <div
59
- ref={ref}
60
- data-menubar
61
- className={cn(
62
- "flex h-10 items-center space-x-1 rounded-md border bg-background p-1",
63
- className
64
- )}
65
- {...props}
66
- >
67
- {children}
68
- </div>
69
- </MenubarContext.Provider>
70
- )
71
- }
72
- )
73
- Menubar.displayName = "Menubar"
74
-
75
- // MenubarMenu
76
- interface MenubarMenuProps {
77
- children: React.ReactNode
78
- }
79
-
80
- const MenubarMenu = ({ children }: MenubarMenuProps) => {
81
- const menuId = React.useId()
82
- const triggerRef = React.useRef<HTMLButtonElement>(null)
83
-
84
- return (
85
- <MenubarMenuContext.Provider value={{ menuId, triggerRef }}>
86
- <div className="relative">
87
- {children}
88
- </div>
89
- </MenubarMenuContext.Provider>
90
- )
91
- }
92
- MenubarMenu.displayName = "MenubarMenu"
93
-
94
- // MenubarTrigger
95
- const MenubarTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
96
- ({ className, children, ...props }, ref) => {
97
- const { activeMenu, setActiveMenu } = useMenubar()
98
- const { menuId, triggerRef } = useMenubarMenu()
99
- const isOpen = activeMenu === menuId
100
-
101
- const handleClick = () => {
102
- setActiveMenu(isOpen ? null : menuId)
103
- }
104
-
105
- const handleMouseEnter = () => {
106
- if (activeMenu && activeMenu !== menuId) {
107
- setActiveMenu(menuId)
108
- }
109
- }
110
-
111
- return (
112
- <button
113
- ref={triggerRef}
114
- className={cn(
115
- "flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none",
116
- "focus:bg-accent focus:text-accent-foreground",
117
- isOpen && "bg-accent text-accent-foreground",
118
- className
119
- )}
120
- onClick={handleClick}
121
- onMouseEnter={handleMouseEnter}
122
- {...props}
123
- >
124
- {children}
125
- </button>
126
- )
127
- }
128
- )
129
- MenubarTrigger.displayName = "MenubarTrigger"
130
-
131
- // MenubarContent
132
- const MenubarContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
133
- ({ className, children, ...props }, ref) => {
134
- const { activeMenu, setActiveMenu } = useMenubar()
135
- const { menuId, triggerRef } = useMenubarMenu()
136
- const isOpen = activeMenu === menuId
137
- const [position, setPosition] = React.useState({ top: 0, left: 0 })
138
- const contentRef = React.useRef<HTMLDivElement>(null)
139
-
140
- React.useEffect(() => {
141
- if (!isOpen || !triggerRef.current) return
142
- const rect = triggerRef.current.getBoundingClientRect()
143
- setPosition({
144
- top: rect.bottom + 4,
145
- left: rect.left,
146
- })
147
- }, [isOpen, triggerRef])
148
-
149
- // Close on Escape
150
- React.useEffect(() => {
151
- if (!isOpen) return
152
- const handleEscape = (e: KeyboardEvent) => {
153
- if (e.key === "Escape") setActiveMenu(null)
154
- }
155
- document.addEventListener("keydown", handleEscape)
156
- return () => document.removeEventListener("keydown", handleEscape)
157
- }, [isOpen, setActiveMenu])
158
-
159
- if (!isOpen) return null
160
-
161
- return (
162
- <div
163
- ref={contentRef}
164
- className={cn(
165
- "fixed z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
166
- "animate-in fade-in-0 slide-in-from-top-2",
167
- className
168
- )}
169
- style={{
170
- top: position.top,
171
- left: position.left,
172
- }}
173
- {...props}
174
- >
175
- {children}
176
- </div>
177
- )
178
- }
179
- )
180
- MenubarContent.displayName = "MenubarContent"
181
-
182
- // MenubarItem
183
- interface MenubarItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
184
- inset?: boolean
185
- }
186
-
187
- const MenubarItem = React.forwardRef<HTMLButtonElement, MenubarItemProps>(
188
- ({ className, inset, children, ...props }, ref) => {
189
- const { setActiveMenu } = useMenubar()
190
-
191
- return (
192
- <button
193
- ref={ref}
194
- className={cn(
195
- "relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
196
- "focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground",
197
- "disabled:pointer-events-none disabled:opacity-50",
198
- inset && "pl-8",
199
- className
200
- )}
201
- onClick={() => setActiveMenu(null)}
202
- {...props}
203
- >
204
- {children}
205
- </button>
206
- )
207
- }
208
- )
209
- MenubarItem.displayName = "MenubarItem"
210
-
211
- // MenubarSeparator
212
- const MenubarSeparator = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
213
- ({ className, ...props }, ref) => (
214
- <div ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
215
- )
216
- )
217
- MenubarSeparator.displayName = "MenubarSeparator"
218
-
219
- // MenubarLabel
220
- const MenubarLabel = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement> & { inset?: boolean }>(
221
- ({ className, inset, ...props }, ref) => (
222
- <div
223
- ref={ref}
224
- className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
225
- {...props}
226
- />
227
- )
228
- )
229
- MenubarLabel.displayName = "MenubarLabel"
230
-
231
- // MenubarShortcut
232
- const MenubarShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => (
233
- <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />
234
- )
235
- MenubarShortcut.displayName = "MenubarShortcut"
236
-
237
- export {
238
- Menubar,
239
- MenubarMenu,
240
- MenubarTrigger,
241
- MenubarContent,
242
- MenubarItem,
243
- MenubarSeparator,
244
- MenubarLabel,
245
- MenubarShortcut,
246
- }
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "@/lib/utils"
5
+
6
+ // Menubar Context
7
+ interface MenubarContextValue {
8
+ activeMenu: string | null
9
+ setActiveMenu: (menu: string | null) => void
10
+ }
11
+
12
+ const MenubarContext = React.createContext<MenubarContextValue | null>(null)
13
+
14
+ function useMenubar() {
15
+ const context = React.useContext(MenubarContext)
16
+ if (!context) {
17
+ throw new Error("useMenubar must be used within a Menubar")
18
+ }
19
+ return context
20
+ }
21
+
22
+ // MenubarMenu Context
23
+ interface MenubarMenuContextValue {
24
+ menuId: string
25
+ triggerRef: React.RefObject<HTMLButtonElement | null>
26
+ }
27
+
28
+ const MenubarMenuContext = React.createContext<MenubarMenuContextValue | null>(null)
29
+
30
+ function useMenubarMenu() {
31
+ const context = React.useContext(MenubarMenuContext)
32
+ if (!context) {
33
+ throw new Error("useMenubarMenu must be used within a MenubarMenu")
34
+ }
35
+ return context
36
+ }
37
+
38
+ // Menubar Root
39
+ const Menubar = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
40
+ ({ className, children, ...props }, ref) => {
41
+ const [activeMenu, setActiveMenu] = React.useState<string | null>(null)
42
+
43
+ // Close on outside click
44
+ React.useEffect(() => {
45
+ if (!activeMenu) return
46
+ const handleClick = (e: MouseEvent) => {
47
+ const target = e.target as Element
48
+ if (!target.closest('[data-menubar]')) {
49
+ setActiveMenu(null)
50
+ }
51
+ }
52
+ document.addEventListener("click", handleClick)
53
+ return () => document.removeEventListener("click", handleClick)
54
+ }, [activeMenu])
55
+
56
+ return (
57
+ <MenubarContext.Provider value={{ activeMenu, setActiveMenu }}>
58
+ <div
59
+ ref={ref}
60
+ data-menubar
61
+ className={cn(
62
+ "flex h-10 items-center space-x-1 rounded-md border bg-background p-1",
63
+ className
64
+ )}
65
+ {...props}
66
+ >
67
+ {children}
68
+ </div>
69
+ </MenubarContext.Provider>
70
+ )
71
+ }
72
+ )
73
+ Menubar.displayName = "Menubar"
74
+
75
+ // MenubarMenu
76
+ interface MenubarMenuProps {
77
+ children: React.ReactNode
78
+ }
79
+
80
+ const MenubarMenu = ({ children }: MenubarMenuProps) => {
81
+ const menuId = React.useId()
82
+ const triggerRef = React.useRef<HTMLButtonElement>(null)
83
+
84
+ return (
85
+ <MenubarMenuContext.Provider value={{ menuId, triggerRef }}>
86
+ <div className="relative">
87
+ {children}
88
+ </div>
89
+ </MenubarMenuContext.Provider>
90
+ )
91
+ }
92
+ MenubarMenu.displayName = "MenubarMenu"
93
+
94
+ // MenubarTrigger
95
+ const MenubarTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
96
+ ({ className, children, ...props }, ref) => {
97
+ const { activeMenu, setActiveMenu } = useMenubar()
98
+ const { menuId, triggerRef } = useMenubarMenu()
99
+ const isOpen = activeMenu === menuId
100
+
101
+ const handleClick = () => {
102
+ setActiveMenu(isOpen ? null : menuId)
103
+ }
104
+
105
+ const handleMouseEnter = () => {
106
+ if (activeMenu && activeMenu !== menuId) {
107
+ setActiveMenu(menuId)
108
+ }
109
+ }
110
+
111
+ return (
112
+ <button
113
+ ref={triggerRef}
114
+ className={cn(
115
+ "flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none",
116
+ "focus:bg-accent focus:text-accent-foreground",
117
+ isOpen && "bg-accent text-accent-foreground",
118
+ className
119
+ )}
120
+ onClick={handleClick}
121
+ onMouseEnter={handleMouseEnter}
122
+ {...props}
123
+ >
124
+ {children}
125
+ </button>
126
+ )
127
+ }
128
+ )
129
+ MenubarTrigger.displayName = "MenubarTrigger"
130
+
131
+ // MenubarContent
132
+ const MenubarContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
133
+ ({ className, children, ...props }, ref) => {
134
+ const { activeMenu, setActiveMenu } = useMenubar()
135
+ const { menuId, triggerRef } = useMenubarMenu()
136
+ const isOpen = activeMenu === menuId
137
+ const [position, setPosition] = React.useState({ top: 0, left: 0 })
138
+ const contentRef = React.useRef<HTMLDivElement>(null)
139
+
140
+ React.useEffect(() => {
141
+ if (!isOpen || !triggerRef.current) return
142
+ const rect = triggerRef.current.getBoundingClientRect()
143
+ setPosition({
144
+ top: rect.bottom + 4,
145
+ left: rect.left,
146
+ })
147
+ }, [isOpen, triggerRef])
148
+
149
+ // Close on Escape
150
+ React.useEffect(() => {
151
+ if (!isOpen) return
152
+ const handleEscape = (e: KeyboardEvent) => {
153
+ if (e.key === "Escape") setActiveMenu(null)
154
+ }
155
+ document.addEventListener("keydown", handleEscape)
156
+ return () => document.removeEventListener("keydown", handleEscape)
157
+ }, [isOpen, setActiveMenu])
158
+
159
+ if (!isOpen) return null
160
+
161
+ return (
162
+ <div
163
+ ref={contentRef}
164
+ className={cn(
165
+ "fixed z-50 min-w-[12rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
166
+ "animate-in fade-in-0 slide-in-from-top-2",
167
+ className
168
+ )}
169
+ style={{
170
+ top: position.top,
171
+ left: position.left,
172
+ }}
173
+ {...props}
174
+ >
175
+ {children}
176
+ </div>
177
+ )
178
+ }
179
+ )
180
+ MenubarContent.displayName = "MenubarContent"
181
+
182
+ // MenubarItem
183
+ interface MenubarItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
184
+ inset?: boolean
185
+ }
186
+
187
+ const MenubarItem = React.forwardRef<HTMLButtonElement, MenubarItemProps>(
188
+ ({ className, inset, children, ...props }, ref) => {
189
+ const { setActiveMenu } = useMenubar()
190
+
191
+ return (
192
+ <button
193
+ ref={ref}
194
+ className={cn(
195
+ "relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
196
+ "focus:bg-accent focus:text-accent-foreground hover:bg-accent hover:text-accent-foreground",
197
+ "disabled:pointer-events-none disabled:opacity-50",
198
+ inset && "pl-8",
199
+ className
200
+ )}
201
+ onClick={() => setActiveMenu(null)}
202
+ {...props}
203
+ >
204
+ {children}
205
+ </button>
206
+ )
207
+ }
208
+ )
209
+ MenubarItem.displayName = "MenubarItem"
210
+
211
+ // MenubarSeparator
212
+ const MenubarSeparator = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
213
+ ({ className, ...props }, ref) => (
214
+ <div ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
215
+ )
216
+ )
217
+ MenubarSeparator.displayName = "MenubarSeparator"
218
+
219
+ // MenubarLabel
220
+ const MenubarLabel = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement> & { inset?: boolean }>(
221
+ ({ className, inset, ...props }, ref) => (
222
+ <div
223
+ ref={ref}
224
+ className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
225
+ {...props}
226
+ />
227
+ )
228
+ )
229
+ MenubarLabel.displayName = "MenubarLabel"
230
+
231
+ // MenubarShortcut
232
+ const MenubarShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => (
233
+ <span className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)} {...props} />
234
+ )
235
+ MenubarShortcut.displayName = "MenubarShortcut"
236
+
237
+ export {
238
+ Menubar,
239
+ MenubarMenu,
240
+ MenubarTrigger,
241
+ MenubarContent,
242
+ MenubarItem,
243
+ MenubarSeparator,
244
+ MenubarLabel,
245
+ MenubarShortcut,
246
+ }
@@ -0,0 +1,46 @@
1
+ "use client"
2
+
3
+ import Script from 'next/script';
4
+ import type { FC } from 'react';
5
+
6
+ interface MetaPixelProps {
7
+ pixelIds: string[]; // ← array now
8
+ }
9
+
10
+ const MetaPixel: FC<MetaPixelProps> = ({ pixelIds }) => {
11
+ return (
12
+ <>
13
+ <Script
14
+ id="fb-script-multi"
15
+ strategy="afterInteractive"
16
+ dangerouslySetInnerHTML={{
17
+ __html: `
18
+ !function(f,b,e,v,n,t,s)
19
+ {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
20
+ n.callMethod.apply(n,arguments):n.queue.push(arguments)};
21
+ if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
22
+ n.queue=[];t=b.createElement(e);t.async=!0;
23
+ t.src=v;s=b.getElementsByTagName(e)[0];
24
+ s.parentNode.insertBefore(t,s)}(window, document,'script',
25
+ 'https://connect.facebook.net/en_US/fbevents.js');
26
+ ${pixelIds.map(id => `fbq('init', '${id}');`).join('\n')}
27
+ fbq('track', 'PageView');
28
+ `,
29
+ }}
30
+ />
31
+
32
+ {/* One noscript tag per pixel */}
33
+ {pixelIds.map(id => (
34
+ <noscript key={id}>
35
+ <img
36
+ height="1" width="1" style={{ display: 'none' }}
37
+ src={`https://www.facebook.com/tr?id=${id}&ev=PageView&noscript=1`}
38
+ alt=""
39
+ />
40
+ </noscript>
41
+ ))}
42
+ </>
43
+ );
44
+ };
45
+
46
+ export default MetaPixel;
@@ -0,0 +1,33 @@
1
+ "use client"
2
+
3
+ import Script from 'next/script';
4
+ import type { FC } from 'react';
5
+
6
+ interface MicrosoftClarityProps {
7
+ clarityIds: string[];
8
+ }
9
+
10
+ const MicrosoftClarity: FC<MicrosoftClarityProps> = ({ clarityIds }) => {
11
+ return (
12
+ <>
13
+ {clarityIds.map((id) => (
14
+ <Script
15
+ key={id}
16
+ id={`microsoft-clarity-init-${id}`}
17
+ strategy="afterInteractive"
18
+ dangerouslySetInnerHTML={{
19
+ __html: `
20
+ (function(c,l,a,r,i,t,y){
21
+ c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
22
+ t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
23
+ y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
24
+ })(window, document, "clarity", "script", "${id}");
25
+ `,
26
+ }}
27
+ />
28
+ ))}
29
+ </>
30
+ );
31
+ };
32
+
33
+ export default MicrosoftClarity;