├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature_request.md └── workflows │ └── test.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── CHANGELOG.md ├── License ├── README.md ├── README_zh_CN.md ├── docs ├── client-render.svg ├── how-to-work.md ├── img.png └── img_1.png ├── images ├── logo.png ├── mometa-code-edit.gif ├── mometa-delete.gif ├── mometa-edit.gif ├── mometa-insert-material.gif ├── mometa-locate.gif ├── mometa-move.gif ├── mometa-preview-clientrender.gif ├── mometa-preview-responsive.gif ├── mometa-preview-url.gif └── snapshot.png ├── lerna.json ├── package.json ├── packages ├── __template │ ├── index.js │ └── template │ │ ├── README.md │ │ ├── __tests__ │ │ ├── fixture │ │ │ └── .keep │ │ ├── helper.ts.hbs │ │ └── main.test.ts.hbs │ │ ├── jest.config.js │ │ ├── package.json.js │ │ ├── src │ │ └── index.ts.hbs │ │ └── tsconfig.json.hbs ├── app-webpack4 │ ├── .commitlintrc.js │ ├── .env │ ├── .gitignore │ ├── .prettierrc.js │ ├── .stylelintrc.js │ ├── CHANGELOG.md │ ├── README.md │ ├── config │ │ ├── config.js │ │ ├── env.js │ │ ├── getHttpsConfig.js │ │ ├── getPublicUrlOrPath.js │ │ ├── jest │ │ │ ├── babelTransform.js │ │ │ ├── cssTransform.js │ │ │ └── fileTransform.js │ │ ├── modules.js │ │ ├── paths.js │ │ ├── pnpTs.js │ │ ├── utils.js │ │ ├── webpack.config.js │ │ └── webpackDevServer.config.js │ ├── mometa-material.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── saber.yml │ ├── scripts │ │ ├── build.js │ │ ├── start.js │ │ └── test.js │ ├── src │ │ ├── app.scss │ │ ├── app.tsx │ │ ├── index.tsx │ │ ├── page-loading.tsx │ │ ├── react-app-env.d.ts │ │ ├── reportWebVitals.ts │ │ └── setupTests.ts │ └── tsconfig.json ├── app │ ├── .env │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── config │ │ ├── env.js │ │ ├── getHttpsConfig.js │ │ ├── jest │ │ │ ├── babelTransform.js │ │ │ ├── cssTransform.js │ │ │ └── fileTransform.js │ │ ├── modules.js │ │ ├── paths.js │ │ ├── webpack.config.js │ │ ├── webpack │ │ │ └── persistentCache │ │ │ │ └── createEnvironmentHash.js │ │ └── webpackDevServer.config.js │ ├── mometa-material.config.js │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── scripts │ │ ├── build.js │ │ ├── start.js │ │ └── test.js │ ├── src │ │ ├── api │ │ │ └── index.ts │ │ ├── component │ │ │ └── detail │ │ │ │ └── index.tsx │ │ ├── index.css │ │ ├── index.tsx │ │ ├── layout │ │ │ └── index.tsx │ │ ├── materials │ │ │ └── button │ │ │ │ ├── index.tsx │ │ │ │ └── style.css │ │ ├── pages │ │ │ ├── app │ │ │ │ ├── App.css │ │ │ │ ├── App.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── logo.svg │ │ │ ├── detail │ │ │ │ └── index.tsx │ │ │ ├── edit │ │ │ │ └── index.tsx │ │ │ └── home │ │ │ │ └── index.tsx │ │ ├── react-app-env.d.ts │ │ ├── render-router.tsx │ │ ├── reportWebVitals.ts │ │ ├── routes.tsx │ │ └── setupTests.ts │ └── tsconfig.json ├── editor │ ├── .gitignore │ ├── CHANGELOG.md │ ├── README.md │ ├── __template │ │ └── component │ │ │ ├── index.js │ │ │ └── template │ │ │ ├── index.tsx.hbs │ │ │ └── style.scss.hbs │ ├── __tests__ │ │ ├── fixture │ │ │ ├── .keep │ │ │ └── webpack │ │ │ │ └── src │ │ │ │ └── index.js │ │ ├── helper.ts │ │ ├── main.test.ts │ │ └── webpack-plugin.test.ts │ ├── babel │ │ └── plugin-react.js │ ├── example │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── config │ │ │ ├── entry │ │ │ │ └── __mometa_outer_vendor__.js │ │ │ ├── env.js │ │ │ ├── getHttpsConfig.js │ │ │ ├── jest │ │ │ │ ├── babelTransform.js │ │ │ │ ├── cssTransform.js │ │ │ │ └── fileTransform.js │ │ │ ├── modules.js │ │ │ ├── paths.js │ │ │ ├── post-buildruntime.js │ │ │ ├── webpack.config.js │ │ │ ├── webpack │ │ │ │ └── persistentCache │ │ │ │ │ └── createEnvironmentHash.js │ │ │ └── webpackDevServer.config.js │ │ ├── mometa-material.config.js │ │ ├── package.json │ │ ├── public │ │ │ ├── editor-runtime.html │ │ │ ├── favicon.png │ │ │ └── index.html │ │ ├── scripts │ │ │ ├── build.js │ │ │ ├── start.js │ │ │ └── test.js │ │ ├── src │ │ │ ├── .prettierignore │ │ │ ├── app │ │ │ │ ├── App.tsx │ │ │ │ ├── ListPage.tsx │ │ │ │ ├── Panel.tsx │ │ │ │ ├── elements.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.css │ │ │ ├── editor.tsx │ │ │ ├── index.tsx │ │ │ ├── materials │ │ │ │ └── button │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.css │ │ │ ├── mock │ │ │ │ ├── noop-webpack-plugin.js │ │ │ │ └── terser-webpack-plugin.js │ │ │ ├── react-app-env.d.ts │ │ │ ├── setupProxy.js │ │ │ └── setupTests.ts │ │ └── tsconfig.json │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── babel │ │ │ └── react │ │ │ │ ├── __snapshots__ │ │ │ │ └── index.test.ts.snap │ │ │ │ ├── index.test.ts │ │ │ │ └── index.ts │ │ ├── editor.ts │ │ ├── entry.tsx │ │ ├── module │ │ │ ├── config │ │ │ │ └── const.ts │ │ │ ├── render-floating.tsx │ │ │ └── render │ │ │ │ ├── .keep │ │ │ │ ├── components │ │ │ │ ├── error-boundary │ │ │ │ │ └── index.tsx │ │ │ │ ├── header │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── logo.png │ │ │ │ │ └── style.scss │ │ │ │ ├── left-panel │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ ├── location-widget │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ ├── material-panel │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ ├── resize-handler │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ ├── resize-widget │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ ├── right-panel │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ └── stage │ │ │ │ │ ├── api-core.tsx │ │ │ │ │ ├── create-api.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── style.scss │ │ │ │ ├── editor │ │ │ │ ├── index.tsx │ │ │ │ ├── sse.ts │ │ │ │ └── style.scss │ │ │ │ ├── style │ │ │ │ └── _var.scss │ │ │ │ └── utils │ │ │ │ ├── error-overlay │ │ │ │ ├── formatWebpackMessages.ts │ │ │ │ └── index.ts │ │ │ │ ├── externals-modules.ts │ │ │ │ ├── fetch-preload.ts │ │ │ │ ├── use-persist-ref.ts │ │ │ │ └── utils.ts │ │ ├── mometa │ │ │ ├── config │ │ │ │ └── const.ts │ │ │ ├── define.d.ts │ │ │ ├── entry.ts │ │ │ ├── location-register.ts │ │ │ ├── render-register.ts │ │ │ ├── runtime │ │ │ │ ├── components │ │ │ │ │ └── more-button │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── style.scss │ │ │ │ ├── dnd.tsx │ │ │ │ ├── dom-api.ts │ │ │ │ ├── empty-placeholder.tsx │ │ │ │ ├── floating-ui.tsx │ │ │ │ ├── provider.tsx │ │ │ │ └── style │ │ │ │ │ └── _var.scss │ │ │ ├── shared-register.ts │ │ │ └── utils │ │ │ │ ├── debuglog.ts │ │ │ │ ├── dom-utils.ts │ │ │ │ ├── emotion-css.ts │ │ │ │ ├── get-from-main.ts │ │ │ │ └── use-hooks.ts │ │ └── shared │ │ │ ├── code-editor │ │ │ └── index.tsx │ │ │ ├── hot.ts │ │ │ ├── locate-material-parents.ts │ │ │ ├── open-react-element.tsx │ │ │ ├── pipe.ts │ │ │ └── utils.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── webpack │ │ ├── common-plugin.js │ │ ├── create-server.js │ │ ├── event-stream │ │ └── createEventStream.js │ │ ├── index.js │ │ ├── inject-entry.js │ │ ├── launchEditor.js │ │ ├── materials-compiler │ │ ├── client-render-compile.js │ │ ├── client-render-loader │ │ │ ├── bye.js │ │ │ ├── index.js │ │ │ ├── preview-code-gen.js │ │ │ ├── preview-loader.js │ │ │ └── write-runtime-preview-render.js │ │ └── index.js │ │ ├── options-json.js │ │ ├── paths.js │ │ └── runtime │ │ ├── .gitignore │ │ ├── client-render-main.js │ │ ├── handle.js │ │ ├── preview-render │ │ └── .gitkeep │ │ └── runtime-entry.js ├── fs-handler │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── __snapshots__ │ │ │ └── main.test.ts.snap │ │ ├── fixture │ │ │ ├── .keep │ │ │ ├── nested.tsx │ │ │ ├── react-comp.tsx │ │ │ ├── simple.d.ts │ │ │ ├── simple.js │ │ │ ├── simple.js.map │ │ │ └── simple.tsx │ │ ├── helper.ts │ │ └── main.test.ts │ ├── const.js │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── common │ │ │ ├── add-material │ │ │ │ └── index.ts │ │ │ ├── del.ts │ │ │ ├── index.ts │ │ │ ├── insert-node.ts │ │ │ ├── move-node.ts │ │ │ └── replace-node.ts │ │ ├── const.ts │ │ ├── index.ts │ │ └── utils │ │ │ ├── compare.ts │ │ │ ├── line-contents.test.ts │ │ │ └── line-contents.ts │ └── tsconfig.json ├── materials-generator │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── plugins │ │ │ ├── create.ts │ │ │ └── helper.ts │ │ └── types.ts │ ├── tsconfig.json │ └── types.js ├── materials-resolver │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── fixture │ │ │ ├── invalid-mat-lib │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ └── mat-lib │ │ │ │ ├── index.js │ │ │ │ ├── mometa.js │ │ │ │ └── package.json │ │ ├── helper.ts │ │ └── main.test.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── plugins │ │ │ ├── materials.ts │ │ │ └── react-component-asset.ts │ │ └── utils │ │ │ ├── react-api-parse.ts │ │ │ ├── resolve-async-config.ts │ │ │ ├── search-core.ts │ │ │ ├── sorted-globby.ts │ │ │ └── to-array.ts │ └── tsconfig.json ├── react-docgen-typescript │ ├── CHANGELOG.md │ ├── README.md │ ├── __tests__ │ │ ├── fixture │ │ │ └── .keep │ │ ├── helper.ts │ │ └── main.test.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── __tests__ │ │ │ ├── __sourceMapInit.ts │ │ │ ├── buildFilter.ts │ │ │ ├── data │ │ │ │ ├── AppMenu.tsx │ │ │ │ ├── ButtonWithOnClickComponent.tsx │ │ │ │ ├── Column.tsx │ │ │ │ ├── ColumnHigherOrderComponent.tsx │ │ │ │ ├── ColumnHigherOrderComponentHoc.tsx │ │ │ │ ├── ColumnWithAnnotatedChildren.tsx │ │ │ │ ├── ColumnWithDefaultAnonymousExportOnly.tsx │ │ │ │ ├── ColumnWithDefaultExport.tsx │ │ │ │ ├── ColumnWithDefaultExportOnly.tsx │ │ │ │ ├── ColumnWithHtmlAttributes.tsx │ │ │ │ ├── ColumnWithLog.tsx │ │ │ │ ├── ColumnWithMethods.tsx │ │ │ │ ├── ColumnWithPick.tsx │ │ │ │ ├── ColumnWithPropsWithExternalType.MyExternalType.tsx │ │ │ │ ├── ColumnWithPropsWithExternalType.tsx │ │ │ │ ├── ColumnWithStaticComponents.tsx │ │ │ │ ├── ColumnWithStaticMethods.tsx │ │ │ │ ├── ColumnWithUndocumentedProps.tsx │ │ │ │ ├── ColumnWithoutExportedProps.tsx │ │ │ │ ├── ComplexGenericUnionIntersection.tsx │ │ │ │ ├── ComplexGenericUnionIntersectionWithOmit.tsx │ │ │ │ ├── ComponentWithDefaultProps.tsx │ │ │ │ ├── ComponentWithImportedDefaultProps.tsx │ │ │ │ ├── ComponentWithReferencedDefaultProps.tsx │ │ │ │ ├── ComponentWithTypeJsDocTag.tsx │ │ │ │ ├── ConstExport.tsx │ │ │ │ ├── ExportObject.tsx │ │ │ │ ├── ExportsDefaultInterface.tsx │ │ │ │ ├── ExportsPropTypeImport.tsx │ │ │ │ ├── ExportsPropTypeShape.tsx │ │ │ │ ├── ExtendsExternalPropsComponent.tsx │ │ │ │ ├── ExtendsExternalPropsComponentParentProps.tsx │ │ │ │ ├── ExternalPropsComponent.tsx │ │ │ │ ├── ExternalPropsComponentProps.ts │ │ │ │ ├── ExtractLiteralValuesFromEnum.tsx │ │ │ │ ├── ExtractLiteralValuesFromUnion.tsx │ │ │ │ ├── ExtractPropTags.tsx │ │ │ │ ├── FilePathCheck.tsx │ │ │ │ ├── FlippableImage.tsx │ │ │ │ ├── ForwardRefDefaultExport.tsx │ │ │ │ ├── ForwardRefDefaultExportAtExport.tsx │ │ │ │ ├── ForwardRefDefaultValues.tsx │ │ │ │ ├── FunctionDeclaration.tsx │ │ │ │ ├── FunctionDeclarationAsDefaultExport.tsx │ │ │ │ ├── FunctionDeclarationAsDefaultExportWithMemo.tsx │ │ │ │ ├── FunctionDeclarationDefaultProps.tsx │ │ │ │ ├── FunctionDeclarationVisibleName.tsx │ │ │ │ ├── FunctionalComponentAsConst.tsx │ │ │ │ ├── FunctionalComponentAsConstAsDefaultExport.tsx │ │ │ │ ├── FunctionalComponentAsConstAsNamedExport.tsx │ │ │ │ ├── FunctionalComponentWithDesctructuredProps.constants.ts │ │ │ │ ├── FunctionalComponentWithDesctructuredProps.tsx │ │ │ │ ├── FunctionalComponentWithDesctructuredPropsAndImportedConstants.tsx │ │ │ │ ├── GenericWithExtends.tsx │ │ │ │ ├── HOCIntersectionProps.tsx │ │ │ │ ├── InlineConst.tsx │ │ │ │ ├── Issue188.tsx │ │ │ │ ├── Issue320.tsx │ │ │ │ ├── JSDocWithParam.tsx │ │ │ │ ├── OnlyDefaultExportUnion.tsx │ │ │ │ ├── OnlyDefaultExportUnionAsExport.tsx │ │ │ │ ├── PureRow.tsx │ │ │ │ ├── ReactSFCAsConst.tsx │ │ │ │ ├── ReactSFCAsConstAsDefaultExport.tsx │ │ │ │ ├── ReactSFCAsConstAsNamedExport.tsx │ │ │ │ ├── Regression_v0_0_12.tsx │ │ │ │ ├── RemoveOptionalValuesFromEnum.tsx │ │ │ │ ├── RemoveOptionalValuesFromUnion.tsx │ │ │ │ ├── Row.tsx │ │ │ │ ├── SeparateDefaultProps.tsx │ │ │ │ ├── SeparateDefaultPropsIndividual.tsx │ │ │ │ ├── SimpleDiscriminatedUnionIntersection.tsx │ │ │ │ ├── SimpleGenericUnionIntersection.tsx │ │ │ │ ├── SimpleUnionIntersection.tsx │ │ │ │ ├── StatefulDisplayName.tsx │ │ │ │ ├── StatefulDisplayNameDefaultExport.tsx │ │ │ │ ├── StatefulDisplayNameFolder │ │ │ │ │ └── index.tsx │ │ │ │ ├── StatefulDisplayNameHOC.tsx │ │ │ │ ├── StatefulIntersectionExternalProps.tsx │ │ │ │ ├── StatefulIntersectionProps.tsx │ │ │ │ ├── Stateless.tsx │ │ │ │ ├── StatelessDisplayName.tsx │ │ │ │ ├── StatelessDisplayNameDefaultExport.tsx │ │ │ │ ├── StatelessDisplayNameDefaultExportDifferentFilename.tsx │ │ │ │ ├── StatelessDisplayNameFolder │ │ │ │ │ └── index.tsx │ │ │ │ ├── StatelessDisplayNameHOC.tsx │ │ │ │ ├── StatelessDisplayNameStyledComponent.tsx │ │ │ │ ├── StatelessIntersectionExternalProps.tsx │ │ │ │ ├── StatelessIntersectionGenericProps.tsx │ │ │ │ ├── StatelessIntersectionProps.tsx │ │ │ │ ├── StatelessShorthandDefaultProps.tsx │ │ │ │ ├── StatelessStaticComponents.tsx │ │ │ │ ├── StatelessWithDefaultOnlyJsDoc.tsx │ │ │ │ ├── StatelessWithDefaultProps.tsx │ │ │ │ ├── StatelessWithDefaultPropsAsString.tsx │ │ │ │ ├── StatelessWithDefaultPropsTypescript3.tsx │ │ │ │ ├── StatelessWithDestructuredProps.tsx │ │ │ │ ├── StatelessWithDestructuredPropsArrow.tsx │ │ │ │ ├── UnassignedLet.tsx │ │ │ │ ├── const.ts │ │ │ │ ├── shapes.ts │ │ │ │ ├── tsconfig.json │ │ │ │ └── withHOC.tsx │ │ │ ├── parser.ts │ │ │ ├── testUtils.ts │ │ │ └── trimFileName.ts │ │ ├── buildFilter.ts │ │ ├── index.ts │ │ ├── parser.ts │ │ ├── propTypesParser.ts │ │ └── trimFileName.ts │ └── tsconfig.json └── react-refresh-webpack-plugin │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── client │ ├── ErrorOverlayEntry.js │ ├── ReactRefreshEntry.js │ ├── package.json │ └── utils │ │ ├── errorEventHandlers.js │ │ ├── formatWebpackErrors.js │ │ ├── patchUrl.js │ │ └── retry.js │ ├── lib │ ├── globals.js │ ├── index.js │ ├── options.json │ ├── runtime │ │ ├── RefreshUtils.development.js │ │ ├── RefreshUtils.js │ │ └── RefreshUtils.production.js │ ├── types.js │ └── utils │ │ ├── getAdditionalEntries.js │ │ ├── getIntegrationEntry.js │ │ ├── getRefreshGlobal.js │ │ ├── getSocketIntegration.js │ │ ├── index.js │ │ ├── injectRefreshEntry.js │ │ ├── injectRefreshLoader.js │ │ ├── makeRefreshRuntimeModule.js │ │ └── normalizeOptions.js │ ├── loader │ ├── index.js │ ├── options.json │ ├── types.js │ └── utils │ │ ├── getIdentitySourceMap.js │ │ ├── getModuleSystem.js │ │ ├── getRefreshModuleRuntime.js │ │ ├── index.js │ │ └── normalizeOptions.js │ ├── options │ └── index.js │ ├── overlay │ ├── components │ │ ├── CompileErrorTrace.js │ │ ├── PageHeader.js │ │ ├── RuntimeErrorFooter.js │ │ ├── RuntimeErrorHeader.js │ │ ├── RuntimeErrorStack.js │ │ └── Spacer.js │ ├── containers │ │ ├── CompileErrorContainer.js │ │ └── RuntimeErrorContainer.js │ ├── index.js │ ├── package.json │ ├── theme.js │ └── utils.js │ ├── package.json │ ├── sockets │ ├── WDSSocket.js │ ├── WHMEventSource.js │ ├── WPSSocket.js │ ├── package.json │ └── utils │ │ ├── getCurrentScriptSource.js │ │ ├── getSocketUrlParts.js │ │ ├── getUrlFromParts.js │ │ └── getWDSMetadata.js │ ├── tsconfig.json │ └── types │ ├── loader │ ├── index.d.ts │ └── types.d.ts │ └── options │ └── index.d.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts ├── run-build.js ├── run-packlimit ├── run-pkgxo ├── run-test └── run.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | title: 'Bug: ' 5 | labels: bug 6 | assignees: imcuttle 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Environment (please complete the following information):** 27 | 28 | - mometa version: 29 | - OS: [e.g. iOS] 30 | - npm/pnpm/Node.js Version: [e.g. 22] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: 'Feature: ' 5 | labels: enhancement 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .DS_Store 3 | node_modules/ 4 | dist/ 5 | /public/ 6 | **/*debug.log 7 | coverage/ 8 | .entry 9 | .dist 10 | .vscode 11 | lib/ 12 | types/ 13 | es/ 14 | 15 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | __templates/ 2 | __template/ 3 | pnpm-lock.yaml 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | useTabs: false, // Indent lines with tabs instead of spaces. 3 | printWidth: 120, // Specify the length of line that the printer will wrap on. 4 | tabWidth: 2, // Specify the number of spaces per indentation-level. 5 | singleQuote: true, // Use single quotes instead of double quotes. 6 | trailingComma: 'none', 7 | semi: false 8 | } 9 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) imcuttle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /docs/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/docs/img.png -------------------------------------------------------------------------------- /docs/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/docs/img_1.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/logo.png -------------------------------------------------------------------------------- /images/mometa-code-edit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-code-edit.gif -------------------------------------------------------------------------------- /images/mometa-delete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-delete.gif -------------------------------------------------------------------------------- /images/mometa-edit.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-edit.gif -------------------------------------------------------------------------------- /images/mometa-insert-material.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-insert-material.gif -------------------------------------------------------------------------------- /images/mometa-locate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-locate.gif -------------------------------------------------------------------------------- /images/mometa-move.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-move.gif -------------------------------------------------------------------------------- /images/mometa-preview-clientrender.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-preview-clientrender.gif -------------------------------------------------------------------------------- /images/mometa-preview-responsive.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-preview-responsive.gif -------------------------------------------------------------------------------- /images/mometa-preview-url.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/mometa-preview-url.gif -------------------------------------------------------------------------------- /images/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/images/snapshot.png -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/*", "packages/editor/example"], 3 | "version": "0.0.33", 4 | "extendCommands": ["lerna-command-toc"], 5 | "command": { 6 | "publish": { 7 | "changelogPreset": { 8 | "name": "conventional-changelog-conventionalcommits" 9 | }, 10 | "conventionalCommits": true, 11 | "message": "chore(release): publish" 12 | }, 13 | "run": { 14 | "stream": true 15 | }, 16 | "bootstrap": { 17 | "hoist": true, 18 | "nohoist": ["webpack-manifest-plugin", "@types/react-router-dom", "@types/react-router"], 19 | "npmClientArgs": [] 20 | } 21 | }, 22 | "ignoreChanges": ["**/__fixtures__/**", "**/__tests__/**", "**/package.json"] 23 | } 24 | -------------------------------------------------------------------------------- /packages/__template/template/__tests__/fixture/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/__template/template/__tests__/fixture/.keep -------------------------------------------------------------------------------- /packages/__template/template/__tests__/helper.ts.hbs: -------------------------------------------------------------------------------- 1 | /** * @file helper */ const nps = require('path') 2 | 3 | {{#if useTs}} 4 | export function fixture(...args: string[]) { return nps.join.apply(nps, [__dirname, 'fixture'].concat(...args)) } 5 | {{else}} 6 | export function fixture(...args) { return nps.join.apply(nps, [__dirname, 'fixture'].concat(...args)) } 7 | {{/if}} -------------------------------------------------------------------------------- /packages/__template/template/__tests__/main.test.ts.hbs: -------------------------------------------------------------------------------- 1 | {{#if useTs}} 2 | import 3 | {{camelCase name}} 4 | from '../src' 5 | {{else}} 6 | const 7 | {{camelCase name}} 8 | = require('../src') 9 | {{/if}} 10 | 11 | describe('{{camelCase name}}', function() { it( 'spec case', function () { } ) }) -------------------------------------------------------------------------------- /packages/__template/template/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../../package.json').jest 3 | } 4 | -------------------------------------------------------------------------------- /packages/__template/template/src/index.ts.hbs: -------------------------------------------------------------------------------- 1 | /** 2 | * {{description}} 3 | * @author {{_.git.name}} 4 | */ 5 | 6 | {{#if useTs}}export default{{else}}module.exports ={{/if}} function {{camelCase name}}() { } 7 | -------------------------------------------------------------------------------- /packages/__template/template/tsconfig.json.hbs: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "{{{rootRelativeDir}}}/tsconfig.json", 3 | "compilerOptions": {}, 4 | "exclude": ["node_modules"], 5 | "include": ["./src"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/app-webpack4/.commitlintrc.js: -------------------------------------------------------------------------------- 1 | /* 2 | build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交 3 | ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交 4 | docs:文档更新 5 | feat:新增功能 6 | merge:分支合并 Merge branch ? of ? 7 | fix:bug 修复 8 | perf:性能, 体验优化 9 | refactor:重构代码(既没有新增功能,也没有修复 bug) 10 | style:不影响程序逻辑的代码修改(修改空白字符,格式缩进,补全缺失的分号等,没有改变代码逻辑) 11 | test:新增测试用例或是更新现有测试 12 | revert:回滚某个更早之前的提交 13 | chore:不属于以上类型的其他类型 14 | */ 15 | 16 | module.exports = { 17 | extends: ['@tutor/commitlint-recommended'], 18 | }; 19 | -------------------------------------------------------------------------------- /packages/app-webpack4/.env: -------------------------------------------------------------------------------- 1 | PORT=5000 2 | -------------------------------------------------------------------------------- /packages/app-webpack4/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /packages/app-webpack4/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | singleQuote: true, 4 | trailingComma: 'es5', 5 | arrowParens: 'avoid', 6 | tabWidth: 2, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/app-webpack4/.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'stylelint-config-sass-guidelines', 3 | rules: { 4 | 'at-rule-name-case': 'lower', 5 | 'block-no-empty': true, 6 | 'no-empty-source': null, 7 | 'declaration-block-semicolon-newline-after': null, 8 | 'no-duplicate-selectors': null, 9 | 'scss/selector-no-redundant-nesting-selector': null, 10 | 'rule-empty-line-before': null, 11 | 'max-nesting-depth': null, 12 | 'order/properties-alphabetical-order': null, 13 | 'declaration-colon-newline-after': 'always-multi-line', 14 | 'value-list-comma-newline-after': 'always-multi-line', 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /packages/app-webpack4/README.md: -------------------------------------------------------------------------------- 1 | # app-webpack4 2 | 3 | > abc 4 | -------------------------------------------------------------------------------- /packages/app-webpack4/config/config.js: -------------------------------------------------------------------------------- 1 | const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; 2 | const HOST = process.env.HOST || 'local.yuanfudao.biz'; 3 | 4 | module.exports = { 5 | DEFAULT_PORT, 6 | HOST, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/app-webpack4/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const babelJest = require('babel-jest'); 4 | 5 | const hasJsxRuntime = (() => { 6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { 7 | return false; 8 | } 9 | 10 | try { 11 | require.resolve('react/jsx-runtime'); 12 | return true; 13 | } catch (e) { 14 | return false; 15 | } 16 | })(); 17 | 18 | module.exports = babelJest.createTransformer({ 19 | presets: [ 20 | [ 21 | require.resolve('babel-preset-react-app'), 22 | { 23 | runtime: hasJsxRuntime ? 'automatic' : 'classic', 24 | }, 25 | ], 26 | ], 27 | babelrc: false, 28 | configFile: false, 29 | }); 30 | -------------------------------------------------------------------------------- /packages/app-webpack4/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};'; 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform'; 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /packages/app-webpack4/config/pnpTs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { resolveModuleName } = require('ts-pnp'); 4 | 5 | exports.resolveModuleName = (typescript, moduleName, containingFile, compilerOptions, resolutionHost) => { 6 | return resolveModuleName(moduleName, containingFile, compilerOptions, resolutionHost, typescript.resolveModuleName); 7 | }; 8 | 9 | exports.resolveTypeReferenceDirective = (typescript, moduleName, containingFile, compilerOptions, resolutionHost) => { 10 | return resolveModuleName( 11 | moduleName, 12 | containingFile, 13 | compilerOptions, 14 | resolutionHost, 15 | typescript.resolveTypeReferenceDirective 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/app-webpack4/config/utils.js: -------------------------------------------------------------------------------- 1 | const GIT_BRANCH = process.env.GIT_BRANCH; 2 | const isOnlineBranch = !!GIT_BRANCH && /^(online)$/.test(GIT_BRANCH); 3 | const isTestMainBranch = !!GIT_BRANCH && /^(master$)/.test(GIT_BRANCH); 4 | const isTestOtherBranch = !isOnlineBranch && !isTestMainBranch; 5 | 6 | module.exports = { 7 | isTestOtherBranch, 8 | isTestMainBranch, 9 | isOnlineBranch, 10 | GIT_BRANCH, 11 | }; 12 | -------------------------------------------------------------------------------- /packages/app-webpack4/mometa-material.config.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { 3 | name: 'WWWppX', 4 | key: 'component-x', 5 | }, 6 | require('@mometa-mat/antd').default, 7 | ]; 8 | -------------------------------------------------------------------------------- /packages/app-webpack4/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app-webpack4/public/favicon.ico -------------------------------------------------------------------------------- /packages/app-webpack4/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app-webpack4/public/logo192.png -------------------------------------------------------------------------------- /packages/app-webpack4/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app-webpack4/public/logo512.png -------------------------------------------------------------------------------- /packages/app-webpack4/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/app-webpack4/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/app-webpack4/src/app.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app-webpack4/src/app.scss -------------------------------------------------------------------------------- /packages/app-webpack4/src/app.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ConfigProvider, Button, Typography } from 'antd'; 3 | import { HashRouter } from 'react-router-dom'; 4 | import { Route } from 'react-router'; 5 | import zhCN from 'antd/lib/locale/zh_CN'; 6 | import './app.scss'; 7 | import pageDefaultLoading from '@/page-loading'; 8 | 9 | function App() { 10 | return ( 11 | 12 | 13 | 14 | 15 | <> 16 |

