@limboai/react 0.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 (60) hide show
  1. package/README.md +134 -0
  2. package/dist/icons/CRLogo.d.ts +12 -0
  3. package/dist/icons/LinkedInIcon.d.ts +13 -0
  4. package/dist/icons/index.d.ts +4 -0
  5. package/dist/index.cjs +2169 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.ts +11 -0
  8. package/dist/index.mjs +2147 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/dist/shared/hooks/index.d.ts +2 -0
  11. package/dist/shared/hooks/useTooltipVisibility.d.ts +32 -0
  12. package/dist/shared/index.d.ts +2 -0
  13. package/dist/types/index.d.ts +59 -0
  14. package/dist/types/media.d.ts +56 -0
  15. package/dist/ui/core/Slot.d.ts +33 -0
  16. package/dist/ui/core/credential/CredentialBadge.d.ts +63 -0
  17. package/dist/ui/core/credential/CredentialOverlayContent.d.ts +23 -0
  18. package/dist/ui/core/credential/CredentialOverlayRoot.d.ts +35 -0
  19. package/dist/ui/core/credential/CredentialOverlayTrigger.d.ts +23 -0
  20. package/dist/ui/core/credential/context/CredentialBadgeContext.d.ts +8 -0
  21. package/dist/ui/core/credential/context/CredentialOverlayContext.d.ts +21 -0
  22. package/dist/ui/core/credential/context/index.d.ts +2 -0
  23. package/dist/ui/core/credential/hooks/index.d.ts +2 -0
  24. package/dist/ui/core/credential/hooks/useCredentialBadgeContext.d.ts +15 -0
  25. package/dist/ui/core/credential/hooks/useCredentialOverlayContext.d.ts +23 -0
  26. package/dist/ui/core/credential/index.d.ts +36 -0
  27. package/dist/ui/core/index.d.ts +2 -0
  28. package/dist/ui/core/passport/PassportActions.d.ts +27 -0
  29. package/dist/ui/core/passport/PassportCopyButton.d.ts +38 -0
  30. package/dist/ui/core/passport/PassportField.d.ts +39 -0
  31. package/dist/ui/core/passport/PassportFooter.d.ts +20 -0
  32. package/dist/ui/core/passport/PassportHeader.d.ts +19 -0
  33. package/dist/ui/core/passport/PassportIdentities.d.ts +35 -0
  34. package/dist/ui/core/passport/PassportLogo.d.ts +25 -0
  35. package/dist/ui/core/passport/PassportRoot.d.ts +24 -0
  36. package/dist/ui/core/passport/PassportSigners.d.ts +28 -0
  37. package/dist/ui/core/passport/PassportTitle.d.ts +30 -0
  38. package/dist/ui/core/passport/context/PassportContext.d.ts +12 -0
  39. package/dist/ui/core/passport/context/index.d.ts +1 -0
  40. package/dist/ui/core/passport/hooks/index.d.ts +2 -0
  41. package/dist/ui/core/passport/hooks/usePassportContext.d.ts +20 -0
  42. package/dist/ui/core/passport/hooks/usePassportData.d.ts +22 -0
  43. package/dist/ui/core/passport/index.d.ts +49 -0
  44. package/dist/ui/default/LimboBadge.d.ts +22 -0
  45. package/dist/ui/default/LimboImage.d.ts +66 -0
  46. package/dist/ui/default/LimboPassport.d.ts +30 -0
  47. package/dist/ui/default/LimboVideo.d.ts +64 -0
  48. package/dist/ui/default/constants.d.ts +19 -0
  49. package/dist/ui/default/index.d.ts +10 -0
  50. package/dist/ui/index.d.ts +3 -0
  51. package/dist/ui/media/MediaImage.d.ts +87 -0
  52. package/dist/ui/media/MediaVideo.d.ts +85 -0
  53. package/dist/ui/media/context/MediaContext.d.ts +19 -0
  54. package/dist/ui/media/context/index.d.ts +1 -0
  55. package/dist/ui/media/hooks/index.d.ts +3 -0
  56. package/dist/ui/media/hooks/useHeicConversion.d.ts +32 -0
  57. package/dist/ui/media/hooks/useMediaContext.d.ts +13 -0
  58. package/dist/ui/media/hooks/useMediaOverlay.d.ts +37 -0
  59. package/dist/ui/media/index.d.ts +5 -0
  60. package/package.json +71 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2169 @@
