@cfp-studio/plugin-react 17.2.1 → 17.3.1

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 CHANGED
@@ -3,6 +3,7 @@
3
3
  React 框架的 CFP Studio 插件,支持 React 组件/Story 静态分析、属性/类型提取、预览渲染、CSF/Storybook 兼容等。
4
4
 
5
5
  ## 特性
6
+
6
7
  - 自动检测并适配 React 16/17/18+ 项目
7
8
  - 支持 React 组件/Story 的批量静态分析与属性/类型提取
8
9
  - 兼容 CSF/Storybook 规范,支持 args/参数提取
@@ -10,6 +11,7 @@ React 框架的 CFP Studio 插件,支持 React 组件/Story 静态分析、属
10
11
  - 内置丰富的 E2E/单元测试用例,覆盖多种工程模板
11
12
 
12
13
  ## 架构与工作原理
14
+
13
15
  - 通过 `FrameworkPluginFactory` 实现插件注册与兼容性检测
14
16
  - 使用 `@cfp-studio/analyzer-react` 进行 TS/JSX 类型分析
15
17
  - `react-js-imports-plugin` 自动为 .js 文件注入 React 导入,兼容 React 17+ 新写法
@@ -17,6 +19,7 @@ React 框架的 CFP Studio 插件,支持 React 组件/Story 静态分析、属
17
19
  - 支持多种 React 工程模板(apps/ 下有多种测试工程)
18
20
 
19
21
  ## 主要 API/模块
22
+
20
23
  - `src/index.ts`:插件主入口,注册工厂与分析器
21
24
  - `src/react-js-imports-plugin.ts`:自动注入 React 导入
22
25
  - `preview/index.tsx`:前端渲染入口
@@ -24,19 +27,23 @@ React 框架的 CFP Studio 插件,支持 React 组件/Story 静态分析、属
24
27
  - `tests/`、`apps/`:丰富的测试与模板
25
28
 
26
29
  ## 用法示例
30
+
27
31
  ```ts
28
- import { reactFrameworkPlugin } from '@cfp-studio/plugin-react';
32
+ import { reactFrameworkPlugin } from "@cfp-studio/plugin-react";
29
33
  // 传入 core/Previewer 或 createChromelessWorkspace 等集成
30
34
  ```
31
35
 
32
36
  ## 依赖
37
+
33
38
  - `react`、`@cfp-studio/*`、`typescript`、`vite`、`esbuild-plugin-polyfill-node`
34
39
  - 测试:`vitest`、`@playwright/test`
35
40
 
36
41
  ## 构建
42
+
37
43
  ```sh
38
44
  pnpm build
39
45
  ```
40
46
 
41
47
  ## 许可证
48
+
42
49
  MIT
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  /// <reference types="node" />
2
- import { Reader } from "@cfp-studio/vfs";
3
- import * as fs$1 from "node:fs";
4
2
  import * as url$1 from "node:url";
5
3
  import { URL as URL$1 } from "node:url";
4
+ import * as fs$1 from "node:fs";
5
+ import { Reader } from "@cfp-studio/vfs";
6
6
  import { Analyzer } from "@cfp-studio/analyzer-api";
7
7
  import * as http from "node:http";
8
8
  import { Agent, ClientRequest, ClientRequestArgs, IncomingMessage, OutgoingHttpHeaders, Server } from "node:http";
@@ -15,6 +15,8 @@ import * as stream from "node:stream";
15
15
  import { Duplex, DuplexOptions } from "node:stream";
16
16
  import { SecureContextOptions } from "node:tls";
17
17
  import { ZlibOptions } from "node:zlib";
18
+ import Lightningcss from "lightningcss";
19
+ import DartSass from "sass";
18
20
  import SassEmbedded from "sass-embedded";
19
21
  import Less from "less";
20
22
  import Stylus from "stylus";
