@fluid-app/portal-sdk 0.1.368 → 0.1.370

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 (64) hide show
  1. package/dist/{CalendarWidget-CkuTpX1q.mjs → CalendarWidget--EIsxRov.mjs} +20 -4
  2. package/dist/CalendarWidget--EIsxRov.mjs.map +1 -0
  3. package/dist/{CalendarWidget-DEqx8mjm.cjs → CalendarWidget-M1_WyHA_.cjs} +19 -3
  4. package/dist/CalendarWidget-M1_WyHA_.cjs.map +1 -0
  5. package/dist/{EmbedWidget-B18Qzd0T.cjs → EmbedWidget-CFqodi8C.cjs} +2 -1
  6. package/dist/{EmbedWidget-CoZgo8aI.cjs → EmbedWidget-D1lbYjuL.cjs} +300 -3
  7. package/dist/EmbedWidget-D1lbYjuL.cjs.map +1 -0
  8. package/dist/{EmbedWidget-BJY7l4pI.mjs → EmbedWidget-p_Ybl0em.mjs} +300 -3
  9. package/dist/EmbedWidget-p_Ybl0em.mjs.map +1 -0
  10. package/dist/{FluidProvider-YssKGmXj.mjs → FluidProvider-Bmmdax4d.mjs} +5 -5
  11. package/dist/{FluidProvider-YssKGmXj.mjs.map → FluidProvider-Bmmdax4d.mjs.map} +1 -1
  12. package/dist/{FluidProvider-CXqHtKMw.cjs → FluidProvider-DG7duKf4.cjs} +5 -5
  13. package/dist/{FluidProvider-CXqHtKMw.cjs.map → FluidProvider-DG7duKf4.cjs.map} +1 -1
  14. package/dist/{MessagingScreen-BYDYBjwV.cjs → MessagingScreen-BIJU7dWT.cjs} +4 -4
  15. package/dist/{MessagingScreen-DdFiAFdf.mjs → MessagingScreen-BY8IowR0.mjs} +4 -4
  16. package/dist/{MessagingScreen-DImdW2jI.mjs → MessagingScreen-CyxUDdcb.mjs} +2 -2
  17. package/dist/{MessagingScreen-DImdW2jI.mjs.map → MessagingScreen-CyxUDdcb.mjs.map} +1 -1
  18. package/dist/{MessagingScreen-CJBAdOPp.cjs → MessagingScreen-ylXd2Um7.cjs} +2 -2
  19. package/dist/{MessagingScreen-CJBAdOPp.cjs.map → MessagingScreen-ylXd2Um7.cjs.map} +1 -1
  20. package/dist/{OrdersScreen-DSLwMt-8.cjs → OrdersScreen-1b2ZzMEg.cjs} +4 -4
  21. package/dist/{OrdersScreen-DunUiDwt.cjs → OrdersScreen-B-biRUNQ.cjs} +2 -2
  22. package/dist/{OrdersScreen-DunUiDwt.cjs.map → OrdersScreen-B-biRUNQ.cjs.map} +1 -1
  23. package/dist/{OrdersScreen-B0jx8cnV.mjs → OrdersScreen-BVRpsxMF.mjs} +4 -4
  24. package/dist/{OrdersScreen-DyQOtPM9.mjs → OrdersScreen-DsTMrxlo.mjs} +2 -2
  25. package/dist/{OrdersScreen-DyQOtPM9.mjs.map → OrdersScreen-DsTMrxlo.mjs.map} +1 -1
  26. package/dist/{ProfileScreen-BG7J9E1o.cjs → ProfileScreen-DYe6Msda.cjs} +3 -3
  27. package/dist/{ProfileScreen-BG7J9E1o.cjs.map → ProfileScreen-DYe6Msda.cjs.map} +1 -1
  28. package/dist/{ProfileScreen-CpHWYc0b.cjs → ProfileScreen-Dsbr8wip.cjs} +5 -5
  29. package/dist/{ProfileScreen-6zq3b24t.mjs → ProfileScreen-DvnWtXlF.mjs} +3 -3
  30. package/dist/{ProfileScreen-6zq3b24t.mjs.map → ProfileScreen-DvnWtXlF.mjs.map} +1 -1
  31. package/dist/{ProfileScreen-CQRzoZA5.mjs → ProfileScreen-DzgGP3lr.mjs} +5 -5
  32. package/dist/{ShopScreen-BdE_Wx1n.mjs → ShopScreen-Cy5cf6tn.mjs} +4 -4
  33. package/dist/{ShopScreen-Dh4amrNp.mjs → ShopScreen-DVYzIHJA.mjs} +2 -2
  34. package/dist/{ShopScreen-Dh4amrNp.mjs.map → ShopScreen-DVYzIHJA.mjs.map} +1 -1
  35. package/dist/{ShopScreen-DAsoH_nU.cjs → ShopScreen-DcgyX3Wk.cjs} +2 -2
  36. package/dist/{ShopScreen-DAsoH_nU.cjs.map → ShopScreen-DcgyX3Wk.cjs.map} +1 -1
  37. package/dist/{ShopScreen-CrITAsuX.cjs → ShopScreen-nUFdeac6.cjs} +4 -4
  38. package/dist/{SubscriptionsScreen-D0QQAQAn.mjs → SubscriptionsScreen-BnRWR4Df.mjs} +5 -5
  39. package/dist/{SubscriptionsScreen-fHeWecM6.cjs → SubscriptionsScreen-Day2TSrY.cjs} +5 -5
  40. package/dist/{SubscriptionsScreen-B0Aup6Pw.mjs → SubscriptionsScreen-DqG_qHS_.mjs} +3 -3
  41. package/dist/{SubscriptionsScreen-B0Aup6Pw.mjs.map → SubscriptionsScreen-DqG_qHS_.mjs.map} +1 -1
  42. package/dist/{SubscriptionsScreen-CxYdU6Sr.cjs → SubscriptionsScreen-Dw68LWDh.cjs} +3 -3
  43. package/dist/{SubscriptionsScreen-CxYdU6Sr.cjs.map → SubscriptionsScreen-Dw68LWDh.cjs.map} +1 -1
  44. package/dist/index.cjs +20 -20
  45. package/dist/index.d.cts +20 -0
  46. package/dist/index.d.cts.map +1 -1
  47. package/dist/index.d.mts +20 -0
  48. package/dist/index.d.mts.map +1 -1
  49. package/dist/index.mjs +20 -20
  50. package/dist/preview/preview-entry.cjs +4 -4
  51. package/dist/preview/preview-entry.mjs +4 -4
  52. package/dist/{use-portal-card-add-3ds-flow-B-HZhV7O.mjs → use-portal-card-add-3ds-flow-FSWDlXtP.mjs} +2 -2
  53. package/dist/{use-portal-card-add-3ds-flow-B-HZhV7O.mjs.map → use-portal-card-add-3ds-flow-FSWDlXtP.mjs.map} +1 -1
  54. package/dist/{use-portal-card-add-3ds-flow-Bu-6T-WF.cjs → use-portal-card-add-3ds-flow-hGLvDBZT.cjs} +2 -2
  55. package/dist/{use-portal-card-add-3ds-flow-Bu-6T-WF.cjs.map → use-portal-card-add-3ds-flow-hGLvDBZT.cjs.map} +1 -1
  56. package/dist/{widget-package-utils-04GgcH5M.cjs → widget-package-utils-BGu5fWAU.cjs} +2 -2
  57. package/dist/{widget-package-utils-04GgcH5M.cjs.map → widget-package-utils-BGu5fWAU.cjs.map} +1 -1
  58. package/dist/{widget-package-utils-08fEY11c.mjs → widget-package-utils-DzdFCK04.mjs} +2 -2
  59. package/dist/{widget-package-utils-08fEY11c.mjs.map → widget-package-utils-DzdFCK04.mjs.map} +1 -1
  60. package/package.json +14 -14
  61. package/dist/CalendarWidget-CkuTpX1q.mjs.map +0 -1
  62. package/dist/CalendarWidget-DEqx8mjm.cjs.map +0 -1
  63. package/dist/EmbedWidget-BJY7l4pI.mjs.map +0 -1
  64. package/dist/EmbedWidget-CoZgo8aI.cjs.map +0 -1
@@ -1,4 +1,5 @@
1
1
  import { ut as __exportAll } from "./use-account-D70N5avv.mjs";
2
+ import { i as useOptionalStore } from "./use-optional-store-BPICvfcP.mjs";
2
3
  import { n as useRepUser } from "./RepUserContext-D1G5lEuo.mjs";
3
4
  import { t as useWidgetRenderState } from "./WidgetRenderStateContext-Deuk22Oj.mjs";
4
5
  import { r as useShellTranslation } from "./shell-translation-api-context-SVRZkj2i.mjs";
@@ -7,6 +8,219 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
7
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
9
  import { Bell, BookOpen, BookmarkIcon, Calendar, ExternalLink, Gift, Globe, GraduationCap, Heart, Maximize2, RotateCw, ShoppingBag, Sparkles, Star, Trophy, User, Video, X, Zap } from "lucide-react";
9
10
  import { createPortal } from "react-dom";