1
+ "use client";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
+ let react_jsx_runtime = require("react/jsx-runtime");
4
+ let react = require("react");
5
+
6
+ //#region src/icons/CRLogo.tsx
7
+ const CR_LOGO_BASE64 = "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";
8
+ /**
9
+ * Content Credentials (CR) Logo
10
+ *
11
+ * Based on the Content Authenticity Initiative logo
12
+ */
13
+ const CRLogo = ({ size = 20, className, style }) => {
14
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
15
+ src: `data:image/png;base64,${CR_LOGO_BASE64}`,
16
+ width: size,
17
+ height: size,
18
+ className,
19
+ style,
20
+ alt: "Content Credentials"
21
+ });
22
+ };
23
+
24
+ //#endregion
25
+ //#region src/icons/LinkedInIcon.tsx
26
+ /**
27
+ * LinkedIn Icon as inline SVG
28
+ *
29
+ * Used for LinkedIn identity verification links
30
+ */
31
+ const LinkedInIcon = ({ size = 14, color = "#0077B5", className, style }) => {
32
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
33
+ width: size,
34
+ height: size,
35
+ viewBox: "0 0 24 24",
36
+ fill: color,
37
+ className,
38
+ style,
39
+ "aria-hidden": "true",
40
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" })
41
+ });
42
+ };
43
+
44
+ //#endregion
45
+ //#region src/shared/hooks/useTooltipVisibility.ts
46
+ /**
47
+ * Hook for managing tooltip visibility with delayed hide
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * const { isVisible, show, hide, toggle } = useTooltipVisibility({
52
+ * hasCredentials: validation?.has_credentials ?? false,
53
+ * hideDelay: 300,
54
+ * });
55
+ * ```
56
+ */
57
+ function useTooltipVisibility({ hasCredentials, initialVisible = false, hideDelay = 300 }) {
58
+ const [isVisible, setIsVisible] = (0, react.useState)(initialVisible);
59
+ const timeoutRef = (0, react.useRef)(null);
60
+ const clearPendingHide = (0, react.useCallback)(() => {
61
+ if (timeoutRef.current !== null) {
62
+ clearTimeout(timeoutRef.current);
63
+ timeoutRef.current = null;
64
+ }
65
+ }, []);
66
+ (0, react.useEffect)(() => clearPendingHide, [clearPendingHide]);
67
+ const show = (0, react.useCallback)(() => {
68
+ clearPendingHide();
69
+ if (hasCredentials) setIsVisible(true);
70
+ }, [hasCredentials, clearPendingHide]);
71
+ const hide = (0, react.useCallback)(() => {
72
+ clearPendingHide();
73
+ timeoutRef.current = setTimeout(() => setIsVisible(false), hideDelay);
74
+ }, [hideDelay, clearPendingHide]);
75
+ const toggle = (0, react.useCallback)(() => {
76
+ clearPendingHide();
77
+ if (hasCredentials) setIsVisible((v) => !v);
78
+ }, [hasCredentials, clearPendingHide]);
79
+ const setVisible = (0, react.useCallback)((visible) => {
80
+ clearPendingHide();
81
+ if (!visible || hasCredentials) setIsVisible(visible);
82
+ }, [hasCredentials, clearPendingHide]);
83
+ (0, react.useDebugValue)({
84
+ isVisible,
85
+ hasCredentials
86
+ });
87
+ return {
88
+ isVisible,
89
+ show,
90
+ hide,
91
+ toggle,
92
+ setVisible
93
+ };
94
+ }
95
+
96
+ //#endregion
97
+ //#region src/types/media.ts
98
+ /**
99
+ * Field names available in passport components
100
+ */
101
+ const PassportFieldName = {
102
+ Issuer: "issuer",
103
+ Date: "date"
104
+ };
105
+ /**
106
+ * Passport display variants
107
+ */
108
+ const PassportVariant = {
109
+ Basic: "basic",
110
+ Full: "full"
111
+ };
112
+
113
+ //#endregion
114
+ //#region src/types/index.ts
115
+ /**
116
+ * Validation status enum with const assertion and satisfies for type safety
117
+ */
118
+ const ValidationStatus = {
119
+ Idle: "idle",
120
+ Error: "error",
121
+ Success: "success",
122
+ Loading: "loading"
123
+ };
124
+
125
+ //#endregion
126
+ //#region src/ui/core/credential/context/CredentialBadgeContext.tsx
127
+ const CredentialBadgeContext = (0, react.createContext)(null);
128
+
129
+ //#endregion
130
+ //#region src/ui/core/credential/hooks/useCredentialBadgeContext.ts
131
+ /**
132
+ * Access the CredentialBadge context
133
+ *
134
+ * Must be used within a CredentialBadge.Root component
135
+ *
136
+ * @example
137
+ * ```tsx
138
+ * function MyBadgeContent() {
139
+ * const { status, hasCredentials } = useCredentialBadgeContext();
140
+ * return <div>{status}</div>;
141
+ * }
142
+ * ```
143
+ */
144
+ function useCredentialBadgeContext() {
145
+ const context = (0, react.useContext)(CredentialBadgeContext);
146
+ if (!context) throw new Error("useCredentialBadgeContext must be used within a CredentialBadge.Root");
147
+ (0, react.useDebugValue)({
148
+ status: context.status,
149
+ hasCredentials: context.hasCredentials
150
+ });
151
+ return context;
152
+ }
153
+
154
+ //#endregion
155
+ //#region src/ui/core/credential/context/CredentialOverlayContext.tsx
156
+ const CredentialOverlayContext = (0, react.createContext)(null);
157
+
158
+ //#endregion
159
+ //#region src/ui/core/credential/hooks/useCredentialOverlayContext.ts
160
+ /**
161
+ * Access the CredentialOverlay context
162
+ *
163
+ * Must be used within a CredentialOverlay.Root component
164
+ *
165
+ * @example
166
+ * ```tsx
167
+ * function MyTrigger() {
168
+ * const { show, hide, toggle, isVisible } = useCredentialOverlayContext();
169
+ * return (
170
+ * <button
171
+ * onMouseEnter={show}
172
+ * onMouseLeave={hide}
173
+ * onClick={toggle}
174
+ * >
175
+ * {isVisible ? "Hide" : "Show"}
176
+ * </button>
177
+ * );
178
+ * }
179
+ * ```
180
+ */
181
+ function useCredentialOverlayContext() {
182
+ const context = (0, react.useContext)(CredentialOverlayContext);
183
+ if (!context) throw new Error("useCredentialOverlayContext must be used within a CredentialOverlay.Root");
184
+ (0, react.useDebugValue)({
185
+ status: context.status,
186
+ isVisible: context.isVisible
187
+ });
188
+ return context;
189
+ }
190
+
191
+ //#endregion
192
+ //#region src/ui/core/credential/CredentialBadge.tsx
193
+ /**
194
+ * CredentialBadge.Root - Provider wrapper for the CredentialBadge compound component
195
+ *
196
+ * Provides context with status and hasCredentials to all child components.
197
+ * Children are slot components that render based on the current state.
198
+ *
199
+ * @example
200
+ * ```tsx
201
+ * <CredentialBadge.Root status={status} hasCredentials={hasCredentials}>
202
+ * <CredentialBadge.Loading>
203
+ * <Spinner />
204
+ * </CredentialBadge.Loading>
205
+ *
206
+ * <CredentialBadge.Verified>
207
+ * <CheckIcon className="text-green-500" />
208
+ * </CredentialBadge.Verified>
209
+ *
210
+ * <CredentialBadge.NoCredentials>
211
+ * <span>No credentials</span>
212
+ * </CredentialBadge.NoCredentials>
213
+ *
214
+ * <CredentialBadge.Error>
215
+ * <span>Error</span>
216
+ * </CredentialBadge.Error>
217
+ * </CredentialBadge.Root>
218
+ * ```
219
+ */
220
+ const CredentialBadgeRoot = (0, react.forwardRef)(({ status, hasCredentials, children, ...props }, ref) => {
221
+ const contextValue = (0, react.useMemo)(() => ({
222
+ status,
223
+ hasCredentials
224
+ }), [status, hasCredentials]);
225
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CredentialBadgeContext.Provider, {
226
+ value: contextValue,
227
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
228
+ ref,
229
+ ...props,
230
+ children
231
+ })
232
+ });
233
+ });
234
+ CredentialBadgeRoot.displayName = "CredentialBadge.Root";
235
+ function createStatusComponent(displayName, shouldRender) {
236
+ const Component = ({ children }) => {
237
+ const { status, hasCredentials } = useCredentialBadgeContext();
238
+ if (!shouldRender(status, hasCredentials)) return null;
239
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
240
+ };
241
+ Component.displayName = displayName;
242
+ return Component;
243
+ }
244
+ /**
245
+ * CredentialBadge.Loading - Renders children only when status is "loading"
246
+ */
247
+ const CredentialBadgeLoading = createStatusComponent("CredentialBadge.Loading", (status) => status === ValidationStatus.Loading);
248
+ /**
249
+ * CredentialBadge.Error - Renders children only when status is "error"
250
+ */
251
+ const CredentialBadgeError = createStatusComponent("CredentialBadge.Error", (status) => status === ValidationStatus.Error);
252
+ /**
253
+ * CredentialBadge.Verified - Renders children only when status is "success" and has credentials
254
+ */
255
+ const CredentialBadgeVerified = createStatusComponent("CredentialBadge.Verified", (status, hasCredentials) => status === ValidationStatus.Success && hasCredentials);
256
+ /**
257
+ * CredentialBadge.Idle - Renders children only when status is "idle"
258
+ */
259
+ const CredentialBadgeIdle = createStatusComponent("CredentialBadge.Idle", (status) => status === ValidationStatus.Idle);
260
+ /**
261
+ * CredentialBadge.NoCredentials - Renders children only when status is "success" but no credentials
262
+ */
263
+ const CredentialBadgeNoCredentials = createStatusComponent("CredentialBadge.NoCredentials", (status, hasCredentials) => status === ValidationStatus.Success && !hasCredentials);
264
+ /**
265
+ * CredentialBadge - Headless compound component for displaying credential status
266
+ *
267
+ * @example
268
+ * ```tsx
269
+ * import { CredentialBadge } from "@limboai/react";
270
+ *
271
+ * <CredentialBadge.Root status={status} hasCredentials={hasCredentials}>
272
+ * <CredentialBadge.Loading>
273
+ * <div className="animate-pulse bg-blue-500 rounded-full p-2">
274
+ * <Spinner />
275
+ * </div>
276
+ * </CredentialBadge.Loading>
277
+ *
278
+ * <CredentialBadge.Verified>
279
+ * <button className="bg-green-500 rounded-full p-2">
280
+ * <CheckIcon />
281
+ * </button>
282
+ * </CredentialBadge.Verified>
283
+ *
284
+ * <CredentialBadge.NoCredentials>
285
+ * <span className="bg-red-500 text-white text-xs px-2 py-1 rounded">
286
+ * No credentials
287
+ * </span>
288
+ * </CredentialBadge.NoCredentials>
289
+ *
290
+ * <CredentialBadge.Error>
291
+ * <span className="bg-red-500 text-white text-xs px-2 py-1 rounded">
292
+ * Error
293
+ * </span>
294
+ * </CredentialBadge.Error>
295
+ * </CredentialBadge.Root>
296
+ * ```
297
+ */
298
+ const CredentialBadge = {
299
+ Root: CredentialBadgeRoot,
300
+ Loading: CredentialBadgeLoading,
301
+ Verified: CredentialBadgeVerified,
302
+ NoCredentials: CredentialBadgeNoCredentials,
303
+ Error: CredentialBadgeError,
304
+ Idle: CredentialBadgeIdle
305
+ };
306
+
307
+ //#endregion
308
+ //#region src/ui/core/credential/CredentialOverlayContent.tsx
309
+ /**
310
+ * CredentialOverlay.Content - Content that appears when the overlay is visible
311
+ *
312
+ * Only renders when the overlay is visible and credentials exist.
313
+ * Use forceMount to always render (useful for CSS transitions).
314
+ *
315
+ * @example
316
+ * ```tsx
317
+ * <CredentialOverlay.Content className="absolute top-12 right-0 bg-white shadow-lg rounded-lg p-4">
318
+ * <Passport.Root validation={validation}>
319
+ * ...
320
+ * </Passport.Root>
321
+ * </CredentialOverlay.Content>
322
+ * ```
323
+ */
324
+ const CredentialOverlayContent = (0, react.forwardRef)(({ children, forceMount, onMouseLeave, ...props }, ref) => {
325
+ const { isVisible, hasCredentials, validation, hide } = useCredentialOverlayContext();
326
+ if (!forceMount && (!isVisible || !hasCredentials || !validation)) return null;
327
+ const handleMouseLeave = (e) => {
328
+ hide();
329
+ onMouseLeave?.(e);
330
+ };
331
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
332
+ ref,
333
+ role: "tooltip",
334
+ tabIndex: -1,
335
+ "data-state": isVisible ? "open" : "closed",
336
+ onMouseLeave: handleMouseLeave,
337
+ ...props,
338
+ children
339
+ });
340
+ });
341
+ CredentialOverlayContent.displayName = "CredentialOverlay.Content";
342
+
343
+ //#endregion
344
+ //#region src/ui/core/credential/CredentialOverlayRoot.tsx
345
+ /**
346
+ * CredentialOverlay.Root - Provider wrapper for the CredentialOverlay compound component
347
+ *
348
+ * Provides context with validation data and visibility state to all child components.
349
+ * Manages tooltip visibility with configurable hide delay.
350
+ *
351
+ * @example
352
+ * ```tsx
353
+ * <CredentialOverlay.Root validation={validation} status="success">
354
+ * <CredentialOverlay.Trigger className="absolute top-2 right-2">
355
+ * <button className="bg-green-500 p-2 rounded-full">✓</button>
356
+ * </CredentialOverlay.Trigger>
357
+ *
358
+ * <CredentialOverlay.Content className="absolute top-12 right-0 bg-white shadow-lg rounded-lg p-4">
359
+ * <Passport.Root validation={validation}>
360
+ * ...
361
+ * </Passport.Root>
362
+ * </CredentialOverlay.Content>
363
+ * </CredentialOverlay.Root>
364
+ * ```
365
+ */
366
+ const CredentialOverlayRoot = (0, react.forwardRef)(({ validation, status = "idle", hideDelay = 300, children, ...props }, ref) => {
367
+ const overlayId = (0, react.useId)();
368
+ const hasCredentials = validation?.has_credentials ?? false;
369
+ const { isVisible, show, hide, toggle } = useTooltipVisibility({
370
+ hasCredentials,
371
+ hideDelay
372
+ });
373
+ const contextValue = (0, react.useMemo)(() => ({
374
+ validation,
375
+ status,
376
+ hasCredentials,
377
+ isVisible,
378
+ show,
379
+ hide,
380
+ toggle,
381
+ overlayId
382
+ }), [
383
+ validation,
384
+ status,
385
+ hasCredentials,
386
+ isVisible,
387
+ show,
388
+ hide,
389
+ toggle,
390
+ overlayId
391
+ ]);
392
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CredentialOverlayContext.Provider, {
393
+ value: contextValue,
394
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
395
+ ref,
396
+ ...props,
397
+ children
398
+ })
399
+ });
400
+ });
401
+ CredentialOverlayRoot.displayName = "CredentialOverlay.Root";
402
+
403
+ //#endregion
404
+ //#region src/ui/core/Slot.tsx
405
+ /**
406
+ * Compose multiple refs into a single callback ref
407
+ * Handles function refs, object refs, and undefined refs safely
408
+ */
409
+ function composeRefs(...refs) {
410
+ return (instance) => {
411
+ for (const ref of refs) if (typeof ref === "function") ref(instance);
412
+ else if (ref != null) ref.current = instance;
413
+ };
414
+ }
415
+ /**
416
+ * Compose event handlers, calling child handler first then slot handler
417
+ */
418
+ function composeEventHandlers(childHandler, slotHandler) {
419
+ if (!childHandler && !slotHandler) return void 0;
420
+ if (!childHandler) return slotHandler;
421
+ if (!slotHandler) return childHandler;
422
+ return (event) => {
423
+ childHandler(event);
424
+ slotHandler(event);
425
+ };
426
+ }
427
+ /**
428
+ * Merge props from slot and child element
429
+ * - Event handlers are composed (child first, then slot)
430
+ * - className is concatenated
431
+ * - style is shallow merged (child overrides slot)
432
+ * - Other props: child overrides slot
433
+ */
434
+ function mergeProps(slotProps, childProps) {
435
+ const merged = { ...slotProps };
436
+ for (const key in childProps) {
437
+ const slotValue = slotProps[key];
438
+ const childValue = childProps[key];
439
+ if (/^on[A-Z]/.test(key)) merged[key] = composeEventHandlers(childValue, slotValue);
440
+ else if (key === "className") merged[key] = [slotValue, childValue].filter(Boolean).join(" ");
441
+ else if (key === "style") merged[key] = {
442
+ ...slotValue,
443
+ ...childValue
444
+ };
445
+ else merged[key] = childValue;
446
+ }
447
+ return merged;
448
+ }
449
+ /**
450
+ * Slot - Enables the asChild pattern for composable components
451
+ *
452
+ * Renders the child element with merged props and refs from the slot.
453
+ * This enables consumers to use their own elements while inheriting
454
+ * behavior from headless components.
455
+ *
456
+ * Inspired by Radix UI's Slot primitive.
457
+ *
458
+ * @example
459
+ * ```tsx
460
+ * // Component with asChild support
461
+ * const Button = forwardRef<HTMLButtonElement, ButtonProps>(
462
+ * ({ asChild, ...props }, ref) => {
463
+ * const Comp = asChild ? Slot : 'button';
464
+ * return <Comp ref={ref} {...props} />;
465
+ * }
466
+ * );
467
+ *
468
+ * // Consumer renders their own element
469
+ * <Button asChild onClick={handleClick}>
470
+ * <a href="/link">Click me</a>
471
+ * </Button>
472
+ * // Renders: <a href="/link" onClick={handleClick}>Click me</a>
473
+ * ```
474
+ */
475
+ const Slot = (0, react.forwardRef)(({ children, ...slotProps }, forwardedRef) => {
476
+ const childArray = react.Children.toArray(children);
477
+ const slottableChild = childArray.find(react.isValidElement);
478
+ if (!slottableChild || !(0, react.isValidElement)(slottableChild)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
479
+ const child = slottableChild;
480
+ const grandchildren = childArray.flatMap((c) => c === slottableChild ? react.Children.toArray(child.props.children) : [c]);
481
+ return (0, react.cloneElement)(child, {
482
+ ...mergeProps(slotProps, child.props),
483
+ ref: forwardedRef ? composeRefs(forwardedRef, child.props.ref) : child.props.ref,
484
+ children: grandchildren.length > 0 ? grandchildren : void 0
485
+ });
486
+ });
487
+ Slot.displayName = "Slot";
488
+
489
+ //#endregion
490
+ //#region src/ui/core/credential/CredentialOverlayTrigger.tsx
491
+ /**
492
+ * CredentialOverlay.Trigger - Trigger element for showing/hiding the overlay
493
+ *
494
+ * Attaches hover and click handlers to show/hide the tooltip.
495
+ * Use asChild to render your own element.
496
+ *
497
+ * @example
498
+ * ```tsx
499
+ * <CredentialOverlay.Trigger asChild>
500
+ * <button className="bg-green-500 p-2 rounded-full">
501
+ * <CheckIcon />
502
+ * </button>
503
+ * </CredentialOverlay.Trigger>
504
+ * ```
505
+ */
506
+ const CredentialOverlayTrigger = (0, react.forwardRef)(({ asChild, children, onMouseEnter, onMouseLeave, onClick, ...props }, ref) => {
507
+ const { show, hide, toggle, hasCredentials } = useCredentialOverlayContext();
508
+ const triggerProps = {
509
+ onMouseEnter: (0, react.useCallback)((e) => {
510
+ show();
511
+ onMouseEnter?.(e);
512
+ }, [show, onMouseEnter]),
513
+ onMouseLeave: (0, react.useCallback)((e) => {
514
+ hide();
515
+ onMouseLeave?.(e);
516
+ }, [hide, onMouseLeave]),
517
+ onClick: (0, react.useCallback)((e) => {
518
+ toggle();
519
+ onClick?.(e);
520
+ }, [toggle, onClick]),
521
+ "aria-label": hasCredentials ? "View content credentials" : "No credentials found",
522
+ "aria-haspopup": "dialog",
523
+ ...props
524
+ };
525
+ if (asChild) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Slot, {
526
+ ref,
527
+ ...triggerProps,
528
+ children
529
+ });
530
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
531
+ ref,
532
+ ...triggerProps,
533
+ children
534
+ });
535
+ });
536
+ CredentialOverlayTrigger.displayName = "CredentialOverlay.Trigger";
537
+
538
+ //#endregion
539
+ //#region src/ui/core/credential/index.ts
540
+ /**
541
+ * CredentialOverlay - Headless compound component for trigger + tooltip pattern
542
+ *
543
+ * @example
544
+ * ```tsx
545
+ * import { CredentialOverlay, Passport, CredentialBadge } from "@limboai/react";
546
+ *
547
+ * <div className="relative">
548
+ * <img src="/photo.jpg" />
549
+ *
550
+ * <CredentialOverlay.Root validation={validation} status={status}>
551
+ * <CredentialOverlay.Trigger className="absolute top-2 right-2">
552
+ * <CredentialBadge.Root status={status} hasCredentials={hasCredentials}>
553
+ * <CredentialBadge.Verified>
554
+ * <button className="bg-green-500 p-2 rounded-full">✓</button>
555
+ * </CredentialBadge.Verified>
556
+ * </CredentialBadge.Root>
557
+ * </CredentialOverlay.Trigger>
558
+ *
559
+ * <CredentialOverlay.Content className="absolute top-12 right-0 bg-white shadow-lg rounded-lg p-4">
560
+ * <Passport.Root validation={validation}>
561
+ * ...
562
+ * </Passport.Root>
563
+ * </CredentialOverlay.Content>
564
+ * </CredentialOverlay.Root>
565
+ * </div>
566
+ * ```
567
+ */
568
+ const CredentialOverlay = {
569
+ Root: CredentialOverlayRoot,
570
+ Trigger: CredentialOverlayTrigger,
571
+ Content: CredentialOverlayContent
572
+ };
573
+
574
+ //#endregion
575
+ //#region src/ui/core/passport/context/PassportContext.tsx
576
+ const PassportContext = (0, react.createContext)(null);
577
+
578
+ //#endregion
579
+ //#region src/ui/core/passport/hooks/usePassportContext.ts
580
+ /**
581
+ * Access the Passport context
582
+ *
583
+ * Must be used within a Passport.Root component
584
+ *
585
+ * @example
586
+ * ```tsx
587
+ * function MyCustomField() {
588
+ * const { issuer, issuedDate, copied, isPending } = usePassportContext();
589
+ * return (
590
+ * <div>
591
+ * <p>{issuer} - {issuedDate}</p>
592
+ * {isPending && <span>Copying...</span>}
593
+ * </div>
594
+ * );
595
+ * }
596
+ * ```
597
+ */
598
+ function usePassportContext() {
599
+ const context = (0, react.useContext)(PassportContext);
600
+ if (!context) throw new Error("usePassportContext must be used within a Passport.Root");
601
+ (0, react.useDebugValue)({
602
+ issuer: context.issuer,
603
+ copied: context.copied
604
+ });
605
+ return context;
606
+ }
607
+
608
+ //#endregion
609
+ //#region src/ui/core/passport/hooks/usePassportData.ts
610
+ /**
611
+ * Extract actions from c2pa.actions.v2 or c2pa.actions assertion
612
+ */
613
+ function extractActions(assertions) {
614
+ const actionsAssertion = assertions.find((a) => a.label === "c2pa.actions.v2" || a.label === "c2pa.actions");
615
+ if (!actionsAssertion?.value) return [];
616
+ const value = actionsAssertion.value;
617
+ if (value.actions && Array.isArray(value.actions)) return value.actions.map((a) => a.action).filter((action) => Boolean(action));
618
+ if (value.action) return [value.action];
619
+ return [];
620
+ }
621
+ /**
622
+ * Extract verified identities from cawg.identity assertion
623
+ * Supports both:
624
+ * - Direct format: value.verifiedIdentities
625
+ * - CAWG 1.1 Verifiable Credential format: value.credentialSubject.verifiedIdentities
626
+ */
627
+ function extractIdentities(assertions) {
628
+ const identityAssertion = assertions.find((a) => a.label === "cawg.identity");
629
+ if (!identityAssertion?.value) return [];
630
+ const value = identityAssertion.value;
631
+ if (value.credentialSubject?.verifiedIdentities && Array.isArray(value.credentialSubject.verifiedIdentities)) return value.credentialSubject.verifiedIdentities;
632
+ if (value.verifiedIdentities && Array.isArray(value.verifiedIdentities)) return value.verifiedIdentities;
633
+ return [];
634
+ }
635
+ /**
636
+ * Format a date string for display
637
+ */
638
+ function formatDate(dateString) {
639
+ return new Date(dateString).toLocaleDateString("en-US", {
640
+ year: "numeric",
641
+ month: "long",
642
+ day: "numeric"
643
+ });
644
+ }
645
+ /**
646
+ * Hook to extract and process data from a C2PA validation response
647
+ *
648
+ * Extracts issuer, date, actions, identities, and signers from the validation
649
+ * response for easy consumption by Passport components.
650
+ *
651
+ * @example
652
+ * ```tsx
653
+ * const { issuer, issuedDate, actions, verifiedIdentities, previousSigners } =
654
+ * usePassportData(validation);
655
+ *
656
+ * return (
657
+ * <div>
658
+ * <p>Issued by: {issuer}</p>
659
+ * <p>Date: {issuedDate}</p>
660
+ * </div>
661
+ * );
662
+ * ```
663
+ */
664
+ function usePassportData(validation) {
665
+ const data = (0, react.useMemo)(() => {
666
+ const activeManifest = validation.manifest_chain?.find((manifest) => manifest.label === validation.active_manifest_label) || validation.manifest_chain?.[0] || null;
667
+ const issuer = activeManifest?.signature_info.issuer || "Unknown";
668
+ const issuedDateRaw = activeManifest?.signature_info.time || null;
669
+ return {
670
+ issuer,
671
+ issuedDate: issuedDateRaw ? formatDate(issuedDateRaw) : "Date unknown",
672
+ issuedDateRaw,
673
+ actions: activeManifest?.assertions ? extractActions(activeManifest.assertions) : [],
674
+ verifiedIdentities: activeManifest?.assertions ? extractIdentities(activeManifest.assertions) : [],
675
+ previousSigners: validation.manifest_chain?.filter((m) => m.label !== validation.active_manifest_label) || [],
676
+ activeManifest,
677
+ validation
678
+ };
679
+ }, [validation]);
680
+ (0, react.useDebugValue)({
681
+ issuer: data.issuer,
682
+ hasActions: data.actions.length > 0
683
+ });
684
+ return data;
685
+ }
686
+
687
+ //#endregion
688
+ //#region src/ui/core/passport/PassportActions.tsx
689
+ /**
690
+ * Format action label for display
691
+ * e.g., "c2pa.edited" -> "Edited"
692
+ */
693
+ function formatActionLabel(action) {
694
+ const withoutNamespace = action.split(".").pop() || action;
695
+ return withoutNamespace.charAt(0).toUpperCase() + withoutNamespace.slice(1);
696
+ }
697
+ /**
698
+ * Passport.Actions - Display actions from the manifest
699
+ *
700
+ * Renders actions using a render prop for full styling control.
701
+ * Returns null if there are no actions.
702
+ *
703
+ * @example
704
+ * ```tsx
705
+ * <Passport.Actions className="mt-4">
706
+ * {(actions) => (
707
+ * <div className="flex gap-2">
708
+ * {actions.map((action) => (
709
+ * <span key={action} className="tag bg-gray-100 px-2 py-1 rounded">
710
+ * {action}
711
+ * </span>
712
+ * ))}
713
+ * </div>
714
+ * )}
715
+ * </Passport.Actions>
716
+ * ```
717
+ */
718
+ const PassportActions = (0, react.forwardRef)(({ children, ...props }, ref) => {
719
+ const { actions } = usePassportContext();
720
+ if (actions.length === 0) return null;
721
+ const formattedActions = actions.map(formatActionLabel);
722
+ if (typeof children !== "function") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
723
+ ref,
724
+ ...props,
725
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
726
+ "data-passport-actions-label": true,
727
+ children: "Actions"
728
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
729
+ "data-passport-actions-list": true,
730
+ children: formattedActions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
731
+ "data-passport-action": true,
732
+ children: action
733
+ }, action))
734
+ })]
735
+ });
736
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
737
+ ref,
738
+ ...props,
739
+ children: children(formattedActions)
740
+ });
741
+ });
742
+ PassportActions.displayName = "Passport.Actions";
743
+
744
+ //#endregion
745
+ //#region src/ui/core/passport/PassportCopyButton.tsx
746
+ /**
747
+ * Passport.CopyButton - Copy validation JSON to clipboard
748
+ *
749
+ * Renders a button that copies the validation JSON to clipboard.
750
+ * Supports pending state from React 19's useActionState.
751
+ * Use asChild to provide your own button element.
752
+ *
753
+ * @example
754
+ * ```tsx
755
+ * // Default button
756
+ * <Passport.CopyButton className="btn" />
757
+ *
758
+ * // Custom button with asChild
759
+ * <Passport.CopyButton asChild>
760
+ * <button className="my-button">
761
+ * Copy JSON
762
+ * </button>
763
+ * </Passport.CopyButton>
764
+ *
765
+ * // Access pending state in custom component
766
+ * function CustomCopyButton() {
767
+ * const { copyJson, copied, isPending } = usePassportContext();
768
+ * return (
769
+ * <button onClick={copyJson} disabled={isPending}>
770
+ * {isPending ? "Copying..." : copied ? "Copied!" : "Copy"}
771
+ * </button>
772
+ * );
773
+ * }
774
+ * ```
775
+ */
776
+ const PassportCopyButton = (0, react.forwardRef)(({ asChild, children, onClick, disabled, ...props }, ref) => {
777
+ const { copyJson, copied, isPending } = usePassportContext();
778
+ const handleClick = (e) => {
779
+ copyJson();
780
+ onClick?.(e);
781
+ };
782
+ const commonProps = {
783
+ onClick: handleClick,
784
+ disabled: disabled || isPending,
785
+ "data-copied": copied || void 0,
786
+ "data-pending": isPending || void 0,
787
+ "aria-busy": isPending || void 0,
788
+ ...props
789
+ };
790
+ if (asChild && children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Slot, {
791
+ ref,
792
+ ...commonProps,
793
+ children
794
+ });
795
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
796
+ ref,
797
+ type: "button",
798
+ ...commonProps,
799
+ children: isPending ? "Copying..." : copied ? "Copied!" : "Copy JSON"
800
+ });
801
+ });
802
+ PassportCopyButton.displayName = "Passport.CopyButton";
803
+
804
+ //#endregion
805
+ //#region src/ui/core/passport/PassportField.tsx
806
+ const DEFAULT_LABELS = {
807
+ [PassportFieldName.Issuer]: "Issued by",
808
+ [PassportFieldName.Date]: "Date issued"
809
+ };
810
+ /**
811
+ * Passport.Field - Display a field from the passport data
812
+ *
813
+ * Automatically fills the value from context based on the field name.
814
+ * Use a render function for complete control over layout.
815
+ *
816
+ * @example
817
+ * ```tsx
818
+ * // Simple usage with default rendering
819
+ * <Passport.Field name="issuer" className="mb-2" />
820
+ *
821
+ * // Custom label
822
+ * <Passport.Field name="date" label="Signed on" />
823
+ *
824
+ * // Render function for custom layout
825
+ * <Passport.Field name="issuer">
826
+ * {({ label, value }) => (
827
+ * <div className="flex justify-between">
828
+ * <span className="font-bold">{label}</span>
829
+ * <span>{value}</span>
830
+ * </div>
831
+ * )}
832
+ * </Passport.Field>
833
+ * ```
834
+ */
835
+ const PassportField = (0, react.forwardRef)(({ name, label, children, ...props }, ref) => {
836
+ const context = usePassportContext();
837
+ const value = name === PassportFieldName.Issuer ? context.issuer : context.issuedDate;
838
+ const displayLabel = label ?? DEFAULT_LABELS[name];
839
+ if (typeof children === "function") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
840
+ ref,
841
+ ...props,
842
+ children: children({
843
+ label: displayLabel,
844
+ value
845
+ })
846
+ });
847
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
848
+ ref,
849
+ ...props,
850
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
851
+ "data-passport-field-label": true,
852
+ children: displayLabel
853
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
854
+ "data-passport-field-value": true,
855
+ children: value
856
+ })]
857
+ });
858
+ });
859
+ PassportField.displayName = "Passport.Field";
860
+
861
+ //#endregion
862
+ //#region src/ui/core/passport/PassportFooter.tsx
863
+ /**
864
+ * Passport.Footer - Footer slot for the Passport
865
+ *
866
+ * A simple div wrapper for footer content. Style it yourself.
867
+ *
868
+ * @example
869
+ * ```tsx
870
+ * <Passport.Footer className="mt-4 border-t pt-4 flex justify-end">
871
+ * <Passport.CopyButton asChild>
872
+ * <button className="btn-primary">Copy JSON</button>
873
+ * </Passport.CopyButton>
874
+ * </Passport.Footer>
875
+ * ```
876
+ */
877
+ const PassportFooter = (0, react.forwardRef)(({ children, ...props }, ref) => {
878
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
879
+ ref,
880
+ ...props,
881
+ children
882
+ });
883
+ });
884
+ PassportFooter.displayName = "Passport.Footer";
885
+
886
+ //#endregion
887
+ //#region src/ui/core/passport/PassportHeader.tsx
888
+ /**
889
+ * Passport.Header - Header slot for the Passport
890
+ *
891
+ * A simple div wrapper for header content. Style it yourself.
892
+ *
893
+ * @example
894
+ * ```tsx
895
+ * <Passport.Header className="flex items-center gap-2 mb-4">
896
+ * <Passport.Logo className="w-6 h-6" />
897
+ * <Passport.Title className="text-lg font-bold" />
898
+ * </Passport.Header>
899
+ * ```
900
+ */
901
+ const PassportHeader = (0, react.forwardRef)(({ children, ...props }, ref) => {
902
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
903
+ ref,
904
+ ...props,
905
+ children
906
+ });
907
+ });
908
+ PassportHeader.displayName = "Passport.Header";
909
+
910
+ //#endregion
911
+ //#region src/ui/core/passport/PassportIdentities.tsx
912
+ /**
913
+ * Convert VerifiedIdentity to IdentityInfo for easier rendering
914
+ */
915
+ function toIdentityInfo(identity) {
916
+ return {
917
+ username: identity.name,
918
+ provider: identity.provider.name,
919
+ uri: identity.uri,
920
+ verifiedAt: identity.verifiedAt
921
+ };
922
+ }
923
+ /**
924
+ * Passport.Identities - Display verified identities from the manifest
925
+ *
926
+ * Renders identities using a render prop for full styling control.
927
+ * Returns null if there are no identities.
928
+ *
929
+ * @example
930
+ * ```tsx
931
+ * <Passport.Identities className="mt-4">
932
+ * {(identities) => (
933
+ * <ul className="space-y-2">
934
+ * {identities.map((identity) => (
935
+ * <li key={identity.provider} className="flex items-center gap-2">
936
+ * {identity.provider === "LinkedIn" && <LinkedInIcon />}
937
+ * {identity.uri ? (
938
+ * <a href={identity.uri} target="_blank" rel="noopener noreferrer">
939
+ * {identity.username}
940
+ * </a>
941
+ * ) : (
942
+ * <span>{identity.username}</span>
943
+ * )}
944
+ * </li>
945
+ * ))}
946
+ * </ul>
947
+ * )}
948
+ * </Passport.Identities>
949
+ * ```
950
+ */
951
+ const PassportIdentities = (0, react.forwardRef)(({ children, ...props }, ref) => {
952
+ const { verifiedIdentities } = usePassportContext();
953
+ if (verifiedIdentities.length === 0) return null;
954
+ const identities = verifiedIdentities.map(toIdentityInfo);
955
+ const label = identities.length === 1 ? "Verified Identity" : `Verified Identities (${identities.length})`;
956
+ if (typeof children !== "function") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
957
+ ref,
958
+ ...props,
959
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
960
+ "data-passport-identities-label": true,
961
+ children: label
962
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
963
+ "data-passport-identities-list": true,
964
+ children: identities.map((identity) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
965
+ "data-passport-identity": true,
966
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
967
+ "data-passport-identity-provider": true,
968
+ children: identity.provider
969
+ }), identity.uri ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
970
+ href: identity.uri,
971
+ target: "_blank",
972
+ rel: "noopener noreferrer",
973
+ "data-passport-identity-link": true,
974
+ children: identity.username
975
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
976
+ "data-passport-identity-username": true,
977
+ children: identity.username
978
+ })]
979
+ }, identity.provider))
980
+ })]
981
+ });
982
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
983
+ ref,
984
+ ...props,
985
+ children: children(identities)
986
+ });
987
+ });
988
+ PassportIdentities.displayName = "Passport.Identities";
989
+
990
+ //#endregion
991
+ //#region src/ui/core/passport/PassportLogo.tsx
992
+ /**
993
+ * Passport.Logo - Logo for the Passport
994
+ *
995
+ * Renders the Content Credentials logo by default.
996
+ * Use asChild to provide your own logo element.
997
+ *
998
+ * @example
999
+ * ```tsx
1000
+ * // Default logo
1001
+ * <Passport.Logo className="w-6 h-6" />
1002
+ *
1003
+ * // Custom logo with asChild
1004
+ * <Passport.Logo asChild>
1005
+ * <img src="/my-logo.svg" alt="Logo" className="w-6 h-6" />
1006
+ * </Passport.Logo>
1007
+ * ```
1008
+ */
1009
+ const PassportLogo = (0, react.forwardRef)(({ asChild, children, ...props }, ref) => {
1010
+ if (asChild && children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Slot, {
1011
+ ref,
1012
+ ...props,
1013
+ children
1014
+ });
1015
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CRLogo, { ...props });
1016
+ });
1017
+ PassportLogo.displayName = "Passport.Logo";
1018
+
1019
+ //#endregion
1020
+ //#region src/ui/core/passport/PassportRoot.tsx
1021
+ /**
1022
+ * Passport.Root - Provider wrapper for the Passport compound component
1023
+ *
1024
+ * Provides context with processed validation data to all child components.
1025
+ * Uses React 19's useTransition for non-blocking copy operations.
1026
+ *
1027
+ * @example
1028
+ * ```tsx
1029
+ * <Passport.Root validation={validation} className="my-tooltip bg-white p-4 rounded">
1030
+ * <Passport.Header />
1031
+ * <Passport.Field name="issuer" />
1032
+ * <Passport.Footer />
1033
+ * </Passport.Root>
1034
+ * ```
1035
+ */
1036
+ const PassportRoot = (0, react.forwardRef)(({ validation, children, ...props }, ref) => {
1037
+ const titleId = (0, react.useId)();
1038
+ const passportData = usePassportData(validation);
1039
+ const [copied, setCopied] = (0, react.useState)(false);
1040
+ const [isPending, startTransition] = (0, react.useTransition)();
1041
+ const copyJson = (0, react.useCallback)(async () => {
1042
+ startTransition(async () => {
1043
+ try {
1044
+ await navigator.clipboard.writeText(JSON.stringify(validation, null, 2));
1045
+ setCopied(true);
1046
+ setTimeout(() => setCopied(false), 2e3);
1047
+ } catch (error) {
1048
+ console.error("Failed to copy:", error);
1049
+ }
1050
+ });
1051
+ return true;
1052
+ }, [validation]);
1053
+ const contextValue = (0, react.useMemo)(() => ({
1054
+ ...passportData,
1055
+ copyJson,
1056
+ copied,
1057
+ isPending,
1058
+ titleId
1059
+ }), [
1060
+ passportData,
1061
+ copyJson,
1062
+ copied,
1063
+ isPending,
1064
+ titleId
1065
+ ]);
1066
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PassportContext.Provider, {
1067
+ value: contextValue,
1068
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1069
+ ref,
1070
+ role: "dialog",
1071
+ "aria-labelledby": titleId,
1072
+ ...props,
1073
+ children
1074
+ })
1075
+ });
1076
+ });
1077
+ PassportRoot.displayName = "Passport.Root";
1078
+
1079
+ //#endregion
1080
+ //#region src/ui/core/passport/PassportSigners.tsx
1081
+ /**
1082
+ * Passport.Signers - Display previous signers in the manifest chain
1083
+ *
1084
+ * Renders signers using a render prop for full styling control.
1085
+ * Returns null if there are no previous signers.
1086
+ *
1087
+ * @example
1088
+ * ```tsx
1089
+ * <Passport.Signers className="mt-4">
1090
+ * {(signers) => (
1091
+ * <ul className="space-y-1">
1092
+ * {signers.map((signer) => (
1093
+ * <li key={signer.id} className="text-sm text-gray-600">
1094
+ * {signer.label}
1095
+ * </li>
1096
+ * ))}
1097
+ * </ul>
1098
+ * )}
1099
+ * </Passport.Signers>
1100
+ * ```
1101
+ */
1102
+ const PassportSigners = (0, react.forwardRef)(({ children, ...props }, ref) => {
1103
+ const { previousSigners } = usePassportContext();
1104
+ if (previousSigners.length === 0) return null;
1105
+ const signers = previousSigners.map((manifest) => ({
1106
+ id: manifest.instance_id,
1107
+ label: manifest.signature_info.issuer,
1108
+ signedAt: manifest.signature_info.time ?? void 0
1109
+ }));
1110
+ const label = signers.length === 1 ? "Previous Signer" : `Previous Signers (${signers.length})`;
1111
+ if (typeof children !== "function") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1112
+ ref,
1113
+ ...props,
1114
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1115
+ "data-passport-signers-label": true,
1116
+ children: label
1117
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1118
+ "data-passport-signers-list": true,
1119
+ children: signers.map((signer) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1120
+ "data-passport-signer": true,
1121
+ children: signer.label
1122
+ }, signer.id))
1123
+ })]
1124
+ });
1125
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1126
+ ref,
1127
+ ...props,
1128
+ children: children(signers)
1129
+ });
1130
+ });
1131
+ PassportSigners.displayName = "Passport.Signers";
1132
+
1133
+ //#endregion
1134
+ //#region src/ui/core/passport/PassportTitle.tsx
1135
+ /**
1136
+ * Passport.Title - Title for the Passport
1137
+ *
1138
+ * Renders a heading with the passport title. Defaults to "Content Credentials"
1139
+ * if no children are provided.
1140
+ *
1141
+ * @example
1142
+ * ```tsx
1143
+ * // Default title
1144
+ * <Passport.Title className="text-lg font-bold" />
1145
+ *
1146
+ * // Custom title
1147
+ * <Passport.Title className="text-lg font-bold">
1148
+ * My Custom Title
1149
+ * </Passport.Title>
1150
+ *
1151
+ * // With asChild
1152
+ * <Passport.Title asChild>
1153
+ * <h1 className="custom-heading">Content Credentials</h1>
1154
+ * </Passport.Title>
1155
+ * ```
1156
+ */
1157
+ const PassportTitle = (0, react.forwardRef)(({ asChild, children, ...props }, ref) => {
1158
+ const Comp = asChild ? Slot : "h2";
1159
+ const content = children ?? "Content Credentials";
1160
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Comp, {
1161
+ ref,
1162
+ id: "passport-title",
1163
+ ...props,
1164
+ children: content
1165
+ });
1166
+ });
1167
+ PassportTitle.displayName = "Passport.Title";
1168
+
1169
+ //#endregion
1170
+ //#region src/ui/core/passport/index.ts
1171
+ /**
1172
+ * Passport - Headless compound component for displaying C2PA content credentials
1173
+ *
1174
+ * @example
1175
+ * ```tsx
1176
+ * import { Passport } from "@limboai/react";
1177
+ *
1178
+ * <Passport.Root validation={validation} className="my-tooltip">
1179
+ * <Passport.Header className="flex items-center gap-2">
1180
+ * <Passport.Logo className="w-6 h-6" />
1181
+ * <Passport.Title className="text-lg font-bold" />
1182
+ * </Passport.Header>
1183
+ *
1184
+ * <Passport.Field name="issuer" className="my-field" />
1185
+ * <Passport.Field name="date" className="my-field" />
1186
+ *
1187
+ * <Passport.Actions className="mt-4">
1188
+ * {(actions) => actions.map(a => <span key={a} className="tag">{a}</span>)}
1189
+ * </Passport.Actions>
1190
+ *
1191
+ * <Passport.Identities>
1192
+ * {(identities) => identities.map(id => <MyIdentityCard key={id.provider} {...id} />)}
1193
+ * </Passport.Identities>
1194
+ *
1195
+ * <Passport.Signers>
1196
+ * {(signers) => signers.map(s => <MySignerRow key={s.id} {...s} />)}
1197
+ * </Passport.Signers>
1198
+ *
1199
+ * <Passport.Footer className="mt-4 border-t pt-4">
1200
+ * <Passport.CopyButton asChild>
1201
+ * <button className="btn-primary">Copy JSON</button>
1202
+ * </Passport.CopyButton>
1203
+ * </Passport.Footer>
1204
+ * </Passport.Root>
1205
+ * ```
1206
+ */
1207
+ const Passport = {
1208
+ Root: PassportRoot,
1209
+ Header: PassportHeader,
1210
+ Title: PassportTitle,
1211
+ Logo: PassportLogo,
1212
+ Field: PassportField,
1213
+ Actions: PassportActions,
1214
+ Identities: PassportIdentities,
1215
+ Signers: PassportSigners,
1216
+ Footer: PassportFooter,
1217
+ CopyButton: PassportCopyButton
1218
+ };
1219
+
1220
+ //#endregion
1221
+ //#region src/ui/default/constants.ts
1222
+ const BadgePosition = {
1223
+ TopRight: "top-right",
1224
+ TopLeft: "top-left",
1225
+ BottomRight: "bottom-right",
1226
+ BottomLeft: "bottom-left"
1227
+ };
1228
+ const PassportVariant$1 = {
1229
+ Basic: "basic",
1230
+ Full: "full"
1231
+ };
1232
+ const Theme = {
1233
+ Light: "light",
1234
+ Dark: "dark"
1235
+ };
1236
+ const wrapperStyle = {
1237
+ position: "relative",
1238
+ display: "inline-block"
1239
+ };
1240
+
1241
+ //#endregion
1242
+ //#region src/ui/default/LimboBadge.tsx
1243
+ const badgeStyles = {
1244
+ light: {
1245
+ backgroundColor: "#ffffff",
1246
+ borderRadius: "9999px",
1247
+ padding: "8px",
1248
+ boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
1249
+ cursor: "pointer",
1250
+ border: "1px solid #e5e7eb",
1251
+ display: "flex",
1252
+ alignItems: "center",
1253
+ justifyContent: "center"
1254
+ },
1255
+ dark: {
1256
+ backgroundColor: "#1f2937",
1257
+ borderRadius: "9999px",
1258
+ padding: "8px",
1259
+ boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.3), 0 4px 6px -4px rgb(0 0 0 / 0.3)",
1260
+ cursor: "pointer",
1261
+ border: "1px solid #374151",
1262
+ display: "flex",
1263
+ alignItems: "center",
1264
+ justifyContent: "center"
1265
+ }
1266
+ };
1267
+ const badgePositionStyles = {
1268
+ "top-right": {
1269
+ position: "absolute",
1270
+ top: "8px",
1271
+ right: "8px"
1272
+ },
1273
+ "top-left": {
1274
+ position: "absolute",
1275
+ top: "8px",
1276
+ left: "8px"
1277
+ },
1278
+ "bottom-right": {
1279
+ position: "absolute",
1280
+ bottom: "8px",
1281
+ right: "8px"
1282
+ },
1283
+ "bottom-left": {
1284
+ position: "absolute",
1285
+ bottom: "8px",
1286
+ left: "8px"
1287
+ }
1288
+ };
1289
+ /**
1290
+ * LimboBadge - Pre-styled badge component with CRLogo
1291
+ *
1292
+ * A ready-to-use badge for displaying content credentials status.
1293
+ */
1294
+ const LimboBadge = ({ position = BadgePosition.TopRight, theme = Theme.Light, onClick, onMouseEnter, onMouseLeave, style }) => {
1295
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1296
+ type: "button",
1297
+ onClick,
1298
+ onMouseEnter,
1299
+ onMouseLeave,
1300
+ style: {
1301
+ ...badgeStyles[theme],
1302
+ ...badgePositionStyles[position],
1303
+ ...style
1304
+ },
1305
+ "aria-label": "View content credentials",
1306
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CRLogo, { size: 16 })
1307
+ });
1308
+ };
1309
+ LimboBadge.displayName = "LimboBadge";
1310
+
1311
+ //#endregion
1312
+ //#region src/ui/media/hooks/useHeicConversion.ts
1313
+ const isHeic = (src) => /\.(heic|heif)$/i.test(src);
1314
+ async function convertHeicToJpeg(file, signal) {
1315
+ if (typeof window === "undefined") return void 0;
1316
+ const { default: heic2any } = await import("heic2any");
1317
+ if (signal.aborted) return void 0;
1318
+ const res = await heic2any({
1319
+ blob: file,
1320
+ toType: "image/jpeg"
1321
+ });
1322
+ const blob = res instanceof Blob ? res : res[0];
1323
+ if (!blob) throw new Error("HEIC to JPEG conversion failed");
1324
+ return blob;
1325
+ }
1326
+ /**
1327
+ * Hook for automatic HEIC to JPEG conversion
1328
+ *
1329
+ * Uses AbortController for proper cleanup and race condition handling.
1330
+ * Automatically revokes blob URLs on cleanup.
1331
+ *
1332
+ * @example
1333
+ * ```tsx
1334
+ * const { displaySrc, isConverting, error } = useHeicConversion({
1335
+ * src: imageUrl,
1336
+ * enabled: true,
1337
+ * });
1338
+ *
1339
+ * return (
1340
+ * <img
1341
+ * src={displaySrc}
1342
+ * data-converting={isConverting || undefined}
1343
+ * />
1344
+ * );
1345
+ * ```
1346
+ */
1347
+ function useHeicConversion({ src, enabled = true }) {
1348
+ const [displaySrc, setDisplaySrc] = (0, react.useState)(src);
1349
+ const [isConverting, setIsConverting] = (0, react.useState)(false);
1350
+ const [error, setError] = (0, react.useState)(null);
1351
+ (0, react.useEffect)(() => {
1352
+ if (!src || !enabled || !isHeic(src)) {
1353
+ setDisplaySrc(src);
1354
+ setIsConverting(false);
1355
+ setError(null);
1356
+ return;
1357
+ }
1358
+ const controller = new AbortController();
1359
+ const { signal } = controller;
1360
+ let blobUrl = null;
1361
+ setIsConverting(true);
1362
+ setError(null);
1363
+ const convert = async () => {
1364
+ try {
1365
+ const response = await fetch(src, { signal });
1366
+ if (!response.ok) throw new Error(`Fetch failed: ${response.status}`);
1367
+ const blob = await convertHeicToJpeg(await response.blob(), signal);
1368
+ if (signal.aborted || !blob) return;
1369
+ blobUrl = URL.createObjectURL(blob);
1370
+ setDisplaySrc(blobUrl);
1371
+ setIsConverting(false);
1372
+ } catch (e) {
1373
+ if (signal.aborted) return;
1374
+ setError(e instanceof Error ? e.message : "HEIC conversion failed");
1375
+ setDisplaySrc(src);
1376
+ setIsConverting(false);
1377
+ }
1378
+ };
1379
+ convert();
1380
+ return () => {
1381
+ controller.abort();
1382
+ if (blobUrl) URL.revokeObjectURL(blobUrl);
1383
+ };
1384
+ }, [src, enabled]);
1385
+ (0, react.useDebugValue)({
1386
+ isConverting,
1387
+ hasError: !!error
1388
+ });
1389
+ return {
1390
+ displaySrc,
1391
+ isConverting,
1392
+ error
1393
+ };
1394
+ }
1395
+
1396
+ //#endregion
1397
+ //#region src/ui/media/context/MediaContext.tsx
1398
+ const MediaContext = (0, react.createContext)(null);
1399
+ MediaContext.displayName = "MediaContext";
1400
+
1401
+ //#endregion
1402
+ //#region src/ui/media/hooks/useMediaContext.ts
1403
+ /**
1404
+ * Hook to access Media context
1405
+ *
1406
+ * Use this hook inside MediaImage/MediaVideo render props to access
1407
+ * the media context including validation data and overlay visibility state.
1408
+ *
1409
+ * @example
1410
+ * ```tsx
1411
+ * const { validation, status, isVisible, toggle } = useMediaContext();
1412
+ * ```
1413
+ */
1414
+ function useMediaContext() {
1415
+ const context = (0, react.useContext)(MediaContext);
1416
+ if (!context) throw new Error("useMediaContext must be used within a MediaImage or MediaVideo component");
1417
+ (0, react.useDebugValue)({
1418
+ status: context.status,
1419
+ isVisible: context.isVisible
1420
+ });
1421
+ return context;
1422
+ }
1423
+
1424
+ //#endregion
1425
+ //#region src/ui/media/hooks/useMediaOverlay.ts
1426
+ /**
1427
+ * Shared hook for overlay state management in media components
1428
+ *
1429
+ * Extracts common logic used by both MediaImage and MediaVideo components
1430
+ * for managing tooltip visibility and building render props.
1431
+ *
1432
+ * @example
1433
+ * ```tsx
1434
+ * const { hasCredentials, contextValue, badgeProps, tooltipProps } = useMediaOverlay({
1435
+ * validation,
1436
+ * validationStatus,
1437
+ * hideDelay: 300,
1438
+ * });
1439
+ * ```
1440
+ */
1441
+ function useMediaOverlay({ validation, validationStatus, hideDelay = 300 }) {
1442
+ const hasCredentials = validation?.has_credentials ?? false;
1443
+ const { isVisible, show, hide, toggle } = useTooltipVisibility({
1444
+ hasCredentials,
1445
+ hideDelay
1446
+ });
1447
+ const contextValue = {
1448
+ validation,
1449
+ status: validationStatus,
1450
+ hasCredentials,
1451
+ isVisible,
1452
+ show,
1453
+ hide,
1454
+ toggle
1455
+ };
1456
+ const badgeProps = {
1457
+ status: validationStatus,
1458
+ hasCredentials,
1459
+ isVisible,
1460
+ show,
1461
+ hide,
1462
+ toggle
1463
+ };
1464
+ const tooltipProps = validation ? {
1465
+ validation,
1466
+ isVisible,
1467
+ onMouseEnter: show,
1468
+ onClose: hide
1469
+ } : null;
1470
+ (0, react.useDebugValue)({
1471
+ isVisible,
1472
+ hasCredentials
1473
+ });
1474
+ return {
1475
+ hasCredentials,
1476
+ contextValue,
1477
+ badgeProps,
1478
+ tooltipProps
1479
+ };
1480
+ }
1481
+
1482
+ //#endregion
1483
+ //#region src/ui/media/MediaImage.tsx
1484
+ /**
1485
+ * MediaImage - Headless image component with built-in credential overlay support
1486
+ *
1487
+ * A minimal image component that handles HEIC to JPEG conversion and provides
1488
+ * built-in support for displaying credential badges and tooltips via render props.
1489
+ *
1490
+ * This component is headless - it applies no styles. Users must provide
1491
+ * all styling through className, style props, or render functions.
1492
+ *
1493
+ * @example
1494
+ * ```tsx
1495
+ * // Basic usage - just the image with HEIC support
1496
+ * <MediaImage src="/photo.heic" alt="Photo" className="w-full h-auto" />
1497
+ *
1498
+ * // With built-in overlay (using render props)
1499
+ * <MediaImage
1500
+ * src="/photo.jpg"
1501
+ * alt="Photo"
1502
+ * validation={validation}
1503
+ * validationStatus="success"
1504
+ * wrapperClassName="relative inline-block"
1505
+ * className="w-80 h-60 object-cover rounded-lg"
1506
+ * renderBadge={({ status, hasCredentials, toggle }) => (
1507
+ * <button
1508
+ * onClick={toggle}
1509
+ * className="absolute top-2 right-2 bg-green-500 rounded-full p-2"
1510
+ * >
1511
+ * <CRLogo size={16} />
1512
+ * </button>
1513
+ * )}
1514
+ * renderTooltip={({ validation, isVisible, onClose }) =>
1515
+ * isVisible && (
1516
+ * <div className="absolute top-14 right-0 bg-white shadow-lg rounded-lg p-4">
1517
+ * <Passport.Root validation={validation}>
1518
+ * <Passport.Header>...</Passport.Header>
1519
+ * <Passport.Field name="issuer" />
1520
+ * <Passport.Footer>
1521
+ * <Passport.CopyButton />
1522
+ * </Passport.Footer>
1523
+ * </Passport.Root>
1524
+ * </div>
1525
+ * )
1526
+ * }
1527
+ * />
1528
+ *
1529
+ * // With compound components (external overlay)
1530
+ * <div className="relative">
1531
+ * <MediaImage src="/photo.jpg" alt="Photo" className="w-full" />
1532
+ * <CredentialOverlay.Root validation={validation} status="success">
1533
+ * <CredentialOverlay.Trigger className="absolute top-2 right-2">
1534
+ * <CredentialBadge.Root status="success" hasCredentials={true}>
1535
+ * <CredentialBadge.Verified>
1536
+ * <button className="bg-green-500 p-2 rounded-full">OK</button>
1537
+ * </CredentialBadge.Verified>
1538
+ * </CredentialBadge.Root>
1539
+ * </CredentialOverlay.Trigger>
1540
+ * <CredentialOverlay.Content className="absolute top-12 right-0">
1541
+ * <Passport.Root validation={validation}>...</Passport.Root>
1542
+ * </CredentialOverlay.Content>
1543
+ * </CredentialOverlay.Root>
1544
+ * </div>
1545
+ * ```
1546
+ */
1547
+ const MediaImage = (0, react.forwardRef)(({ validation = null, validationStatus = "idle", renderBadge, renderTooltip, wrapperClassName, wrapperStyle, hideDelay = 300, enableHeicConversion = true, src, ...imgProps }, ref) => {
1548
+ const { displaySrc, isConverting } = useHeicConversion({
1549
+ src,
1550
+ enabled: enableHeicConversion
1551
+ });
1552
+ const { contextValue, badgeProps, tooltipProps } = useMediaOverlay({
1553
+ validation,
1554
+ validationStatus,
1555
+ hideDelay
1556
+ });
1557
+ const imageElement = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1558
+ ref,
1559
+ ...imgProps,
1560
+ src: displaySrc,
1561
+ alt: imgProps.alt || "",
1562
+ "data-converting": isConverting || void 0
1563
+ });
1564
+ if (!renderBadge && !renderTooltip) return imageElement;
1565
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaContext.Provider, {
1566
+ value: contextValue,
1567
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1568
+ className: wrapperClassName,
1569
+ style: wrapperStyle,
1570
+ children: [
1571
+ imageElement,
1572
+ renderBadge?.(badgeProps),
1573
+ tooltipProps && renderTooltip?.(tooltipProps)
1574
+ ]
1575
+ })
1576
+ });
1577
+ });
1578
+ MediaImage.displayName = "MediaImage";
1579
+
1580
+ //#endregion
1581
+ //#region src/ui/media/MediaVideo.tsx
1582
+ /**
1583
+ * MediaVideo - Headless video component with built-in credential overlay support
1584
+ *
1585
+ * A minimal video component for use with C2PA credentials. Provides built-in
1586
+ * support for displaying credential badges and tooltips via render props.
1587
+ *
1588
+ * This component is headless - it applies no styles. Users must provide
1589
+ * all styling through className, style props, or render functions.
1590
+ *
1591
+ * @example
1592
+ * ```tsx
1593
+ * // Basic usage - just the video
1594
+ * <MediaVideo src="/video.mp4" controls className="w-full h-auto" />
1595
+ *
1596
+ * // With built-in overlay (using render props)
1597
+ * <MediaVideo
1598
+ * src="/video.mp4"
1599
+ * controls
1600
+ * validation={validation}
1601
+ * validationStatus="success"
1602
+ * wrapperClassName="relative inline-block"
1603
+ * className="w-80 h-60 object-cover rounded-lg"
1604
+ * renderBadge={({ status, hasCredentials, toggle }) => (
1605
+ * <button
1606
+ * onClick={toggle}
1607
+ * className="absolute top-2 right-2 bg-green-500 rounded-full p-2"
1608
+ * >
1609
+ * <CRLogo size={16} />
1610
+ * </button>
1611
+ * )}
1612
+ * renderTooltip={({ validation, isVisible, onClose }) =>
1613
+ * isVisible && (
1614
+ * <div className="absolute top-14 right-0 bg-white shadow-lg rounded-lg p-4">
1615
+ * <Passport.Root validation={validation}>
1616
+ * <Passport.Header>...</Passport.Header>
1617
+ * <Passport.Field name="issuer" />
1618
+ * <Passport.Footer>
1619
+ * <Passport.CopyButton />
1620
+ * </Passport.Footer>
1621
+ * </Passport.Root>
1622
+ * </div>
1623
+ * )
1624
+ * }
1625
+ * />
1626
+ *
1627
+ * // With compound components (external overlay)
1628
+ * <div className="relative">
1629
+ * <MediaVideo src="/video.mp4" controls className="w-full" />
1630
+ * <CredentialOverlay.Root validation={validation} status="success">
1631
+ * <CredentialOverlay.Trigger className="absolute top-2 right-2">
1632
+ * <CredentialBadge.Root status="success" hasCredentials={true}>
1633
+ * <CredentialBadge.Verified>
1634
+ * <button className="bg-green-500 p-2 rounded-full">OK</button>
1635
+ * </CredentialBadge.Verified>
1636
+ * </CredentialBadge.Root>
1637
+ * </CredentialOverlay.Trigger>
1638
+ * <CredentialOverlay.Content className="absolute top-12 right-0">
1639
+ * <Passport.Root validation={validation}>...</Passport.Root>
1640
+ * </CredentialOverlay.Content>
1641
+ * </CredentialOverlay.Root>
1642
+ * </div>
1643
+ * ```
1644
+ */
1645
+ const MediaVideo = (0, react.forwardRef)(({ validation = null, validationStatus = "idle", renderBadge, renderTooltip, wrapperClassName, wrapperStyle, hideDelay = 300, ...videoProps }, ref) => {
1646
+ const { contextValue, badgeProps, tooltipProps } = useMediaOverlay({
1647
+ validation,
1648
+ validationStatus,
1649
+ hideDelay
1650
+ });
1651
+ const videoElement = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("video", {
1652
+ ref,
1653
+ ...videoProps
1654
+ });
1655
+ if (!renderBadge && !renderTooltip) return videoElement;
1656
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaContext.Provider, {
1657
+ value: contextValue,
1658
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1659
+ className: wrapperClassName,
1660
+ style: wrapperStyle,
1661
+ children: [
1662
+ videoElement,
1663
+ renderBadge?.(badgeProps),
1664
+ tooltipProps && renderTooltip?.(tooltipProps)
1665
+ ]
1666
+ })
1667
+ });
1668
+ });
1669
+ MediaVideo.displayName = "MediaVideo";
1670
+
1671
+ //#endregion
1672
+ //#region src/ui/default/LimboPassport.tsx
1673
+ const tooltipPositionStyles = {
1674
+ "top-right": {
1675
+ position: "absolute",
1676
+ top: "56px",
1677
+ right: "0",
1678
+ zIndex: 10
1679
+ },
1680
+ "top-left": {
1681
+ position: "absolute",
1682
+ top: "56px",
1683
+ left: "0",
1684
+ zIndex: 10
1685
+ },
1686
+ "bottom-right": {
1687
+ position: "absolute",
1688
+ bottom: "56px",
1689
+ right: "0",
1690
+ zIndex: 10
1691
+ },
1692
+ "bottom-left": {
1693
+ position: "absolute",
1694
+ bottom: "56px",
1695
+ left: "0",
1696
+ zIndex: 10
1697
+ }
1698
+ };
1699
+ const passportContainerStyles = {
1700
+ light: {
1701
+ backgroundColor: "#ffffff",
1702
+ border: "1px solid #e5e7eb",
1703
+ borderRadius: "12px",
1704
+ padding: "20px",
1705
+ width: "320px",
1706
+ boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
1707
+ fontFamily: "system-ui, -apple-system, sans-serif"
1708
+ },
1709
+ dark: {
1710
+ backgroundColor: "#111827",
1711
+ border: "1px solid #374151",
1712
+ borderRadius: "12px",
1713
+ padding: "20px",
1714
+ width: "320px",
1715
+ boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.3), 0 4px 6px -4px rgb(0 0 0 / 0.3)",
1716
+ fontFamily: "system-ui, -apple-system, sans-serif"
1717
+ }
1718
+ };
1719
+ const fieldLabelStyles = {
1720
+ light: {
1721
+ fontSize: "11px",
1722
+ fontWeight: 500,
1723
+ color: "#6b7280",
1724
+ textTransform: "uppercase",
1725
+ letterSpacing: "0.05em",
1726
+ marginBottom: "4px"
1727
+ },
1728
+ dark: {
1729
+ fontSize: "11px",
1730
+ fontWeight: 500,
1731
+ color: "#9ca3af",
1732
+ textTransform: "uppercase",
1733
+ letterSpacing: "0.05em",
1734
+ marginBottom: "4px"
1735
+ }
1736
+ };
1737
+ const fieldValueStyles = {
1738
+ light: {
1739
+ fontSize: "13px",
1740
+ color: "#111827"
1741
+ },
1742
+ dark: {
1743
+ fontSize: "13px",
1744
+ color: "#f3f4f6"
1745
+ }
1746
+ };
1747
+ const passportHeaderStyles = {
1748
+ container: {
1749
+ display: "flex",
1750
+ alignItems: "center",
1751
+ gap: "8px",
1752
+ marginBottom: "16px"
1753
+ },
1754
+ logo: {
1755
+ width: "20px",
1756
+ height: "20px"
1757
+ },
1758
+ title: {
1759
+ light: {
1760
+ fontSize: "16px",
1761
+ fontWeight: 600,
1762
+ color: "#111827"
1763
+ },
1764
+ dark: {
1765
+ fontSize: "16px",
1766
+ fontWeight: 600,
1767
+ color: "#ffffff"
1768
+ }
1769
+ }
1770
+ };
1771
+ const passportFooterStyles = {
1772
+ container: {
1773
+ light: {
1774
+ marginTop: "16px",
1775
+ paddingTop: "16px",
1776
+ borderTop: "1px solid #f3f4f6",
1777
+ display: "flex",
1778
+ justifyContent: "space-between",
1779
+ alignItems: "center"
1780
+ },
1781
+ dark: {
1782
+ marginTop: "16px",
1783
+ paddingTop: "16px",
1784
+ borderTop: "1px solid #374151",
1785
+ display: "flex",
1786
+ justifyContent: "space-between",
1787
+ alignItems: "center"
1788
+ }
1789
+ },
1790
+ copyButton: {
1791
+ light: {
1792
+ display: "inline-flex",
1793
+ alignItems: "center",
1794
+ gap: "6px",
1795
+ fontSize: "13px",
1796
+ fontWeight: 500,
1797
+ color: "#4b5563",
1798
+ cursor: "pointer",
1799
+ backgroundColor: "transparent",
1800
+ border: "none",
1801
+ padding: 0
1802
+ },
1803
+ dark: {
1804
+ display: "inline-flex",
1805
+ alignItems: "center",
1806
+ gap: "6px",
1807
+ fontSize: "13px",
1808
+ fontWeight: 500,
1809
+ color: "#9ca3af",
1810
+ cursor: "pointer",
1811
+ backgroundColor: "transparent",
1812
+ border: "none",
1813
+ padding: 0
1814
+ }
1815
+ },
1816
+ closeButton: {
1817
+ light: {
1818
+ fontSize: "13px",
1819
+ color: "#9ca3af",
1820
+ backgroundColor: "transparent",
1821
+ border: "none",
1822
+ cursor: "pointer"
1823
+ },
1824
+ dark: {
1825
+ fontSize: "13px",
1826
+ color: "#6b7280",
1827
+ backgroundColor: "transparent",
1828
+ border: "none",
1829
+ cursor: "pointer"
1830
+ }
1831
+ }
1832
+ };
1833
+ const fieldContainerStyle = { marginBottom: "12px" };
1834
+ const identityStyles = {
1835
+ container: {
1836
+ display: "flex",
1837
+ flexDirection: "column",
1838
+ gap: "6px"
1839
+ },
1840
+ item: {
1841
+ display: "flex",
1842
+ alignItems: "center",
1843
+ gap: "8px"
1844
+ },
1845
+ link: {
1846
+ color: "#3b82f6",
1847
+ textDecoration: "none"
1848
+ }
1849
+ };
1850
+ const signerStyles = { container: {
1851
+ display: "flex",
1852
+ flexDirection: "column",
1853
+ gap: "4px"
1854
+ } };
1855
+ const actionTagStyles = {
1856
+ light: {
1857
+ backgroundColor: "#f3f4f6",
1858
+ color: "#374151",
1859
+ fontSize: "12px",
1860
+ padding: "2px 8px",
1861
+ borderRadius: "4px"
1862
+ },
1863
+ dark: {
1864
+ backgroundColor: "#374151",
1865
+ color: "#d1d5db",
1866
+ fontSize: "12px",
1867
+ padding: "2px 8px",
1868
+ borderRadius: "4px"
1869
+ }
1870
+ };
1871
+ const actionsContainerStyle = {
1872
+ display: "flex",
1873
+ flexWrap: "wrap",
1874
+ gap: "6px"
1875
+ };
1876
+ /**
1877
+ * LimboPassport - Pre-styled passport tooltip component
1878
+ *
1879
+ * Renders a passport with configurable variant (basic or full).
1880
+ */
1881
+ const LimboPassport = ({ validation, isVisible, theme = Theme.Light, position = BadgePosition.TopRight, variant = PassportVariant$1.Basic, showDate = true, onMouseEnter, onClose, style }) => {
1882
+ if (!isVisible) return null;
1883
+ const containerStyle = {
1884
+ ...tooltipPositionStyles[position],
1885
+ ...style
1886
+ };
1887
+ const isFull = variant === PassportVariant$1.Full;
1888
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1889
+ role: "tooltip",
1890
+ style: containerStyle,
1891
+ onMouseEnter,
1892
+ onMouseLeave: onClose,
1893
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Passport.Root, {
1894
+ validation,
1895
+ style: passportContainerStyles[theme],
1896
+ children: [
1897
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Passport.Header, {
1898
+ style: passportHeaderStyles.container,
1899
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Logo, { style: passportHeaderStyles.logo }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Title, { style: passportHeaderStyles.title[theme] })]
1900
+ }),
1901
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Field, {
1902
+ name: "issuer",
1903
+ style: fieldContainerStyle,
1904
+ children: ({ label, value }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1905
+ style: fieldLabelStyles[theme],
1906
+ children: label
1907
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1908
+ style: fieldValueStyles[theme],
1909
+ children: value
1910
+ })] })
1911
+ }),
1912
+ showDate && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Field, {
1913
+ name: "date",
1914
+ style: fieldContainerStyle,
1915
+ children: ({ label, value }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1916
+ style: fieldLabelStyles[theme],
1917
+ children: label
1918
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1919
+ style: fieldValueStyles[theme],
1920
+ children: value
1921
+ })] })
1922
+ }),
1923
+ isFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Identities, {
1924
+ style: fieldContainerStyle,
1925
+ children: (identities) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1926
+ style: fieldLabelStyles[theme],
1927
+ children: identities.length === 1 ? "Verified Identity" : `Verified Identities (${identities.length})`
1928
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1929
+ style: identityStyles.container,
1930
+ children: identities.map((identity) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1931
+ style: identityStyles.item,
1932
+ children: [identity.provider.toLowerCase().includes("linkedin") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LinkedInIcon, { size: 16 }), identity.uri ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1933
+ href: identity.uri,
1934
+ target: "_blank",
1935
+ rel: "noopener noreferrer",
1936
+ style: {
1937
+ ...fieldValueStyles[theme],
1938
+ ...identityStyles.link
1939
+ },
1940
+ children: identity.username
1941
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1942
+ style: fieldValueStyles[theme],
1943
+ children: identity.username
1944
+ })]
1945
+ }, identity.provider))
1946
+ })] })
1947
+ }),
1948
+ isFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Signers, {
1949
+ style: fieldContainerStyle,
1950
+ children: (signers) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1951
+ style: fieldLabelStyles[theme],
1952
+ children: signers.length === 1 ? "Previous Signer" : `Previous Signers (${signers.length})`
1953
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1954
+ style: signerStyles.container,
1955
+ children: signers.map((signer) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1956
+ style: fieldValueStyles[theme],
1957
+ children: signer.label
1958
+ }, signer.id))
1959
+ })] })
1960
+ }),
1961
+ isFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.Actions, {
1962
+ style: fieldContainerStyle,
1963
+ children: (actions) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1964
+ style: fieldLabelStyles[theme],
1965
+ children: "Actions"
1966
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1967
+ style: actionsContainerStyle,
1968
+ children: actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1969
+ style: actionTagStyles[theme],
1970
+ children: action
1971
+ }, action))
1972
+ })] })
1973
+ }),
1974
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Passport.Footer, {
1975
+ style: passportFooterStyles.container[theme],
1976
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Passport.CopyButton, { style: passportFooterStyles.copyButton[theme] }), isFull && onClose && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1977
+ type: "button",
1978
+ onClick: onClose,
1979
+ style: passportFooterStyles.closeButton[theme],
1980
+ children: "Close"
1981
+ })]
1982
+ })
1983
+ ]
1984
+ })
1985
+ });
1986
+ };
1987
+ LimboPassport.displayName = "LimboPassport";
1988
+
1989
+ //#endregion
1990
+ //#region src/ui/default/LimboImage.tsx
1991
+ /**
1992
+ * LimboImage - Pre-styled image component with default badge and passport
1993
+ *
1994
+ * A ready-to-use image component that displays content credentials with
1995
+ * a pre-configured badge and passport tooltip.
1996
+ *
1997
+ * @example
1998
+ * ```tsx
1999
+ * // Basic usage with click interaction
2000
+ * <LimboImage
2001
+ * src="/photo.jpg"
2002
+ * alt="Photo"
2003
+ * validation={validation}
2004
+ * validationStatus="success"
2005
+ * />
2006
+ *
2007
+ * // With hover interaction and dark theme
2008
+ * <LimboImage
2009
+ * src="/photo.jpg"
2010
+ * alt="Photo"
2011
+ * validation={validation}
2012
+ * validationStatus="success"
2013
+ * interactionMode="hover"
2014
+ * theme="dark"
2015
+ * badgePosition="bottomRight"
2016
+ * />
2017
+ *
2018
+ * // Full passport variant
2019
+ * <LimboImage
2020
+ * src="/photo.jpg"
2021
+ * alt="Photo"
2022
+ * validation={validation}
2023
+ * validationStatus="success"
2024
+ * passportVariant="full"
2025
+ * />
2026
+ * ```
2027
+ */
2028
+ const LimboImage = (0, react.forwardRef)(({ validation = null, validationStatus = "idle", badgePosition = BadgePosition.TopRight, theme = Theme.Light, passportVariant = PassportVariant$1.Basic, interactionMode = "click", showDate = true, hideDelay = 300, enableHeicConversion = true, wrapperStyle: customWrapperStyle, ...imgProps }, ref) => {
2029
+ const combinedWrapperStyle = {
2030
+ ...wrapperStyle,
2031
+ ...customWrapperStyle
2032
+ };
2033
+ const renderBadge = ({ hasCredentials, toggle, show, hide }) => {
2034
+ if (!hasCredentials) return null;
2035
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimboBadge, {
2036
+ position: badgePosition,
2037
+ theme,
2038
+ ...interactionMode === "hover" ? {
2039
+ onMouseEnter: show,
2040
+ onMouseLeave: hide
2041
+ } : { onClick: toggle }
2042
+ });
2043
+ };
2044
+ const renderTooltip = ({ validation: tooltipValidation, isVisible, onMouseEnter, onClose }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimboPassport, {
2045
+ validation: tooltipValidation,
2046
+ isVisible,
2047
+ theme,
2048
+ position: badgePosition,
2049
+ variant: passportVariant,
2050
+ showDate,
2051
+ onMouseEnter: interactionMode === "hover" ? onMouseEnter : void 0,
2052
+ onClose
2053
+ });
2054
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaImage, {
2055
+ ref,
2056
+ ...imgProps,
2057
+ validation,
2058
+ validationStatus,
2059
+ hideDelay,
2060
+ enableHeicConversion,
2061
+ wrapperStyle: combinedWrapperStyle,
2062
+ renderBadge,
2063
+ renderTooltip
2064
+ });
2065
+ });
2066
+ LimboImage.displayName = "LimboImage";
2067
+
2068
+ //#endregion
2069
+ //#region src/ui/default/LimboVideo.tsx
2070
+ /**
2071
+ * LimboVideo - Pre-styled video component with default badge and passport
2072
+ *
2073
+ * A ready-to-use video component that displays content credentials with
2074
+ * a pre-configured badge and passport tooltip.
2075
+ *
2076
+ * @example
2077
+ * ```tsx
2078
+ * // Basic usage with click interaction
2079
+ * <LimboVideo
2080
+ * src="/video.mp4"
2081
+ * controls
2082
+ * validation={validation}
2083
+ * validationStatus="success"
2084
+ * />
2085
+ *
2086
+ * // With hover interaction and dark theme
2087
+ * <LimboVideo
2088
+ * src="/video.mp4"
2089
+ * controls
2090
+ * validation={validation}
2091
+ * validationStatus="success"
2092
+ * interactionMode="hover"
2093
+ * theme="dark"
2094
+ * badgePosition="bottomRight"
2095
+ * />
2096
+ *
2097
+ * // Full passport variant
2098
+ * <LimboVideo
2099
+ * src="/video.mp4"
2100
+ * controls
2101
+ * validation={validation}
2102
+ * validationStatus="success"
2103
+ * passportVariant="full"
2104
+ * />
2105
+ * ```
2106
+ */
2107
+ const LimboVideo = (0, react.forwardRef)(({ validation = null, validationStatus = "idle", badgePosition = BadgePosition.TopRight, theme = Theme.Light, passportVariant = PassportVariant$1.Basic, interactionMode = "click", showDate = true, hideDelay = 300, wrapperStyle: customWrapperStyle, ...videoProps }, ref) => {
2108
+ const combinedWrapperStyle = {
2109
+ ...wrapperStyle,
2110
+ ...customWrapperStyle
2111
+ };
2112
+ const renderBadge = ({ hasCredentials, toggle, show, hide }) => {
2113
+ if (!hasCredentials) return null;
2114
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimboBadge, {
2115
+ position: badgePosition,
2116
+ theme,
2117
+ ...interactionMode === "hover" ? {
2118
+ onMouseEnter: show,
2119
+ onMouseLeave: hide
2120
+ } : { onClick: toggle }
2121
+ });
2122
+ };
2123
+ const renderTooltip = ({ validation: tooltipValidation, isVisible, onMouseEnter, onClose }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimboPassport, {
2124
+ validation: tooltipValidation,
2125
+ isVisible,
2126
+ theme,
2127
+ position: badgePosition,
2128
+ variant: passportVariant,
2129
+ showDate,
2130
+ onMouseEnter: interactionMode === "hover" ? onMouseEnter : void 0,
2131
+ onClose
2132
+ });
2133
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaVideo, {
2134
+ ref,
2135
+ ...videoProps,
2136
+ validation,
2137
+ validationStatus,
2138
+ hideDelay,
2139
+ wrapperStyle: combinedWrapperStyle,
2140
+ renderBadge,
2141
+ renderTooltip
2142
+ });
2143
+ });
2144
+ LimboVideo.displayName = "LimboVideo";
2145
+
2146
+ //#endregion
2147
+ exports.BadgePosition = BadgePosition;
2148
+ exports.CRLogo = CRLogo;
2149
+ exports.CredentialBadge = CredentialBadge;
2150
+ exports.CredentialOverlay = CredentialOverlay;
2151
+ exports.LimboBadge = LimboBadge;
2152
+ exports.LimboImage = LimboImage;
2153
+ exports.LimboPassport = LimboPassport;
2154
+ exports.LimboVideo = LimboVideo;
2155
+ exports.LinkedInIcon = LinkedInIcon;
2156
+ exports.MediaImage = MediaImage;
2157
+ exports.MediaVideo = MediaVideo;
2158
+ exports.Passport = Passport;
2159
+ exports.PassportVariant = PassportVariant;
2160
+ exports.Theme = Theme;
2161
+ exports.ValidationStatus = ValidationStatus;
2162
+ exports.useCredentialBadgeContext = useCredentialBadgeContext;
2163
+ exports.useCredentialOverlayContext = useCredentialOverlayContext;
2164
+ exports.useHeicConversion = useHeicConversion;
2165
+ exports.useMediaContext = useMediaContext;
2166
+ exports.usePassportContext = usePassportContext;
2167
+ exports.usePassportData = usePassportData;
2168
+ exports.useTooltipVisibility = useTooltipVisibility;
2169
+ //# sourceMappingURL=index.cjs.map