Compare commits

...

74 Commits

Author SHA1 Message Date
openinula 68ad2d3e9c Merge pull request '新增inula max 内容' (#8) from xiaohuoni/inula:master into master 2024-10-21 14:06:44 +08:00
xiaohuoni 70f7bb3f51 Merge pull request '增加inula max 框架' (#1) from feat-inula-max into master 2024-10-21 12:48:32 +08:00
xiaohuoni 540c8d582b feat: add inula-max 2024-10-17 19:25:06 +08:00
openinula 002dc545c2 Merge pull request '解耦reconciler' (#5) from kbdsg/inula:master into master 2024-10-16 09:47:16 +08:00
openinula 9f1d2fbc56 Merge pull request 'openInula 测试工具' (#6) from Maxwell_YCM/inula:master into master 2024-10-16 09:45:52 +08:00
Maxwell_YCM 9f5c9bb370 add test lib 2024-10-15 22:09:28 +08:00
超级无敌数码暴龙战士 af32cb79f9 feat: 解耦reconciler 2024-10-15 21:56:37 +08:00
openinula fbc9c11946 Merge pull request 'inula-testing-library' (#4) from Aojunha/inula:plugins into master 2024-10-15 20:59:04 +08:00
小豪 2047bb27db feat: inula-testing-library 2024-10-15 13:42:50 +08:00
openinula 847fbd5bc0 Merge pull request 'OpenInula AI 代码生成工具' (#2) from LirongRen/inula:master into master
XI
2024-10-15 09:52:15 +08:00
openinula d488477ca3 Merge pull request 'OpenInula 类型系统开发' (#3) from Shanyujia/inula:master into master 2024-10-15 09:50:40 +08:00
renlirong c901b953c5 feat: inula code generator 2024-10-14 19:23:14 +08:00
Shanyujia 22772af364 Delete .DS_Store 2024-10-14 18:50:07 +08:00
eleliauk f295549122 feat:类型系统开发 2024-10-14 18:16:29 +08:00
涂旭辉 2c2c3926e7
!167 fix(inulax): 状态管理器问题修复
Merge pull request !167 from xuan/sync
2024-04-07 02:14:31 +00:00
huangxuan ecaaacb812
fix(inulax): 修复嵌套使用connect的错误 2024-04-07 09:34:36 +08:00
huangxuan 6688cde7ab
fix(inulax): 修复动态组件死循环 2024-04-02 14:57:50 +08:00
涂旭辉 8a7623d281
!166 inula 代码同步
Merge pull request !166 from xuan/sync
2024-04-02 03:21:55 +00:00
huangxuan 0375ed95fc
fix(core): 修复antd Tree组件报错 2024-04-02 11:08:16 +08:00
huangxuan 4a825cec88
fix(inulax): 修复状态管理器触发类组件重新渲染,shouldComponentUpdate不生效的问题 2024-04-02 11:02:48 +08:00
huangxuan aa4984f997
feat(router): 修复HashRouter push与当前页面相同的URL时页面不刷新的问题 2024-04-02 10:53:25 +08:00
huangxuan 78f4bce57c
fix(router): inula-router路由匹配规则兼容react-router;HashHistory hash格式不合法时重定向至合法URL 2024-04-02 10:52:22 +08:00
huangxuan ebfe1eceb9
feat(core): 限制dangerouslySetInnerHTML API生效的条件,减少XSS攻击面 2024-04-02 10:47:31 +08:00
huangxuan ec34490202
feat(core): 导出version,兼容mobx 2024-04-02 09:51:58 +08:00
xuan eb5cb8237b !165 fix(core): 修复css变量为undefined是仍然被渲染的错误
* chore: bump jest to 29.7.0
* fix(core): 修复css变量为undefined是仍然被渲染的错误
2024-03-13 07:11:16 +00:00
聪小陈 b1b2224c6b !150 chore: 在官网统一维护 contributing
* chore: contributing docs
2024-02-20 04:49:41 +00:00
stevending1st 3ad82f5fe4 !142 fix(createInula): Repair the address of the official website
* fix(createInula): Repair the address of the official website
2024-02-17 06:43:25 +00:00
Hoikan 37dfbb1dff
add default pipeline template yaml 2024-02-05 06:23:02 +00:00
陈超涛 63b82c2632
!128 fix: eslint error
Merge pull request !128 from 聪小陈/fix-eslint-error
2024-01-31 01:58:17 +00:00
xiaohuoni c8d0ef933c fix: inula use workspace 2024-01-30 16:48:33 +08:00
xiaohuoni 98ca7531c9 chore: pr docs 2024-01-30 16:47:45 +08:00
xiaohuoni a3f7709c90 fix: build scripts error 2024-01-30 15:49:21 +08:00
xiaohuoni 7f4eae3127 fix: eslint error 2024-01-30 11:37:51 +08:00
openInula-robot f295f25176
!118 fix(request): 优化请求参数使用体验并解决 url 拼接问题
Merge pull request !118 from 涂旭辉/master
2024-01-24 07:24:53 +00:00
13659257719 22b05d908a Merge branch 'master' of https://gitee.com/openInula/inula 2024-01-24 15:23:35 +08:00
13659257719 0903248e2f fix(request): 优化请求参数使用体验和解决 URL 拼接问题 2024-01-24 15:23:16 +08:00
13659257719 80e22da1ec fix(request): 优化请求参数使用体验和解决 URL 拼接问题 2024-01-24 15:22:55 +08:00
openInula-robot ab1c68de6b
!111 增加ESM build格式
Merge pull request !111 from Hoikan/master
2024-01-17 09:08:04 +00:00
Hoikan 7c126dd857 Merge branch 'master' of gitee.com:openInula/inula into master
Signed-off-by: Hoikan <408255371@qq.com>
2024-01-17 08:02:53 +00:00
openInula-robot c3e3007aa6
!113 chore: 格式化代码,移动inula core ut
Merge pull request !113 from xuan/main
2024-01-11 12:38:06 +00:00
huangxuan 6dc8d0fcfa
chore: 格式化代码,inula-core ut更换路径 2024-01-11 20:19:01 +08:00
openInula-robot 0ac8ab0b6c
!112 chore: 配置githook格式化提交和校验commitMsg
Merge pull request !112 from xuan/main
2024-01-11 10:44:38 +00:00
huangxuan cb01814a27
fix(core): 删除无用代码 2024-01-11 17:55:48 +08:00
huangxuan b0f765f798
chore: 配置githook格式化提交和校验commitMsg 2024-01-11 17:23:29 +08:00
haiqin e336483157 fix: revert in not complete 2024-01-09 14:53:34 +08:00
haiqin c9bb4c07de chore: fix conflict 2024-01-08 11:53:10 +08:00
haiqin b4bbd146e8 build: add esm format 2024-01-08 11:49:49 +08:00
openInula-robot 74a54ceb61
!109 修复Suspense fallback中的组件发生更新时报错
Merge pull request !109 from Hoikan/master
2024-01-02 07:42:56 +00:00
haiqin 95f658a6e5 fix: fix test 2024-01-02 15:37:40 +08:00
haiqin f4d21f69a4 fix: fix test 2024-01-02 15:35:19 +08:00
haiqin 444b73f7ec fix: update got error in <Suspense /> fallback 2024-01-02 15:02:11 +08:00
openInula-robot c1de5906a9
!108 关于代码注释的一些建议
Merge pull request !108 from 陈贯劼/master
2023-12-28 10:06:22 +00:00
cgj b026ca8786 [comment]添加CONTRIBUTING.md,包含一些注释相关的建议 2023-12-28 17:35:46 +08:00
openInula-robot 210baeec9f
!106 更新Readme
Merge pull request !106 from 杨煦庭/master
2023-12-26 09:21:18 +00:00
openInula-robot b6017e6194
!107 [all]<feat> 版本号升级
Merge pull request !107 from 涂旭辉/master
2023-12-25 03:37:07 +00:00
13659257719 3bebf5280e [all]<feat> 版本号升级 2023-12-25 11:36:02 +08:00
杨煦庭 32e509f9de
update README.md.
Signed-off-by: 杨煦庭 <990815_yxt@sina.com>
2023-12-21 08:51:10 +00:00
杨煦庭 b2a08e8c6c
更新Readme 2023-12-21 07:56:37 +00:00
杨煦庭 d5780d248d
更新Readme 2023-12-21 07:52:18 +00:00
openInula-robot d44a968798
!105 [intl][create]<feat> 版本号更新
Merge pull request !105 from 涂旭辉/master
2023-12-19 03:26:35 +00:00
13659257719 9a53bbbe54 [intl][create]<feat> 版本号升级 2023-12-19 11:23:44 +08:00
openInula-robot 0cfcc3c437
!104 更新readme图片链接
Merge pull request !104 from 杨煦庭/master
2023-12-11 03:53:26 +00:00
yangxuting 81235e6276 更新readme图片链接 2023-12-11 09:37:20 +08:00
yangxuting 6595eb7044 修复Readme图片 2023-12-07 10:33:34 +08:00
openInula-robot 75bed609fe
!103 [inulax] isSame比较方法问题修复
Merge pull request !103 from xuan/main
2023-12-07 01:23:58 +00:00
openInula-robot efd914a426
!102 更新同步inula-intl代碼
Merge pull request !102 from YUYU-W/master
2023-12-06 08:30:00 +00:00
huangxuan 955b2cb574
[inulax] isSame比较方法问题修复 2023-12-06 16:06:26 +08:00
wangyu fb3180f2f2 modified: babel.config.js
modified:   example/App.tsx
	modified:   example/index.tsx
	modified:   index.ts
	modified:   package.json
	modified:   src/parser/Lexer.ts
	modified:   src/parser/mappingRule.ts
	modified:   src/parser/parseMappingRule.ts
	modified:   src/parser/parser.ts
	modified:   src/types/types.ts
	modified:   tsconfig.json
2023-12-06 15:37:37 +08:00
wangyu 925a6de0e2 add 2023-12-06 15:30:02 +08:00
openInula-robot b4ba997e72
!101 [all]<feat> 版本号升级
Merge pull request !101 from 涂旭辉/master
2023-12-06 01:48:11 +00:00
13659257719 ee784d80cd [all]<feat> 版本号升级 2023-12-06 09:47:08 +08:00
13659257719 4785c3092c [inula-router]<feat> 版本号升级 2023-12-06 09:45:22 +08:00
openInula-robot 949d059816
!100 [inual-rpiter]<feat> 版本号升级
Merge pull request !100 from 涂旭辉/master
2023-12-06 01:32:49 +00:00
13659257719 706a904856 [inula-router]<feat> 版本号升级 2023-12-06 09:21:24 +08:00
446 changed files with 15481 additions and 3240 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1,3 +1,3 @@
**/node_modules **/node_modules
build/ **/build/
*.d.ts *.d.ts

View File

@ -22,7 +22,7 @@ module.exports = {
], ],
root: true, root: true,
plugins: ['jest', 'no-for-of-loops', 'no-function-declare-after-return', 'react', '@typescript-eslint'], plugins: ['jest', 'no-function-declare-after-return', 'react', '@typescript-eslint'],
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
@ -56,8 +56,8 @@ module.exports = {
'comma-dangle': ['error', 'only-multiline'], 'comma-dangle': ['error', 'only-multiline'],
'no-constant-condition': 'off', 'no-constant-condition': 'off',
'no-for-of-loops/no-for-of-loops': 'error',
'no-function-declare-after-return/no-function-declare-after-return': 'error', 'no-function-declare-after-return/no-function-declare-after-return': 'error',
'@typescript-eslint/ban-ts-comment': 'warn'
}, },
globals: { globals: {
isDev: true, isDev: true,

View File

@ -3,7 +3,7 @@
**关联的 Issues:** [请列出与此 PR 相关的 issue 编号] **关联的 Issues:** [请列出与此 PR 相关的 issue 编号]
**检查项(无需修改,提交后界面上可勾选):** **检查项(无需修改,提交后界面上可勾选):**
- [ ] 代码已经被检视 - [ ] 代码已经被审查
- [ ] 代码符合项目的代码标准和最佳实践 - [ ] 代码符合项目的代码标准和最佳实践
- [ ] 代码已经通过所有测试用例 - [ ] 代码已经通过所有测试用例
- [ ] 代码不影响现有功能的正常使用 - [ ] 代码不影响现有功能的正常使用

4
.gitignore vendored
View File

@ -5,3 +5,7 @@ package-lock.json
pnpm-lock.yaml pnpm-lock.yaml
/packages/**/node_modules /packages/**/node_modules
/packages/inula-cli/lib /packages/inula-cli/lib
build
/packages/inula-router/connectRouter
/packages/inula-router/router
.inula-max

4
.husky/commit-msg Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run commitlint

4
.husky/pre-commit Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint-commit

3
.prettierignore Normal file
View File

@ -0,0 +1,3 @@
**/build
*.md
*.html

View File

@ -16,17 +16,17 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
printWidth: 120, // 一行120字符数如果超过会进行换行 printWidth: 120, // 一行120字符数如果超过会进行换行
tabWidth: 2, // tab等2个空格 tabWidth: 2, // tab等2个空格
useTabs: false, // 用空格缩进行 useTabs: false, // 用空格缩进行
semi: true, // 行尾使用分号 semi: true, // 行尾使用分号
singleQuote: true, // 字符串使用单引号 singleQuote: true, // 字符串使用单引号
quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号 quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号
jsxSingleQuote: false, // 在JSX中使用双引号 jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等) trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格 bracketSpacing: true, // 对象的括号间增加空格
bracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾 bracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号 arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码 vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码
endOfLine: 'lf', // 仅限换行(\n endOfLine: 'auto', // 仅限换行(\n
}; };

View File

@ -0,0 +1,51 @@
version: '1.0'
name: branch-pipeline
displayName: BranchPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
exclude:
- master
include:
- .*

View File

@ -0,0 +1,49 @@
version: '1.0'
name: master-pipeline
displayName: MasterPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
- stage:
name: release
displayName: 发布
steps:
- step: publish@release_artifacts
name: publish_release_artifacts
displayName: '发布'
# 上游上传制品任务的产出
dependArtifact: output
# 发布制品版本号
version: '1.0.0.0'
# 是否开启版本号自增,默认开启
autoIncrement: true
triggers:
push:
branches:
include:
- master

36
.workflow/pr-pipeline.yml Normal file
View File

@ -0,0 +1,36 @@
version: '1.0'
name: pr-pipeline
displayName: PRPipeline
stages:
- stage:
name: compile
displayName: 编译
steps:
- step: build@nodejs
name: build_nodejs
displayName: Nodejs 构建
# 支持8.16.2、10.17.0、12.16.1、14.16.0、15.12.0五个版本
nodeVersion: 14.16.0
# 构建命令:安装依赖 -> 清除上次打包产物残留 -> 执行构建 【请根据项目实际产出进行填写】
commands:
- npm install && rm -rf ./dist && npm run build
# 非必填字段开启后表示将构建产物暂存但不会上传到制品库中7天后自动清除
artifacts:
# 构建产物名字作为产物的唯一标识可向下传递支持自定义默认为BUILD_ARTIFACT。在下游可以通过${BUILD_ARTIFACT}方式引用来获取构建物地址
- name: BUILD_ARTIFACT
# 构建产物获取路径,是指代码编译完毕之后构建物的所在路径
path:
- ./dist
- step: publish@general_artifacts
name: publish_general_artifacts
displayName: 上传制品
# 上游构建任务定义的产物名默认BUILD_ARTIFACT
dependArtifact: BUILD_ARTIFACT
# 上传到制品库时的制品命名默认output
artifactName: output
dependsOn: build_nodejs
triggers:
pr:
branches:
include:
- master

3
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,3 @@
# Inula Contributing Guide
查看[贡献指南](https://docs.openinula.net/docs/%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97)获取完整指南。

View File

@ -6,68 +6,73 @@
## 技术架构 ## 技术架构
![输入图片说明](https://gitee.com/openInula/inula-docs/raw/master/static/img/structure.png) ![](https://openinula-website.obs.ap-southeast-1.myhuaweicloud.com/misc/structure.png)
### 核心能力 ## 核心能力
#### 响应式API(实验性功能可在reactive分支查看代码或使用npm仓中experiment版本体验) ### 响应式API
* openInula 通过最小化重新渲染的范围从而进行高效的UI渲染。这种方式避免了虚拟 DOM 的开销,使得 openInula 在性能方面表现出色。 openInula 通过监听状态变量的变化,以细粒度的依赖追踪机制来实现响应式更新,避免了虚拟 DOM 的开销。通过最小化重新渲染的范围从而进行高效的UI渲染。无需用户过度关注性能优化。
* openInula 通过比较变化前后的 JavaScript 对象以细粒度的依赖追踪机制来实现响应式更新,无需用户过度关注性能优化。
* 简洁API
1. openInula 提供了两组简洁直观的API--响应式 API 和与 React 一致的传统 API使得开发者可以轻松地构建复杂的交互式界面。
2. openInula 简洁的 API 极大降低了开发者的学习成本开发者使用响应式API可以快速构建高效的前端界面。
#### 兼容 ReactAPI >(实验性功能,可在 `reactive` 分支查看代码或使用 npm 仓中 experimental 版本体验)
* 与React保持一致、可以无缝支持 React 生态。 ### 兼容 React API
* 使用传统 API 可以无缝将 React 项目切换至 openInulaReact 应用可零修改切换至 openInula。
提供与 React 一致的 API完全支持 React 生态,可将 React 应用可零修改切换至 openInula。
### openInula 配套组件 ### openInula 配套组件
#### 状态管理器 → inula-X #### 状态管理器 inula-X
inula-X 是 openInula 默认提供的状态管理器。无需额外引入三方库,就可以简单实现跨组件/页面共享状态。
inula-X 是 openInula 默认提供的状态管理器,无需额外引入三方库,就可以简单实现跨组件/页面共享状态。
inula-X 与 Redux 相比,可创建多个 Store不需要在 Reducer 中返回 state 并且简化了 Action 和 Reducer 的创建步骤原生支持异步能力组件能做到精准重渲染。inula-X 均可使用函数组件、class 组件,能提供 redux 的适配接口及支持响应式的特点。 inula-X 与 Redux 相比,可创建多个 Store不需要在 Reducer 中返回 state 并且简化了 Action 和 Reducer 的创建步骤原生支持异步能力组件能做到精准重渲染。inula-X 均可使用函数组件、class 组件,能提供 redux 的适配接口及支持响应式的特点。
#### 路由 inula-router #### 路由 inula-router
inula-router 是 openInula 生态组建的一部分,为 openInula 提供前端路由的能力,是构建大型应用必要组件。 inula-router 为 openInula 提供前端路由的能力,是构建大型应用必要组件,涵盖 react-router、history、connect-react-router 的功能。
inula-router 涵盖 react-router、history、connect-react-router 的功能。
#### 请求 inula-request #### 请求 inula-request
inula-request 是 openInula 生态组件,涵盖常见的网络请求方式,并提供动态轮询钩子函数给用户更便捷的定制化请求体验。 inula-request 是 openInula 的网络请求组件,不仅涵盖常见的网络请求方式,还提供动态轮询钩子函数给用户更便捷的定制化请求体验。
#### 国际化 inula-intl #### 国际化 inula-intl
inula-intl 是基于 openInula 生态组件,其主要提供了国际化功能,涵盖了基本的国际化组件和钩子函数,便于用户在构建国际化能力时方便操作 inula-intl 是基于 openInula 的国际化组件,涵盖了基本的国际化组件和钩子函数,允许用户更方便地构建国际化能力
#### 调试工具 inula-dev-tools #### 调试工具 inula-dev-tools
inula-dev-tools 是一个为 openInula 开发者提供的强大工具集,能够方便地查看和编辑组件树、管理应用状态以及进行性能分析,极大提高了开发效率和诊断问题的便捷性。 inula-dev-tools 是一个为 openInula 开发者提供的强大工具集,能够方便地查看和编辑组件树、管理应用状态以及进行性能分析,极大提高了开发效率和诊断问题的便捷性。
#### 脚手架 → inula-cli #### 脚手架 create-inula
inula-cli 是一套针对 openInula 的编译期插件它支持代码优化、JSX 语法转换以及代码分割,有助于提高应用的性能、可读性和可维护性 create-inula 是一套用于创建 openInula 项目的脚手架工具。它预置了一系列项目模板,允许开发者通过命令行按需快速生成可运行的项目代码
## openInula 文档 ## 参与贡献
我们鼓励开发者以各种方式参与代码贡献、生态拓展或文档反馈,献您的原创内容,详细请参考[贡献指南](https://docs.openinula.net/docs/%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97)。
### 官方链接
欢迎访问 openInula 官网与文档仓库,参与 openInula 开发者文档开源项目,与我们一起完善开发者文档。 欢迎访问 openInula 官网与文档仓库,参与 openInula 开发者文档开源项目,与我们一起完善开发者文档。
+ openInula 官网地址:[https://www.openinula.net/](https://www.openinula.net/) * openInula 官网:[https://www.openinula.net/](https://www.openinula.net/)
+ openInula 文档站地址:[https://docs.openinula.net/](https://docs.openinula.net/) * openInula 文档:[https://docs.openinula.net/](https://docs.openinula.net/)
* openInula 仓库地址:[https://gitee.com/openinula/inula](https://gitee.com/openinula/inula)
* openInula 社提案备忘录RFC[https://gitee.com/openInula/rfcs](https://gitee.com/openInula/rfcs)
## 代码仓地址 ### 社区贡献者案例
openInula 仓库地址:[https://gitee.com/openinula](https://gitee.com/openinula) **[`umi-inula`](https://gitee.com/congxiaochen/inula)**
## 如何参与 基于 umijs 与 openInula 的开发框架集成官方组件与UI、AIGC等功能开箱即用。
**参与贡献** **[`VoerkaI18n`](https://github.com/zhangfisher/voerka-i18n/)**
欢迎您参与贡献,我们鼓励开发者以各种方式参与文档反馈和贡献。
您可以对现有文档进行评价、简单更改、反馈文档质量问题、贡献您的原创内容,详细请参考[贡献指南](https://docs.openinula.net/docs/%E8%B4%A1%E7%8C%AE%E6%8C%87%E5%8D%97)。 适用于多框架的 JavaScript 国际化解决方案,提供对 openInula 的适配。
- [适配示例](https://gitee.com/link?target=https%3A%2F%2Fgithub.com%2Fzhangfisher%2Fvoerka-i18n%2Ftree%2Fmaster%2Fexamples%2Fopeninula)
- [适配文档](https://gitee.com/link?target=https%3A%2F%2Fzhangfisher.github.io%2Fvoerka-i18n%2F%23%2Fzh%2Fguide%2Fintegration%2Fopeninula)
## 许可协议 ## 许可协议
@ -75,6 +80,8 @@ openInula 主要遵循 [Mulan Permissive Software License v2](http://license.cos
## 联系方式 ## 联系方式
team@inulajs.org * 官方邮箱: [team@inulajs.org](mailto:team@inulajs.org)
* 微信公众号:
![](https://www.openinula.net/assets/qrcode.inula-02f99d58.jpg)

19
commitlint.config.js Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
module.exports = {
extends: ['@commitlint/config-conventional'],
'type-enum': ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'types'],
};

View File

@ -5,65 +5,86 @@
"private": true, "private": true,
"scripts": { "scripts": {
"lint": "eslint . --ext .ts --fix", "lint": "eslint . --ext .ts --fix",
"prettier": "prettier -w libs/**/*.ts", "lint-commit": "lint-staged",
"prettier": "prettier .prettierrc.js -w packages/**/*.{ts,tsx,js,jsx}",
"build:inula": "pnpm -F openinula build", "build:inula": "pnpm -F openinula build",
"test:inula": "pnpm -F openinula test", "test:inula": "pnpm -F openinula test",
"test:inula-intl": "pnpm -F inula-intl test",
"test:inula-request": "pnpm -F inula-request test",
"test:inula-router": "pnpm -F inula-router test",
"build:inula-cli": "pnpm -F inula-cli build", "build:inula-cli": "pnpm -F inula-cli build",
"build:inula-intl": "pnpm -F inula-intl build", "build:inula-intl": "pnpm -F inula-intl build",
"build:inula-request": "pnpm -F inula-request build", "build:inula-request": "pnpm -F inula-request build",
"build:inula-router": "pnpm -F inula-router build" "build:inula-router": "pnpm -F inula-router build",
"commitlint": "commitlint --config commitlint.config.js -e",
"postinstall": "husky install"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"prettier .prettierrc.js -w"
]
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.16.7", "@babel/core": "7.23.7",
"@babel/plugin-proposal-class-properties": "7.16.7", "@babel/plugin-proposal-class-properties": "7.18.6",
"@babel/plugin-proposal-nullish-coalescing-operator": "7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator": "7.18.6",
"@babel/plugin-proposal-object-rest-spread": "7.16.7", "@babel/plugin-proposal-object-rest-spread": "7.20.7",
"@babel/plugin-proposal-optional-chaining": "7.16.7", "@babel/plugin-proposal-optional-chaining": "7.21.0",
"@babel/plugin-proposal-private-methods": "7.16.7", "@babel/plugin-proposal-private-methods": "7.18.6",
"@babel/plugin-proposal-private-property-in-object": "7.16.7", "@babel/plugin-proposal-private-property-in-object": "7.21.11",
"@babel/plugin-syntax-jsx": "7.16.7", "@babel/plugin-syntax-jsx": "7.23.3",
"@babel/plugin-transform-arrow-functions": "7.16.7", "@babel/plugin-transform-arrow-functions": "7.23.3",
"@babel/plugin-transform-block-scoped-functions": "7.16.7", "@babel/plugin-transform-block-scoped-functions": "7.23.3",
"@babel/plugin-transform-block-scoping": "7.16.7", "@babel/plugin-transform-block-scoping": "7.23.4",
"@babel/plugin-transform-classes": "7.16.7", "@babel/plugin-transform-classes": "7.23.8",
"@babel/plugin-transform-computed-properties": "7.16.7", "@babel/plugin-transform-computed-properties": "7.23.3",
"@babel/plugin-transform-destructuring": "7.16.7", "@babel/plugin-transform-destructuring": "7.23.3",
"@babel/plugin-transform-for-of": "7.16.7", "@babel/plugin-transform-for-of": "7.23.6",
"@babel/plugin-transform-literals": "7.16.7", "@babel/plugin-transform-literals": "7.23.3",
"@babel/plugin-transform-object-assign": "7.16.7", "@babel/plugin-transform-object-assign": "7.23.3",
"@babel/plugin-transform-object-super": "7.16.7", "@babel/plugin-transform-object-super": "7.23.3",
"@babel/plugin-transform-parameters": "7.16.7", "@babel/plugin-transform-parameters": "7.23.3",
"@babel/plugin-transform-react-jsx": "7.16.7", "@babel/plugin-transform-react-jsx": "7.23.4",
"@babel/plugin-transform-react-jsx-source": "^7.16.7", "@babel/plugin-transform-react-jsx-source": "^7.23.3",
"@babel/plugin-transform-runtime": "7.16.7", "@babel/plugin-transform-runtime": "7.23.7",
"@babel/plugin-transform-shorthand-properties": "7.16.7", "@babel/plugin-transform-shorthand-properties": "7.23.3",
"@babel/plugin-transform-spread": "7.16.7", "@babel/plugin-transform-spread": "7.23.3",
"@babel/plugin-transform-template-literals": "7.16.7", "@babel/plugin-transform-template-literals": "7.23.3",
"@babel/preset-env": "7.16.7", "@babel/preset-env": "7.23.8",
"@babel/preset-typescript": "7.16.7", "@babel/preset-typescript": "7.23.3",
"@babel/runtime": "7.16.7", "@babel/runtime": "7.23.8",
"@rollup/plugin-babel": "^5.3.1", "@commitlint/cli": "^17.8.1",
"@rollup/plugin-node-resolve": "^13.3.0", "@commitlint/config-conventional": "^17.8.1",
"@rollup/plugin-babel": "^6.0.4",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^4.0.0", "@rollup/plugin-replace": "^4.0.0",
"@types/jest": "^26.0.24", "@types/jest": "^29.5.11",
"@types/node": "^17.0.18", "@types/node": "^17.0.18",
"@typescript-eslint/eslint-plugin": "4.8.0", "@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "4.8.0", "@typescript-eslint/parser": "6.18.1",
"babel-jest": "^27.5.1", "@babel/parser": "^7.24.7",
"magic-string": "^0.30.10",
"babel-jest": "^29.7.0",
"ejs": "^3.1.8", "ejs": "^3.1.8",
"eslint": "7.13.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^6.9.0", "eslint-config-prettier": "^6.9.0",
"eslint-plugin-jest": "^22.15.0", "eslint-plugin-jest": "^22.15.0",
"eslint-plugin-no-for-of-loops": "^1.0.0",
"eslint-plugin-no-function-declare-after-return": "^1.0.0", "eslint-plugin-no-function-declare-after-return": "^1.0.0",
"eslint-plugin-react": "7.14.3", "eslint-plugin-react": "7.14.3",
"jest": "^25.5.4", "husky": "^8.0.3",
"jest-environment-jsdom-sixteen": "^1.0.3", "jest": "^29.7.0",
"prettier": "2.6.2", "jest-environment-jsdom": "^29.7.0",
"rollup": "^2.75.5", "lint-staged": "^15.2.0",
"openinula": "workspace:*",
"prettier": "^3.1.1",
"rollup": "^2.79.1",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-execute": "^1.1.1", "rollup-plugin-execute": "^1.1.1",
"rollup-plugin-terser": "^7.0.2", "rollup-plugin-terser": "^7.0.2",
"typescript": "4.2.3" "rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-polyfill-node": "^0.13.0",
"ts-jest": "^29.1.1",
"typescript": "^4.9.5"
}, },
"engines": { "engines": {
"node": ">=10.x", "node": ">=10.x",

View File

@ -1,32 +0,0 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
'use strict';
module.exports = {
printWidth: 120, // 一行120字符数如果超过会进行换行
tabWidth: 2, // tab等2个空格
useTabs: false, // 用空格缩进行
semi: true, // 行尾使用分号
singleQuote: true, // 字符串使用单引号
quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号
jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格
bracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码
endOfLine: 'lf', // 仅限换行(\n
};

View File

@ -140,8 +140,7 @@ class BasicGenerator extends Generator {
if (fs.lstatSync(fullpath).isDirectory()) { if (fs.lstatSync(fullpath).isDirectory()) {
this.traverseDirBubble(fullpath, dirCallback, fileCallback); this.traverseDirBubble(fullpath, dirCallback, fileCallback);
dirCallback(fullpath); dirCallback(fullpath);
} } else {
else{
fileCallback(fullpath); fileCallback(fullpath);
} }
} }

View File

@ -11,7 +11,7 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"openinula": "^0.0.1" "openinula": "^0.1.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.21.4", "@babel/core": "^7.21.4",

View File

@ -34,7 +34,9 @@ function App() {
<h2>了解更多</h2> <h2>了解更多</h2>
<p> <p>
要了解 Inula查看{' '} 要了解 Inula查看{' '}
<a href="https://openinula.com/" target="_blank">Inula 官网</a> <a href="https://openinula.net/" target="_blank">
Inula 官网
</a>
</p> </p>
</div> </div>
</div> </div>

View File

@ -10,7 +10,7 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"openinula": "^0.0.1" "openinula": "^0.1.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.21.4", "@babel/core": "^7.21.4",

View File

@ -33,10 +33,12 @@ class App extends Inula.Component {
</div> </div>
<div class="card animate__animated animate__zoomIn"> <div class="card animate__animated animate__zoomIn">
<h2>了解更多</h2> <h2>了解更多</h2>
<p> <p>
要了解 Inula查看{' '} 要了解 Inula查看{' '}
<a href="https://openinula.org" target="_blank">Inula 官网</a> <a href="https://openinula.org" target="_blank">
</p> Inula 官网
</a>
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -26,7 +26,7 @@ function App() {
</div> </div>
<div className="content"> <div className="content">
<div className="card animate__animated animate__zoomIn"> <div className="card animate__animated animate__zoomIn">
<ReactiveComponent/> <ReactiveComponent />
</div> </div>
</div> </div>
<div class="content"> <div class="content">
@ -34,7 +34,9 @@ function App() {
<h2>了解更多</h2> <h2>了解更多</h2>
<p> <p>
要了解 Inula查看{' '} 要了解 Inula查看{' '}
<a href="https://openinula.com/" target="_blank">Inula 官网</a> <a href="https://openinula.net/" target="_blank">
Inula 官网
</a>
</p> </p>
</div> </div>
</div> </div>

View File

@ -27,16 +27,18 @@ class App extends Inula.Component {
</div> </div>
<div className="content"> <div className="content">
<div className="card animate__animated animate__zoomIn"> <div className="card animate__animated animate__zoomIn">
<ReactiveComponent/> <ReactiveComponent />
</div> </div>
</div> </div>
<div class="content"> <div class="content">
<div class="card animate__animated animate__zoomIn"> <div class="card animate__animated animate__zoomIn">
<h2>了解更多</h2> <h2>了解更多</h2>
<p> <p>
要了解 Inula查看{' '} 要了解 Inula查看{' '}
<a href="https://openinula.org" target="_blank">Inula 官网</a> <a href="https://openinula.org" target="_blank">
</p> Inula 官网
</a>
</p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -32,8 +32,8 @@ const generatorType = fs
}); });
const runGenerator = async (templatePath, { name = '', cwd = process.cwd(), args = {} }) => { const runGenerator = async (templatePath, { name = '', cwd = process.cwd(), args = {} }) => {
let currentPath;
return new Promise(resolve => { return new Promise(resolve => {
let currentPath;
if (name) { if (name) {
mkdirp.sync(name); mkdirp.sync(name);
currentPath = path.join(cwd, name); currentPath = path.join(cwd, name);
@ -68,10 +68,10 @@ const run = async config => {
{ {
name: 'projectName', name: 'projectName',
message: 'Project name', message: 'Project name',
type: 'input' type: 'input',
}, },
]); ]);
config.name = answers.projectName; config.name = answers.projectName;
} }
if (!type) { if (!type) {
const answers = await inquirer.prompt([ const answers = await inquirer.prompt([

View File

@ -1,6 +1,6 @@
{ {
"name": "create-inula", "name": "create-inula",
"version": "0.0.6", "version": "0.0.8",
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"bin": { "bin": {

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
module.exports = {
'parser': 'babel-eslint',
'env': {
'amd': true,
'es6': true,
'browser': true,
'node': false
},
'parserOptions': {
'ecmaVersion': 6,
'sourceType': 'module',
'ecmaFeatures': {
'jsx': true
}
},
'ignorePatterns': [
"src/template"
],
'rules': {
'indent': [
'error',
4,
{
SwitchCase: 1,
flatTernaryExpressions: true
}
],
'no-unused-vars': 'off', // 允许变量声明后未使用
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
"no-underscore-dangle": ["off", "always"], // 允许私有变量 _xxx的变量命名方式
'filenames/match-exported': 0,
'consistent-return': 0,
"comma-dangle": [2, "never"], // 组和对象键值对最后一个逗号, never参数不能带末尾的逗号, always参数必须带末尾的逗号
'global-require': 0, // 允许require语句不出现在顶层中
'no-nested-ternary': 0, // 允许嵌套三元表达式
'no-unused-expressions': 0, // 允许使用未执行的表达式。比如fn是一个函数允许 fn && fn()
'no-throw-literal': 0, // 允许throw抛出对象格式
'@typescript-eslint/member-ordering': 0 // 禁用TypeScript声明规范
}
}

View File

@ -1,3 +0,0 @@
node_modules/
webpack/
public/

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
export default {
printWidth: 120, // 一行120字符数如果超过会进行换行
tabWidth: 2, // tab等2个空格
useTabs: false, // 用空格缩进行
semi: true, // 行尾使用分号
singleQuote: true, // 字符串使用单引号
quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号
jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格
jsxBracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码
endOfLine: 'lf', // 仅限换行(\n
};

View File

@ -17,4 +17,4 @@
import run from '../lib/cli/cli.js'; import run from '../lib/cli/cli.js';
run(); run();

View File

@ -13,29 +13,4 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
const {preset} = require("./jest.config"); declare module 'crequire';
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['> 1%', 'last 2 versions', 'not ie <= 8'],
node: 'current',
},
useBuiltIns: 'usage',
corejs: 3,
},
],
[
'@babel/preset-typescript',
],
[
"@babel/preset-react",
{
"runtime": "automatic",
"importSource": "openinula"
}
]
],
};

View File

@ -1,51 +0,0 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
import webpack from 'webpack';
import { build } from 'vite';
export default (api: any) => {
api.registerCommand({
name: 'build',
description: 'build application for production',
initialState: api.buildConfig,
fn: async function (args: any, state: any) {
switch (api.compileMode) {
case 'webpack':
if (state) {
api.applyHook({ name: 'beforeCompile', args: state });
state.forEach((s: any) => {
webpack(s.config, (err: any, stats: any) => {
if (err || stats.hasErrors()) {
api.logger.error(`Build failed.err: ${err}, stats:${stats}`);
}
});
});
} else {
api.logger.error(`Build failed. Can't find build config.`);
}
break;
case 'vite':
if (state) {
api.applyHook({ name: 'beforeCompile' });
build(state);
} else {
api.logger.error(`Build failed. Can't find build config.`);
}
break;
}
},
});
};

View File

@ -19,7 +19,6 @@ import { createServer } from 'vite';
import { API } from '../../../types/types'; import { API } from '../../../types/types';
import setupProxy from '../../../utils/setupProxy.js'; import setupProxy from '../../../utils/setupProxy.js';
export default (api: API) => { export default (api: API) => {
api.registerCommand({ api.registerCommand({
name: 'dev', name: 'dev',
@ -46,7 +45,7 @@ export default (api: API) => {
if (api.userConfig.devBuildConfig.devProxy) { if (api.userConfig.devBuildConfig.devProxy) {
devServerOptions.onBeforeSetupMiddleware = (devServer: WebpackDevServer) => { devServerOptions.onBeforeSetupMiddleware = (devServer: WebpackDevServer) => {
setupProxy(devServer.app, api); setupProxy(devServer.app, api);
} };
} }
api.applyHook({ api.applyHook({

View File

@ -33,15 +33,17 @@ export default (api: API) => {
args._.shift(); args._.shift();
} }
if (args._.length === 0) { if (args._.length === 0) {
api.logger.warn("Can't find any generate options."); api.logger.warn('Can\'t find any generate options.');
return; return;
} }
switch (args._[0]) { switch (args._[0]) {
case 'jest': case 'jest':
args._.shift(); {
const isESM = api.packageJson['type'] === 'module'; args._.shift();
await generateJest(args, api.cwd, isESM); const isESM = api.packageJson['type'] === 'module';
await generateJest(args, api.cwd, isESM);
}
break; break;
default: default:
} }
@ -50,7 +52,7 @@ export default (api: API) => {
}; };
const generateJest = async (args: yargsParser.Arguments, cwd: string, isESM: boolean) => { const generateJest = async (args: yargsParser.Arguments, cwd: string, isESM: boolean) => {
let isTs: boolean = false; let isTs = false;
if (args['ts']) { if (args['ts']) {
isTs = true; isTs = true;
} else { } else {

View File

@ -25,7 +25,7 @@ export default (api: any) => {
initialState: api.userConfig.remoteProxy, initialState: api.userConfig.remoteProxy,
fn: async function (args: any, state: any) { fn: async function (args: any, state: any) {
if (!state) { if (!state) {
api.logger.error(`Invalid proxy config!`); api.logger.error('Invalid proxy config!');
return; return;
} }
const app = express(); const app = express();

View File

@ -46,7 +46,7 @@ export default async function run() {
initializeEnv(); initializeEnv();
if (command === 'version' || command === 'help') { if (command === 'version' || command === 'help') {
process.env.INNER_COMMAND = "true" process.env.INNER_COMMAND = 'true';
} }
switch (command) { switch (command) {
@ -61,9 +61,9 @@ export default async function run() {
break; break;
} }
let enableDebug: boolean = false; let enableDebug = false;
if (process.env.DEBUG === "true") { if (process.env.DEBUG === 'true') {
enableDebug = true; enableDebug = true;
} }

View File

@ -89,7 +89,7 @@ export default class Config {
getConfigFile(): string | null { getConfigFile(): string | null {
const configFileList: string[] = DEFAULT_CONFIG_FILES.map(f => join(this.cwd, f)); const configFileList: string[] = DEFAULT_CONFIG_FILES.map(f => join(this.cwd, f));
for (let configFile of configFileList) { for (const configFile of configFileList) {
if (existsSync(configFile)) { if (existsSync(configFile)) {
return configFile; return configFile;
} }

View File

@ -46,11 +46,11 @@ export default class Hub {
userConfig: UserConfig = {}; userConfig: UserConfig = {};
packageJson: PackageJSON; packageJson: PackageJSON;
stage: ServiceStage = ServiceStage.uninitialized; stage: ServiceStage = ServiceStage.uninitialized;
buildConfig: {name:string, config: object}[] = []; buildConfig: { name: string; config: Record<string, unknown> }[] = [];
pluginManager: Plugin; pluginManager: Plugin;
buildConfigPath: BuildConfig[] = []; buildConfigPath: BuildConfig[] = [];
devBuildConfig: object = {}; devBuildConfig: Record<string, unknown> = {};
compileMode: string = ''; compileMode = '';
builtInPlugins: string[] = []; builtInPlugins: string[] = [];
pluginPaths: string[] = []; pluginPaths: string[] = [];
devProxy: DevProxy | null = null; devProxy: DevProxy | null = null;
@ -95,7 +95,7 @@ export default class Hub {
this.userConfig = await this.configManager.getUserConfig(); this.userConfig = await this.configManager.getUserConfig();
// 设置编译模式 // 设置编译模式
this.setCompileMode() this.setCompileMode();
// 获取编译配置 // 获取编译配置
await this.analyzeBuildConfig(); await this.analyzeBuildConfig();
@ -135,8 +135,8 @@ export default class Hub {
: this.pluginManager.commands[command]; : this.pluginManager.commands[command];
if (commands === undefined) { if (commands === undefined) {
this.logger.error(`Invalid command ${command}`) this.logger.error(`Invalid command ${command}`);
return return;
} }
const { fn } = commands as ICommand; const { fn } = commands as ICommand;
@ -150,21 +150,22 @@ export default class Hub {
async analyzeBuildConfig() { async analyzeBuildConfig() {
if (this.userConfig.devBuildConfig) { if (this.userConfig.devBuildConfig) {
let { name, path, env } = this.userConfig.devBuildConfig; let { path } = this.userConfig.devBuildConfig;
const { env } = this.userConfig.devBuildConfig;
path = isAbsolute(path) ? path : join(process.cwd(), path); path = isAbsolute(path) ? path : join(process.cwd(), path);
if (!existsSync(path)) { if (!existsSync(path)) {
this.logger.warn(`Cant't find dev build config. Path is ${path}`); this.logger.warn(`Cant't find dev build config. Path is ${path}`);
return; return;
} }
this.logger.debug(`Find dev build config. Path is ${path}`); this.logger.debug(`Find dev build config. Path is ${path}`);
let bc = await loadModule<object | Function>(path); const bc = await loadModule<Record<string, unknown> | ((...args: any[]) => any)>(path);
if (bc == undefined) { if (bc == undefined) {
return; return;
} }
let finalBc = {}; let finalBc = {};
if (typeof bc === 'function') { if (typeof bc === 'function') {
finalBc = bc(env) finalBc = bc(env);
this.devBuildConfig = finalBc; this.devBuildConfig = finalBc;
return; return;
} }
@ -175,55 +176,54 @@ export default class Hub {
} }
} }
if (!this.userConfig.buildConfig) { if (!this.userConfig.buildConfig) {
switch (this.compileMode) { switch (this.compileMode) {
case 'webpack': case 'webpack':
this.buildConfigPath.push({name:'default', path:'./webpack.config.js'}) this.buildConfigPath.push({ name: 'default', path: './webpack.config.js' });
break; break;
case 'vite': case 'vite':
this.buildConfigPath.push({name:'default', path:'./vite.config.js'}) this.buildConfigPath.push({ name: 'default', path: './vite.config.js' });
break; break;
default: default:
this.logger.warn(`Unknown compile mode ${this.compileMode}`); this.logger.warn(`Unknown compile mode ${this.compileMode}`);
break; break;
} }
} else { } else {
this.userConfig.buildConfig.forEach((userBuildConfig) => { this.userConfig.buildConfig.forEach(userBuildConfig => {
if (typeof userBuildConfig === 'object') { if (typeof userBuildConfig === 'object') {
this.buildConfigPath.push(userBuildConfig); this.buildConfigPath.push(userBuildConfig);
} }
}) });
} }
this.buildConfigPath.forEach(async (config) => { this.buildConfigPath.forEach(async config => {
let {name, path} = config; let { path } = config;
const { name } = config;
path = isAbsolute(path) ? path : join(process.cwd(), path); path = isAbsolute(path) ? path : join(process.cwd(), path);
if (!existsSync(path)) { if (!existsSync(path)) {
this.logger.debug(`Cant't find build config. Path is ${path}`); this.logger.debug(`Cant't find build config. Path is ${path}`);
return; return;
} }
this.logger.debug(`Find build config. Path is ${path}`); this.logger.debug(`Find build config. Path is ${path}`);
let bc = await loadModule<object | Function >(path); const bc = await loadModule<Record<string, unknown> | ((...args: any[]) => any)>(path);
if (bc == undefined) { if (bc == undefined) {
return; return;
} }
let finalBc = {}; let finalBc = {};
if (typeof bc === 'function') { if (typeof bc === 'function') {
finalBc = bc(config.env) finalBc = bc(config.env);
this.buildConfig.push({name: name, config: finalBc}); this.buildConfig.push({ name: name, config: finalBc });
return; return;
} }
this.buildConfig.push({name: name, config: bc}); this.buildConfig.push({ name: name, config: bc });
}) });
} }
getConfigName(name: string): string { getConfigName(name: string): string {
name = name.replace('webpack.', ''); name = name.replace('webpack.', '');
name = name.replace('.js', ''); name = name.replace('.js', '');
name = name.replace('.ts', ''); name = name.replace('.ts', '');
return name return name;
} }
} }

View File

@ -36,7 +36,7 @@ export interface IPlugin {
id: string; id: string;
key: string; key: string;
path: string; path: string;
apply: Function; apply: (...args: any[]) => any;
} }
export default class Plugin { export default class Plugin {
@ -57,7 +57,7 @@ export default class Plugin {
} = {}; } = {};
hub: Hub; hub: Hub;
logger: Logger; logger: Logger;
registerFunction: Function[] = []; registerFunction: ((...args: any[]) => any)[] = [];
// 解决调用this[props]时ts提示属性未知 // 解决调用this[props]时ts提示属性未知
[key: string]: any; [key: string]: any;
@ -110,7 +110,7 @@ export default class Plugin {
}); });
for (const obj of objs) { for (const obj of objs) {
const module: Function | undefined = await loadModule(obj.path); const module: ((...args: any[]) => any) | undefined = await loadModule(obj.path);
if (module) { if (module) {
try { try {
module(obj.api); module(obj.api);
@ -135,15 +135,11 @@ export default class Plugin {
return new Proxy(pluginAPI, { return new Proxy(pluginAPI, {
get: (target: PluginAPI, prop: string) => { get: (target: PluginAPI, prop: string) => {
if (['userConfig', 'devBuildConfig', 'buildConfig', 'compileMode', 'packageJson', 'cwd'].includes(prop)) { if (['userConfig', 'devBuildConfig', 'buildConfig', 'compileMode', 'packageJson', 'cwd'].includes(prop)) {
return typeof this.hub[prop] === 'function' return typeof this.hub[prop] === 'function' ? this.hub[prop].bind(this.hub) : this.hub[prop];
? this.hub[prop].bind(this.hub)
: this.hub[prop];
} }
if (['setStore', 'logger', 'commands'].includes(prop)) { if (['setStore', 'logger', 'commands'].includes(prop)) {
return typeof this[prop] === 'function' return typeof this[prop] === 'function' ? this[prop].bind(this) : this[prop];
? this[prop].bind(this)
: this[prop];
} }
return target[prop]; return target[prop];

View File

@ -55,11 +55,11 @@ export default class PluginAPI {
this.register(hook); this.register(hook);
} }
registerMethod(fn: Function) { registerMethod(fn: (...args: any[]) => any) {
this.manager.registerFunction.push(fn); this.manager.registerFunction.push(fn);
} }
async applyHook(name: string, args?: any ) { async applyHook(name: string, args?: any) {
const hooks: IHook[] = this.manager.hooks[name] || []; const hooks: IHook[] = this.manager.hooks[name] || [];
let config: any = undefined; let config: any = undefined;
for (const hook of hooks) { for (const hook of hooks) {

View File

@ -19,11 +19,8 @@ import { Logger } from '../utils/logger.js';
import type * as http from 'http'; import type * as http from 'http';
import type * as express from 'express'; import type * as express from 'express';
type Request = express.Request;
interface Request extends express.Request { type Response = express.Response;
}
interface Response extends express.Response {
}
export interface IDep { export interface IDep {
[name: string]: string; [name: string]: string;
@ -40,7 +37,7 @@ export interface IPlugin {
id: string; id: string;
key: string; key: string;
path: string; path: string;
apply: Function; apply: (...args: any[]) => any;
config?: IPluginConfig; config?: IPluginConfig;
isPreset?: boolean; isPreset?: boolean;
@ -48,7 +45,7 @@ export interface IPlugin {
export interface IPluginConfig { export interface IPluginConfig {
default?: any; default?: any;
onChange?: string | Function; onChange?: string | ((...args: any[]) => any);
} }
export interface IHook { export interface IHook {
@ -97,8 +94,8 @@ export interface API {
(hook: IHook): void; (hook: IHook): void;
}; };
registerMethod: { registerMethod: {
(method: Function): void; (method: (...args: any[]) => any): void;
} };
applyHook: { applyHook: {
(opts: applyHookConfig): void; (opts: applyHookConfig): void;
}; };
@ -136,22 +133,22 @@ export interface MockConfig {
export interface DevBuildConfig { export interface DevBuildConfig {
name: string; name: string;
path: string; path: string;
args?: object; args?: Record<string, unknown>;
env?: object; env?: Record<string, unknown>;
devProxy?: DevProxy; devProxy?: DevProxy;
} }
export interface DevProxy { export interface DevProxy {
target: string; target: string;
matcher: ((pathname: string, req: Request) => boolean); matcher: (pathname: string, req: Request) => boolean;
onProxyRes: (proxyRes: http.IncomingMessage, req: Request, res: Response) => void; onProxyRes: (proxyRes: http.IncomingMessage, req: Request, res: Response) => void;
} }
export interface BuildConfig { export interface BuildConfig {
name: string; name: string;
path: string; path: string;
args?: object; args?: Record<string, unknown>;
env?: object; env?: Record<string, unknown>;
} }
export type ExportUserConfig = UserConfig | Promise<UserConfig>; export type ExportUserConfig = UserConfig | Promise<UserConfig>;

View File

@ -52,7 +52,7 @@ const buildConfig = async (fileName: string, format: 'esm' | 'cjs' = 'esm'): Pro
return { return {
loader: args.path.endsWith('.ts') ? 'ts' : 'js', loader: args.path.endsWith('.ts') ? 'ts' : 'js',
contents: contents contents: contents,
}; };
}); });
}, },

View File

@ -27,7 +27,6 @@ export async function loadModule<T>(filePath: string): Promise<T | undefined> {
const isTsFile: boolean = filePath.endsWith('ts'); const isTsFile: boolean = filePath.endsWith('ts');
const isJsFile: boolean = filePath.endsWith('js'); const isJsFile: boolean = filePath.endsWith('js');
let content: T | undefined; let content: T | undefined;
// js文件可以直接通过import引用 // js文件可以直接通过import引用

View File

@ -15,8 +15,8 @@
export enum LogLevel { export enum LogLevel {
DEBUG = 0, DEBUG = 0,
INFO = 1, INFO = 1,
WARN = 2, WARN = 2,
ERROR = 3, ERROR = 3,
} }

View File

@ -15,7 +15,7 @@
import chokidar from 'chokidar'; import chokidar from 'chokidar';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';
import {globSync} from 'glob'; import { globSync } from 'glob';
import { join } from 'path'; import { join } from 'path';
import { createRequire } from 'module'; import { createRequire } from 'module';
@ -38,13 +38,15 @@ function getMocksFile() {
const mockFiles = globSync('**/*.js', { const mockFiles = globSync('**/*.js', {
cwd: mockDir, cwd: mockDir,
}); });
let ret = mockFiles.reduce((mocks: any, mockFile: string) => { const ret = mockFiles.reduce((mocks: any, mockFile: string) => {
if (!mockFile.startsWith('_')) { if (!mockFile.startsWith('_')) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const file = require(join(mockDir, mockFile));
mocks = { mocks = {
...mocks, ...mocks,
...require(join(mockDir, mockFile)), ...file,
}; };
console.log('mockFile', require(join(mockDir, mockFile))); console.log('mockFile', file);
} }
return mocks; return mocks;
@ -54,8 +56,8 @@ function getMocksFile() {
} }
function generateRoutes(app: any) { function generateRoutes(app: any) {
let mockStartIndex = app._router.stack.length, const mockStartIndex = app._router.stack.length;
mocks: Mock = {}; let mocks: Mock = {};
try { try {
mocks = getMocksFile(); mocks = getMocksFile();
@ -93,8 +95,8 @@ function generateRoutes(app: any) {
respond instanceof Function respond instanceof Function
? respond ? respond
: (_req: any, res: { send: (arg0: any) => void }) => { : (_req: any, res: { send: (arg0: any) => void }) => {
res.send(respond); res.send(respond);
} }
); );
} catch (error) { } catch (error) {
console.error(error); console.error(error);

View File

@ -17,12 +17,14 @@ import { createProxyMiddleware } from 'http-proxy-middleware';
import { API } from '../types/types'; import { API } from '../types/types';
export default (app: any, api: API) => { export default (app: any, api: API) => {
const { devProxy } = api.userConfig.devBuildConfig; const { devProxy } = api.userConfig.devBuildConfig;
app.use(createProxyMiddleware(devProxy.matcher, { app.use(
target: devProxy.target, createProxyMiddleware(devProxy.matcher, {
secure: false, target: devProxy.target,
changeOrigin: true, secure: false,
ws: false, changeOrigin: true,
onProxyRes: devProxy.onProxyRes ws: false,
})); onProxyRes: devProxy.onProxyRes,
} })
);
};

View File

@ -16,8 +16,7 @@
import { dirname } from 'path'; import { dirname } from 'path';
import { readFileSync, writeFileSync } from 'fs'; import { readFileSync, writeFileSync } from 'fs';
import resolve from 'resolve'; import resolve from 'resolve';
// @ts-ignore import crequire from 'crequire';
import crequire from 'crequire'
import { createRequire } from 'module'; import { createRequire } from 'module';
const require = createRequire(import.meta.url); const require = createRequire(import.meta.url);

View File

@ -11,9 +11,16 @@
"moduleResolution": "node", "moduleResolution": "node",
"esModuleInterop": true, "esModuleInterop": true,
}, },
"include": ["src/**/*"], "include": [
"exclude": ["node_modules", "**/*.spec.ts", "./src/template/**/*"], "src/**/*",
"./externals.d.ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"./src/template/**/*"
],
"ts-node": { "ts-node": {
"esm": true, "esm": true,
}, },
} }

View File

@ -17,9 +17,7 @@ module.exports = api => {
const isTest = api.env('test'); const isTest = api.env('test');
console.log('isTest', isTest); console.log('isTest', isTest);
const plugins = [ const plugins = [['@babel/plugin-proposal-class-properties', { loose: false }]];
['@babel/plugin-proposal-class-properties', { loose: false }],
];
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
plugins.push(['@babel/plugin-transform-react-jsx-source']); plugins.push(['@babel/plugin-transform-react-jsx-source']);
@ -30,11 +28,13 @@ module.exports = api => {
'@babel/preset-env', '@babel/preset-env',
'@babel/preset-typescript', '@babel/preset-typescript',
[ [
'@babel/preset-react', { '@babel/preset-react',
runtime: 'classic', {
'pragma': 'Inula.createElement', runtime: 'classic',
'pragmaFrag': 'Inula.Fragment', pragma: 'Inula.createElement',
}] pragmaFrag: 'Inula.Fragment',
},
],
], ],
plugins, plugins,
}; };

View File

@ -14,6 +14,6 @@
*/ */
declare module '*.less' { declare module '*.less' {
const resource: {[key: string]: string}; const resource: { [key: string]: string };
export = resource; export = resource;
} }

View File

@ -45,7 +45,7 @@
"webpack-dev-server": "^4.7.4" "webpack-dev-server": "^4.7.4"
}, },
"dependencies": { "dependencies": {
"openinula": "^0.0.1", "openinula": "^0.1.1",
"flatted-object": "^0.1.2", "flatted-object": "^0.1.2",
"json-decycle": "^2.0.1", "json-decycle": "^2.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",

View File

@ -13,9 +13,9 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import { checkMessage, packagePayload, changeSource } from "../utils/transferUtils"; import { checkMessage, packagePayload, changeSource } from '../utils/transferUtils';
import { RequestAllVNodeTreeInfos, InitDevToolPageConnection, DevToolBackground } from "../utils/constants"; import { RequestAllVNodeTreeInfos, InitDevToolPageConnection, DevToolBackground } from '../utils/constants';
import { DevToolPanel, DevToolContentScript } from "../utils/constants"; import { DevToolPanel, DevToolContentScript } from '../utils/constants';
// 多个页面 tab 页共享一个 background需要建立连接池给每个 tab 建立连接 // 多个页面 tab 页共享一个 background需要建立连接池给每个 tab 建立连接
export const connections = {}; export const connections = {};

View File

@ -47,7 +47,7 @@ function requestObservedComponents(tabId) {
packagePayload( packagePayload(
{ {
type: 'inulax request observed components', type: 'inulax request observed components',
data: {} data: {},
}, },
'dev tool background' 'dev tool background'
) )
@ -65,7 +65,7 @@ function executeAction(tabId, storeId, action, params) {
action, action,
storeId, storeId,
params, params,
} },
}, },
'dev tool background' 'dev tool background'
) )
@ -82,7 +82,7 @@ function queueAction(tabId, storeId, action, params) {
action, action,
storeId, storeId,
params, params,
} },
}, },
'sev tool background' 'sev tool background'
) )
@ -167,12 +167,13 @@ chrome.runtime.onMessage.addListener(function (message, sender) {
type: 'INULA_DEV_TOOLS', type: 'INULA_DEV_TOOLS',
payload: { payload: {
type: 'inulax stores', type: 'inulax stores',
stores: storesPerTab[tabId]?.map(store => { stores:
// 连接被监测的组件 storesPerTab[tabId]?.map(store => {
requestObservedComponents(tabId); // 连接被监测的组件
const observedComponents = getObservedComponents(store, tabId); requestObservedComponents(tabId);
return { ...store, observedComponents }; const observedComponents = getObservedComponents(store, tabId);
}) || [], return { ...store, observedComponents };
}) || [],
newStore: message.payload.data.store.id, newStore: message.payload.data.store.id,
}, },
from: DevToolBackground, from: DevToolBackground,
@ -184,11 +185,12 @@ chrome.runtime.onMessage.addListener(function (message, sender) {
type: 'INULA_DEV_TOOLS', type: 'INULA_DEV_TOOLS',
payload: { payload: {
type: 'inulax stores', type: 'inulax stores',
stores: storesPerTab[sender.tab.id]?.map(store => { stores:
// 连接被监测的组件 storesPerTab[sender.tab.id]?.map(store => {
const observedComponents = getObservedComponents(store, sender.tab?.id); // 连接被监测的组件
return { ...store, observedComponents }; const observedComponents = getObservedComponents(store, sender.tab?.id);
}) || [], return { ...store, observedComponents };
}) || [],
updated: message.payload.data.store.id, updated: message.payload.data.store.id,
}, },
from: DevToolBackground, from: DevToolBackground,
@ -200,30 +202,17 @@ chrome.runtime.onMessage.addListener(function (message, sender) {
if (message.from === DevToolPanel) { if (message.from === DevToolPanel) {
// panel -> inulaXHandler // panel -> inulaXHandler
if (message.payload.type === 'inulax run action') { if (message.payload.type === 'inulax run action') {
executeAction( executeAction(message.payload.tabId, message.payload.storeId, message.payload.action, message.payload.args);
message.payload.tabId,
message.payload.storeId,
message.payload.action,
message.payload.args
);
return; return;
} }
if (message.payload.type === 'inulax change state') { if (message.payload.type === 'inulax change state') {
chrome.tabs.sendMessage( chrome.tabs.sendMessage(message.payload.tabId, packagePayload(message.payload, 'dev tool background'));
message.payload.tabId,
packagePayload(message.payload, 'dev tool background')
);
return; return;
} }
if (message.payload.type === 'inulax queue action') { if (message.payload.type === 'inulax queue action') {
queueAction( queueAction(message.payload.tabId, message.payload.storeId, message.payload.action, message.payload.args);
message.payload.tabId,
message.payload.storeId,
message.payload.action,
message.payload.args
);
return; return;
} }
@ -240,7 +229,7 @@ chrome.runtime.onMessage.addListener(function (message, sender) {
return; return;
} }
if (message.payload.type === 'inula setPersistent'){ if (message.payload.type === 'inula setPersistent') {
const { tabId, persistent } = message.payload; const { tabId, persistent } = message.payload;
eventPersistencePerTab[tabId] = persistent; eventPersistencePerTab[tabId] = persistent;
return; return;
@ -278,14 +267,12 @@ chrome.runtime.onMessage.addListener(function (message, sender) {
type: 'INULA_DEV_TOOLS', type: 'INULA_DEV_TOOLS',
payload: { payload: {
type: 'inulax stores', type: 'inulax stores',
stores: storesPerTab[message.payload.tabId]?.map(store => { stores:
requestObservedComponents(message.payload.tabId); storesPerTab[message.payload.tabId]?.map(store => {
const observedComponents = getObservedComponents( requestObservedComponents(message.payload.tabId);
store.id, const observedComponents = getObservedComponents(store.id, message.payload.tabId);
message.payload.tabId return { ...store, observedComponents };
); }) || [],
return { ...store, observedComponents };
}) || [],
}, },
from: DevToolBackground, from: DevToolBackground,
}); });

View File

@ -47,7 +47,7 @@ const ComponentAttr = memo(function ComponentAttr({
attrs, attrs,
id, id,
dropdownRef, dropdownRef,
}: { }: {
attrsName: string; attrsName: string;
attrsType: string; attrsType: string;
attrs: IAttr[]; attrs: IAttr[];
@ -421,7 +421,12 @@ function ComponentInfo({ name, attrs, parents, id, source, onClickParent }: ICom
<b>Copy value to console</b> <b>Copy value to console</b>
</li> </li>
<li <li
onClick={() => storeVariable((dropdownRef.current as any).attrInfo.attrsName, (dropdownRef.current as any).attrInfo.path)} onClick={() =>
storeVariable(
(dropdownRef.current as any).attrInfo.attrsName,
(dropdownRef.current as any).attrInfo.path
)
}
> >
<b>Store as global variable</b> <b>Store as global variable</b>
</li> </li>

View File

@ -38,7 +38,7 @@ export default function Search(props: SearchProps) {
onchange={handleChange} onchange={handleChange}
className={styles.search} className={styles.search}
value={value} value={value}
placeholder='Search Component' placeholder="Search Component"
/> />
); );
} }

View File

@ -20,7 +20,7 @@ export function SizeObserver(props) {
const { children, ...rest } = props; const { children, ...rest } = props;
const containerRef = useRef<HTMLDivElement>(); const containerRef = useRef<HTMLDivElement>();
const [size, setSize] = useState<{ width: number; height: number }>(); const [size, setSize] = useState<{ width: number; height: number }>();
const notifyChild = (element) => { const notifyChild = element => {
setSize({ setSize({
width: element.offsetWidth, width: element.offsetWidth,
height: element.offsetHeight, height: element.offsetHeight,

View File

@ -18,7 +18,6 @@
* *
*/ */
export default class ItemMap<T> { export default class ItemMap<T> {
// 不要用 indexOf 进行位置计算,它会遍历数组 // 不要用 indexOf 进行位置计算,它会遍历数组
private lastRenderItemToIndexMap: Map<T | undefined, number>; private lastRenderItemToIndexMap: Map<T | undefined, number>;
@ -26,7 +25,7 @@ export default class ItemMap<T> {
this.lastRenderItemToIndexMap = new Map(); this.lastRenderItemToIndexMap = new Map();
} }
public calculateReSortedItems(nextItems: T[]): (T|undefined)[] { public calculateReSortedItems(nextItems: T[]): (T | undefined)[] {
if (this.lastRenderItemToIndexMap.size === 0) { if (this.lastRenderItemToIndexMap.size === 0) {
nextItems.forEach((item, index) => { nextItems.forEach((item, index) => {
this.lastRenderItemToIndexMap.set(item, index); this.lastRenderItemToIndexMap.set(item, index);

View File

@ -36,13 +36,13 @@ interface IProps<T extends { id: number | string }> {
export type RenderInfoType<T> = { export type RenderInfoType<T> = {
visibleItems: T[]; visibleItems: T[];
} };
function parseTranslate<T>(data: T[], itemHeight: number) { function parseTranslate<T>(data: T[], itemHeight: number) {
const map = new Map<T, number>(); const map = new Map<T, number>();
data.forEach((item, index) => { data.forEach((item, index) => {
map.set(item, index * itemHeight); map.set(item, index * itemHeight);
}) });
return map; return map;
} }
@ -121,7 +121,7 @@ export function VList<T extends { id: number | string }>(props: IProps<T>) {
className={styles.item} className={styles.item}
style={{ transform: `translateY(${itemToTranslateYMap.get(item)}px)` }} style={{ transform: `translateY(${itemToTranslateYMap.get(item)}px)` }}
> >
{children(item,indentationLength)} {children(item, indentationLength)}
</div> </div>
); );
}); });

View File

@ -152,7 +152,7 @@ function Item(props: IItem) {
return ( return (
<div {...itemAttr}> <div {...itemAttr}>
<div <div
style={{marginLeft: indentation * indentationLength}} style={{ marginLeft: indentation * indentationLength }}
className={styles.treeIcon} className={styles.treeIcon}
onclick={handleClickCollapse} onclick={handleClickCollapse}
> >
@ -182,15 +182,7 @@ function VTree(props: {
selectItem: IData; selectItem: IData;
onSelectItem: (item: IData) => void; onSelectItem: (item: IData) => void;
}) { }) {
const { const { data, maxDeep, highlightValue, scrollToItem, onRendered, onCollapseNode, onSelectItem } = props;
data,
maxDeep,
highlightValue,
scrollToItem,
onRendered,
onCollapseNode,
onSelectItem
} = props;
const [collapseNode, setCollapseNode] = useState(props.collapsedNodes || []); const [collapseNode, setCollapseNode] = useState(props.collapsedNodes || []);
const [selectItem, setSelectItem] = useState(props.selectItem); const [selectItem, setSelectItem] = useState(props.selectItem);
const [childItems, setChildItems] = useState<Array<IData>>([]); const [childItems, setChildItems] = useState<Array<IData>>([]);
@ -251,12 +243,9 @@ function VTree(props: {
[onSelectItem] [onSelectItem]
); );
const handleMouseEnterItem = useCallback( const handleMouseEnterItem = useCallback(item => {
item => { postMessageToBackground(Highlight, item);
postMessageToBackground(Highlight, item); }, null);
},
null
);
const handleMouseLeaveItem = () => { const handleMouseLeaveItem = () => {
postMessageToBackground(RemoveHighlight); postMessageToBackground(RemoveHighlight);

View File

@ -20,7 +20,7 @@ const overlayStyles = {
background: 'rgba(120, 170, 210, 0.7)', background: 'rgba(120, 170, 210, 0.7)',
padding: 'rgba(77, 200, 0, 0.3)', padding: 'rgba(77, 200, 0, 0.3)',
margin: 'rgba(255, 155, 0, 0.3)', margin: 'rgba(255, 155, 0, 0.3)',
border: 'rgba(255, 200, 50, 0.3)' border: 'rgba(255, 200, 50, 0.3)',
}; };
type Rect = { type Rect = {
@ -58,7 +58,7 @@ function getOwnerIframe(node: Element): Element | null {
function getElementStyle(domElement: Element) { function getElementStyle(domElement: Element) {
const style = window.getComputedStyle(domElement); const style = window.getComputedStyle(domElement);
return{ return {
marginLeft: parseInt(style.marginLeft, 10), marginLeft: parseInt(style.marginLeft, 10),
marginRight: parseInt(style.marginRight, 10), marginRight: parseInt(style.marginRight, 10),
marginTop: parseInt(style.marginTop, 10), marginTop: parseInt(style.marginTop, 10),
@ -70,7 +70,7 @@ function getElementStyle(domElement: Element) {
paddingLeft: parseInt(style.paddingLeft, 10), paddingLeft: parseInt(style.paddingLeft, 10),
paddingRight: parseInt(style.paddingRight, 10), paddingRight: parseInt(style.paddingRight, 10),
paddingTop: parseInt(style.paddingTop, 10), paddingTop: parseInt(style.paddingTop, 10),
paddingBottom: parseInt(style.paddingBottom, 10) paddingBottom: parseInt(style.paddingBottom, 10),
}; };
} }
@ -86,7 +86,7 @@ function mergeRectOffsets(rects: Array<Rect>): Rect {
width: previousRect.width + rect.width, width: previousRect.width + rect.width,
height: previousRect.height + rect.height, height: previousRect.height + rect.height,
bottom: previousRect.bottom + rect.bottom, bottom: previousRect.bottom + rect.bottom,
right: previousRect.right + rect.right right: previousRect.right + rect.right,
}; };
}); });
} }
@ -99,18 +99,15 @@ function getBoundingClientRectWithBorderOffset(node: Element) {
top: dimensions.borderTop, top: dimensions.borderTop,
left: dimensions.borderLeft, left: dimensions.borderLeft,
bottom: dimensions.borderBottom, bottom: dimensions.borderBottom,
right:dimensions.borderRight, right: dimensions.borderRight,
// 高度和宽度不会被使用 // 高度和宽度不会被使用
width: 0, width: 0,
height: 0 height: 0,
} },
]); ]);
} }
function getNestedBoundingClientRect( function getNestedBoundingClientRect(node: HTMLElement, boundaryWindow): Rect {
node: HTMLElement,
boundaryWindow
): Rect {
const ownerIframe = getOwnerIframe(node); const ownerIframe = getOwnerIframe(node);
if (ownerIframe && ownerIframe !== boundaryWindow) { if (ownerIframe && ownerIframe !== boundaryWindow) {
const rects = [node.getBoundingClientRect()] as Rect[]; const rects = [node.getBoundingClientRect()] as Rect[];
@ -125,7 +122,7 @@ function getNestedBoundingClientRect(
break; break;
} }
if (currentIframe &&getOwnerWindow(currentIframe) === boundaryWindow) { if (currentIframe && getOwnerWindow(currentIframe) === boundaryWindow) {
onlyOneMore = true; onlyOneMore = true;
} }
} }
@ -156,7 +153,7 @@ class OverlayRect {
assign(this.node.style, { assign(this.node.style, {
borderColor: overlayStyles.margin, borderColor: overlayStyles.margin,
pointerEvents: 'none', pointerEvents: 'none',
position: 'fixed' position: 'fixed',
}); });
this.node.style.zIndex = '10000000'; this.node.style.zIndex = '10000000';
@ -179,13 +176,25 @@ class OverlayRect {
setBoxStyle(eleStyle, 'padding', this.padding); setBoxStyle(eleStyle, 'padding', this.padding);
assign(this.content.style, { assign(this.content.style, {
height: boxRect.height - eleStyle.borderTop - eleStyle.borderBottom - eleStyle.paddingTop - eleStyle.paddingBottom + 'px', height:
width: boxRect.width - eleStyle.borderLeft - eleStyle.borderRight - eleStyle.paddingLeft - eleStyle.paddingRight + 'px' boxRect.height -
eleStyle.borderTop -
eleStyle.borderBottom -
eleStyle.paddingTop -
eleStyle.paddingBottom +
'px',
width:
boxRect.width -
eleStyle.borderLeft -
eleStyle.borderRight -
eleStyle.paddingLeft -
eleStyle.paddingRight +
'px',
}); });
assign(this.node.style, { assign(this.node.style, {
top: boxRect.top - eleStyle.marginTop + 'px', top: boxRect.top - eleStyle.marginTop + 'px',
left: boxRect.left - eleStyle.marginLeft + 'px' left: boxRect.left - eleStyle.marginLeft + 'px',
}); });
} }
} }
@ -235,7 +244,7 @@ class ElementOverlay {
top: Number.POSITIVE_INFINITY, top: Number.POSITIVE_INFINITY,
right: Number.NEGATIVE_INFINITY, right: Number.NEGATIVE_INFINITY,
bottom: Number.NEGATIVE_INFINITY, bottom: Number.NEGATIVE_INFINITY,
left: Number.POSITIVE_INFINITY left: Number.POSITIVE_INFINITY,
}; };
elements.forEach((element, index) => { elements.forEach((element, index) => {

View File

@ -44,7 +44,7 @@ import {
ClassComponent, ClassComponent,
IncompleteClassComponent, IncompleteClassComponent,
ForwardRef, ForwardRef,
MemoComponent MemoComponent,
} from '../../../inula/src/renderer/vnode/VNodeTags'; } from '../../../inula/src/renderer/vnode/VNodeTags';
import { pickElement } from './pickElement'; import { pickElement } from './pickElement';
@ -101,11 +101,7 @@ function parseCompAttrs(id: number) {
function calculateNextValue(editValue, value, attrPath) { function calculateNextValue(editValue, value, attrPath) {
let nextState; let nextState;
const editValueType = typeof editValue; const editValueType = typeof editValue;
if ( if (editValueType === 'string' || editValueType === 'undefined' || editValueType === 'boolean') {
editValueType === 'string' ||
editValueType === 'undefined' ||
editValueType === 'boolean'
) {
nextState = value; nextState = value;
} else if (editValueType === 'number') { } else if (editValueType === 'number') {
const numValue = Number(value); const numValue = Number(value);
@ -125,10 +121,7 @@ function calculateNextValue(editValue, value, attrPath) {
nextState = newValue; nextState = newValue;
} }
} else { } else {
console.error( console.error('The dev tools tried to edit a non-editable value, this is a bug, please report.', editValue);
'The dev tools tried to edit a non-editable value, this is a bug, please report.',
editValue
);
} }
return nextState; return nextState;
} }
@ -153,10 +146,7 @@ function modifyVNodeAttrs(data) {
const nextState = calculateNextValue(editValue, value, path.slice(1)); const nextState = calculateNextValue(editValue, value, path.slice(1));
helper.updateHooks(vNode, path[0], nextState); helper.updateHooks(vNode, path[0], nextState);
} else { } else {
console.error( console.error('The dev tools tried to edit a non-editable hook, this is a bug, please report.', hooks);
'The dev tools tried to edit a non-editable hook, this is a bug, please report.',
hooks
);
} }
} else if (type === ModifyState) { } else if (type === ModifyState) {
const oldState = vNode.state || {}; const oldState = vNode.state || {};
@ -190,11 +180,7 @@ function logComponentData(id: number) {
* @param {Array<string | number>} path * @param {Array<string | number>} path
* @param {string} attrsName props hooks * @param {string} attrsName props hooks
*/ */
const getValueByPath = ( const getValueByPath = (vNode: VNode, path: Array<string | number>, attrsName: string) => {
vNode: VNode,
path: Array<string | number>,
attrsName: string
) => {
if (attrsName === 'Props') { if (attrsName === 'Props') {
return path.reduce((previousValue, currentValue) => { return path.reduce((previousValue, currentValue) => {
return previousValue[currentValue]; return previousValue[currentValue];
@ -218,12 +204,7 @@ const getValueByPath = (
* @param {Array<string | number>} path * @param {Array<string | number>} path
* @param {string} attrsName * @param {string} attrsName
*/ */
function logDataWithPath( function logDataWithPath(id: number, itemName: string, path: Array<string | number>, attrsName: string) {
id: number,
itemName: string,
path: Array<string | number>,
attrsName: string
) {
const vNode = queryVNode(id); const vNode = queryVNode(id);
if (vNode === null) { if (vNode === null) {
console.warn(`Could not find vNode with id "${id}"`); console.warn(`Could not find vNode with id "${id}"`);
@ -246,11 +227,7 @@ function logDataWithPath(
* @param {Array<string |number>} path * @param {Array<string |number>} path
* @param {string} attrsName * @param {string} attrsName
*/ */
function storeDataWithPath( function storeDataWithPath(id: number, path: Array<string | number>, attrsName: string) {
id: number,
path: Array<string | number>,
attrsName: string
) {
const vNode = queryVNode(id); const vNode = queryVNode(id);
if (vNode === null) { if (vNode === null) {
console.warn(`Could not find vNode with id "${id}"`); console.warn(`Could not find vNode with id "${id}"`);
@ -284,9 +261,7 @@ export function getElement(travelVNodeTree, treeRoot: VNode) {
} }
} }
}, },
(node: VNode) => (node: VNode) => node.realNode != null && (Object.keys(node.realNode).length > 0 || node.realNode.size > 0)
node.realNode != null &&
(Object.keys(node.realNode).length > 0 || node.realNode.size > 0)
); );
return result; return result;
} }

View File

@ -56,46 +56,33 @@ const inspectVNode = () => {
let currentPanel = null; let currentPanel = null;
chrome.devtools.inspectedWindow.eval( chrome.devtools.inspectedWindow.eval('window.__INULA_DEV_HOOK__', function (isInula, error) {
'window.__INULA_DEV_HOOK__', if (!isInula || panelCreated) {
function (isInula, error) { return;
if (!isInula || panelCreated) {
return;
}
panelCreated = true;
chrome.devtools.panels.create(
'Inula',
'',
'panel.html',
(extensionPanel) => {
extensionPanel.onShown.addListener((panel) => {
if (currentPanel === panel) {
return;
}
currentPanel = panel;
const container = panel.document.getElementById('root');
const element = createElement(Panel, { viewSource, inspectVNode });
render(element, container);
});
}
);
chrome.devtools.panels.create(
'InulaX',
'',
'panelX.html',
(extensionPanel) => {
extensionPanel.onShown.addListener((panel) => {
if (currentPanel === panel) {
return;
}
currentPanel = panel;
const container = panel.document.getElementById('root');
const element = createElement(PanelX, {});
render(element, container);
});
}
);
} }
);
panelCreated = true;
chrome.devtools.panels.create('Inula', '', 'panel.html', extensionPanel => {
extensionPanel.onShown.addListener(panel => {
if (currentPanel === panel) {
return;
}
currentPanel = panel;
const container = panel.document.getElementById('root');
const element = createElement(Panel, { viewSource, inspectVNode });
render(element, container);
});
});
chrome.devtools.panels.create('InulaX', '', 'panelX.html', extensionPanel => {
extensionPanel.onShown.addListener(panel => {
if (currentPanel === panel) {
return;
}
currentPanel = panel;
const container = panel.document.getElementById('root');
const element = createElement(PanelX, {});
render(element, container);
});
});
});

View File

@ -13,15 +13,7 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import { import { useState, useEffect, useRef, memo, useMemo, useCallback, useReducer } from 'openinula';
useState,
useEffect,
useRef,
memo,
useMemo,
useCallback,
useReducer,
} from 'openinula';
import VTree, { IData } from '../components/VTree'; import VTree, { IData } from '../components/VTree';
import Search from '../components/Search'; import Search from '../components/Search';
import ComponentInfo from '../components/ComponentInfo'; import ComponentInfo from '../components/ComponentInfo';
@ -134,26 +126,20 @@ interface IIdToNodeMap {
* @param {null | HTMLElement} resizeElement * @param {null | HTMLElement} resizeElement
* @param {number} percentage * @param {number} percentage
*/ */
const setResizePCTForElement = ( const setResizePCTForElement = (resizeElement: null | HTMLElement, percentage: number): void => {
resizeElement: null | HTMLElement,
percentage: number
): void => {
if (resizeElement !== null) { if (resizeElement !== null) {
resizeElement.style.setProperty( resizeElement.style.setProperty('--horizontal-percentage', `${percentage}`);
'--horizontal-percentage',
`${percentage}`
);
} }
}; };
function resizeReducer(state: ResizeState, action: ResizeAction): ResizeState { function resizeReducer(state: ResizeState, action: ResizeAction): ResizeState {
switch (action.type) { switch (action.type) {
case "START_RESIZE": case 'START_RESIZE':
return { return {
...state, ...state,
isResizing: action.payload, isResizing: action.payload,
}; };
case "SET_HORIZONTAL_PERCENTAGE": case 'SET_HORIZONTAL_PERCENTAGE':
return { return {
...state, ...state,
horizontalPercentage: action.payload, horizontalPercentage: action.payload,
@ -183,11 +169,7 @@ function Panel({ viewSource, inspectVNode }) {
const [isPicking, setPicking] = useState(false); const [isPicking, setPicking] = useState(false);
const [source, setSource] = useState<Source>(null); const [source, setSource] = useState<Source>(null);
const idToTreeNodeMapref = useRef<IIdToNodeMap>({}); const idToTreeNodeMapref = useRef<IIdToNodeMap>({});
const [state, dispatch] = useReducer( const [state, dispatch] = useReducer(resizeReducer, null, initResizeState);
resizeReducer,
null,
initResizeState
);
const pageRef = useRef<null | HTMLElement>(null); const pageRef = useRef<null | HTMLElement>(null);
const treeRef = useRef<null | HTMLElement>(null); const treeRef = useRef<null | HTMLElement>(null);
@ -214,16 +196,12 @@ function Panel({ viewSource, inspectVNode }) {
// 对象数据只是记录了引用,内容可能在后续被修改,打印字符串可以获取当前真正内容,不被后续修改影响 // 对象数据只是记录了引用,内容可能在后续被修改,打印字符串可以获取当前真正内容,不被后续修改影响
logger.info(JSON.stringify(payload)); logger.info(JSON.stringify(payload));
if (payload) { if (payload) {
const {type, data} = payload; const { type, data } = payload;
if (type === AllVNodeTreeInfos) { if (type === AllVNodeTreeInfos) {
const idToTreeNodeMap = idToTreeNodeMapref.current; const idToTreeNodeMap = idToTreeNodeMapref.current;
const nextIdToTreeNodeMap: IIdToNodeMap = {}; const nextIdToTreeNodeMap: IIdToNodeMap = {};
const allTreeData = data.reduce((pre, current) => { const allTreeData = data.reduce((pre, current) => {
const parsedTreeData = parseVNodeData( const parsedTreeData = parseVNodeData(current, idToTreeNodeMap, nextIdToTreeNodeMap);
current,
idToTreeNodeMap,
nextIdToTreeNodeMap
);
return pre.concat(parsedTreeData); return pre.concat(parsedTreeData);
}, []); }, []);
idToTreeNodeMapref.current = nextIdToTreeNodeMap; idToTreeNodeMapref.current = nextIdToTreeNodeMap;
@ -284,10 +262,7 @@ function Panel({ viewSource, inspectVNode }) {
setShowItems(info.visibleItems); setShowItems(info.visibleItems);
}; };
const parents = useMemo( const parents = useMemo(() => getParents(selectComp, parsedVNodeData), [selectComp, parsedVNodeData]);
() => getParents(selectComp, parsedVNodeData),
[selectComp, parsedVNodeData]
);
const viewSourceFunction = useMemo( const viewSourceFunction = useMemo(
() => ({ () => ({
@ -338,7 +313,7 @@ function Panel({ viewSource, inspectVNode }) {
const mouseAbscissa = event.clientX - left; const mouseAbscissa = event.clientX - left;
const pageSizeMin = MINIMUM_SIZE; const pageSizeMin = MINIMUM_SIZE;
const pageSizeMax = width-MINIMUM_SIZE; const pageSizeMax = width - MINIMUM_SIZE;
const isMouseInPage = mouseAbscissa > pageSizeMin && mouseAbscissa < pageSizeMax; const isMouseInPage = mouseAbscissa > pageSizeMin && mouseAbscissa < pageSizeMax;
@ -394,16 +369,10 @@ function Panel({ viewSource, inspectVNode }) {
{`${matchItems.indexOf(currentItem) + 1}/${matchItems.length}`} {`${matchItems.indexOf(currentItem) + 1}/${matchItems.length}`}
</span> </span>
<div className={styles.divider} /> <div className={styles.divider} />
<button <button className={styles.searchAction} onClick={onSelectLast}>
className={styles.searchAction}
onClick={onSelectLast}
>
<Arrow direction={'up'} /> <Arrow direction={'up'} />
</button> </button>
<button <button className={styles.searchAction} onClick={onSelectNext}>
className={styles.searchAction}
onClick={onSelectNext}
>
<Arrow direction={'down'} /> <Arrow direction={'down'} />
</button> </button>
<button className={styles.searchAction} onClick={onClear}> <button className={styles.searchAction} onClick={onClear}>

View File

@ -51,11 +51,7 @@ export function initBackgroundConnection(type) {
} }
let reconnectionTimes = 0; let reconnectionTimes = 0;
export function postMessageToBackground( export function postMessageToBackground(type: string, data?: any, inulaX?: boolean) {
type: string,
data?: any,
inulaX?: boolean
) {
try { try {
const payload = data const payload = data
? { type, tabId: chrome.devtools.inspectedWindow.tabId, data } ? { type, tabId: chrome.devtools.inspectedWindow.tabId, data }

View File

@ -16,7 +16,7 @@
import { useState } from 'openinula'; import { useState } from 'openinula';
import styles from './PanelX.less'; import styles from './PanelX.less';
import { Tree } from './Tree'; import { Tree } from './Tree';
import {displayValue, omit} from './utils'; import { displayValue, omit } from './utils';
type Mutation = { type Mutation = {
mutation: boolean; mutation: boolean;
@ -118,11 +118,7 @@ export function DiffTree({
fontFamily: 'monospace', fontFamily: 'monospace',
}} }}
className={`${ className={`${
expanded expanded ? 'expanded' : `not-expanded ${mutated && !isPrimitive && !expanded ? styles.changed : ''}`
? 'expanded'
: `not-expanded ${
mutated && !isPrimitive && !expanded ? styles.changed : ''
}`
}`} }`}
onClick={e => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
@ -165,11 +161,7 @@ export function DiffTree({
// 如果至少有一个是复杂变量,则需要展开按钮 // 如果至少有一个是复杂变量,则需要展开按钮
<> <>
{forcedExpand ? '' : expanded ? <span></span> : <span></span>} {forcedExpand ? '' : expanded ? <span></span> : <span></span>}
{index === 0 || index ? ( {index === 0 || index ? <b className={styles.purple}>{displayValue(index, search)}: </b> : ''}
<b className={styles.purple}>{displayValue(index, search)}: </b>
) : (
''
)}
{isArray ? ( {isArray ? (
// 如果都是数组进行比较 // 如果都是数组进行比较
expanded ? ( expanded ? (
@ -210,17 +202,10 @@ export function DiffTree({
) : isSet ? ( ) : isSet ? (
expanded ? ( expanded ? (
<div> <div>
<div> <div>{forcedLabel || `Set(${mutation.to?.values.length})`}</div>
{forcedLabel || `Set(${mutation.to?.values.length})`} {Array(Math.max(mutation.from?.values.length, mutation.to?.values.length))
</div>
{Array(
Math.max(
mutation.from?.values.length,
mutation.to?.values.length
)
)
.fill(true) .fill(true)
.map((i ,index) => ( .map((i, index) => (
<div> <div>
{mutation.values[index].mutation ? ( {mutation.values[index].mutation ? (
<DiffTree <DiffTree
@ -244,22 +229,13 @@ export function DiffTree({
))} ))}
</div> </div>
) : ( ) : (
<span> <span>{forcedLabel || `Set(${mutation.to?.values.length})`}</span>
{forcedLabel || `Set(${mutation.to?.values.length})`}
</span>
) )
) : isMap ? ( ) : isMap ? (
expanded ? ( expanded ? (
<> <>
<span> <span>{forcedLabel || `Map(${mutation.to?.entries.length})`}</span>
{forcedLabel || `Map(${mutation.to?.entries.length})`} {Array(Math.max(mutation.from?.entries.length, mutation.to?.entries.length))
</span>
{Array(
Math.max(
mutation.from?.entries.length,
mutation.to?.entries.length
)
)
.fill(true) .fill(true)
.map((i, index) => .map((i, index) =>
mutation.entries[index].mutation ? ( mutation.entries[index].mutation ? (
@ -289,9 +265,7 @@ export function DiffTree({
)} )}
</> </>
) : ( ) : (
<span> <span>{forcedLabel || `Map(${mutation.to?.entries.length})`}</span>
{forcedLabel || `Map(${mutation.to?.entries.length})`}
</span>
) )
) : expanded ? ( ) : expanded ? (
// 如果都是 object 进行比较 // 如果都是 object 进行比较

View File

@ -22,7 +22,7 @@ import {
} from '../panelConnection'; } from '../panelConnection';
import { Table } from './Table'; import { Table } from './Table';
import { Tree } from './Tree'; import { Tree } from './Tree';
import {fullTextSearch, omit} from './utils'; import { fullTextSearch, omit } from './utils';
import styles from './PanelX.less'; import styles from './PanelX.less';
import { Checkbox } from '../utils/Checkbox'; import { Checkbox } from '../utils/Checkbox';
import { DiffTree } from './DiffTree'; import { DiffTree } from './DiffTree';
@ -57,9 +57,7 @@ function extractDataByType(message, search) {
> >
<Tree <Tree
data={{ data={{
Action: `${message.data.action.action}${ Action: `${message.data.action.action}${message.data.fromQueue ? ' (queued)' : ''}`,
message.data.fromQueue ? ' (queued)' : ''
}`
}} }}
expand={true} expand={true}
indent={-4} indent={-4}
@ -92,7 +90,7 @@ function extractDataByType(message, search) {
); );
} }
return <span className={styles.grey}>N/A</span> return <span className={styles.grey}>N/A</span>;
} }
export default function EventLog({ setNextStore, setEventFilter, eventFilter }) { export default function EventLog({ setNextStore, setEventFilter, eventFilter }) {
@ -204,26 +202,27 @@ export default function EventLog({ setNextStore, setEventFilter, eventFilter })
timestamp: event.timestamp, timestamp: event.timestamp,
type: event.message.type, type: event.message.type,
time: `${date.toLocaleTimeString()} - ${date.toLocaleDateString()}`, time: `${date.toLocaleTimeString()} - ${date.toLocaleDateString()}`,
state: event.message.type === eventTypes.STATE_CHANGE ? ( state:
<DiffTree event.message.type === eventTypes.STATE_CHANGE ? (
mutation={event.message.data.change.mutation} <DiffTree
expand={true} mutation={event.message.data.change.mutation}
forcedExpand={true} expand={true}
indent={0} forcedExpand={true}
search={eventFilter['fulltext']} indent={0}
omitAttrs={['_inulaObserver']} search={eventFilter['fulltext']}
doNotDisplayIcon={true} omitAttrs={['_inulaObserver']}
/> doNotDisplayIcon={true}
) : ( />
<Tree ) : (
data={event.message.data.store.$s} <Tree
expand={true} data={event.message.data.store.$s}
search={eventFilter['fulltext']} expand={true}
forcedExpand={true} search={eventFilter['fulltext']}
indent={-4} forcedExpand={true}
omitAttrs={['_inulaObserver']} indent={-4}
/> omitAttrs={['_inulaObserver']}
), />
),
storeClick: ( storeClick: (
<span <span
className={styles.link} className={styles.link}
@ -235,10 +234,7 @@ export default function EventLog({ setNextStore, setEventFilter, eventFilter })
{event.message.data.store.id} {event.message.data.store.id}
</span> </span>
), ),
additionalData: extractDataByType( additionalData: extractDataByType(event.message, eventFilter['fulltext']),
event.message,
eventFilter['fulltext']
),
storeId: event.message.data.store.id, storeId: event.message.data.store.id,
event, event,
}; };
@ -271,7 +267,7 @@ export default function EventLog({ setNextStore, setEventFilter, eventFilter })
<span className={styles.grey}>{' | '}</span> <span className={styles.grey}>{' | '}</span>
<span <span
style={{ style={{
cursor: 'pointer' cursor: 'pointer',
}} }}
onClick={e => { onClick={e => {
e.stopPropagation(); e.stopPropagation();
@ -342,18 +338,14 @@ export default function EventLog({ setNextStore, setEventFilter, eventFilter })
{Object.values(eventTypes).map(eventType => { {Object.values(eventTypes).map(eventType => {
return ( return (
<button <button
className={`${styles.filterButton} ${ className={`${styles.filterButton} ${usedTypes[eventType] ? '' : styles.grey} ${
usedTypes[eventType] ? '' : styles.grey
} ${
eventFilter['message.type'] === eventType ? styles.active : '' eventFilter['message.type'] === eventType ? styles.active : ''
}`} }`}
onClick={() => { onClick={() => {
addFilter('message.type', eventType); addFilter('message.type', eventType);
}} }}
> >
{`${eventType.replace('inulax ', '')}(${ {`${eventType.replace('inulax ', '')}(${usedTypes[eventType] || 0})`}
usedTypes[eventType] || 0
})`}
</button> </button>
); );
})} })}
@ -374,20 +366,12 @@ export default function EventLog({ setNextStore, setEventFilter, eventFilter })
type: data.type, type: data.type,
store: { store: {
actions: Object.fromEntries( actions: Object.fromEntries(
Object.entries(message.data.store.$config.actions).map( Object.entries(message.data.store.$config.actions).map(([id, action]) => {
([id, action]) => { return [id, (action as string).replace(/\{.*}/gms, '{...}').replace('function ', '')];
return [ })
id,
(action as string).replace(/\{.*}/gms, '{...}').replace('function ', ''),
];
}
)
), ),
computed: Object.fromEntries( computed: Object.fromEntries(
Object.keys(message.data.store.$c).map(key => [ Object.keys(message.data.store.$c).map(key => [key, message.data.store.expanded[key]])
key,
message.data.store.expanded[key],
])
), ),
state: message.data.store.$s, state: message.data.store.$s,
id: message.data.store.id, id: message.data.store.id,

View File

@ -73,7 +73,7 @@ export function Modal({
<input <input
ref={inputRef} ref={inputRef}
type={'text'} type={'text'}
onKeyPress={({key}) => { onKeyPress={({ key }) => {
if (key === 'Enter') { if (key === 'Enter') {
tryGatherData(); tryGatherData();
} }

View File

@ -32,12 +32,7 @@ export default function PanelX() {
{ {
id: 'stores', id: 'stores',
title: 'Stores', title: 'Stores',
getComponent: () => ( getComponent: () => <Stores nextStoreId={nextStoreId} showFilteredEvents={showFilterEvents} />,
<Stores
nextStoreId={nextStoreId}
showFilteredEvents={showFilterEvents}
/>
),
}, },
{ {
id: 'events', id: 'events',
@ -60,10 +55,7 @@ export default function PanelX() {
<div style={{ marginBottom: '10px' }}> <div style={{ marginBottom: '10px' }}>
{tabs.map(tab => {tabs.map(tab =>
tab.id === active ? ( tab.id === active ? (
<button <button className={`${styles.tab} ${styles.active}`} disabled={true}>
className={`${styles.tab} ${styles.active}`}
disabled={true}
>
{tab.title} {tab.title}
</button> </button>
) : ( ) : (

View File

@ -14,7 +14,7 @@
*/ */
import { useState } from 'openinula'; import { useState } from 'openinula';
import {Tree} from './Tree'; import { Tree } from './Tree';
import styles from './PanelX.less'; import styles from './PanelX.less';
type displayKeysType = [string, string][]; type displayKeysType = [string, string][];
@ -84,14 +84,10 @@ export function Table({
<span></span> <span></span>
{data.map(row => ( {data.map(row => (
<div <div
className={`${styles.row} ${ className={`${styles.row} ${keyToDisplay === row[dataKey] ? styles.active : ''}`}
keyToDisplay === row[dataKey] ? styles.active : ''
}`}
onClick={() => { onClick={() => {
setManualOverride(true); setManualOverride(true);
setKeyToDisplay( setKeyToDisplay(keyToDisplay === row[dataKey] ? null : row[dataKey]);
keyToDisplay === row[dataKey] ? null : row[dataKey]
);
}} }}
> >
<div className={styles.cell}>{row?.[attr] || ''}</div> <div className={styles.cell}>{row?.[attr] || ''}</div>
@ -119,11 +115,7 @@ export function Table({
<div className={styles.row}> <div className={styles.row}>
<div className={styles.cell}> <div className={styles.cell}>
<Tree <Tree
data={ data={displayDataProcessor ? displayDataProcessor(displayRow) : displayRow}
displayDataProcessor
? displayDataProcessor(displayRow)
: displayRow
}
indent={displayRow[displayKeys[0][0]]} indent={displayRow[displayKeys[0][0]]}
expand={true} expand={true}
search={search} search={search}
@ -142,7 +134,7 @@ export function Table({
<div className={`${styles.row} ${styles.header}`}> <div className={`${styles.row} ${styles.header}`}>
{displayKeys.map(([key, title]) => ( {displayKeys.map(([key, title]) => (
<div className={styles.cell}>{title}</div> <div className={styles.cell}>{title}</div>
))} ))}
</div> </div>
{data.map(item => ( {data.map(item => (
<div <div

View File

@ -15,7 +15,7 @@
import { useState } from 'openinula'; import { useState } from 'openinula';
import styles from './PanelX.less'; import styles from './PanelX.less';
import {Modal} from './Modal'; import { Modal } from './Modal';
import { displayValue, omit } from './utils'; import { displayValue, omit } from './utils';
export function Tree({ export function Tree({
@ -36,7 +36,7 @@ export function Tree({
expand?: boolean; expand?: boolean;
search?: string; search?: string;
forcedExpand?: boolean; forcedExpand?: boolean;
className?: string | undefined className?: string | undefined;
omitAttrs?: string[]; omitAttrs?: string[];
onEdit?: (path: any[], value: any) => void | null; onEdit?: (path: any[], value: any) => void | null;
forcedLabel?: string | number | null; forcedLabel?: string | number | null;
@ -71,11 +71,7 @@ export function Tree({
}} }}
> >
{new Array(Math.max(indent, 0)).fill(<span>&nbsp;</span>)} {new Array(Math.max(indent, 0)).fill(<span>&nbsp;</span>)}
{forcedExpand || isVNode ? null : expanded ? ( {forcedExpand || isVNode ? null : expanded ? <span></span> : <span></span>}
<span></span>
) : (
<span></span>
)}
{index === 0 || index ? ( {index === 0 || index ? (
<> <>
<b className={styles.purple}>{displayValue(index, search)}: </b> <b className={styles.purple}>{displayValue(index, search)}: </b>
@ -84,28 +80,28 @@ export function Tree({
'' ''
)} )}
{forcedLabel {forcedLabel
? forcedLabel ? forcedLabel
: expanded : expanded
? isVNode ? isVNode
? null ? null
: Array.isArray(data) : Array.isArray(data)
? `Array(${data.length})` ? `Array(${data.length})`
: isMap : isMap
? `Map(${data.entries.length})` ? `Map(${data.entries.length})`
: isSet : isSet
? `Set(${data.values.length})` ? `Set(${data.values.length})`
: '{ ... }' : '{ ... }'
: isWeakMap : isWeakMap
? 'WeakMap()' ? 'WeakMap()'
: isWeakSet : isWeakSet
? 'WeakSet()' ? 'WeakSet()'
: isMap : isMap
? `Map(${data.entries.length})` ? `Map(${data.entries.length})`
: isSet : isSet
? `Set(${data.values.length})` ? `Set(${data.values.length})`
: Array.isArray(data) : Array.isArray(data)
? `Array(${data.length})` ? `Array(${data.length})`
: '{ ... }'} : '{ ... }'}
</span> </span>
{expanded || isVNode ? ( {expanded || isVNode ? (
isArray ? ( isArray ? (
@ -122,8 +118,8 @@ export function Tree({
onEdit={ onEdit={
onEdit onEdit
? (path, val) => { ? (path, val) => {
onEdit(path.concat([index]), val); onEdit(path.concat([index]), val);
} }
: null : null
} }
/> />
@ -138,7 +134,7 @@ export function Tree({
{data.entries.map(([key, value]) => { {data.entries.map(([key, value]) => {
return ( return (
<Tree <Tree
data={{key, value}} data={{ key, value }}
indent={indent + 4} indent={indent + 4}
search={search} search={search}
className={className} className={className}
@ -174,8 +170,8 @@ export function Tree({
onEdit={ onEdit={
onEdit onEdit
? (path, val) => { ? (path, val) => {
onEdit(path.concat([key]), val); onEdit(path.concat([key]), val);
} }
: null : null
} }
/> />

View File

@ -25,7 +25,7 @@ export function highlight(source, search) {
const parts = source.split(search); const parts = source.split(search);
const result = []; const result = [];
for (let i= 0; i < parts.length * 2 - 1; i++) { for (let i = 0; i < parts.length * 2 - 1; i++) {
if (i % 2) { if (i % 2) {
result.push(<span className={styles.highlighted}>{search}</span>); result.push(<span className={styles.highlighted}>{search}</span>);
} else { } else {
@ -38,11 +38,7 @@ export function highlight(source, search) {
export function displayValue(val: any, search = '') { export function displayValue(val: any, search = '') {
if (typeof val === 'boolean') { if (typeof val === 'boolean') {
return ( return <span>{highlight(val ? 'true' : 'false', search)}</span>;
<span>
{highlight(val ? 'true' : 'false', search)}
</span>
);
} }
if (val === '') { if (val === '') {
@ -62,10 +58,7 @@ export function displayValue(val: any, search = '') {
return ( return (
<span> <span>
<i>ƒ</i> <i>ƒ</i>
{highlight( {highlight(val.match(/^function\s?\([\w,]*\)/g)[0].replace(/^function\s?/, ''), search)}
val.match(/^function\s?\([\w,]*\)/g)[0].replace(/^function\s?/, ''),
search
)}
</span> </span>
); );
} }
@ -75,7 +68,10 @@ export function displayValue(val: any, search = '') {
return <span className={styles.blue}>{highlight('' + val, search)}</span>; return <span className={styles.blue}>{highlight('' + val, search)}</span>;
} }
if (typeof val === 'function') { if (typeof val === 'function') {
const args = val.toString().match(/^function\s?\([\w,]*\)/g)[0].replace(/^function\s?/, ''); const args = val
.toString()
.match(/^function\s?\([\w,]*\)/g)[0]
.replace(/^function\s?/, '');
return ( return (
<span> <span>
<i>ƒ</i> <i>ƒ</i>
@ -108,9 +104,7 @@ export function fullTextSearch(value, search) {
return value.values.some(val => fullTextSearch(val, search)); return value.values.some(val => fullTextSearch(val, search));
} }
if (value?._type === 'Map') { if (value?._type === 'Map') {
return value.entries.some( return value.entries.some((key, val) => fullTextSearch(key, search) || fullTextSearch(val, search));
(key, val) => fullTextSearch(key, search) || fullTextSearch(val, search)
);
} }
return Object.values(value).some(val => fullTextSearch(val, search)); return Object.values(value).some(val => fullTextSearch(val, search));
} }
@ -165,8 +159,7 @@ export function stringify(data) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
return ( return (
<span> <span>
<span className={styles.purple}>{key}</span>:{' '} <span className={styles.purple}>{key}</span>: {`Array(${value.length})`}
{`Array(${value.length})`}
</span> </span>
); );
} }
@ -188,16 +181,14 @@ export function stringify(data) {
if ((value as any)?._type === 'Set') { if ((value as any)?._type === 'Set') {
return ( return (
<span> <span>
<span className={styles.purple}>{key}</span>:{' '} <span className={styles.purple}>{key}</span>: {`Set(${(value as Set<any>).size})`}
{`Set(${(value as Set<any>).size})`}
</span> </span>
); );
} }
if ((value as any)?._type === 'Map') { if ((value as any)?._type === 'Map') {
return ( return (
<span> <span>
<span className={styles.purple}>{key}</span>:{' '} <span className={styles.purple}>{key}</span>: {`Map(${(value as Map<any, any>).size})`}
{`Map(${(value as Map<any, any>).size})`}
</span> </span>
); );
} }

View File

@ -50,14 +50,14 @@ export type IAttr = {
hIndex?: number; // 用于记录 hook 的 hIndex 值 hIndex?: number; // 用于记录 hook 的 hIndex 值
} & ( } & (
| { | {
type: ShowAsStringType; type: ShowAsStringType;
value: string; value: string;
} }
| { | {
type: 'boolean'; type: 'boolean';
value: boolean; value: boolean;
} }
); );
type ShowType = ShowAsStringType | 'boolean'; type ShowType = ShowAsStringType | 'boolean';
@ -79,10 +79,7 @@ const getObjectKeys = (attr: Record<string, any>): Array<string | number | symbo
let current = attr; let current = attr;
try { try {
while (current != null) { while (current != null) {
const currentKeys = [ const currentKeys = [...Object.keys(current), ...Object.getOwnPropertySymbols(current)];
...Object.keys(current),
...Object.getOwnPropertySymbols(current)
];
const descriptors = Object.getOwnPropertyDescriptors(current); const descriptors = Object.getOwnPropertyDescriptors(current);
currentKeys.forEach(key => { currentKeys.forEach(key => {
// @ts-ignore key 可以为 symbol 类型 // @ts-ignore key 可以为 symbol 类型
@ -99,10 +96,7 @@ const getObjectKeys = (attr: Record<string, any>): Array<string | number | symbo
}; };
// 用于比较两个 key 值的顺序 // 用于比较两个 key 值的顺序
export function sortKeys( export function sortKeys(firstKey: string | number | symbol, secondKey: string | number | symbol): number {
firstKey: string | number | symbol,
secondKey: string | number | symbol
): number {
if (firstKey.toString() > secondKey.toString()) { if (firstKey.toString() > secondKey.toString()) {
return 1; return 1;
} else if (secondKey.toString() > firstKey.toString()) { } else if (secondKey.toString() > firstKey.toString()) {
@ -137,11 +131,7 @@ const parseSubTitle = <T>(attr: T) => {
} else if (AttrType === 'function') { } else if (AttrType === 'function') {
const funcName = attr['name']; const funcName = attr['name'];
return `ƒ ${funcName}() {}`; return `ƒ ${funcName}() {}`;
} else if ( } else if (AttrType === 'boolean' || AttrType === 'number' || AttrType === 'undefined') {
AttrType === 'boolean' ||
AttrType === 'number' ||
AttrType === 'undefined'
) {
return `${attr}`; return `${attr}`;
} else if (AttrType === 'object') { } else if (AttrType === 'object') {
if (attr === null) { if (attr === null) {
@ -179,24 +169,13 @@ const parseSubTitle = <T>(attr: T) => {
} }
}; };
const parseSubAttr = ( const parseSubAttr = (attr: any, parentIndentation: number, attrName: string, result: IAttr[], hIndex?: number) => {
attr: any,
parentIndentation: number,
attrName: string,
result: IAttr[],
hIndex?: number
) => {
const AttrType = typeof attr; const AttrType = typeof attr;
let value: any; let value: any;
let showType: any; let showType: any;
let addSubState; let addSubState;
if ( if (AttrType === 'boolean' || AttrType === 'number' || AttrType === 'undefined' || AttrType === 'string') {
AttrType === 'boolean' ||
AttrType === 'number' ||
AttrType === 'undefined' ||
AttrType === 'string'
) {
value = attr; value = attr;
showType = AttrType; showType = AttrType;
} else if (AttrType === 'function') { } else if (AttrType === 'function') {
@ -308,11 +287,7 @@ export function parseAttr(rootAttr: any) {
return result; return result;
} }
export function parseHooks( export function parseHooks(hooks: Hook<any, any>[] | null, depContexts: Array<ContextType<any>> | null, getHookInfo) {
hooks: Hook<any, any>[] | null,
depContexts: Array<ContextType<any>> | null,
getHookInfo
) {
const result: IAttr[] = []; const result: IAttr[] = [];
const indentation = 0; const indentation = 0;
if (depContexts !== null && depContexts?.length > 0) { if (depContexts !== null && depContexts?.length > 0) {
@ -343,7 +318,7 @@ export function parseVNodeAttrs(vNode: VNode, getHookInfo) {
src, src,
}; };
} else if (propsAndHooksTag.includes(tag)) { } else if (propsAndHooksTag.includes(tag)) {
const { props, hooks, depContexts, src } = vNode; const { props, hooks, depContexts, src } = vNode;
const parsedProps = parseAttr(props); const parsedProps = parseAttr(props);
const parsedHooks = parseHooks(hooks, depContexts, getHookInfo); const parsedHooks = parseHooks(hooks, depContexts, getHookInfo);
return { return {

View File

@ -21,7 +21,7 @@ import {
ForwardRef, ForwardRef,
FunctionComponent, FunctionComponent,
MemoComponent, MemoComponent,
SuspenseComponent SuspenseComponent,
} from '../../../inula/src/renderer/vnode/VNodeTags'; } from '../../../inula/src/renderer/vnode/VNodeTags';
export type NameObj = { export type NameObj = {
@ -61,13 +61,7 @@ const componentType = [
MemoComponent, MemoComponent,
]; ];
const badgeNameArr: Array<string> = [ const badgeNameArr: Array<string> = ['withRouter(', 'SideEffect(', 'Connect(', 'injectIntl(', 'Pure('];
'withRouter(',
'SideEffect(',
'Connect(',
'injectIntl(',
'Pure(',
];
export function isUserComponent(tag: string) { export function isUserComponent(tag: string) {
return componentType.includes(tag); return componentType.includes(tag);

View File

@ -14,7 +14,7 @@
*/ */
interface IArrow { interface IArrow {
direction: 'up' | 'down' direction: 'up' | 'down';
} }
export default function Arrow({ direction: director }: IArrow) { export default function Arrow({ direction: director }: IArrow) {
@ -26,8 +26,8 @@ export default function Arrow({ direction: director }: IArrow) {
} }
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='1rem' height='1rem'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="1rem" height="1rem">
<path d={d} fill='currentColor' /> <path d={d} fill="currentColor" />
</svg> </svg>
); );
} }

View File

@ -15,8 +15,8 @@
export default function Close() { export default function Close() {
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='1rem' height='1rem'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="1rem" height="1rem">
<path d='M4 3 L3 4 L7 8 L3 12 L4 13 L8 9 L12 13 L13 12 L9 8 L13 4 L12 3 L8 7z' fill='currentColor' /> <path d="M4 3 L3 4 L7 8 L3 12 L4 13 L8 9 L12 13 L13 12 L9 8 L13 4 L12 3 L8 7z" fill="currentColor" />
</svg> </svg>
); );
} }

View File

@ -15,13 +15,15 @@
export default function Debug() { export default function Debug() {
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='1.3rem' height='1.3rem' margin-top='0.4rem'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1.3rem" height="1.3rem" margin-top="0.4rem">
<path d='M0 0h24v24H0z' fill='none'/> <path d="M0 0h24v24H0z" fill="none" />
<path d='M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4 41 15.59 3l-2.17 2.17c12 96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 <path
d="M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4 41 15.59 3l-2.17 2.17c12 96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41
3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34 04.67 09 1H4v2h2.81c1.04 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34 04.67 09 1H4v2h2.81c1.04
1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6
8h-4v-2h4v2zm0-4h-4v-2h4v2z' 8h-4v-2h4v2zm0-4h-4v-2h4v2z"
fill='currentColor' /> fill="currentColor"
/>
</svg> </svg>
); );
} }

View File

@ -15,12 +15,15 @@
export default function Discover() { export default function Discover() {
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='1.3rem' height='1.3rem'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1.3rem" height="1.3rem">
<path d='M0 0h24v24H0z' fill='none' /> <path d="M0 0h24v24H0z" fill="none" />
<path d='M15.5 14h-.79l-.28-.27C15 41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 <path
d="M15.5 14h-.79l-.28-.27C15 41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91
16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99
5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z' 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"
fill='#343231' p-id='4151' /> fill="#343231"
p-id="4151"
/>
</svg> </svg>
); );
} }

View File

@ -15,12 +15,14 @@
export default function Eye() { export default function Eye() {
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='1.3rem' height='1.3rem'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1.3rem" height="1.3rem">
<path d='M0 0h24v24H0z' fill='none'/> <path d="M0 0h24v24H0z" fill="none" />
<path d='M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 <path
d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12
17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3
3-1.34 3-3-1.34-3-3-3z' 3-1.34 3-3-1.34-3-3-3z"
fill='currentColor' /> fill="currentColor"
/>
</svg> </svg>
); );
} }

View File

@ -15,10 +15,12 @@
export default function Location() { export default function Location() {
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='1.3rem' height='1.3rem'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="1.3rem" height="1.3rem">
<path d='M0 0h24v24H0z' fill='none' /> <path d="M0 0h24v24H0z" fill="none" />
<path d='M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z' <path
fill='currentColor' /> d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"
fill="currentColor"
/>
</svg> </svg>
); );
} }

View File

@ -15,8 +15,20 @@
export default function Operation() { export default function Operation() {
return ( return (
<svg t="1669105013009" className="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2821" width="1rem" height="1rem"> <svg
<path d="M177.23392 943.96416c25.93792 0 50.3296-10.13248 68.70528-28.50816l208.18432-208.18944 29.36832-29.36832 38.90688 14.51008a323.70688 323.70688 0 0 0 112.85504 20.18304c86.48704 0 167.90528-33.664 229.05344-94.90432 83.4816-83.39456 113.4592-203.37152 83.99872-312.96512L795.60704 457.4208l-45.77792 45.77792-45.85984-45.77792-137.41568-137.41056-45.77792-45.87008 45.77792-45.7728 152.61696-152.61696a327.44448 327.44448 0 0 0-83.90656-10.99264c-86.48704 0-167.81824 33.66912-228.9664 94.90944C316.96896 248.89856 287.68256 383.13472 331.5712 501.57056l14.42816 38.90688-29.37344 29.36832-208.09728 208.19456c-18.37568 18.37568-28.51328 42.76736-28.51328 68.70528 0 25.93792 10.13248 50.3296 28.51328 68.7104a96.41472 96.41472 0 0 0 68.70528 28.50816m0 64.76288a161.67936 161.67936 0 0 1-114.57024-47.41632c-63.21152-63.29856-63.21152-165.84704 0-229.05344L270.848 524.07296c-51.18976-138.01984-21.30432-299.31008 89.57952-410.27072C436.352 37.9648 535.808 0 635.25888 0c68.4544 0 136.81664 17.95072 197.53472 53.77024l-220.38016 220.37504 137.41568 137.41568 220.38528-220.38016c88.02816 149.0944 68.0192 344.30976-60.12416 472.3712-75.83744 75.83232-175.37536 113.79712-274.83136 113.79712a389.6064 389.6064 0 0 1-135.35232-24.2176l-208.18944 208.18432c-31.60576 31.60064-73.088 47.4112-114.4832 47.4112z" p-id="2822"/> t="1669105013009"
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2821"
width="1rem"
height="1rem"
>
<path
d="M177.23392 943.96416c25.93792 0 50.3296-10.13248 68.70528-28.50816l208.18432-208.18944 29.36832-29.36832 38.90688 14.51008a323.70688 323.70688 0 0 0 112.85504 20.18304c86.48704 0 167.90528-33.664 229.05344-94.90432 83.4816-83.39456 113.4592-203.37152 83.99872-312.96512L795.60704 457.4208l-45.77792 45.77792-45.85984-45.77792-137.41568-137.41056-45.77792-45.87008 45.77792-45.7728 152.61696-152.61696a327.44448 327.44448 0 0 0-83.90656-10.99264c-86.48704 0-167.81824 33.66912-228.9664 94.90944C316.96896 248.89856 287.68256 383.13472 331.5712 501.57056l14.42816 38.90688-29.37344 29.36832-208.09728 208.19456c-18.37568 18.37568-28.51328 42.76736-28.51328 68.70528 0 25.93792 10.13248 50.3296 28.51328 68.7104a96.41472 96.41472 0 0 0 68.70528 28.50816m0 64.76288a161.67936 161.67936 0 0 1-114.57024-47.41632c-63.21152-63.29856-63.21152-165.84704 0-229.05344L270.848 524.07296c-51.18976-138.01984-21.30432-299.31008 89.57952-410.27072C436.352 37.9648 535.808 0 635.25888 0c68.4544 0 136.81664 17.95072 197.53472 53.77024l-220.38016 220.37504 137.41568 137.41568 220.38528-220.38016c88.02816 149.0944 68.0192 344.30976-60.12416 472.3712-75.83744 75.83232-175.37536 113.79712-274.83136 113.79712a389.6064 389.6064 0 0 1-135.35232-24.2176l-208.18944 208.18432c-31.60576 31.60064-73.088 47.4112-114.4832 47.4112z"
p-id="2822"
/>
</svg> </svg>
); );
} }

View File

@ -15,23 +15,23 @@
export default function Select() { export default function Select() {
return ( return (
<svg width='1rem' height='1rem' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'> <svg width="1rem" height="1rem" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<g fill='none' fill-rule='evenodd'> <g fill="none" fill-rule="evenodd">
<g stroke='currentColor'> <g stroke="currentColor">
<path <path
stroke-width='.291' stroke-width=".291"
fill='currentColor' fill="currentColor"
fill-rule='nonzero' fill-rule="nonzero"
stroke-linecap='round' stroke-linecap="round"
stroke-linejoin='round' stroke-linejoin="round"
d='M6 6l3.014 9 2.508-3.533L15 8.791z' d="M6 6l3.014 9 2.508-3.533L15 8.791z"
></path> ></path>
<path stroke-width='2' d='M10.417 10.417l2.87 2.87L15 15'></path> <path stroke-width="2" d="M10.417 10.417l2.87 2.87L15 15"></path>
</g> </g>
<path <path
d='M12.188 0A2.812 2.812 0 0 1 15 2.813V5h-1V2.857A1.857 1.857 0 0 0 12.143 1H2.857A1.857 1.857 0 0 0 1 2.857v9.286C1 13.169 1.831 14 2.857 14H5v1H2.812A2.812 2.812 0 0 1 0 12.187V2.813A2.812 2.812 0 0 1 2.813 0h9.374z' d="M12.188 0A2.812 2.812 0 0 1 15 2.813V5h-1V2.857A1.857 1.857 0 0 0 12.143 1H2.857A1.857 1.857 0 0 0 1 2.857v9.286C1 13.169 1.831 14 2.857 14H5v1H2.812A2.812 2.812 0 0 1 0 12.187V2.813A2.812 2.812 0 0 1 2.813 0h9.374z"
fill='currentColor' fill="currentColor"
fill-rule='nonzero' fill-rule="nonzero"
></path> ></path>
</g> </g>
</svg> </svg>

View File

@ -14,7 +14,7 @@
*/ */
interface IArrow { interface IArrow {
director: 'right' | 'down' director: 'right' | 'down';
} }
export default function Triangle({ director }: IArrow) { export default function Triangle({ director }: IArrow) {
@ -25,8 +25,8 @@ export default function Triangle({ director }: IArrow) {
d = 'm0 2h16 l-8 12 z'; d = 'm0 2h16 l-8 12 z';
} }
return ( return (
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='8px' height='8px'> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="8px" height="8px">
<path d={d} fill='currentColor' /> <path d={d} fill="currentColor" />
</svg> </svg>
); );
} }

View File

@ -16,26 +16,26 @@
export function Checkbox({ value }) { export function Checkbox({ value }) {
return ( return (
<div <div
style={{ style={{
border: '1px solid black', border: '1px solid black',
borderRadius: '2px', borderRadius: '2px',
width: '0.75rem', width: '0.75rem',
height: '0.75rem', height: '0.75rem',
padding: '1px', padding: '1px',
backgroundColor: 'white', backgroundColor: 'white',
display: 'inline-block', display: 'inline-block',
position: 'relative', position: 'relative',
cursor: 'pointer', cursor: 'pointer',
verticalAlign: 'sub', verticalAlign: 'sub',
marginBottom: '0.1rem' marginBottom: '0.1rem',
}} }}
> >
<div <div
style={{ style={{
width: '100%', width: '100%',
height: '100%', height: '100%',
backgroundColor: value? 'black' : 'white', backgroundColor: value ? 'black' : 'white',
position: 'relative' position: 'relative',
}} }}
></div> ></div>
</div> </div>

View File

@ -13,7 +13,7 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import { createContext } from "openinula"; import { createContext } from 'openinula';
const PickElementContext = createContext(null); const PickElementContext = createContext(null);
PickElementContext.displayName = 'PickElementContext'; PickElementContext.displayName = 'PickElementContext';

View File

@ -13,7 +13,7 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import {createContext} from 'openinula'; import { createContext } from 'openinula';
const ViewSourceContext = createContext(null); const ViewSourceContext = createContext(null);
ViewSourceContext.displayName = 'ViewSourceContext'; ViewSourceContext.displayName = 'ViewSourceContext';

View File

@ -31,11 +31,7 @@ export function injectSrc(src) {
script.remove(); script.remove();
}; };
ifNullThrows( ifNullThrows(document.head || document.getElementsByName('head')[0] || document.documentElement).appendChild(script);
document.head
|| document.getElementsByName('head')[0]
|| document.documentElement
).appendChild(script);
} }
export function injectCode(code) { export function injectCode(code) {

View File

@ -18,10 +18,10 @@
* *
*/ */
interface LoggerType { interface LoggerType {
error: typeof console.error, error: typeof console.error;
info: typeof console.info, info: typeof console.info;
log: typeof console.log, log: typeof console.log;
warn: typeof console.warn warn: typeof console.warn;
} }
export function createLogger(id: string): LoggerType { export function createLogger(id: string): LoggerType {

View File

@ -34,7 +34,7 @@ export function packagePayload(payload: PayloadType, from: string, inulaX?: bool
return { return {
type: devTools, type: devTools,
payload, payload,
from from,
}; };
} }

View File

@ -26,28 +26,12 @@ function handleBuildDir() {
if (!isBuildExist) { if (!isBuildExist) {
fs.mkdirSync(staticDir); fs.mkdirSync(staticDir);
} }
fs.copyFileSync(path.join(__dirname, 'src', 'panel', 'panel.html'), path.join(staticDir, 'panel.html'));
fs.copyFileSync(path.join(__dirname, 'src', 'panelX', 'panel.html'), path.join(staticDir, 'panelX.html'));
fs.copyFileSync(path.join(__dirname, 'src', 'main', 'main.html'), path.join(staticDir, 'main.html'));
fs.copyFileSync(path.join(__dirname, 'src', 'manifest.json'), path.join(staticDir, 'manifest.json'));
fs.copyFileSync( fs.copyFileSync(
path.join(__dirname, 'src', 'panel', 'panel.html'), path.join(__dirname, '../inula/build/umd', 'inula.development.js'),
path.join(staticDir, 'panel.html')
);
fs.copyFileSync(
path.join(__dirname, 'src', 'panelX', 'panel.html'),
path.join(staticDir, 'panelX.html')
);
fs.copyFileSync(
path.join(__dirname, 'src', 'main', 'main.html'),
path.join(staticDir, 'main.html')
);
fs.copyFileSync(
path.join(__dirname, 'src', 'manifest.json'),
path.join(staticDir, 'manifest.json')
);
fs.copyFileSync(
path.join(
__dirname,
'../inula/build/umd',
'inula.development.js'
),
path.join(staticDir, 'inula.development.js') path.join(staticDir, 'inula.development.js')
); );
} }
@ -65,7 +49,7 @@ const config = {
}, },
output: { output: {
path: path.resolve(__dirname, './build'), path: path.resolve(__dirname, './build'),
filename: '[name].js' filename: '[name].js',
}, },
mode: 'development', mode: 'development',
devtool: 'inline-source-map', devtool: 'inline-source-map',

View File

@ -24,7 +24,7 @@ module.exports = {
}, },
output: { output: {
path: path.resolve(__dirname, './dist'), path: path.resolve(__dirname, './dist'),
filename: '[name].js' filename: '[name].js',
}, },
mode: 'development', mode: 'development',
devtool: 'source-map', devtool: 'source-map',
@ -73,5 +73,5 @@ module.exports = {
open: 'panel.html', open: 'panel.html',
port: 9000, port: 9000,
magicHtml: true, magicHtml: true,
} },
}; };

View File

@ -0,0 +1,42 @@
{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "current"
}
}],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-syntax-jsx",
[
"@babel/plugin-transform-react-jsx",
{
"runtime": "automatic",
"importSource": "openinula"
}
],
["@babel/plugin-proposal-class-properties", { "loose": true }],
["@babel/plugin-proposal-private-methods", { "loose": true }],
["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
"@babel/plugin-transform-object-assign",
"@babel/plugin-transform-object-super",
["@babel/plugin-proposal-object-rest-spread", { "loose": true, "useBuiltIns": true }],
["@babel/plugin-transform-template-literals", { "loose": true }],
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-literals",
"@babel/plugin-transform-for-of",
"@babel/plugin-transform-block-scoped-functions",
"@babel/plugin-transform-classes",
"@babel/plugin-transform-shorthand-properties",
"@babel/plugin-transform-computed-properties",
"@babel/plugin-transform-parameters",
["@babel/plugin-transform-spread", { "loose": true, "useBuiltIns": true }],
["@babel/plugin-transform-block-scoping", { "throwIfClosureRequired": false }],
["@babel/plugin-transform-destructuring", { "loose": true, "useBuiltIns": true }],
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-optional-chaining"
]
}

View File

@ -1,74 +0,0 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
root: true,
plugins: ['jest', 'no-for-of-loops', 'no-function-declare-after-return', 'react', '@typescript-eslint'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 8,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
modules: true,
experimentalObjectRestSpread: true,
},
},
env: {
browser: true,
jest: true,
node: true,
es6: true,
},
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-empty-function': 'off',
semi: ['warn', 'always'],
quotes: ['warn', 'single'],
'accessor-pairs': 'off',
'brace-style': ['error', '1tbs'],
'func-style': ['warn', 'declaration', { allowArrowFunctions: true }],
'max-lines-per-function': 'off',
'object-curly-newline': 'off',
// 尾随逗号
'comma-dangle': ['error', 'only-multiline'],
'no-constant-condition': 'off',
'no-for-of-loops/no-for-of-loops': 'error',
'no-function-declare-after-return/no-function-declare-after-return': 'error',
},
globals: {
isDev: true,
isTest: true,
},
overrides: [
{
files: ['scripts/tests/**/*.js'],
globals: {
container: true,
},
},
],
};

View File

@ -1,30 +0,0 @@
/*
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
*
* openInula is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
module.exports = {
printWidth: 120, // 一行120字符数如果超过会进行换行
tabWidth: 2, // tab等2个空格
useTabs: false, // 用空格缩进行
semi: true, // 行尾使用分号
singleQuote: true, // 字符串使用单引号
quoteProps: 'as-needed', // 仅在需要时在对象属性添加引号
jsxSingleQuote: false, // 在JSX中使用双引号
trailingComma: 'es5', // 使用尾逗号(对象、数组等)
bracketSpacing: true, // 对象的括号间增加空格
bracketSameLine: false, // 将多行JSX元素的>放在最后一行的末尾
arrowParens: 'avoid', // 在唯一的arrow函数参数周围省略括号
vueIndentScriptAndStyle: false, // 不缩进Vue文件中的<script>和<style>标记内的代码
endOfLine: 'lf', // 仅限换行(\n
};

View File

@ -0,0 +1,50 @@
import fs from 'fs';
import path from 'path';
import dts from 'rollup-plugin-dts';
function deleteFolder(filePath) {
if (fs.existsSync(filePath)) {
if (fs.lstatSync(filePath).isDirectory()) {
const files = fs.readdirSync(filePath);
files.forEach(file => {
const nextFilePath = path.join(filePath, file);
const states = fs.lstatSync(nextFilePath);
if (states.isDirectory()) {
deleteFolder(nextFilePath);
} else {
fs.unlinkSync(nextFilePath);
}
});
fs.rmdirSync(filePath);
} else if (fs.lstatSync(filePath).isFile()) {
fs.unlinkSync(filePath);
}
}
}
/**
*
* @param folders {string[]}
* @returns {{buildEnd(): void, name: string}}
*/
export function cleanUp(folders) {
return {
name: 'clean-up',
buildEnd() {
folders.forEach(f => deleteFolder(f));
},
};
}
function buildTypeConfig() {
return {
input: './build/@types/index.d.ts',
output: {
file: './build/@types/index.d.ts',
format: 'es',
},
plugins: [dts(), cleanUp(['./build/@types/example', './build/@types/src'])],
};
}
export default [buildTypeConfig()];

View File

@ -13,44 +13,49 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula, { useState } from 'openinula'; import { useState } from 'openinula';
import { IntlProvider } from "../index"; import { IntlProvider } from '../index';
import zh from "./locale/zh"; import zh from './locale/zh';
import en from "./locale/en"; import en from './locale/en';
import Example1 from "./components/Example1"; import Example1 from './components/Example1';
import Example2 from "./components/Example2"; import Example2 from './components/Example2';
import Example3 from "./components/Example3"; import Example3 from './components/Example3';
import Example4 from "./components/Example4"; import Example4 from './components/Example4';
import Example5 from "./components/Example5"; import Example5 from './components/Example5';
import Example6 from "./components/Example6"; import Example6 from './components/Example6';
const App = () => { const App = () => {
const [locale, setLocale] = useState('zh'); const [locale, setLocale] = useState('zh');
const handleChange = () => { const handleChange = () => {
locale === 'zh' ? setLocale('en') : setLocale('zh'); locale === 'zh' ? setLocale('en') : setLocale('zh');
}; };
const message = locale === 'zh' ? zh : en const message = locale === 'zh' ? zh : en;
return ( return (
<IntlProvider locale={locale} messages={locale === 'zh' ? zh : en}> <>
<header>Inula-Intl API Test Demo</header> <IntlProvider locale={locale} messages={locale === 'zh' ? zh : en}>
<header>Inula-Intl API Test Demo</header>
<div className='container'> <div className="container">
<Example1/> <Example1 />
<Example2/> <Example2 />
<Example3/> <Example3 locale={locale} setLocale={setLocale} />
</div>
<div className="container">
{/*<Example4 locale={locale} messages={message} />*/}
<Example5 />
</div>
<div className="button">
<button onClick={handleChange}></button>
</div>
</IntlProvider>
<div className="container">
<Example4 locale={locale} messages={message} />
</div> </div>
<div className='container'> <div className="container">
<Example4 locale={locale} messages={message}/> <Example6 locale={{ locale }} messages={message} />
<Example5/>
<Example6 locale={{ locale }} messages={message}/>
</div> </div>
<div className='button'> </>
<button onClick={handleChange}></button>
</div>
</IntlProvider>
); );
} };
export default App export default App;

View File

@ -13,16 +13,16 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula from "openinula"; import { useIntl } from '../../index';
import { useIntl } from "../../index";
const Example1 = () => { const Example1 = () => {
const { i18n } = useIntl(); const i18n = useIntl();
return ( return (
<div className="card"> <div className="card">
<h2>useIntl方式测试Demo</h2> <h2>useIntl方式测试Demo</h2>
<pre>{i18n.formatMessage({ id: 'text1' })}</pre> <pre>{i18n.formatMessage({ id: 'text1' })}</pre>
<pre>{i18n.$t({ id: 'text1' })}</pre>
</div> </div>
); );
}; };

View File

@ -12,16 +12,17 @@
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula from "openinula"; import { FormattedMessage } from '../../index';
import { FormattedMessage } from "../../index";
const Example2= () => {
const Example2 = () => {
return ( return (
<div className="card"> <div className="card">
<h2>FormattedMessage方式测试Demo</h2> <h2>FormattedMessage方式测试Demo</h2>
<pre> <pre>
<FormattedMessage id='text2'/> <FormattedMessage id="text2" />
</pre>
<pre>
<FormattedMessage id="text5" values={{ testComponent1: <b>123</b>, testComponent2: <b>456</b> }} />
</pre> </pre>
</div> </div>
); );

View File

@ -13,24 +13,26 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula from 'openinula'; import { FormattedMessage } from '../../index';
import { FormattedMessage } from "../../index";
const Example3 = (props) => { const Example3 = props => {
const { locale, setLocale } = props; const { locale, setLocale } = props;
return ( return (
<div className="card"> <div className="card">
<h2>FormattedMessage方式测试Demo</h2> <h2>FormattedMessage方式测试Demo</h2>
<pre> <pre>
<button className="testButton" onClick={() => { <button
setLocale(locale === 'zh' ? 'en' : 'zh') className="testButton"
}}> onClick={() => {
<FormattedMessage id={'button'}/> setLocale(locale === 'zh' ? 'en' : 'zh');
}}
>
<FormattedMessage id={'button'} />
</button> </button>
<br/> <br />
</pre> </pre>
</div> </div>
); );
} };
export default Example3; export default Example3;

View File

@ -13,10 +13,9 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula from "openinula"; import { createIntl } from '../../index';
import { createIntl } from "../../index";
const Example4 = (props) => { const Example4 = props => {
// 受渲染时机影响createIntl方式需控制时序否则慢一拍 // 受渲染时机影响createIntl方式需控制时序否则慢一拍
const intl = createIntl({ ...props }); const intl = createIntl({ ...props });
const msg = intl.formatMessage({ id: 'text3' }); const msg = intl.formatMessage({ id: 'text3' });

View File

@ -13,23 +13,16 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula, { Component } from 'openinula';
import { injectIntl } from '../../index'; import { injectIntl } from '../../index';
class Example5 extends Component<any, any, any> { const Example5 = ({ intl }) => {
public constructor(props: any, context) { // 使用intl.formatMessage来获取国际化消息
super(props, context); console.log(intl + '------------intl-------------');
} return (
<div className="card">
render() { <h2>injectIntl方式测试Demo</h2>
const { intl } = this.props as any; <pre>{intl.formatMessage({ id: 'text4' })}</pre>
return ( </div>
<div className="card"> );
<h2>injectIntl方式测试Demo</h2> };
<pre>{intl.formatMessage({ id: 'text4' })}</pre>
</div>
);
}
}
export default injectIntl(Example5); export default injectIntl(Example5);

Some files were not shown because too many files have changed in this diff Show More