11
+ //#region ../../platform/app-bridge/src/errors.ts
12
+ var FluidBridgeError = class extends Error {
13
+ code;
14
+ details;
15
+ constructor(code, message, details) {
16
+ super(message);
17
+ this.name = "FluidBridgeError";
18
+ this.code = code;
19
+ this.details = details;
20
+ }
21
+ };
22
+ var FluidBridgeIncompatibleVersionError = class extends FluidBridgeError {
23
+ constructor(message = "Fluid App Bridge SDK is not compatible with the host", details) {
24
+ super("incompatible_version", message, details);
25
+ this.name = "FluidBridgeIncompatibleVersionError";
26
+ }
27
+ };
28
+ var FluidBridgeTokenMintError = class extends FluidBridgeError {
29
+ constructor(message = "Fluid App Bridge host could not mint a session token", details) {
30
+ super("token_mint_failed", message, details);
31
+ this.name = "FluidBridgeTokenMintError";
32
+ }
33
+ };
34
+ var FluidBridgeUnauthorizedError = class extends FluidBridgeError {
35
+ constructor(message = "Fluid App Bridge request is unauthorized", details) {
36
+ super("unauthorized", message, details);
37
+ this.name = "FluidBridgeUnauthorizedError";
38
+ }
39
+ };
40
+ var FluidBridgeForbiddenOriginError = class extends FluidBridgeError {
41
+ constructor(message = "Fluid App Bridge host origin is forbidden", details) {
42
+ super("forbidden_origin", message, details);
43
+ this.name = "FluidBridgeForbiddenOriginError";
44
+ }
45
+ };
46
+ var FluidBridgeInvalidContextError = class extends FluidBridgeError {
47
+ constructor(message = "Fluid App Bridge context is invalid", details) {
48
+ super("invalid_context", message, details);
49
+ this.name = "FluidBridgeInvalidContextError";
50
+ }
51
+ };
52
+ var FluidBridgeFailedAuthenticationError = class extends FluidBridgeError {
53
+ constructor(message = "Fluid App Bridge authentication failed", details) {
54
+ super("failed_authentication", message, details);
55
+ this.name = "FluidBridgeFailedAuthenticationError";
56
+ }
57
+ };
58
+ //#endregion
59
+ //#region ../../platform/app-bridge/src/protocol.ts
60
+ const FLUID_BRIDGE_PROTOCOL_VERSION = "2026-07";
61
+ const APP_BRIDGE_SDK_NAME = "@fluid-commerce/app-bridge";
62
+ const APP_BRIDGE_SDK_VERSION = "0.1.0";
63
+ const FluidBridgeMessageType = {
64
+ SessionTokenRequest: "FLUID::SESSION_TOKEN_REQUEST",
65
+ SessionTokenRespond: "FLUID::SESSION_TOKEN_RESPOND",
66
+ ContextRequest: "FLUID::CONTEXT_REQUEST",
67
+ ContextRespond: "FLUID::CONTEXT_RESPOND",
68
+ FailedAuthentication: "FLUID::ERROR::FAILED_AUTHENTICATION",
69
+ Unauthorized: "FLUID::ERROR::UNAUTHORIZED",
70
+ IncompatibleVersion: "FLUID::ERROR::INCOMPATIBLE_VERSION",
71
+ TokenMintFailed: "FLUID::ERROR::TOKEN_MINT_FAILED",
72
+ InvalidContext: "FLUID::ERROR::INVALID_CONTEXT"
73
+ };
74
+ //#endregion
75
+ //#region ../../platform/app-bridge/src/host.ts
76
+ function createFluidBridgeHost(options) {
77
+ const targetWindow = options.targetWindow ?? window;
78
+ const appOrigin = normalizeOrigin(options.appOrigin);
79
+ const handleMessage = (event) => {
80
+ if (event.origin !== appOrigin) return;
81
+ if (event.source !== options.iframe.contentWindow) return;
82
+ if (!isBridgeEnvelope(event.data)) return;
83
+ respondToBridgeMessage(options, event.data, appOrigin);
84
+ };
85
+ targetWindow.addEventListener("message", handleMessage);
86
+ return { destroy: () => targetWindow.removeEventListener("message", handleMessage) };
87
+ }
88
+ async function respondToBridgeMessage(options, envelope, appOrigin) {
89
+ const childWindow = options.iframe.contentWindow;
90
+ if (!childWindow) return;
91
+ try {
92
+ validateRequestPayload(envelope.payload, options.clientId);
93
+ switch (envelope.type) {
94
+ case FluidBridgeMessageType.ContextRequest: {
95
+ const context = await options.getContext();
96
+ childWindow.postMessage({
97
+ id: envelope.id,
98
+ type: FluidBridgeMessageType.ContextRespond,
99
+ payload: context
100
+ }, appOrigin);
101
+ return;
102
+ }
103
+ case FluidBridgeMessageType.SessionTokenRequest: {
104
+ const context = await options.getContext();
105
+ const sessionToken = await options.getSessionToken(context);
106
+ if (sessionToken.length === 0) throw new FluidBridgeTokenMintError("Fluid App Bridge host returned an empty session token");
107
+ childWindow.postMessage({
108
+ id: envelope.id,
109
+ type: FluidBridgeMessageType.SessionTokenRespond,
110
+ payload: { sessionToken }
111
+ }, appOrigin);
112
+ return;
113
+ }
114
+ default: throw new FluidBridgeForbiddenOriginError("Fluid App Bridge host received an unsupported message type", { type: envelope.type });
115
+ }
116
+ } catch (error) {
117
+ childWindow.postMessage({
118
+ id: envelope.id,
119
+ type: errorTypeFor(error),
120
+ payload: errorPayloadFor(error)
121
+ }, appOrigin);
122
+ }
123
+ }
124
+ function validateRequestPayload(value, clientId) {
125
+ if (typeof value !== "object" || value === null) throw new FluidBridgeInvalidContextError("Fluid App Bridge request payload is invalid");
126
+ if (!("clientId" in value) || value.clientId !== clientId) throw new FluidBridgeFailedAuthenticationError("Fluid App Bridge request client ID does not match the host context");
127
+ if (!("protocol" in value) || value.protocol !== "2026-07") throw new FluidBridgeIncompatibleVersionError();
128
+ return value;
129
+ }
130
+ function isBridgeEnvelope(value) {
131
+ if (typeof value !== "object" || value === null) return false;
132
+ return "id" in value && "type" in value && "payload" in value && typeof value.id === "string" && typeof value.type === "string";
133
+ }
134
+ function errorTypeFor(error) {
135
+ if (error instanceof FluidBridgeFailedAuthenticationError) return FluidBridgeMessageType.FailedAuthentication;
136
+ if (error instanceof FluidBridgeIncompatibleVersionError) return FluidBridgeMessageType.IncompatibleVersion;
137
+ if (error instanceof FluidBridgeUnauthorizedError) return FluidBridgeMessageType.Unauthorized;
138
+ if (error instanceof FluidBridgeTokenMintError) return FluidBridgeMessageType.TokenMintFailed;
139
+ if (error instanceof FluidBridgeInvalidContextError) return FluidBridgeMessageType.InvalidContext;
140
+ if (error instanceof FluidBridgeForbiddenOriginError) return FluidBridgeMessageType.InvalidContext;
141
+ return FluidBridgeMessageType.TokenMintFailed;
142
+ }
143
+ function errorPayloadFor(error) {
144
+ if (error instanceof Error && "code" in error && typeof error.code === "string") return {
145
+ code: error.code,
146
+ message: error.message,
147
+ details: "details" in error ? error.details : void 0
148
+ };
149
+ return {
150
+ code: "token_mint_failed",
151
+ message: "Fluid App Bridge host could not complete the request",
152
+ details: error
153
+ };
154
+ }
155
+ function normalizeOrigin(origin) {
156
+ return new URL(origin).origin;
157
+ }
158
+ //#endregion
159
+ //#region ../../platform/app-bridge/src/session-token-api.ts
160
+ const DEFAULT_SESSION_TOKEN_PATH = "api/v2025-06/app_bridge/session_token";
161
+ async function mintAppBridgeSessionToken({ request, apiBaseUrl, authToken, fetch: fetchImplementation = globalThis.fetch?.bind(globalThis) }) {
162
+ if (!fetchImplementation) throw new FluidBridgeTokenMintError("Fluid App Bridge host requires a fetch implementation to mint session tokens");
163
+ const response = await fetchImplementation(resolveSessionTokenUrl(apiBaseUrl), {
164
+ method: "POST",
165
+ headers: sessionTokenHeaders(authToken),
166
+ body: JSON.stringify(sessionTokenRequestBody(request))
167
+ });
168
+ const body = await response.json().catch(() => null);
169
+ if (!response.ok) throw errorForTokenResponse(response.status, body);
170
+ if (!isSessionTokenSuccessResponse(body) || body.session_token.length === 0) throw new FluidBridgeTokenMintError("Fluid App Bridge backend returned an invalid session token response", { body });
171
+ return body.session_token;
172
+ }
173
+ function sessionTokenRequestFromContext(context, sessionId) {
174
+ return {
175
+ clientId: context.app.clientId,
176
+ entry: context.entry,
177
+ resources: context.resources,
178
+ allowedOrigins: context.fetch.allowedOrigins,
179
+ ...sessionId ? { sessionId } : {}
180
+ };
181
+ }
182
+ function sessionTokenHeaders(authToken) {
183
+ const headers = new Headers({
184
+ "Content-Type": "application/json",
185
+ "X-Fluid-App-Bridge-Protocol": FLUID_BRIDGE_PROTOCOL_VERSION,
186
+ "X-Fluid-App-Bridge-Version": APP_BRIDGE_SDK_VERSION,
187
+ "X-Fluid-App-Bridge-Sdk": APP_BRIDGE_SDK_NAME
188
+ });
189
+ if (authToken) headers.set("Authorization", `Bearer ${authToken}`);
190
+ return headers;
191
+ }
192
+ function sessionTokenRequestBody(request) {
193
+ return {
194
+ client_id: request.clientId,
195
+ entry: request.entry,
196
+ resources: request.resources ?? [],
197
+ allowed_origins: request.allowedOrigins ?? [],
198
+ ...request.sessionId ? { session_id: request.sessionId } : {}
199
+ };
200
+ }
201
+ function resolveSessionTokenUrl(apiBaseUrl) {
202
+ if (!apiBaseUrl) return `/${DEFAULT_SESSION_TOKEN_PATH}`;
203
+ return new URL(DEFAULT_SESSION_TOKEN_PATH, ensureTrailingSlash(apiBaseUrl)).toString();
204
+ }
205
+ function ensureTrailingSlash(url) {
206
+ return url.endsWith("/") ? url : `${url}/`;
207
+ }
208
+ function isSessionTokenSuccessResponse(value) {
209
+ return typeof value === "object" && value !== null && "session_token" in value && typeof value.session_token === "string";
210
+ }
211
+ function errorForTokenResponse(status, body) {
212
+ const errorBody = isLegacyErrorResponse(body) ? body.error : void 0;
213
+ const message = errorBody?.message ?? "Fluid App Bridge backend rejected the session-token request";
214
+ const details = errorBody?.details ?? body;
215
+ if (status === 401) return new FluidBridgeUnauthorizedError(message, details);
216
+ if (status === 403) return new FluidBridgeFailedAuthenticationError(message, details);
217
+ if (status === 422) return new FluidBridgeIncompatibleVersionError(message, details);
218
+ return new FluidBridgeTokenMintError(message, details);
219
+ }
220
+ function isLegacyErrorResponse(value) {
221
+ return typeof value === "object" && value !== null && "error" in value;
222
+ }
223
+ //#endregion
10
224
  //#region ../widgets/src/widgets/EmbedWidget.tsx
11
225
  var EmbedWidget_exports = /* @__PURE__ */ __exportAll({
12
226
  EmbedWidget: () => EmbedWidget,
@@ -42,6 +256,13 @@ function useEmbedUrl(url, publicId) {
42
256
  };
43
257
  }, [url, publicId]);
44
258
  }
