102 lines
3.5 KiB
TypeScript
102 lines
3.5 KiB
TypeScript
import React from 'react';
|
|
import * as ReactDOM from 'react-dom/client';
|
|
import r2wc from 'react-to-webcomponent';
|
|
import ExcalidrawWrapper from './ExcalidrawElement';
|
|
import type { Scene } from './types'; // Importer le type Scene si défini ailleurs
|
|
import { exportToBlob, exportToSvg } from '@excalidraw/excalidraw'; // Importer les fonctions exportToBlob et exportToSvg
|
|
|
|
// Définition du type pour l'événement personnalisé
|
|
declare global {
|
|
interface HTMLElementEventMap {
|
|
'ready': CustomEvent<{ apiAvailable: boolean }>;
|
|
}
|
|
}
|
|
|
|
// Map attributes/props to React props
|
|
const BaseCE = r2wc(ExcalidrawWrapper as any, React as any, ReactDOM as any, {
|
|
props: {
|
|
initialData: 'json',
|
|
readOnly: 'boolean',
|
|
theme: 'string',
|
|
lang: 'string',
|
|
gridMode: 'boolean',
|
|
zenMode: 'boolean',
|
|
hostRef: 'object',
|
|
},
|
|
// render in light DOM to allow package styles to apply
|
|
});
|
|
|
|
class ExcalidrawElement extends (BaseCE as any) {
|
|
connectedCallback() {
|
|
// Ensure the React component receives a reference to the host element before first render
|
|
(this as any).__host = this;
|
|
(this as any).hostRef = this;
|
|
|
|
// Dispatch a ready event once the API has been set on the host by the React wrapper
|
|
const onReady = () => {
|
|
console.log('[excalidraw-editor] 🎨 READY event dispatched', { apiAvailable: !!(this as any).__excalidrawAPI });
|
|
this.dispatchEvent(new CustomEvent('ready', {
|
|
detail: { apiAvailable: !!(this as any).__excalidrawAPI },
|
|
bubbles: true,
|
|
composed: true,
|
|
}));
|
|
};
|
|
|
|
if ((this as any).__excalidrawAPI) {
|
|
onReady();
|
|
} else {
|
|
const checkApi = setInterval(() => {
|
|
if ((this as any).__excalidrawAPI) {
|
|
clearInterval(checkApi);
|
|
onReady();
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
super.connectedCallback?.();
|
|
}
|
|
|
|
|
|
// Imperative API surface
|
|
getScene() {
|
|
const api = (this as any).__excalidrawAPI;
|
|
if (!api) return { elements: [], appState: {}, files: {} } as Scene;
|
|
return {
|
|
elements: api.getSceneElements?.() ?? [],
|
|
appState: api.getAppState?.() ?? {},
|
|
files: api.getFiles?.() ?? {},
|
|
} as Scene;
|
|
}
|
|
exportPNG(opts?: { withBackground?: boolean }) {
|
|
const api = (this as any).__excalidrawAPI;
|
|
if (!api) return { elements: [], appState: {}, files: {} };
|
|
const elements = api.getSceneElements?.() ?? [];
|
|
const appState = { ...(api.getAppState?.() ?? {}), exportBackground: !!opts?.withBackground } as any;
|
|
const files = api.getFiles?.() ?? {};
|
|
return exportToBlob({ elements, appState, files, mimeType: 'image/png', quality: 1 });
|
|
}
|
|
async exportSVG(opts?: { withBackground?: boolean }) {
|
|
const api = (this as any).__excalidrawAPI;
|
|
if (!api) return { elements: [], appState: {}, files: {} };
|
|
const elements = api.getSceneElements?.() ?? [];
|
|
const appState = { ...(api.getAppState?.() ?? {}), exportBackground: !!opts?.withBackground } as any;
|
|
const files = api.getFiles?.() ?? {};
|
|
const svgEl = await exportToSvg({ elements, appState, files });
|
|
const svgText = new XMLSerializer().serializeToString(svgEl);
|
|
return new Blob([svgText], { type: 'image/svg+xml' });
|
|
}
|
|
setScene(scene: any) {
|
|
const api = (this as any).__excalidrawAPI;
|
|
if (!api) return;
|
|
api.updateScene(scene);
|
|
}
|
|
refresh() {
|
|
const api = (this as any).__excalidrawAPI;
|
|
if (!api) return;
|
|
api.refresh();
|
|
}
|
|
}
|
|
|
|
if (!customElements.get('excalidraw-editor')) {
|
|
customElements.define('excalidraw-editor', ExcalidrawElement as any);
|
|
} |