@adhese/sdk-devtools 0.6.3 → 0.6.4

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.
@@ -0,0 +1,842 @@
1
+ import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
2
+ import { createRoot } from "react-dom/client";
3
+ import { forwardRef, useState, useEffect, useMemo, Fragment, useCallback, useId, useRef } from "react";
4
+ import { createPortal } from "react-dom";
5
+ import upperFirst from "lodash/upperFirst";
6
+ import { clsx } from "clsx";
7
+ import { twMerge } from "tailwind-merge";
8
+ import { cva } from "class-variance-authority";
9
+ import { Slot } from "@radix-ui/react-slot";
10
+ import * as SheetPrimitive from "@radix-ui/react-dialog";
11
+ import { Cross2Icon } from "@radix-ui/react-icons";
12
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
13
+ import * as SwitchPrimitives from "@radix-ui/react-switch";
14
+ import * as LabelPrimitive from "@radix-ui/react-label";
15
+ function cn(...inputs) {
16
+ return twMerge(clsx(inputs));
17
+ }
18
+ function setCooke({
19
+ key,
20
+ value,
21
+ expires,
22
+ path,
23
+ samesite,
24
+ secure
25
+ }) {
26
+ document.cookie = `${key}=${value}; ${expires ? `expires=${expires.toString()};` : ""} ${path ? `path=${path};` : ""} ${samesite ? `samesite=${samesite};` : ""} ${secure ? `secure=${secure};` : ""}`;
27
+ }
28
+ function deleteCookie(key) {
29
+ document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
30
+ }
31
+ function getCookie(key) {
32
+ const cookies = document.cookie.split(";");
33
+ for (const cookie of cookies) {
34
+ const [cookieKey2, cookieValue] = cookie.split("=");
35
+ if (cookieKey2.trim() === key)
36
+ return cookieValue;
37
+ }
38
+ return "";
39
+ }
40
+ function hasCookie(key) {
41
+ return document.cookie.includes(`${key}=`);
42
+ }
43
+ const Table = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
44
+ "table",
45
+ {
46
+ ref,
47
+ className: cn("w-full caption-bottom text-sm", className),
48
+ ...props
49
+ }
50
+ ) }));
51
+ Table.displayName = "Table";
52
+ const TableHeader = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
53
+ TableHeader.displayName = "TableHeader";
54
+ const TableBody = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
55
+ "tbody",
56
+ {
57
+ ref,
58
+ className: cn("[&_tr:last-child]:border-0", className),
59
+ ...props
60
+ }
61
+ ));
62
+ TableBody.displayName = "TableBody";
63
+ const TableFooter = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
64
+ "tfoot",
65
+ {
66
+ ref,
67
+ className: cn(
68
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
69
+ className
70
+ ),
71
+ ...props
72
+ }
73
+ ));
74
+ TableFooter.displayName = "TableFooter";
75
+ const TableRow = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
76
+ "tr",
77
+ {
78
+ ref,
79
+ className: cn(
80
+ "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
81
+ className
82
+ ),
83
+ ...props
84
+ }
85
+ ));
86
+ TableRow.displayName = "TableRow";
87
+ const TableHead = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
88
+ "th",
89
+ {
90
+ ref,
91
+ className: cn(
92
+ "h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
93
+ className
94
+ ),
95
+ ...props
96
+ }
97
+ ));
98
+ TableHead.displayName = "TableHead";
99
+ const TableCell = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
100
+ "td",
101
+ {
102
+ ref,
103
+ className: cn(
104
+ "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
105
+ className
106
+ ),
107
+ ...props
108
+ }
109
+ ));
110
+ TableCell.displayName = "TableCell";
111
+ const TableCaption = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
112
+ "caption",
113
+ {
114
+ ref,
115
+ className: cn("mt-4 text-sm text-muted-foreground", className),
116
+ ...props
117
+ }
118
+ ));
119
+ TableCaption.displayName = "TableCaption";
120
+ const badgeVariants = cva(
121
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
122
+ {
123
+ variants: {
124
+ variant: {
125
+ default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
126
+ secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
127
+ destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
128
+ outline: "text-foreground"
129
+ }
130
+ },
131
+ defaultVariants: {
132
+ variant: "default"
133
+ }
134
+ }
135
+ );
136
+ function Badge({ className, variant, ...props }) {
137
+ return /* @__PURE__ */ jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
138
+ }
139
+ const buttonVariants = cva(
140
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
141
+ {
142
+ variants: {
143
+ variant: {
144
+ default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
145
+ destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
146
+ outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
147
+ secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
148
+ ghost: "hover:bg-accent hover:text-accent-foreground",
149
+ link: "text-primary underline-offset-4 hover:underline"
150
+ },
151
+ size: {
152
+ default: "h-9 px-4 py-2",
153
+ sm: "h-6 rounded-md px-3 text-xs",
154
+ lg: "h-10 rounded-md px-8",
155
+ icon: "h-9 w-9"
156
+ }
157
+ },
158
+ defaultVariants: {
159
+ variant: "default",
160
+ size: "default"
161
+ }
162
+ }
163
+ );
164
+ const Button = forwardRef(
165
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
166
+ const Component = asChild ? Slot : "button";
167
+ return /* @__PURE__ */ jsx(
168
+ Component,
169
+ {
170
+ className: cn(buttonVariants({ variant, size, className })),
171
+ ref,
172
+ ...props
173
+ }
174
+ );
175
+ }
176
+ );
177
+ Button.displayName = "Button";
178
+ const Sheet = SheetPrimitive.Root;
179
+ const SheetTrigger = SheetPrimitive.Trigger;
180
+ const SheetPortal = SheetPrimitive.Portal;
181
+ const SheetOverlay = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
182
+ SheetPrimitive.Overlay,
183
+ {
184
+ className: cn(
185
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
186
+ className
187
+ ),
188
+ ...props,
189
+ ref
190
+ }
191
+ ));
192
+ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
193
+ const sheetVariants = cva(
194
+ "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
195
+ {
196
+ variants: {
197
+ side: {
198
+ top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
199
+ bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
200
+ left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
201
+ right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-[calc(100vw-16rem)]"
202
+ }
203
+ },
204
+ defaultVariants: {
205
+ side: "right"
206
+ }
207
+ }
208
+ );
209
+ const SheetContent = forwardRef(({ side = "right", className, children, ...props }, ref) => /* @__PURE__ */ jsxs(SheetPortal, { children: [
210
+ /* @__PURE__ */ jsx(SheetOverlay, {}),
211
+ /* @__PURE__ */ jsxs(
212
+ SheetPrimitive.Content,
213
+ {
214
+ ref,
215
+ className: cn(sheetVariants({ side }), className),
216
+ ...props,
217
+ children: [
218
+ children,
219
+ /* @__PURE__ */ jsxs(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary", children: [
220
+ /* @__PURE__ */ jsx(Cross2Icon, { className: "h-4 w-4" }),
221
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
222
+ ] })
223
+ ]
224
+ }
225
+ )
226
+ ] }));
227
+ SheetContent.displayName = SheetPrimitive.Content.displayName;
228
+ function SheetHeader({
229
+ className,
230
+ ...props
231
+ }) {
232
+ return /* @__PURE__ */ jsx(
233
+ "div",
234
+ {
235
+ className: cn(
236
+ "flex flex-col space-y-2 text-center sm:text-left",
237
+ className
238
+ ),
239
+ ...props
240
+ }
241
+ );
242
+ }
243
+ SheetHeader.displayName = "SheetHeader";
244
+ const SheetTitle = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
245
+ SheetPrimitive.Title,
246
+ {
247
+ ref,
248
+ className: cn("text-lg font-semibold text-foreground", className),
249
+ ...props
250
+ }
251
+ ));
252
+ SheetTitle.displayName = SheetPrimitive.Title.displayName;
253
+ const SheetDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
254
+ SheetPrimitive.Description,
255
+ {
256
+ ref,
257
+ className: cn("text-sm text-muted-foreground", className),
258
+ ...props
259
+ }
260
+ ));
261
+ SheetDescription.displayName = SheetPrimitive.Description.displayName;
262
+ const slotStatus = {
263
+ unloaded: "Waiting to load",
264
+ loaded: "Ready to render",
265
+ rendered: "Rendered"
266
+ };
267
+ const slotIndexBadgeClasses = [
268
+ "bg-blue-500 hover:bg-blue-500",
269
+ "bg-amber-500 hover:bg-amber-500",
270
+ "bg-green-500 hover:bg-green-500",
271
+ "bg-red-500 hover:bg-red-500",
272
+ "bg-purple-500 hover:bg-purple-500",
273
+ "bg-cyan-500 hover:bg-cyan-500",
274
+ "bg-pink-500 hover:bg-pink-500"
275
+ ];
276
+ function SlotsTable({ adheseContext }) {
277
+ const [slots, setSlots] = useState([]);
278
+ useEffect(() => {
279
+ var _a, _b;
280
+ function onSlotsChange(newSlots) {
281
+ setSlots(newSlots);
282
+ }
283
+ (_a = adheseContext.events) == null ? void 0 : _a.changeSlots.addListener(onSlotsChange);
284
+ onSlotsChange(((_b = adheseContext.getAll) == null ? void 0 : _b.call(adheseContext)) ?? []);
285
+ return () => {
286
+ var _a2;
287
+ (_a2 = adheseContext.events) == null ? void 0 : _a2.changeSlots.removeListener(onSlotsChange);
288
+ };
289
+ }, []);
290
+ const formattedSlots = useMemo(() => slots.map((slot) => {
291
+ const ad = slot.ad.value;
292
+ const iframe = slot.getElement();
293
+ let status = "unloaded";
294
+ if (iframe)
295
+ status = "rendered";
296
+ else if (ad)
297
+ status = "loaded";
298
+ return {
299
+ ...slot,
300
+ name: slot.name.value,
301
+ ad,
302
+ status,
303
+ format: slot.format.value,
304
+ iframe,
305
+ parameters: Array.from(slot.parameters.entries())
306
+ };
307
+ }), [slots]);
308
+ const slotParametersExist = formattedSlots.some((formattedSlot) => formattedSlot.parameters.length > 0);
309
+ const previewExist = formattedSlots.some((formattedSlot) => {
310
+ var _a;
311
+ return (_a = formattedSlot.ad) == null ? void 0 : _a.preview;
312
+ });
313
+ const origins = useMemo(() => {
314
+ const set = /* @__PURE__ */ new Set();
315
+ for (const slot of formattedSlots) {
316
+ const { ad } = slot;
317
+ if (ad)
318
+ set.add(ad.origin);
319
+ }
320
+ return Array.from(set);
321
+ }, [formattedSlots]);
322
+ return formattedSlots.length > 0 ? /* @__PURE__ */ jsxs(Table, { children: [
323
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
324
+ /* @__PURE__ */ jsx(TableHead, { children: "Name" }),
325
+ /* @__PURE__ */ jsx(TableHead, { children: "Format" }),
326
+ origins.length > 1 && /* @__PURE__ */ jsx(TableHead, { children: "Origin" }),
327
+ /* @__PURE__ */ jsx(TableHead, { children: "Location" }),
328
+ /* @__PURE__ */ jsx(TableHead, { children: "Render Status" }),
329
+ /* @__PURE__ */ jsx(TableHead, { children: "Campaign ID" }),
330
+ /* @__PURE__ */ jsx(TableHead, { children: "Booking ID" }),
331
+ /* @__PURE__ */ jsx(TableHead, { children: "Creative ID" }),
332
+ /* @__PURE__ */ jsx(TableHead, { children: "Traffic ID" }),
333
+ /* @__PURE__ */ jsx(TableHead, { children: "Creative type" }),
334
+ /* @__PURE__ */ jsx(TableHead, { children: "Viewability tracked" }),
335
+ /* @__PURE__ */ jsx(TableHead, { children: "Impression tracked" }),
336
+ /* @__PURE__ */ jsx(TableHead, { children: "Element" }),
337
+ slotParametersExist && /* @__PURE__ */ jsx(TableHead, { children: "Parameters" }),
338
+ previewExist && /* @__PURE__ */ jsx(TableHead, { children: "Preview" })
339
+ ] }) }),
340
+ /* @__PURE__ */ jsx(TableBody, { children: formattedSlots.map(({
341
+ ad,
342
+ name,
343
+ format,
344
+ location,
345
+ status,
346
+ isViewabilityTracked,
347
+ isImpressionTracked,
348
+ iframe,
349
+ parameters
350
+ }, index) => /* @__PURE__ */ jsxs(Fragment, { children: [
351
+ /* @__PURE__ */ jsxs(TableRow, { id: name, children: [
352
+ /* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: /* @__PURE__ */ jsx(Badge, { className: cn(slotIndexBadgeClasses[index % slotIndexBadgeClasses.length], "text-white"), children: name }) }),
353
+ /* @__PURE__ */ jsx(TableCell, { children: !(ad == null ? void 0 : ad.adFormat) || (ad == null ? void 0 : ad.adFormat) === format ? format : /* @__PURE__ */ jsxs(Fragment$1, { children: [
354
+ /* @__PURE__ */ jsx("del", { className: "text-red-300 italic", children: format }),
355
+ /* @__PURE__ */ jsx("ins", { className: "no-underline text-green-700", children: ad == null ? void 0 : ad.adFormat })
356
+ ] }) }),
357
+ origins.length > 1 && /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.origin) && /* @__PURE__ */ jsx(Badge, { className: cn(slotIndexBadgeClasses[origins.indexOf(ad.origin) % slotIndexBadgeClasses.length], "text-white"), children: upperFirst(ad.origin.toLowerCase()) }) }),
358
+ /* @__PURE__ */ jsx(TableCell, { children: location }),
359
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
360
+ Badge,
361
+ {
362
+ className: cn({
363
+ unloaded: "bg-secondary text-secondary-foreground hover:bg-secondary",
364
+ loaded: "bg-blue-100 text-blue-900 hover:bg-blue-100",
365
+ rendered: "bg-green-100 text-green-900 hover:bg-green-100"
366
+ }[status]),
367
+ children: slotStatus[status]
368
+ }
369
+ ) }),
370
+ /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.orderId) && (ad == null ? void 0 : ad.orderId) !== "0" ? /* @__PURE__ */ jsx(
371
+ "a",
372
+ {
373
+ href: `https://${adheseContext.options.account}.adhese.org/campaigns.html#campaignDetail/editCampaign/${ad.orderId}`,
374
+ target: "_blank",
375
+ referrerPolicy: "no-referrer",
376
+ className: cn(buttonVariants({
377
+ variant: "ghost",
378
+ size: "sm"
379
+ })),
380
+ children: ad.orderId
381
+ }
382
+ ) : "-" }),
383
+ /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.adspaceId) && (ad == null ? void 0 : ad.adspaceId) !== "0" ? /* @__PURE__ */ jsx(
384
+ "a",
385
+ {
386
+ href: `https://${adheseContext.options.account}.adhese.org/campaigns.html#campaignDetail/bookingDetail/${ad.adspaceId}/${ad.orderId}`,
387
+ target: "_blank",
388
+ referrerPolicy: "no-referrer",
389
+ className: cn(buttonVariants({
390
+ variant: "ghost",
391
+ size: "sm"
392
+ })),
393
+ children: ad.adspaceId
394
+ }
395
+ ) : "-" }),
396
+ /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.libId) && (ad == null ? void 0 : ad.orderId) !== "0" ? /* @__PURE__ */ jsx(
397
+ "a",
398
+ {
399
+ href: `https://${adheseContext.options.account}.adhese.org/campaigns.html#campaignDetail/creativeDetail/${ad.libId}/${ad.orderId}`,
400
+ target: "_blank",
401
+ referrerPolicy: "no-referrer",
402
+ className: cn(buttonVariants({
403
+ variant: "ghost",
404
+ size: "sm"
405
+ })),
406
+ children: ad.libId
407
+ }
408
+ ) : "-" }),
409
+ /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.id) ?? "-" }),
410
+ /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.ext) ? /* @__PURE__ */ jsx(Badge, { variant: "outline", children: ad.ext }) : "-" }),
411
+ /* @__PURE__ */ jsx(TableCell, { children: isViewabilityTracked.value ? /* @__PURE__ */ jsx(Badge, { className: "bg-green-100 text-green-900 hover:bg-green-100", children: "Yes" }) : /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: "No" }) }),
412
+ /* @__PURE__ */ jsx(TableCell, { children: isImpressionTracked.value ? /* @__PURE__ */ jsx(Badge, { className: "bg-green-100 text-green-900 hover:bg-green-100", children: "Yes" }) : /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: "No" }) }),
413
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
414
+ Button,
415
+ {
416
+ variant: "secondary",
417
+ size: "sm",
418
+ disabled: !iframe,
419
+ onClick: () => {
420
+ if (iframe) {
421
+ iframe.scrollIntoView();
422
+ iframe.style.outline = "solid 5px red";
423
+ setTimeout(() => {
424
+ iframe.style.outline = "";
425
+ }, 1e3);
426
+ }
427
+ },
428
+ children: "Go to element"
429
+ }
430
+ ) }),
431
+ slotParametersExist && /* @__PURE__ */ jsx(TableCell, { children: parameters.length > 0 && /* @__PURE__ */ jsxs(Sheet, { children: [
432
+ /* @__PURE__ */ jsx(
433
+ SheetTrigger,
434
+ {
435
+ className: buttonVariants({
436
+ variant: "secondary",
437
+ size: "sm"
438
+ }),
439
+ children: "Show"
440
+ }
441
+ ),
442
+ /* @__PURE__ */ jsxs(SheetContent, { className: "bg-white flex flex-col gap-4", children: [
443
+ /* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Parameters" }) }),
444
+ /* @__PURE__ */ jsxs(Table, { children: [
445
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
446
+ /* @__PURE__ */ jsx(TableHead, { children: "Key" }),
447
+ /* @__PURE__ */ jsx(TableHead, { children: "Value" })
448
+ ] }) }),
449
+ /* @__PURE__ */ jsx(TableBody, { children: parameters.map(([parameterName, value]) => /* @__PURE__ */ jsxs(TableRow, { children: [
450
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", children: parameterName }) }),
451
+ /* @__PURE__ */ jsx(TableCell, { children: Array.isArray(value) ? /* @__PURE__ */ jsx("ul", { className: "flex gap-1", children: value.map((item, paramIndex) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", children: item }) }, paramIndex)) }) : /* @__PURE__ */ jsx(Badge, { variant: "outline", children: value }) })
452
+ ] }, parameterName)) })
453
+ ] })
454
+ ] })
455
+ ] }) }),
456
+ previewExist && /* @__PURE__ */ jsx(TableCell, { children: (ad == null ? void 0 : ad.preview) && /* @__PURE__ */ jsx(Badge, { className: "bg-amber-400 text-amber-950 hover:bg-amber-400", children: "PREVIEW" }) })
457
+ ] }),
458
+ (iframe == null ? void 0 : iframe.parentElement) && createPortal(
459
+ /* @__PURE__ */ jsxs("div", { className: "absolute inset-1 flex gap-2 items-start", children: [
460
+ /* @__PURE__ */ jsx(Badge, { className: cn(slotIndexBadgeClasses[index % slotIndexBadgeClasses.length], "text-white"), children: name }),
461
+ (ad == null ? void 0 : ad.preview) && /* @__PURE__ */ jsx(Badge, { className: "bg-amber-400 text-amber-950 hover:bg-amber-400", children: "PREVIEW" })
462
+ ] }),
463
+ iframe.parentElement
464
+ )
465
+ ] }, name)) })
466
+ ] }) : /* @__PURE__ */ jsx("p", { children: "No slots available" });
467
+ }
468
+ const Tabs = TabsPrimitive.Root;
469
+ const TabsList = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
470
+ TabsPrimitive.List,
471
+ {
472
+ ref,
473
+ className: cn(
474
+ "inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
475
+ className
476
+ ),
477
+ ...props
478
+ }
479
+ ));
480
+ TabsList.displayName = TabsPrimitive.List.displayName;
481
+ const TabsTrigger = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
482
+ TabsPrimitive.Trigger,
483
+ {
484
+ ref,
485
+ className: cn(
486
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
487
+ className
488
+ ),
489
+ ...props
490
+ }
491
+ ));
492
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
493
+ const TabsContent = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
494
+ TabsPrimitive.Content,
495
+ {
496
+ ref,
497
+ className: cn(
498
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
499
+ className
500
+ ),
501
+ ...props
502
+ }
503
+ ));
504
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
505
+ const dateFormatter = new Intl.DateTimeFormat("en-US", {
506
+ hour: "numeric",
507
+ minute: "numeric",
508
+ second: "numeric",
509
+ fractionalSecondDigits: 3,
510
+ hour12: false
511
+ });
512
+ const logTableRowClasses = {
513
+ error: "bg-red-100 text-red-900",
514
+ warn: "bg-amber-100 text-amber-900"
515
+ };
516
+ const logBadgeClasses = {
517
+ error: "bg-red-500 text-white",
518
+ warn: "bg-amber-500 text-white",
519
+ info: "bg-blue-500 text-white"
520
+ };
521
+ function LogTable({
522
+ adheseContext
523
+ }) {
524
+ const [logs, setLogs] = useState([]);
525
+ useEffect(() => {
526
+ function onLogsChange() {
527
+ setLogs(
528
+ adheseContext.logger.getLogs().toSorted(
529
+ (a, b) => b.timestamp - a.timestamp
530
+ )
531
+ );
532
+ }
533
+ adheseContext.logger.events.log.addListener(onLogsChange);
534
+ onLogsChange();
535
+ return () => {
536
+ adheseContext.logger.events.log.removeListener(onLogsChange);
537
+ };
538
+ }, []);
539
+ return /* @__PURE__ */ jsxs(Table, { children: [
540
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
541
+ /* @__PURE__ */ jsx(TableHead, { children: "Time" }),
542
+ /* @__PURE__ */ jsx(TableHead, { children: "Scope" }),
543
+ /* @__PURE__ */ jsx(TableHead, { children: "Level" }),
544
+ /* @__PURE__ */ jsx(TableHead, { children: "Message" }),
545
+ /* @__PURE__ */ jsx(TableHead, { children: "Attributes" })
546
+ ] }) }),
547
+ /* @__PURE__ */ jsx(TableBody, { children: logs.map((log) => /* @__PURE__ */ jsxs(TableRow, { className: logTableRowClasses[log.level] ?? "", children: [
548
+ /* @__PURE__ */ jsx(TableCell, { children: dateFormatter.format(new Date(log.timestamp)) }),
549
+ /* @__PURE__ */ jsx(TableCell, { children: log.scope }),
550
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(
551
+ Badge,
552
+ {
553
+ variant: "secondary",
554
+ className: logBadgeClasses[log.level] ?? "",
555
+ children: upperFirst(log.level)
556
+ }
557
+ ) }),
558
+ /* @__PURE__ */ jsx(TableCell, { children: log.message }),
559
+ /* @__PURE__ */ jsx(TableCell, { children: Boolean(log.attributes) && /* @__PURE__ */ jsxs(Sheet, { children: [
560
+ /* @__PURE__ */ jsx(
561
+ SheetTrigger,
562
+ {
563
+ className: buttonVariants({
564
+ variant: "secondary",
565
+ size: "sm"
566
+ }),
567
+ children: "Show"
568
+ }
569
+ ),
570
+ /* @__PURE__ */ jsxs(SheetContent, { className: "bg-white flex flex-col gap-4", children: [
571
+ /* @__PURE__ */ jsx(SheetHeader, { children: /* @__PURE__ */ jsx(SheetTitle, { children: "Attributes" }) }),
572
+ /* @__PURE__ */ jsx("pre", { className: "p-4 bg-accent overflow-auto max-h-full text-sm rounded-md", children: JSON.stringify(log.attributes, null, 2) })
573
+ ] })
574
+ ] }) })
575
+ ] }, log.id)) })
576
+ ] });
577
+ }
578
+ function ParametersTable({
579
+ adheseContext
580
+ }) {
581
+ const [parameters, setParameters] = useState([]);
582
+ useEffect(() => {
583
+ var _a;
584
+ function onParametersChange() {
585
+ var _a2;
586
+ setParameters(Array.from(((_a2 = adheseContext.parameters) == null ? void 0 : _a2.entries()) ?? []).map(([name, value]) => ({
587
+ name,
588
+ value
589
+ })).toSorted((a, b) => a.name.localeCompare(b.name)));
590
+ }
591
+ (_a = adheseContext.events) == null ? void 0 : _a.parametersChange.addListener(onParametersChange);
592
+ onParametersChange();
593
+ return () => {
594
+ var _a2;
595
+ (_a2 = adheseContext.events) == null ? void 0 : _a2.parametersChange.removeListener(onParametersChange);
596
+ };
597
+ }, []);
598
+ return /* @__PURE__ */ jsxs(Table, { children: [
599
+ /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
600
+ /* @__PURE__ */ jsx(TableHead, { children: "Parameter" }),
601
+ /* @__PURE__ */ jsx(TableHead, { children: "Value" })
602
+ ] }) }),
603
+ /* @__PURE__ */ jsx(TableBody, { children: parameters.map((parameter) => /* @__PURE__ */ jsxs(TableRow, { children: [
604
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", children: parameter.name }) }),
605
+ /* @__PURE__ */ jsx(TableCell, { children: Array.isArray(parameter.value) ? /* @__PURE__ */ jsx("ul", { className: "flex gap-1", children: parameter.value.map((item, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Badge, { variant: "outline", children: item }) }, index)) }) : /* @__PURE__ */ jsx(Badge, { variant: "outline", children: parameter.value }) })
606
+ ] }, parameter.name)) })
607
+ ] });
608
+ }
609
+ const Switch = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
610
+ SwitchPrimitives.Root,
611
+ {
612
+ className: cn(
613
+ "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
614
+ className
615
+ ),
616
+ ...props,
617
+ ref,
618
+ children: /* @__PURE__ */ jsx(
619
+ SwitchPrimitives.Thumb,
620
+ {
621
+ className: cn(
622
+ "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
623
+ )
624
+ }
625
+ )
626
+ }
627
+ ));
628
+ Switch.displayName = SwitchPrimitives.Root.displayName;
629
+ const labelVariants = cva(
630
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
631
+ );
632
+ const Label = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
633
+ LabelPrimitive.Root,
634
+ {
635
+ ref,
636
+ className: cn(labelVariants(), className),
637
+ ...props
638
+ }
639
+ ));
640
+ Label.displayName = LabelPrimitive.Root.displayName;
641
+ const Input = forwardRef(
642
+ ({ className, type, ...props }, ref) => /* @__PURE__ */ jsx(
643
+ "input",
644
+ {
645
+ type,
646
+ className: cn(
647
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
648
+ className
649
+ ),
650
+ ref,
651
+ ...props
652
+ }
653
+ )
654
+ );
655
+ Input.displayName = "Input";
656
+ const cookieKey = "debugKey";
657
+ function setDebugCookie(value) {
658
+ setCooke({
659
+ key: cookieKey,
660
+ value,
661
+ expires: new Date(Date.now() + 24 * 60 * 60 * 1e3)
662
+ });
663
+ }
664
+ function simpleStringify(value) {
665
+ if (typeof value === "object")
666
+ return Object.values(value).map((nestedValue) => `${simpleStringify(nestedValue)}`).join("");
667
+ if (typeof value === "boolean")
668
+ return value ? "1" : "0";
669
+ return String(value);
670
+ }
671
+ function FronttailSettings({
672
+ adheseContext,
673
+ className,
674
+ "aria-labelledby": ariaLabelledBy,
675
+ ...props
676
+ }) {
677
+ const autoGeneratedKey = useMemo(() => `adhese-${adheseContext.options.account}-${btoa(simpleStringify(adheseContext.options)).slice(0, 20)}`, [adheseContext.options]);
678
+ const [fronttailDebugKey, setFronttailDebugKey] = useState(hasCookie(cookieKey) ? getCookie(cookieKey) : autoGeneratedKey);
679
+ const [isFronttailEnabled, setIsFronttailEnabled] = useState(hasCookie(cookieKey));
680
+ const onFronttailDebugKeyChange = useCallback((event) => {
681
+ const { value } = event.target;
682
+ setFronttailDebugKey(value);
683
+ if (isFronttailEnabled && value.length > 4)
684
+ setDebugCookie(value);
685
+ }, [setDebugCookie, isFronttailEnabled]);
686
+ const onFrontailEnabledChange = useCallback(() => {
687
+ setIsFronttailEnabled((value) => {
688
+ if (value)
689
+ deleteCookie(cookieKey);
690
+ else
691
+ setDebugCookie(fronttailDebugKey);
692
+ return !value;
693
+ });
694
+ }, [setDebugCookie, fronttailDebugKey]);
695
+ const id = useId();
696
+ return /* @__PURE__ */ jsxs("section", { className: cn("flex flex-col gap-6", className), "aria-labelledby": ariaLabelledBy ?? `fronttailHeading${id}`, ...props, children: [
697
+ /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold", id: `fronttailHeading${id}`, children: "Fronttail settings" }),
698
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
699
+ /* @__PURE__ */ jsx(Switch, { checked: isFronttailEnabled, onCheckedChange: onFrontailEnabledChange, id: `fronttailSwitch${id}` }),
700
+ /* @__PURE__ */ jsxs(Label, { htmlFor: `fronttailSwitch${id}`, children: [
701
+ "Enable Fronttail debugging",
702
+ /* @__PURE__ */ jsx("span", { className: "text-gray-400 font-normal", children: " – Cookie will expire automatically in 1 day" })
703
+ ] })
704
+ ] }),
705
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
706
+ /* @__PURE__ */ jsx(Label, { htmlFor: `fronttailDebugKey${id}`, children: "Debug key" }),
707
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
708
+ /* @__PURE__ */ jsx(
709
+ Input,
710
+ {
711
+ id: `fronttailDebugKey${id}`,
712
+ value: fronttailDebugKey,
713
+ onChange: onFronttailDebugKeyChange,
714
+ className: cn("max-w-60", {
715
+ // eslint-disable-next-line ts/naming-convention
716
+ "border-destructive": fronttailDebugKey.length < 4
717
+ })
718
+ }
719
+ ),
720
+ /* @__PURE__ */ jsx(
721
+ Button,
722
+ {
723
+ variant: "outline",
724
+ onClick: () => {
725
+ setFronttailDebugKey(autoGeneratedKey);
726
+ if (isFronttailEnabled)
727
+ setDebugCookie(autoGeneratedKey);
728
+ },
729
+ children: "Auto generate key"
730
+ }
731
+ )
732
+ ] }),
733
+ fronttailDebugKey.length < 4 && /* @__PURE__ */ jsx("span", { className: "text-sm text-destructive", children: "Debug key must contain at least 4 characters" })
734
+ ] })
735
+ ] });
736
+ }
737
+ const settingClasses = "border-solid border-b-2 border-accent pb-8 mb-8 last:mb-0 last:pb-0 last:border-0";
738
+ function Settings({
739
+ adheseContext
740
+ }) {
741
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(FronttailSettings, { adheseContext, className: settingClasses }) });
742
+ }
743
+ function PreviewButton() {
744
+ return /* @__PURE__ */ jsx(Fragment$1, { children: window.location.search.includes("adhesePreviewCreativeId") && /* @__PURE__ */ jsx(
745
+ Button,
746
+ {
747
+ onClick: () => {
748
+ const currentUrl = new URL(window.location.href);
749
+ window.location.replace(`${currentUrl.origin}${currentUrl.pathname === "/" ? "" : currentUrl.pathname}`);
750
+ },
751
+ variant: "secondary",
752
+ children: "Disable preview mode"
753
+ }
754
+ ) });
755
+ }
756
+ function Devtools({ adheseContext }) {
757
+ const [spacing, setSpacing] = useState(0);
758
+ const appRef = useRef(null);
759
+ const [isOpen, setIsOpen] = useState(false);
760
+ useEffect(() => {
761
+ let resizeObserver;
762
+ if (isOpen) {
763
+ resizeObserver = new ResizeObserver(
764
+ ([entry]) => {
765
+ setSpacing(entry.target.getBoundingClientRect().height);
766
+ }
767
+ );
768
+ if (appRef.current)
769
+ resizeObserver.observe(appRef.current);
770
+ }
771
+ return () => {
772
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
773
+ };
774
+ }, [isOpen]);
775
+ return /* @__PURE__ */ jsx("div", { className: "adhese-devtools", children: isOpen ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
776
+ /* @__PURE__ */ jsx(
777
+ "section",
778
+ {
779
+ className: "fixed bottom-0 w-full border-t-2 border-t-accent bg-background shadow-lg overflow-auto",
780
+ ref: appRef,
781
+ "aria-label": "Adhese Devtools",
782
+ children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "slots", children: [
783
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between p-4", children: [
784
+ /* @__PURE__ */ jsxs(TabsList, { children: [
785
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "slots", children: "Slots" }),
786
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "logs", children: "Logs" }),
787
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "parameters", children: "Parameters" }),
788
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "settings", children: "Settings" })
789
+ ] }),
790
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
791
+ /* @__PURE__ */ jsx(PreviewButton, {}),
792
+ /* @__PURE__ */ jsx(
793
+ Button,
794
+ {
795
+ onClick: setIsOpen.bind(null, false),
796
+ children: "Close"
797
+ }
798
+ )
799
+ ] })
800
+ ] }),
801
+ /* @__PURE__ */ jsxs("div", { className: "overflow-auto max-h-96 border-t-2 border-t-accent p-4", children: [
802
+ /* @__PURE__ */ jsx(TabsContent, { value: "slots", children: /* @__PURE__ */ jsx(SlotsTable, { adheseContext }) }),
803
+ /* @__PURE__ */ jsx(TabsContent, { value: "logs", children: /* @__PURE__ */ jsx(LogTable, { adheseContext }) }),
804
+ /* @__PURE__ */ jsx(TabsContent, { value: "parameters", children: /* @__PURE__ */ jsx(ParametersTable, { adheseContext }) }),
805
+ /* @__PURE__ */ jsx(TabsContent, { value: "settings", children: /* @__PURE__ */ jsx(Settings, { adheseContext }) })
806
+ ] })
807
+ ] })
808
+ }
809
+ ),
810
+ /* @__PURE__ */ jsx(
811
+ "div",
812
+ {
813
+ style: {
814
+ height: spacing
815
+ }
816
+ }
817
+ )
818
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "fixed bottom-4 right-4 flex flex-col gap-2", children: [
819
+ /* @__PURE__ */ jsx(Button, { onClick: setIsOpen.bind(null, true), children: "Open Adhese Devtools" }),
820
+ /* @__PURE__ */ jsx(PreviewButton, {})
821
+ ] }) });
822
+ }
823
+ const Devtools$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
824
+ __proto__: null,
825
+ Devtools
826
+ }, Symbol.toStringTag, { value: "Module" }));
827
+ function createAdheseDevtools(element, context) {
828
+ const root = createRoot(element);
829
+ root.render(/* @__PURE__ */ jsx(Devtools, { adheseContext: context }));
830
+ return () => {
831
+ root.unmount();
832
+ };
833
+ }
834
+ const main = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
835
+ __proto__: null,
836
+ createAdheseDevtools
837
+ }, Symbol.toStringTag, { value: "Module" }));
838
+ export {
839
+ Devtools$1 as D,
840
+ main as m
841
+ };
842
+ //# sourceMappingURL=devtools-B63USM72.js.map