End

17 |

Start

18 | 19 |
20 | {/**/} 21 |
22 |
23 |
24 | ); 25 | } 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /packages/app-webpack4/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './app'; 4 | import reportWebVitals from './reportWebVitals'; 5 | 6 | ReactDOM.render( 7 | // 8 | , 9 | // , 10 | document.getElementById('root') 11 | ); 12 | 13 | // If you want to start measuring performance in your app, pass a function 14 | // to log results (for example: reportWebVitals(console.log)) 15 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 16 | reportWebVitals(); 17 | -------------------------------------------------------------------------------- /packages/app-webpack4/src/page-loading.tsx: -------------------------------------------------------------------------------- 1 | // DO NOT MODIFY ME! I was used in react-webpack-lazyloader 2 | import * as React from 'react'; 3 | import { Spin } from 'antd'; 4 | 5 | const pageDefaultLoading = ; 6 | export default pageDefaultLoading; 7 | -------------------------------------------------------------------------------- /packages/app-webpack4/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /packages/app-webpack4/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /packages/app-webpack4/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "experimentalDecorators": true, 4 | "target": "es5", 5 | "lib": ["dom", "dom.iterable", "esnext"], 6 | "allowJs": true, 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "module": "esnext", 14 | "moduleResolution": "node", 15 | "resolveJsonModule": true, 16 | "isolatedModules": true, 17 | "noEmit": true, 18 | "jsx": "react-jsx", 19 | "baseUrl": ".", 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/app/.env: -------------------------------------------------------------------------------- 1 | PORT=4000 2 | #MOMETA_EDITOR=webstorm 3 | MOMETA_EDITOR=vscode 4 | -------------------------------------------------------------------------------- /packages/app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /packages/app/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const babelJest = require('babel-jest').default 4 | 5 | const hasJsxRuntime = (() => { 6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { 7 | return false 8 | } 9 | 10 | try { 11 | require.resolve('react/jsx-runtime') 12 | return true 13 | } catch (e) { 14 | return false 15 | } 16 | })() 17 | 18 | module.exports = babelJest.createTransformer({ 19 | presets: [ 20 | [ 21 | require.resolve('babel-preset-react-app'), 22 | { 23 | runtime: hasJsxRuntime ? 'automatic' : 'classic' 24 | } 25 | ] 26 | ], 27 | babelrc: false, 28 | configFile: false 29 | }) 30 | -------------------------------------------------------------------------------- /packages/app/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};' 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/app/config/webpack/persistentCache/createEnvironmentHash.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const { createHash } = require('crypto') 3 | 4 | module.exports = (env) => { 5 | const hash = createHash('md5') 6 | hash.update(JSON.stringify(env)) 7 | 8 | return hash.digest('hex') 9 | } 10 | -------------------------------------------------------------------------------- /packages/app/mometa-material.config.js: -------------------------------------------------------------------------------- 1 | // const { resolveLibMatConfig } = require('@mometa/materials-resolver') 2 | // const React from 'react' 3 | 4 | module.exports = [ 5 | { 6 | name: 'Local Mat', 7 | key: 'local-mat', 8 | assetGroups: [ 9 | { 10 | name: '通用', 11 | key: 'gen', 12 | assets: [ 13 | { 14 | name: '按钮', 15 | key: 'Button', 16 | cover: 'https://gw.alipayobjects.com/zos/alicdn/fNUKzY1sk/Button.svg', 17 | data: { 18 | code: '', 19 | dependencies: { 20 | Button: { 21 | source: '@/materials/button', 22 | mode: 'default' 23 | } 24 | } 25 | } 26 | } 27 | ] 28 | } 29 | ] 30 | }, 31 | require('@mometa-mat/antd').default 32 | ] 33 | -------------------------------------------------------------------------------- /packages/app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app/public/favicon.ico -------------------------------------------------------------------------------- /packages/app/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app/public/logo192.png -------------------------------------------------------------------------------- /packages/app/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/app/public/logo512.png -------------------------------------------------------------------------------- /packages/app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/app/src/api/index.ts: -------------------------------------------------------------------------------- 1 | import axiosStatic from 'axios' 2 | 3 | const axios = axiosStatic.create({ 4 | baseURL: 'https://jsonplaceholder.typicode.com/' 5 | }) 6 | 7 | export async function getUsers(filterParams?: any) { 8 | const res = await axios.get('/users', { params: filterParams }) 9 | return res.data 10 | } 11 | 12 | export async function getUser(id: any) { 13 | const res = await axios.get('/users/' + id) 14 | return res.data 15 | } 16 | 17 | export async function updateUser(id: any, data: any) { 18 | const res = await axios.put('/users/' + id, data) 19 | return res.data 20 | } 21 | 22 | export async function createUser(data: any) { 23 | const res = await axios.post('/users', data) 24 | return res.data 25 | } 26 | 27 | export async function removeUser(id: any) { 28 | const res = await axios.delete('/users/' + id) 29 | return res.data 30 | } 31 | -------------------------------------------------------------------------------- /packages/app/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 4 | 'Droid Sans', 'Helvetica Neue', sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | } 8 | 9 | code { 10 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 11 | } 12 | -------------------------------------------------------------------------------- /packages/app/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './index.css' 4 | import { HashRouter, BrowserRouter } from 'react-router-dom' 5 | import reportWebVitals from './reportWebVitals' 6 | import { RouterRender } from './render-router' 7 | import { routes } from './routes' 8 | 9 | ReactDOM.render( 10 | 11 | 12 | 13 | 14 | , 15 | document.getElementById('root') 16 | ) 17 | 18 | // If you want to start measuring performance in your app, pass a function 19 | // to log results (for example: reportWebVitals(console.log)) 20 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 21 | reportWebVitals() 22 | -------------------------------------------------------------------------------- /packages/app/src/materials/button/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './style.css' 3 | 4 | console.log('materials Button') 5 | 6 | export default function Button() { 7 | console.log('materials Button render1') 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /packages/app/src/materials/button/style.css: -------------------------------------------------------------------------------- 1 | .mat-button { 2 | color: red !important; 3 | } 4 | -------------------------------------------------------------------------------- /packages/app/src/pages/app/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/app/src/pages/app/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import logo from './logo.svg' 3 | import './App.css' 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 |

10 | Edit src/App.tsx and save to reload. 11 |

12 | logo 13 | 14 | Learn React 15 | 16 |
17 |
18 | ) 19 | } 20 | 21 | export default App 22 | -------------------------------------------------------------------------------- /packages/app/src/pages/app/index.tsx: -------------------------------------------------------------------------------- 1 | import App from './App' 2 | 3 | export default App 4 | -------------------------------------------------------------------------------- /packages/app/src/pages/detail/index.tsx: -------------------------------------------------------------------------------- 1 | import { Detail } from '../../component/detail' 2 | 3 | export default function DetailPage({ match }: any) { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /packages/app/src/pages/edit/index.tsx: -------------------------------------------------------------------------------- 1 | import { Detail } from '../../component/detail' 2 | 3 | export default function EditPage({ match }: any) { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /packages/app/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals' 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry) 7 | getFID(onPerfEntry) 8 | getFCP(onPerfEntry) 9 | getLCP(onPerfEntry) 10 | getTTFB(onPerfEntry) 11 | }) 12 | } 13 | } 14 | 15 | export default reportWebVitals 16 | -------------------------------------------------------------------------------- /packages/app/src/routes.tsx: -------------------------------------------------------------------------------- 1 | import HomePage from './pages/home' 2 | import DetailPage from './pages/detail' 3 | import { RouteConfig } from './render-router' 4 | import App from './pages/app' 5 | import Layout from './layout' 6 | import EditPage from './pages/edit' 7 | import { Detail } from './component/detail' 8 | 9 | export const routes: RouteConfig[] = [ 10 | { 11 | path: '', 12 | component: Layout, 13 | routes: [ 14 | { 15 | name: 'Home', 16 | path: '/', 17 | component: HomePage 18 | }, 19 | { 20 | path: '/detail/:id', 21 | component: DetailPage 22 | }, 23 | { 24 | path: '/edit/:id', 25 | component: EditPage 26 | }, 27 | { 28 | path: '/new', 29 | component: () => { 30 | return 31 | } 32 | }, 33 | { 34 | name: 'App', 35 | path: '/app', 36 | component: App 37 | } 38 | ] 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /packages/app/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom' 6 | -------------------------------------------------------------------------------- /packages/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx", 18 | "baseUrl": ".", 19 | "paths": { 20 | "@/*": ["./src/*"] 21 | } 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/editor/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | -------------------------------------------------------------------------------- /packages/editor/README.md: -------------------------------------------------------------------------------- 1 | # @mometa/editor 2 | 3 | [![NPM version](https://img.shields.io/npm/v/@mometa/editor.svg?style=flat-square)](https://www.npmjs.com/package/@mometa/editor) 4 | [![NPM Downloads](https://img.shields.io/npm/dm/@mometa/editor.svg?style=flat-square&maxAge=43200)](https://www.npmjs.com/package/@mometa/editor) 5 | [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://prettier.io/) 6 | [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square)](https://conventionalcommits.org) 7 | 8 | > 编辑器 9 | 10 | ## Installation 11 | 12 | ```bash 13 | npm install @mometa/editor 14 | # or use yarn 15 | yarn add @mometa/editor 16 | ``` 17 | 18 | ## Usage 19 | 20 | ```javascript 21 | import editor from '@mometa/editor' 22 | ``` 23 | 24 | ## Contributing 25 | 26 | - Fork it! 27 | - Create your new branch: 28 | `git checkout -b feature-new` or `git checkout -b fix-which-bug` 29 | - Start your magic work now 30 | - Make sure npm test passes 31 | - Commit your changes: 32 | `git commit -am 'feat: some description (close #123)'` or `git commit -am 'fix: some description (fix #123)'` 33 | - Push to the branch: `git push` 34 | - Submit a pull request :) 35 | 36 | ## Authors 37 | 38 | This library is written and maintained by [imcuttle](mailto:imcuttle@163.com). 39 | 40 | ## License 41 | 42 | MIT - [imcuttle](mailto:imcuttle@163.com) 43 | -------------------------------------------------------------------------------- /packages/editor/__template/component/index.js: -------------------------------------------------------------------------------- 1 | const nps = require('path') 2 | const { paramCase, pascalCase } = require('change-case') 3 | 4 | const packagePrefix = require('../../package.json').packagePrefix || '' 5 | 6 | module.exports = (edam) => { 7 | return { 8 | prompts: [ 9 | { 10 | name: 'name', 11 | type: 'input', 12 | message: `输入组件名`, 13 | default: '', 14 | transformer: (value) => paramCase(value), 15 | validate: (name) => !name && '必填' 16 | } 17 | ], 18 | process: ({ name, description, useTs }) => { 19 | edam.config.output = nps.join(edam.config.output, name) 20 | return { 21 | move: { 22 | '**/*.hbs': '[path][name]' 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/editor/__template/component/template/index.tsx.hbs: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import p from 'prefix-classname' 3 | import { CLS_PREFIX } from '../../../config/const' 4 | 5 | import './style.scss' 6 | 7 | const cn = p('') 8 | const c = p(`${CLS_PREFIX}-{{{name}}}`) 9 | 10 | export interface {{{pascalCase name}}}Props { 11 | className?: string 12 | } 13 | 14 | const {{{pascalCase name}}}: React.FC<{{{pascalCase name}}}Props> = React.memo(({ className }) => { 15 | return ( 16 |
17 |
18 | ) 19 | }) 20 | 21 | {{{pascalCase name}}}.defaultProps = {} 22 | 23 | export default {{{pascalCase name}}} 24 | -------------------------------------------------------------------------------- /packages/editor/__template/component/template/style.scss.hbs: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-{{{name}}} { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /packages/editor/__tests__/fixture/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/editor/__tests__/fixture/.keep -------------------------------------------------------------------------------- /packages/editor/__tests__/fixture/webpack/src/index.js: -------------------------------------------------------------------------------- 1 | console.log('hello world') 2 | -------------------------------------------------------------------------------- /packages/editor/__tests__/helper.ts: -------------------------------------------------------------------------------- 1 | /** * @file helper */ const nps = require('path') 2 | 3 | export function fixture(...args: string[]) { 4 | return nps.join.apply(nps, [__dirname, 'fixture'].concat(...args)) 5 | } 6 | -------------------------------------------------------------------------------- /packages/editor/__tests__/main.test.ts: -------------------------------------------------------------------------------- 1 | // import editor from '../src/editor' 2 | 3 | describe('editor', function () { 4 | it.skip('spec case', function () {}) 5 | }) 6 | -------------------------------------------------------------------------------- /packages/editor/__tests__/webpack-plugin.test.ts: -------------------------------------------------------------------------------- 1 | import { createFsFromVolume, Volume } from 'memfs' 2 | import { promisify } from 'util' 3 | import Plugin from '../webpack' 4 | import { fixture } from './helper' 5 | 6 | const getWebpack = (version: any = '') => { 7 | return require('webpack') 8 | } 9 | 10 | const getConfig = () => { 11 | return { 12 | mode: 'development', 13 | context: fixture('webpack'), 14 | entry: './src/index.js', 15 | plugins: [ 16 | new Plugin({ 17 | server: false, 18 | react: true 19 | }) 20 | ] 21 | } as any 22 | } 23 | 24 | const run = async (version: any = '') => { 25 | const memFs = createFsFromVolume(new Volume()) 26 | const webpack = getWebpack(version) 27 | const compiler = webpack(getConfig()) 28 | compiler.webpack = webpack 29 | compiler.outputFileSystem = memFs 30 | const stats = await promisify(compiler.run.bind(compiler))() 31 | return stats 32 | } 33 | 34 | describe('editor webpack plugin', function () { 35 | it.skip('webpack5', async function () { 36 | const stats = await run() 37 | expect(Object.keys(stats.compilation.getAssets())).toMatchObject(['mometa/index.html']) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /packages/editor/babel/plugin-react.js: -------------------------------------------------------------------------------- 1 | const __MOMETA_LOCAL__ = !!process.env.__MOMETA_LOCAL__ 2 | if (__MOMETA_LOCAL__) { 3 | module.exports = require('../src/babel/react') 4 | } else { 5 | module.exports = require('../lib/babel/react') 6 | } 7 | -------------------------------------------------------------------------------- /packages/editor/example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /packages/editor/example/config/entry/__mometa_outer_vendor__.js: -------------------------------------------------------------------------------- 1 | global.__mometa_outer_vendor_require__ = (path) => { 2 | if (typeof __mometa_outer_vendor__ === 'undefined' || !__mometa_outer_vendor__?.[path]) { 3 | return { 4 | react: require('react'), 5 | 'react-dom': require('react-dom') 6 | }[path] 7 | } 8 | return __mometa_outer_vendor__?.[path] 9 | } 10 | -------------------------------------------------------------------------------- /packages/editor/example/config/jest/babelTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const babelJest = require('babel-jest').default 4 | 5 | const hasJsxRuntime = (() => { 6 | if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') { 7 | return false 8 | } 9 | 10 | try { 11 | require.resolve('react/jsx-runtime') 12 | return true 13 | } catch (e) { 14 | return false 15 | } 16 | })() 17 | 18 | module.exports = babelJest.createTransformer({ 19 | presets: [ 20 | [ 21 | require.resolve('babel-preset-react-app'), 22 | { 23 | runtime: hasJsxRuntime ? 'automatic' : 'classic' 24 | } 25 | ] 26 | ], 27 | babelrc: false, 28 | configFile: false 29 | }) 30 | -------------------------------------------------------------------------------- /packages/editor/example/config/jest/cssTransform.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // This is a custom Jest transformer turning style imports into empty objects. 4 | // http://facebook.github.io/jest/docs/en/webpack.html 5 | 6 | module.exports = { 7 | process() { 8 | return 'module.exports = {};' 9 | }, 10 | getCacheKey() { 11 | // The output is always the same. 12 | return 'cssTransform' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/editor/example/config/post-buildruntime.js: -------------------------------------------------------------------------------- 1 | const nps = require('path') 2 | const fs = require('fs') 3 | const globby = require('globby') 4 | const runtimePath = nps.join(__dirname, '../../build/runtime/') 5 | 6 | const jsPaths = globby.sync('**/*.js', { cwd: runtimePath, absolute: true, onlyFiles: true }) 7 | 8 | jsPaths.forEach((runtimeJsPath) => { 9 | const content = fs.readFileSync(runtimeJsPath, 'utf-8') 10 | if (content.includes('__webpack_require_mometa__')) { 11 | return 12 | } 13 | 14 | // 修复 webpack chunk 模式下,__webpack_require__ 命名冲突问题 15 | fs.writeFileSync(runtimeJsPath, content.replace(/__webpack_require__/g, '__webpack_require_mometa__')) 16 | }) 17 | console.log('done! __webpack_require__ rename', jsPaths) 18 | -------------------------------------------------------------------------------- /packages/editor/example/config/webpack/persistentCache/createEnvironmentHash.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const { createHash } = require('crypto') 3 | 4 | module.exports = (env) => { 5 | const hash = createHash('md5') 6 | hash.update(JSON.stringify(env)) 7 | 8 | return hash.digest('hex') 9 | } 10 | -------------------------------------------------------------------------------- /packages/editor/example/mometa-material.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require('../../app/mometa-material.config').concat([ 2 | { 3 | name: 'HHHPAC', 4 | key: 'component' 5 | } 6 | ]) 7 | -------------------------------------------------------------------------------- /packages/editor/example/public/editor-runtime.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mometa Editor 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/editor/example/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/editor/example/public/favicon.png -------------------------------------------------------------------------------- /packages/editor/example/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mometa Editor 8 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/editor/example/src/.prettierignore: -------------------------------------------------------------------------------- 1 | /app/ 2 | -------------------------------------------------------------------------------- /packages/editor/example/src/app/ListPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Input, Button } from 'antd' 3 | import 'antd/lib/input/style/css' 4 | 5 | export default function ListPage(props: any) { 6 | return ( 7 |
8 |

9 | ListPage 10 |

11 | 12 | 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /packages/editor/example/src/app/Panel.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export class Panel extends React.Component { 4 | render() { 5 | return ( 6 | // @ts-ignore 7 | 8 |
Panel Content
9 |

Panel Title

10 | {/*// @ts-ignore*/} 11 |
12 | ) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/editor/example/src/app/elements.tsx: -------------------------------------------------------------------------------- 1 | import { Panel } from './Panel' 2 | import React from 'react' 3 | import Tabs from 'antd/es/tabs' 4 | 5 | export const body = ( 6 | <> 7 |

body

8 |
9 | {} 10 |

h3

11 |
12 | 13 | ) 14 | 15 | export const panel = ( 16 | 17 |

extra

18 |
19 | ) 20 | -------------------------------------------------------------------------------- /packages/editor/example/src/app/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { StrictMode } from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { BrowserRouter, HashRouter } from 'react-router-dom' 4 | import { Routes, Route, Outlet, Link } from 'react-router-dom' 5 | 6 | import './styles.css' 7 | 8 | import App from './App' 9 | import ListPage from './ListPage' 10 | 11 | const Navigation = () => { 12 | return ( 13 |
    14 |
  • 15 | App 16 |
  • 17 |
  • 18 | ListPage 19 |
  • 20 |
21 | ) 22 | } 23 | 24 | const rootElement = document.getElementById('root') 25 | ReactDOM.render( 26 | 27 | 28 | 29 | 30 | } /> 31 | } /> 32 | 33 | 34 | , 35 | rootElement 36 | ) 37 | -------------------------------------------------------------------------------- /packages/editor/example/src/app/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: sans-serif; 3 | -webkit-font-smoothing: auto; 4 | -moz-font-smoothing: auto; 5 | -moz-osx-font-smoothing: grayscale; 6 | font-smoothing: auto; 7 | text-rendering: optimizeLegibility; 8 | font-smooth: always; 9 | -webkit-tap-highlight-color: transparent; 10 | -webkit-touch-callout: none; 11 | } 12 | 13 | h1 { 14 | font-size: 1.5rem; 15 | } 16 | -------------------------------------------------------------------------------- /packages/editor/example/src/editor.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { Editor } from '@mometa/editor/editor' 4 | 5 | function App() { 6 | // @ts-ignore 7 | const config = global.__mometa_editor_config__ 8 | return 9 | } 10 | 11 | ReactDOM.render(, document.getElementById('root')) 12 | -------------------------------------------------------------------------------- /packages/editor/example/src/index.tsx: -------------------------------------------------------------------------------- 1 | import './editor' 2 | -------------------------------------------------------------------------------- /packages/editor/example/src/materials/button/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './style.css' 3 | 4 | console.log('materials Button') 5 | 6 | export default function Button() { 7 | console.log('materials Button render1') 8 | return
123
9 | } 10 | -------------------------------------------------------------------------------- /packages/editor/example/src/materials/button/style.css: -------------------------------------------------------------------------------- 1 | .no { 2 | color: red !important; 3 | } 4 | -------------------------------------------------------------------------------- /packages/editor/example/src/mock/noop-webpack-plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = class { 2 | apply() {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/editor/example/src/mock/terser-webpack-plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = class { 2 | apply() {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/editor/example/src/setupProxy.js: -------------------------------------------------------------------------------- 1 | const proxy = require('http-proxy-middleware') 2 | 3 | module.exports = function (app) { 4 | if (process.env.MOMETA_MODE === 'client') { 5 | const csbProxy = proxy.createProxyMiddleware({ 6 | logLevel: 'debug', 7 | ws: true, 8 | // @see https://github.com/cuttle-fighting/codesandbox-client/tree/for-mometa 9 | target: 'http://localhost:4001', 10 | changeOrigin: true, 11 | pathRewrite: {} 12 | }) 13 | app.use('/bundler.html', csbProxy) 14 | app.use('/static/', csbProxy) 15 | app.use('/babel-transpiler.*.worker.js', csbProxy) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/editor/example/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom' 6 | -------------------------------------------------------------------------------- /packages/editor/example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "type": "module", 4 | "ts-node": { 5 | "transpileOnly": true, 6 | "compilerOptions": { 7 | "module": "commonjs" 8 | } 9 | }, 10 | "compilerOptions": { 11 | "target": "ES6", 12 | "lib": ["dom", "dom.iterable", "esnext"], 13 | "allowJs": true, 14 | "skipLibCheck": true, 15 | "esModuleInterop": true, 16 | "allowSyntheticDefaultImports": true, 17 | "strict": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "noFallthroughCasesInSwitch": true, 20 | "module": "ESNext", 21 | "moduleResolution": "node", 22 | "resolveJsonModule": true, 23 | "isolatedModules": true, 24 | "noEmit": true, 25 | "jsx": "react-jsx", 26 | "baseUrl": ".", 27 | "paths": { 28 | "@/*": ["./src/*"], 29 | "@mometa/fs-handler": ["../../fs-handler/src"], 30 | "@mometa/fs-handler/*": ["../../fs-handler/src/*"], 31 | "@mometa/editor": ["../src"], 32 | "@mometa/editor/*": ["../src/*"] 33 | } 34 | }, 35 | "include": ["src"] 36 | } 37 | -------------------------------------------------------------------------------- /packages/editor/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../../package.json').jest, 3 | moduleNameMapper: { 4 | ...require('../../package.json').jest.moduleNameMapper 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/editor/src/babel/react/index.test.ts: -------------------------------------------------------------------------------- 1 | import { transform } from '@babel/core' 2 | import babelPluginMometaReactInject from '.' 3 | 4 | describe('babel-react', () => { 5 | it('spec', function () { 6 | const rs = transform( 7 | ` 8 | const arr = new Array(100).fill(1) 9 | const elem =
10 | Hello World 11 | 14 | 15 |

物料

16 | {arr.map((x, i) => ( 17 |

content_{i}

18 | ))} 19 |

20 |
21 | 22 |
23 |
24 | `, 25 | { 26 | filename: '/file.jsx', 27 | cwd: '/', 28 | parserOpts: { 29 | plugins: ['jsx'] 30 | }, 31 | babelrc: false, 32 | plugins: [[babelPluginMometaReactInject, { emptyPlaceholderPath: 'empty' }]] 33 | } 34 | ) 35 | 36 | expect(rs.code).toMatchSnapshot() 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /packages/editor/src/editor.ts: -------------------------------------------------------------------------------- 1 | /** * 2 | 编辑器 3 | * @author 4 | imcuttle 5 | */ 6 | 7 | export { default as Editor } from './module/render/editor' 8 | -------------------------------------------------------------------------------- /packages/editor/src/entry.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { Editor } from './editor' 4 | 5 | ReactDOM.render( 6 | 7 | 8 | , 9 | document.getElementById('root') 10 | ) 11 | -------------------------------------------------------------------------------- /packages/editor/src/module/config/const.ts: -------------------------------------------------------------------------------- 1 | import { createReactBehaviorSubject } from '@rcp/use.behaviorsubject' 2 | 3 | export const CLS_PREFIX = 'mometa-editor' 4 | 5 | const { useSubject: useOveringNode, subject: overingNodeSubject } = createReactBehaviorSubject(null) 6 | const { useSubject: useSelectedNode, subject: selectedNodeSubject } = createReactBehaviorSubject(null, {}) 7 | const { useSubject: useIframeWindows, subject: iframeWindowsSubject } = createReactBehaviorSubject< 8 | Array 9 | >([]) 10 | const { useSubject: useLocationAction, subject: locationActionSubject } = createReactBehaviorSubject<{ 11 | action: 'PUSH' | 'REPLACE' 12 | url?: string 13 | data?: any 14 | // 来自外部的改动? 15 | outer?: boolean 16 | }>(null, { 17 | eq: (a, b) => a === b 18 | }) 19 | 20 | export { 21 | selectedNodeSubject, 22 | overingNodeSubject, 23 | useOveringNode, 24 | useSelectedNode, 25 | locationActionSubject, 26 | useLocationAction, 27 | iframeWindowsSubject, 28 | useIframeWindows 29 | } 30 | -------------------------------------------------------------------------------- /packages/editor/src/module/render-floating.tsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom' 2 | import React from 'react' 3 | import { useBehaviorSubject } from '@rcp/use.behaviorsubject' 4 | 5 | import { DndLayout } from '../mometa/runtime/dnd' 6 | import { iframeWindowsSubject } from './config/const' 7 | 8 | export const floatingRender = (container) => { 9 | ReactDOM.render(, container) 10 | return () => { 11 | ReactDOM.unmountComponentAtNode(container) 12 | } 13 | } 14 | 15 | export function DndLayoutManager() { 16 | const [wins] = useBehaviorSubject(iframeWindowsSubject) 17 | const doms = React.useMemo(() => { 18 | return wins?.map((w) => w.document.body).filter((x) => x && x.parentNode) 19 | }, [wins]) 20 | 21 | return ( 22 | <> 23 | {doms?.map((dom, i) => ( 24 | 25 | ))} 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/editor/src/module/render/.keep -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/error-boundary/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ErrorBoundary, ErrorBoundaryProps, FallbackProps } from 'react-error-boundary' 3 | 4 | import { Alert, Button } from 'antd' 5 | 6 | function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) { 7 | return ( 8 | {error.stack}} 11 | type="error" 12 | showIcon 13 | action={} 14 | /> 15 | ) 16 | } 17 | 18 | export type AppErrorBoundaryPropsType = Partial 19 | 20 | const AppErrorBoundary: React.FC = React.memo(({ children, ...props }) => ( 21 | // @ts-ignore 22 | 23 | {children} 24 | 25 | )) 26 | 27 | AppErrorBoundary.defaultProps = {} 28 | 29 | export default AppErrorBoundary 30 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/header/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/editor/src/module/render/components/header/logo.png -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/header/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-header { 4 | height: 35px; 5 | display: flex; 6 | padding: 0 10px; 7 | align-items: center; 8 | 9 | z-index: 1; 10 | box-shadow: 0 2px 4px 0 rgb(0 0 0 / 12%), 0 0 6px 0 rgb(0 0 0 / 4%); 11 | 12 | .mmt-ant-divider-vertical { 13 | top: 0; 14 | height: 1.2em; 15 | } 16 | 17 | &__switch { 18 | > * { 19 | margin-left: 4px; 20 | margin-right: 4px; 21 | } 22 | } 23 | 24 | &__logo { 25 | font-size: 20px; 26 | font-weight: 400; 27 | margin-right: 230px; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/left-panel/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import p from 'prefix-classname' 3 | import { CLS_PREFIX } from '../../../config/const' 4 | 5 | import './style.scss' 6 | import MaterialPanel, { MaterialPanelProps } from '../material-panel' 7 | import { Tabs } from 'antd' 8 | 9 | const cn = p('') 10 | const c = p(`${CLS_PREFIX}-left-panel`) 11 | 12 | export interface LeftPanelProps extends Pick { 13 | className?: string 14 | loading?: boolean 15 | } 16 | 17 | const LeftPanel: React.FC = React.memo(({ loading, className, materials }) => { 18 | return ( 19 |
20 | 21 |
22 | ) 23 | }) 24 | 25 | LeftPanel.defaultProps = { 26 | materials: [] 27 | } 28 | 29 | export default LeftPanel 30 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/left-panel/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-left-panel { 4 | padding: 0 10px; 5 | } 6 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/location-widget/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-location-widget { 4 | display: flex; 5 | height: 45px; 6 | align-items: center; 7 | padding: 0 10px; 8 | 9 | &__btns { 10 | margin-right: 10px; 11 | } 12 | 13 | &__url { 14 | flex: 1; 15 | } 16 | &__input { 17 | width: 100%; 18 | background-color: #f1f3f4; 19 | border-radius: 15px; 20 | 21 | &:hover, 22 | &:focus { 23 | background-color: #e6e9ea; 24 | } 25 | &:focus { 26 | outline: 1px solid #1890ff; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/resize-handler/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import p from 'prefix-classname' 3 | import { CLS_PREFIX } from '../../../config/const' 4 | 5 | import './style.scss' 6 | 7 | const cn = p('') 8 | const c = p(`${CLS_PREFIX}-resize-handler`) 9 | 10 | export interface ResizeHandlerProps { 11 | className?: string 12 | bottom?: boolean 13 | left?: boolean 14 | right?: boolean 15 | bottomRight?: boolean 16 | } 17 | 18 | const ResizeHandler: React.FC = React.memo(({ bottomRight, right, bottom, left, className }) => { 19 | return ( 20 |
32 | ) 33 | }) 34 | 35 | ResizeHandler.defaultProps = {} 36 | 37 | export default ResizeHandler 38 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/resize-widget/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-resize-widget { 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | padding: 6px 0; 8 | border-top: 1px solid #f0f0f0; 9 | > * { 10 | margin-left: 5px; 11 | margin-right: 5px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/right-panel/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-rpanel { 4 | padding: 0 10px; 5 | 6 | &__btns { 7 | display: flex; 8 | justify-content: flex-end; 9 | } 10 | 11 | &__tabs { 12 | height: 100%; 13 | overflow: visible !important; 14 | 15 | .mmt-ant-tabs-content-holder { 16 | overflow: auto; 17 | margin-right: -10px; 18 | padding-right: 10px; 19 | 20 | padding-top: 20px; 21 | padding-bottom: 40px; 22 | } 23 | 24 | .mmt-ant-tabs-nav { 25 | margin-bottom: 0 !important; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/components/stage/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-stage { 4 | display: flex; 5 | flex-direction: column; 6 | 7 | &__spin { 8 | flex: 1; 9 | margin-top: 40px; 10 | } 11 | 12 | &__iframe-wrapper { 13 | position: relative; 14 | background-color: #fff; 15 | width: 100%; 16 | display: flex; 17 | } 18 | 19 | &__iframe-mask { 20 | position: absolute; 21 | width: 100%; 22 | text-align: center; 23 | padding-top: 40px; 24 | height: 100%; 25 | } 26 | &__iframe { 27 | width: 100%; 28 | height: 100%; 29 | border: none; 30 | box-shadow: 0 2px 4px 0 rgb(0 0 0 / 12%), 0 0 6px 0 rgb(0 0 0 / 4%); 31 | z-index: 100; 32 | } 33 | &__iframe-floating-container { 34 | position: absolute; 35 | z-index: 200; 36 | } 37 | 38 | &__sandpack { 39 | &, 40 | .sp-wrapper, 41 | .sp-layout, 42 | .sp-stack, 43 | .sp-preview-container { 44 | height: 100% !important; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/editor/sse.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events' 2 | 3 | export function createClientConnection(url) { 4 | if (typeof EventSource === 'undefined') { 5 | throw new Error(`Because of typeof EventSource === 'undefined', So materials hot updating feature is disabled`) 6 | } else { 7 | const source = new EventSource(url) 8 | const evtEmitter = new EventEmitter() 9 | source.addEventListener('message', function (ev) { 10 | let data: any = {} 11 | try { 12 | data = JSON.parse(ev.data) 13 | console.log('Received Data from remote:', data) 14 | evtEmitter.emit('message', data) 15 | } catch (e) {} 16 | }) 17 | 18 | return { 19 | addHandler: (handler: (d: any) => void) => { 20 | evtEmitter.on('message', handler) 21 | return () => { 22 | evtEmitter.off('message', handler) 23 | } 24 | }, 25 | close: () => { 26 | source.close() 27 | evtEmitter.removeAllListeners() 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/style/_var.scss: -------------------------------------------------------------------------------- 1 | $prefix: mometa-editor; 2 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/utils/externals-modules.ts: -------------------------------------------------------------------------------- 1 | // register externals for iframe 2 | const modules = (global.__externals_modules = { 3 | 'react-dom': require('react-dom'), 4 | react: require('react'), 5 | 'react-dnd': require('react-dnd') 6 | }) 7 | 8 | export function addModule(path, exports: any) { 9 | const prev = modules[path] 10 | const has = Reflect.has(modules, path) 11 | modules[path] = exports 12 | 13 | return () => { 14 | if (has) { 15 | modules[path] = prev 16 | } else { 17 | delete modules[path] 18 | } 19 | } 20 | } 21 | 22 | export function addModules(mods: Record) { 23 | const fns = [] 24 | for (const [name, exp] of Object.entries(mods)) { 25 | fns.push(addModule(name, exp)) 26 | } 27 | return () => { 28 | fns.forEach((fn) => fn()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/utils/use-persist-ref.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react' 2 | 3 | export default function usePersistRef(value: T) { 4 | // eslint-disable-next-line react-hooks/rules-of-hooks 5 | const ref = useRef(value) 6 | ref.current = value 7 | 8 | return ref 9 | } 10 | -------------------------------------------------------------------------------- /packages/editor/src/module/render/utils/utils.ts: -------------------------------------------------------------------------------- 1 | import type { RequestData } from '@mometa/fs-handler' 2 | 3 | export function createPreload(data: any, other?: Omit) { 4 | return { 5 | ...other, 6 | relativeFilename: data.relativeFilename, 7 | filename: data.filename 8 | } as any 9 | } 10 | 11 | export function symbol(name: string) { 12 | return `MOMETA_${name}` 13 | } 14 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/config/const.ts: -------------------------------------------------------------------------------- 1 | export const CLS_PREFIX = 'mometa-runtime' 2 | 3 | export { OpType } from '@mometa/fs-handler/const' 4 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/define.d.ts: -------------------------------------------------------------------------------- 1 | declare var __mometa_env_react_jsx_runtime__: any 2 | declare var __mometa_env_is_dev__: any 3 | declare var __mometa_env_which__: 'react' 4 | 5 | interface RangeLocation { 6 | start: { 7 | line: number 8 | column: number 9 | } 10 | end: { 11 | line: number 12 | column: number 13 | } 14 | } 15 | 16 | interface MometaData extends RangeLocation { 17 | name: string 18 | text: string 19 | filename: string 20 | emptyChildren: boolean 21 | relativeFilename: string 22 | hash: string 23 | 24 | isFirst: boolean 25 | selfClosed: boolean 26 | innerStart: { 27 | line: number 28 | column: number 29 | } 30 | innerEnd: { 31 | line: number 32 | column: number 33 | } 34 | 35 | container?: { 36 | isFirstElement: boolean 37 | text: string 38 | hash: string 39 | } & RangeLocation 40 | 41 | previousSibling?: { 42 | text: string 43 | } & RangeLocation 44 | 45 | nextSibling?: { 46 | text: string 47 | } & RangeLocation 48 | } 49 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/entry.ts: -------------------------------------------------------------------------------- 1 | import { isInIframe } from '../shared/utils' 2 | 3 | if (!global.__MOMETA_INITIALIZED__) { 4 | global.__MOMETA_INITIALIZED__ = true 5 | 6 | if (__mometa_env_react_jsx_runtime__ && __mometa_env_is_dev__) { 7 | let JSXDEVRuntime 8 | try { 9 | JSXDEVRuntime = require('$mometa-external:react/jsx-dev-runtime') 10 | } catch (err) {} 11 | if (JSXDEVRuntime) { 12 | const { jsxDEV } = JSXDEVRuntime 13 | // 转移 __mometa 14 | JSXDEVRuntime.jsxDEV = function _jsxDev() { 15 | let [type, props, key, isStaticChildren, source, ...rest] = arguments 16 | if (props?.__mometa) { 17 | const __mometa = props?.__mometa 18 | delete props?.__mometa 19 | if (isInIframe()) { 20 | source = { 21 | ...source, 22 | __mometa 23 | } 24 | } 25 | } 26 | return jsxDEV.apply(this, [type, props, key, isStaticChildren, source, ...rest]) 27 | } 28 | } 29 | } 30 | 31 | // iframe 32 | if (isInIframe()) { 33 | require('./shared-register') 34 | require('./location-register') 35 | require('./render-register') 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/location-register.ts: -------------------------------------------------------------------------------- 1 | import { getSharedFromMain } from './utils/get-from-main' 2 | const { locationActionSubject } = getSharedFromMain() 3 | 4 | const getUrl = (url) => { 5 | if (url == null) { 6 | return null 7 | } 8 | 9 | if (url.trim().startsWith('#')) { 10 | return location.pathname + (location.search || '') + url 11 | } 12 | return url 13 | } 14 | 15 | // React Router <=5 HashRouter 16 | window.addEventListener('hashchange', (evt) => { 17 | locationActionSubject.next({ action: 'PUSH', url: getUrl(location.hash) }) 18 | }) 19 | 20 | // BrowserRouter & React Router >=6 HashRouter 21 | const rawPushState = history.pushState 22 | history.pushState = function _pushState() { 23 | const [, , url] = arguments 24 | if (url != null) { 25 | Promise.resolve().then(() => { 26 | locationActionSubject.next({ action: 'PUSH', url: getUrl(url) }) 27 | }) 28 | } 29 | return rawPushState.apply(this, arguments) 30 | } 31 | 32 | const rawReplaceState = history.replaceState 33 | history.replaceState = function _replaceState() { 34 | const [, , url] = arguments 35 | if (url != null) { 36 | Promise.resolve().then(() => { 37 | locationActionSubject.next({ action: 'REPLACE', url: getUrl(url) }) 38 | }) 39 | } 40 | return rawReplaceState.apply(this, arguments) 41 | } 42 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/runtime/components/more-button/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../style/_var'; 2 | 3 | .#{$prefix}-more-button { 4 | } 5 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/runtime/empty-placeholder.tsx: -------------------------------------------------------------------------------- 1 | import { isInIframe } from '../../shared/utils' 2 | import { getSharedFromMain, useHeaderStatus } from '../utils/get-from-main' 3 | 4 | export default function EmptyPlaceholder({ __mometa }) { 5 | const React = require('react') 6 | if (!React || !isInIframe()) { 7 | return null 8 | } 9 | 10 | const [{ canSelect }] = useHeaderStatus() 11 | 12 | return React.createElement( 13 | 'mometa-empty-placeholder', 14 | { 15 | style: { 16 | color: '#a1a0a0', 17 | fontStyle: 'italic', 18 | width: '100%', 19 | ...(canSelect 20 | ? { 21 | display: 'block' 22 | } 23 | : { 24 | display: 'none' 25 | }) 26 | } 27 | }, 28 | '空视图元素' 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/runtime/provider.tsx: -------------------------------------------------------------------------------- 1 | import { SharedProvider } from '@rcp/use.shared' 2 | import { ConfigProvider } from 'antd' 3 | import zhCN from 'antd/lib/locale/zh_CN' 4 | import React from 'react' 5 | import { DndProvider } from 'react-dnd' 6 | import getWindow from 'get-window' 7 | 8 | import { getSharedFromMain } from '../utils/get-from-main' 9 | const { _sharedMap, _sharedUpdateMap, ddManager } = getSharedFromMain() 10 | 11 | export function Provider({ children, dom }) { 12 | React.useLayoutEffect(() => { 13 | const bk: any = ddManager.getBackend() 14 | const win = getWindow(dom) 15 | bk.addEventListeners(win) 16 | return () => { 17 | bk.removeEventListeners(win) 18 | } 19 | }, [ddManager]) 20 | 21 | return ( 22 | 23 | 24 | {children} 25 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/runtime/style/_var.scss: -------------------------------------------------------------------------------- 1 | $prefix: mometa-runtime; 2 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/shared-register.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { setId, register, addRemoteGlobalThis } from '../shared/pipe' 3 | 4 | setId('runtime') 5 | addRemoteGlobalThis(window.parent) 6 | 7 | register('RefreshUtils', require('$mometa-external:@mometa/react-refresh-webpack-plugin/lib/runtime/RefreshUtils')) 8 | register('@emotion/css', require('./utils/emotion-css')) 9 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/utils/debuglog.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-console 2 | const log = console.log.bind(console, '[MOMETA DEBUG]') 3 | 4 | export function debuglog(...args: any[]) { 5 | log(...args) 6 | } 7 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/utils/emotion-css.ts: -------------------------------------------------------------------------------- 1 | import createEmotion from '@emotion/css/create-instance/dist/emotion-css-create-instance.esm.js' 2 | 3 | const mod = createEmotion({ 4 | key: 'mometa-css' 5 | }) as typeof import('@emotion/css') 6 | 7 | export function refresh() { 8 | mod.flush() 9 | } 10 | 11 | export const injectGlobal: typeof import('@emotion/css')['injectGlobal'] = function () { 12 | return mod.injectGlobal.apply(mod, arguments) 13 | } 14 | 15 | refresh() 16 | 17 | export const css: typeof mod['css'] = function () { 18 | return mod.css.apply(this, arguments) 19 | } 20 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/utils/get-from-main.ts: -------------------------------------------------------------------------------- 1 | import { useBehaviorSubject } from '@rcp/use.behaviorsubject' 2 | // @ts-ignore 3 | import { remoteGlobalThisSet, getByRemoteById, getInLocal, data, getByRemoteOnce } from '../../shared/pipe' 4 | 5 | export function getSharedFromMain() { 6 | const shared = getByRemoteById('shared', 'main') ?? getInLocal('shared') 7 | if (!shared) { 8 | throw new Error(`未找到来自父窗口共享资源`) 9 | } 10 | return shared 11 | } 12 | 13 | export function useSelectedNode() { 14 | const { selectedNodeSubject } = getSharedFromMain() 15 | return useBehaviorSubject(selectedNodeSubject) 16 | } 17 | 18 | export function useOveringNode() { 19 | const { overingNodeSubject } = getSharedFromMain() 20 | return useBehaviorSubject(overingNodeSubject) 21 | } 22 | 23 | export function useHeaderStatus() { 24 | const { headerStatusSubject } = getSharedFromMain() 25 | return useBehaviorSubject(headerStatusSubject) 26 | } 27 | 28 | export function useLocationAction() { 29 | const { locationActionSubject } = getSharedFromMain() 30 | return useBehaviorSubject(locationActionSubject) 31 | } 32 | -------------------------------------------------------------------------------- /packages/editor/src/mometa/utils/use-hooks.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { pick } from 'lodash-es' 3 | 4 | export function useStyle(style: CSSStyleDeclaration, dom: HTMLElement) { 5 | const styleKeys = React.useMemo(() => Object.keys(style), [style]) 6 | React.useLayoutEffect(() => { 7 | const cachedStyle = pick(dom.style, styleKeys) 8 | Object.assign(dom.style, style) 9 | return () => { 10 | Object.assign(dom.style, cachedStyle) 11 | } 12 | }, [dom, styleKeys, style]) 13 | } 14 | -------------------------------------------------------------------------------- /packages/editor/src/shared/hot.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { getByRemoteOnce, getInLocal } from './pipe' 3 | 4 | export function addUpdateCallbackListener(fn) { 5 | var RefreshUtils = getByRemoteOnce('RefreshUtils') ?? getInLocal('RefreshUtils') 6 | if (!RefreshUtils) { 7 | throw new Error('没有找到 RefreshUtils') 8 | } 9 | RefreshUtils?.eventEmitter?.on('updateCallback', fn) 10 | return () => { 11 | RefreshUtils?.eventEmitter?.off('updateCallback', fn) 12 | } 13 | } 14 | 15 | export function addExecuteRuntimeListener(fn) { 16 | var RefreshUtils = getByRemoteOnce('RefreshUtils') ?? getInLocal('RefreshUtils') 17 | if (!RefreshUtils) { 18 | throw new Error('没有找到 RefreshUtils') 19 | } 20 | const handler = function () { 21 | setTimeout(() => { 22 | fn.apply(this, arguments) 23 | }, 100) 24 | } 25 | RefreshUtils?.eventEmitter?.on('executeRuntime', handler) 26 | return () => { 27 | RefreshUtils?.eventEmitter?.off('executeRuntime', handler) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/editor/src/shared/locate-material-parents.ts: -------------------------------------------------------------------------------- 1 | export const locateMaterialParents = function locateMaterialParents(materialsConfig, path) { 2 | var parents = [] 3 | var target = materialsConfig[path[0]] 4 | if (!target) { 5 | return 6 | } 7 | parents.push(target) 8 | const isInvalid = path.slice(1).some(function (k, i) { 9 | let name 10 | if (i === 0) { 11 | name = 'assetGroups' 12 | } else if (i === 1) { 13 | name = 'assets' 14 | } 15 | if (!target[name]) { 16 | return true 17 | } 18 | target = target[name][k] 19 | if (!target) { 20 | return true 21 | } 22 | parents.push(target) 23 | }) 24 | 25 | if (isInvalid) { 26 | return 27 | } 28 | 29 | return parents 30 | } 31 | -------------------------------------------------------------------------------- /packages/editor/src/shared/open-react-element.tsx: -------------------------------------------------------------------------------- 1 | import { createOpenReactStandalone } from '@rcp/util.open' 2 | import React from 'react' 3 | import { ConfigProvider } from 'antd' 4 | import zhCN from 'antd/lib/locale/zh_CN' 5 | 6 | export const openReactStandalone = createOpenReactStandalone({ 7 | wrapper: (elem) => ( 8 | 9 | {elem} 10 | 11 | ) 12 | }) 13 | -------------------------------------------------------------------------------- /packages/editor/src/shared/utils.ts: -------------------------------------------------------------------------------- 1 | export function isInIframe() { 2 | return window.parent && window.parent !== window 3 | } 4 | 5 | export function lazy any>(fn: T): T { 6 | let isCalled = false 7 | let v 8 | 9 | // @ts-ignore 10 | return () => { 11 | if (!isCalled) { 12 | isCalled = true 13 | v = fn() 14 | } 15 | return v 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/editor/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "type": "module", 4 | "compilerOptions": { 5 | "target": "ES6" 6 | }, 7 | "include": ["./src"], 8 | "exclude": ["node_modules", "**/__tests__/**", "example"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@mometa/fs-handler": ["../fs-handler/src"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/editor/webpack/common-plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = class CommonPlugin { 2 | constructor(options) { 3 | this.options = options || {} 4 | } 5 | 6 | getWebpack(compiler) { 7 | return this.options.__webpack || compiler.webpack || require('webpack') 8 | } 9 | 10 | /** 11 | * @param compiler {import('webpack').Compiler} 12 | * @return {number} 13 | */ 14 | getWebpackMajor(compiler) { 15 | if (!compiler.hooks) { 16 | throw new Error(`[MometaEditorPlugin] don't support the webpack version.`) 17 | } 18 | if ('cache' in compiler) { 19 | return 5 20 | } 21 | return 4 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/editor/webpack/materials-compiler/client-render-loader/preview-code-gen.js: -------------------------------------------------------------------------------- 1 | const { getAddMaterialOps, createLineContentsByContent } = require('@mometa/fs-handler') 2 | 3 | module.exports = async function previewCodeGen({ asset, react, path }) { 4 | const isReact = String(react) === 'true' 5 | 6 | const importCodes = [] 7 | if (isReact) { 8 | importCodes.push(`import * as React from 'react';`, `import * as ReactDOM from 'react-dom';`) 9 | } 10 | 11 | const ops = await getAddMaterialOps( 12 | createLineContentsByContent(importCodes.join('\n')), 13 | { line: 0, column: 1 }, 14 | asset.data, 15 | { 16 | esModule: true 17 | } 18 | ) 19 | if (ops.insertDeps) { 20 | importCodes.push(ops.insertDeps.map((x) => x.preload.data.newText.replace(/^;/, '')).join('\n') || '') 21 | } 22 | 23 | return ` 24 | /* preview-render ${asset.name || ''} ${asset.key || ''} */ 25 | ${importCodes.join('\n')} 26 | export default function previewRender(dom) { 27 | return ${ops.insertCode ? `ReactDOM.render(${ops.insertCode.preload.data.newText}, dom)` : ''}; 28 | };`.trim() 29 | } 30 | -------------------------------------------------------------------------------- /packages/editor/webpack/materials-compiler/client-render-loader/preview-loader.js: -------------------------------------------------------------------------------- 1 | const { getAddMaterialOps, createLineContentsByContent } = require('@mometa/fs-handler') 2 | const { sha1 } = require('object-hash') 3 | const { getOptions } = require('loader-utils') 4 | 5 | /** 6 | * 7 | * @this {import('webpack').LoaderContext} 8 | * @returns {Promise} 9 | */ 10 | module.exports.pitch = async function (request) { 11 | this.cacheable(false) 12 | const { asset, react, path } = this.getOptions ? this.getOptions() : getOptions(this) 13 | const isReact = String(react) === 'true' 14 | 15 | const importCodes = [] 16 | if (isReact) { 17 | importCodes.push(`import * as React from 'react';`, `import * as ReactDOM from 'react-dom';`) 18 | } 19 | 20 | const ops = await getAddMaterialOps( 21 | createLineContentsByContent(importCodes.join('\n')), 22 | { line: 0, column: 1 }, 23 | asset.data, 24 | { 25 | esModule: true 26 | } 27 | ) 28 | importCodes.push(ops.insertDeps?.map((x) => x.preload.data.newText.replace(/^;/, '')).join('\n') ?? '') 29 | 30 | return ` 31 | /* preview-render ${asset.name || ''} ${asset.key || ''} */ 32 | ${importCodes.join('\n')} 33 | export default function previewRender(dom) { 34 | return ${ops.insertCode ? `ReactDOM.render(${ops.insertCode.preload.data.newText}, dom)` : ''}; 35 | };` 36 | } 37 | -------------------------------------------------------------------------------- /packages/editor/webpack/paths.js: -------------------------------------------------------------------------------- 1 | const nps = require('path') 2 | 3 | const webpackRoot = (exports.webpackRoot = __dirname) 4 | 5 | exports.runtimeDir = nps.join(webpackRoot, 'runtime') 6 | exports.runtimePreviewRender = nps.join(webpackRoot, 'runtime/preview-render') 7 | -------------------------------------------------------------------------------- /packages/editor/webpack/runtime/.gitignore: -------------------------------------------------------------------------------- 1 | /preview-render/ 2 | !/preview-render/.gitkeep 3 | -------------------------------------------------------------------------------- /packages/editor/webpack/runtime/client-render-main.js: -------------------------------------------------------------------------------- 1 | // noop placeholder 2 | -------------------------------------------------------------------------------- /packages/editor/webpack/runtime/handle.js: -------------------------------------------------------------------------------- 1 | var { locateMaterialParents } = require('../../es/shared/locate-material-parents') 2 | 3 | function get(target, name) { 4 | if (!target) { 5 | return 6 | } 7 | if (Array.isArray(name)) { 8 | if (!name.length) { 9 | return target 10 | } 11 | return get(target[name[0]], name.slice(1)) 12 | } 13 | return target[name] 14 | } 15 | 16 | module.exports = function (clientRenderEntities, materialsConfigName) { 17 | var materialsConfig = get(global, materialsConfigName) 18 | 19 | if (clientRenderEntities && clientRenderEntities.length) { 20 | clientRenderEntities.some(function (entity) { 21 | var parents = locateMaterialParents(materialsConfig, entity.path) 22 | if (!parents || !parents.length) { 23 | console.error(`clientRenderEntities and materialsConfig is not matched`, { 24 | materialsConfig, 25 | clientRenderEntities 26 | }) 27 | return true 28 | } 29 | 30 | var target = parents[parents.length - 1] 31 | target.runtime = Object.assign({}, entity.runtime, target.runtime) 32 | }) 33 | } 34 | return materialsConfig 35 | } 36 | -------------------------------------------------------------------------------- /packages/editor/webpack/runtime/preview-render/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/editor/webpack/runtime/preview-render/.gitkeep -------------------------------------------------------------------------------- /packages/editor/webpack/runtime/runtime-entry.js: -------------------------------------------------------------------------------- 1 | if (__mometa_env_is_local__) { 2 | module.exports = require(`../../src/mometa/entry`) 3 | } else { 4 | module.exports = require(`../../build/runtime/entry`) 5 | } 6 | -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/fs-handler/__tests__/fixture/.keep -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/nested.tsx: -------------------------------------------------------------------------------- 1 | import React, { StrictMode } from 'react' 2 | import Tabs from 'antd/es/tabs' 3 | import 'antd/es/tabs/style/index.css' 4 | 5 | type Props = {} 6 | 7 | const array = new Array(100).fill(1) 8 | 9 | export default function App(props: Props) { 10 | return ( 11 |
12 |

Hello World👌

13 | 14 | 15 |

16 |

simple 66xxxxxasdasdas6

17 |

18 | nested 19 | hahahax 20 |

21 | {array.map((x, i) => ( 22 |

物料_{i}

23 | ))} 24 |
25 | 26 |
27 |
28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/react-comp.tsx: -------------------------------------------------------------------------------- 1 | import React, { StrictMode } from 'react' 2 | import Tabs from 'antd/es/tabs' 3 | import 'antd/es/tabs/style/index.css' 4 | 5 | type Props = { 6 | x: string 7 | } 8 | 9 | const array = new Array(100).fill(1) 10 | 11 | export default function App(props: Props) { 12 | return ( 13 |
14 |

Hello World

15 | 16 | 17 |

18 |

单独 p

19 | {array.map((x, i) => ( 20 |

物料__{i}

21 | ))} 22 |
23 | 24 |
25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/simple.d.ts: -------------------------------------------------------------------------------- 1 | import 'side-effect' 2 | export { Button } from 'antd' 3 | -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/simple.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | Object.defineProperty(exports, '__esModule', { value: true }) 3 | exports.Button = void 0 4 | require('side-effect') 5 | const elem = React.createElement('div', null, 'abc') 6 | var antd_1 = require('antd') 7 | Object.defineProperty(exports, 'Button', { 8 | enumerable: true, 9 | get: function () { 10 | return antd_1.Button 11 | } 12 | }) 13 | //# sourceMappingURL=simple.js.map 14 | -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/simple.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"simple.js","sourceRoot":"","sources":["simple.tsx"],"names":[],"mappings":";;;AACA,uBAAoB;AAEpB,MAAM,IAAI,GAAG,uCAAc,CAAA;AAE3B,6BAA6B;AAApB,8FAAA,MAAM,OAAA"} -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/fixture/simple.tsx: -------------------------------------------------------------------------------- 1 | import { Input } from 'antd' 2 | import 'side-effect' 3 | 4 | const elem =
abc
5 | 6 | export { Button } from 'antd' 7 | -------------------------------------------------------------------------------- /packages/fs-handler/__tests__/helper.ts: -------------------------------------------------------------------------------- 1 | /** * @file helper */ const nps = require('path') 2 | 3 | export function fixture(...args: string[]) { 4 | return nps.join.apply(nps, [__dirname, 'fixture'].concat(...args)) 5 | } 6 | 7 | export function readContent(...args: string[]) { 8 | return require('fs').readFileSync(fixture(...args), 'utf-8') 9 | } 10 | -------------------------------------------------------------------------------- /packages/fs-handler/const.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/const') 2 | -------------------------------------------------------------------------------- /packages/fs-handler/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../../package.json').jest 3 | } 4 | -------------------------------------------------------------------------------- /packages/fs-handler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mometa/fs-handler", 3 | "version": "0.0.33", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "author": "imcuttle ", 8 | "description": "代码操作转换核心逻辑,如删除、移动、替换、插入等", 9 | "main": "lib", 10 | "types": "types", 11 | "module": "es", 12 | "files": [ 13 | "lib", 14 | "es", 15 | "types" 16 | ], 17 | "scripts": { 18 | "test": "npx ../../scripts/run.js test", 19 | "build": "npx ../../scripts/run.js build", 20 | "packlimit": "npx ../../scripts/run.js packlimit", 21 | "dev": "npm run build -- --watch", 22 | "prepare": "npm run build", 23 | "prepublishOnly": "npm run packlimit", 24 | "version": "npm test && npm run packlimit" 25 | }, 26 | "dependencies": { 27 | "@babel/core": "^7.16.5", 28 | "lodash.groupby": "^4.6.0", 29 | "memoize-fn": "^2.0.1", 30 | "pify": "^4.0.1", 31 | "prettier": "^2.5.1", 32 | "run-seq": "^1.0.4" 33 | }, 34 | "devDependencies": { 35 | "@mometa/materials-generator": "^0.0.33" 36 | }, 37 | "keywords": [ 38 | "imcuttle", 39 | "fs-handler", 40 | "imcuttle", 41 | "mometa", 42 | "mometa" 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git+https://github.com/imcuttle/mometa.git", 47 | "directory": "packages/fs-handler" 48 | }, 49 | "gitHead": "333b833f49286bef901694a6f84b1248131098a0" 50 | } 51 | -------------------------------------------------------------------------------- /packages/fs-handler/src/common/del.ts: -------------------------------------------------------------------------------- 1 | import { Middleware, OpType } from '../index' 2 | import replaceNodeMiddleware from './replace-node' 3 | 4 | import './add-material' 5 | 6 | export default function delMiddleware(): Middleware { 7 | return async (data, ctx, next) => { 8 | if (data.type === OpType.DEL) { 9 | return replaceNodeMiddleware()( 10 | { 11 | type: OpType.REPLACE_NODE, 12 | preload: { 13 | ...data.preload, 14 | data: { 15 | newText: '' 16 | } 17 | } 18 | }, 19 | ctx, 20 | next 21 | ) 22 | } 23 | return next() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/fs-handler/src/common/index.ts: -------------------------------------------------------------------------------- 1 | import { Middleware } from '../index' 2 | import commonDelMiddleware from './del' 3 | import commonReplaceNodeMiddleware from './replace-node' 4 | import moveNodeMiddleware from './move-node' 5 | import insertNodeMiddleware from './insert-node' 6 | 7 | export default function commonMiddlewares(): Middleware[] { 8 | return [commonDelMiddleware(), commonReplaceNodeMiddleware(), moveNodeMiddleware(), insertNodeMiddleware()] 9 | } 10 | -------------------------------------------------------------------------------- /packages/fs-handler/src/common/move-node.ts: -------------------------------------------------------------------------------- 1 | import { Middleware, OpType } from '../index' 2 | import { EMPTY } from '../utils/line-contents' 3 | import delMiddleware from './del' 4 | 5 | export default function moveNodeMiddleware(): Middleware { 6 | return async (data, ctx, next) => { 7 | if (data.type === OpType.MOVE_NODE) { 8 | const toPos = data.preload.data?.to 9 | if (!toPos) { 10 | return next() 11 | } 12 | 13 | const text = ctx.lines.map((x) => x.line.content).join('\n') 14 | delMiddleware()( 15 | { 16 | type: OpType.DEL, 17 | preload: { 18 | ...data.preload 19 | } 20 | }, 21 | ctx, 22 | () => {} 23 | ) 24 | 25 | const toLine = ctx.lineContents.locateLineByPos(toPos.line) 26 | if (toLine.content === EMPTY) { 27 | toLine.setContent(text) 28 | } else { 29 | toLine.setContent( 30 | toLine.slice(0, toPos.column).content + text + toLine.slice(toPos.column ?? toLine.content.length).content 31 | ) 32 | } 33 | } 34 | return next() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/fs-handler/src/const.ts: -------------------------------------------------------------------------------- 1 | export enum OpType { 2 | DEL, 3 | REPLACE_NODE, 4 | MOVE_NODE, 5 | INSERT_NODE 6 | } 7 | -------------------------------------------------------------------------------- /packages/fs-handler/src/utils/compare.ts: -------------------------------------------------------------------------------- 1 | import { Point } from './line-contents' 2 | 3 | export function comparePoint(p1: Point, p2: Point): 1 | 0 | -1 { 4 | if (p1.line > p2.line) { 5 | return 1 6 | } 7 | if (p1.line < p2.line) { 8 | return -1 9 | } 10 | 11 | if (p1.column > p2.column) { 12 | return 1 13 | } 14 | if (p1.column < p2.column) { 15 | return -1 16 | } 17 | return 0 18 | } 19 | -------------------------------------------------------------------------------- /packages/fs-handler/src/utils/line-contents.test.ts: -------------------------------------------------------------------------------- 1 | import { Range, Point, LineContents, createLineContentsByContent } from './line-contents' 2 | 3 | describe('content-parser', function () { 4 | it('should spec', function () { 5 | const vo = createLineContentsByContent( 6 | ` 7 | import React, { StrictMode } from "react"; 8 | import Tabs from "antd/es/tabs"; 9 | import "antd/es/tabs/style/index.css"; 10 | 11 | type Props = { 12 | x: string 13 | } 14 | 15 | const array = new Array(100).fill(1) 16 | 17 | export default function App(props: Props) { 18 | 19 | return ( 20 |
21 |

Hello World

22 | 23 | 24 |

25 |

单独 p

26 | {array.map((x, i) =>

物料__{i}

)} 27 |
28 | 29 |
30 |
31 | ) 32 | } 33 | `.trim(), 34 | { filename: '/App.tsx' } 35 | ) 36 | 37 | const lines = vo 38 | .locateByRange({ 39 | start: { line: 19, column: 8 }, 40 | end: { line: 19, column: 19 } 41 | }) 42 | .map((x) => x.line) 43 | expect(new LineContents(lines).toString()).toMatchInlineSnapshot(`"

单独 p

"`) 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /packages/fs-handler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { "extends": "../../tsconfig.json", "compilerOptions": {}, "exclude": ["node_modules"], "include": ["./src"] } 2 | -------------------------------------------------------------------------------- /packages/materials-generator/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../../package.json').jest 3 | } 4 | -------------------------------------------------------------------------------- /packages/materials-generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mometa/materials-generator", 3 | "version": "0.0.33", 4 | "publishConfig": { 5 | "access": "public", 6 | "main": "lib", 7 | "types": "types", 8 | "module": "es" 9 | }, 10 | "author": "imcuttle ", 11 | "description": "物料生成 & 解析", 12 | "main": "src", 13 | "files": [ 14 | "lib", 15 | "es", 16 | "types" 17 | ], 18 | "scripts": { 19 | "test": "echo noop", 20 | "build": "npx ../../scripts/run.js build", 21 | "packlimit": "../../scripts/run packlimit", 22 | "dev": "npm run build -- --watch", 23 | "prepare": "npm run build", 24 | "prepublishOnly": "npm run packlimit", 25 | "version": "npm test && npm run packlimit" 26 | }, 27 | "keywords": [ 28 | "imcuttle", 29 | "materials-generator", 30 | "mometa" 31 | ], 32 | "repository": { 33 | "type": "git", 34 | "url": "git+https://github.com/imcuttle/mometa.git", 35 | "directory": "packages/materials-generator" 36 | }, 37 | "gitHead": "333b833f49286bef901694a6f84b1248131098a0" 38 | } 39 | -------------------------------------------------------------------------------- /packages/materials-generator/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugins/create' 2 | export * from './plugins/helper' 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /packages/materials-generator/src/plugins/create.ts: -------------------------------------------------------------------------------- 1 | import { Asset, AssetGroup, Material } from '../types' 2 | 3 | export function material( 4 | name: string, 5 | key: string, 6 | children: Material['assetGroups'] | Promise = [] 7 | ): Material { 8 | return { 9 | name, 10 | key, 11 | // @ts-ignore 12 | assetGroups: children 13 | } 14 | } 15 | 16 | export function group( 17 | name: string, 18 | key: string, 19 | assets: AssetGroup['assets'] | Promise = [] 20 | ): AssetGroup { 21 | return { 22 | name, 23 | key, 24 | // @ts-ignore 25 | assets 26 | } 27 | } 28 | 29 | export function asset(name: string, key: string, data: Asset['data'] = { code: '' }): Asset { 30 | return { 31 | name, 32 | key, 33 | data 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/materials-generator/src/plugins/helper.ts: -------------------------------------------------------------------------------- 1 | export const isClientRender = typeof document !== 'undefined' && typeof location !== 'undefined' 2 | -------------------------------------------------------------------------------- /packages/materials-generator/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Material { 2 | name: string 3 | key: any 4 | assetGroups: AssetGroup[] 5 | } 6 | 7 | export interface AssetGroup { 8 | name: string 9 | key: any 10 | assets: Asset[] 11 | } 12 | 13 | // import { Button as AntButton } from 'antd' 14 | export interface AssetImport { 15 | source: string // "antd" 16 | mode: 'default' | 'named' | 'namespace' // named 17 | imported?: string // "Button" 18 | local?: string // "AntButton" 19 | } 20 | 21 | export interface Asset { 22 | name: string 23 | key: any 24 | cover?: string 25 | homepage?: string 26 | 27 | data: { 28 | code: string // '' 29 | dependencies?: Record // { Button: { mode: 'named', source: 'antd' } } 30 | sideEffectDependencies?: Array 31 | } 32 | 33 | runtime?: { 34 | previewRender?: (dom: HTMLElement) => void | (() => void) 35 | __fallbackPreviewRender?: (dom: HTMLElement) => void | (() => void) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/materials-generator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "." 5 | }, 6 | "exclude": ["node_modules"], 7 | "include": ["./src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/materials-generator/types.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/types') 2 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/fixture/invalid-mat-lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | Promise.resolve(1), 3 | { 4 | x: Promise.resolve(1), 5 | y: [Promise.resolve(1)] 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/fixture/invalid-mat-lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mat-lib", 3 | "private": true, 4 | "version": "1.0.0", 5 | "mometa": "mometa.js", 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/fixture/mat-lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | Promise.resolve(1), 3 | { 4 | x: Promise.resolve(1), 5 | y: [Promise.resolve(1)] 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/fixture/mat-lib/mometa.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | Promise.resolve(1), 3 | { 4 | x: Promise.resolve(1), 5 | y: [Promise.resolve(1)] 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/fixture/mat-lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mat-lib", 3 | "private": true, 4 | "version": "1.0.0", 5 | "mometa": "mometa.js", 6 | "dependencies": {} 7 | } 8 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/helper.ts: -------------------------------------------------------------------------------- 1 | /** * @file helper */ const nps = require('path') 2 | 3 | export function fixture(...args: string[]) { 4 | return nps.join.apply(nps, [__dirname, 'fixture'].concat(...args)) 5 | } 6 | -------------------------------------------------------------------------------- /packages/materials-resolver/__tests__/main.test.ts: -------------------------------------------------------------------------------- 1 | import { resolveLibMatConfig, resolveAsyncConfig } from '../src' 2 | import { fixture } from './helper' 3 | 4 | describe('materialsResolver', function () { 5 | it('resolveAsyncConfig', async function () { 6 | expect( 7 | await resolveAsyncConfig([ 8 | Promise.resolve(1), 9 | Promise.resolve(2), 10 | { 11 | 3: Promise.resolve(3) 12 | } 13 | ]) 14 | ).toEqual([1, 2, { 3: 3 }]) 15 | }) 16 | it('resolveLibMatConfig valid', async function () { 17 | expect(await resolveLibMatConfig(fixture('mat-lib'))).toEqual([1, { x: 1, y: [1] }]) 18 | }) 19 | 20 | it('resolveLibMatConfig invalid', async function () { 21 | let error 22 | try { 23 | await resolveLibMatConfig(fixture('invalid-mat-lib')) 24 | } catch (e) { 25 | error = e 26 | } 27 | 28 | expect(error?.message).toMatch(`Cannot find module '${fixture('invalid-mat-lib', 'mometa.js')}'`) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/materials-resolver/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../../package.json').jest 3 | } 4 | -------------------------------------------------------------------------------- /packages/materials-resolver/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mometa/materials-resolver", 3 | "version": "0.0.33", 4 | "publishConfig": { 5 | "access": "public" 6 | }, 7 | "author": "余聪 ", 8 | "description": "Resolve materials config", 9 | "main": "lib", 10 | "types": "types", 11 | "module": "es", 12 | "files": [ 13 | "lib", 14 | "es", 15 | "types" 16 | ], 17 | "scripts": { 18 | "test": "npx ../../scripts/run.js test", 19 | "build": "npx ../../scripts/run.js build", 20 | "packlimit": "npx ../../scripts/run.js packlimit", 21 | "dev": "npm run build -- --watch", 22 | "prepare": "npm run build", 23 | "prepublishOnly": "npm run packlimit && ../../scripts/run pkgxo --submit", 24 | "postpublish": "../../scripts/run pkgxo --reset", 25 | "version": "npm test && npm run packlimit" 26 | }, 27 | "dependencies": { 28 | "find-up": "^5.0.0", 29 | "globby": "^11.0.4" 30 | }, 31 | "devDependencies": { 32 | "@mometa/materials-generator": "^0.0.33" 33 | }, 34 | "keywords": [ 35 | "余聪", 36 | "materials-resolver", 37 | "imcuttle", 38 | "mometa" 39 | ], 40 | "repository": { 41 | "type": "git", 42 | "url": "git+https://github.com/imcuttle/mometa.git", 43 | "directory": "packages/materials-resolver" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/materials-resolver/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Resolve materials config 3 | * @author 余聪 4 | */ 5 | 6 | export * from './plugins/materials' 7 | export * from './utils/resolve-async-config' 8 | export * from './utils/search-core' 9 | -------------------------------------------------------------------------------- /packages/materials-resolver/src/plugins/materials.ts: -------------------------------------------------------------------------------- 1 | import type { Material } from '@mometa/materials-generator' 2 | import { materialExplorer } from '../utils/search-core' 3 | import { resolveAsyncConfig } from '../utils/resolve-async-config' 4 | import { resolve } from 'path' 5 | import { sortedGlobby } from '../utils/sorted-globby' 6 | import { flatten } from '../utils/to-array' 7 | 8 | export async function materials(findDirs: string[] | string, cwd?: string): Promise { 9 | const list = [] 10 | const dirs = await sortedGlobby(findDirs, cwd) 11 | await Promise.all( 12 | dirs.map(async (dir) => { 13 | dir = resolve(cwd || '', dir) 14 | const d = await materialExplorer.search(dir) 15 | if (!d?.isEmpty) { 16 | list.push(...flatten(await resolveAsyncConfig(d.config))) 17 | } 18 | }) 19 | ) 20 | return list 21 | } 22 | -------------------------------------------------------------------------------- /packages/materials-resolver/src/plugins/react-component-asset.ts: -------------------------------------------------------------------------------- 1 | // import { Asset } from '../types' 2 | // import * as fs from 'fs' 3 | // import { pascalCase } from 'change-case' 4 | // import * as nps from 'path' 5 | // import reactApiParse from '../utils/react-api-parse' 6 | // 7 | // export function reactComponentAsset( 8 | // filename: string, 9 | // { componentName }: { componentName?: string } = {} 10 | // ): Asset | null { 11 | // const basename = nps.basename(filename, nps.extname(filename)) 12 | // const result = reactApiParse(filename, { 13 | // // button/index.jsx => Button 14 | // // src/button.js => Button 15 | // componentName: 16 | // componentName ?? 17 | // pascalCase(['index', 'index.d'].includes(basename) ? nps.basename(nps.dirname(filename)) : basename) 18 | // }) 19 | // 20 | // console.log('result', JSON.stringify(result, null, 2), Object.keys(result)) 21 | // for (const [k, v] of Object.entries(result)) { 22 | // } 23 | // 24 | // return null 25 | // } 26 | -------------------------------------------------------------------------------- /packages/materials-resolver/src/utils/search-core.ts: -------------------------------------------------------------------------------- 1 | import findUp from 'find-up' 2 | import * as nps from 'path' 3 | 4 | function isModFile(filename: string, mod) { 5 | const base = nps.basename(filename) 6 | // if (base === 'package.json') { 7 | // return !!require(filename)[mod] 8 | // } 9 | return base.includes(mod) 10 | } 11 | 12 | export const materialExplorer = { 13 | async search(dir) { 14 | const filepath = await materialExplorer.findUp(dir) 15 | if (!filepath) { 16 | return { 17 | filepath, 18 | isEmpty: true, 19 | config: null 20 | } 21 | } 22 | return { 23 | filepath, 24 | isEmpty: false, 25 | config: require(filepath) 26 | } 27 | }, 28 | findUp(dir) { 29 | return findUp('mometa-material.config.js', { 30 | cwd: dir 31 | }) 32 | } 33 | } 34 | export function isMaterialsFile(filename: string) { 35 | return isModFile(filename, 'mometa-material') 36 | } 37 | -------------------------------------------------------------------------------- /packages/materials-resolver/src/utils/sorted-globby.ts: -------------------------------------------------------------------------------- 1 | import globby from 'globby' 2 | import * as fs from 'fs' 3 | import * as nps from 'path' 4 | import { toArray } from './to-array' 5 | 6 | export async function sortedGlobby(patterns: string | string[], cwd?: string) { 7 | patterns = toArray(patterns) as string[] 8 | 9 | const ps: string[] = [] 10 | const dirs: string[] = [] 11 | patterns.forEach((dir) => { 12 | const dirPath = nps.resolve(cwd || '', dir) 13 | if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) { 14 | dirs.push(dirPath) 15 | return 16 | } 17 | ps.push(dir) 18 | }) 19 | 20 | const files = await globby(ps, { cwd, onlyDirectories: true }) 21 | const sortedDirs = files.sort((a, b) => a.localeCompare(b)) 22 | return Array.from(new Set(dirs.concat(sortedDirs)).values()) 23 | } 24 | -------------------------------------------------------------------------------- /packages/materials-resolver/src/utils/to-array.ts: -------------------------------------------------------------------------------- 1 | export function toArray(v: any) { 2 | if (Array.isArray(v)) { 3 | return v 4 | } 5 | if (v == null) { 6 | return v 7 | } 8 | return [v] 9 | } 10 | 11 | export function flatten(v: any[]) { 12 | const newArr = [] 13 | toArray(v).forEach((x) => { 14 | if (Array.isArray(x)) { 15 | newArr.push(...flatten(x)) 16 | } else { 17 | newArr.push(x) 18 | } 19 | }) 20 | return newArr 21 | } 22 | -------------------------------------------------------------------------------- /packages/materials-resolver/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": {}, 4 | "exclude": ["node_modules"], 5 | "include": ["./src"] 6 | } 7 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/__tests__/fixture/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imcuttle/mometa/ddc44915377df7c9fdaeeefeaa460a36ece49734/packages/react-docgen-typescript/__tests__/fixture/.keep -------------------------------------------------------------------------------- /packages/react-docgen-typescript/__tests__/helper.ts: -------------------------------------------------------------------------------- 1 | /** * @file helper */ const nps = require('path') 2 | 3 | export function fixture(...args: string[]) { 4 | return nps.join.apply(nps, [__dirname, 'fixture'].concat(...args)) 5 | } 6 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/__tests__/main.test.ts: -------------------------------------------------------------------------------- 1 | // import reactDocgenTypescript from '../src' 2 | 3 | describe('reactDocgenTypescript', function () { 4 | it.skip('spec case', function () {}) 5 | }) 6 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../../package.json').jest 3 | } 4 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mometa/react-docgen-typescript", 3 | "version": "0.0.33", 4 | "private": true, 5 | "publishConfig": { 6 | "access": "public" 7 | }, 8 | "author": "imcuttle ", 9 | "description": "forked from https://github.com/styleguidist/react-docgen-typescript", 10 | "main": "lib", 11 | "types": "types", 12 | "module": "es", 13 | "files": [ 14 | "lib", 15 | "es", 16 | "types" 17 | ], 18 | "scripts": { 19 | "__test": "../../scripts/run.js test", 20 | "build": "../../scripts/run.js build", 21 | "packlimit": "../../scripts/run.js packlimit", 22 | "dev": "npm run build -- --watch", 23 | "prepublishOnly": "npm run build && npm run packlimit", 24 | "version": "npm run packlimit" 25 | }, 26 | "keywords": [ 27 | "imcuttle", 28 | "react-docgen-typescript", 29 | "mometa" 30 | ], 31 | "devDependencies": { 32 | "chai": "^4.3.4", 33 | "typescript": "*" 34 | }, 35 | "peerDependencies": { 36 | "typescript": "*" 37 | }, 38 | "repository": { 39 | "type": "git", 40 | "url": "git+https://github.com/imcuttle/mometa.git", 41 | "directory": "packages/react-docgen-typescript" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/src/__tests__/__sourceMapInit.ts: -------------------------------------------------------------------------------- 1 | import * as sourceMapSupport from 'source-map-support' 2 | sourceMapSupport.install() 3 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/src/__tests__/data/AppMenu.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | /** IAppMenuProps props */ 4 | export interface IAppMenuProps { 5 | /** menu description */ 6 | menu: any 7 | } 8 | 9 | export interface IAppMenuState { 10 | menu: any 11 | } 12 | 13 | /** AppMenu description */ 14 | export class AppMenu extends React.Component { 15 | constructor(props, context) { 16 | super(props, context) 17 | this.state = { 18 | menu: this.props.menu 19 | } 20 | 21 | this.handleClick = this.handleClick.bind(this) 22 | } 23 | 24 | componentWillReceiveProps(newProps: IAppMenuProps) { 25 | /* empty on purpose */ 26 | } 27 | 28 | handleClick(info) { 29 | /* empty on purpose */ 30 | } 31 | 32 | render() { 33 | return
test
34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/react-docgen-typescript/src/__tests__/data/ButtonWithOnClickComponent.tsx: -------------------------------------------------------------------------------- 1 | import { FC, PropsWithRef } from 'react' 2 | 3 | type HTMLButtonProps = JSX.IntrinsicElements['button'] 4 | 5 | type Props = HTMLButtonProps & { 6 | /** onClick event handler */ 7 | onClick?: HTMLButtonProps['onClick'] 8 | } 9 | 10 | const ButtonWithOnClickComponent: FC = (props) => { 11 | return