cyrus-studio 1.0.6 → 1.0.8
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/README.md +107 -65
- package/bin/mcp-server.js +394 -0
- package/dist/index.cjs +1167 -0
- package/dist/index.d.ts +351 -0
- package/dist/index.js +41 -0
- package/dist/index.mjs +1137 -0
- package/dist/protocol.d.ts +35 -0
- package/dist/protocol.js +31 -0
- package/dist/src/index.d.ts +1176 -0
- package/dist/src/index.js +41 -0
- package/package.json +39 -50
- package/dist/assets/AuthDialog-bjTyuBr7.js +0 -1
- package/dist/assets/CanvaSaveModal-BfM3xRxS.js +0 -1
- package/dist/assets/CodingWorkspace-BKcqDIZx.js +0 -6
- package/dist/assets/CreateAppDialog-D8utCQ_b.js +0 -1236
- package/dist/assets/CreateProjectDialog-BVn3XyiE.js +0 -1
- package/dist/assets/HistoryTimelineDialog-B6LM34kT.js +0 -1
- package/dist/assets/ImportModal-B5pjYSjk.js +0 -83
- package/dist/assets/KeyboardShortcutsDialog-azy2kfng.js +0 -1
- package/dist/assets/LiveRuntimeWorkspace-CFPr1I0-.js +0 -1
- package/dist/assets/ShareExportDialog-BrQois88.js +0 -1
- package/dist/assets/UserProfileDialog-B2TENVlq.js +0 -1
- package/dist/assets/WelcomeOnboardingModal-Dyig1GK1.js +0 -1
- package/dist/assets/index-Cc_706Lp.css +0 -2
- package/dist/assets/index-DM7S-Aaa.js +0 -793
- package/dist/assets/reactTsGenerator-CpUD2_5K.js +0 -1330
- package/dist/assets/rolldown-runtime-Dd_uD5pT.js +0 -1
- package/dist/assets/themes-Iute1uX4.js +0 -1
- package/dist/assets/typechecker-BbGTunMD.js +0 -2
- package/dist/assets/vendor-firebase-DNMzpOGz.js +0 -32
- package/dist/assets/vendor-icons-CT-OIlA-.js +0 -13
- package/dist/assets/vendor-jszip-BhaZ3FnA.js +0 -2
- package/dist/assets/vendor-react-DVnpuVEx.js +0 -227
- package/dist/assets/vendor-utils-BqqQ8OQf.js +0 -1
- package/dist/favicon.svg +0 -1
- package/dist/icons.svg +0 -24
- package/dist/index.html +0 -50
- package/dist/login-bg.png +0 -0
- package/dist/test-sdk-sandbox.html +0 -125
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export type CyrusElementType =
|
|
4
|
+
| 'text'
|
|
5
|
+
| 'heading'
|
|
6
|
+
| 'paragraph'
|
|
7
|
+
| 'button'
|
|
8
|
+
| 'badge'
|
|
9
|
+
| 'avatar'
|
|
10
|
+
| 'icon'
|
|
11
|
+
| 'image'
|
|
12
|
+
| 'video'
|
|
13
|
+
| 'svg'
|
|
14
|
+
| 'container'
|
|
15
|
+
| 'box'
|
|
16
|
+
| 'form'
|
|
17
|
+
| 'formField'
|
|
18
|
+
| 'input'
|
|
19
|
+
| 'textarea'
|
|
20
|
+
| 'searchBar'
|
|
21
|
+
| 'select'
|
|
22
|
+
| 'checkbox'
|
|
23
|
+
| 'switch'
|
|
24
|
+
| 'toggleSwitch'
|
|
25
|
+
| 'navbar'
|
|
26
|
+
| 'sidebar'
|
|
27
|
+
| 'bottomNav'
|
|
28
|
+
| 'tabs'
|
|
29
|
+
| 'card'
|
|
30
|
+
| 'metricCard'
|
|
31
|
+
| 'pricingCard'
|
|
32
|
+
| 'featureCard'
|
|
33
|
+
| 'testimonialCard'
|
|
34
|
+
| 'productCard'
|
|
35
|
+
| 'hero'
|
|
36
|
+
| 'heroSection'
|
|
37
|
+
| 'featureSection'
|
|
38
|
+
| 'faq'
|
|
39
|
+
| 'cta'
|
|
40
|
+
| 'footer'
|
|
41
|
+
| 'chart'
|
|
42
|
+
| 'lineChart'
|
|
43
|
+
| 'barChart'
|
|
44
|
+
| 'areaChart'
|
|
45
|
+
| 'pieChart'
|
|
46
|
+
| 'statCard'
|
|
47
|
+
| 'kpiCard'
|
|
48
|
+
| 'metric'
|
|
49
|
+
| 'table'
|
|
50
|
+
| 'dataTable'
|
|
51
|
+
| (string & {});
|
|
52
|
+
|
|
53
|
+
export interface CyrusIRStyleProperties {
|
|
54
|
+
width?: string | number;
|
|
55
|
+
height?: string | number;
|
|
56
|
+
backgroundColor?: string;
|
|
57
|
+
backgroundGradient?: string;
|
|
58
|
+
textColor?: string;
|
|
59
|
+
fontSize?: number;
|
|
60
|
+
fontWeight?: string;
|
|
61
|
+
borderRadius?: number;
|
|
62
|
+
borderWidth?: number;
|
|
63
|
+
borderColor?: string;
|
|
64
|
+
padding?: number;
|
|
65
|
+
paddingTop?: number;
|
|
66
|
+
paddingRight?: number;
|
|
67
|
+
paddingBottom?: number;
|
|
68
|
+
paddingLeft?: number;
|
|
69
|
+
opacity?: number;
|
|
70
|
+
objectFit?: 'cover' | 'contain' | 'fill';
|
|
71
|
+
shadow?: string;
|
|
72
|
+
[key: string]: any;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface CyrusIRContentProperties {
|
|
76
|
+
text?: string;
|
|
77
|
+
title?: string;
|
|
78
|
+
headline?: string;
|
|
79
|
+
subhead?: string;
|
|
80
|
+
subtitle?: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
badge?: string;
|
|
83
|
+
brandName?: string;
|
|
84
|
+
buttonText?: string;
|
|
85
|
+
secondaryButtonText?: string;
|
|
86
|
+
planName?: string;
|
|
87
|
+
price?: string;
|
|
88
|
+
value?: string;
|
|
89
|
+
trend?: string;
|
|
90
|
+
quote?: string;
|
|
91
|
+
author?: string;
|
|
92
|
+
role?: string;
|
|
93
|
+
imageUrl?: string;
|
|
94
|
+
src?: string;
|
|
95
|
+
url?: string;
|
|
96
|
+
icon?: string;
|
|
97
|
+
links?: string[];
|
|
98
|
+
features?: string[];
|
|
99
|
+
question?: string;
|
|
100
|
+
answer?: string;
|
|
101
|
+
rating?: number;
|
|
102
|
+
[key: string]: any;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface CyrusIRElement {
|
|
106
|
+
id?: string;
|
|
107
|
+
type: CyrusElementType;
|
|
108
|
+
name?: string;
|
|
109
|
+
x?: number;
|
|
110
|
+
y?: number;
|
|
111
|
+
width?: number;
|
|
112
|
+
height?: number;
|
|
113
|
+
styles?: CyrusIRStyleProperties;
|
|
114
|
+
content?: CyrusIRContentProperties;
|
|
115
|
+
children?: CyrusIRElement[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface CyrusIRPage {
|
|
119
|
+
id?: string;
|
|
120
|
+
name?: string;
|
|
121
|
+
slug?: string;
|
|
122
|
+
backgroundColor?: string;
|
|
123
|
+
elements: CyrusIRElement[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface CyrusIRDocument {
|
|
127
|
+
version: '1.0';
|
|
128
|
+
projectTitle: string;
|
|
129
|
+
type?: 'webapp' | 'website' | 'dashboard' | 'landing' | 'mobile';
|
|
130
|
+
theme?: 'light' | 'dark' | 'system';
|
|
131
|
+
palette?: {
|
|
132
|
+
primary?: string;
|
|
133
|
+
secondary?: string;
|
|
134
|
+
background?: string;
|
|
135
|
+
surface?: string;
|
|
136
|
+
text?: string;
|
|
137
|
+
};
|
|
138
|
+
pages: CyrusIRPage[];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── 1. MCP Types ──────────────────────────────────────────────────
|
|
142
|
+
export interface CyrusMCPToolDefinition {
|
|
143
|
+
name: string;
|
|
144
|
+
description: string;
|
|
145
|
+
inputSchema: {
|
|
146
|
+
type: 'object';
|
|
147
|
+
properties: Record<string, any>;
|
|
148
|
+
required?: string[];
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface CyrusMCPToolCall {
|
|
153
|
+
id?: string;
|
|
154
|
+
name: string;
|
|
155
|
+
arguments: Record<string, any>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface CyrusMCPToolResult {
|
|
159
|
+
toolCallId?: string;
|
|
160
|
+
success: boolean;
|
|
161
|
+
data?: any;
|
|
162
|
+
error?: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export declare const CYRUS_MCP_TOOL_DEFINITIONS: CyrusMCPToolDefinition[];
|
|
166
|
+
export declare function executeCyrusMCPTool(controller: any, toolCall: CyrusMCPToolCall): Promise<CyrusMCPToolResult>;
|
|
167
|
+
|
|
168
|
+
// ─── 2. Design Token Types ─────────────────────────────────────────
|
|
169
|
+
export interface CyrusDesignTokens {
|
|
170
|
+
preset?: 'shadcn-zinc' | 'shadcn-slate' | 'shadcn-violet' | 'shadcn-rose' | 'apple-hig' | 'tailwind-cyberpunk' | 'custom';
|
|
171
|
+
colors?: {
|
|
172
|
+
primary?: string;
|
|
173
|
+
primaryForeground?: string;
|
|
174
|
+
secondary?: string;
|
|
175
|
+
secondaryForeground?: string;
|
|
176
|
+
accent?: string;
|
|
177
|
+
accentForeground?: string;
|
|
178
|
+
background?: string;
|
|
179
|
+
foreground?: string;
|
|
180
|
+
surface?: string;
|
|
181
|
+
card?: string;
|
|
182
|
+
cardForeground?: string;
|
|
183
|
+
muted?: string;
|
|
184
|
+
mutedForeground?: string;
|
|
185
|
+
border?: string;
|
|
186
|
+
ring?: string;
|
|
187
|
+
[key: string]: string | undefined;
|
|
188
|
+
};
|
|
189
|
+
typography?: {
|
|
190
|
+
fontFamilySans?: string;
|
|
191
|
+
fontFamilyMono?: string;
|
|
192
|
+
fontFamilyHeading?: string;
|
|
193
|
+
baseFontSize?: number;
|
|
194
|
+
headingScale?: number;
|
|
195
|
+
};
|
|
196
|
+
radii?: {
|
|
197
|
+
sm?: number;
|
|
198
|
+
md?: number;
|
|
199
|
+
lg?: number;
|
|
200
|
+
xl?: number;
|
|
201
|
+
full?: number;
|
|
202
|
+
};
|
|
203
|
+
shadows?: {
|
|
204
|
+
sm?: string;
|
|
205
|
+
md?: string;
|
|
206
|
+
lg?: string;
|
|
207
|
+
glow?: string;
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export declare const DESIGN_SYSTEM_PRESETS: Record<string, CyrusDesignTokens>;
|
|
212
|
+
export declare function parseFigmaTokens(rawTokensJson: any): CyrusDesignTokens;
|
|
213
|
+
export declare function importTailwindConfig(tailwindConfig: any): CyrusDesignTokens;
|
|
214
|
+
export declare function exportToCssVariables(tokens: CyrusDesignTokens): string;
|
|
215
|
+
|
|
216
|
+
// ─── 3. Custom Component Registration ──────────────────────────────
|
|
217
|
+
export interface CyrusCustomComponentDefinition {
|
|
218
|
+
type: string;
|
|
219
|
+
title: string;
|
|
220
|
+
category?: 'custom' | 'ui' | 'data' | 'ecommerce' | 'layout';
|
|
221
|
+
icon?: string;
|
|
222
|
+
description?: string;
|
|
223
|
+
defaultWidth?: number;
|
|
224
|
+
defaultHeight?: number;
|
|
225
|
+
defaultStyles?: CyrusIRStyleProperties;
|
|
226
|
+
defaultContent?: Record<string, any>;
|
|
227
|
+
schema?: Record<string, any>;
|
|
228
|
+
renderTemplate?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ─── 4. Headless Compiler & Preview ────────────────────────────────
|
|
232
|
+
export interface CyrusCompileOptions {
|
|
233
|
+
framework?: 'react-tailwind' | 'flutter' | 'swiftui' | 'html-css';
|
|
234
|
+
includeWrapper?: boolean;
|
|
235
|
+
minify?: boolean;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface CyrusHeadlessValidationResult {
|
|
239
|
+
valid: boolean;
|
|
240
|
+
document: CyrusIRDocument;
|
|
241
|
+
elementCount: number;
|
|
242
|
+
pageCount: number;
|
|
243
|
+
warnings: string[];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export declare function compileCyrusIR(rawDocument: any, options?: CyrusCompileOptions): string;
|
|
247
|
+
export declare function validateIRHeadless(rawJson: any): CyrusHeadlessValidationResult;
|
|
248
|
+
export declare function renderHeadlessSVG(rawDocument: any, pageIndex?: number, viewportWidth?: number): string;
|
|
249
|
+
|
|
250
|
+
// ─── 7. White-Labeling & Theming ───────────────────────────────────
|
|
251
|
+
export interface CyrusWhiteLabelConfig {
|
|
252
|
+
brandName?: string;
|
|
253
|
+
brandTagline?: string;
|
|
254
|
+
logoUrl?: string;
|
|
255
|
+
primaryColor?: string;
|
|
256
|
+
accentColor?: string;
|
|
257
|
+
headerBackground?: string;
|
|
258
|
+
studioBackground?: string;
|
|
259
|
+
accentGlow?: boolean;
|
|
260
|
+
hideHeader?: boolean;
|
|
261
|
+
hideAIPanel?: boolean;
|
|
262
|
+
hideProperties?: boolean;
|
|
263
|
+
hideCodeDrawer?: boolean;
|
|
264
|
+
hideQuickAdd?: boolean;
|
|
265
|
+
hideLiveTest?: boolean;
|
|
266
|
+
hideZoomControls?: boolean;
|
|
267
|
+
customCss?: string;
|
|
268
|
+
allowedTools?: string[];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export type CyrusHostMessage =
|
|
272
|
+
| { type: 'CYRUS_SET_DOCUMENT'; payload: CyrusIRDocument }
|
|
273
|
+
| { type: 'CYRUS_UPDATE_ELEMENT'; payload: { id: string; updates: Partial<CyrusIRElement> } }
|
|
274
|
+
| { type: 'CYRUS_CREATE_ELEMENT'; payload: { element: CyrusIRElement; select?: boolean } }
|
|
275
|
+
| { type: 'CYRUS_DELETE_ELEMENT'; payload: { id: string } }
|
|
276
|
+
| { type: 'CYRUS_SET_THEME'; payload: { theme: 'light' | 'dark' } }
|
|
277
|
+
| { type: 'CYRUS_SELECT_ELEMENT'; payload: { elementId: string } }
|
|
278
|
+
| { type: 'CYRUS_GENERATE_FROM_PROMPT'; payload: { prompt: string; provider?: string; apiKey?: string } }
|
|
279
|
+
| { type: 'CYRUS_MCP_TOOL_CALL'; payload: CyrusMCPToolCall }
|
|
280
|
+
| { type: 'CYRUS_SET_DESIGN_TOKENS'; payload: CyrusDesignTokens }
|
|
281
|
+
| { type: 'CYRUS_REGISTER_CUSTOM_COMPONENT'; payload: CyrusCustomComponentDefinition }
|
|
282
|
+
| { type: 'CYRUS_SET_WHITELABEL_CONFIG'; payload: CyrusWhiteLabelConfig }
|
|
283
|
+
| { type: 'CYRUS_STREAM_INCREMENTAL_ELEMENTS'; payload: { elements: CyrusIRElement[]; isComplete?: boolean } }
|
|
284
|
+
| { type: 'CYRUS_REQUEST_CANVAS_SNAPSHOT'; payload?: { format?: 'png' | 'svg' | 'json' } };
|
|
285
|
+
|
|
286
|
+
export type CyrusCanvasMessage =
|
|
287
|
+
| { type: 'CYRUS_READY'; payload: { version: string } }
|
|
288
|
+
| { type: 'CYRUS_STATE_CHANGED'; payload: CyrusIRDocument | { projectId: string; name: string; document: CyrusIRDocument } }
|
|
289
|
+
| { type: 'CYRUS_CODE_SYNC'; payload: { react: string; html: string; flutter: string; swiftui: string } }
|
|
290
|
+
| { type: 'CYRUS_SELECTION_CHANGED'; payload: { selectedIds: string[] } }
|
|
291
|
+
| { type: 'CYRUS_MCP_TOOL_RESULT'; payload: CyrusMCPToolResult }
|
|
292
|
+
| { type: 'CYRUS_CANVAS_SNAPSHOT_RESPONSE'; payload: { snapshotUrl?: string; svg?: string; document: CyrusIRDocument } }
|
|
293
|
+
| { type: 'CYRUS_EXPORT_TRIGGERED'; payload: { format: string; code: string } };
|
|
294
|
+
|
|
295
|
+
export declare function validateAndRepairCyrusIR(rawInput: any, fallbackTitle?: string): CyrusIRDocument;
|
|
296
|
+
export declare function getCyrusLLMSystemPrompt(options?: { type?: string; theme?: 'light' | 'dark' }): string;
|
|
297
|
+
|
|
298
|
+
export interface CyrusEmbedUrlOptions {
|
|
299
|
+
projectId?: string;
|
|
300
|
+
hostUrl?: string;
|
|
301
|
+
theme?: 'light' | 'dark';
|
|
302
|
+
readOnly?: boolean;
|
|
303
|
+
whiteLabel?: CyrusWhiteLabelConfig;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export declare function createCyrusEmbedUrl(options?: CyrusEmbedUrlOptions): string;
|
|
307
|
+
|
|
308
|
+
export declare function generateReactTailwind(doc: CyrusIRDocument): string;
|
|
309
|
+
export declare function generateHtmlCss(doc: CyrusIRDocument): string;
|
|
310
|
+
export declare function generateFlutter(doc: CyrusIRDocument): string;
|
|
311
|
+
export declare function generateSwiftUI(doc: CyrusIRDocument): string;
|
|
312
|
+
|
|
313
|
+
export declare class CyrusCanvasController {
|
|
314
|
+
constructor(iframeWindow?: Window | null, targetOrigin?: string);
|
|
315
|
+
setIframeWindow(win: Window | null, origin?: string): void;
|
|
316
|
+
sendMessage(msg: CyrusHostMessage): void;
|
|
317
|
+
setDocument(doc: CyrusIRDocument): void;
|
|
318
|
+
setTheme(theme: 'light' | 'dark'): void;
|
|
319
|
+
selectElement(elementId: string): void;
|
|
320
|
+
createElement(element: CyrusIRElement, select?: boolean): void;
|
|
321
|
+
updateStyles(elementId: string, styles: Record<string, any>): void;
|
|
322
|
+
updateContent(elementId: string, content: Record<string, any>): void;
|
|
323
|
+
deleteElement(elementId: string): void;
|
|
324
|
+
setDesignTokens(tokens: CyrusDesignTokens): void;
|
|
325
|
+
importTailwindTokens(tailwindConfig: any): void;
|
|
326
|
+
importFigmaTokens(figmaTokensJson: any): void;
|
|
327
|
+
registerComponent(definition: CyrusCustomComponentDefinition): void;
|
|
328
|
+
setWhiteLabelConfig(config: CyrusWhiteLabelConfig): void;
|
|
329
|
+
streamIncrementalElements(elements: CyrusIRElement[], isComplete?: boolean): void;
|
|
330
|
+
requestCanvasSnapshot(format?: 'svg' | 'json' | 'png'): void;
|
|
331
|
+
executeMCPTool(toolCall: CyrusMCPToolCall): Promise<CyrusMCPToolResult>;
|
|
332
|
+
generateFromPrompt(prompt: string, provider?: string, apiKey?: string): void;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export interface CyrusIframeProps extends React.IframeHTMLAttributes<HTMLIFrameElement> {
|
|
336
|
+
projectId?: string;
|
|
337
|
+
hostUrl?: string;
|
|
338
|
+
theme?: 'light' | 'dark';
|
|
339
|
+
initialDocument?: CyrusIRDocument;
|
|
340
|
+
whiteLabel?: CyrusWhiteLabelConfig;
|
|
341
|
+
designTokens?: CyrusDesignTokens;
|
|
342
|
+
customComponents?: CyrusCustomComponentDefinition[];
|
|
343
|
+
onReady?: (info: { version: string }) => void;
|
|
344
|
+
onStateChange?: (doc: CyrusIRDocument) => void;
|
|
345
|
+
onCodeSync?: (code: { react: string; html: string; flutter: string; swiftui: string }) => void;
|
|
346
|
+
onSelectionChange?: (selectedIds: string[]) => void;
|
|
347
|
+
onMCPToolResult?: (result: CyrusMCPToolResult) => void;
|
|
348
|
+
controllerRef?: React.MutableRefObject<CyrusCanvasController | null>;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export declare function CyrusCanvasIframe(props: CyrusIframeProps): React.ReactElement;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export * from './protocol.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates an embeddable Cyrus studio URL from a project ID or custom host.
|
|
5
|
+
*/
|
|
6
|
+
export function createCyrusEmbedUrl(options = {}) {
|
|
7
|
+
const host = options.hostUrl || 'http://localhost:5173';
|
|
8
|
+
const pid = options.projectId || 'demo';
|
|
9
|
+
const theme = options.theme || 'light';
|
|
10
|
+
return `${host}/#/embed/${pid}?theme=${theme}&readOnly=${Boolean(options.readOnly)}`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* React Component to embed the Cyrus Visual Canvas Studio in any web app.
|
|
14
|
+
*/
|
|
15
|
+
export function CyrusCanvasIframe({ projectId = 'demo', hostUrl = 'http://localhost:5173', theme = 'light', onStateChange, style, className, ...rest }) {
|
|
16
|
+
const embedUrl = createCyrusEmbedUrl({ projectId, hostUrl, theme });
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (!onStateChange || typeof window === 'undefined')
|
|
19
|
+
return;
|
|
20
|
+
const handleMessage = (event) => {
|
|
21
|
+
if (event.data && event.data.type === 'CYRUS_STATE_CHANGED') {
|
|
22
|
+
onStateChange(event.data.payload);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
window.addEventListener('message', handleMessage);
|
|
26
|
+
return () => window.removeEventListener('message', handleMessage);
|
|
27
|
+
}, [onStateChange]);
|
|
28
|
+
return React.createElement('iframe', {
|
|
29
|
+
src: embedUrl,
|
|
30
|
+
className: className || 'w-full h-full border-0 rounded-2xl shadow-lg',
|
|
31
|
+
style: {
|
|
32
|
+
width: '100%',
|
|
33
|
+
height: '600px',
|
|
34
|
+
border: 'none',
|
|
35
|
+
borderRadius: '16px',
|
|
36
|
+
...style,
|
|
37
|
+
},
|
|
38
|
+
title: 'Cyrus Visual Canvas Studio',
|
|
39
|
+
...rest,
|
|
40
|
+
});
|
|
41
|
+
}
|