@fluid-app/portal-sdk 0.1.216 → 0.1.217
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.
- package/dist/EmbedWidget-BysWpVIC.cjs +684 -0
- package/dist/EmbedWidget-BysWpVIC.cjs.map +1 -0
- package/dist/EmbedWidget-tU8njf5H.mjs +654 -0
- package/dist/EmbedWidget-tU8njf5H.mjs.map +1 -0
- package/dist/{FluidProvider-D0ZapBR-.mjs → FluidProvider-02beRTpR.mjs} +3 -3
- package/dist/{FluidProvider-D0ZapBR-.mjs.map → FluidProvider-02beRTpR.mjs.map} +1 -1
- package/dist/{FluidProvider-ZbTGc_uY.cjs → FluidProvider-BgFmXtHo.cjs} +3 -3
- package/dist/{FluidProvider-ZbTGc_uY.cjs.map → FluidProvider-BgFmXtHo.cjs.map} +1 -1
- package/dist/{MessagingScreen-CkwCSMou.cjs → MessagingScreen-BkLcqJbs.cjs} +2 -2
- package/dist/{MessagingScreen-CkwCSMou.cjs.map → MessagingScreen-BkLcqJbs.cjs.map} +1 -1
- package/dist/{MessagingScreen-B8azvEc0.mjs → MessagingScreen-CJlVOY5R.mjs} +2 -2
- package/dist/{MessagingScreen-B8azvEc0.mjs.map → MessagingScreen-CJlVOY5R.mjs.map} +1 -1
- package/dist/{MessagingScreen-C5QOgB1w.cjs → MessagingScreen-sN7aBvGk.cjs} +3 -3
- package/dist/{ProfileScreen-DMmfRQp8.cjs → ProfileScreen-Bgo6iTKe.cjs} +3 -3
- package/dist/{ProfileScreen-BhmbCKGd.mjs → ProfileScreen-CNYqUDNB.mjs} +2 -2
- package/dist/{ProfileScreen-BhmbCKGd.mjs.map → ProfileScreen-CNYqUDNB.mjs.map} +1 -1
- package/dist/{ProfileScreen-DsEH0aZU.cjs → ProfileScreen-rPqgsNCc.cjs} +2 -2
- package/dist/{ProfileScreen-DsEH0aZU.cjs.map → ProfileScreen-rPqgsNCc.cjs.map} +1 -1
- package/dist/{ShopScreen-CWCPGEbn.mjs → ShopScreen-B9lHJ8L2.mjs} +2 -2
- package/dist/{ShopScreen-CWCPGEbn.mjs.map → ShopScreen-B9lHJ8L2.mjs.map} +1 -1
- package/dist/{ShopScreen-C6UUeGA9.cjs → ShopScreen-DUHzufCU.cjs} +2 -2
- package/dist/{ShopScreen-C6UUeGA9.cjs.map → ShopScreen-DUHzufCU.cjs.map} +1 -1
- package/dist/{ShopScreen-BBPH0l23.cjs → ShopScreen-g6FQ4R1_.cjs} +3 -3
- package/dist/index.cjs +11 -11
- package/dist/index.d.cts +21 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +21 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +11 -11
- package/package.json +10 -10
- package/dist/EmbedWidget-C3mGurOv.mjs +0 -221
- package/dist/EmbedWidget-C3mGurOv.mjs.map +0 -1
- package/dist/EmbedWidget-PIWoA9sU.cjs +0 -251
- package/dist/EmbedWidget-PIWoA9sU.cjs.map +0 -1
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { r as __exportAll } from "./es-Cw_Kikmu.mjs";
|
|
2
|
-
import { i as getBorderColorField, n as borderWidthClasses, o as getBorderRadiusField, p as getHeightField, s as getBorderWidthField, t as borderColorClasses } from "./registries-DT36l-bR.mjs";
|
|
3
|
-
import { createContext, useContext, useEffect, useMemo, useRef } from "react";
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
-
import { Globe } from "lucide-react";
|
|
6
|
-
//#region ../widgets/src/contexts/RepUserContext.tsx
|
|
7
|
-
const RepUserContext = createContext(null);
|
|
8
|
-
function RepUserProvider({ user, children }) {
|
|
9
|
-
const value = useMemo(() => user, [user]);
|
|
10
|
-
return /* @__PURE__ */ jsx(RepUserContext.Provider, {
|
|
11
|
-
value,
|
|
12
|
-
children
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
function useRepUser() {
|
|
16
|
-
return useContext(RepUserContext);
|
|
17
|
-
}
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region ../widgets/src/widgets/EmbedWidget.tsx
|
|
20
|
-
var EmbedWidget_exports = /* @__PURE__ */ __exportAll({
|
|
21
|
-
EmbedWidget: () => EmbedWidget,
|
|
22
|
-
embedWidgetPropertySchema: () => embedWidgetPropertySchema
|
|
23
|
-
});
|
|
24
|
-
function isValidHttpUrl(urlString) {
|
|
25
|
-
try {
|
|
26
|
-
const parsed = new URL(urlString);
|
|
27
|
-
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
28
|
-
} catch {
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function EmbedWidget({ url = "", title = "Embedded Content", height = "400px", fullScreen = false, allowFullscreen = true, loading = "lazy", borderRadius = "md", borderWidth = "none", borderColor = "muted", editMode = false, isSelected = false, className, ...props }) {
|
|
33
|
-
const isFullScreen = fullScreen;
|
|
34
|
-
const iframeRef = useRef(null);
|
|
35
|
-
const publicId = useRepUser()?.publicId;
|
|
36
|
-
const normalizedUrl = url && (url.startsWith("http://") || url.startsWith("https://")) ? url : url ? `https://${url}` : "";
|
|
37
|
-
let isValidUrl = false;
|
|
38
|
-
if (normalizedUrl) try {
|
|
39
|
-
const parsed = new URL(normalizedUrl);
|
|
40
|
-
isValidUrl = (parsed.protocol === "http:" || parsed.protocol === "https:") && (parsed.hostname.includes(".") || parsed.hostname === "localhost");
|
|
41
|
-
} catch {}
|
|
42
|
-
const iframeSrc = useMemo(() => {
|
|
43
|
-
if (!isValidUrl) return normalizedUrl;
|
|
44
|
-
if (!publicId) return normalizedUrl;
|
|
45
|
-
const urlObj = new URL(normalizedUrl);
|
|
46
|
-
urlObj.searchParams.set("public_id", publicId);
|
|
47
|
-
return urlObj.toString();
|
|
48
|
-
}, [
|
|
49
|
-
normalizedUrl,
|
|
50
|
-
isValidUrl,
|
|
51
|
-
publicId
|
|
52
|
-
]);
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (!isValidUrl || editMode) return;
|
|
55
|
-
const expectedOrigin = new URL(normalizedUrl).origin;
|
|
56
|
-
function handleMessage(event) {
|
|
57
|
-
if (event.origin !== expectedOrigin) return;
|
|
58
|
-
if (event.source !== iframeRef.current?.contentWindow) return;
|
|
59
|
-
let data;
|
|
60
|
-
if (typeof event.data === "string") try {
|
|
61
|
-
data = JSON.parse(event.data);
|
|
62
|
-
} catch {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
else data = event.data;
|
|
66
|
-
if (typeof data === "object" && data !== null && "type" in data && data.type === "OPEN_FULL_SCREEN_WEBVIEW") {
|
|
67
|
-
const messageUrl = data.url;
|
|
68
|
-
if (messageUrl && isValidHttpUrl(messageUrl)) window.open(messageUrl, "_blank", "noopener,noreferrer");
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
window.addEventListener("message", handleMessage);
|
|
72
|
-
return () => window.removeEventListener("message", handleMessage);
|
|
73
|
-
}, [
|
|
74
|
-
normalizedUrl,
|
|
75
|
-
isValidUrl,
|
|
76
|
-
editMode
|
|
77
|
-
]);
|
|
78
|
-
if (!url) return /* @__PURE__ */ jsx("div", {
|
|
79
|
-
className: `flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${isFullScreen ? "h-full" : ""} ${className}`,
|
|
80
|
-
style: isFullScreen ? void 0 : { height },
|
|
81
|
-
...props,
|
|
82
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
83
|
-
className: "flex flex-col items-center gap-2 p-6 text-center",
|
|
84
|
-
children: [
|
|
85
|
-
/* @__PURE__ */ jsx(Globe, { className: "h-12 w-12 opacity-50" }),
|
|
86
|
-
/* @__PURE__ */ jsx("p", {
|
|
87
|
-
className: "text-sm font-medium",
|
|
88
|
-
children: "Enter a URL to embed external content"
|
|
89
|
-
}),
|
|
90
|
-
/* @__PURE__ */ jsx("p", {
|
|
91
|
-
className: "text-xs opacity-75",
|
|
92
|
-
children: "Configure the URL in the properties panel"
|
|
93
|
-
})
|
|
94
|
-
]
|
|
95
|
-
})
|
|
96
|
-
});
|
|
97
|
-
if (!isValidUrl) return /* @__PURE__ */ jsx("div", {
|
|
98
|
-
className: `flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${isFullScreen ? "h-full" : ""} ${className}`,
|
|
99
|
-
style: isFullScreen ? void 0 : { height },
|
|
100
|
-
...props,
|
|
101
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
102
|
-
className: "flex flex-col items-center gap-2 p-6 text-center",
|
|
103
|
-
children: [
|
|
104
|
-
/* @__PURE__ */ jsx(Globe, { className: "h-12 w-12 opacity-50" }),
|
|
105
|
-
/* @__PURE__ */ jsx("p", {
|
|
106
|
-
className: "text-sm font-medium",
|
|
107
|
-
children: "Enter a URL to embed external content"
|
|
108
|
-
}),
|
|
109
|
-
/* @__PURE__ */ jsx("p", {
|
|
110
|
-
className: "text-xs opacity-75",
|
|
111
|
-
children: "Configure the URL in the properties panel"
|
|
112
|
-
})
|
|
113
|
-
]
|
|
114
|
-
})
|
|
115
|
-
});
|
|
116
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
117
|
-
className: `relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== "none" ? borderColorClasses[borderColor] : ""} ${isFullScreen ? "h-full" : ""} ${className}`,
|
|
118
|
-
...props,
|
|
119
|
-
children: [/* @__PURE__ */ jsx("iframe", {
|
|
120
|
-
ref: iframeRef,
|
|
121
|
-
src: iframeSrc,
|
|
122
|
-
title,
|
|
123
|
-
width: "100%",
|
|
124
|
-
style: isFullScreen ? { height: "100%" } : { height },
|
|
125
|
-
loading,
|
|
126
|
-
allowFullScreen: allowFullscreen,
|
|
127
|
-
className: `rounded-${borderRadius} border-border border`,
|
|
128
|
-
sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
|
|
129
|
-
}), editMode && !isSelected && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-10" })]
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
const embedWidgetPropertySchema = {
|
|
133
|
-
widgetType: "EmbedWidget",
|
|
134
|
-
displayName: "Embed",
|
|
135
|
-
fields: [
|
|
136
|
-
{
|
|
137
|
-
key: "url",
|
|
138
|
-
label: "URL",
|
|
139
|
-
type: "text",
|
|
140
|
-
description: "The URL of the external site to embed",
|
|
141
|
-
placeholder: "https://example.com",
|
|
142
|
-
defaultValue: "",
|
|
143
|
-
group: "Content"
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
key: "title",
|
|
147
|
-
label: "Title",
|
|
148
|
-
type: "text",
|
|
149
|
-
description: "Accessibility title for the embedded content",
|
|
150
|
-
defaultValue: "Embedded Content",
|
|
151
|
-
group: "Content"
|
|
152
|
-
},
|
|
153
|
-
getBorderRadiusField({
|
|
154
|
-
key: "borderRadius",
|
|
155
|
-
label: "Border Radius",
|
|
156
|
-
description: "Border radius for the embed container",
|
|
157
|
-
defaultValue: "md",
|
|
158
|
-
group: "Design"
|
|
159
|
-
}),
|
|
160
|
-
getBorderWidthField({
|
|
161
|
-
key: "borderWidth",
|
|
162
|
-
label: "Border Width",
|
|
163
|
-
description: "Border width for the widget",
|
|
164
|
-
defaultValue: "none",
|
|
165
|
-
group: "Design"
|
|
166
|
-
}),
|
|
167
|
-
getBorderColorField({
|
|
168
|
-
key: "borderColor",
|
|
169
|
-
label: "Border Color",
|
|
170
|
-
description: "Border color for the widget",
|
|
171
|
-
defaultValue: "muted",
|
|
172
|
-
group: "Design"
|
|
173
|
-
}),
|
|
174
|
-
{
|
|
175
|
-
key: "fullScreen",
|
|
176
|
-
label: "Full Screen",
|
|
177
|
-
type: "boolean",
|
|
178
|
-
description: "When enabled, the embed fills the available space",
|
|
179
|
-
defaultValue: false,
|
|
180
|
-
group: "Design"
|
|
181
|
-
},
|
|
182
|
-
getHeightField({
|
|
183
|
-
key: "height",
|
|
184
|
-
label: "Height",
|
|
185
|
-
description: "Height of the embedded iframe",
|
|
186
|
-
defaultValue: "400px",
|
|
187
|
-
group: "Design",
|
|
188
|
-
requiresKeyValue: {
|
|
189
|
-
key: "fullScreen",
|
|
190
|
-
value: false
|
|
191
|
-
}
|
|
192
|
-
}),
|
|
193
|
-
{
|
|
194
|
-
key: "allowFullscreen",
|
|
195
|
-
label: "Allow Fullscreen",
|
|
196
|
-
type: "boolean",
|
|
197
|
-
description: "Allow the embedded content to use fullscreen mode",
|
|
198
|
-
defaultValue: true,
|
|
199
|
-
group: "Settings"
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
key: "loading",
|
|
203
|
-
label: "Loading",
|
|
204
|
-
type: "select",
|
|
205
|
-
description: "When to load the embedded content",
|
|
206
|
-
options: [{
|
|
207
|
-
label: "Lazy (on scroll)",
|
|
208
|
-
value: "lazy"
|
|
209
|
-
}, {
|
|
210
|
-
label: "Eager (immediately)",
|
|
211
|
-
value: "eager"
|
|
212
|
-
}],
|
|
213
|
-
defaultValue: "lazy",
|
|
214
|
-
group: "Settings"
|
|
215
|
-
}
|
|
216
|
-
]
|
|
217
|
-
};
|
|
218
|
-
//#endregion
|
|
219
|
-
export { useRepUser as a, RepUserProvider as i, EmbedWidget_exports as n, embedWidgetPropertySchema as r, EmbedWidget as t };
|
|
220
|
-
|
|
221
|
-
//# sourceMappingURL=EmbedWidget-C3mGurOv.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedWidget-C3mGurOv.mjs","names":[],"sources":["../../widgets/src/contexts/RepUserContext.tsx","../../widgets/src/widgets/EmbedWidget.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\";\n\nexport interface RepUser {\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n publicId?: string;\n}\n\nconst RepUserContext = createContext<RepUser | null>(null);\n\nexport interface RepUserProviderProps {\n user: RepUser;\n children: ReactNode;\n}\n\nexport function RepUserProvider({\n user,\n children,\n}: RepUserProviderProps): React.JSX.Element {\n const value = useMemo(() => user, [user]);\n return (\n <RepUserContext.Provider value={value}>{children}</RepUserContext.Provider>\n );\n}\n\nexport function useRepUser(): RepUser | null {\n return useContext(RepUserContext);\n}\n","import { Globe } from \"lucide-react\";\nimport { useEffect, useMemo, useRef, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\n\ntype EmbedWidgetMessage = {\n type: \"OPEN_FULL_SCREEN_WEBVIEW\";\n url: 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\ntype EmbedWidgetProps = ComponentProps<\"div\"> & {\n url?: string;\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 editMode?: boolean;\n isSelected?: boolean;\n};\n\nexport function EmbedWidget({\n url = \"\",\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 = false,\n isSelected = false,\n className,\n ...props\n}: EmbedWidgetProps): React.JSX.Element {\n const isFullScreen = fullScreen;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const repUser = useRepUser();\n const publicId = repUser?.publicId;\n\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 const iframeSrc = useMemo(() => {\n if (!isValidUrl) return normalizedUrl;\n if (!publicId) return normalizedUrl;\n const urlObj = new URL(normalizedUrl);\n urlObj.searchParams.set(\"public_id\", publicId);\n return urlObj.toString();\n }, [normalizedUrl, isValidUrl, publicId]);\n\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 }, [normalizedUrl, isValidUrl, editMode]);\n\n if (!url) {\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${isFullScreen ? \"h-full\" : \"\"} ${className}`}\n style={isFullScreen ? undefined : { height }}\n {...props}\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\">\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 if (!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 ${isFullScreen ? \"h-full\" : \"\"} ${className}`}\n style={isFullScreen ? undefined : { height }}\n {...props}\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\">\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 return (\n <div\n className={`relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${isFullScreen ? \"h-full\" : \"\"} ${className}`}\n {...props}\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\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: \"Title\",\n type: \"text\",\n description: \"Accessibility title for the embedded content\",\n defaultValue: \"Embedded Content\",\n group: \"Content\",\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: \"When enabled, the embed fills the available space\",\n defaultValue: false,\n group: \"Design\",\n },\n getHeightField({\n key: \"height\",\n label: \"Height\",\n description: \"Height of the embedded iframe\",\n defaultValue: \"400px\",\n group: \"Design\",\n requiresKeyValue: {\n key: \"fullScreen\",\n 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\",\n options: [\n { label: \"Lazy (on scroll)\", value: \"lazy\" },\n { label: \"Eager (immediately)\", value: \"eager\" },\n ],\n defaultValue: \"lazy\",\n group: \"Settings\",\n },\n ],\n};\n"],"mappings":"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"}
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
const require_chunk = require("./chunk-9hOWP6kD.cjs");
|
|
2
|
-
const require_registries = require("./registries-CpUM406S.cjs");
|
|
3
|
-
let react = require("react");
|
|
4
|
-
react = require_chunk.__toESM(react);
|
|
5
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
-
let lucide_react = require("lucide-react");
|
|
7
|
-
//#region ../widgets/src/contexts/RepUserContext.tsx
|
|
8
|
-
const RepUserContext = (0, react.createContext)(null);
|
|
9
|
-
function RepUserProvider({ user, children }) {
|
|
10
|
-
const value = (0, react.useMemo)(() => user, [user]);
|
|
11
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RepUserContext.Provider, {
|
|
12
|
-
value,
|
|
13
|
-
children
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
function useRepUser() {
|
|
17
|
-
return (0, react.useContext)(RepUserContext);
|
|
18
|
-
}
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region ../widgets/src/widgets/EmbedWidget.tsx
|
|
21
|
-
var EmbedWidget_exports = /* @__PURE__ */ require_chunk.__exportAll({
|
|
22
|
-
EmbedWidget: () => EmbedWidget,
|
|
23
|
-
embedWidgetPropertySchema: () => embedWidgetPropertySchema
|
|
24
|
-
});
|
|
25
|
-
function isValidHttpUrl(urlString) {
|
|
26
|
-
try {
|
|
27
|
-
const parsed = new URL(urlString);
|
|
28
|
-
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
29
|
-
} catch {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function EmbedWidget({ url = "", title = "Embedded Content", height = "400px", fullScreen = false, allowFullscreen = true, loading = "lazy", borderRadius = "md", borderWidth = "none", borderColor = "muted", editMode = false, isSelected = false, className, ...props }) {
|
|
34
|
-
const isFullScreen = fullScreen;
|
|
35
|
-
const iframeRef = (0, react.useRef)(null);
|
|
36
|
-
const publicId = useRepUser()?.publicId;
|
|
37
|
-
const normalizedUrl = url && (url.startsWith("http://") || url.startsWith("https://")) ? url : url ? `https://${url}` : "";
|
|
38
|
-
let isValidUrl = false;
|
|
39
|
-
if (normalizedUrl) try {
|
|
40
|
-
const parsed = new URL(normalizedUrl);
|
|
41
|
-
isValidUrl = (parsed.protocol === "http:" || parsed.protocol === "https:") && (parsed.hostname.includes(".") || parsed.hostname === "localhost");
|
|
42
|
-
} catch {}
|
|
43
|
-
const iframeSrc = (0, react.useMemo)(() => {
|
|
44
|
-
if (!isValidUrl) return normalizedUrl;
|
|
45
|
-
if (!publicId) return normalizedUrl;
|
|
46
|
-
const urlObj = new URL(normalizedUrl);
|
|
47
|
-
urlObj.searchParams.set("public_id", publicId);
|
|
48
|
-
return urlObj.toString();
|
|
49
|
-
}, [
|
|
50
|
-
normalizedUrl,
|
|
51
|
-
isValidUrl,
|
|
52
|
-
publicId
|
|
53
|
-
]);
|
|
54
|
-
(0, react.useEffect)(() => {
|
|
55
|
-
if (!isValidUrl || editMode) return;
|
|
56
|
-
const expectedOrigin = new URL(normalizedUrl).origin;
|
|
57
|
-
function handleMessage(event) {
|
|
58
|
-
if (event.origin !== expectedOrigin) return;
|
|
59
|
-
if (event.source !== iframeRef.current?.contentWindow) return;
|
|
60
|
-
let data;
|
|
61
|
-
if (typeof event.data === "string") try {
|
|
62
|
-
data = JSON.parse(event.data);
|
|
63
|
-
} catch {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
else data = event.data;
|
|
67
|
-
if (typeof data === "object" && data !== null && "type" in data && data.type === "OPEN_FULL_SCREEN_WEBVIEW") {
|
|
68
|
-
const messageUrl = data.url;
|
|
69
|
-
if (messageUrl && isValidHttpUrl(messageUrl)) window.open(messageUrl, "_blank", "noopener,noreferrer");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
window.addEventListener("message", handleMessage);
|
|
73
|
-
return () => window.removeEventListener("message", handleMessage);
|
|
74
|
-
}, [
|
|
75
|
-
normalizedUrl,
|
|
76
|
-
isValidUrl,
|
|
77
|
-
editMode
|
|
78
|
-
]);
|
|
79
|
-
if (!url) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
80
|
-
className: `flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${isFullScreen ? "h-full" : ""} ${className}`,
|
|
81
|
-
style: isFullScreen ? void 0 : { height },
|
|
82
|
-
...props,
|
|
83
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
84
|
-
className: "flex flex-col items-center gap-2 p-6 text-center",
|
|
85
|
-
children: [
|
|
86
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Globe, { className: "h-12 w-12 opacity-50" }),
|
|
87
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
88
|
-
className: "text-sm font-medium",
|
|
89
|
-
children: "Enter a URL to embed external content"
|
|
90
|
-
}),
|
|
91
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
92
|
-
className: "text-xs opacity-75",
|
|
93
|
-
children: "Configure the URL in the properties panel"
|
|
94
|
-
})
|
|
95
|
-
]
|
|
96
|
-
})
|
|
97
|
-
});
|
|
98
|
-
if (!isValidUrl) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
99
|
-
className: `flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${isFullScreen ? "h-full" : ""} ${className}`,
|
|
100
|
-
style: isFullScreen ? void 0 : { height },
|
|
101
|
-
...props,
|
|
102
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
103
|
-
className: "flex flex-col items-center gap-2 p-6 text-center",
|
|
104
|
-
children: [
|
|
105
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Globe, { className: "h-12 w-12 opacity-50" }),
|
|
106
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
107
|
-
className: "text-sm font-medium",
|
|
108
|
-
children: "Enter a URL to embed external content"
|
|
109
|
-
}),
|
|
110
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
111
|
-
className: "text-xs opacity-75",
|
|
112
|
-
children: "Configure the URL in the properties panel"
|
|
113
|
-
})
|
|
114
|
-
]
|
|
115
|
-
})
|
|
116
|
-
});
|
|
117
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
118
|
-
className: `relative w-full rounded-${borderRadius} ${require_registries.borderWidthClasses[borderWidth]} ${borderWidth !== "none" ? require_registries.borderColorClasses[borderColor] : ""} ${isFullScreen ? "h-full" : ""} ${className}`,
|
|
119
|
-
...props,
|
|
120
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
121
|
-
ref: iframeRef,
|
|
122
|
-
src: iframeSrc,
|
|
123
|
-
title,
|
|
124
|
-
width: "100%",
|
|
125
|
-
style: isFullScreen ? { height: "100%" } : { height },
|
|
126
|
-
loading,
|
|
127
|
-
allowFullScreen: allowFullscreen,
|
|
128
|
-
className: `rounded-${borderRadius} border-border border`,
|
|
129
|
-
sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
|
|
130
|
-
}), editMode && !isSelected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "absolute inset-0 z-10" })]
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
const embedWidgetPropertySchema = {
|
|
134
|
-
widgetType: "EmbedWidget",
|
|
135
|
-
displayName: "Embed",
|
|
136
|
-
fields: [
|
|
137
|
-
{
|
|
138
|
-
key: "url",
|
|
139
|
-
label: "URL",
|
|
140
|
-
type: "text",
|
|
141
|
-
description: "The URL of the external site to embed",
|
|
142
|
-
placeholder: "https://example.com",
|
|
143
|
-
defaultValue: "",
|
|
144
|
-
group: "Content"
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
key: "title",
|
|
148
|
-
label: "Title",
|
|
149
|
-
type: "text",
|
|
150
|
-
description: "Accessibility title for the embedded content",
|
|
151
|
-
defaultValue: "Embedded Content",
|
|
152
|
-
group: "Content"
|
|
153
|
-
},
|
|
154
|
-
require_registries.getBorderRadiusField({
|
|
155
|
-
key: "borderRadius",
|
|
156
|
-
label: "Border Radius",
|
|
157
|
-
description: "Border radius for the embed container",
|
|
158
|
-
defaultValue: "md",
|
|
159
|
-
group: "Design"
|
|
160
|
-
}),
|
|
161
|
-
require_registries.getBorderWidthField({
|
|
162
|
-
key: "borderWidth",
|
|
163
|
-
label: "Border Width",
|
|
164
|
-
description: "Border width for the widget",
|
|
165
|
-
defaultValue: "none",
|
|
166
|
-
group: "Design"
|
|
167
|
-
}),
|
|
168
|
-
require_registries.getBorderColorField({
|
|
169
|
-
key: "borderColor",
|
|
170
|
-
label: "Border Color",
|
|
171
|
-
description: "Border color for the widget",
|
|
172
|
-
defaultValue: "muted",
|
|
173
|
-
group: "Design"
|
|
174
|
-
}),
|
|
175
|
-
{
|
|
176
|
-
key: "fullScreen",
|
|
177
|
-
label: "Full Screen",
|
|
178
|
-
type: "boolean",
|
|
179
|
-
description: "When enabled, the embed fills the available space",
|
|
180
|
-
defaultValue: false,
|
|
181
|
-
group: "Design"
|
|
182
|
-
},
|
|
183
|
-
require_registries.getHeightField({
|
|
184
|
-
key: "height",
|
|
185
|
-
label: "Height",
|
|
186
|
-
description: "Height of the embedded iframe",
|
|
187
|
-
defaultValue: "400px",
|
|
188
|
-
group: "Design",
|
|
189
|
-
requiresKeyValue: {
|
|
190
|
-
key: "fullScreen",
|
|
191
|
-
value: false
|
|
192
|
-
}
|
|
193
|
-
}),
|
|
194
|
-
{
|
|
195
|
-
key: "allowFullscreen",
|
|
196
|
-
label: "Allow Fullscreen",
|
|
197
|
-
type: "boolean",
|
|
198
|
-
description: "Allow the embedded content to use fullscreen mode",
|
|
199
|
-
defaultValue: true,
|
|
200
|
-
group: "Settings"
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
key: "loading",
|
|
204
|
-
label: "Loading",
|
|
205
|
-
type: "select",
|
|
206
|
-
description: "When to load the embedded content",
|
|
207
|
-
options: [{
|
|
208
|
-
label: "Lazy (on scroll)",
|
|
209
|
-
value: "lazy"
|
|
210
|
-
}, {
|
|
211
|
-
label: "Eager (immediately)",
|
|
212
|
-
value: "eager"
|
|
213
|
-
}],
|
|
214
|
-
defaultValue: "lazy",
|
|
215
|
-
group: "Settings"
|
|
216
|
-
}
|
|
217
|
-
]
|
|
218
|
-
};
|
|
219
|
-
//#endregion
|
|
220
|
-
Object.defineProperty(exports, "EmbedWidget", {
|
|
221
|
-
enumerable: true,
|
|
222
|
-
get: function() {
|
|
223
|
-
return EmbedWidget;
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
Object.defineProperty(exports, "EmbedWidget_exports", {
|
|
227
|
-
enumerable: true,
|
|
228
|
-
get: function() {
|
|
229
|
-
return EmbedWidget_exports;
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
Object.defineProperty(exports, "RepUserProvider", {
|
|
233
|
-
enumerable: true,
|
|
234
|
-
get: function() {
|
|
235
|
-
return RepUserProvider;
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
Object.defineProperty(exports, "embedWidgetPropertySchema", {
|
|
239
|
-
enumerable: true,
|
|
240
|
-
get: function() {
|
|
241
|
-
return embedWidgetPropertySchema;
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
Object.defineProperty(exports, "useRepUser", {
|
|
245
|
-
enumerable: true,
|
|
246
|
-
get: function() {
|
|
247
|
-
return useRepUser;
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
//# sourceMappingURL=EmbedWidget-PIWoA9sU.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EmbedWidget-PIWoA9sU.cjs","names":["Globe","borderWidthClasses","borderColorClasses","getBorderRadiusField","getBorderWidthField","getBorderColorField","getHeightField"],"sources":["../../widgets/src/contexts/RepUserContext.tsx","../../widgets/src/widgets/EmbedWidget.tsx"],"sourcesContent":["import React, {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\";\n\nexport interface RepUser {\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n publicId?: string;\n}\n\nconst RepUserContext = createContext<RepUser | null>(null);\n\nexport interface RepUserProviderProps {\n user: RepUser;\n children: ReactNode;\n}\n\nexport function RepUserProvider({\n user,\n children,\n}: RepUserProviderProps): React.JSX.Element {\n const value = useMemo(() => user, [user]);\n return (\n <RepUserContext.Provider value={value}>{children}</RepUserContext.Provider>\n );\n}\n\nexport function useRepUser(): RepUser | null {\n return useContext(RepUserContext);\n}\n","import { Globe } from \"lucide-react\";\nimport { useEffect, useMemo, useRef, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n getBorderRadiusField,\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n} from \"../core/fields\";\nimport { useRepUser } from \"../contexts/RepUserContext\";\n\ntype EmbedWidgetMessage = {\n type: \"OPEN_FULL_SCREEN_WEBVIEW\";\n url: 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\ntype EmbedWidgetProps = ComponentProps<\"div\"> & {\n url?: string;\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 editMode?: boolean;\n isSelected?: boolean;\n};\n\nexport function EmbedWidget({\n url = \"\",\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 = false,\n isSelected = false,\n className,\n ...props\n}: EmbedWidgetProps): React.JSX.Element {\n const isFullScreen = fullScreen;\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const repUser = useRepUser();\n const publicId = repUser?.publicId;\n\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 const iframeSrc = useMemo(() => {\n if (!isValidUrl) return normalizedUrl;\n if (!publicId) return normalizedUrl;\n const urlObj = new URL(normalizedUrl);\n urlObj.searchParams.set(\"public_id\", publicId);\n return urlObj.toString();\n }, [normalizedUrl, isValidUrl, publicId]);\n\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 }, [normalizedUrl, isValidUrl, editMode]);\n\n if (!url) {\n return (\n <div\n className={`flex items-center justify-center rounded-${borderRadius} border-border bg-muted text-muted-foreground border-2 border-dashed ${isFullScreen ? \"h-full\" : \"\"} ${className}`}\n style={isFullScreen ? undefined : { height }}\n {...props}\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\">\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 if (!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 ${isFullScreen ? \"h-full\" : \"\"} ${className}`}\n style={isFullScreen ? undefined : { height }}\n {...props}\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\">\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 return (\n <div\n className={`relative w-full rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} ${isFullScreen ? \"h-full\" : \"\"} ${className}`}\n {...props}\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\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: \"Title\",\n type: \"text\",\n description: \"Accessibility title for the embedded content\",\n defaultValue: \"Embedded Content\",\n group: \"Content\",\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: \"When enabled, the embed fills the available space\",\n defaultValue: false,\n group: \"Design\",\n },\n getHeightField({\n key: \"height\",\n label: \"Height\",\n description: \"Height of the embedded iframe\",\n defaultValue: \"400px\",\n group: \"Design\",\n requiresKeyValue: {\n key: \"fullScreen\",\n 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\",\n options: [\n { label: \"Lazy (on scroll)\", value: \"lazy\" },\n { label: \"Eager (immediately)\", value: \"eager\" },\n ],\n defaultValue: \"lazy\",\n group: \"Settings\",\n },\n ],\n};\n"],"mappings":"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"}
|