259
+ function getEmbedOrigin(url) {
260
+ try {
261
+ return new URL(url).origin;
262
+ } catch {
263
+ return null;
264
+ }
265
+ }
45
266
  function useEmbedPostMessageBridge({ iframeRef, normalizedUrl, isValidUrl, editMode }) {
46
267
  useEffect(() => {
47
268
  if (!isValidUrl || editMode) return;
@@ -211,13 +432,15 @@ const getHeaderIcon = (name) => {
211
432
  if (!name) return GraduationCap;
212
433
  return HEADER_ICON_MAP[name] ?? GraduationCap;
213
434
  };
214
- function EmbedWidget({ url = "", title = "Embedded Content", height = "400px", fullScreen = false, allowFullscreen = true, loading = "lazy", borderRadius = "md", borderWidth = "none", borderColor = "muted", editMode: _editMode, isSelected: _isSelected, displayMode = "inline", coverResource, coverUseCustomUrl = false, coverImageUrl = "", coverTitle = "", coverMeta = "", coverShowHeader = true, coverHeaderIcon = "GraduationCap", coverHeaderIconColor = "primary", coverHeight = "320px", className, ...props }) {
435
+ function EmbedWidget({ url = "", appBridge, title = "Embedded Content", height = "400px", fullScreen = false, allowFullscreen = true, loading = "lazy", borderRadius = "md", borderWidth = "none", borderColor = "muted", editMode: _editMode, isSelected: _isSelected, displayMode = "inline", coverResource, coverUseCustomUrl = false, coverImageUrl = "", coverTitle = "", coverMeta = "", coverShowHeader = true, coverHeaderIcon = "GraduationCap", coverHeaderIconColor = "primary", coverHeight = "320px", className, ...props }) {
215
436
  const renderState = useWidgetRenderState();
216
437
  const editMode = _editMode ?? renderState.editMode;
217
438
  const isSelected = _isSelected ?? renderState.isSelected;
218
439
  const isFullScreen = fullScreen;
219
440
  const iframeRef = useRef(null);
220
- const publicId = useRepUser()?.publicId;
441
+ const repUser = useRepUser();
442
+ const publicId = repUser?.publicId;
443
+ const { data: store } = useOptionalStore();
221
444
  const [modalOpen, setModalOpen] = useState(false);
222
445
  const [coverReloadKey, setCoverReloadKey] = useState(0);
223
446
  const [iframeReloadKey, setIframeReloadKey] = useState(0);
@@ -230,6 +453,80 @@ function EmbedWidget({ url = "", title = "Embedded Content", height = "400px", f
230
453
  isValidUrl,
231
454
  editMode
232
455
  });
456
+ const appBridgeClientId = appBridge?.clientId;
457
+ const appBridgeEntryType = appBridge?.entryType;
458
+ const appBridgeEntryName = appBridge?.entryName;
459
+ const appBridgeResources = appBridge?.resources;
460
+ const appBridgeAppOrigins = appBridge?.appOrigins;
461
+ const appBridgeContext = useMemo(() => {
462
+ if (!appBridgeClientId || !store || !isValidUrl) return null;
463
+ return {
464
+ protocol: FLUID_BRIDGE_PROTOCOL_VERSION,
465
+ app: { clientId: appBridgeClientId },
466
+ store: {
467
+ subdomain: store.subdomain,
468
+ url: `https://${store.subdomain}.fluid.app`,
469
+ name: store.name
470
+ },
471
+ ...repUser ? { actor: {
472
+ type: "member",
473
+ ...repUser.publicId ? { uuid: repUser.publicId } : {},
474
+ roles: [],
475
+ permissions: []
476
+ } } : {},
477
+ entry: {
478
+ type: appBridgeEntryType ?? "portal_embed",
479
+ name: appBridgeEntryName ?? title
480
+ },
481
+ resources: appBridgeResources ?? [],
482
+ fetch: { allowedOrigins: [getEmbedOrigin(normalizedUrl), ...appBridgeAppOrigins ?? []].filter((origin) => Boolean(origin)) },
483
+ sdk: { minVersion: APP_BRIDGE_SDK_VERSION }
484
+ };
485
+ }, [
486
+ appBridgeAppOrigins,
487
+ appBridgeClientId,
488
+ appBridgeEntryName,
489
+ appBridgeEntryType,
490
+ appBridgeResources,
491
+ isValidUrl,
492
+ normalizedUrl,
493
+ repUser,
494
+ store,
495
+ title
496
+ ]);
497
+ const appBridgeContextRef = useRef(null);
498
+ const appBridgeContextReady = appBridgeContext !== null;
499
+ useEffect(() => {
500
+ appBridgeContextRef.current = appBridgeContext;
501
+ }, [appBridgeContext]);
502
+ const getAppBridgeContext = useCallback(() => {
503
+ if (!appBridgeContextRef.current) throw new Error("App Bridge context is unavailable");
504
+ return appBridgeContextRef.current;
505
+ }, []);
506
+ const getAppBridgeSessionToken = useCallback((bridgeContext) => mintAppBridgeSessionToken({ request: sessionTokenRequestFromContext(bridgeContext) }), []);
507
+ useEffect(() => {
508
+ if (!appBridgeClientId || !appBridgeContextReady || editMode) return;
509
+ const iframe = iframeRef.current;
510
+ const appOrigin = getEmbedOrigin(normalizedUrl);
511
+ if (!iframe || !appOrigin) return;
512
+ const host = createFluidBridgeHost({
513
+ iframe,
514
+ appOrigin,
515
+ clientId: appBridgeClientId,
516
+ getContext: getAppBridgeContext,
517
+ getSessionToken: getAppBridgeSessionToken
518
+ });
519
+ return () => host.destroy();
520
+ }, [
521
+ appBridgeClientId,
522
+ appBridgeContextReady,
523
+ editMode,
524
+ getAppBridgeContext,
525
+ getAppBridgeSessionToken,
526
+ iframeReloadKey,
527
+ modalOpen,
528
+ normalizedUrl
529
+ ]);
233
530
  useModalBodyScrollLock(modalOpen);
234
531
  useModalEscapeClose(modalOpen, closeModal);
235
532
  const embedability = useEmbedability(normalizedUrl, isValidUrl, editMode && displayMode !== "cover");
@@ -706,4 +1003,4 @@ const embedWidgetPropertySchema = {
706
1003
  //#endregion
707
1004
  export { EmbedWidget_exports as n, embedWidgetPropertySchema as r, EmbedWidget as t };
708
1005
 
709
- //# sourceMappingURL=EmbedWidget-BJY7l4pI.mjs.map
1006
+ //# sourceMappingURL=EmbedWidget-p_Ybl0em.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmbedWidget-p_Ybl0em.mjs","names":[],"sources":["../../../platform/app-bridge/src/errors.ts","../../../platform/app-bridge/src/protocol.ts","../../../platform/app-bridge/src/host.ts","../../../platform/app-bridge/src/session-token-api.ts","../../widgets/src/widgets/EmbedWidget.tsx"],"sourcesContent":["export type FluidBridgeErrorCode =\n | \"configuration_error\"\n | \"host_unavailable\"\n | \"handshake_timeout\"\n | \"incompatible_version\"\n | \"token_mint_failed\"\n | \"unauthorized\"\n | \"forbidden_origin\"\n | \"invalid_context\"\n | \"request_timeout\"\n | \"fetch_target_not_allowed\"\n | \"network_error\"\n | \"failed_authentication\";\n\nexport class FluidBridgeError extends Error {\n readonly code: FluidBridgeErrorCode;\n readonly details?: unknown;\n\n constructor(code: FluidBridgeErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"FluidBridgeError\";\n this.code = code;\n this.details = details;\n }\n}\n\nexport class FluidBridgeConfigurationError extends FluidBridgeError {\n constructor(message: string, details?: unknown) {\n super(\"configuration_error\", message, details);\n this.name = \"FluidBridgeConfigurationError\";\n }\n}\n\nexport class FluidBridgeHostUnavailableError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host is unavailable\",\n details?: unknown,\n ) {\n super(\"host_unavailable\", message, details);\n this.name = \"FluidBridgeHostUnavailableError\";\n }\n}\n\nexport class FluidBridgeHandshakeTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host did not respond before the handshake timed out\",\n details?: unknown,\n ) {\n super(\"handshake_timeout\", message, details);\n this.name = \"FluidBridgeHandshakeTimeoutError\";\n }\n}\n\nexport class FluidBridgeIncompatibleVersionError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge SDK is not compatible with the host\",\n details?: unknown,\n ) {\n super(\"incompatible_version\", message, details);\n this.name = \"FluidBridgeIncompatibleVersionError\";\n }\n}\n\nexport class FluidBridgeTokenMintError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host could not mint a session token\",\n details?: unknown,\n ) {\n super(\"token_mint_failed\", message, details);\n this.name = \"FluidBridgeTokenMintError\";\n }\n}\n\nexport class FluidBridgeUnauthorizedError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request is unauthorized\",\n details?: unknown,\n ) {\n super(\"unauthorized\", message, details);\n this.name = \"FluidBridgeUnauthorizedError\";\n }\n}\n\nexport class FluidBridgeForbiddenOriginError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge host origin is forbidden\",\n details?: unknown,\n ) {\n super(\"forbidden_origin\", message, details);\n this.name = \"FluidBridgeForbiddenOriginError\";\n }\n}\n\nexport class FluidBridgeInvalidContextError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge context is invalid\",\n details?: unknown,\n ) {\n super(\"invalid_context\", message, details);\n this.name = \"FluidBridgeInvalidContextError\";\n }\n}\n\nexport class FluidBridgeRequestTimeoutError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge request timed out\",\n details?: unknown,\n ) {\n super(\"request_timeout\", message, details);\n this.name = \"FluidBridgeRequestTimeoutError\";\n }\n}\n\nexport class FluidBridgeFetchTargetError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge fetch target is not allowed\",\n details?: unknown,\n ) {\n super(\"fetch_target_not_allowed\", message, details);\n this.name = \"FluidBridgeFetchTargetError\";\n }\n}\n\nexport class FluidBridgeNetworkError extends FluidBridgeError {\n constructor(message = \"Fluid App Bridge fetch failed\", details?: unknown) {\n super(\"network_error\", message, details);\n this.name = \"FluidBridgeNetworkError\";\n }\n}\n\nexport class FluidBridgeFailedAuthenticationError extends FluidBridgeError {\n constructor(\n message = \"Fluid App Bridge authentication failed\",\n details?: unknown,\n ) {\n super(\"failed_authentication\", message, details);\n this.name = \"FluidBridgeFailedAuthenticationError\";\n }\n}\n","export const FLUID_BRIDGE_PROTOCOL_VERSION = \"2026-07\";\nexport const APP_BRIDGE_SDK_NAME = \"@fluid-commerce/app-bridge\";\nexport const APP_BRIDGE_SDK_VERSION = \"0.1.0\";\n\nexport const FluidBridgeMessageType = {\n SessionTokenRequest: \"FLUID::SESSION_TOKEN_REQUEST\",\n SessionTokenRespond: \"FLUID::SESSION_TOKEN_RESPOND\",\n ContextRequest: \"FLUID::CONTEXT_REQUEST\",\n ContextRespond: \"FLUID::CONTEXT_RESPOND\",\n FailedAuthentication: \"FLUID::ERROR::FAILED_AUTHENTICATION\",\n Unauthorized: \"FLUID::ERROR::UNAUTHORIZED\",\n IncompatibleVersion: \"FLUID::ERROR::INCOMPATIBLE_VERSION\",\n TokenMintFailed: \"FLUID::ERROR::TOKEN_MINT_FAILED\",\n InvalidContext: \"FLUID::ERROR::INVALID_CONTEXT\",\n} as const;\n\nexport type FluidBridgeMessageTypeValue =\n (typeof FluidBridgeMessageType)[keyof typeof FluidBridgeMessageType];\n\nexport type BridgeActorType = \"admin\" | \"member\" | \"customer\" | \"anonymous\";\nexport type BridgeEntryType =\n | \"droplet\"\n | \"drop_zone\"\n | \"mobile_embed\"\n | \"portal_embed\"\n | \"app_extension\";\n\nexport interface BridgeResource {\n type: string;\n id: string;\n}\n\nexport interface BridgeContext {\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n app: { clientId: string };\n store: { subdomain: string; url: string; uuid?: string; name?: string };\n actor?: {\n type: BridgeActorType;\n uuid?: string;\n roles?: string[];\n permissions?: string[];\n memberType?: string;\n };\n entry: { type: BridgeEntryType; name?: string };\n resources: BridgeResource[];\n fetch: { allowedOrigins: string[] };\n sdk: { minVersion: string; recommendedVersion?: string };\n}\n\nexport interface BridgeEnvelope<TType extends string, TPayload> {\n id: string;\n type: TType;\n payload: TPayload;\n}\n","import {\n FLUID_BRIDGE_PROTOCOL_VERSION,\n FluidBridgeMessageType,\n type BridgeContext,\n type BridgeEnvelope,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeForbiddenOriginError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeInvalidContextError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n type FluidBridgeErrorCode,\n} from \"./errors\";\n\ntype RequestPayload = {\n clientId: string;\n protocol: typeof FLUID_BRIDGE_PROTOCOL_VERSION;\n};\n\ntype HostErrorPayload = {\n code: FluidBridgeErrorCode;\n message: string;\n details?: unknown;\n};\n\nexport interface CreateFluidBridgeHostOptions {\n iframe: HTMLIFrameElement;\n appOrigin: string;\n clientId: string;\n getContext: () => BridgeContext | Promise<BridgeContext>;\n getSessionToken: (context: BridgeContext) => string | Promise<string>;\n targetWindow?: Window;\n}\n\nexport interface FluidBridgeHost {\n destroy: () => void;\n}\n\nexport function createFluidBridgeHost(\n options: CreateFluidBridgeHostOptions,\n): FluidBridgeHost {\n const targetWindow = options.targetWindow ?? window;\n const appOrigin = normalizeOrigin(options.appOrigin);\n\n const handleMessage = (event: MessageEvent<unknown>): void => {\n if (event.origin !== appOrigin) return;\n if (event.source !== options.iframe.contentWindow) return;\n if (!isBridgeEnvelope(event.data)) return;\n\n void respondToBridgeMessage(options, event.data, appOrigin);\n };\n\n targetWindow.addEventListener(\"message\", handleMessage);\n\n return {\n destroy: () => targetWindow.removeEventListener(\"message\", handleMessage),\n };\n}\n\nasync function respondToBridgeMessage(\n options: CreateFluidBridgeHostOptions,\n envelope: BridgeEnvelope<string, unknown>,\n appOrigin: string,\n): Promise<void> {\n const childWindow = options.iframe.contentWindow;\n if (!childWindow) return;\n\n try {\n validateRequestPayload(envelope.payload, options.clientId);\n\n switch (envelope.type) {\n case FluidBridgeMessageType.ContextRequest: {\n const context = await options.getContext();\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.ContextRespond,\n payload: context,\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.ContextRespond,\n BridgeContext\n >,\n appOrigin,\n );\n return;\n }\n case FluidBridgeMessageType.SessionTokenRequest: {\n const context = await options.getContext();\n const sessionToken = await options.getSessionToken(context);\n if (sessionToken.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host returned an empty session token\",\n );\n }\n childWindow.postMessage(\n {\n id: envelope.id,\n type: FluidBridgeMessageType.SessionTokenRespond,\n payload: { sessionToken },\n } satisfies BridgeEnvelope<\n typeof FluidBridgeMessageType.SessionTokenRespond,\n { sessionToken: string }\n >,\n appOrigin,\n );\n return;\n }\n default:\n throw new FluidBridgeForbiddenOriginError(\n \"Fluid App Bridge host received an unsupported message type\",\n { type: envelope.type },\n );\n }\n } catch (error) {\n childWindow.postMessage(\n {\n id: envelope.id,\n type: errorTypeFor(error),\n payload: errorPayloadFor(error),\n } satisfies BridgeEnvelope<string, HostErrorPayload>,\n appOrigin,\n );\n }\n}\n\nfunction validateRequestPayload(\n value: unknown,\n clientId: string,\n): RequestPayload {\n if (typeof value !== \"object\" || value === null) {\n throw new FluidBridgeInvalidContextError(\n \"Fluid App Bridge request payload is invalid\",\n );\n }\n if (!(\"clientId\" in value) || value.clientId !== clientId) {\n throw new FluidBridgeFailedAuthenticationError(\n \"Fluid App Bridge request client ID does not match the host context\",\n );\n }\n if (\n !(\"protocol\" in value) ||\n value.protocol !== FLUID_BRIDGE_PROTOCOL_VERSION\n ) {\n throw new FluidBridgeIncompatibleVersionError();\n }\n return value as RequestPayload;\n}\n\nfunction isBridgeEnvelope(\n value: unknown,\n): value is BridgeEnvelope<string, unknown> {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n return (\n \"id\" in value &&\n \"type\" in value &&\n \"payload\" in value &&\n typeof value.id === \"string\" &&\n typeof value.type === \"string\"\n );\n}\n\nfunction errorTypeFor(error: unknown): string {\n if (error instanceof FluidBridgeFailedAuthenticationError) {\n return FluidBridgeMessageType.FailedAuthentication;\n }\n if (error instanceof FluidBridgeIncompatibleVersionError) {\n return FluidBridgeMessageType.IncompatibleVersion;\n }\n if (error instanceof FluidBridgeUnauthorizedError) {\n return FluidBridgeMessageType.Unauthorized;\n }\n if (error instanceof FluidBridgeTokenMintError) {\n return FluidBridgeMessageType.TokenMintFailed;\n }\n if (error instanceof FluidBridgeInvalidContextError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n if (error instanceof FluidBridgeForbiddenOriginError) {\n return FluidBridgeMessageType.InvalidContext;\n }\n return FluidBridgeMessageType.TokenMintFailed;\n}\n\nfunction errorPayloadFor(error: unknown): HostErrorPayload {\n if (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\"\n ) {\n return {\n code: error.code as FluidBridgeErrorCode,\n message: error.message,\n details: \"details\" in error ? error.details : undefined,\n };\n }\n return {\n code: \"token_mint_failed\",\n message: \"Fluid App Bridge host could not complete the request\",\n details: error,\n };\n}\n\nfunction normalizeOrigin(origin: string): string {\n return new URL(origin).origin;\n}\n","import {\n APP_BRIDGE_SDK_NAME,\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n type BridgeContext,\n} from \"./protocol\";\nimport {\n FluidBridgeFailedAuthenticationError,\n FluidBridgeIncompatibleVersionError,\n FluidBridgeTokenMintError,\n FluidBridgeUnauthorizedError,\n} from \"./errors\";\n\nexport interface AppBridgeSessionTokenRequest {\n clientId: string;\n entry: BridgeContext[\"entry\"];\n resources?: BridgeContext[\"resources\"];\n allowedOrigins?: string[];\n sessionId?: string;\n}\n\nexport interface MintAppBridgeSessionTokenOptions {\n request: AppBridgeSessionTokenRequest;\n apiBaseUrl?: string;\n authToken?: string;\n fetch?: typeof fetch;\n}\n\ninterface SessionTokenSuccessResponse {\n session_token: string;\n}\n\ninterface LegacyErrorResponse {\n error?: {\n message?: string;\n details?: unknown;\n };\n}\n\nconst DEFAULT_SESSION_TOKEN_PATH = \"api/v2025-06/app_bridge/session_token\";\n\nexport async function mintAppBridgeSessionToken({\n request,\n apiBaseUrl,\n authToken,\n fetch: fetchImplementation = globalThis.fetch?.bind(globalThis),\n}: MintAppBridgeSessionTokenOptions): Promise<string> {\n if (!fetchImplementation) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge host requires a fetch implementation to mint session tokens\",\n );\n }\n\n const response = await fetchImplementation(\n resolveSessionTokenUrl(apiBaseUrl),\n {\n method: \"POST\",\n headers: sessionTokenHeaders(authToken),\n body: JSON.stringify(sessionTokenRequestBody(request)),\n },\n );\n\n const body: unknown = await response.json().catch(() => null);\n\n if (!response.ok) {\n throw errorForTokenResponse(response.status, body);\n }\n\n if (!isSessionTokenSuccessResponse(body) || body.session_token.length === 0) {\n throw new FluidBridgeTokenMintError(\n \"Fluid App Bridge backend returned an invalid session token response\",\n { body },\n );\n }\n\n return body.session_token;\n}\n\nexport function sessionTokenRequestFromContext(\n context: BridgeContext,\n sessionId?: string,\n): AppBridgeSessionTokenRequest {\n return {\n clientId: context.app.clientId,\n entry: context.entry,\n resources: context.resources,\n allowedOrigins: context.fetch.allowedOrigins,\n ...(sessionId ? { sessionId } : {}),\n };\n}\n\nfunction sessionTokenHeaders(authToken: string | undefined): Headers {\n const headers = new Headers({\n \"Content-Type\": \"application/json\",\n \"X-Fluid-App-Bridge-Protocol\": FLUID_BRIDGE_PROTOCOL_VERSION,\n \"X-Fluid-App-Bridge-Version\": APP_BRIDGE_SDK_VERSION,\n \"X-Fluid-App-Bridge-Sdk\": APP_BRIDGE_SDK_NAME,\n });\n\n if (authToken) {\n headers.set(\"Authorization\", `Bearer ${authToken}`);\n }\n\n return headers;\n}\n\nfunction sessionTokenRequestBody(\n request: AppBridgeSessionTokenRequest,\n): Record<string, unknown> {\n return {\n client_id: request.clientId,\n entry: request.entry,\n resources: request.resources ?? [],\n allowed_origins: request.allowedOrigins ?? [],\n ...(request.sessionId ? { session_id: request.sessionId } : {}),\n };\n}\n\nfunction resolveSessionTokenUrl(apiBaseUrl: string | undefined): string {\n if (!apiBaseUrl) {\n return `/${DEFAULT_SESSION_TOKEN_PATH}`;\n }\n return new URL(\n DEFAULT_SESSION_TOKEN_PATH,\n ensureTrailingSlash(apiBaseUrl),\n ).toString();\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith(\"/\") ? url : `${url}/`;\n}\n\nfunction isSessionTokenSuccessResponse(\n value: unknown,\n): value is SessionTokenSuccessResponse {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"session_token\" in value &&\n typeof value.session_token === \"string\"\n );\n}\n\nfunction errorForTokenResponse(status: number, body: unknown): Error {\n const errorBody = isLegacyErrorResponse(body) ? body.error : undefined;\n const message =\n errorBody?.message ??\n \"Fluid App Bridge backend rejected the session-token request\";\n const details = errorBody?.details ?? body;\n\n if (status === 401) {\n return new FluidBridgeUnauthorizedError(message, details);\n }\n if (status === 403) {\n return new FluidBridgeFailedAuthenticationError(message, details);\n }\n if (status === 422) {\n return new FluidBridgeIncompatibleVersionError(message, details);\n }\n return new FluidBridgeTokenMintError(message, details);\n}\n\nfunction isLegacyErrorResponse(value: unknown): value is LegacyErrorResponse {\n return typeof value === \"object\" && value !== null && \"error\" in value;\n}\n","import {\n APP_BRIDGE_SDK_VERSION,\n FLUID_BRIDGE_PROTOCOL_VERSION,\n createFluidBridgeHost,\n mintAppBridgeSessionToken,\n sessionTokenRequestFromContext,\n type BridgeContext,\n type BridgeEntryType,\n type BridgeResource,\n} from \"@fluid-commerce/app-bridge\";\nimport {\n Bell,\n BookmarkIcon,\n BookOpen,\n Calendar,\n ExternalLink,\n Gift,\n Globe,\n GraduationCap,\n Heart,\n Maximize2,\n RotateCw,\n ShoppingBag,\n Sparkles,\n Star,\n Trophy,\n User,\n Video,\n X,\n Zap,\n type LucideIcon,\n} from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type RefObject,\n} from \"react\";\nimport type React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport { useShellTranslation } from \"@fluid-app/portal-core/shell-translation-api-context\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n ShareableItem,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n getColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\nimport { useWidgetRenderState } from \"../contexts/WidgetRenderStateContext\";\nimport { useOptionalStore } from \"@fluid-app/portal-react/hooks/use-optional-store\";\n\ntype EmbedWidgetMessage = {\n type: \"OPEN_FULL_SCREEN_WEBVIEW\";\n url: string;\n};\n\nexport type EmbedWidgetAppBridgeConfig = {\n clientId?: string;\n appOrigins?: string[];\n entryType?: BridgeEntryType;\n entryName?: string;\n resources?: BridgeResource[];\n};\n\ntype DisplayMode = \"inline\" | \"cover\";\n\ntype EmbedUrlState = {\n normalizedUrl: string;\n isValidUrl: boolean;\n iframeSrc: string;\n};\n\nfunction isValidHttpUrl(urlString: string): boolean {\n try {\n const parsed = new URL(urlString);\n return parsed.protocol === \"https:\" || parsed.protocol === \"http:\";\n } catch {\n return false;\n }\n}\n\nfunction useEmbedUrl(url: string, publicId: string | undefined): EmbedUrlState {\n return useMemo(() => {\n const normalizedUrl =\n url && (url.startsWith(\"http://\") || url.startsWith(\"https://\"))\n ? url\n : url\n ? `https://${url}`\n : \"\";\n\n let isValidUrl = false;\n if (normalizedUrl) {\n try {\n const parsed = new URL(normalizedUrl);\n isValidUrl =\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n (parsed.hostname.includes(\".\") || parsed.hostname === \"localhost\");\n } catch {\n // invalid URL\n }\n }\n\n if (!isValidUrl || !publicId) {\n return { normalizedUrl, isValidUrl, iframeSrc: normalizedUrl };\n }\n\n const urlObj = new URL(normalizedUrl);\n urlObj.searchParams.set(\"public_id\", publicId);\n return { normalizedUrl, isValidUrl, iframeSrc: urlObj.toString() };\n }, [url, publicId]);\n}\n\ntype UseEmbedPostMessageBridgeProps = {\n iframeRef: RefObject<HTMLIFrameElement | null>;\n normalizedUrl: string;\n isValidUrl: boolean;\n editMode: boolean;\n};\n\nfunction getEmbedOrigin(url: string): string | null {\n try {\n return new URL(url).origin;\n } catch {\n return null;\n }\n}\n\nfunction useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n}: UseEmbedPostMessageBridgeProps): void {\n useEffect(() => {\n if (!isValidUrl || editMode) return;\n\n const expectedOrigin = new URL(normalizedUrl).origin;\n\n function handleMessage(event: MessageEvent) {\n if (event.origin !== expectedOrigin) return;\n if (event.source !== iframeRef.current?.contentWindow) return;\n\n let data: unknown;\n if (typeof event.data === \"string\") {\n try {\n data = JSON.parse(event.data);\n } catch {\n return;\n }\n } else {\n data = event.data;\n }\n\n if (\n typeof data === \"object\" &&\n data !== null &&\n \"type\" in data &&\n (data as EmbedWidgetMessage).type === \"OPEN_FULL_SCREEN_WEBVIEW\"\n ) {\n const messageUrl = (data as EmbedWidgetMessage).url;\n if (messageUrl && isValidHttpUrl(messageUrl)) {\n window.open(messageUrl, \"_blank\", \"noopener,noreferrer\");\n }\n }\n }\n\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [iframeRef, normalizedUrl, isValidUrl, editMode]);\n}\n\ntype EmbedabilityState = \"idle\" | \"checking\" | \"embeddable\" | \"blocked\";\n\nfunction useEmbedability(\n normalizedUrl: string,\n isValidUrl: boolean,\n editMode: boolean,\n): EmbedabilityState {\n const [state, setState] = useState<EmbedabilityState>(\"idle\");\n\n useEffect(() => {\n if (!editMode || !isValidUrl) {\n setState(\"idle\");\n return;\n }\n setState(\"checking\");\n const controller = new AbortController();\n const timer = setTimeout(() => {\n fetch(`/api/embed-can-frame?url=${encodeURIComponent(normalizedUrl)}`, {\n signal: controller.signal,\n })\n .then((res) => (res.ok ? res.json() : null))\n .then((data: { canFrame?: boolean } | null) => {\n if (controller.signal.aborted) return;\n if (data && typeof data.canFrame === \"boolean\") {\n setState(data.canFrame ? \"embeddable\" : \"blocked\");\n } else {\n setState(\"idle\");\n }\n })\n .catch(() => {\n if (!controller.signal.aborted) {\n setState(\"idle\");\n }\n });\n }, 400);\n\n return () => {\n controller.abort();\n clearTimeout(timer);\n };\n }, [normalizedUrl, isValidUrl, editMode]);\n\n return state;\n}\n\nfunction useModalBodyScrollLock(isOpen: boolean): void {\n useEffect(() => {\n if (!isOpen) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [isOpen]);\n}\n\nfunction useModalEscapeClose(isOpen: boolean, onClose: () => void): void {\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [isOpen, onClose]);\n}\n\nfunction useDialogFocusRestore(dialogRef: RefObject<HTMLElement | null>): void {\n useEffect(() => {\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n dialogRef.current?.focus();\n return () => {\n previouslyFocused?.focus();\n };\n }, [dialogRef]);\n}\n\n// ---------- header icon registry ----------\n\nconst HEADER_ICON_MAP: Record<string, LucideIcon> = {\n GraduationCap,\n Video,\n BookOpen,\n Globe,\n User,\n Star,\n Heart,\n Trophy,\n Sparkles,\n Zap,\n Gift,\n ShoppingBag,\n Bell,\n Calendar,\n Bookmark: BookmarkIcon,\n};\n\nconst HEADER_ICON_OPTIONS: Array<{ label: string; value: string }> = [\n { label: \"Graduation Cap\", value: \"GraduationCap\" },\n { label: \"Video\", value: \"Video\" },\n { label: \"Book\", value: \"BookOpen\" },\n { label: \"Globe\", value: \"Globe\" },\n { label: \"User\", value: \"User\" },\n { label: \"Star\", value: \"Star\" },\n { label: \"Heart\", value: \"Heart\" },\n { label: \"Trophy\", value: \"Trophy\" },\n { label: \"Sparkles\", value: \"Sparkles\" },\n { label: \"Zap / Lightning\", value: \"Zap\" },\n { label: \"Gift\", value: \"Gift\" },\n { label: \"Shopping Bag\", value: \"ShoppingBag\" },\n { label: \"Bell\", value: \"Bell\" },\n { label: \"Calendar\", value: \"Calendar\" },\n { label: \"Bookmark\", value: \"Bookmark\" },\n];\n\nconst getHeaderIcon = (name: string | undefined): LucideIcon => {\n if (!name) return GraduationCap;\n return HEADER_ICON_MAP[name] ?? GraduationCap;\n};\n\ntype EmbedWidgetProps = ComponentProps<\"div\"> & {\n url?: string;\n appBridge?: EmbedWidgetAppBridgeConfig;\n title?: string;\n height?: string;\n fullScreen?: boolean;\n allowFullscreen?: boolean;\n loading?: \"eager\" | \"lazy\";\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n // Builder render state is provided by WidgetRenderStateContext.\n editMode?: boolean;\n // Builder render state is provided by WidgetRenderStateContext.\n isSelected?: boolean;\n\n // Cover-mode additions (all optional — inline mode ignores these)\n displayMode?: DisplayMode;\n coverResource?: ShareableItem;\n coverUseCustomUrl?: boolean;\n coverImageUrl?: string;\n coverTitle?: string;\n coverMeta?: string;\n coverShowHeader?: boolean;\n coverHeaderIcon?: string;\n coverHeaderIconColor?: ColorOptions;\n coverHeight?: string;\n};\n\nexport function EmbedWidget({\n url = \"\",\n appBridge,\n title = \"Embedded Content\",\n height = \"400px\",\n fullScreen = false,\n allowFullscreen = true,\n loading = \"lazy\",\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n editMode: _editMode,\n isSelected: _isSelected,\n\n displayMode = \"inline\",\n coverResource,\n coverUseCustomUrl = false,\n coverImageUrl = \"\",\n coverTitle = \"\",\n coverMeta = \"\",\n coverShowHeader = true,\n coverHeaderIcon = \"GraduationCap\",\n coverHeaderIconColor = \"primary\",\n coverHeight = \"320px\",\n\n className,\n ...props\n}: EmbedWidgetProps): React.JSX.Element {\n const renderState = useWidgetRenderState();\n const editMode = _editMode ?? renderState.editMode;\n const isSelected = _isSelected ?? renderState.isSelected;\n const isFullScreen = fullScreen;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const repUser = useRepUser();\n const publicId = repUser?.publicId;\n const { data: store } = useOptionalStore();\n\n const [modalOpen, setModalOpen] = useState(false);\n const [coverReloadKey, setCoverReloadKey] = useState(0);\n const [iframeReloadKey, setIframeReloadKey] = useState(0);\n\n const closeModal = useCallback(() => setModalOpen(false), []);\n const { t } = useShellTranslation();\n\n const { normalizedUrl, isValidUrl, iframeSrc } = useEmbedUrl(url, publicId);\n useEmbedPostMessageBridge({\n iframeRef,\n normalizedUrl,\n isValidUrl,\n editMode,\n });\n\n const appBridgeClientId = appBridge?.clientId;\n const appBridgeEntryType = appBridge?.entryType;\n const appBridgeEntryName = appBridge?.entryName;\n const appBridgeResources = appBridge?.resources;\n const appBridgeAppOrigins = appBridge?.appOrigins;\n\n const appBridgeContext = useMemo<BridgeContext | null>(() => {\n if (!appBridgeClientId || !store || !isValidUrl) return null;\n\n return {\n protocol: FLUID_BRIDGE_PROTOCOL_VERSION,\n app: { clientId: appBridgeClientId },\n store: {\n subdomain: store.subdomain,\n url: `https://${store.subdomain}.fluid.app`,\n name: store.name,\n },\n ...(repUser\n ? {\n actor: {\n type: \"member\" as const,\n ...(repUser.publicId ? { uuid: repUser.publicId } : {}),\n roles: [],\n permissions: [],\n },\n }\n : {}),\n entry: {\n type: appBridgeEntryType ?? \"portal_embed\",\n name: appBridgeEntryName ?? title,\n },\n resources: appBridgeResources ?? [],\n fetch: {\n allowedOrigins: [\n getEmbedOrigin(normalizedUrl),\n ...(appBridgeAppOrigins ?? []),\n ].filter((origin): origin is string => Boolean(origin)),\n },\n sdk: { minVersion: APP_BRIDGE_SDK_VERSION },\n };\n }, [\n appBridgeAppOrigins,\n appBridgeClientId,\n appBridgeEntryName,\n appBridgeEntryType,\n appBridgeResources,\n isValidUrl,\n normalizedUrl,\n repUser,\n store,\n title,\n ]);\n const appBridgeContextRef = useRef<BridgeContext | null>(null);\n const appBridgeContextReady = appBridgeContext !== null;\n\n useEffect(() => {\n appBridgeContextRef.current = appBridgeContext;\n }, [appBridgeContext]);\n\n const getAppBridgeContext = useCallback(() => {\n if (!appBridgeContextRef.current) {\n throw new Error(\"App Bridge context is unavailable\");\n }\n return appBridgeContextRef.current;\n }, []);\n\n const getAppBridgeSessionToken = useCallback(\n (bridgeContext: BridgeContext) =>\n mintAppBridgeSessionToken({\n request: sessionTokenRequestFromContext(bridgeContext),\n }),\n [],\n );\n\n useEffect(() => {\n if (!appBridgeClientId || !appBridgeContextReady || editMode) return;\n\n const iframe = iframeRef.current;\n const appOrigin = getEmbedOrigin(normalizedUrl);\n if (!iframe || !appOrigin) return;\n\n const host = createFluidBridgeHost({\n iframe,\n appOrigin,\n clientId: appBridgeClientId,\n getContext: getAppBridgeContext,\n getSessionToken: getAppBridgeSessionToken,\n });\n\n return () => host.destroy();\n }, [\n appBridgeClientId,\n appBridgeContextReady,\n editMode,\n getAppBridgeContext,\n getAppBridgeSessionToken,\n iframeReloadKey,\n modalOpen,\n normalizedUrl,\n ]);\n useModalBodyScrollLock(modalOpen);\n useModalEscapeClose(modalOpen, closeModal);\n const embedability = useEmbedability(\n normalizedUrl,\n isValidUrl,\n editMode && displayMode !== \"cover\",\n );\n\n // ----- Empty/invalid URL states -----\n\n if (!url || !isValidUrl) {\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : { height: displayMode === \"cover\" ? coverHeight : height }\n }\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"size-12 opacity-50\" />\n <p className=\"text-sm font-medium\">\n Enter a URL to embed external content\n </p>\n <p className=\"text-xs opacity-75\">\n Configure the URL in the properties panel\n </p>\n </div>\n </div>\n );\n }\n\n // ----- Cover mode -----\n\n if (displayMode === \"cover\") {\n const resolvedCoverImage = coverUseCustomUrl\n ? coverImageUrl\n : coverResource?.imageUrl || coverResource?.image_url || coverImageUrl;\n\n const effectiveTitle = coverTitle || title;\n const HeaderIcon = getHeaderIcon(coverHeaderIcon);\n\n const handleOpenModal = () => {\n if (editMode) return;\n setModalOpen(true);\n };\n\n const handleReload = () => {\n if (editMode) return;\n setCoverReloadKey((key) => key + 1);\n };\n\n const handleOpenNewTab = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (editMode) return;\n window.open(iframeSrc, \"_blank\", \"noopener,noreferrer\");\n };\n\n return (\n <>\n <div\n className={`relative w-full overflow-hidden rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-background ${className ?? \"\"}`}\n style={{\n boxShadow:\n \"0 1px 2px color-mix(in oklch, var(--color-foreground) 5%, transparent), 0 12px 32px -16px color-mix(in oklch, var(--color-foreground) 10%, transparent)\",\n }}\n {...props}\n >\n {/* Inset hairline ring */}\n <div\n aria-hidden=\"true\"\n className={`pointer-events-none absolute inset-0 z-[1] rounded-${borderRadius}`}\n style={{\n boxShadow:\n \"inset 0 0 0 1px color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n />\n {coverShowHeader && (\n <div className=\"relative z-[2] flex items-center gap-3 px-5 py-3\">\n <span\n aria-hidden=\"true\"\n className={`text-${coverHeaderIconColor}-foreground flex size-7 shrink-0 items-center justify-center rounded-${borderRadius}`}\n style={{\n background: `linear-gradient(135deg, color-mix(in oklch, var(--color-${coverHeaderIconColor}) 75%, white 25%) 0%, var(--color-${coverHeaderIconColor}) 100%)`,\n boxShadow: `\n inset 0 1px 0 rgba(255,255,255,0.25),\n inset 0 -1px 0 rgba(0,0,0,0.08),\n 0 1px 2px color-mix(in oklch, var(--color-${coverHeaderIconColor}) 25%, transparent)\n `,\n }}\n >\n <HeaderIcon className=\"size-3.5\" strokeWidth={2.25} />\n </span>\n\n <div className=\"min-w-0 flex-1\">\n {effectiveTitle && (\n <h3 className=\"text-foreground truncate text-[15px] leading-tight font-semibold tracking-tight\">\n {effectiveTitle}\n </h3>\n )}\n {coverMeta && (\n <p className=\"text-foreground/40 mt-0.5 truncate text-[11px] font-medium tracking-[0.08em] uppercase\">\n {coverMeta}\n </p>\n )}\n </div>\n\n <div className=\"bg-foreground/5 flex shrink-0 items-center rounded-lg p-0.5\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n handleReload();\n }}\n />\n <HeaderIconButton\n Icon={Maximize2}\n label=\"Open\"\n onClick={(e) => {\n e.stopPropagation();\n handleOpenModal();\n }}\n />\n <HeaderIconButton\n Icon={ExternalLink}\n label=\"Open in new tab\"\n onClick={handleOpenNewTab}\n />\n </div>\n </div>\n )}\n\n <button\n type=\"button\"\n onClick={handleOpenModal}\n disabled={editMode}\n className={`relative block w-full overflow-hidden ${editMode ? \"cursor-default\" : \"cursor-pointer\"}`}\n style={{ height: coverHeight }}\n aria-label={`Open ${effectiveTitle || title}`}\n >\n {resolvedCoverImage ? (\n <img\n key={`cover-${coverReloadKey}`}\n src={resolvedCoverImage}\n alt={effectiveTitle || title}\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"bg-muted flex h-full w-full items-center justify-center\">\n <Globe className=\"text-muted-foreground/40 size-16\" />\n </div>\n )}\n </button>\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n\n {modalOpen && (\n <EmbedModal\n key={`modal-${iframeReloadKey}`}\n src={iframeSrc}\n title={effectiveTitle || title}\n allowFullscreen={allowFullscreen}\n iframeRef={iframeRef}\n onClose={closeModal}\n onReload={() => setIframeReloadKey((key) => key + 1)}\n />\n )}\n </>\n );\n }\n\n // ----- Inline mode (original behavior) -----\n\n // When the probe confirms the URL blocks embedding, show a warning card\n // instead of a blank iframe. Otherwise render the iframe — embeddable\n // sites (YouTube /embed/, Calendly, Vimeo, etc.) render live in the builder.\n if (editMode && embedability === \"blocked\") {\n let displayUrl = normalizedUrl;\n try {\n const parsed = new URL(normalizedUrl);\n displayUrl = `${parsed.host}${parsed.pathname === \"/\" ? \"\" : parsed.pathname}`;\n } catch {\n // fall through with the normalized URL\n }\n const inlineHeight = isFullScreen\n ? \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\"\n : height;\n\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-destructive/40 bg-destructive/5 text-destructive border-2 border-dashed ${className ?? \"\"}`}\n {...props}\n style={{ height: inlineHeight }}\n >\n <div className=\"flex flex-col items-center gap-2 p-6 text-center\">\n <Globe className=\"h-12 w-12 opacity-50\" />\n <p className=\"text-sm font-medium\">{t(\"embed_blocked_title\")}</p>\n <p className=\"max-w-xs truncate text-xs opacity-75\">{displayUrl}</p>\n <p className=\"text-xs opacity-60\">{t(\"embed_blocked_hint\")}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${className ?? \"\"}`}\n {...props}\n style={\n isFullScreen\n ? {\n height:\n \"var(--portal-fullscreen-embed-height, calc(100dvh - 4rem))\",\n }\n : undefined\n }\n >\n <iframe\n ref={iframeRef}\n src={iframeSrc}\n title={title}\n width=\"100%\"\n style={isFullScreen ? { height: \"100%\" } : { height }}\n loading={loading}\n allowFullScreen={allowFullscreen}\n className={`rounded-${borderRadius} border-border border`}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox\"\n />\n {editMode && !isSelected && <div className=\"absolute inset-0 z-10\" />}\n </div>\n );\n}\n\n// ----- Header icon button -----\n\ntype HeaderIconButtonProps = {\n Icon: LucideIcon;\n label: string;\n onClick: (e: React.MouseEvent) => void;\n};\n\nfunction HeaderIconButton({\n Icon,\n label,\n onClick,\n}: HeaderIconButtonProps): React.JSX.Element {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className=\"text-foreground/45 hover:text-foreground hover:bg-background flex size-7 items-center justify-center rounded-md transition-colors\"\n >\n <Icon className=\"size-3.5\" strokeWidth={2.25} />\n </button>\n );\n}\n\n// ----- Modal -----\n\ntype EmbedModalProps = {\n src: string;\n title: string;\n allowFullscreen: boolean;\n iframeRef: RefObject<HTMLIFrameElement | null>;\n onClose: () => void;\n onReload: () => void;\n};\n\nfunction EmbedModal({\n src,\n title,\n allowFullscreen,\n iframeRef,\n onClose,\n onReload,\n}: EmbedModalProps): React.JSX.Element {\n const dialogRef = useRef<HTMLDivElement>(null);\n\n useDialogFocusRestore(dialogRef);\n\n // Portal to document.body so the fixed-position dialog isn't clipped by\n // a transformed widget container on the live canvas (CSS transforms make\n // descendants the containing block for `position: fixed`).\n return createPortal(\n <div\n ref={dialogRef}\n tabIndex={-1}\n className=\"fixed inset-0 z-[100] flex items-center justify-center p-4 focus:outline-none sm:p-8\"\n style={{\n background: \"color-mix(in oklch, var(--color-foreground) 80%, black)\",\n }}\n onClick={onClose}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div\n className=\"bg-background relative flex h-full max-h-[95vh] w-full max-w-[1400px] flex-col overflow-hidden rounded-2xl shadow-2xl\"\n onClick={(e) => e.stopPropagation()}\n >\n <div\n className=\"flex items-center justify-between gap-4 px-5 py-3\"\n style={{\n borderBottom:\n \"1px solid color-mix(in oklch, var(--color-foreground) 8%, transparent)\",\n }}\n >\n <h3 className=\"text-foreground truncate text-sm font-semibold tracking-tight\">\n {title}\n </h3>\n <div className=\"flex shrink-0 items-center gap-1\">\n <HeaderIconButton\n Icon={RotateCw}\n label=\"Reload\"\n onClick={(e) => {\n e.stopPropagation();\n onReload();\n }}\n />\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"text-foreground/60 hover:text-foreground hover:bg-foreground/5 flex size-9 shrink-0 items-center justify-center rounded-full transition-colors\"\n >\n <X className=\"size-5\" />\n </button>\n </div>\n </div>\n <iframe\n ref={iframeRef}\n src={src}\n title={title}\n className=\"flex-1 border-0\"\n allowFullScreen={allowFullscreen}\n sandbox=\"allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox\"\n />\n </div>\n </div>,\n document.body,\n );\n}\n\n// ----- Schema -----\n\nexport const embedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"EmbedWidget\",\n displayName: \"Embed\",\n fields: [\n // Content\n {\n key: \"url\",\n label: \"URL\",\n type: \"text\",\n description: \"The URL of the external site to embed\",\n placeholder: \"https://example.com\",\n defaultValue: \"\",\n group: \"Content\",\n },\n {\n key: \"title\",\n label: \"Screen Reader Label\",\n type: \"text\",\n description:\n \"Describes the embed for screen readers and assistive tech. Not visible on the page.\",\n defaultValue: \"Embedded Content\",\n group: \"Content\",\n },\n\n // Display Mode\n {\n key: \"displayMode\",\n label: \"Display Mode\",\n type: \"buttonGroup\",\n description:\n \"Inline: iframe renders directly. Cover: shows a card that opens the embed in a full-screen modal.\",\n defaultValue: \"inline\",\n options: [\n { label: \"Inline\", value: \"inline\" },\n { label: \"Cover + Modal\", value: \"cover\" },\n ],\n group: \"Display Mode\",\n },\n\n // Cover fields — all gated behind displayMode=cover\n {\n key: \"coverResource\",\n label: \"Cover Image\",\n type: \"image\",\n description: \"Select the image shown before the embed opens\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverUseCustomUrl\",\n label: \"Use Custom URL\",\n type: \"boolean\",\n description: \"Enter a custom image URL instead of selecting media\",\n defaultValue: false,\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverImageUrl\",\n label: \"Cover Image URL\",\n type: \"text\",\n description: \"Direct URL to the cover image\",\n placeholder: \"https://example.com/cover.jpg\",\n defaultValue: \"\",\n group: \"Cover\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverUseCustomUrl\", value: true },\n ],\n },\n getHeightField({\n key: \"coverHeight\",\n label: \"Cover Height\",\n description: \"Height of the cover image area\",\n defaultValue: \"320px\",\n group: \"Cover\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n }),\n\n // Cover header (optional)\n {\n key: \"coverShowHeader\",\n label: \"Show Card Header\",\n type: \"boolean\",\n description: \"Show the header with icon, title, and action buttons\",\n defaultValue: true,\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverHeaderIcon\",\n label: \"Header Icon\",\n type: \"select\",\n description: \"Icon displayed in the colored badge on the left\",\n options: HEADER_ICON_OPTIONS,\n defaultValue: \"GraduationCap\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n getColorField({\n key: \"coverHeaderIconColor\",\n label: \"Icon Badge Color\",\n description: \"Background color of the icon badge\",\n defaultValue: \"primary\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n }),\n {\n key: \"coverTitle\",\n label: \"Header Title\",\n type: \"text\",\n description:\n \"Title shown in the card header and modal (falls back to the widget Title if empty). Available even when the card header is hidden so the modal still has a meaningful title.\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: { key: \"displayMode\", value: \"cover\" },\n },\n {\n key: \"coverMeta\",\n label: \"Meta Text\",\n type: \"text\",\n description:\n \"Small uppercase meta line below the title (e.g. 'APR 16 · COACHING THE HOSTESS')\",\n defaultValue: \"\",\n group: \"Cover Header\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"cover\" },\n { key: \"coverShowHeader\", value: true },\n ],\n },\n\n // Design\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the embed container\",\n defaultValue: \"md\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n group: \"Design\",\n }),\n {\n key: \"fullScreen\",\n label: \"Full Screen\",\n type: \"boolean\",\n description:\n \"Inline mode: fill the available space instead of a fixed height\",\n defaultValue: false,\n group: \"Design\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n getHeightField({\n key: \"height\",\n label: \"Height\",\n description: \"Height of the inline embed iframe\",\n defaultValue: \"400px\",\n group: \"Design\",\n requiresKeyValue: [\n { key: \"displayMode\", value: \"inline\" },\n { key: \"fullScreen\", value: false },\n ],\n }),\n\n // Settings\n {\n key: \"allowFullscreen\",\n label: \"Allow Fullscreen\",\n type: \"boolean\",\n description: \"Allow the embedded content to use fullscreen mode\",\n defaultValue: true,\n group: \"Settings\",\n },\n {\n key: \"loading\",\n label: \"Loading\",\n type: \"select\",\n description: \"When to load the embedded content (inline mode only)\",\n options: [\n { label: \"Lazy (on scroll)\", value: \"lazy\" },\n { label: \"Eager (immediately)\", value: \"eager\" },\n ],\n defaultValue: \"lazy\",\n group: \"Settings\",\n requiresKeyValue: { key: \"displayMode\", value: \"inline\" },\n },\n ],\n};\n"],"mappings":";;;;;;;;;;;AAcA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CACA;CAEA,YAAY,MAA4B,SAAiB,SAAmB;AAC1E,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO;AACZ,OAAK,UAAU;;;AA+BnB,IAAa,sCAAb,cAAyD,iBAAiB;CACxE,YACE,UAAU,wDACV,SACA;AACA,QAAM,wBAAwB,SAAS,QAAQ;AAC/C,OAAK,OAAO;;;AAIhB,IAAa,4BAAb,cAA+C,iBAAiB;CAC9D,YACE,UAAU,wDACV,SACA;AACA,QAAM,qBAAqB,SAAS,QAAQ;AAC5C,OAAK,OAAO;;;AAIhB,IAAa,+BAAb,cAAkD,iBAAiB;CACjE,YACE,UAAU,4CACV,SACA;AACA,QAAM,gBAAgB,SAAS,QAAQ;AACvC,OAAK,OAAO;;;AAIhB,IAAa,kCAAb,cAAqD,iBAAiB;CACpE,YACE,UAAU,6CACV,SACA;AACA,QAAM,oBAAoB,SAAS,QAAQ;AAC3C,OAAK,OAAO;;;AAIhB,IAAa,iCAAb,cAAoD,iBAAiB;CACnE,YACE,UAAU,uCACV,SACA;AACA,QAAM,mBAAmB,SAAS,QAAQ;AAC1C,OAAK,OAAO;;;AA+BhB,IAAa,uCAAb,cAA0D,iBAAiB;CACzE,YACE,UAAU,0CACV,SACA;AACA,QAAM,yBAAyB,SAAS,QAAQ;AAChD,OAAK,OAAO;;;;;ACxIhB,MAAa,gCAAgC;AAC7C,MAAa,sBAAsB;AACnC,MAAa,yBAAyB;AAEtC,MAAa,yBAAyB;CACpC,qBAAqB;CACrB,qBAAqB;CACrB,gBAAgB;CAChB,gBAAgB;CAChB,sBAAsB;CACtB,cAAc;CACd,qBAAqB;CACrB,iBAAiB;CACjB,gBAAgB;CACjB;;;AC0BD,SAAgB,sBACd,SACiB;CACjB,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,YAAY,gBAAgB,QAAQ,UAAU;CAEpD,MAAM,iBAAiB,UAAuC;AAC5D,MAAI,MAAM,WAAW,UAAW;AAChC,MAAI,MAAM,WAAW,QAAQ,OAAO,cAAe;AACnD,MAAI,CAAC,iBAAiB,MAAM,KAAK,CAAE;AAE9B,yBAAuB,SAAS,MAAM,MAAM,UAAU;;AAG7D,cAAa,iBAAiB,WAAW,cAAc;AAEvD,QAAO,EACL,eAAe,aAAa,oBAAoB,WAAW,cAAc,EAC1E;;AAGH,eAAe,uBACb,SACA,UACA,WACe;CACf,MAAM,cAAc,QAAQ,OAAO;AACnC,KAAI,CAAC,YAAa;AAElB,KAAI;AACF,yBAAuB,SAAS,SAAS,QAAQ,SAAS;AAE1D,UAAQ,SAAS,MAAjB;GACE,KAAK,uBAAuB,gBAAgB;IAC1C,MAAM,UAAU,MAAM,QAAQ,YAAY;AAC1C,gBAAY,YACV;KACE,IAAI,SAAS;KACb,MAAM,uBAAuB;KAC7B,SAAS;KACV,EAID,UACD;AACD;;GAEF,KAAK,uBAAuB,qBAAqB;IAC/C,MAAM,UAAU,MAAM,QAAQ,YAAY;IAC1C,MAAM,eAAe,MAAM,QAAQ,gBAAgB,QAAQ;AAC3D,QAAI,aAAa,WAAW,EAC1B,OAAM,IAAI,0BACR,wDACD;AAEH,gBAAY,YACV;KACE,IAAI,SAAS;KACb,MAAM,uBAAuB;KAC7B,SAAS,EAAE,cAAc;KAC1B,EAID,UACD;AACD;;GAEF,QACE,OAAM,IAAI,gCACR,8DACA,EAAE,MAAM,SAAS,MAAM,CACxB;;UAEE,OAAO;AACd,cAAY,YACV;GACE,IAAI,SAAS;GACb,MAAM,aAAa,MAAM;GACzB,SAAS,gBAAgB,MAAM;GAChC,EACD,UACD;;;AAIL,SAAS,uBACP,OACA,UACgB;AAChB,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,OAAM,IAAI,+BACR,8CACD;AAEH,KAAI,EAAE,cAAc,UAAU,MAAM,aAAa,SAC/C,OAAM,IAAI,qCACR,qEACD;AAEH,KACE,EAAE,cAAc,UAChB,MAAM,aAAA,UAEN,OAAM,IAAI,qCAAqC;AAEjD,QAAO;;AAGT,SAAS,iBACP,OAC0C;AAC1C,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO;AAET,QACE,QAAQ,SACR,UAAU,SACV,aAAa,SACb,OAAO,MAAM,OAAO,YACpB,OAAO,MAAM,SAAS;;AAI1B,SAAS,aAAa,OAAwB;AAC5C,KAAI,iBAAiB,qCACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,oCACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,6BACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,0BACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,+BACnB,QAAO,uBAAuB;AAEhC,KAAI,iBAAiB,gCACnB,QAAO,uBAAuB;AAEhC,QAAO,uBAAuB;;AAGhC,SAAS,gBAAgB,OAAkC;AACzD,KACE,iBAAiB,SACjB,UAAU,SACV,OAAO,MAAM,SAAS,SAEtB,QAAO;EACL,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,SAAS,aAAa,QAAQ,MAAM,UAAU,KAAA;EAC/C;AAEH,QAAO;EACL,MAAM;EACN,SAAS;EACT,SAAS;EACV;;AAGH,SAAS,gBAAgB,QAAwB;AAC/C,QAAO,IAAI,IAAI,OAAO,CAAC;;;;ACxKzB,MAAM,6BAA6B;AAEnC,eAAsB,0BAA0B,EAC9C,SACA,YACA,WACA,OAAO,sBAAsB,WAAW,OAAO,KAAK,WAAW,IACX;AACpD,KAAI,CAAC,oBACH,OAAM,IAAI,0BACR,+EACD;CAGH,MAAM,WAAW,MAAM,oBACrB,uBAAuB,WAAW,EAClC;EACE,QAAQ;EACR,SAAS,oBAAoB,UAAU;EACvC,MAAM,KAAK,UAAU,wBAAwB,QAAQ,CAAC;EACvD,CACF;CAED,MAAM,OAAgB,MAAM,SAAS,MAAM,CAAC,YAAY,KAAK;AAE7D,KAAI,CAAC,SAAS,GACZ,OAAM,sBAAsB,SAAS,QAAQ,KAAK;AAGpD,KAAI,CAAC,8BAA8B,KAAK,IAAI,KAAK,cAAc,WAAW,EACxE,OAAM,IAAI,0BACR,uEACA,EAAE,MAAM,CACT;AAGH,QAAO,KAAK;;AAGd,SAAgB,+BACd,SACA,WAC8B;AAC9B,QAAO;EACL,UAAU,QAAQ,IAAI;EACtB,OAAO,QAAQ;EACf,WAAW,QAAQ;EACnB,gBAAgB,QAAQ,MAAM;EAC9B,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;EACnC;;AAGH,SAAS,oBAAoB,WAAwC;CACnE,MAAM,UAAU,IAAI,QAAQ;EAC1B,gBAAgB;EAChB,+BAA+B;EAC/B,8BAA8B;EAC9B,0BAA0B;EAC3B,CAAC;AAEF,KAAI,UACF,SAAQ,IAAI,iBAAiB,UAAU,YAAY;AAGrD,QAAO;;AAGT,SAAS,wBACP,SACyB;AACzB,QAAO;EACL,WAAW,QAAQ;EACnB,OAAO,QAAQ;EACf,WAAW,QAAQ,aAAa,EAAE;EAClC,iBAAiB,QAAQ,kBAAkB,EAAE;EAC7C,GAAI,QAAQ,YAAY,EAAE,YAAY,QAAQ,WAAW,GAAG,EAAE;EAC/D;;AAGH,SAAS,uBAAuB,YAAwC;AACtE,KAAI,CAAC,WACH,QAAO,IAAI;AAEb,QAAO,IAAI,IACT,4BACA,oBAAoB,WAAW,CAChC,CAAC,UAAU;;AAGd,SAAS,oBAAoB,KAAqB;AAChD,QAAO,IAAI,SAAS,IAAI,GAAG,MAAM,GAAG,IAAI;;AAG1C,SAAS,8BACP,OACsC;AACtC,QACE,OAAO,UAAU,YACjB,UAAU,QACV,mBAAmB,SACnB,OAAO,MAAM,kBAAkB;;AAInC,SAAS,sBAAsB,QAAgB,MAAsB;CACnE,MAAM,YAAY,sBAAsB,KAAK,GAAG,KAAK,QAAQ,KAAA;CAC7D,MAAM,UACJ,WAAW,WACX;CACF,MAAM,UAAU,WAAW,WAAW;AAEtC,KAAI,WAAW,IACb,QAAO,IAAI,6BAA6B,SAAS,QAAQ;AAE3D,KAAI,WAAW,IACb,QAAO,IAAI,qCAAqC,SAAS,QAAQ;AAEnE,KAAI,WAAW,IACb,QAAO,IAAI,oCAAoC,SAAS,QAAQ;AAElE,QAAO,IAAI,0BAA0B,SAAS,QAAQ;;AAGxD,SAAS,sBAAsB,OAA8C;AAC3E,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,WAAW;;;;;;;;AC5EnE,SAAS,eAAe,WAA4B;AAClD,KAAI;EACF,MAAM,SAAS,IAAI,IAAI,UAAU;AACjC,SAAO,OAAO,aAAa,YAAY,OAAO,aAAa;SACrD;AACN,SAAO;;;AAIX,SAAS,YAAY,KAAa,UAA6C;AAC7E,QAAO,cAAc;EACnB,MAAM,gBACJ,QAAQ,IAAI,WAAW,UAAU,IAAI,IAAI,WAAW,WAAW,IAC3D,MACA,MACE,WAAW,QACX;EAER,IAAI,aAAa;AACjB,MAAI,cACF,KAAI;GACF,MAAM,SAAS,IAAI,IAAI,cAAc;AACrC,iBACG,OAAO,aAAa,WAAW,OAAO,aAAa,cACnD,OAAO,SAAS,SAAS,IAAI,IAAI,OAAO,aAAa;UAClD;AAKV,MAAI,CAAC,cAAc,CAAC,SAClB,QAAO;GAAE;GAAe;GAAY,WAAW;GAAe;EAGhE,MAAM,SAAS,IAAI,IAAI,cAAc;AACrC,SAAO,aAAa,IAAI,aAAa,SAAS;AAC9C,SAAO;GAAE;GAAe;GAAY,WAAW,OAAO,UAAU;GAAE;IACjE,CAAC,KAAK,SAAS,CAAC;;AAUrB,SAAS,eAAe,KAA4B;AAClD,KAAI;AACF,SAAO,IAAI,IAAI,IAAI,CAAC;SACd;AACN,SAAO;;;AAIX,SAAS,0BAA0B,EACjC,WACA,eACA,YACA,YACuC;AACvC,iBAAgB;AACd,MAAI,CAAC,cAAc,SAAU;EAE7B,MAAM,iBAAiB,IAAI,IAAI,cAAc,CAAC;EAE9C,SAAS,cAAc,OAAqB;AAC1C,OAAI,MAAM,WAAW,eAAgB;AACrC,OAAI,MAAM,WAAW,UAAU,SAAS,cAAe;GAEvD,IAAI;AACJ,OAAI,OAAO,MAAM,SAAS,SACxB,KAAI;AACF,WAAO,KAAK,MAAM,MAAM,KAAK;WACvB;AACN;;OAGF,QAAO,MAAM;AAGf,OACE,OAAO,SAAS,YAChB,SAAS,QACT,UAAU,QACT,KAA4B,SAAS,4BACtC;IACA,MAAM,aAAc,KAA4B;AAChD,QAAI,cAAc,eAAe,WAAW,CAC1C,QAAO,KAAK,YAAY,UAAU,sBAAsB;;;AAK9D,SAAO,iBAAiB,WAAW,cAAc;AACjD,eAAa,OAAO,oBAAoB,WAAW,cAAc;IAChE;EAAC;EAAW;EAAe;EAAY;EAAS,CAAC;;AAKtD,SAAS,gBACP,eACA,YACA,UACmB;CACnB,MAAM,CAAC,OAAO,YAAY,SAA4B,OAAO;AAE7D,iBAAgB;AACd,MAAI,CAAC,YAAY,CAAC,YAAY;AAC5B,YAAS,OAAO;AAChB;;AAEF,WAAS,WAAW;EACpB,MAAM,aAAa,IAAI,iBAAiB;EACxC,MAAM,QAAQ,iBAAiB;AAC7B,SAAM,4BAA4B,mBAAmB,cAAc,IAAI,EACrE,QAAQ,WAAW,QACpB,CAAC,CACC,MAAM,QAAS,IAAI,KAAK,IAAI,MAAM,GAAG,KAAM,CAC3C,MAAM,SAAwC;AAC7C,QAAI,WAAW,OAAO,QAAS;AAC/B,QAAI,QAAQ,OAAO,KAAK,aAAa,UACnC,UAAS,KAAK,WAAW,eAAe,UAAU;QAElD,UAAS,OAAO;KAElB,CACD,YAAY;AACX,QAAI,CAAC,WAAW,OAAO,QACrB,UAAS,OAAO;KAElB;KACH,IAAI;AAEP,eAAa;AACX,cAAW,OAAO;AAClB,gBAAa,MAAM;;IAEpB;EAAC;EAAe;EAAY;EAAS,CAAC;AAEzC,QAAO;;AAGT,SAAS,uBAAuB,QAAuB;AACrD,iBAAgB;AACd,MAAI,CAAC,OAAQ;EACb,MAAM,mBAAmB,SAAS,KAAK,MAAM;AAC7C,WAAS,KAAK,MAAM,WAAW;AAC/B,eAAa;AACX,YAAS,KAAK,MAAM,WAAW;;IAEhC,CAAC,OAAO,CAAC;;AAGd,SAAS,oBAAoB,QAAiB,SAA2B;AACvE,iBAAgB;AACd,MAAI,CAAC,OAAQ;EAEb,MAAM,iBAAiB,UAAyB;AAC9C,OAAI,MAAM,QAAQ,SAAU,UAAS;;AAGvC,SAAO,iBAAiB,WAAW,cAAc;AACjD,eAAa,OAAO,oBAAoB,WAAW,cAAc;IAChE,CAAC,QAAQ,QAAQ,CAAC;;AAGvB,SAAS,sBAAsB,WAAgD;AAC7E,iBAAgB;EACd,MAAM,oBACJ,SAAS,yBAAyB,cAC9B,SAAS,gBACT;AACN,YAAU,SAAS,OAAO;AAC1B,eAAa;AACX,sBAAmB,OAAO;;IAE3B,CAAC,UAAU,CAAC;;AAKjB,MAAM,kBAA8C;CAClD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,UAAU;CACX;AAED,MAAM,sBAA+D;CACnE;EAAE,OAAO;EAAkB,OAAO;EAAiB;CACnD;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAQ,OAAO;EAAY;CACpC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAS,OAAO;EAAS;CAClC;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAmB,OAAO;EAAO;CAC1C;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAgB,OAAO;EAAe;CAC/C;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC;AAED,MAAM,iBAAiB,SAAyC;AAC9D,KAAI,CAAC,KAAM,QAAO;AAClB,QAAO,gBAAgB,SAAS;;AAgClC,SAAgB,YAAY,EAC1B,MAAM,IACN,WACA,QAAQ,oBACR,SAAS,SACT,aAAa,OACb,kBAAkB,MAClB,UAAU,QACV,eAAe,MACf,cAAc,QACd,cAAc,SACd,UAAU,WACV,YAAY,aAEZ,cAAc,UACd,eACA,oBAAoB,OACpB,gBAAgB,IAChB,aAAa,IACb,YAAY,IACZ,kBAAkB,MAClB,kBAAkB,iBAClB,uBAAuB,WACvB,cAAc,SAEd,WACA,GAAG,SACmC;CACtC,MAAM,cAAc,sBAAsB;CAC1C,MAAM,WAAW,aAAa,YAAY;CAC1C,MAAM,aAAa,eAAe,YAAY;CAC9C,MAAM,eAAe;CACrB,MAAM,YAAY,OAA0B,KAAK;CACjD,MAAM,UAAU,YAAY;CAC5B,MAAM,WAAW,SAAS;CAC1B,MAAM,EAAE,MAAM,UAAU,kBAAkB;CAE1C,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,EAAE;CACvD,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,EAAE;CAEzD,MAAM,aAAa,kBAAkB,aAAa,MAAM,EAAE,EAAE,CAAC;CAC7D,MAAM,EAAE,MAAM,qBAAqB;CAEnC,MAAM,EAAE,eAAe,YAAY,cAAc,YAAY,KAAK,SAAS;AAC3E,2BAA0B;EACxB;EACA;EACA;EACA;EACD,CAAC;CAEF,MAAM,oBAAoB,WAAW;CACrC,MAAM,qBAAqB,WAAW;CACtC,MAAM,qBAAqB,WAAW;CACtC,MAAM,qBAAqB,WAAW;CACtC,MAAM,sBAAsB,WAAW;CAEvC,MAAM,mBAAmB,cAAoC;AAC3D,MAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,WAAY,QAAO;AAExD,SAAO;GACL,UAAU;GACV,KAAK,EAAE,UAAU,mBAAmB;GACpC,OAAO;IACL,WAAW,MAAM;IACjB,KAAK,WAAW,MAAM,UAAU;IAChC,MAAM,MAAM;IACb;GACD,GAAI,UACA,EACE,OAAO;IACL,MAAM;IACN,GAAI,QAAQ,WAAW,EAAE,MAAM,QAAQ,UAAU,GAAG,EAAE;IACtD,OAAO,EAAE;IACT,aAAa,EAAE;IAChB,EACF,GACD,EAAE;GACN,OAAO;IACL,MAAM,sBAAsB;IAC5B,MAAM,sBAAsB;IAC7B;GACD,WAAW,sBAAsB,EAAE;GACnC,OAAO,EACL,gBAAgB,CACd,eAAe,cAAc,EAC7B,GAAI,uBAAuB,EAAE,CAC9B,CAAC,QAAQ,WAA6B,QAAQ,OAAO,CAAC,EACxD;GACD,KAAK,EAAE,YAAY,wBAAwB;GAC5C;IACA;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;CACF,MAAM,sBAAsB,OAA6B,KAAK;CAC9D,MAAM,wBAAwB,qBAAqB;AAEnD,iBAAgB;AACd,sBAAoB,UAAU;IAC7B,CAAC,iBAAiB,CAAC;CAEtB,MAAM,sBAAsB,kBAAkB;AAC5C,MAAI,CAAC,oBAAoB,QACvB,OAAM,IAAI,MAAM,oCAAoC;AAEtD,SAAO,oBAAoB;IAC1B,EAAE,CAAC;CAEN,MAAM,2BAA2B,aAC9B,kBACC,0BAA0B,EACxB,SAAS,+BAA+B,cAAc,EACvD,CAAC,EACJ,EAAE,CACH;AAED,iBAAgB;AACd,MAAI,CAAC,qBAAqB,CAAC,yBAAyB,SAAU;EAE9D,MAAM,SAAS,UAAU;EACzB,MAAM,YAAY,eAAe,cAAc;AAC/C,MAAI,CAAC,UAAU,CAAC,UAAW;EAE3B,MAAM,OAAO,sBAAsB;GACjC;GACA;GACA,UAAU;GACV,YAAY;GACZ,iBAAiB;GAClB,CAAC;AAEF,eAAa,KAAK,SAAS;IAC1B;EACD;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AACF,wBAAuB,UAAU;AACjC,qBAAoB,WAAW,WAAW;CAC1C,MAAM,eAAe,gBACnB,eACA,YACA,YAAY,gBAAgB,QAC7B;AAID,KAAI,CAAC,OAAO,CAAC,WACX,QACE,oBAAC,OAAD;EACE,WAAW,4CAA4C,aAAa,uEAAuE,aAAa;EACxJ,GAAI;EACJ,OACE,eACI,EACE,QACE,8DACH,GACD,EAAE,QAAQ,gBAAgB,UAAU,cAAc,QAAQ;YAGhE,qBAAC,OAAD;GAAK,WAAU;aAAf;IACE,oBAAC,OAAD,EAAO,WAAU,sBAAuB,CAAA;IACxC,oBAAC,KAAD;KAAG,WAAU;eAAsB;KAE/B,CAAA;IACJ,oBAAC,KAAD;KAAG,WAAU;eAAqB;KAE9B,CAAA;IACA;;EACF,CAAA;AAMV,KAAI,gBAAgB,SAAS;EAC3B,MAAM,qBAAqB,oBACvB,gBACA,eAAe,YAAY,eAAe,aAAa;EAE3D,MAAM,iBAAiB,cAAc;EACrC,MAAM,aAAa,cAAc,gBAAgB;EAEjD,MAAM,wBAAwB;AAC5B,OAAI,SAAU;AACd,gBAAa,KAAK;;EAGpB,MAAM,qBAAqB;AACzB,OAAI,SAAU;AACd,sBAAmB,QAAQ,MAAM,EAAE;;EAGrC,MAAM,oBAAoB,MAAwB;AAChD,KAAE,iBAAiB;AACnB,OAAI,SAAU;AACd,UAAO,KAAK,WAAW,UAAU,sBAAsB;;AAGzD,SACE,qBAAA,YAAA,EAAA,UAAA,CACE,qBAAC,OAAD;GACE,WAAW,2CAA2C,aAAa,GAAG,mBAAmB,aAAa,GAAG,gBAAgB,SAAS,mBAAmB,eAAe,GAAG,iBAAiB,aAAa;GACrM,OAAO,EACL,WACE,2JACH;GACD,GAAI;aANN;IASE,oBAAC,OAAD;KACE,eAAY;KACZ,WAAW,sDAAsD;KACjE,OAAO,EACL,WACE,gFACH;KACD,CAAA;IACD,mBACC,qBAAC,OAAD;KAAK,WAAU;eAAf;MACE,oBAAC,QAAD;OACE,eAAY;OACZ,WAAW,QAAQ,qBAAqB,uEAAuE;OAC/G,OAAO;QACL,YAAY,2DAA2D,qBAAqB,oCAAoC,qBAAqB;QACrJ,WAAW;;;gEAGmC,qBAAqB;;QAEpE;iBAED,oBAAC,YAAD;QAAY,WAAU;QAAW,aAAa;QAAQ,CAAA;OACjD,CAAA;MAEP,qBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,kBACC,oBAAC,MAAD;QAAI,WAAU;kBACX;QACE,CAAA,EAEN,aACC,oBAAC,KAAD;QAAG,WAAU;kBACV;QACC,CAAA,CAEF;;MAEN,qBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,oBAAC,kBAAD;SACE,MAAM;SACN,OAAM;SACN,UAAU,MAAM;AACd,YAAE,iBAAiB;AACnB,wBAAc;;SAEhB,CAAA;QACF,oBAAC,kBAAD;SACE,MAAM;SACN,OAAM;SACN,UAAU,MAAM;AACd,YAAE,iBAAiB;AACnB,2BAAiB;;SAEnB,CAAA;QACF,oBAAC,kBAAD;SACE,MAAM;SACN,OAAM;SACN,SAAS;SACT,CAAA;QACE;;MACF;;IAGR,oBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,UAAU;KACV,WAAW,yCAAyC,WAAW,mBAAmB;KAClF,OAAO,EAAE,QAAQ,aAAa;KAC9B,cAAY,QAAQ,kBAAkB;eAErC,qBACC,oBAAC,OAAD;MAEE,KAAK;MACL,KAAK,kBAAkB;MACvB,WAAU;MACV,EAJK,SAAS,iBAId,GAEF,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,OAAD,EAAO,WAAU,oCAAqC,CAAA;MAClD,CAAA;KAED,CAAA;IACR,YAAY,CAAC,cAAc,oBAAC,OAAD,EAAK,WAAU,yBAA0B,CAAA;IACjE;MAEL,aACC,oBAAC,YAAD;GAEE,KAAK;GACL,OAAO,kBAAkB;GACR;GACN;GACX,SAAS;GACT,gBAAgB,oBAAoB,QAAQ,MAAM,EAAE;GACpD,EAPK,SAAS,kBAOd,CAEH,EAAA,CAAA;;AASP,KAAI,YAAY,iBAAiB,WAAW;EAC1C,IAAI,aAAa;AACjB,MAAI;GACF,MAAM,SAAS,IAAI,IAAI,cAAc;AACrC,gBAAa,GAAG,OAAO,OAAO,OAAO,aAAa,MAAM,KAAK,OAAO;UAC9D;EAGR,MAAM,eAAe,eACjB,+DACA;AAEJ,SACE,oBAAC,OAAD;GACE,WAAW,4CAA4C,aAAa,kFAAkF,aAAa;GACnK,GAAI;GACJ,OAAO,EAAE,QAAQ,cAAc;aAE/B,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD,EAAO,WAAU,wBAAyB,CAAA;KAC1C,oBAAC,KAAD;MAAG,WAAU;gBAAuB,EAAE,sBAAsB;MAAK,CAAA;KACjE,oBAAC,KAAD;MAAG,WAAU;gBAAwC;MAAe,CAAA;KACpE,oBAAC,KAAD;MAAG,WAAU;gBAAsB,EAAE,qBAAqB;MAAK,CAAA;KAC3D;;GACF,CAAA;;AAIV,QACE,qBAAC,OAAD;EACE,WAAW,2BAA2B,aAAa,GAAG,mBAAmB,aAAa,GAAG,gBAAgB,SAAS,mBAAmB,eAAe,GAAG,GAAG,aAAa;EACvK,GAAI;EACJ,OACE,eACI,EACE,QACE,8DACH,GACD,KAAA;YATR,CAYE,oBAAC,UAAD;GACE,KAAK;GACL,KAAK;GACE;GACP,OAAM;GACN,OAAO,eAAe,EAAE,QAAQ,QAAQ,GAAG,EAAE,QAAQ;GAC5C;GACT,iBAAiB;GACjB,WAAW,WAAW,aAAa;GACnC,SAAQ;GACR,CAAA,EACD,YAAY,CAAC,cAAc,oBAAC,OAAD,EAAK,WAAU,yBAA0B,CAAA,CACjE;;;AAYV,SAAS,iBAAiB,EACxB,MACA,OACA,WAC2C;AAC3C,QACE,oBAAC,UAAD;EACE,MAAK;EACI;EACT,cAAY;EACZ,WAAU;YAEV,oBAAC,MAAD;GAAM,WAAU;GAAW,aAAa;GAAQ,CAAA;EACzC,CAAA;;AAeb,SAAS,WAAW,EAClB,KACA,OACA,iBACA,WACA,SACA,YACqC;CACrC,MAAM,YAAY,OAAuB,KAAK;AAE9C,uBAAsB,UAAU;AAKhC,QAAO,aACL,oBAAC,OAAD;EACE,KAAK;EACL,UAAU;EACV,WAAU;EACV,OAAO,EACL,YAAY,2DACb;EACD,SAAS;EACT,MAAK;EACL,cAAW;EACX,cAAY;YAEZ,qBAAC,OAAD;GACE,WAAU;GACV,UAAU,MAAM,EAAE,iBAAiB;aAFrC,CAIE,qBAAC,OAAD;IACE,WAAU;IACV,OAAO,EACL,cACE,0EACH;cALH,CAOE,oBAAC,MAAD;KAAI,WAAU;eACX;KACE,CAAA,EACL,qBAAC,OAAD;KAAK,WAAU;eAAf,CACE,oBAAC,kBAAD;MACE,MAAM;MACN,OAAM;MACN,UAAU,MAAM;AACd,SAAE,iBAAiB;AACnB,iBAAU;;MAEZ,CAAA,EACF,oBAAC,UAAD;MACE,MAAK;MACL,SAAS;MACT,cAAW;MACX,WAAU;gBAEV,oBAAC,GAAD,EAAG,WAAU,UAAW,CAAA;MACjB,CAAA,CACL;OACF;OACN,oBAAC,UAAD;IACE,KAAK;IACA;IACE;IACP,WAAU;IACV,iBAAiB;IACjB,SAAQ;IACR,CAAA,CACE;;EACF,CAAA,EACN,SAAS,KACV;;AAKH,MAAa,4BAAkD;CAC7D,YAAY;CACZ,aAAa;CACb,QAAQ;EAEN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,aAAa;GACb,cAAc;GACd,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,OAAO;GACR;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAU,OAAO;IAAU,EACpC;IAAE,OAAO;IAAiB,OAAO;IAAS,CAC3C;GACD,OAAO;GACR;EAGD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAS;GACzD;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAS;GACzD;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB,CAChB;IAAE,KAAK;IAAe,OAAO;IAAS,EACtC;IAAE,KAAK;IAAqB,OAAO;IAAM,CAC1C;GACF;EACD,eAAe;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAS;GACzD,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAS;GACzD;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,SAAS;GACT,cAAc;GACd,OAAO;GACP,kBAAkB,CAChB;IAAE,KAAK;IAAe,OAAO;IAAS,EACtC;IAAE,KAAK;IAAmB,OAAO;IAAM,CACxC;GACF;EACD,cAAc;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB,CAChB;IAAE,KAAK;IAAe,OAAO;IAAS,EACtC;IAAE,KAAK;IAAmB,OAAO;IAAM,CACxC;GACF,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAS;GACzD;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,OAAO;GACP,kBAAkB,CAChB;IAAE,KAAK;IAAe,OAAO;IAAS,EACtC;IAAE,KAAK;IAAmB,OAAO;IAAM,CACxC;GACF;EAGD,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAU;GAC1D;EACD,eAAe;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,OAAO;GACP,kBAAkB,CAChB;IAAE,KAAK;IAAe,OAAO;IAAU,EACvC;IAAE,KAAK;IAAc,OAAO;IAAO,CACpC;GACF,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,SAAS,CACP;IAAE,OAAO;IAAoB,OAAO;IAAQ,EAC5C;IAAE,OAAO;IAAuB,OAAO;IAAS,CACjD;GACD,cAAc;GACd,OAAO;GACP,kBAAkB;IAAE,KAAK;IAAe,OAAO;IAAU;GAC1D;EACF;CACF"}
@@ -16,12 +16,12 @@ import { t as LayoutWidget } from "./LayoutWidget-C0TbnxQW.mjs";
16
16
  import { t as TextWidget } from "./TextWidget-CRo4AN5-.mjs";
17
17
  import { t as AlertWidget } from "./AlertWidget-B5aibm-v.mjs";
18
18
  import { t as BulletListWidget } from "./BulletListWidget-CSogQ3cu.mjs";
19
- import { t as CalendarWidget } from "./CalendarWidget-CkuTpX1q.mjs";
19
+ import { t as CalendarWidget } from "./CalendarWidget--EIsxRov.mjs";
20
20
  import { t as CardWidget } from "./CardWidget-DdV1HDy0.mjs";
21
21
  import { t as CarouselWidget } from "./CarouselWidget-BTbRZPWn.mjs";
22
22
  import { t as ChartWidget } from "./ChartWidget-B4vLdttP.mjs";
23
23
  import { t as ContainerWidget } from "./ContainerWidget-BKaiiPlW.mjs";
24
- import { t as EmbedWidget } from "./EmbedWidget-BJY7l4pI.mjs";
24
+ import { t as EmbedWidget } from "./EmbedWidget-p_Ybl0em.mjs";
25
25
  import { t as ImageWidget } from "./ImageWidget-WtC8Rg1y.mjs";
26
26
  import { t as LinkWidget } from "./LinkWidget-mKyp0LGz.mjs";
27
27
  import { t as ListWidget } from "./ListWidget-CRzXIlzF.mjs";
@@ -7398,13 +7398,13 @@ function createWidgetFromShareable(item) {
7398
7398
  const widgetPropertySchemas = {
7399
7399
  AlertWidget: () => import("./AlertWidget-B5aibm-v.mjs").then((n) => n.n).then((m) => m.alertWidgetPropertySchema),
7400
7400
  BulletListWidget: () => import("./BulletListWidget-CSogQ3cu.mjs").then((n) => n.n).then((m) => m.bulletListWidgetPropertySchema),
7401
- CalendarWidget: () => import("./CalendarWidget-CkuTpX1q.mjs").then((n) => n.n).then((m) => m.calendarWidgetPropertySchema),
7401
+ CalendarWidget: () => import("./CalendarWidget--EIsxRov.mjs").then((n) => n.n).then((m) => m.calendarWidgetPropertySchema),
7402
7402
  CardWidget: () => import("./CardWidget-DdV1HDy0.mjs").then((n) => n.n).then((m) => m.cardWidgetPropertySchema),
7403
7403
  CarouselWidget: () => import("./CarouselWidget-BTbRZPWn.mjs").then((n) => n.n).then((m) => m.carouselWidgetPropertySchema),
7404
7404
  CatchUpWidget: () => import("./CatchUpWidget-qNrDLfXJ.mjs").then((n) => n.n).then((m) => m.catchUpWidgetPropertySchema),
7405
7405
  ChartWidget: () => import("./ChartWidget-B4vLdttP.mjs").then((n) => n.n).then((m) => m.chartWidgetPropertySchema),
7406
7406
  ContainerWidget: () => import("./ContainerWidget-BKaiiPlW.mjs").then((n) => n.n).then((m) => m.containerWidgetPropertySchema),
7407
- EmbedWidget: () => import("./EmbedWidget-BJY7l4pI.mjs").then((n) => n.n).then((m) => m.embedWidgetPropertySchema),
7407
+ EmbedWidget: () => import("./EmbedWidget-p_Ybl0em.mjs").then((n) => n.n).then((m) => m.embedWidgetPropertySchema),
7408
7408
  ImageWidget: () => import("./ImageWidget-WtC8Rg1y.mjs").then((n) => n.n).then((m) => m.imageWidgetPropertySchema),
7409
7409
  LayoutWidget: () => import("./LayoutWidget-C0TbnxQW.mjs").then((n) => n.n).then((m) => m.layoutWidgetPropertySchema),
7410
7410
  LinkWidget: () => import("./LinkWidget-mKyp0LGz.mjs").then((n) => n.n).then((m) => m.linkWidgetPropertySchema),
@@ -8780,4 +8780,4 @@ function useFluidContext() {
8780
8780
  //#endregion
8781
8781
  export { createPersister as $, DEFAULT_FONT_SIZES as A, parseColor as B, buildThemeDefinition as C, serialiseTheme as D, deserialiseTheme as E, getDefaultThemeDefinition as F, SEMANTIC_COLOR_NAMES as G, FONT_FAMILY_KEYS as H, generateThemeCSS as I, useAddressFieldsApiOptional as J, ApiError as K, deriveDarkVariant as L, DEFAULT_SPACING as M, DEFAULT_THEME_ID as N, DEFAULT_COLORS as O, DEFAULT_THEME_NAME as P, useAppDefinitionApi as Q, getForegroundColor as R, removeTheme as S, transformThemes as T, FONT_SIZE_KEYS as U, resolveTheme as V, RADIUS_KEYS as W, useLanguagesApi as X, useAddressAutocompleteApi as Y, usePayApi as Z, shellEn as _, messagingDomain as a, applyTheme as b, createSubscriptionsTranslationAdapter as c, ordersDomain as d, deleteDatabase as et, DEFAULT_SDK_WIDGET_REGISTRY as f, createWidgetRegistry as g, createWidgetFromShareable as h, createMessagingTranslationAdapter as i, DEFAULT_RADII as j, DEFAULT_FONT_FAMILIES as k, subscriptionsDomain as l, createScreen as m, useFluidContext as n, createProfileTranslationAdapter as o, widgetPropertySchemas as p, isApiError as q, SUPPORTED_LANGUAGES as r, profileDomain as s, FluidProvider as t, createOrdersTranslationAdapter as u, FluidThemeProvider as v, getActiveThemeId as w, removeAllThemes as x, useThemeContext as y, mergeDarkOverrides as z };
8782
8782
 
8783
- //# sourceMappingURL=FluidProvider-YssKGmXj.mjs.map
8783
+ //# sourceMappingURL=FluidProvider-Bmmdax4d.mjs.map