diff --git a/scripts/generate-react-exports.js b/scripts/generate-react-exports.js index 30679215..4d69b111 100644 --- a/scripts/generate-react-exports.js +++ b/scripts/generate-react-exports.js @@ -9,13 +9,14 @@ const __dirname = path.dirname(__filename); const importStatements = [ 'import React from "react";', - 'import { type EventName, createComponent } from "@lit-labs/react";', + 'import { type EventName, createComponent, ReactWebComponent } from "@lit-labs/react";', // FIXME: These types should be determined automatically 'import { ISelectOption } from "./components/select/bl-select"', ]; const exportStatements = []; +const eventStatements = []; const customElements = fs.readJSONSync(`${__dirname}/../dist/custom-elements.json`); const customElementsModules = customElements.modules; @@ -24,45 +25,40 @@ const baklavaReactFileParts = []; for (const module of customElementsModules) { const { declarations, path } = module; const componentDeclaration = declarations.find(declaration => declaration.customElement === true); - const { events, name: componentName, tagName: fileName, jsDoc } = componentDeclaration; - const eventNames = events - ? events.reduce((acc, curr) => { - acc[getReactEventName(curr.name)] = curr.name; - return acc; - }, {}) - : {}; - - const eventTypes = events - ? `, {${events - .map( - event => - `${getReactEventName(event.name)}: EventName<${cleanGenericTypes( - componentDeclaration.typeParameters, - event.type.text - )}>` - ) - .join(", ")}}` - : ""; + const eventNames = events?.reduce((acc, curr) => { + acc[getReactEventName(curr.name)] = curr.name; + return acc; + }, {}) || {}; + + const eventTypes = events?.map(event => { + const eventName = getReactEventName(event.name); + const eventType = cleanGenericTypes(componentDeclaration.typeParameters, event.type.text); + const predefinedEventName = `${componentName}${eventName.split("onBl")[1]}`; + + eventStatements.push(`export declare type ${predefinedEventName} = ${eventType};`); + return `${eventName}: EventName<${predefinedEventName}>`; + }) || []; const importPath = path.replace(/^src\//, "").replace(/\.ts$/, ""); const typeName = componentName + "Type"; - const componentType = `${typeName}${eventTypes}`; + const formattedEventTypes = eventTypes.length ? `, {${eventTypes.join(", ")}}` : ""; + const componentType = `${typeName}${formattedEventTypes}`; importStatements.push(`import type ${typeName} from "./${importPath}";`); exportStatements.push(`export declare type ${componentName} = ${typeName}`); const source = ` ${jsDoc} - export const ${componentName}: import("@lit-labs/react").ReactWebComponent<${componentType}> = ( - () => createComponent<${componentType}>({ - react: React, - displayName: "${componentName}", - tagName: "${fileName}", - elementClass: customElements.get("${fileName}"), - events: ${JSON.stringify(eventNames)}, - })); + export const ${componentName}: React.LazyExoticComponent> = + customElements.whenDefined('${fileName}').then(() => createComponent<${componentType}>({ + react: React, + displayName: "${componentName}", + tagName: "${fileName}", + elementClass: customElements.get("${fileName}"), + events: ${JSON.stringify(eventNames)}, + })); `; baklavaReactFileParts.push(source); @@ -79,6 +75,7 @@ function writeBaklavaReactFile(fileContentParts) { `/* eslint-disable @typescript-eslint/ban-ts-comment */`, `// @ts-nocheck`, ...importStatements, + ...eventStatements, ...exportStatements, ...fileContentParts, ].join("\n\n"); @@ -92,8 +89,8 @@ function cleanGenericTypes(typeParameters, eventType) { if (!typeParameters?.length || typeParameters.length === 0) return eventType; const paramNames = typeParameters.map(param => param.name); - const paramNamesPattern = paramNames.map(name => `<${name}>|${name} \\| | \\| ${name}`).join('|'); - const regex = new RegExp(paramNamesPattern, 'g'); + const paramNamesPattern = paramNames.map(name => `<${name}>|${name} \\| | \\| ${name}`).join("|"); + const regex = new RegExp(paramNamesPattern, "g"); - return eventType.replace(regex, ''); + return eventType.replace(regex, ""); }