@@ -34,7 +36,7 @@ type FrameworkPluginInfo = {
34
36
  * @returns 实现了 Api 接口的 AxiosApi 实例
35
37
  */
36
38
  //#endregion
37
- //#region ../../../../node_modules/.pnpm/@types+estree@1.0.8/node_modules/@types/estree/index.d.ts
39
+ //#region ../../../../node_modules/.pnpm/@types+estree@1.0.9/node_modules/@types/estree/index.d.ts
38
40
  // This definition file follows a somewhat unusual format. ESTree allows
39
41
  // runtime type checks based on the `type` parameter. In order to explain this
40
42
  // to typescript we want to use discriminated union types:
@@ -284,7 +286,7 @@ interface PrivateIdentifier extends BaseNode {
284
286
  }
285
287
  interface Property extends BaseNode {
286
288
  type: "Property";
287
- key: Expression | PrivateIdentifier;
289
+ key: Expression;
288
290
  value: Expression | Pattern; // Could be an AssignmentProperty
289
291
  kind: "init" | "get" | "set";
290
292
  method: boolean;
@@ -558,7 +560,7 @@ interface AwaitExpression extends BaseExpression {
558
560
  argument: Expression;
559
561
  }
560
562
  //#endregion
561
- //#region ../../../../node_modules/.pnpm/rollup@4.52.0/node_modules/rollup/dist/rollup.d.ts
563
+ //#region ../../../../node_modules/.pnpm/rollup@4.65.0/node_modules/rollup/dist/rollup.d.ts
562
564
  declare module 'estree' {
563
565
  export interface Decorator extends BaseNode {
564
566
  type: 'Decorator';
@@ -638,11 +640,11 @@ type DecodedSourceMapOrMissing = {
638
640
  missing?: false | undefined;
639
641
  });
640
642
  interface SourceMap$1 {
641
- file: string;
643
+ file?: string | undefined;
642
644
  mappings: string;
643
645
  names: string[];
644
646
  sources: string[];
645
- sourcesContent?: string[] | undefined;
647
+ sourcesContent?: (string | null)[] | undefined;
646
648
  version: number;
647
649
  debugId?: string | undefined;
648
650
  toString(): string;
@@ -664,7 +666,8 @@ interface SourceDescription extends Partial<PartialNull<ModuleOptions>> {
664
666
  }
665
667
  interface TransformModuleJSON {
666
668
  ast?: ProgramNode | undefined;
667
- code: string; // note if plugins use new this.cache to opt-out auto transform cache
669
+ code: string;
670
+ safeVariableNames: Record<string, string> | null; // note if plugins use new this.cache to opt-out auto transform cache
668
671
  customTransformCache: boolean;
669
672
  originalCode: string;
670
673
  originalSourcemap: ExistingDecodedSourceMap | null;
@@ -672,6 +675,7 @@ interface TransformModuleJSON {
672
675
  transformDependencies: string[];
673
676
  }
674
677
  interface ModuleJSON extends TransformModuleJSON, ModuleOptions {
678
+ safeVariableNames: Record<string, string> | null;
675
679
  ast: ProgramNode;
676
680
  dependencies: string[];
677
681
  id: string;
@@ -727,6 +731,7 @@ interface ModuleInfo extends ModuleOptions {
727
731
  dynamicallyImportedIds: readonly string[];
728
732
  exportedBindings: Record<string, string[]> | null;
729
733
  exports: string[] | null;
734
+ safeVariableNames: Record<string, string> | null;
730
735
  hasDefaultExport: boolean | null;
731
736
  id: string;
732
737
  implicitlyLoadedAfterOneOf: readonly string[];
@@ -774,6 +779,7 @@ interface PluginContext extends MinimalPluginContext$1 {
774
779
  } & Partial<PartialNull<ModuleOptions>>) => Promise<ModuleInfo>;
775
780
  parse: ParseAst;
776
781
  resolve: (source: string, importer?: string, options?: {
782
+ importerAttributes?: Record<string, string>;
777
783
  attributes?: Record<string, string>;
778
784
  custom?: CustomPluginOptions;
779
785
  isEntry?: boolean;
@@ -810,10 +816,12 @@ type ResolveIdResult = string | NullValue | false | PartialResolvedId;
810
816
  type ResolveIdHook = (this: PluginContext, source: string, importer: string | undefined, options: {
811
817
  attributes: Record<string, string>;
812
818
  custom?: CustomPluginOptions;
819
+ importerAttributes?: Record<string, string> | undefined;
813
820
  isEntry: boolean;
814
821
  }) => ResolveIdResult;
815
822
  type ShouldTransformCachedModuleHook = (this: PluginContext, options: {
816
823
  ast: ProgramNode;
824
+ attributes: Record<string, string>;
817
825
  code: string;
818
826
  id: string;
819
827
  meta: CustomPluginOptions;
@@ -824,7 +832,12 @@ type ShouldTransformCachedModuleHook = (this: PluginContext, options: {
824
832
  type IsExternal = (source: string, importer: string | undefined, isResolved: boolean) => boolean;
825
833
  type HasModuleSideEffects = (id: string, external: boolean) => boolean;
826
834
  type LoadResult = SourceDescription | string | NullValue;
827
- type LoadHook = (this: PluginContext, id: string) => LoadResult;
835
+ type LoadHook = (this: PluginContext, id: string, // temporarily marked as optional for better Vite type-compatibility
836
+ options?: {
837
+ // unused, temporarily added for better Vite type-compatibility
838
+ ssr?: boolean | undefined; // temporarily marked as optional for better Vite type-compatibility
839
+ attributes?: Record<string, string>;
840
+ } | undefined) => LoadResult;
828
841
  interface TransformPluginContext extends PluginContext {
829
842
  debug: LoggingFunctionWithPosition;
830
843
  error: (error: RollupError | string, pos?: number | {
@@ -836,7 +849,12 @@ interface TransformPluginContext extends PluginContext {
836
849
  warn: LoggingFunctionWithPosition;
837
850
  }
838
851
  type TransformResult$2 = string | NullValue | Partial<SourceDescription>;
839
- type TransformHook = (this: TransformPluginContext, code: string, id: string) => TransformResult$2;
852
+ type TransformHook = (this: TransformPluginContext, code: string, id: string, // temporarily marked as optional for better Vite type-compatibility
853
+ options?: {
854
+ // unused, temporarily added for better Vite type-compatibility
855
+ ssr?: boolean | undefined; // temporarily marked as optional for better Vite type-compatibility
856
+ attributes?: Record<string, string>;
857
+ } | undefined) => TransformResult$2;
840
858
  type ModuleParsedHook = (this: PluginContext, info: ModuleInfo) => void;
841
859
  type RenderChunkHook = (this: PluginContext, code: string, chunk: RenderedChunk, options: NormalizedOutputOptions, meta: {
842
860
  chunks: Record<string, RenderedChunk>;
@@ -846,13 +864,16 @@ type RenderChunkHook = (this: PluginContext, code: string, chunk: RenderedChunk,
846
864
  } | string | NullValue;
847
865
  type ResolveDynamicImportHook = (this: PluginContext, specifier: string | AstNode, importer: string, options: {
848
866
  attributes: Record<string, string>;
867
+ importerAttributes: Record<string, string>;
849
868
  }) => ResolveIdResult;
850
869
  type ResolveImportMetaHook = (this: PluginContext, property: string | null, options: {
870
+ attributes: Record<string, string>;
851
871
  chunkId: string;
852
872
  format: InternalModuleFormat;
853
873
  moduleId: string;
854
874
  }) => string | NullValue;
855
875
  type ResolveFileUrlHook = (this: PluginContext, options: {
876
+ attributes: Record<string, string>;
856
877
  chunkId: string;
857
878
  fileName: string;
858
879
  format: InternalModuleFormat;
@@ -903,6 +924,7 @@ interface FunctionPluginHooks {
903
924
  chunk: PreRenderedChunkWithFileName;
904
925
  targetChunk: PreRenderedChunkWithFileName | null;
905
926
  getTargetChunkImports: () => DynamicImportTargetChunk[] | null;
927
+ targetModuleAttributes: Record<string, string>;
906
928
  }) => {
907
929
  left: string;
908
930
  right: string;
@@ -1318,16 +1340,14 @@ interface AwaitingEventEmitter<T extends Record<string, (...parameters: any) =>
1318
1340
  off<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
1319
1341
  /**
1320
1342
  * Registers an event listener that will be awaited before Rollup continues.
1321
- * All listeners will be awaited in parallel while rejections are tracked via
1322
- * Promise.all.
1343
+ * All listeners are invoked and awaited in parallel. Rollup waits until all
1344
+ * of them have settled and then throws the first rejection, if any.
1323
1345
  */
1324
1346
  on<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
1325
1347
  /**
1326
- * Registers an event listener that will be awaited before Rollup continues.
1327
- * All listeners will be awaited in parallel while rejections are tracked via
1328
- * Promise.all.
1329
- * Listeners are removed automatically when removeListenersForCurrentRun is
1330
- * called, which happens automatically after each run.
1348
+ * Registers an event listener like `on`. Listeners are removed automatically
1349
+ * when removeListenersForCurrentRun is called, which happens right before each
1350
+ * rebuild, after the changes that triggered it were announced.
1331
1351
  */
1332
1352
  onCurrentRun<K extends keyof T>(event: K, listener: (...parameters: Parameters<T[K]>) => Promise<ReturnType<T[K]>>): this;
1333
1353
  removeAllListeners(): this;
@@ -1428,7 +1448,7 @@ interface RollupFileStats {
1428
1448
  birthtime: Date;
1429
1449
  }
1430
1450
  //#endregion
1431
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/types/hmrPayload.d.ts
1451
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/types/hmrPayload.d.ts
1432
1452
  type HotPayload = ConnectedPayload | PingPayload | UpdatePayload | FullReloadPayload | CustomPayload | ErrorPayload | PrunePayload;
1433
1453
  interface ConnectedPayload {
1434
1454
  type: 'connected';
@@ -1487,7 +1507,7 @@ interface ErrorPayload {
1487
1507
  };
1488
1508
  }
1489
1509
  //#endregion
1490
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/types/customEvent.d.ts
1510
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/types/customEvent.d.ts
1491
1511
  interface CustomEventMap {
1492
1512
  'vite:beforeUpdate': UpdatePayload;
1493
1513
  'vite:afterUpdate': UpdatePayload;
@@ -1518,7 +1538,7 @@ interface InvalidatePayload {
1518
1538
  */
1519
1539
  type InferCustomEventPayload<T extends string> = T extends keyof CustomEventMap ? CustomEventMap[T] : any;
1520
1540
  //#endregion
1521
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/dist/node/moduleRunnerTransport.d-DJ_mE5sf.d.ts
1541
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/dist/node/moduleRunnerTransport.d-DJ_mE5sf.d.ts
1522
1542
  interface FetchFunctionOptions {
1523
1543
  cached?: boolean;
1524
1544
  startOffset?: number;
@@ -2181,12 +2201,12 @@ declare global {
2181
2201
  interface URL {}
2182
2202
  }
2183
2203
  //#endregion
2184
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/types/internal/lightningcssOptions.d.ts
2204
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/types/internal/lightningcssOptions.d.ts
2185
2205
  /* eslint-enable @typescript-eslint/ban-ts-comment */
2186
2206
  type LightningCSSOptions = Omit<Lightningcss.BundleAsyncOptions<Lightningcss.CustomAtRules>, 'filename' | 'resolver' | 'minify' | 'sourceMap' | 'analyzeDependencies' // properties not overridden by Vite, but does not make sense to set by end users
2187
2207
  | 'inputSourceMap' | 'projectRoot'>;
2188
2208
  //#endregion
2189
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/types/internal/cssPreprocessorOptions.d.ts
2209
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/types/internal/cssPreprocessorOptions.d.ts
2190
2210
  /* eslint-enable @typescript-eslint/ban-ts-comment */
2191
2211
  // https://github.com/type-challenges/type-challenges/issues/29285
2192
2212
  type IsAny<T> = boolean extends (T extends never ? true : false) ? true : false;
@@ -2209,7 +2229,7 @@ declare global {
2209
2229
  interface HTMLLinkElement {}
2210
2230
  }
2211
2231
  //#endregion
2212
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/types/metadata.d.ts
2232
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/types/metadata.d.ts
2213
2233
  interface ChunkMetadata {
2214
2234
  importedAssets: Set<string>;
2215
2235
  importedCss: Set<string>;
@@ -2242,7 +2262,7 @@ declare module 'rollup' {
2242
2262
  }
2243
2263
  }
2244
2264
  //#endregion
2245
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.19.2_jiti@2.6.1_less@4.2.2_lightningcss@1.30.2_sass@1.85.1_terser@5.40.0_tsx@4.19.3_yaml@2.7.0/node_modules/vite/dist/node/index.d.ts
2265
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/dist/node/index.d.ts
2246
2266
  interface Alias {
2247
2267
  find: string | RegExp;
2248
2268
  replacement: string;
@@ -5757,9 +5777,6 @@ interface FrameworkPlugin extends Analyzer {
5757
5777
  */
5758
5778
  //#endregion
5759
5779
  //#region src/index.d.ts
5760
- /**
5761
- * 定义一个名为 reactFrameworkPlugin 的框架插件工厂对象
5762
- */
5763
5780
  declare const reactFrameworkPlugin: FrameworkPluginFactory;
5764
5781
  /**
5765
5782
  * 导出默认的 reactFrameworkPlugin 对象
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{factoryWithDefaultOptions as e}from"@cfp-studio/analyzer-api/factory";import{EMPTY_OBJECT_TYPE as t,NODE_TYPE as n,UNKNOWN_TYPE as r,arrayType as i,createTypeAnalyzer as a,dereferenceType as o,functionType as s,helpers as c,maybeOptionalType as l,objectType as u,stripUnusedTypes as d}from"@cfp-studio/type-analyzer";import{createFileSystemReader as f,createStackedReader as p}from"@cfp-studio/vfs";import m from"node:fs";import h from"node:path";import g from"typescript";import _ from"node:url";import{decodePreviewableId as v,generatePreviewableId as y}from"@cfp-studio/analyzer-api";import{parseSerializableValue as b}from"@cfp-studio/serializable-values";import{extractArgs as x,extractCsf3Stories as S,extractStoriesInfo as C,resolvePreviewableId as w}from"@cfp-studio/storybook-helpers";import T from"@vitejs/plugin-react";import{polyfillNode as E}from"esbuild-plugin-polyfill-node";function D(e,t){for(let n of e.statements)if(g.isExpressionStatement(n)&&g.isBinaryExpression(n.expression)&&n.expression.operatorToken.kind===g.SyntaxKind.EqualsToken&&g.isPropertyAccessExpression(n.expression.left)&&g.isIdentifier(n.expression.left.expression)){if(n.expression.left.expression.text!==t)continue;if(n.expression.left.name.text===`propTypes`)return n.expression.right}else if(g.isClassDeclaration(n)&&n.name){if(n.name.text!==t)continue;for(let e of n.members)if(g.isPropertyDeclaration(e)&&e.initializer&&e.name.getText()===`propTypes`)return e.initializer}return null}function O(e,t,n,r,i){let a=t.sourceFile(n),o=null;a&&(o=D(a,r));let s=null;return s=o?A(t,o):k(e,t,i),{props:s.type,types:{...s.collected}}}function k(e,n,i){let a=i.getParameters()[0];if(!a)return{type:t,collected:{}};if(!a.valueDeclaration)return{type:r,collected:{}};let s=n.checker.getTypeOfSymbolAtLocation(a,a.valueDeclaration);try{let{type:e,collected:t}=n.resolveType(s);if([e]=o(e,t,[]),e.kind===`object`&&g.isParameter(a.valueDeclaration)&&g.isObjectBindingPattern(a.valueDeclaration.name)){let t=a.valueDeclaration.name,n=new Set,r=new Set,i=!1;for(let e of t.elements){if(e.dotDotDotToken){i=!0;break}let t=e.propertyName||e.name;if(!g.isIdentifier(t)){i=!0;break}n.add(t.text),e.initializer&&r.add(t.text)}i||(e=u(Object.fromEntries(Object.entries(e.fields).filter(([e])=>n.has(e)).map(([e,t])=>[e,l(t,r.has(e))]))))}return{type:e,collected:t}}catch(t){e.warn(`Unable to resolve props type for ${n.checker.typeToString(s)}`),e.error(t.toString())}return{type:r,collected:{}}}function A(e,t){let n=e.checker.getTypeAtLocation(t),i={},a={};for(let t of n.getProperties())i[t.name]=(()=>{if(!t.valueDeclaration)return r;let n=e.checker.getTypeAtLocation(t.valueDeclaration),i=e.resolveTypeArguments(n),o=i.types[0];return o?(a={...a,...i.collected},l(o,n.symbol.name===`Requireable`)):r})();let o=u(i);return{type:o,collected:d(a,[o])}}async function j(e,t,n,i){let a=t.sourceFile(i);if(!a)return[];let o=[];for(let e of a.statements)if(g.isExportAssignment(e)){if(g.isIdentifier(e.expression))continue;o.push([`default`,e,e.expression])}else if(g.isVariableStatement(e))for(let t of e.declarationList.declarations)!g.isIdentifier(t.name)||!t.initializer||o.push([t.name.text,e,t.initializer]);else if(g.isFunctionDeclaration(e)){let t=!!e.modifiers?.find(e=>e.kind===g.SyntaxKind.ExportKeyword)&&!!e.modifiers?.find(e=>e.kind===g.SyntaxKind.DefaultKeyword),n=e.name?.text;(t||n)&&o.push([n||`default`,e,e])}else g.isClassDeclaration(e)&&e.name&&o.push([e.name.text,e,e]);let s=C(a);e.debug(`**storiresInfo: ${s}`);let l=[],u=x(a),d=c.extractExportedNames(a);async function f(r,a,o){if(o===`default`&&s)return null;let c=u[o],l=o===`default`||!!d[o],f=N(t.checker,a);if(s&&l&&(c||f?.parameters.length===0)){let i=M(e,t,n,s.component);return{...r,analyze:async()=>({args:c?{sourcePosition:{start:c.getStart(),end:c.getEnd()},value:await b(c)}:null}),associatedComponent:i}}return f?{...r,exported:l,analyze:async()=>O(e,t,i,o,f)}:null}for(let[e,t,r]of o){let a=await f({id:y({filePath:h.relative(n,i),name:e}),sourcePosition:{start:t.getStart(),end:t.getEnd()}},r,e);a&&l.push(a)}return[...l,...await S(n,t,a,async i=>{let{filePath:a}=v(i),o=(await j(e,t,n,h.join(n,a))).find(e=>e.id===i);return!o||!(`exported`in o)?{props:r,types:{}}:o.analyze()})]}function M(e,t,n,i){let a=w(n,t.checker,i);return i&&a?{id:a,analyze:async()=>{let o=N(t.checker,i);if(!o)return{props:r,types:{}};let{filePath:s,name:c}=v(a);return O(e,t,h.join(n,s),c,o)}}:null}function N(e,t){let n=e.getTypeAtLocation(t);if(n.flags===g.TypeFlags.Any&&g.isCallExpression(t)&&g.isPropertyAccessExpression(t.expression)&&g.isIdentifier(t.expression.name)&&t.expression.name.text===`bind`){let r=e.getSymbolAtLocation(t.expression.expression);r?.valueDeclaration&&g.isVariableDeclaration(r.valueDeclaration)&&r.valueDeclaration.initializer&&(n=e.getTypeAtLocation(r.valueDeclaration.initializer))}for(let e of n.getCallSignatures())if(P(e.getReturnType()))return e;if(n.symbol){let r=e.getTypeOfSymbolAtLocation(n.symbol,t);for(let e of r.getConstructSignatures())if(e.getReturnType().getProperty(`render`))return e}return null}function P(e){return!!I(e)}const F=new Set([`Element`,`ReactElement`]);function I(e){if(e.isUnion()){for(let t of e.types)if(I(t))return!0}return F.has(e.symbol?.getEscapedName().toString())}const L={Component:n,ComponentClass:s(n),FunctionComponent:s(n),ReactElement:n,ReactNode:n,ReactNodeArray:i(n),ReactPortal:n},R=e(({rootDir:e,reader:t,logger:n})=>{let r=_.fileURLToPath(new URL(`.`,import.meta.url)),i=h.join(r,`..`,`types`),o=h.join(r,`..`,`node_modules`),s=m.existsSync(i)?i:o,c=a({reader:p([t,f({mapping:{from:s,to:h.join(e,`node_modules`)},watch:!1}),...s===i?[f({mapping:{from:i,to:h.join(e,`node_modules`,`@types`)},watch:!1})]:[]]),rootDir:e,specialTypes:L,tsCompilerOptions:{jsx:g.JsxEmit.ReactJSX,jsxImportSource:`react`},warn:n.warn.bind(n)});return{typeAnalyzer:c,crawlFiles:async t=>{let r=t.map(t=>h.isAbsolute(t)?t:h.join(e,t)),i=c.analyze(r),a=[],o=[];for(let t of r)for(let r of await j(n,i,e,t))`exported`in r?a.push(r):o.push(r);return{components:a,stories:o}},dispose:()=>{c.dispose()}}}),z=/import (\* as )?React[ ,]/;function B(){return{name:`previewjs:react-js-imports`,async transform(e,t){return t.includes(`node_modules`)||h.extname(t)!==`.js`||z.test(e)?e:`import React from 'react';${e}`}}}const V={info:{apiVersion:5,name:`@cfp-studio/plugin-react`},isCompatible:async e=>{let t=await e.react?.readInstalledVersion();if(!t)return!1;let[n,r]=t.split(`.`).map(e=>Number.parseInt(e));return Number.isNaN(n)||Number.isNaN(r)?!1:n>=17||n===16&&r>=14},async create({rootDir:e,reader:t,logger:n,dependencies:r}){let i=_.fileURLToPath(new URL(`.`,import.meta.url)),a=R({rootDir:e,reader:t,logger:n});return{defaultWrapperPath:`__previewjs__/Wrapper.tsx`,previewDirPath:h.join(i,`..`,`preview`),...a,viteConfig:e=>{let t=e.find(e=>e.name.startsWith(`vite:react-`));return{optimizeDeps:{esbuildOptions:{plugins:r.next?[E()]:[]}},resolve:{alias:{"react-native":`react-native-web`}},plugins:[B(),...e,...t?[]:[T()],{name:`previewjs:update-react-import`,async transform(e,t){if(!t.endsWith(`__previewjs_internal__/renderer/index.tsx`))return;let n=Number.parseInt(await r.react?.readInstalledVersion()||`0`);return e.replace(/__PREVIEWJS_PLUGIN_REACT_IMPORT_PATH__/g,n>=18?`./render-18`:`./render-16`)}}]}}}}};export{V as default};
1
+ import e from"node:path";import t from"node:url";import n from"@vitejs/plugin-react";import{polyfillNode as r}from"esbuild-plugin-polyfill-node";import i from"node:fs";import{createAnalyzer as a}from"@cfp-studio/analyzer-api/analyzer";import{createFileSystemReader as o,createStackedReader as s}from"@cfp-studio/vfs";import c from"typescript";import{decodePreviewableId as l,defineSpecialTypes as u,generatePreviewableId as d}from"@cfp-studio/analyzer-api";import{parseSerializableValue as f}from"@cfp-studio/serializable-values";import{extractArgs as p,extractCsf3Stories as m,extractStoriesInfo as h,resolvePreviewableId as g}from"@cfp-studio/storybook-helpers";import{EMPTY_OBJECT_TYPE as _,NODE_TYPE as v,UNKNOWN_TYPE as y,arrayType as b,dereferenceType as x,functionType as S,helpers as C,maybeOptionalType as w,objectType as T,stripUnusedTypes as E}from"@cfp-studio/type-analyzer";function D(e,t){for(let n of e.statements)if(c.isExpressionStatement(n)&&c.isBinaryExpression(n.expression)&&n.expression.operatorToken.kind===c.SyntaxKind.EqualsToken&&c.isPropertyAccessExpression(n.expression.left)&&c.isIdentifier(n.expression.left.expression)){if(n.expression.left.expression.text!==t)continue;if(n.expression.left.name.text===`propTypes`)return n.expression.right}else if(c.isClassDeclaration(n)&&n.name){if(n.name.text!==t)continue;for(let e of n.members)if(c.isPropertyDeclaration(e)&&e.initializer&&e.name.getText()===`propTypes`)return e.initializer}return null}function O(e,t,n,r,i){let a=t.sourceFile(n),o=null;a&&(o=D(a,r));let s=null;return s=o?A(t,o):k(e,t,i),{props:s.type,types:{...s.collected}}}function k(e,t,n){let r=n.getParameters()[0];if(!r)return{type:_,collected:{}};if(!r.valueDeclaration)return{type:y,collected:{}};let i=t.checker.getTypeOfSymbolAtLocation(r,r.valueDeclaration);try{let{type:e,collected:n}=t.resolveType(i);if([e]=x(e,n,[]),e.kind===`object`&&c.isParameter(r.valueDeclaration)&&c.isObjectBindingPattern(r.valueDeclaration.name)){let t=r.valueDeclaration.name,n=new Set,i=new Set,a=!1;for(let e of t.elements){if(e.dotDotDotToken){a=!0;break}let t=e.propertyName||e.name;if(!c.isIdentifier(t)){a=!0;break}n.add(t.text),e.initializer&&i.add(t.text)}a||(e=T(Object.fromEntries(Object.entries(e.fields).filter(([e])=>n.has(e)).map(([e,t])=>[e,w(t,i.has(e))]))))}return{type:e,collected:n}}catch(n){e.warn(`Unable to resolve props type for ${t.checker.typeToString(i)}`),e.error(n.toString())}return{type:y,collected:{}}}function A(e,t){let n=e.checker.getTypeAtLocation(t),r={},i={};for(let t of n.getProperties())r[t.name]=(()=>{if(!t.valueDeclaration)return y;let n=e.checker.getTypeAtLocation(t.valueDeclaration),r=e.resolveTypeArguments(n),a=r.types[0];return a?(i={...i,...r.collected},w(a,n.symbol.name===`Requireable`)):y})();let a=T(r);return{type:a,collected:E(i,[a])}}async function j(t,n,r,i){let a=n.sourceFile(i);if(!a)return[];let o=[];for(let e of a.statements)if(c.isExportAssignment(e)){if(c.isIdentifier(e.expression))continue;o.push([`default`,e,e.expression])}else if(c.isVariableStatement(e))for(let t of e.declarationList.declarations)!c.isIdentifier(t.name)||!t.initializer||o.push([t.name.text,e,t.initializer]);else if(c.isFunctionDeclaration(e)){let t=!!e.modifiers?.find(e=>e.kind===c.SyntaxKind.ExportKeyword)&&!!e.modifiers?.find(e=>e.kind===c.SyntaxKind.DefaultKeyword),n=e.name?.text;(t||n)&&o.push([n||`default`,e,e])}else c.isClassDeclaration(e)&&e.name&&o.push([e.name.text,e,e]);let s=h(a);t.debug(`**storiresInfo: ${s}`);let u=[],g=p(a),_=C.extractExportedNames(a);async function v(e,a,o){if(o===`default`&&s)return null;let c=g[o],l=o===`default`||!!_[o],u=N(n.checker,a);if(s&&l&&(c||u?.parameters.length===0)){let i=M(t,n,r,s.component);return{...e,analyze:async()=>({args:c?{sourcePosition:{start:c.getStart(),end:c.getEnd()},value:await f(c)}:null}),associatedComponent:i}}return u?{...e,exported:l,analyze:async()=>O(t,n,i,o,u)}:null}for(let[t,n,a]of o){let o=await v({id:d({filePath:e.relative(r,i),name:t}),sourcePosition:{start:n.getStart(),end:n.getEnd()}},a,t);o&&u.push(o)}return[...u,...await m(r,n,a,async i=>{let{filePath:a}=l(i),o=(await j(t,n,r,e.join(r,a))).find(e=>e.id===i);return!o||!(`exported`in o)?{props:y,types:{}}:o.analyze()})]}function M(t,n,r,i){let a=g(r,n.checker,i);return i&&a?{id:a,analyze:async()=>{let o=N(n.checker,i);if(!o)return{props:y,types:{}};let{filePath:s,name:c}=l(a);return O(t,n,e.join(r,s),c,o)}}:null}function N(e,t){let n=e.getTypeAtLocation(t);if(n.flags===c.TypeFlags.Any&&c.isCallExpression(t)&&c.isPropertyAccessExpression(t.expression)&&c.isIdentifier(t.expression.name)&&t.expression.name.text===`bind`){let r=e.getSymbolAtLocation(t.expression.expression);r?.valueDeclaration&&c.isVariableDeclaration(r.valueDeclaration)&&r.valueDeclaration.initializer&&(n=e.getTypeAtLocation(r.valueDeclaration.initializer))}for(let e of n.getCallSignatures())if(P(e.getReturnType()))return e;if(n.symbol){let r=e.getTypeOfSymbolAtLocation(n.symbol,t);for(let e of r.getConstructSignatures())if(e.getReturnType().getProperty(`render`))return e}return null}function P(e){return!!I(e)}const F=new Set([`Element`,`ReactElement`]);function I(e){if(e.isUnion()){for(let t of e.types)if(I(t))return!0}return F.has(e.symbol?.getEscapedName().toString())}const L=u({Component:v,ComponentClass:S(v),FunctionComponent:S(v),ReactElement:v,ReactNode:v,ReactNodeArray:b(v),ReactPortal:v}),R=a({typeAnalyzerOptions:({reader:n,rootDir:r})=>{let a=t.fileURLToPath(new URL(`.`,import.meta.url)),l=e.join(a,`..`,`types`),u=e.join(a,`..`,`node_modules`),d=i.existsSync(l)?l:u;return{reader:s([n,o({mapping:{from:d,to:e.join(r,`node_modules`)},watch:!1}),...d===l?[o({mapping:{from:l,to:e.join(r,`node_modules`,`@types`)},watch:!1})]:[]]),specialTypes:L,tsCompilerOptions:{jsx:c.JsxEmit.ReactJSX,jsxImportSource:`react`}}},crawlFile:({logger:e,resolver:t,rootDir:n,absoluteFilePath:r})=>j(e,t,n,r)}),z={line:`data-inspector-line`,column:`data-inspector-column`,relativePath:`data-inspector-relative-path`};function B(e){return e.includes(z.relativePath)}function V(e,t){if(!e.includes(`<`)||B(e))return;let n=c.createSourceFile(t.relativePath,e,c.ScriptTarget.Latest,!0,c.ScriptKind.TSX),r=[],i=e=>{if(c.isJsxElement(e)||c.isJsxSelfClosingElement(e)){let i=c.isJsxElement(e)?e.openingElement:e,a=i.tagName.getStart(n),{line:o,character:s}=n.getLineAndCharacterOfPosition(a),l=i.tagName.getEnd(),u=` ${z.line}="${o+1}" ${z.column}="${s+1}" ${z.relativePath}="${H(t.relativePath)}"`;r.push({at:l,text:u})}c.forEachChild(e,i)};if(i(n),r.length===0)return;r.sort((e,t)=>t.at-e.at);let a=e;for(let{at:e,text:t}of r)a=a.slice(0,e)+t+a.slice(e);return a}function H(e){return e.replace(/&/g,`&amp;`).replace(/"/g,`&quot;`)}const U=/import (\* as )?React[ ,]/;function W(){return{name:`previewjs:react-js-imports`,async transform(t,n){return n.includes(`node_modules`)||e.extname(n)!==`.js`||U.test(t)?t:`import React from 'react';${t}`}}}function G(){let t=``;return{name:`previewjs:inspector-attrs`,enforce:`pre`,configResolved(e){t=e.root},transform(n,r){let i=r.split(`?`)[0]??r;if(!/\.[jt]sx$/.test(i)||i.includes(`node_modules`)||i.includes(`__previewjs__`))return;let a=V(n,{relativePath:e.relative(t,i).split(e.sep).join(`/`)});if(a!==void 0)return{code:a,map:null}}}}const K={info:{apiVersion:5,name:`@cfp-studio/plugin-react`},isCompatible:async e=>{let t=await e.react?.readInstalledVersion();if(!t)return!1;let[n,r]=t.split(`.`).map(e=>Number.parseInt(e));return Number.isNaN(n)||Number.isNaN(r)?!1:n>=17||n===16&&r>=14},async create({rootDir:i,reader:a,logger:o,dependencies:s}){let c=t.fileURLToPath(new URL(`.`,import.meta.url)),l=R({rootDir:i,reader:a,logger:o});return{defaultWrapperPath:`__previewjs__/Wrapper.tsx`,previewDirPath:e.join(c,`..`,`preview`),...l,viteConfig:e=>{let t=e.find(e=>e.name.startsWith(`vite:react-`));return{optimizeDeps:{esbuildOptions:{plugins:s.next?[r()]:[]}},resolve:{alias:{"react-native":`react-native-web`}},plugins:[G(),W(),...e,...t?[]:[n()],{name:`previewjs:update-react-import`,async transform(e,t){if(!t.endsWith(`__previewjs_internal__/renderer/index.tsx`))return;let n=Number.parseInt(await s.react?.readInstalledVersion()||`0`);return e.replace(/__PREVIEWJS_PLUGIN_REACT_IMPORT_PATH__/g,n>=18?`./render-18`:`./render-16`)}}]}}}}};export{K as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfp-studio/plugin-react",
3
- "version": "17.2.1",
3
+ "version": "17.3.1",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "dist",
@@ -15,11 +15,11 @@
15
15
  "@vitejs/plugin-react": "4.3.4",
16
16
  "esbuild-plugin-polyfill-node": "0.3.0",
17
17
  "typescript": "5.9.3",
18
- "@cfp-studio/analyzer-api": "0.1.12",
19
- "@cfp-studio/type-analyzer": "10.1.8",
20
- "@cfp-studio/vfs": "2.1.6",
18
+ "@cfp-studio/analyzer-api": "0.1.13",
19
+ "@cfp-studio/serializable-values": "9.0.8",
21
20
  "@cfp-studio/storybook-helpers": "6.0.2",
22
- "@cfp-studio/serializable-values": "9.0.8"
21
+ "@cfp-studio/type-analyzer": "10.1.8",
22
+ "@cfp-studio/vfs": "2.1.7"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@playwright/test": "1.64.1",
@@ -33,9 +33,9 @@
33
33
  "react-dom": "18.3.1",
34
34
  "vite": "6.4.5",
35
35
  "vitest": "5.0.5",
36
- "@cfp-studio/iframe": "18.2.0",
37
- "@cfp-studio/testing": "14.0.1",
38
- "@cfp-studio/core": "1.0.6"
36
+ "@cfp-studio/core": "1.0.6",
37
+ "@cfp-studio/iframe": "18.4.1",
38
+ "@cfp-studio/testing": "14.0.1"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">=20"
@@ -2,48 +2,42 @@ import type { ReactNode } from "react";
2
2
  import { Component } from "react";
3
3
 
4
4
  type ErrorBoundaryProps = {
5
- renderId: number;
6
- children: ReactNode;
5
+ renderId: number;
6
+ children: ReactNode;
7
7
  };
8
8
 
9
9
  let errorBoundaryInstance: ErrorBoundary | null = null;
10
10
 
11
- export async function expectErrorBoundary(
12
- renderId: number,
13
- shouldAbortRender: () => boolean
14
- ) {
15
- while (
16
- !errorBoundaryInstance ||
17
- errorBoundaryInstance.props.renderId !== renderId
18
- ) {
19
- await new Promise((resolve) => setTimeout(resolve, 100));
20
- if (shouldAbortRender()) {
21
- return null;
22
- }
23
- }
24
- return errorBoundaryInstance;
11
+ export async function expectErrorBoundary(renderId: number, shouldAbortRender: () => boolean) {
12
+ while (!errorBoundaryInstance || errorBoundaryInstance.props.renderId !== renderId) {
13
+ await new Promise((resolve) => setTimeout(resolve, 100));
14
+ if (shouldAbortRender()) {
15
+ return null;
16
+ }
17
+ }
18
+ return errorBoundaryInstance;
25
19
  }
26
20
 
27
21
  export class ErrorBoundary extends Component<ErrorBoundaryProps> {
28
- state = {
29
- error: null as Error | null,
30
- };
31
-
32
- constructor(props: ErrorBoundaryProps) {
33
- super(props);
34
- // eslint-disable-next-line @typescript-eslint/no-this-alias
35
- errorBoundaryInstance = this;
36
- }
37
-
38
- static getDerivedStateFromError(error: Error) {
39
- return { error };
40
- }
41
-
42
- render() {
43
- if (this.state.error) {
44
- return <></>;
45
- }
46
-
47
- return this.props.children;
48
- }
22
+ state = {
23
+ error: null as Error | null,
24
+ };
25
+
26
+ constructor(props: ErrorBoundaryProps) {
27
+ super(props);
28
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
29
+ errorBoundaryInstance = this;
30
+ }
31
+
32
+ static getDerivedStateFromError(error: Error) {
33
+ return { error };
34
+ }
35
+
36
+ render() {
37
+ if (this.state.error) {
38
+ return <></>;
39
+ }
40
+
41
+ return this.props.children;
42
+ }
49
43
  }
package/preview/index.tsx CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { GetPropsFn, RendererLoader } from "@cfp-studio/iframe";
2
- import React from "react";
3
- import { ErrorBoundary, expectErrorBoundary } from "./error-boundary";
4
2
  // @ts-ignore
5
3
  import { render } from "__PREVIEWJS_PLUGIN_REACT_IMPORT_PATH__";
4
+ import React from "react";
5
+
6
+ import { ErrorBoundary, expectErrorBoundary } from "./error-boundary";
6
7
  import { rootContainer } from "./root";
7
8
 
8
9
  /**
@@ -17,78 +18,70 @@ import { rootContainer } from "./root";
17
18
  * @returns 一个对象,包含渲染函数和 JSX 工厂函数。
18
19
  */
19
20
  export const loadRenderer: RendererLoader = async ({
20
- wrapperModule,
21
- wrapperName,
22
- previewableModule,
23
- previewableName,
24
- renderId,
25
- shouldAbortRender,
21
+ wrapperModule,
22
+ wrapperName,
23
+ previewableModule,
24
+ previewableName,
25
+ renderId,
26
+ shouldAbortRender,
26
27
  }) => {
27
- const isStoryModule = !!previewableModule.default?.component;
28
- const Wrapper = wrapperModule?.[wrapperName || "Wrapper"] || React.Fragment;
29
- const Previewable =
30
- previewableModule[previewableName] ||
31
- previewableModule.PreviewJsEval(
32
- `try { return ${previewableName}; } catch { return null; }`
33
- );
34
- if (!Previewable) {
35
- throw new Error(`No component or story named '${previewableName}'`);
36
- }
37
- const decorators = [
38
- ...(Previewable.decorators || []),
39
- ...(previewableModule.default?.decorators || []),
40
- ];
41
- const RenderComponent = isStoryModule
42
- ? typeof Previewable === "function"
43
- ? Previewable
44
- : Previewable.render ||
45
- Previewable.component ||
46
- previewableModule.default?.render ||
47
- previewableModule.default?.component ||
48
- Previewable
49
- : Previewable;
50
- const Renderer = (props: any) => {
51
- return (
52
- <ErrorBoundary renderId={renderId}>
53
- <Wrapper>
54
- {decorators.reduce(
55
- (component, decorator) => () => decorator(component),
56
- () => <RenderComponent {...props} />
57
- )()}
58
- </Wrapper>
59
- </ErrorBoundary>
60
- );
61
- };
62
- return {
63
- render: async (getProps: GetPropsFn) => {
64
- if (shouldAbortRender()) {
65
- return;
66
- }
67
- await render(
68
- <Renderer
69
- {...getProps({
70
- presetGlobalProps: previewableModule.default?.args || {},
71
- presetProps: Previewable.args || {},
72
- })}
73
- />
74
- );
75
- if (shouldAbortRender()) {
76
- return;
77
- }
78
- const errorBoundary = await expectErrorBoundary(
79
- renderId,
80
- shouldAbortRender
81
- );
82
- if (!errorBoundary) {
83
- return;
84
- }
85
- if (errorBoundary.state.error) {
86
- throw errorBoundary.state.error;
87
- }
88
- if (Previewable.play) {
89
- await Previewable.play({ canvasElement: rootContainer });
90
- }
91
- },
92
- jsxFactory: React.createElement,
93
- };
28
+ const isStoryModule = !!previewableModule.default?.component;
29
+ const Wrapper = wrapperModule?.[wrapperName || "Wrapper"] || React.Fragment;
30
+ const Previewable =
31
+ previewableModule[previewableName] ||
32
+ previewableModule.PreviewJsEval(`try { return ${previewableName}; } catch { return null; }`);
33
+ if (!Previewable) {
34
+ throw new Error(`No component or story named '${previewableName}'`);
35
+ }
36
+ const decorators = [...(Previewable.decorators || []), ...(previewableModule.default?.decorators || [])];
37
+ const RenderComponent = isStoryModule
38
+ ? typeof Previewable === "function"
39
+ ? Previewable
40
+ : Previewable.render ||
41
+ Previewable.component ||
42
+ previewableModule.default?.render ||
43
+ previewableModule.default?.component ||
44
+ Previewable
45
+ : Previewable;
46
+ const Renderer = (props: any) => {
47
+ return (
48
+ <ErrorBoundary renderId={renderId}>
49
+ <Wrapper>
50
+ {decorators.reduce(
51
+ (component, decorator) => () => decorator(component),
52
+ () => <RenderComponent {...props} />,
53
+ )()}
54
+ </Wrapper>
55
+ </ErrorBoundary>
56
+ );
57
+ };
58
+ return {
59
+ render: async (getProps: GetPropsFn) => {
60
+ if (shouldAbortRender()) {
61
+ return;
62
+ }
63
+ await render(
64
+ <Renderer
65
+ {...getProps({
66
+ presetGlobalProps: previewableModule.default?.args || {},
67
+ presetProps: Previewable.args || {},
68
+ })}
69
+ />,
70
+ );
71
+ if (shouldAbortRender()) {
72
+ return;
73
+ }
74
+ const errorBoundary = await expectErrorBoundary(renderId, shouldAbortRender);
75
+ if (!errorBoundary) {
76
+ return;
77
+ }
78
+ if (errorBoundary.state.error) {
79
+ throw errorBoundary.state.error;
80
+ }
81
+ if (Previewable.play) {
82
+ await Previewable.play({ canvasElement: rootContainer });
83
+ }
84
+ },
85
+ jsxFactory: React.createElement,
86
+ };
94
87
  };
@@ -1,6 +1,7 @@
1
1
  import ReactDOM from "react-dom";
2
+
2
3
  import { rootContainer } from "./root";
3
4
 
4
5
  export function render(node: JSX.Element) {
5
- ReactDOM.render(node, rootContainer);
6
+ ReactDOM.render(node, rootContainer);
6
7
  }
@@ -1,11 +1,12 @@
1
1
  import type { Root } from "react-dom/client";
2
2
  import { createRoot } from "react-dom/client";
3
+
3
4
  import { rootContainer } from "./root";
4
5
 
5
6
  let root: Root | null = null;
6
7
  export function render(node: JSX.Element) {
7
- if (!root) {
8
- root = createRoot(rootContainer);
9
- }
10
- root.render(node);
8
+ if (!root) {
9
+ root = createRoot(rootContainer);
10
+ }
11
+ root.render(node);
11
12
  }
@@ -1,9 +1,9 @@
1
1
  {
2
- "extends": "../../../../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "module": "ES2022",
5
- "moduleResolution": "Bundler",
6
- "jsx": "preserve"
7
- },
8
- "exclude": ["types"]
2
+ "extends": "../../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "ES2022",
5
+ "moduleResolution": "Bundler",
6
+ "jsx": "preserve"
7
+ },
8
+ "exclude": ["types"]
9
9
  }