Compare commits
No commits in common. "master" and "master" have entirely different histories.
|
|
@ -8,4 +8,3 @@ pnpm-lock.yaml
|
|||
build
|
||||
/packages/inula-router/connectRouter
|
||||
/packages/inula-router/router
|
||||
.inula-max
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
# openinula + vite
|
||||
|
||||
该模板提供了 `openinula` 工作在 `vite`的基础配置。
|
||||
> 请注意由于Vite插件有node版本限制,请使用`node -v`命令确认node版本大于等于node v18。
|
||||
|
|
@ -1,49 +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 Inula from 'openinula';
|
||||
import './styles.css';
|
||||
|
||||
class App extends Inula.Component {
|
||||
render() {
|
||||
return (
|
||||
<div class="container">
|
||||
<div class="hero">
|
||||
<h1 class="hero-title animate__animated animate__bounceInDown">欢迎来到 Inula 项目!</h1>
|
||||
<p class="hero-subtitle animate__animated animate__bounceInUp">你已成功创建你的第一个 Inula 项目</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="card animate__animated animate__zoomIn">
|
||||
<h2>开始吧</h2>
|
||||
<p>
|
||||
编辑 <code>src/App.js</code> 并保存以重新加载。
|
||||
</p>
|
||||
</div>
|
||||
<div class="card animate__animated animate__zoomIn">
|
||||
<h2>了解更多</h2>
|
||||
<p>
|
||||
要了解 Inula,查看{' '}
|
||||
<a href="https://openinula.org" target="_blank">
|
||||
Inula 官网
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
@ -1,19 +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 Inula from 'openinula';
|
||||
import App from './App';
|
||||
|
||||
Inula.render(<App />, document.getElementById('root'));
|
||||
|
|
@ -1,43 +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.
|
||||
*/
|
||||
|
||||
const BasicGenerator = require('../../BasicGenerator');
|
||||
|
||||
class Generator extends BasicGenerator {
|
||||
prompting() {
|
||||
return this.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'bundlerType',
|
||||
message: 'Please select the build type',
|
||||
choices: ['webpack', 'vite'],
|
||||
},
|
||||
]).then(props => {
|
||||
this.prompts = props;
|
||||
});
|
||||
}
|
||||
|
||||
writing() {
|
||||
const src = this.templatePath(this.prompts.bundlerType);
|
||||
const dest = this.destinationPath();
|
||||
this.writeFiles(src, dest, {
|
||||
context: {
|
||||
...this.prompts,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Generator;
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"description": "simple reactive app template."
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
# openinula + vite
|
||||
|
||||
该模板提供了 `openinula` 工作在 `vite`的基础配置。
|
||||
> 请注意由于Vite插件有node版本限制,请使用`node -v`命令确认node版本大于等于node v18。
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>My Inula App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/index.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"name": "inula-vite-app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"openinula": "0.0.0-experimental-20231201"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.4",
|
||||
"@babel/preset-env": "^7.21.4",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@vitejs/plugin-react": "^3.1.0",
|
||||
"@vitejs/plugin-react-refresh": "^1.3.6",
|
||||
"babel-plugin-import": "^1.13.6",
|
||||
"vite": "^4.2.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +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 Inula, { useComputed, useReactive, useRef } from 'openinula';
|
||||
|
||||
function ReactiveComponent() {
|
||||
const renderCount = ++useRef(0).current;
|
||||
|
||||
const data = useReactive({ count: 0 });
|
||||
const countText = useComputed(() => {
|
||||
return `计时: ${data.count.get()}`;
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
data.count.set(c => c + 1);
|
||||
}, 1000);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{countText}</div>
|
||||
<div>组件渲染次数:{renderCount}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReactiveComponent;
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #6a11cb 0%, #2575fc 100%);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 3em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 1vh;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.card h2,
|
||||
.card p {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.card a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
@ -1,47 +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 Inula from 'openinula';
|
||||
import ReactiveComponent from './ReactiveComponent';
|
||||
import './index.css';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div class="container">
|
||||
<div class="hero">
|
||||
<h1 class="hero-title animate__animated animate__bounceInDown">欢迎来到 Inula 项目!</h1>
|
||||
<p class="hero-subtitle animate__animated animate__bounceInUp">你已成功创建你的第一个响应式 Inula 项目</p>
|
||||
</div>
|
||||
<div className="content">
|
||||
<div className="card animate__animated animate__zoomIn">
|
||||
<ReactiveComponent />
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="card animate__animated animate__zoomIn">
|
||||
<h2>了解更多</h2>
|
||||
<p>
|
||||
要了解 Inula,查看{' '}
|
||||
<a href="https://openinula.net/" target="_blank">
|
||||
Inula 官网
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Inula.render(<App />, document.getElementById('root'));
|
||||
|
|
@ -1,29 +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 react from '@vitejs/plugin-react';
|
||||
|
||||
let alias = {
|
||||
react: 'openinula', // 新增
|
||||
'react-dom': 'openinula', // 新增
|
||||
'react/jsx-dev-runtime': 'openinula/jsx-dev-runtime',
|
||||
};
|
||||
|
||||
export default {
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias,
|
||||
},
|
||||
};
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"name": "inula-webpack-app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "webpack serve --mode development",
|
||||
"build": "webpack --mode production"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"openinula": "0.0.0-experimental-20231201"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.4",
|
||||
"@babel/preset-env": "^7.21.4",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"babel-loader": "^9.1.2",
|
||||
"css-loader": "^6.7.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"style-loader": "^3.3.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.77.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.13.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +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 Inula from 'openinula';
|
||||
import ReactiveComponent from './ReactiveComponent';
|
||||
import './styles.css';
|
||||
|
||||
class App extends Inula.Component {
|
||||
render() {
|
||||
return (
|
||||
<div class="container">
|
||||
<div class="hero">
|
||||
<h1 class="hero-title animate__animated animate__bounceInDown">欢迎来到 Inula 项目!</h1>
|
||||
<p class="hero-subtitle animate__animated animate__bounceInUp">你已成功创建你的第一个响应式 Inula 项目</p>
|
||||
</div>
|
||||
<div className="content">
|
||||
<div className="card animate__animated animate__zoomIn">
|
||||
<ReactiveComponent />
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="card animate__animated animate__zoomIn">
|
||||
<h2>了解更多</h2>
|
||||
<p>
|
||||
要了解 Inula,查看{' '}
|
||||
<a href="https://openinula.org" target="_blank">
|
||||
Inula 官网
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
@ -1,38 +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 Inula, { useComputed, useReactive, useRef } from 'openinula';
|
||||
|
||||
function ReactiveComponent() {
|
||||
const renderCount = ++useRef(0).current;
|
||||
|
||||
const data = useReactive({ count: 0 });
|
||||
const countText = useComputed(() => {
|
||||
return `计时: ${data.count.get()}`;
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
data.count.set(c => c + 1);
|
||||
}, 1000);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{countText}</div>
|
||||
<div>组件渲染次数:{renderCount}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ReactiveComponent;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Inula App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="../dist/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,19 +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 Inula from 'openinula';
|
||||
import App from './App';
|
||||
|
||||
Inula.render(<App />, document.getElementById('root'));
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #6a11cb 0%, #2575fc 100%);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 3em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 1vh;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.card h2,
|
||||
.card p {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.card a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
@ -1,84 +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.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.jsx',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bundle.js',
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
[
|
||||
'@babel/preset-react',
|
||||
{
|
||||
runtime: 'automatic', // 新增
|
||||
importSource: 'openinula', // 新增
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'images/',
|
||||
publicPath: 'images/',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
use: ['file-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, 'src/index.html'),
|
||||
filename: 'index.html',
|
||||
}),
|
||||
],
|
||||
devServer: {
|
||||
static: path.join(__dirname, 'dist'),
|
||||
compress: true,
|
||||
port: 9000,
|
||||
open: true,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'],
|
||||
},
|
||||
};
|
||||
|
|
@ -57,7 +57,7 @@ export default (api: API) => {
|
|||
api.applyHook({ name: 'afterStartDevServer' });
|
||||
});
|
||||
} else {
|
||||
api.logger.error('Can\'t find config');
|
||||
api.logger.error("Can't find config");
|
||||
}
|
||||
break;
|
||||
case 'vite':
|
||||
|
|
@ -70,7 +70,7 @@ export default (api: API) => {
|
|||
server.printUrls();
|
||||
});
|
||||
} else {
|
||||
api.logger.error('Can\'t find config');
|
||||
api.logger.error("Can't find config");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export default (api: API) => {
|
|||
args._.shift();
|
||||
}
|
||||
if (args._.length === 0) {
|
||||
api.logger.warn('Can\'t find any generate options.');
|
||||
api.logger.warn("Can't find any generate options.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@
|
|||
"html-webpack-plugin": "^5.5.1",
|
||||
"jest-environment-jsdom": "^29.5.0",
|
||||
"jsdom": "^21.1.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react": "18.2.0-h3",
|
||||
"react-dom": "18.2.0-h3",
|
||||
"rollup-plugin-livereload": "^2.0.5",
|
||||
"rollup-plugin-serve": "^1.1.0",
|
||||
"rollup-plugin-visualizer": "^5.10.0",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
],
|
||||
"license": "MulanPSL2",
|
||||
"devDependencies": {
|
||||
"@cloudsop/horizon": "^0.0.58",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import dts from 'rollup-plugin-dts';
|
||||
import { parse } from '@babel/parser';
|
||||
import MagicString from 'magic-string';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
const LIB_NAME = 'Inula';
|
||||
|
||||
function deleteFolder(filePath) {
|
||||
if (fs.existsSync(filePath)) {
|
||||
|
|
@ -51,6 +56,264 @@ export function cleanUp(folders) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取AST语法树节点的名称
|
||||
*
|
||||
* @param node AST语法树节点
|
||||
* @returns 节点的名称
|
||||
*/
|
||||
function getNodeName(node) {
|
||||
if (node.type === 'VariableDeclaration') {
|
||||
node = node.declarations[0];
|
||||
if (!node.id) {
|
||||
return '';
|
||||
}
|
||||
return node.id.name;
|
||||
} else if (
|
||||
node.type === 'TSTypeAliasDeclaration' ||
|
||||
node.type === 'TSInterfaceDeclaration' ||
|
||||
node.type === 'TSDeclareFunction' ||
|
||||
node.type === 'TSEnumDeclaration' ||
|
||||
node.type === 'ClassDeclaration' ||
|
||||
node.type === 'TSModuleDeclaration'
|
||||
) {
|
||||
if (!node.id) {
|
||||
return '';
|
||||
}
|
||||
return node.id.name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断AST语法树节点是否是Horizon变量节点
|
||||
*
|
||||
* @param node AST语法树节点
|
||||
* @returns true 是 false 不是
|
||||
*/
|
||||
function isHorizonVariable(node) {
|
||||
if (node.type === 'VariableDeclaration') {
|
||||
let tmpNode = node.declarations[0];
|
||||
if (!tmpNode.id) {
|
||||
return false;
|
||||
}
|
||||
let exoprtName = tmpNode.id.name;
|
||||
if (exoprtName === LIB_NAME) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为导出的类型节点加上前缀export
|
||||
*
|
||||
* @param node AST语法树节点
|
||||
* @param isExported 导出的类型名称集合
|
||||
* @param hasAliasExport 导出的重命名类型的集合
|
||||
* @param magicStr 原始的AST语法树对应的magic对象
|
||||
* @param parentDecl 当节点为VariableDeclaration类型的子节点时,该变量代表父亲节点,其他类型该参数不传
|
||||
*/
|
||||
function processDeclaration(node, isExported, hasAliasExport, magicStr, parentDecl) {
|
||||
if (!node.id) {
|
||||
return;
|
||||
}
|
||||
assert(node.id.type === 'Identifier');
|
||||
const name = node.id.name;
|
||||
if (name.startsWith('_')) {
|
||||
return;
|
||||
}
|
||||
if (isExported.has(name) && !hasAliasExport.has(name)) {
|
||||
const start = (parentDecl || node).start;
|
||||
assert(typeof start === 'number');
|
||||
magicStr.prependLeft(start, 'export ');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成Horzion的namespace,达到可以Horzion.foo的效果
|
||||
*
|
||||
* @example
|
||||
* 原始文件内容:
|
||||
* type foo
|
||||
* type f001
|
||||
* type fooA$1
|
||||
* const Horzion {
|
||||
* version
|
||||
* }
|
||||
* export { typeof foo, type f001, type fooA$1 as fooA, default Horzion}
|
||||
* 修改后的文件内容:
|
||||
* export type foo
|
||||
* export type f001
|
||||
* type fooA$1
|
||||
* declare namespace Horzion {
|
||||
* export { type foo };
|
||||
* export { type f001 };
|
||||
* export { type fooA$1 as fooA };
|
||||
* }
|
||||
* export { type fooA$1 as fooA };
|
||||
* export default Horzion;
|
||||
* @returns 修改后的文件内容
|
||||
*/
|
||||
function patchNamespaceType() {
|
||||
return {
|
||||
name: 'patch-types',
|
||||
renderChunk(code) {
|
||||
const magicCodeStr = new MagicString(code);
|
||||
const ast = parse(code, {
|
||||
plugins: ['typescript'],
|
||||
sourceType: 'module',
|
||||
});
|
||||
|
||||
const exportedSet = new Set();
|
||||
const hasAliasExportMap = new Map();
|
||||
const aliasTypeArr = [];
|
||||
const exportTypeArr = [];
|
||||
const moduleSet = new Set();
|
||||
|
||||
/**
|
||||
* 第一部分: 遍历AST语法树获取所有的导出的类型名称放入isExported
|
||||
* 获取所有的声明的namespace的名称放入moduleArr
|
||||
*
|
||||
* @example
|
||||
* export { typeof foo } 会将foo放入isExported
|
||||
* delcare namespace foo1 {} 会将foo1放入moduleArr
|
||||
*/
|
||||
for (const node of ast.program.body) {
|
||||
if (node.type === 'TSModuleDeclaration') {
|
||||
moduleSet.add(getNodeName(node));
|
||||
}
|
||||
if (node.type === 'ExportNamedDeclaration' && !node.source) {
|
||||
for (let i = 0; i < node.specifiers.length; i++) {
|
||||
const spec = node.specifiers[i];
|
||||
if (spec.type === 'ExportSpecifier') {
|
||||
exportedSet.add(spec.local.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第二部分:遍历AST语法树 ,去除最后的export声明部分,并且删除Horizon变量的声明
|
||||
* 将除了namespace的导出声明外的所有导出类型放入exportTypeArr
|
||||
* 将所有被重名的导出类型的名称放入aliasTypeArr
|
||||
* 将所有被重名的导出类型的名称和别名放入hasAliasExport,key是类型的名称 value是导出类型的别名
|
||||
*/
|
||||
for (const node of ast.program.body) {
|
||||
if (node.type === 'VariableDeclaration') {
|
||||
if (isHorizonVariable(node)) {
|
||||
// 不导出Horizon变量,需要将Horizon的变量重命名为namespace
|
||||
assert(typeof node.start === 'number');
|
||||
assert(typeof node.end === 'number');
|
||||
magicCodeStr.remove(node.start, node.end);
|
||||
}
|
||||
} else if (node.type === 'ExportNamedDeclaration' && !node.source) {
|
||||
for (let i = 0; i < node.specifiers.length; i++) {
|
||||
const spec = node.specifiers[i];
|
||||
if (spec.type === 'ExportSpecifier' && spec.local.name != LIB_NAME) {
|
||||
assert(spec.exported.type === 'Identifier');
|
||||
const exported = spec.exported.name;
|
||||
if (!moduleSet.has(spec.local.name)) {
|
||||
/**
|
||||
* @example
|
||||
* type foo
|
||||
* namespace foo1{}
|
||||
* export {type foo , foo1}
|
||||
*
|
||||
* 最后放入到exportTypeArr中的为type foo字符串
|
||||
*/
|
||||
exportTypeArr.push(magicCodeStr.slice(spec.start, spec.end));
|
||||
}
|
||||
if (exported !== spec.local.name) {
|
||||
/**
|
||||
* @example
|
||||
* type foo
|
||||
* type foo1
|
||||
* export {type foo as fooalias, type foo1}
|
||||
*
|
||||
* 最后放入aliasTypeArr为type foo as fooalias
|
||||
* 放入hasAliasExport的key为foo, value为fooalias
|
||||
*/
|
||||
aliasTypeArr.push(magicCodeStr.slice(spec.start, spec.end));
|
||||
hasAliasExportMap.set(spec.local.name, exported);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(typeof node.start === 'number');
|
||||
assert(typeof node.end === 'number');
|
||||
magicCodeStr.remove(node.start, node.end);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三部分:遍历AST语法树为所有需要导出的类型加上前缀 export
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* type foo
|
||||
*
|
||||
* @returns
|
||||
*
|
||||
* export type foo
|
||||
*/
|
||||
for (const node of ast.program.body) {
|
||||
if (node.type === 'VariableDeclaration') {
|
||||
if (isHorizonVariable(node)) {
|
||||
continue;
|
||||
}
|
||||
processDeclaration(node.declarations[0], exportedSet, hasAliasExportMap, magicCodeStr, node);
|
||||
if (node.declarations.length > 1) {
|
||||
assert(typeof node.start === 'number');
|
||||
assert(typeof node.end === 'number');
|
||||
throw new Error(
|
||||
`unhandled declare const with more than one declarators:\n${code.slice(node.start, node.end)}`
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
node.type === 'TSTypeAliasDeclaration' ||
|
||||
node.type === 'TSInterfaceDeclaration' ||
|
||||
node.type === 'TSDeclareFunction' ||
|
||||
node.type === 'TSEnumDeclaration' ||
|
||||
node.type === 'ClassDeclaration' ||
|
||||
node.type === 'TSModuleDeclaration'
|
||||
) {
|
||||
processDeclaration(node, exportedSet, hasAliasExportMap, magicCodeStr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第四部分:拼接名称为${HORIZON_NAME} 的namespace,并将它作为默认导出类型
|
||||
* 将所有的重命名的导出类型添加到末尾
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* 结果示例如下
|
||||
* export typeof foo
|
||||
* export typeof foo$1
|
||||
* declare namespace Horizon {
|
||||
* export {typeof foo}
|
||||
* export {typeof foo$1 as fooalias}
|
||||
* }
|
||||
*
|
||||
* export {typeof foo$1 as fooalias}
|
||||
* export default Horizon
|
||||
*/
|
||||
magicCodeStr.append(`declare namespace ${LIB_NAME} {\n`);
|
||||
exportTypeArr.forEach(ele => {
|
||||
magicCodeStr.append(` export { ${ele} };\n`);
|
||||
});
|
||||
magicCodeStr.append('}\n');
|
||||
aliasTypeArr.forEach(ele => {
|
||||
magicCodeStr.append(`export { ${ele} };\n`);
|
||||
});
|
||||
magicCodeStr.append(`export default ${LIB_NAME};`);
|
||||
|
||||
code = magicCodeStr.toString();
|
||||
return code;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildTypeConfig() {
|
||||
return {
|
||||
input: ['./build/@types/index.d.ts'],
|
||||
|
|
@ -58,7 +321,7 @@ function buildTypeConfig() {
|
|||
file: './build/@types/index.d.ts',
|
||||
format: 'es',
|
||||
},
|
||||
plugins: [dts(), cleanUp(['./build/@types/'])],
|
||||
plugins: [dts(), patchNamespaceType(), cleanUp(['./build/@types/'])],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,17 +13,15 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { asyncUpdates, getFirstCustomElement, syncUpdates, startUpdate, createTreeRootVNode } from './Renderer';
|
||||
import { createPortal } from './components/CreatePortal';
|
||||
import type { Container, ElementType } from './Types';
|
||||
import { isElement } from './utils/common';
|
||||
import { findElementByClassInst } from './utils/InternalKeys';
|
||||
import { asyncUpdates, getFirstCustomDom, syncUpdates, startUpdate, createTreeRootVNode } from '../renderer/Renderer';
|
||||
import { createPortal } from '../renderer/components/CreatePortal';
|
||||
import type { Container } from './DOMOperator';
|
||||
import { isElement } from './utils/Common';
|
||||
import { findDOMByClassInst } from '../renderer/vnode/VNodeUtils';
|
||||
import { listenSimulatedDelegatedEvents } from '../event/EventBinding';
|
||||
import { Callback } from './Types';
|
||||
import { Callback } from '../renderer/Types';
|
||||
import { InulaNode } from '../types';
|
||||
import { EVENT_KEY } from './utils/InternalKeys';
|
||||
import { InulaReconciler } from '.';
|
||||
import { EVENT_KEY } from './DOMInternalKeys';
|
||||
|
||||
function createRoot(children: any, container: Container, callback?: Callback) {
|
||||
// 清空容器
|
||||
|
|
@ -42,7 +40,7 @@ function createRoot(children: any, container: Container, callback?: Callback) {
|
|||
if (typeof callback === 'function') {
|
||||
const cb = callback;
|
||||
callback = function () {
|
||||
const instance = getFirstCustomElement(treeRoot);
|
||||
const instance = getFirstCustomDom(treeRoot);
|
||||
cb.call(instance);
|
||||
};
|
||||
}
|
||||
|
|
@ -65,7 +63,7 @@ function executeRender(children: any, container: Container, callback?: Callback)
|
|||
if (typeof callback === 'function') {
|
||||
const cb = callback;
|
||||
callback = function () {
|
||||
const instance = getFirstCustomElement(treeRoot);
|
||||
const instance = getFirstCustomDom(treeRoot);
|
||||
cb.call(instance);
|
||||
};
|
||||
}
|
||||
|
|
@ -73,21 +71,21 @@ function executeRender(children: any, container: Container, callback?: Callback)
|
|||
startUpdate(children, treeRoot, callback);
|
||||
}
|
||||
|
||||
return getFirstCustomElement(treeRoot);
|
||||
return getFirstCustomDom(treeRoot);
|
||||
}
|
||||
|
||||
function findNode(Ele?: Element): null | Element | Text {
|
||||
if (Ele === null || Ele === undefined) {
|
||||
function findDOMNode(domOrEle?: Element): null | Element | Text {
|
||||
if (domOrEle === null || domOrEle === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 普通节点
|
||||
if (isElement(Ele as ElementType)) {
|
||||
return Ele;
|
||||
if (isElement(domOrEle)) {
|
||||
return domOrEle;
|
||||
}
|
||||
|
||||
// class的实例
|
||||
return findElementByClassInst(Ele);
|
||||
return findDOMByClassInst(domOrEle);
|
||||
}
|
||||
|
||||
// 情况根节点监听器
|
||||
|
|
@ -98,7 +96,7 @@ function removeRootEventLister(container: Container) {
|
|||
const listener = events[event];
|
||||
|
||||
if (listener) {
|
||||
InulaReconciler.hostConfig.removeEventListener(container, event, listener);
|
||||
container.removeEventListener(event, listener);
|
||||
events[event] = null;
|
||||
}
|
||||
});
|
||||
|
|
@ -142,7 +140,7 @@ function createRootElement(container: Container, option?: Record<string, any>):
|
|||
export {
|
||||
createPortal,
|
||||
asyncUpdates as unstable_batchedUpdates,
|
||||
findNode,
|
||||
findDOMNode,
|
||||
executeRender as render,
|
||||
createRootElement as createRoot,
|
||||
destroy as unmountComponentAtNode,
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 文件整体功能:给dom节点赋 VNode 的结构体和事件初始化标记
|
||||
*/
|
||||
|
||||
import type { VNode } from '../renderer/Types';
|
||||
import type { Container, Props } from './DOMOperator';
|
||||
|
||||
import { DomComponent, DomText, TreeRoot } from '../renderer/vnode/VNodeTags';
|
||||
|
||||
const randomKey = Math.random().toString(16).slice(2);
|
||||
const INTERNAL_VNODE = `_inula_VNode_${randomKey}`;
|
||||
const INTERNAL_PROPS = `_inula_Props_${randomKey}`;
|
||||
const INTERNAL_NONDELEGATEEVENTS = `_inula_nonDelegatedEvents_${randomKey}`;
|
||||
export const HANDLER_KEY = `_inula_valueChangeHandler_${randomKey}`;
|
||||
export const EVENT_KEY = `_inula_ev_${randomKey}`;
|
||||
|
||||
// 通过 VNode 实例获取 DOM 节点
|
||||
export function getDom(vNode: VNode): Element | Text | null {
|
||||
const { tag } = vNode;
|
||||
if (tag === DomComponent || tag === DomText) {
|
||||
return vNode.realNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 将 VNode 属性相关信息挂到 DOM 对象的特定属性上
|
||||
export function saveVNode(vNode: VNode, dom: Element | Text | Container): void {
|
||||
dom[INTERNAL_VNODE] = vNode;
|
||||
}
|
||||
|
||||
// 用 DOM 节点,来找其对应的 VNode 实例
|
||||
export function getVNode(dom: Node | Container): VNode | null {
|
||||
const vNode = dom[INTERNAL_VNODE] || (dom as Container)._treeRoot;
|
||||
if (vNode) {
|
||||
const { tag } = vNode;
|
||||
if (tag === DomComponent || tag === DomText || tag === TreeRoot) {
|
||||
return vNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 用 DOM 对象,来寻找其对应或者说是最近父级的 vNode
|
||||
export function getNearestVNode(dom: Node): null | VNode {
|
||||
let domNode: Node | null = dom;
|
||||
// 寻找当前节点及其所有祖先节点是否有标记VNODE
|
||||
while (domNode) {
|
||||
const vNode = domNode[INTERNAL_VNODE];
|
||||
if (vNode) {
|
||||
return vNode;
|
||||
}
|
||||
domNode = domNode.parentNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取 vNode 上的属性相关信息
|
||||
export function getVNodeProps(dom: Element | Text): Props | null {
|
||||
return dom[INTERNAL_PROPS] || null;
|
||||
}
|
||||
|
||||
// 将 DOM 属性相关信息挂到 DOM 对象的特定属性上
|
||||
export function updateVNodeProps(dom: Element | Text, props: Props): void {
|
||||
dom[INTERNAL_PROPS] = props;
|
||||
}
|
||||
|
||||
export function getNonDelegatedListenerMap(dom: Element | Text): Map<string, EventListener> {
|
||||
let eventsMap = dom[INTERNAL_NONDELEGATEEVENTS];
|
||||
if (!eventsMap) {
|
||||
eventsMap = new Map();
|
||||
dom[INTERNAL_NONDELEGATEEVENTS] = eventsMap;
|
||||
}
|
||||
return eventsMap;
|
||||
}
|
||||
|
|
@ -1,25 +1,33 @@
|
|||
// /*
|
||||
// * 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.
|
||||
// */
|
||||
/*
|
||||
* 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 { saveVNode, updateVNodeProps } from './DOMInternalKeys';
|
||||
import { createDom } from './utils/DomCreator';
|
||||
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
|
||||
import { controlInputValue } from './valueHandler/ValueChangeHandler';
|
||||
import { updateTextareaValue } from './valueHandler/TextareaValueHandler';
|
||||
import { isDocument, shouldAutoFocus } from './utils/Common';
|
||||
import { NSS } from './utils/DomCreator';
|
||||
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
||||
import { type Container, CommonTags } from '../renderer/Types';
|
||||
import type { VNode } from '../renderer/Types';
|
||||
import { setInitValue, getPropsWithoutValue, updateValue } from './valueHandler';
|
||||
import { compareProps, setDomProps } from './DOMPropertiesHandler/DOMPropertiesHandler';
|
||||
import { isNativeElement, validateProps } from './validators/ValidateProps';
|
||||
import { watchValueChange } from './valueHandler/ValueChangeHandler';
|
||||
import { DomComponent, DomText } from '../renderer/vnode/VNodeTags';
|
||||
import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp';
|
||||
import { getCurrentRoot } from '../renderer/RootStack';
|
||||
|
||||
export type Props = Record<string, any> & {
|
||||
autoFocus?: boolean;
|
||||
children?: any;
|
||||
|
|
@ -29,6 +37,7 @@ export type Props = Record<string, any> & {
|
|||
style?: { display?: string };
|
||||
};
|
||||
|
||||
export type Container = (Element & { _treeRoot?: VNode | null }) | (Document & { _treeRoot?: VNode | null });
|
||||
|
||||
let selectionInfo: null | SelectionData = null;
|
||||
|
||||
|
|
@ -48,7 +57,7 @@ function getChildNS(parentNS: string | null, tagName: string): string {
|
|||
|
||||
// 获取容器
|
||||
export function getNSCtx(parentNS: string, type: string, dom?: Container): string {
|
||||
return dom ? getChildNS((dom as Element).namespaceURI ?? null, dom.nodeName) : getChildNS(parentNS, type);
|
||||
return dom ? getChildNS(dom.namespaceURI ?? null, dom.nodeName) : getChildNS(parentNS, type);
|
||||
}
|
||||
|
||||
export function prepareForSubmit(): void {
|
||||
|
|
@ -60,28 +69,61 @@ export function resetAfterSubmit(): void {
|
|||
selectionInfo = null;
|
||||
}
|
||||
|
||||
export function createElement(tagName: string, props: Props, parentNamespace: string, rootDom: Element): {element: any, props: Props} {
|
||||
// 创建 DOM 对象
|
||||
export function newDom(tagName: string, props: Props, parentNamespace: string, vNode: VNode): Element {
|
||||
// document取值于treeRoot对应的DOM的ownerDocument。
|
||||
// 解决:在iframe中使用top的inula时,inula在创建DOM时用到的document并不是iframe的document,而是top中的document的问题。
|
||||
const doc = rootDom instanceof Document ? rootDom : rootDom.ownerDocument;
|
||||
const rootDom = getCurrentRoot()?.realNode;
|
||||
const doc = isDocument(rootDom) ? rootDom : rootDom.ownerDocument;
|
||||
|
||||
const dom: Element = createDom(tagName, parentNamespace, doc);
|
||||
// 将 vNode 节点挂到 DOM 对象上
|
||||
saveVNode(vNode, dom);
|
||||
// 将属性挂到 DOM 对象上
|
||||
updateVNodeProps(dom, props);
|
||||
|
||||
|
||||
return {element: dom, props};
|
||||
return dom;
|
||||
}
|
||||
export function handleControledElements(target: Element , type: string, props: Props) {
|
||||
switch (type) {
|
||||
case 'input':
|
||||
controlInputValue(<HTMLInputElement>target, props);
|
||||
break;
|
||||
case 'textarea':
|
||||
updateTextareaValue(<HTMLTextAreaElement>target, props);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
// 设置节点默认事件、属性
|
||||
export function initDomProps(dom: Element, tagName: string, rawProps: Props): boolean {
|
||||
validateProps(tagName, rawProps);
|
||||
|
||||
// 获取不包括value,defaultValue的属性
|
||||
const props: Record<string, any> = getPropsWithoutValue(tagName, dom, rawProps);
|
||||
|
||||
// 初始化DOM属性(不包括value,defaultValue)
|
||||
const isNativeTag = isNativeElement(tagName, props);
|
||||
setDomProps(dom, props, isNativeTag, true);
|
||||
|
||||
if (tagName === 'input' || tagName === 'textarea') {
|
||||
// 增加监听value和checked的set、get方法
|
||||
watchValueChange(dom);
|
||||
}
|
||||
|
||||
// 设置dom.value值,触发受控组件的set方法
|
||||
setInitValue(tagName, dom, rawProps);
|
||||
|
||||
return shouldAutoFocus(tagName, rawProps);
|
||||
}
|
||||
|
||||
// 准备更新之前进行一系列校验 DOM,寻找属性差异等准备工作
|
||||
export function getPropChangeList(
|
||||
dom: Element,
|
||||
type: string,
|
||||
lastRawProps: Props,
|
||||
nextRawProps: Props
|
||||
): Record<string, any> {
|
||||
// 校验两个对象的不同
|
||||
validateProps(type, nextRawProps);
|
||||
|
||||
// 重新定义的属性不需要参与对比,被代理的组件需要把这些属性覆盖到props中
|
||||
const oldProps: Record<string, any> = getPropsWithoutValue(type, dom, lastRawProps);
|
||||
const newProps: Record<string, any> = getPropsWithoutValue(type, dom, nextRawProps);
|
||||
|
||||
return compareProps(oldProps, newProps);
|
||||
}
|
||||
|
||||
export function isTextChild(type: string, props: Props): boolean {
|
||||
if (type === 'textarea' || type === 'option' || type === 'noscript') {
|
||||
return true;
|
||||
|
|
@ -98,11 +140,52 @@ export function isTextChild(type: string, props: Props): boolean {
|
|||
);
|
||||
}
|
||||
}
|
||||
export function createText(text: string) {
|
||||
return document.createTextNode(text);
|
||||
|
||||
export function newTextDom(text: string, processing: VNode): Text {
|
||||
const textNode: Text = document.createTextNode(text);
|
||||
saveVNode(processing, textNode);
|
||||
return textNode;
|
||||
}
|
||||
|
||||
// 提交vNode的类型为DomComponent或者DomText的更新
|
||||
export function submitDomUpdate(tag: string, vNode: VNode) {
|
||||
const newProps = vNode.props;
|
||||
const element: Element | null = vNode.realNode;
|
||||
|
||||
if (tag === DomComponent) {
|
||||
// DomComponent类型
|
||||
if (element !== null && element !== undefined) {
|
||||
const type = vNode.type;
|
||||
const changeList = vNode.changeList;
|
||||
vNode.changeList = null;
|
||||
|
||||
if (changeList !== null) {
|
||||
saveVNode(vNode, element);
|
||||
updateVNodeProps(element, newProps);
|
||||
// 应用diff更新Properties.
|
||||
// 当一个选中的radio改变名称,浏览器使另一个radio的复选框为false.
|
||||
if (
|
||||
type === 'input' &&
|
||||
newProps.type === 'radio' &&
|
||||
newProps.name !== null &&
|
||||
newProps.name !== undefined &&
|
||||
newProps.checked !== null &&
|
||||
newProps.checked !== undefined
|
||||
) {
|
||||
updateCommonProp(element, 'checked', newProps.checked, true);
|
||||
}
|
||||
const isNativeTag = isNativeElement(type, newProps);
|
||||
setDomProps(element, changeList, isNativeTag, false);
|
||||
updateValue(type, element, newProps);
|
||||
}
|
||||
}
|
||||
} else if (tag === DomText) {
|
||||
if (element != null) {
|
||||
// text类型
|
||||
element.textContent = newProps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function clearText(dom: Element): void {
|
||||
dom.innerHTML = '';
|
||||
|
|
@ -114,29 +197,28 @@ export function appendChildElement(parent: Element | Container, child: Element |
|
|||
}
|
||||
|
||||
// 插入dom元素
|
||||
export function insertElementBefore(parent: Element | Container, child: Element | Text, beforeChild: Element | Text) {
|
||||
export function insertDomBefore(parent: Element | Container, child: Element | Text, beforeChild: Element | Text) {
|
||||
parent.insertBefore(child, beforeChild);
|
||||
}
|
||||
|
||||
export function removeChildElement(parent: Element | Container, child: Element | Text) {
|
||||
export function removeChildDom(parent: Element | Container, child: Element | Text) {
|
||||
parent.removeChild(child);
|
||||
}
|
||||
|
||||
// 隐藏元素
|
||||
export function hideElement(tag, dom) {
|
||||
if (tag === CommonTags.ComponentElement) {
|
||||
export function hideDom(tag: string, dom: Element | Text) {
|
||||
if (tag === DomComponent) {
|
||||
(dom as HTMLElement).style.display = 'none';
|
||||
} else if (tag === CommonTags.TextElement) {
|
||||
} else if (tag === DomText) {
|
||||
dom.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 不隐藏元素
|
||||
export function unHideElement(tag, dom, props?: Props) {
|
||||
if (tag === CommonTags.ComponentElement) {
|
||||
(dom as HTMLElement).style.display = adjustStyleValue('display', props?.style?.display ?? '') as string;
|
||||
} else if (tag === CommonTags.TextElement) {
|
||||
export function unHideDom(tag: string, dom: Element | Text, props?: Props) {
|
||||
if (tag === DomComponent) {
|
||||
(dom as HTMLElement).style.display = adjustStyleValue('display', props?.style?.display ?? '');
|
||||
} else if (tag === DomText) {
|
||||
dom.textContent = props as any;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,27 @@
|
|||
import { isEventProp } from './ValidateProps';
|
||||
import { getCurrentRoot } from '../RootStack';
|
||||
/*
|
||||
* 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 { allDelegatedInulaEvents } from '../../event/EventHub';
|
||||
import { updateCommonProp } from './UpdateCommonProp';
|
||||
import { setStyles } from './StyleHandler';
|
||||
import { lazyDelegateOnRoot, listenNonDelegatedEvent } from '../../event/EventBinding';
|
||||
import { InulaReconciler } from '../../renderer';
|
||||
import { ElementType } from '../../renderer/Types';
|
||||
import { Props } from '../utils/InternalKeys';
|
||||
import { shouldAutoFocus } from '../utils/common';
|
||||
import { validateProps } from './ValidateProps';
|
||||
|
||||
export function initElementProps(element: Element, tagName: string, rawProps: Props): boolean {
|
||||
validateProps(tagName, rawProps);
|
||||
|
||||
// 获取不包括value,defaultValue的属性
|
||||
const props: Record<string, any> = InulaReconciler.hostConfig.getProps(tagName, element, rawProps);
|
||||
|
||||
// 初始化DOM属性(不包括value,defaultValue)
|
||||
const isNativeTag = isNativeElement(tagName, props);
|
||||
setElementProps(element as ElementType, props, isNativeTag, true);
|
||||
InulaReconciler.hostConfig.onPropInit(element, tagName, rawProps)
|
||||
return shouldAutoFocus(tagName, rawProps);
|
||||
}
|
||||
import { isEventProp } from '../validators/ValidateProps';
|
||||
import { getCurrentRoot } from '../../renderer/RootStack';
|
||||
|
||||
// 初始化DOM属性和更新 DOM 属性
|
||||
export function setElementProps(element: ElementType, props: Record<string, any>, isNativeTag: boolean, isInit: boolean): void {
|
||||
export function setDomProps(dom: Element, props: Record<string, any>, isNativeTag: boolean, isInit: boolean): void {
|
||||
const keysOfProps = Object.keys(props);
|
||||
let propName;
|
||||
let propVal;
|
||||
|
|
@ -30,23 +29,31 @@ export function setElementProps(element: ElementType, props: Record<string, any>
|
|||
for (let i = 0; i < keyLength; i++) {
|
||||
propName = keysOfProps[i];
|
||||
propVal = props[propName];
|
||||
if (isEventProp(propName)) {
|
||||
|
||||
if (propName === 'style') {
|
||||
setStyles(dom, propVal);
|
||||
} else if (isEventProp(propName)) {
|
||||
// 事件监听属性处理
|
||||
const currentRoot = getCurrentRoot();
|
||||
if (!allDelegatedInulaEvents.has(propName)) {
|
||||
listenNonDelegatedEvent(propName, element, propVal);
|
||||
listenNonDelegatedEvent(propName, dom, propVal);
|
||||
} else if (currentRoot && !currentRoot.delegatedEvents.has(propName)) {
|
||||
lazyDelegateOnRoot(currentRoot, propName);
|
||||
}
|
||||
continue;
|
||||
} else if (propName === 'children') {
|
||||
// 只处理纯文本子节点,其他children在VNode树中处理
|
||||
const type = typeof propVal;
|
||||
if (type === 'string' || type === 'number') {
|
||||
dom.textContent = propVal;
|
||||
}
|
||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||
dom.innerHTML = propVal.__html;
|
||||
} else if (!isInit || (propVal !== null && propVal !== undefined)) {
|
||||
updateCommonProp(dom, propName, propVal, isNativeTag);
|
||||
}
|
||||
InulaReconciler.hostConfig.setProps(element, propName, propVal, isNativeTag, isInit);
|
||||
}
|
||||
}
|
||||
// 是内置元素
|
||||
export function isNativeElement(tagName: string, props: Record<string, any>) {
|
||||
return !tagName.includes('-') && props.is === undefined;
|
||||
}
|
||||
|
||||
// 找出两个 DOM 属性的差别,生成需要更新的属性集合
|
||||
export function compareProps(oldProps: Record<string, any>, newProps: Record<string, any>): Record<string, any> {
|
||||
let updatesForStyle = {};
|
||||
|
|
@ -13,13 +13,11 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
//kb-tag
|
||||
import { getPropDetails, PROPERTY_TYPE } from '../../renderer/props/PropertiesData';
|
||||
import { isInvalidValue } from '../../renderer/props/ValidateProps';
|
||||
import { getPropDetails, PROPERTY_TYPE } from '../validators/PropertiesData';
|
||||
import { isInvalidValue } from '../validators/ValidateProps';
|
||||
import { getNamespaceCtx } from '../../renderer/ContextSaver';
|
||||
import { NSS } from '../utils/DomCreator';
|
||||
import { getTag } from '../../renderer/utils/common';
|
||||
|
||||
import { getDomTag } from '../utils/Common';
|
||||
|
||||
// 不需要装换的svg属性集合
|
||||
const svgHumpAttr = new Set();
|
||||
|
|
@ -113,7 +111,7 @@ export function updateCommonProp(dom: Element, attrName: string, value: any, isN
|
|||
|
||||
if (!isNativeTag || propDetails === null) {
|
||||
// 特殊处理svg的属性,把驼峰式的属性名称转成'-'
|
||||
if (getTag(dom) === 'svg' || getNamespaceCtx() === NSS.svg) {
|
||||
if (getDomTag(dom) === 'svg' || getNamespaceCtx() === NSS.svg) {
|
||||
if (!svgHumpAttr.has(attrName)) {
|
||||
attrName = convertToLowerCase(attrName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
* 处理文本框、输入框中框选范围内的数据
|
||||
*/
|
||||
|
||||
import { getIFrameFocusedDom } from './utils/Common';
|
||||
import { isElement, isText } from '../renderer/utils/common';
|
||||
import { getIFrameFocusedDom, isText } from './utils/Common';
|
||||
import { isElement } from './utils/Common';
|
||||
|
||||
type SelectionRange = {
|
||||
start: number | null;
|
||||
|
|
|
|||
|
|
@ -1,141 +0,0 @@
|
|||
import { ElementType, HostConfigType } from '../renderer/Types';
|
||||
import {
|
||||
createElement as createDom,
|
||||
clearText,
|
||||
appendChildElement,
|
||||
removeChildElement,
|
||||
insertElementBefore,
|
||||
hideElement,
|
||||
unHideElement,
|
||||
isTextChild,
|
||||
handleControledElements,
|
||||
createText,
|
||||
prepareForSubmit,
|
||||
resetAfterSubmit,
|
||||
} from './DOMOperator';
|
||||
import { setStyles } from './DOMPropertiesHandler/StyleHandler';
|
||||
import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp';
|
||||
import { updateValue } from './valueHandler';
|
||||
import { getPropsWithoutValue } from './valueHandler';
|
||||
import { watchValueChange } from './valueHandler/ValueChangeHandler';
|
||||
import { setInitValue } from './valueHandler';
|
||||
import { InulaDom } from './utils/Interface';
|
||||
import { updateInputHandlerIfChanged } from './valueHandler/ValueChangeHandler';
|
||||
|
||||
export const defaultHostConfig: Partial<HostConfigType> = {
|
||||
elementConfig: {
|
||||
common: document.createElement('div'),
|
||||
text: document.createTextNode(''),
|
||||
input: document.createElement('input'),
|
||||
button: document.createElement('button'),
|
||||
select: document.createElement('select'),
|
||||
textarea: document.createElement('textarea'),
|
||||
document: document,
|
||||
},
|
||||
addEventListener(element, eventName, handler, isCapture) {
|
||||
element.addEventListener(eventName, handler, isCapture);
|
||||
},
|
||||
removeEventListener(element, eventName, handler) {
|
||||
element.removeEventListener(eventName, handler);
|
||||
},
|
||||
createElement(tagName, props, parentNamespace, rootElement) {
|
||||
return createDom(tagName, props, parentNamespace, rootElement as Element);
|
||||
},
|
||||
createText(text) {
|
||||
return createText(text) as ElementType;
|
||||
},
|
||||
getProps(type, element, props) {
|
||||
return getPropsWithoutValue(type, element as Element, props);
|
||||
},
|
||||
handleControledInputElements(target, type, props) {
|
||||
return handleControledElements(target as Element, type, props);
|
||||
},
|
||||
isTextChild(type, props) {
|
||||
return isTextChild(type, props);
|
||||
},
|
||||
setProps(element, propName, propVal, isNativeTag, isInit) {
|
||||
if (propName === 'style') {
|
||||
setStyles(element, propVal);
|
||||
} else if (propName === 'children') {
|
||||
// 只处理纯文本子节点,其他children在VNode树中处理
|
||||
const type = typeof propVal;
|
||||
if (type === 'string' || type === 'number') {
|
||||
element.textContent = propVal;
|
||||
}
|
||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||
element.innerHTML = propVal.__html;
|
||||
} else if (!isInit || (propVal !== null && propVal !== undefined)) {
|
||||
updateCommonProp(element as Element, propName, propVal, isNativeTag);
|
||||
}
|
||||
},
|
||||
updateInputValue(type, element, props) {
|
||||
updateValue(type, element as Element, props);
|
||||
},
|
||||
onSubmit(tag, type, element, newProps) {
|
||||
if (tag === 'Component') {
|
||||
if (
|
||||
type === 'input' &&
|
||||
newProps.type === 'radio' &&
|
||||
newProps.name !== null &&
|
||||
newProps.name !== undefined &&
|
||||
newProps.checked !== null &&
|
||||
newProps.checked !== undefined
|
||||
) {
|
||||
updateCommonProp(element as Element, 'checked', newProps.checked, true);
|
||||
}
|
||||
} else {
|
||||
if (element != null) {
|
||||
// text类型
|
||||
element.textContent = newProps;
|
||||
}
|
||||
}
|
||||
},
|
||||
shouldTriggerChangeEvent(targetElement, elementTag, evtName) {
|
||||
const {type} = targetElement
|
||||
if (elementTag === 'select' || (elementTag === 'input' && type === 'file')) {
|
||||
return evtName === 'change';
|
||||
} else if (elementTag === 'input' && (type === 'checkbox' || type === 'radio')) {
|
||||
if (evtName === 'click') {
|
||||
return updateInputHandlerIfChanged(targetElement);
|
||||
}
|
||||
} else if (targetElement.nodeType === this.elementConfig?.input.nodeType) {
|
||||
if (evtName === 'input' || evtName === 'change') {
|
||||
return updateInputHandlerIfChanged(targetElement);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
hideElement(tag, element) {
|
||||
hideElement(tag, element);
|
||||
},
|
||||
unHideElement(tag, element, props) {
|
||||
unHideElement(tag, element, props);
|
||||
},
|
||||
clearText(element) {
|
||||
clearText(element as Element);
|
||||
},
|
||||
appendChildElement(parent, child) {
|
||||
appendChildElement(parent as Element, child as Element | Text);
|
||||
},
|
||||
insertElementBefore(parent, child, beforeChild) {
|
||||
insertElementBefore(parent as Element, child as Element | Text, beforeChild as Element | Text);
|
||||
},
|
||||
removeChildElement(parent, child) {
|
||||
removeChildElement(parent as Element, child as Element | Text);
|
||||
},
|
||||
prepareForSubmit() {
|
||||
prepareForSubmit();
|
||||
},
|
||||
resetAfterSubmit() {
|
||||
resetAfterSubmit();
|
||||
},
|
||||
onPropInit(element, tagName, rawProps) {
|
||||
if (tagName === this.elementConfig?.input.nodeName || tagName === this.elementConfig?.textarea.nodeName) {
|
||||
// 增加监听value和checked的set、get方法
|
||||
watchValueChange(element);
|
||||
}
|
||||
|
||||
// 设置dom.value值,触发受控组件的set方法
|
||||
setInitValue(tagName, element as InulaDom, rawProps);
|
||||
},
|
||||
};
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
import { InulaDom } from './Interface';
|
||||
import { Props } from '../DOMOperator';
|
||||
|
||||
/**
|
||||
* 获取当前聚焦的 input 或者 textarea 元素
|
||||
|
|
@ -47,4 +48,43 @@ export function getIFrameFocusedDom() {
|
|||
}
|
||||
}
|
||||
return focusedDom;
|
||||
}
|
||||
}
|
||||
|
||||
export function isElement(dom) {
|
||||
return dom.nodeType === 1;
|
||||
}
|
||||
|
||||
export function isText(dom) {
|
||||
return dom.nodeType === 3;
|
||||
}
|
||||
|
||||
export function isComment(dom) {
|
||||
return dom.nodeType === 8;
|
||||
}
|
||||
|
||||
export function isDocument(dom) {
|
||||
return dom.nodeType === 9;
|
||||
}
|
||||
|
||||
export function isDocumentFragment(dom) {
|
||||
return dom.nodeType === 11;
|
||||
}
|
||||
|
||||
export function getDomTag(dom) {
|
||||
return dom.nodeName.toLowerCase();
|
||||
}
|
||||
|
||||
export function isInputElement(dom: Element): dom is HTMLInputElement {
|
||||
return getDomTag(dom) === 'input';
|
||||
}
|
||||
|
||||
const types = ['button', 'input', 'select', 'textarea'];
|
||||
|
||||
// button、input、select、textarea、如果有 autoFocus 属性需要focus
|
||||
export function shouldAutoFocus(tagName: string, props: Props): boolean {
|
||||
return types.includes(tagName) ? Boolean(props.autoFocus) : false;
|
||||
}
|
||||
|
||||
export function isNotNull(object: any): boolean {
|
||||
return object !== null && object !== undefined;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
import { getPropDetails, PropDetails, PROPERTY_TYPE } from './PropertiesData';
|
||||
import { isNativeElement } from './PropHandler';
|
||||
|
||||
const INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/;
|
||||
|
||||
const voidTagElements = [
|
||||
|
|
@ -36,6 +36,11 @@ const voidTagElements = [
|
|||
'menuitem',
|
||||
];
|
||||
|
||||
// 是内置元素
|
||||
export function isNativeElement(tagName: string, props: Record<string, any>) {
|
||||
return !tagName.includes('-') && props.is === undefined;
|
||||
}
|
||||
|
||||
function isInvalidBoolean(attributeName: string, value: any, propDetails: PropDetails): boolean {
|
||||
if (propDetails.type === PROPERTY_TYPE.SPECIAL) {
|
||||
return false;
|
||||
|
|
@ -14,8 +14,7 @@
|
|||
*/
|
||||
|
||||
import { Children } from '../../external/ChildrenUtil';
|
||||
// kb-tag
|
||||
import { Props } from '../../renderer/Types';
|
||||
import { Props } from '../utils/Interface';
|
||||
|
||||
// 把 const a = 'a'; <option>gir{a}ffe</option> 转成 giraffe
|
||||
function concatChildren(children) {
|
||||
|
|
|
|||
|
|
@ -13,16 +13,12 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
//kb-tag
|
||||
import { isNotNull } from '../../renderer/utils/common';
|
||||
import { updateInputValue } from './InputValueHandler';
|
||||
/**
|
||||
* Inula的输入框和文本框的change事件在原生的change事件上做了一层处理
|
||||
* 只有值发生变化时才会触发change事件。
|
||||
*/
|
||||
|
||||
import { HANDLER_KEY } from '../../renderer/utils/InternalKeys';
|
||||
import { Props } from '../../renderer/Types';
|
||||
import { HANDLER_KEY } from '../DOMInternalKeys';
|
||||
|
||||
// 判断是否是 check 类型
|
||||
function isCheckType(dom: HTMLInputElement): boolean {
|
||||
|
|
@ -95,46 +91,3 @@ export function updateInputHandlerIfChanged(dom) {
|
|||
|
||||
return false;
|
||||
}
|
||||
// export function controlInputValue(inputDom: Element, props: Props) {
|
||||
// const { name, type } = props;
|
||||
|
||||
// // 如果是 radio,找出同一form内,name相同的Radio,更新它们Handler的Value
|
||||
// if (type === 'radio' && isNotNull(name)) {
|
||||
// const radioList = document.querySelectorAll<HTMLInputElement>(`input[type="radio"][name="${name}"]`);
|
||||
// for (let i = 0; i < radioList.length; i++) {
|
||||
// const radio = radioList[i];
|
||||
// if (radio === inputDom) {
|
||||
// continue;
|
||||
// }
|
||||
// if (isNotNull(radio.form) && isNotNull(inputDom.form) && radio.form !== inputDom.form) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// updateInputHandlerIfChanged(radio);
|
||||
// }
|
||||
// } else {
|
||||
// updateInputValue(inputDom, props);
|
||||
// }
|
||||
// }
|
||||
|
||||
export function controlInputValue(inputDom: HTMLInputElement, props: Props) {
|
||||
const { name, type } = props;
|
||||
|
||||
// 如果是 radio,找出同一form内,name相同的Radio,更新它们Handler的Value
|
||||
if (type === 'radio' && isNotNull(name)) {
|
||||
const radioList = document.querySelectorAll<HTMLInputElement>(`input[type="radio"][name="${name}"]`);
|
||||
for (let i = 0; i < radioList.length; i++) {
|
||||
const radio = radioList[i];
|
||||
if (radio === inputDom) {
|
||||
continue;
|
||||
}
|
||||
if (isNotNull(radio.form) && isNotNull(inputDom.form) && radio.form !== inputDom.form) {
|
||||
continue;
|
||||
}
|
||||
|
||||
updateInputHandlerIfChanged(radio);
|
||||
}
|
||||
} else {
|
||||
updateInputValue(inputDom, props);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,13 +17,12 @@
|
|||
* 事件绑定实现,分为绑定委托事件和非委托事件
|
||||
*/
|
||||
import { allDelegatedInulaEvents, portalDefaultDelegatedEvents, simulatedDelegatedEvents } from './EventHub';
|
||||
import { EVENT_KEY, getNearestVNode, getNonDelegatedListenerMap } from '../renderer/utils/InternalKeys';
|
||||
import { isDocument } from '../dom/utils/Common';
|
||||
import { EVENT_KEY, getNearestVNode, getNonDelegatedListenerMap } from '../dom/DOMInternalKeys';
|
||||
import { asyncUpdates, runDiscreteUpdates } from '../renderer/TreeBuilder';
|
||||
import { handleEventMain } from './InulaEventMain';
|
||||
import { decorateNativeEvent } from './EventWrapper';
|
||||
import { VNode } from '../renderer/vnode/VNode';
|
||||
import { ElementType } from '../renderer/Types';
|
||||
import { InulaReconciler } from '../renderer';
|
||||
|
||||
// 触发委托事件
|
||||
function triggerDelegatedEvent(
|
||||
|
|
@ -42,15 +41,15 @@ function triggerDelegatedEvent(
|
|||
}
|
||||
|
||||
// 监听委托事件
|
||||
function listenToNativeEvent(nativeEvtName: string, delegatedElement: ElementType, isCapture: boolean) {
|
||||
let element: ElementType = delegatedElement;
|
||||
function listenToNativeEvent(nativeEvtName: string, delegatedElement: Element, isCapture: boolean) {
|
||||
let dom: Element | Document = delegatedElement;
|
||||
// document层次可能触发selectionchange事件,为了捕获这类事件,selectionchange事件绑定在document节点上
|
||||
if (nativeEvtName === 'selectionchange') {
|
||||
element = delegatedElement.ownerDocument;
|
||||
if (nativeEvtName === 'selectionchange' && !isDocument(delegatedElement)) {
|
||||
dom = delegatedElement.ownerDocument;
|
||||
}
|
||||
|
||||
const listener = triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, element);
|
||||
InulaReconciler.hostConfig.addEventListener(element, nativeEvtName, listener, isCapture);
|
||||
const listener = triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, dom);
|
||||
dom.addEventListener(nativeEvtName, listener, isCapture);
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
|
@ -122,15 +121,15 @@ function getWrapperListener(inulaEventName, nativeEvtName, targetElement, listen
|
|||
}
|
||||
|
||||
// 非委托事件单独监听到各自dom节点
|
||||
export function listenNonDelegatedEvent(inulaEventName: string, element: ElementType, listener): void {
|
||||
export function listenNonDelegatedEvent(inulaEventName: string, domElement: Element, listener): void {
|
||||
const isCapture = isCaptureEvent(inulaEventName);
|
||||
const nativeEvtName = getNativeEvtName(inulaEventName, isCapture);
|
||||
|
||||
// 先判断是否存在老的监听事件,若存在则移除
|
||||
const nonDelegatedListenerMap = getNonDelegatedListenerMap(element);
|
||||
const nonDelegatedListenerMap = getNonDelegatedListenerMap(domElement);
|
||||
const currentListener = nonDelegatedListenerMap.get(inulaEventName);
|
||||
if (currentListener) {
|
||||
InulaReconciler.hostConfig.removeEventListener(element, nativeEvtName, currentListener);
|
||||
domElement.removeEventListener(nativeEvtName, currentListener);
|
||||
nonDelegatedListenerMap.delete(inulaEventName);
|
||||
}
|
||||
|
||||
|
|
@ -139,8 +138,8 @@ export function listenNonDelegatedEvent(inulaEventName: string, element: Element
|
|||
}
|
||||
|
||||
// 为了和委托事件对外行为一致,将事件对象封装成CustomBaseEvent
|
||||
const wrapperListener = getWrapperListener(inulaEventName, nativeEvtName, element, listener);
|
||||
const wrapperListener = getWrapperListener(inulaEventName, nativeEvtName, domElement, listener);
|
||||
// 添加新的监听
|
||||
nonDelegatedListenerMap.set(inulaEventName, wrapperListener);
|
||||
InulaReconciler.hostConfig.addEventListener(element, nativeEvtName, wrapperListener, isCapture);
|
||||
domElement.addEventListener(nativeEvtName, wrapperListener, isCapture);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,12 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { getVNodeProps } from '../renderer/utils/InternalKeys';
|
||||
import { getTag } from '../renderer/utils/common';
|
||||
import { InulaReconciler } from '../renderer';
|
||||
import { ElementType } from '../renderer/Types';
|
||||
import { getVNodeProps } from '../dom/DOMInternalKeys';
|
||||
import { getDomTag, isNotNull } from '../dom/utils/Common';
|
||||
import { Props } from '../dom/utils/Interface';
|
||||
import { updateTextareaValue } from '../dom/valueHandler/TextareaValueHandler';
|
||||
import { updateInputHandlerIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||
import { updateInputValue } from '../dom/valueHandler/InputValueHandler';
|
||||
|
||||
// 记录表单控件 input/textarea/select的onChange事件的targets
|
||||
let changeEventTargets: Array<any> | null = null;
|
||||
|
|
@ -35,12 +37,43 @@ export function shouldControlValue(): boolean {
|
|||
return changeEventTargets !== null && changeEventTargets.length > 0;
|
||||
}
|
||||
|
||||
function controlInputValue(inputDom: HTMLInputElement, props: Props) {
|
||||
const { name, type } = props;
|
||||
|
||||
// 如果是 radio,找出同一form内,name相同的Radio,更新它们Handler的Value
|
||||
if (type === 'radio' && isNotNull(name)) {
|
||||
const radioList = document.querySelectorAll<HTMLInputElement>(`input[type="radio"][name="${name}"]`);
|
||||
for (let i = 0; i < radioList.length; i++) {
|
||||
const radio = radioList[i];
|
||||
if (radio === inputDom) {
|
||||
continue;
|
||||
}
|
||||
if (isNotNull(radio.form) && isNotNull(inputDom.form) && radio.form !== inputDom.form) {
|
||||
continue;
|
||||
}
|
||||
|
||||
updateInputHandlerIfChanged(radio);
|
||||
}
|
||||
} else {
|
||||
updateInputValue(inputDom, props);
|
||||
}
|
||||
}
|
||||
|
||||
// 受控组件值重新赋值
|
||||
function controlValue(target: ElementType) {
|
||||
function controlValue(target: Element) {
|
||||
const props = getVNodeProps(target);
|
||||
if (props) {
|
||||
const type = getTag(target);
|
||||
InulaReconciler.hostConfig.handleControledInputElements(target, type ?? '', props);
|
||||
const type = getDomTag(target);
|
||||
switch (type) {
|
||||
case 'input':
|
||||
controlInputValue(<HTMLInputElement>target, props);
|
||||
break;
|
||||
case 'textarea':
|
||||
updateTextareaValue(<HTMLTextAreaElement>target, props);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
import { AnyNativeEvent, ListenerUnitList } from './Types';
|
||||
import type { VNode } from '../renderer/Types';
|
||||
import { setPropertyWritable } from './utils';
|
||||
import { isInputElement, setPropertyWritable } from './utils';
|
||||
import { decorateNativeEvent } from './EventWrapper';
|
||||
import { getListenersFromTree } from './ListenerGetter';
|
||||
import { asyncUpdates, runDiscreteUpdates } from '../renderer/Renderer';
|
||||
|
|
@ -27,11 +27,11 @@ import {
|
|||
inulaEventToNativeMap,
|
||||
transformToInulaEvent,
|
||||
} from './EventHub';
|
||||
import { getTag } from '../renderer/utils/common';
|
||||
import { getElement } from '../renderer/utils/InternalKeys';
|
||||
import { getDomTag } from '../dom/utils/Common';
|
||||
import { updateInputHandlerIfChanged } from '../dom/valueHandler/ValueChangeHandler';
|
||||
import { getDom } from '../dom/DOMInternalKeys';
|
||||
import { recordChangeEventTargets, shouldControlValue, tryControlValue } from './FormValueController';
|
||||
import { getMouseEnterListeners } from './MouseEvent';
|
||||
import { InulaReconciler } from '../renderer';
|
||||
|
||||
// web规范,鼠标右键key值
|
||||
const RIGHT_MOUSE_BUTTON = 2;
|
||||
|
|
@ -42,9 +42,22 @@ const RIGHT_MOUSE_BUTTON = 2;
|
|||
// | <select/> / <input type="file/> | change | NO |
|
||||
// | <input type="checkbox" /> <input type="radio" /> | click | YES |
|
||||
// | <input type="input /> / <input type="text" /> | input / change | YES |
|
||||
function shouldTriggerChangeEvent(targetElement, evtName) {
|
||||
const elementTag = getTag(targetElement);
|
||||
return InulaReconciler.hostConfig.shouldTriggerChangeEvent(targetElement, elementTag ?? '', evtName);
|
||||
function shouldTriggerChangeEvent(targetDom, evtName) {
|
||||
const { type } = targetDom;
|
||||
const domTag = getDomTag(targetDom);
|
||||
|
||||
if (domTag === 'select' || (domTag === 'input' && type === 'file')) {
|
||||
return evtName === 'change';
|
||||
} else if (domTag === 'input' && (type === 'checkbox' || type === 'radio')) {
|
||||
if (evtName === 'click') {
|
||||
return updateInputHandlerIfChanged(targetDom);
|
||||
}
|
||||
} else if (isInputElement(targetDom)) {
|
||||
if (evtName === 'input' || evtName === 'change') {
|
||||
return updateInputHandlerIfChanged(targetDom);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -60,7 +73,7 @@ function getChangeListeners(
|
|||
if (!vNode) {
|
||||
return [];
|
||||
}
|
||||
const targetDom = getElement(vNode);
|
||||
const targetDom = getDom(vNode);
|
||||
|
||||
// 判断是否需要触发change事件
|
||||
if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
import { VNode } from '../renderer/Types';
|
||||
import { Component } from '../renderer/vnode/VNodeTags';
|
||||
import { DomComponent } from '../renderer/vnode/VNodeTags';
|
||||
import { WrappedEvent } from './EventWrapper';
|
||||
import { InulaEventListener, ListenerUnitList } from './Types';
|
||||
import { EVENT_TYPE_ALL, EVENT_TYPE_BUBBLE, EVENT_TYPE_CAPTURE } from './EventHub';
|
||||
|
|
@ -55,7 +55,7 @@ export function getListenersFromTree(
|
|||
// 从目标节点到根节点遍历获取listener
|
||||
while (vNode !== null) {
|
||||
const { realNode, tag } = vNode;
|
||||
if (tag === Component && realNode !== null) {
|
||||
if (tag === DomComponent && realNode !== null) {
|
||||
if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_CAPTURE) {
|
||||
const captureName = inulaEvtName + EVENT_TYPE_CAPTURE;
|
||||
const captureListener = getListenerFromVNode(vNode, captureName);
|
||||
|
|
@ -94,7 +94,7 @@ function getParent(inst: VNode | null): VNode | null {
|
|||
}
|
||||
do {
|
||||
inst = inst.parent;
|
||||
} while (inst && inst.tag !== Component);
|
||||
} while (inst && inst.tag !== DomComponent);
|
||||
return inst || null;
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ function getMouseListenersFromTree(event: WrappedEvent, target: VNode, commonPar
|
|||
break;
|
||||
}
|
||||
const { realNode, tag } = vNode;
|
||||
if (tag === Component && realNode !== null) {
|
||||
if (tag === DomComponent && realNode !== null) {
|
||||
const currentTarget = realNode;
|
||||
const listener = getListenerFromVNode(vNode, registrationName);
|
||||
if (listener) {
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { getNearestVNode, getVNode } from '../renderer/utils/InternalKeys';
|
||||
import { getNearestVNode, getVNode } from '../dom/DOMInternalKeys';
|
||||
import { WrappedEvent } from './EventWrapper';
|
||||
import { VNode } from '../renderer/vnode/VNode';
|
||||
import { AnyNativeEvent, ListenerUnitList } from './Types';
|
||||
import { Component, Text } from '../renderer/vnode/VNodeTags';
|
||||
import { DomComponent, DomText } from '../renderer/vnode/VNodeTags';
|
||||
import { collectMouseListeners } from './ListenerGetter';
|
||||
import { getNearestMountedVNode } from './utils';
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ function getEndpointVNode(
|
|||
toVNode = related ? getNearestVNode(related) : null;
|
||||
if (toVNode !== null) {
|
||||
const nearestMounted = getNearestMountedVNode(toVNode);
|
||||
if (toVNode !== nearestMounted || (toVNode.tag !== Component && toVNode.tag !== Text)) {
|
||||
if (toVNode !== nearestMounted || (toVNode.tag !== DomComponent && toVNode.tag !== DomText)) {
|
||||
toVNode = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,30 @@ import { TYPE_COMMON_ELEMENT } from './JSXElementType';
|
|||
import { getProcessingClassVNode } from '../renderer/GlobalVar';
|
||||
import { Source } from '../renderer/Types';
|
||||
import { BELONG_CLASS_VNODE_KEY } from '../renderer/vnode/VNode';
|
||||
import { InulaElement, KVObject } from '../types';
|
||||
import {
|
||||
Attributes,
|
||||
ClassAttributes,
|
||||
ClassType,
|
||||
ClassicComponent,
|
||||
ClassicComponentClass,
|
||||
ComponentClass,
|
||||
ComponentState,
|
||||
FunctionComponentElement,
|
||||
InulaCElement,
|
||||
InulaElement,
|
||||
InulaNode,
|
||||
KVObject,
|
||||
} from '../types';
|
||||
import { Component } from '../renderer/components/BaseClassComponent';
|
||||
import { DOMAttributes, HTMLAttributes, InputHTMLAttributes, SVGAttributes } from '../jsx-type/baseAttr';
|
||||
import {
|
||||
DOMElement,
|
||||
DetailedInulaHTMLElement,
|
||||
InulaHTML,
|
||||
InulaHTMLElement,
|
||||
InulaSVG,
|
||||
InulaSVGElement,
|
||||
} from '../jsx-type';
|
||||
|
||||
/**
|
||||
* vtype 节点的类型,这里固定是element
|
||||
|
|
@ -109,11 +132,82 @@ function buildElement(isClone, type, setting, children) {
|
|||
return JSXElement(element, key, ref, vNode, props, src);
|
||||
}
|
||||
|
||||
export function createElement(
|
||||
type: 'input',
|
||||
props?: (InputHTMLAttributes<HTMLInputElement> & ClassAttributes<HTMLInputElement>) | null,
|
||||
...children: InulaNode[]
|
||||
): DetailedInulaHTMLElement<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
||||
|
||||
export function createElement<P extends HTMLAttributes<T>, T extends HTMLElement>(
|
||||
type: keyof InulaHTML,
|
||||
props?: (ClassAttributes<T> & P) | null,
|
||||
...children: InulaNode[]
|
||||
): DetailedInulaHTMLElement<P, T>;
|
||||
|
||||
export function createElement<P extends SVGAttributes<T>, T extends SVGElement>(
|
||||
type: keyof InulaSVG,
|
||||
props?: (ClassAttributes<T> & P) | null,
|
||||
...children: InulaNode[]
|
||||
): InulaSVGElement;
|
||||
|
||||
export function createElement<P extends DOMAttributes<T>, T extends Element>(
|
||||
type: string,
|
||||
props?: (ClassAttributes<T> & P) | null,
|
||||
...children: InulaNode[]
|
||||
): DOMElement<P, T>;
|
||||
|
||||
export function createElement<P extends KVObject>(
|
||||
type: ClassType<P, ClassicComponent<P, ComponentState>, ClassicComponentClass<P>>,
|
||||
props?: (ClassAttributes<ClassicComponent<P, ComponentState>> & P) | null,
|
||||
...children: InulaNode[]
|
||||
): InulaCElement<P, ClassicComponent<P, ComponentState>>;
|
||||
export function createElement<P extends KVObject, T extends Component<P, ComponentState>, C extends ComponentClass<P>>(
|
||||
type: ClassType<P, T, C>,
|
||||
props?: (ClassAttributes<T> & P) | null,
|
||||
...children: InulaNode[]
|
||||
): InulaCElement<P, T>;
|
||||
|
||||
// 创建Element结构体,供JSX编译时调用
|
||||
export function createElement(type, setting, ...children) {
|
||||
return buildElement(false, type, setting, children);
|
||||
}
|
||||
|
||||
export function cloneElement<P extends HTMLAttributes<T>, T extends HTMLElement>(
|
||||
element: DetailedInulaHTMLElement<P, T>,
|
||||
props?: P,
|
||||
...children: InulaNode[]
|
||||
): DetailedInulaHTMLElement<P, T>;
|
||||
export function cloneElement<P extends HTMLAttributes<T>, T extends HTMLElement>(
|
||||
element: InulaHTMLElement<T>,
|
||||
props?: P,
|
||||
...children: InulaNode[]
|
||||
): InulaHTMLElement<T>;
|
||||
export function cloneElement<P extends SVGAttributes<T>, T extends SVGElement>(
|
||||
element: InulaSVGElement,
|
||||
props?: P,
|
||||
...children: InulaNode[]
|
||||
): InulaSVGElement;
|
||||
export function cloneElement<P extends DOMAttributes<T>, T extends Element>(
|
||||
element: DOMElement<P, T>,
|
||||
props?: DOMAttributes<T> & P,
|
||||
...children: InulaNode[]
|
||||
): DOMElement<P, T>;
|
||||
export function cloneElement<P>(
|
||||
element: FunctionComponentElement<P>,
|
||||
props?: Partial<P> & Attributes,
|
||||
...children: InulaNode[]
|
||||
): FunctionComponentElement<P>;
|
||||
export function cloneElement<P, T extends Component<P, ComponentState>>(
|
||||
element: InulaCElement<P, T>,
|
||||
props?: Partial<P> & ClassAttributes<T>,
|
||||
...children: InulaNode[]
|
||||
): InulaCElement<P, T>;
|
||||
export function cloneElement<P>(
|
||||
element: InulaElement<P>,
|
||||
props?: Partial<P> & Attributes,
|
||||
...children: InulaNode[]
|
||||
): InulaElement<P>;
|
||||
|
||||
export function cloneElement(element, setting, ...children) {
|
||||
return buildElement(true, element, setting, children);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { travelVNodeTree } from '../renderer/vnode/VNodeUtils';
|
|||
import { Hook, Reducer, MutableRef, Effect, CallBack, Memo } from '../renderer/hooks/HookType';
|
||||
import { VNode } from '../renderer/vnode/VNode';
|
||||
import { launchUpdateFromVNode } from '../renderer/TreeBuilder';
|
||||
import { Component } from '../renderer/vnode/VNodeTags';
|
||||
import { DomComponent } from '../renderer/vnode/VNodeTags';
|
||||
import { getElementTag } from '../renderer/vnode/VNodeCreator';
|
||||
import { JSXElement } from '../renderer/Types';
|
||||
import { EffectConstant } from '../renderer/hooks/EffectConstant';
|
||||
|
|
@ -108,7 +108,7 @@ export const helper = {
|
|||
travelVNodeTree(
|
||||
vNode,
|
||||
(node: VNode) => {
|
||||
if (node.tag === Component) {
|
||||
if (node.tag === DomComponent) {
|
||||
// 找到组件的第一个dom元素,返回它所在父节点的全部子节点
|
||||
const dom = node.realNode;
|
||||
info['Nodes'] = dom?.parentNode?.childNodes;
|
||||
|
|
|
|||
|
|
@ -59,23 +59,20 @@ import { createStore, useStore, clearStore } from './inulax/store/StoreHandler';
|
|||
import * as reduxAdapter from './inulax/adapters/redux';
|
||||
import { watch } from './inulax/proxy/watch';
|
||||
import { act } from './external/TestUtil';
|
||||
import { defaultHostConfig } from './dom';
|
||||
|
||||
import {
|
||||
render,
|
||||
createPortal,
|
||||
unstable_batchedUpdates,
|
||||
findNode as findDOMNode,
|
||||
findDOMNode,
|
||||
unmountComponentAtNode,
|
||||
createRoot,
|
||||
} from './renderer/External';
|
||||
} from './dom/DOMExternal';
|
||||
|
||||
import { syncUpdates as flushSync } from './renderer/TreeBuilder';
|
||||
import { toRaw } from './inulax/proxy/ProxyHandler';
|
||||
import { InulaReconciler } from './renderer';
|
||||
|
||||
const version = __VERSION__;
|
||||
// 使用默认renderer
|
||||
InulaReconciler.setHostConfig(defaultHostConfig);
|
||||
|
||||
const Inula = {
|
||||
Children,
|
||||
|
|
@ -188,4 +185,3 @@ export {
|
|||
|
||||
export * from './types';
|
||||
export default Inula;
|
||||
export { InulaReconciler };
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { unstable_batchedUpdates } from '../../renderer/External';
|
||||
import { unstable_batchedUpdates } from '../../dom/DOMExternal';
|
||||
import { ReduxStoreHandler } from './redux';
|
||||
|
||||
type LinkListNode<T> = {
|
||||
|
|
@ -161,7 +161,7 @@ function createSubscription(store: ReduxStoreHandler, parentSub: Subscription |
|
|||
|
||||
function trySubscribe() {
|
||||
if (!unsubscribe) {
|
||||
// <EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>store<EFBFBD>ı仯<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ѿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>Ƕ<EFBFBD>Ķ<EFBFBD><EFBFBD>ġ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>Ӷ<EFBFBD><EFBFBD><EFBFBD>store<EFBFBD><EFBFBD>
|
||||
// 尝试订阅store的变化。如果已经存在一个订阅,那么它会添加一个嵌套的订阅。否则,它会直接订阅store。
|
||||
unsubscribe = parentSub ? parentSub.addNestedSub(storeChangeHandler) : store.subscribe(storeChangeHandler);
|
||||
listenerStore = getListenerManager();
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,119 @@
|
|||
export interface HTMLElement extends Element {}
|
||||
export interface HTMLAnchorElement extends HTMLElement {}
|
||||
export interface HTMLAreaElement extends HTMLElement {}
|
||||
export interface HTMLAudioElement extends HTMLElement {}
|
||||
export interface HTMLBaseElement extends HTMLElement {}
|
||||
export interface HTMLBodyElement extends HTMLElement {}
|
||||
export interface HTMLBRElement extends HTMLElement {}
|
||||
export interface HTMLButtonElement extends HTMLElement {}
|
||||
export interface HTMLCanvasElement extends HTMLElement {}
|
||||
export interface HTMLDataElement extends HTMLElement {}
|
||||
export interface HTMLDataListElement extends HTMLElement {}
|
||||
export interface HTMLDetailsElement extends HTMLElement {}
|
||||
export interface HTMLDialogElement extends HTMLElement {}
|
||||
export interface HTMLDivElement extends HTMLElement {}
|
||||
export interface HTMLDListElement extends HTMLElement {}
|
||||
export interface HTMLEmbedElement extends HTMLElement {}
|
||||
export interface HTMLFieldSetElement extends HTMLElement {}
|
||||
export interface HTMLFormElement extends HTMLElement {}
|
||||
export interface HTMLHeadingElement extends HTMLElement {}
|
||||
export interface HTMLHeadElement extends HTMLElement {}
|
||||
export interface HTMLHRElement extends HTMLElement {}
|
||||
export interface HTMLHtmlElement extends HTMLElement {}
|
||||
export interface HTMLIFrameElement extends HTMLElement {}
|
||||
export interface HTMLImageElement extends HTMLElement {}
|
||||
export interface HTMLInputElement extends HTMLElement {}
|
||||
export interface HTMLModElement extends HTMLElement {}
|
||||
export interface HTMLLabelElement extends HTMLElement {}
|
||||
export interface HTMLLegendElement extends HTMLElement {}
|
||||
export interface HTMLLIElement extends HTMLElement {}
|
||||
export interface HTMLLinkElement extends HTMLElement {}
|
||||
export interface HTMLMapElement extends HTMLElement {}
|
||||
export interface HTMLMetaElement extends HTMLElement {}
|
||||
export interface HTMLMeterElement extends HTMLElement {}
|
||||
export interface HTMLObjectElement extends HTMLElement {}
|
||||
export interface HTMLOListElement extends HTMLElement {}
|
||||
export interface HTMLOptGroupElement extends HTMLElement {}
|
||||
export interface HTMLOptionElement extends HTMLElement {}
|
||||
export interface HTMLOutputElement extends HTMLElement {}
|
||||
export interface HTMLParagraphElement extends HTMLElement {}
|
||||
export interface HTMLParamElement extends HTMLElement {}
|
||||
export interface HTMLPreElement extends HTMLElement {}
|
||||
export interface HTMLProgressElement extends HTMLElement {}
|
||||
export interface HTMLQuoteElement extends HTMLElement {}
|
||||
export interface HTMLSlotElement extends HTMLElement {}
|
||||
export interface HTMLScriptElement extends HTMLElement {}
|
||||
export interface HTMLSelectElement extends HTMLElement {}
|
||||
export interface HTMLSourceElement extends HTMLElement {}
|
||||
export interface HTMLSpanElement extends HTMLElement {}
|
||||
export interface HTMLStyleElement extends HTMLElement {}
|
||||
export interface HTMLTableElement extends HTMLElement {}
|
||||
export interface HTMLTableColElement extends HTMLElement {}
|
||||
export interface HTMLTableDataCellElement extends HTMLElement {}
|
||||
export interface HTMLTableHeaderCellElement extends HTMLElement {}
|
||||
export interface HTMLTableRowElement extends HTMLElement {}
|
||||
export interface HTMLTableSectionElement extends HTMLElement {}
|
||||
export interface HTMLTemplateElement extends HTMLElement {}
|
||||
export interface HTMLTextAreaElement extends HTMLElement {}
|
||||
export interface HTMLTimeElement extends HTMLElement {}
|
||||
export interface HTMLTitleElement extends HTMLElement {}
|
||||
export interface HTMLTrackElement extends HTMLElement {}
|
||||
export interface HTMLUListElement extends HTMLElement {}
|
||||
export interface HTMLVideoElement extends HTMLElement {}
|
||||
export interface HTMLWebViewElement extends HTMLElement {}
|
||||
|
||||
export interface SVGElement extends Element {}
|
||||
export interface SVGSVGElement extends SVGElement {}
|
||||
export interface SVGCircleElement extends SVGElement {}
|
||||
export interface SVGClipPathElement extends SVGElement {}
|
||||
export interface SVGDefsElement extends SVGElement {}
|
||||
export interface SVGDescElement extends SVGElement {}
|
||||
export interface SVGEllipseElement extends SVGElement {}
|
||||
export interface SVGFEBlendElement extends SVGElement {}
|
||||
export interface SVGFEColorMatrixElement extends SVGElement {}
|
||||
export interface SVGFEComponentTransferElement extends SVGElement {}
|
||||
export interface SVGFECompositeElement extends SVGElement {}
|
||||
export interface SVGFEConvolveMatrixElement extends SVGElement {}
|
||||
export interface SVGFEDiffuseLightingElement extends SVGElement {}
|
||||
export interface SVGFEDisplacementMapElement extends SVGElement {}
|
||||
export interface SVGFEDistantLightElement extends SVGElement {}
|
||||
export interface SVGFEDropShadowElement extends SVGElement {}
|
||||
export interface SVGFEFloodElement extends SVGElement {}
|
||||
export interface SVGFEFuncAElement extends SVGElement {}
|
||||
export interface SVGFEFuncBElement extends SVGElement {}
|
||||
export interface SVGFEFuncGElement extends SVGElement {}
|
||||
export interface SVGFEFuncRElement extends SVGElement {}
|
||||
export interface SVGFEGaussianBlurElement extends SVGElement {}
|
||||
export interface SVGFEImageElement extends SVGElement {}
|
||||
export interface SVGFEMergeElement extends SVGElement {}
|
||||
export interface SVGFEMergeNodeElement extends SVGElement {}
|
||||
export interface SVGFEMorphologyElement extends SVGElement {}
|
||||
export interface SVGFEOffsetElement extends SVGElement {}
|
||||
export interface SVGFEPointLightElement extends SVGElement {}
|
||||
export interface SVGFESpecularLightingElement extends SVGElement {}
|
||||
export interface SVGFESpotLightElement extends SVGElement {}
|
||||
export interface SVGFETileElement extends SVGElement {}
|
||||
export interface SVGFETurbulenceElement extends SVGElement {}
|
||||
export interface SVGFilterElement extends SVGElement {}
|
||||
export interface SVGForeignObjectElement extends SVGElement {}
|
||||
export interface SVGGElement extends SVGElement {}
|
||||
export interface SVGImageElement extends SVGElement {}
|
||||
export interface SVGLineElement extends SVGElement {}
|
||||
export interface SVGLinearGradientElement extends SVGElement {}
|
||||
export interface SVGMarkerElement extends SVGElement {}
|
||||
export interface SVGMaskElement extends SVGElement {}
|
||||
export interface SVGMetadataElement extends SVGElement {}
|
||||
export interface SVGPathElement extends SVGElement {}
|
||||
export interface SVGPatternElement extends SVGElement {}
|
||||
export interface SVGPolygonElement extends SVGElement {}
|
||||
export interface SVGPolylineElement extends SVGElement {}
|
||||
export interface SVGRadialGradientElement extends SVGElement {}
|
||||
export interface SVGRectElement extends SVGElement {}
|
||||
export interface SVGStopElement extends SVGElement {}
|
||||
export interface SVGSwitchElement extends SVGElement {}
|
||||
export interface SVGSymbolElement extends SVGElement {}
|
||||
export interface SVGTextElement extends SVGElement {}
|
||||
export interface SVGTextPathElement extends SVGElement {}
|
||||
export interface SVGTSpanElement extends SVGElement {}
|
||||
export interface SVGUseElement extends SVGElement {}
|
||||
export interface SVGViewElement extends SVGElement {}
|
||||
|
|
@ -0,0 +1,448 @@
|
|||
import { ClassAttributes, InulaElement, InulaNode, LegacyRef } from '../types';
|
||||
import {
|
||||
AllHTMLAttributes,
|
||||
AnchorHTMLAttributes,
|
||||
AreaHTMLAttributes,
|
||||
AudioHTMLAttributes,
|
||||
BaseHTMLAttributes,
|
||||
BlockquoteHTMLAttributes,
|
||||
ButtonHTMLAttributes,
|
||||
CanvasHTMLAttributes,
|
||||
ColHTMLAttributes,
|
||||
ColgroupHTMLAttributes,
|
||||
DOMAttributes,
|
||||
DataHTMLAttributes,
|
||||
DelHTMLAttributes,
|
||||
DetailsHTMLAttributes,
|
||||
DialogHTMLAttributes,
|
||||
EmbedHTMLAttributes,
|
||||
FieldsetHTMLAttributes,
|
||||
FormHTMLAttributes,
|
||||
HTMLAttributes,
|
||||
HtmlHTMLAttributes,
|
||||
IframeHTMLAttributes,
|
||||
ImgHTMLAttributes,
|
||||
InputHTMLAttributes,
|
||||
InsHTMLAttributes,
|
||||
KeygenHTMLAttributes,
|
||||
LabelHTMLAttributes,
|
||||
LiHTMLAttributes,
|
||||
LinkHTMLAttributes,
|
||||
MapHTMLAttributes,
|
||||
MenuHTMLAttributes,
|
||||
MetaHTMLAttributes,
|
||||
MeterHTMLAttributes,
|
||||
ObjectHTMLAttributes,
|
||||
OlHTMLAttributes,
|
||||
OptgroupHTMLAttributes,
|
||||
OptionHTMLAttributes,
|
||||
OutputHTMLAttributes,
|
||||
ParamHTMLAttributes,
|
||||
ProgressHTMLAttributes,
|
||||
QuoteHTMLAttributes,
|
||||
SVGAttributes,
|
||||
InulaSVGProps,
|
||||
ScriptHTMLAttributes,
|
||||
SelectHTMLAttributes,
|
||||
SlotHTMLAttributes,
|
||||
SourceHTMLAttributes,
|
||||
StyleHTMLAttributes,
|
||||
TableHTMLAttributes,
|
||||
TdHTMLAttributes,
|
||||
TextareaHTMLAttributes,
|
||||
ThHTMLAttributes,
|
||||
TimeHTMLAttributes,
|
||||
TrackHTMLAttributes,
|
||||
VideoHTMLAttributes,
|
||||
WebViewHTMLAttributes,
|
||||
} from './baseAttr';
|
||||
import { HTMLWebViewElement } from './baseElement';
|
||||
|
||||
type DOMFactory<P extends DOMAttributes<T>, T extends Element> = (
|
||||
props?: (ClassAttributes<T> & P) | null,
|
||||
...children: InulaNode[]
|
||||
) => DOMElement<P, T>;
|
||||
|
||||
interface InulaHTMLFactory<P extends HTMLAttributes<T>, T extends HTMLElement> extends DOMFactory<P, T> {
|
||||
(props?: (ClassAttributes<T> & P) | null, ...children: InulaNode[]): DetailedInulaHTMLElement<P, T>;
|
||||
}
|
||||
|
||||
export interface InulaHTMLElement<T extends HTMLElement> extends DetailedInulaHTMLElement<AllHTMLAttributes<T>, T> {}
|
||||
|
||||
export interface DOMElement<P extends HTMLAttributes<T> | SVGAttributes<T>, T extends Element>
|
||||
extends InulaElement<P, string> {
|
||||
ref: LegacyRef<T>;
|
||||
}
|
||||
|
||||
export interface InulaSVGElement extends DOMElement<SVGAttributes<SVGElement>, SVGElement> {
|
||||
type: keyof InulaSVG;
|
||||
}
|
||||
|
||||
export interface InulaSVG {
|
||||
animate: InulaSVGFactory;
|
||||
circle: InulaSVGFactory;
|
||||
clipPath: InulaSVGFactory;
|
||||
defs: InulaSVGFactory;
|
||||
desc: InulaSVGFactory;
|
||||
ellipse: InulaSVGFactory;
|
||||
feBlend: InulaSVGFactory;
|
||||
feColorMatrix: InulaSVGFactory;
|
||||
feComponentTransfer: InulaSVGFactory;
|
||||
feComposite: InulaSVGFactory;
|
||||
feConvolveMatrix: InulaSVGFactory;
|
||||
feDiffuseLighting: InulaSVGFactory;
|
||||
feDisplacementMap: InulaSVGFactory;
|
||||
feDistantLight: InulaSVGFactory;
|
||||
feDropShadow: InulaSVGFactory;
|
||||
feFlood: InulaSVGFactory;
|
||||
feFuncA: InulaSVGFactory;
|
||||
feFuncB: InulaSVGFactory;
|
||||
feFuncG: InulaSVGFactory;
|
||||
feFuncR: InulaSVGFactory;
|
||||
feImage: InulaSVGFactory;
|
||||
feGaussianBlur: InulaSVGFactory;
|
||||
feMerge: InulaSVGFactory;
|
||||
feMergeNode: InulaSVGFactory;
|
||||
feMorphology: InulaSVGFactory;
|
||||
feOffset: InulaSVGFactory;
|
||||
fePointLight: InulaSVGFactory;
|
||||
feSpecularLighting: InulaSVGFactory;
|
||||
feSpotLight: InulaSVGFactory;
|
||||
feTile: InulaSVGFactory;
|
||||
feTurbulence: InulaSVGFactory;
|
||||
filter: InulaSVGFactory;
|
||||
foreignObject: InulaSVGFactory;
|
||||
g: InulaSVGFactory;
|
||||
image: InulaSVGFactory;
|
||||
line: InulaSVGFactory;
|
||||
linearGradient: InulaSVGFactory;
|
||||
marker: InulaSVGFactory;
|
||||
mask: InulaSVGFactory;
|
||||
view: InulaSVGFactory;
|
||||
metadata: InulaSVGFactory;
|
||||
path: InulaSVGFactory;
|
||||
pattern: InulaSVGFactory;
|
||||
polygon: InulaSVGFactory;
|
||||
polyline: InulaSVGFactory;
|
||||
radialGradient: InulaSVGFactory;
|
||||
rect: InulaSVGFactory;
|
||||
stop: InulaSVGFactory;
|
||||
svg: InulaSVGFactory;
|
||||
switch: InulaSVGFactory;
|
||||
symbol: InulaSVGFactory;
|
||||
text: InulaSVGFactory;
|
||||
textPath: InulaSVGFactory;
|
||||
tspan: InulaSVGFactory;
|
||||
use: InulaSVGFactory;
|
||||
}
|
||||
|
||||
interface InulaSVGFactory extends DOMFactory<SVGAttributes<SVGElement>, SVGElement> {
|
||||
(props?: (ClassAttributes<SVGElement> & SVGAttributes<SVGElement>) | null, ...children: InulaNode[]): InulaSVGElement;
|
||||
}
|
||||
|
||||
export interface DetailedInulaHTMLElement<P extends HTMLAttributes<T>, T extends HTMLElement> extends DOMElement<P, T> {
|
||||
type: keyof BaseElement;
|
||||
}
|
||||
|
||||
export interface InulaHTML {
|
||||
a: InulaHTMLFactory<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
|
||||
abbr: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
address: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
area: InulaHTMLFactory<AreaHTMLAttributes<HTMLAreaElement>, HTMLAreaElement>;
|
||||
article: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
aside: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
audio: InulaHTMLFactory<AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>;
|
||||
b: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
base: InulaHTMLFactory<BaseHTMLAttributes<HTMLBaseElement>, HTMLBaseElement>;
|
||||
bdi: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
bdo: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
big: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
blockquote: InulaHTMLFactory<BlockquoteHTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>;
|
||||
body: InulaHTMLFactory<HTMLAttributes<HTMLBodyElement>, HTMLBodyElement>;
|
||||
br: InulaHTMLFactory<HTMLAttributes<HTMLBRElement>, HTMLBRElement>;
|
||||
button: InulaHTMLFactory<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;
|
||||
canvas: InulaHTMLFactory<CanvasHTMLAttributes<HTMLCanvasElement>, HTMLCanvasElement>;
|
||||
caption: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
cite: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
code: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
col: InulaHTMLFactory<ColHTMLAttributes<HTMLTableColElement>, HTMLTableColElement>;
|
||||
colgroup: InulaHTMLFactory<ColgroupHTMLAttributes<HTMLTableColElement>, HTMLTableColElement>;
|
||||
data: InulaHTMLFactory<DataHTMLAttributes<HTMLDataElement>, HTMLDataElement>;
|
||||
datalist: InulaHTMLFactory<HTMLAttributes<HTMLDataListElement>, HTMLDataListElement>;
|
||||
dd: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
del: InulaHTMLFactory<DelHTMLAttributes<HTMLModElement>, HTMLModElement>;
|
||||
details: InulaHTMLFactory<DetailsHTMLAttributes<HTMLDetailsElement>, HTMLDetailsElement>;
|
||||
dfn: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
dialog: InulaHTMLFactory<DialogHTMLAttributes<HTMLDialogElement>, HTMLDialogElement>;
|
||||
div: InulaHTMLFactory<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
dl: InulaHTMLFactory<HTMLAttributes<HTMLDListElement>, HTMLDListElement>;
|
||||
dt: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
em: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
embed: InulaHTMLFactory<EmbedHTMLAttributes<HTMLEmbedElement>, HTMLEmbedElement>;
|
||||
fieldset: InulaHTMLFactory<FieldsetHTMLAttributes<HTMLFieldSetElement>, HTMLFieldSetElement>;
|
||||
figcaption: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
figure: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
footer: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
form: InulaHTMLFactory<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>;
|
||||
h1: InulaHTMLFactory<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h2: InulaHTMLFactory<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h3: InulaHTMLFactory<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h4: InulaHTMLFactory<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h5: InulaHTMLFactory<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h6: InulaHTMLFactory<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
head: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLHeadElement>;
|
||||
header: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
hgroup: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
hr: InulaHTMLFactory<HTMLAttributes<HTMLHRElement>, HTMLHRElement>;
|
||||
html: InulaHTMLFactory<HtmlHTMLAttributes<HTMLHtmlElement>, HTMLHtmlElement>;
|
||||
i: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
iframe: InulaHTMLFactory<IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement>;
|
||||
img: InulaHTMLFactory<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>;
|
||||
input: InulaHTMLFactory<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
||||
ins: InulaHTMLFactory<InsHTMLAttributes<HTMLModElement>, HTMLModElement>;
|
||||
kbd: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
keygen: InulaHTMLFactory<KeygenHTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
label: InulaHTMLFactory<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>;
|
||||
legend: InulaHTMLFactory<HTMLAttributes<HTMLLegendElement>, HTMLLegendElement>;
|
||||
li: InulaHTMLFactory<LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>;
|
||||
link: InulaHTMLFactory<LinkHTMLAttributes<HTMLLinkElement>, HTMLLinkElement>;
|
||||
main: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
map: InulaHTMLFactory<MapHTMLAttributes<HTMLMapElement>, HTMLMapElement>;
|
||||
mark: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
menu: InulaHTMLFactory<MenuHTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
menuitem: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
meta: InulaHTMLFactory<MetaHTMLAttributes<HTMLMetaElement>, HTMLMetaElement>;
|
||||
meter: InulaHTMLFactory<MeterHTMLAttributes<HTMLMeterElement>, HTMLMeterElement>;
|
||||
nav: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
noscript: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
object: InulaHTMLFactory<ObjectHTMLAttributes<HTMLObjectElement>, HTMLObjectElement>;
|
||||
ol: InulaHTMLFactory<OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>;
|
||||
optgroup: InulaHTMLFactory<OptgroupHTMLAttributes<HTMLOptGroupElement>, HTMLOptGroupElement>;
|
||||
option: InulaHTMLFactory<OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>;
|
||||
output: InulaHTMLFactory<OutputHTMLAttributes<HTMLOutputElement>, HTMLOutputElement>;
|
||||
p: InulaHTMLFactory<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>;
|
||||
param: InulaHTMLFactory<ParamHTMLAttributes<HTMLParamElement>, HTMLParamElement>;
|
||||
picture: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
pre: InulaHTMLFactory<HTMLAttributes<HTMLPreElement>, HTMLPreElement>;
|
||||
progress: InulaHTMLFactory<ProgressHTMLAttributes<HTMLProgressElement>, HTMLProgressElement>;
|
||||
q: InulaHTMLFactory<QuoteHTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>;
|
||||
rp: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
rt: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
ruby: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
s: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
samp: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
slot: InulaHTMLFactory<SlotHTMLAttributes<HTMLSlotElement>, HTMLSlotElement>;
|
||||
script: InulaHTMLFactory<ScriptHTMLAttributes<HTMLScriptElement>, HTMLScriptElement>;
|
||||
section: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
select: InulaHTMLFactory<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>;
|
||||
small: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
source: InulaHTMLFactory<SourceHTMLAttributes<HTMLSourceElement>, HTMLSourceElement>;
|
||||
span: InulaHTMLFactory<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
|
||||
strong: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
style: InulaHTMLFactory<StyleHTMLAttributes<HTMLStyleElement>, HTMLStyleElement>;
|
||||
sub: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
summary: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
sup: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
table: InulaHTMLFactory<TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>;
|
||||
template: InulaHTMLFactory<HTMLAttributes<HTMLTemplateElement>, HTMLTemplateElement>;
|
||||
tbody: InulaHTMLFactory<HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>;
|
||||
td: InulaHTMLFactory<TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>;
|
||||
textarea: InulaHTMLFactory<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>;
|
||||
tfoot: InulaHTMLFactory<HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>;
|
||||
th: InulaHTMLFactory<ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>;
|
||||
thead: InulaHTMLFactory<HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>;
|
||||
time: InulaHTMLFactory<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement>;
|
||||
title: InulaHTMLFactory<HTMLAttributes<HTMLTitleElement>, HTMLTitleElement>;
|
||||
tr: InulaHTMLFactory<HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>;
|
||||
track: InulaHTMLFactory<TrackHTMLAttributes<HTMLTrackElement>, HTMLTrackElement>;
|
||||
u: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
ul: InulaHTMLFactory<HTMLAttributes<HTMLUListElement>, HTMLUListElement>;
|
||||
var: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
video: InulaHTMLFactory<VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>;
|
||||
wbr: InulaHTMLFactory<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
webview: InulaHTMLFactory<WebViewHTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
}
|
||||
|
||||
export type InulaHTMLProps<E extends HTMLAttributes<T>, T> = ClassAttributes<T> & E;
|
||||
|
||||
export interface BaseElement {
|
||||
// HTML
|
||||
a: InulaHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>;
|
||||
abbr: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
address: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
area: InulaHTMLProps<AreaHTMLAttributes<HTMLAreaElement>, HTMLAreaElement>;
|
||||
article: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
aside: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
audio: InulaHTMLProps<AudioHTMLAttributes<HTMLAudioElement>, HTMLAudioElement>;
|
||||
b: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
base: InulaHTMLProps<BaseHTMLAttributes<HTMLBaseElement>, HTMLBaseElement>;
|
||||
bdi: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
bdo: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
big: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
blockquote: InulaHTMLProps<BlockquoteHTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>;
|
||||
body: InulaHTMLProps<HTMLAttributes<HTMLBodyElement>, HTMLBodyElement>;
|
||||
br: InulaHTMLProps<HTMLAttributes<HTMLBRElement>, HTMLBRElement>;
|
||||
button: InulaHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;
|
||||
canvas: InulaHTMLProps<CanvasHTMLAttributes<HTMLCanvasElement>, HTMLCanvasElement>;
|
||||
caption: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
cite: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
code: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
col: InulaHTMLProps<ColHTMLAttributes<HTMLTableColElement>, HTMLTableColElement>;
|
||||
colgroup: InulaHTMLProps<ColgroupHTMLAttributes<HTMLTableColElement>, HTMLTableColElement>;
|
||||
data: InulaHTMLProps<DataHTMLAttributes<HTMLDataElement>, HTMLDataElement>;
|
||||
datalist: InulaHTMLProps<HTMLAttributes<HTMLDataListElement>, HTMLDataListElement>;
|
||||
dd: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
del: InulaHTMLProps<DelHTMLAttributes<HTMLModElement>, HTMLModElement>;
|
||||
details: InulaHTMLProps<DetailsHTMLAttributes<HTMLDetailsElement>, HTMLDetailsElement>;
|
||||
dfn: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
dialog: InulaHTMLProps<DialogHTMLAttributes<HTMLDialogElement>, HTMLDialogElement>;
|
||||
div: InulaHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
dl: InulaHTMLProps<HTMLAttributes<HTMLDListElement>, HTMLDListElement>;
|
||||
dt: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
em: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
embed: InulaHTMLProps<EmbedHTMLAttributes<HTMLEmbedElement>, HTMLEmbedElement>;
|
||||
fieldset: InulaHTMLProps<FieldsetHTMLAttributes<HTMLFieldSetElement>, HTMLFieldSetElement>;
|
||||
figcaption: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
figure: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
footer: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
form: InulaHTMLProps<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>;
|
||||
h1: InulaHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h2: InulaHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h3: InulaHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h4: InulaHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h5: InulaHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
h6: InulaHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>;
|
||||
head: InulaHTMLProps<HTMLAttributes<HTMLHeadElement>, HTMLHeadElement>;
|
||||
header: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
hgroup: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
hr: InulaHTMLProps<HTMLAttributes<HTMLHRElement>, HTMLHRElement>;
|
||||
html: InulaHTMLProps<HtmlHTMLAttributes<HTMLHtmlElement>, HTMLHtmlElement>;
|
||||
i: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
iframe: InulaHTMLProps<IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement>;
|
||||
img: InulaHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>;
|
||||
input: InulaHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
||||
ins: InulaHTMLProps<InsHTMLAttributes<HTMLModElement>, HTMLModElement>;
|
||||
kbd: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
keygen: InulaHTMLProps<KeygenHTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
label: InulaHTMLProps<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>;
|
||||
legend: InulaHTMLProps<HTMLAttributes<HTMLLegendElement>, HTMLLegendElement>;
|
||||
li: InulaHTMLProps<LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>;
|
||||
link: InulaHTMLProps<LinkHTMLAttributes<HTMLLinkElement>, HTMLLinkElement>;
|
||||
main: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
map: InulaHTMLProps<MapHTMLAttributes<HTMLMapElement>, HTMLMapElement>;
|
||||
mark: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
menu: InulaHTMLProps<MenuHTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
menuitem: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
meta: InulaHTMLProps<MetaHTMLAttributes<HTMLMetaElement>, HTMLMetaElement>;
|
||||
meter: InulaHTMLProps<MeterHTMLAttributes<HTMLMeterElement>, HTMLMeterElement>;
|
||||
nav: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
noindex: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
noscript: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
object: InulaHTMLProps<ObjectHTMLAttributes<HTMLObjectElement>, HTMLObjectElement>;
|
||||
ol: InulaHTMLProps<OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>;
|
||||
optgroup: InulaHTMLProps<OptgroupHTMLAttributes<HTMLOptGroupElement>, HTMLOptGroupElement>;
|
||||
option: InulaHTMLProps<OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>;
|
||||
output: InulaHTMLProps<OutputHTMLAttributes<HTMLOutputElement>, HTMLOutputElement>;
|
||||
p: InulaHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>;
|
||||
param: InulaHTMLProps<ParamHTMLAttributes<HTMLParamElement>, HTMLParamElement>;
|
||||
picture: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
pre: InulaHTMLProps<HTMLAttributes<HTMLPreElement>, HTMLPreElement>;
|
||||
progress: InulaHTMLProps<ProgressHTMLAttributes<HTMLProgressElement>, HTMLProgressElement>;
|
||||
q: InulaHTMLProps<QuoteHTMLAttributes<HTMLQuoteElement>, HTMLQuoteElement>;
|
||||
rp: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
rt: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
ruby: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
s: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
samp: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
slot: InulaHTMLProps<SlotHTMLAttributes<HTMLSlotElement>, HTMLSlotElement>;
|
||||
script: InulaHTMLProps<ScriptHTMLAttributes<HTMLScriptElement>, HTMLScriptElement>;
|
||||
section: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
select: InulaHTMLProps<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>;
|
||||
small: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
source: InulaHTMLProps<SourceHTMLAttributes<HTMLSourceElement>, HTMLSourceElement>;
|
||||
span: InulaHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
|
||||
strong: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
style: InulaHTMLProps<StyleHTMLAttributes<HTMLStyleElement>, HTMLStyleElement>;
|
||||
sub: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
summary: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
sup: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
table: InulaHTMLProps<TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>;
|
||||
template: InulaHTMLProps<HTMLAttributes<HTMLTemplateElement>, HTMLTemplateElement>;
|
||||
tbody: InulaHTMLProps<HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>;
|
||||
td: InulaHTMLProps<TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>;
|
||||
textarea: InulaHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>;
|
||||
tfoot: InulaHTMLProps<HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>;
|
||||
th: InulaHTMLProps<ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>;
|
||||
thead: InulaHTMLProps<HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>;
|
||||
time: InulaHTMLProps<TimeHTMLAttributes<HTMLTimeElement>, HTMLTimeElement>;
|
||||
title: InulaHTMLProps<HTMLAttributes<HTMLTitleElement>, HTMLTitleElement>;
|
||||
tr: InulaHTMLProps<HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>;
|
||||
track: InulaHTMLProps<TrackHTMLAttributes<HTMLTrackElement>, HTMLTrackElement>;
|
||||
u: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
ul: InulaHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>;
|
||||
var: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
video: InulaHTMLProps<VideoHTMLAttributes<HTMLVideoElement>, HTMLVideoElement>;
|
||||
wbr: InulaHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
||||
webview: InulaHTMLProps<WebViewHTMLAttributes<HTMLWebViewElement>, HTMLWebViewElement>;
|
||||
|
||||
// SVG
|
||||
svg: InulaSVGProps<SVGSVGElement>;
|
||||
|
||||
animate: InulaSVGProps<SVGElement>;
|
||||
animateMotion: InulaSVGProps<SVGElement>;
|
||||
animateTransform: InulaSVGProps<SVGElement>;
|
||||
circle: InulaSVGProps<SVGCircleElement>;
|
||||
clipPath: InulaSVGProps<SVGClipPathElement>;
|
||||
defs: InulaSVGProps<SVGDefsElement>;
|
||||
desc: InulaSVGProps<SVGDescElement>;
|
||||
ellipse: InulaSVGProps<SVGEllipseElement>;
|
||||
feBlend: InulaSVGProps<SVGFEBlendElement>;
|
||||
feColorMatrix: InulaSVGProps<SVGFEColorMatrixElement>;
|
||||
feComponentTransfer: InulaSVGProps<SVGFEComponentTransferElement>;
|
||||
feComposite: InulaSVGProps<SVGFECompositeElement>;
|
||||
feConvolveMatrix: InulaSVGProps<SVGFEConvolveMatrixElement>;
|
||||
feDiffuseLighting: InulaSVGProps<SVGFEDiffuseLightingElement>;
|
||||
feDisplacementMap: InulaSVGProps<SVGFEDisplacementMapElement>;
|
||||
feDistantLight: InulaSVGProps<SVGFEDistantLightElement>;
|
||||
feDropShadow: InulaSVGProps<SVGFEDropShadowElement>;
|
||||
feFlood: InulaSVGProps<SVGFEFloodElement>;
|
||||
feFuncA: InulaSVGProps<SVGFEFuncAElement>;
|
||||
feFuncB: InulaSVGProps<SVGFEFuncBElement>;
|
||||
feFuncG: InulaSVGProps<SVGFEFuncGElement>;
|
||||
feFuncR: InulaSVGProps<SVGFEFuncRElement>;
|
||||
feGaussianBlur: InulaSVGProps<SVGFEGaussianBlurElement>;
|
||||
feImage: InulaSVGProps<SVGFEImageElement>;
|
||||
feMerge: InulaSVGProps<SVGFEMergeElement>;
|
||||
feMergeNode: InulaSVGProps<SVGFEMergeNodeElement>;
|
||||
feMorphology: InulaSVGProps<SVGFEMorphologyElement>;
|
||||
feOffset: InulaSVGProps<SVGFEOffsetElement>;
|
||||
fePointLight: InulaSVGProps<SVGFEPointLightElement>;
|
||||
feSpecularLighting: InulaSVGProps<SVGFESpecularLightingElement>;
|
||||
feSpotLight: InulaSVGProps<SVGFESpotLightElement>;
|
||||
feTile: InulaSVGProps<SVGFETileElement>;
|
||||
feTurbulence: InulaSVGProps<SVGFETurbulenceElement>;
|
||||
filter: InulaSVGProps<SVGFilterElement>;
|
||||
foreignObject: InulaSVGProps<SVGForeignObjectElement>;
|
||||
g: InulaSVGProps<SVGGElement>;
|
||||
image: InulaSVGProps<SVGImageElement>;
|
||||
line: InulaSVGProps<SVGLineElement>;
|
||||
linearGradient: InulaSVGProps<SVGLinearGradientElement>;
|
||||
marker: InulaSVGProps<SVGMarkerElement>;
|
||||
mask: InulaSVGProps<SVGMaskElement>;
|
||||
metadata: InulaSVGProps<SVGMetadataElement>;
|
||||
mpath: InulaSVGProps<SVGElement>;
|
||||
path: InulaSVGProps<SVGPathElement>;
|
||||
pattern: InulaSVGProps<SVGPatternElement>;
|
||||
polygon: InulaSVGProps<SVGPolygonElement>;
|
||||
polyline: InulaSVGProps<SVGPolylineElement>;
|
||||
radialGradient: InulaSVGProps<SVGRadialGradientElement>;
|
||||
rect: InulaSVGProps<SVGRectElement>;
|
||||
stop: InulaSVGProps<SVGStopElement>;
|
||||
switch: InulaSVGProps<SVGSwitchElement>;
|
||||
symbol: InulaSVGProps<SVGSymbolElement>;
|
||||
text: InulaSVGProps<SVGTextElement>;
|
||||
textPath: InulaSVGProps<SVGTextPathElement>;
|
||||
tspan: InulaSVGProps<SVGTSpanElement>;
|
||||
use: InulaSVGProps<SVGUseElement>;
|
||||
view: InulaSVGProps<SVGViewElement>;
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
*/
|
||||
|
||||
import type { VNode, ContextType } from './Types';
|
||||
import { Container } from './Types';
|
||||
import type { Container } from '../dom/DOMOperator';
|
||||
|
||||
import { getNSCtx } from '../dom/DOMOperator';
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export function startUpdate(element: any, treeRoot: VNode, callback?: Callback)
|
|||
launchUpdateFromVNode(treeRoot);
|
||||
}
|
||||
|
||||
export function getFirstCustomElement(treeRoot?: VNode | null): Element | Text | null {
|
||||
export function getFirstCustomDom(treeRoot?: VNode | null): Element | Text | null {
|
||||
if (treeRoot?.child) {
|
||||
return treeRoot.child.realNode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import type { VNode } from './Types';
|
|||
|
||||
import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue';
|
||||
import { updateVNode } from './vnode/VNodeCreator';
|
||||
import { ContextProvider, Component, Portal, TreeRoot } from './vnode/VNodeTags';
|
||||
import { ContextProvider, DomComponent, DomPortal, TreeRoot } from './vnode/VNodeTags';
|
||||
import { FlagUtils, InitFlag, Interrupted } from './vnode/VNodeFlags';
|
||||
import { captureVNode } from './render/BaseComponent';
|
||||
import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit';
|
||||
|
|
@ -250,7 +250,7 @@ function recoverTreeContext(vNode: VNode) {
|
|||
while (parent !== null) {
|
||||
if (parent.tag === ContextProvider) {
|
||||
contextProviders.unshift(parent);
|
||||
} else if (parent.tag === Portal) {
|
||||
} else if (parent.tag === DomPortal) {
|
||||
portalRoots.unshift(parent);
|
||||
}
|
||||
parent = parent.parent;
|
||||
|
|
@ -271,7 +271,7 @@ function resetTreeContext(vNode: VNode) {
|
|||
if (parent.tag === ContextProvider) {
|
||||
resetContext(parent);
|
||||
}
|
||||
if (parent.tag === Portal) {
|
||||
if (parent.tag === DomPortal) {
|
||||
popCurrentRoot();
|
||||
}
|
||||
parent = parent.parent;
|
||||
|
|
@ -297,9 +297,9 @@ function buildVNodeTree(treeRoot: VNode) {
|
|||
let parent = startVNode.parent;
|
||||
while (parent !== null) {
|
||||
const tag = parent.tag;
|
||||
if (tag === Component) {
|
||||
if (tag === DomComponent) {
|
||||
break;
|
||||
} else if (tag === TreeRoot || tag === Portal) {
|
||||
} else if (tag === TreeRoot || tag === DomPortal) {
|
||||
break;
|
||||
}
|
||||
parent = parent.parent;
|
||||
|
|
|
|||
|
|
@ -13,20 +13,10 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { BELONG_CLASS_VNODE_KEY, VNode } from './vnode/VNode';
|
||||
import { Component, Text } from './vnode/VNodeTags';
|
||||
import { BELONG_CLASS_VNODE_KEY } from './vnode/VNode';
|
||||
|
||||
export { VNode } from './vnode/VNode';
|
||||
// import { Props } from './utils/InternalKeys';
|
||||
export type Props = Record<string, any> & {
|
||||
autoFocus?: boolean;
|
||||
children?: any;
|
||||
disabled?: boolean;
|
||||
hidden?: boolean;
|
||||
style?: { display?: string };
|
||||
};
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
type Trigger<A> = (A) => void;
|
||||
|
||||
export type UseStateHookType = {
|
||||
|
|
@ -92,75 +82,3 @@ export type Source = {
|
|||
};
|
||||
|
||||
export type Callback = () => void;
|
||||
|
||||
export type Container = any & { _treeRoot?: VNode | null };
|
||||
|
||||
export interface ReconcilerType {
|
||||
render: (...args: any) => void;
|
||||
}
|
||||
|
||||
export type ElementType = {
|
||||
parentNode?: ElementType | null;
|
||||
nodeName?: string;
|
||||
nodeType?: number;
|
||||
[key: string]: any;
|
||||
};
|
||||
export type CommonTagType = typeof Component | typeof Text;
|
||||
export enum CommonTags {
|
||||
ComponentElement = Component,
|
||||
TextElement = Text,
|
||||
}
|
||||
// `hostConfig` 接口定义了与 DOM 操作相关的方法
|
||||
export interface HostConfigType {
|
||||
// 定义元素的name和type值
|
||||
elementConfig: {
|
||||
common: ElementType;
|
||||
text: ElementType;
|
||||
input: ElementType;
|
||||
button: ElementType;
|
||||
select: ElementType;
|
||||
textarea: ElementType;
|
||||
[key: string]: ElementType;
|
||||
};
|
||||
// 节点操作
|
||||
createElement(tagName: string, props: Props, parentNamespace: string, rootElement: ElementType): ElementType;
|
||||
createText(text: string): ElementType;
|
||||
isTextChild(type: string, props: Props): boolean;
|
||||
hideElement(tag: CommonTagType, element: ElementType): void;
|
||||
unHideElement(tag: CommonTagType, element: ElementType, props?: Props): void;
|
||||
removeChildElement(parent: ElementType | Container, child: ElementType): void;
|
||||
insertElementBefore(parent: ElementType | Container, child: ElementType, beforeChild: ElementType): void;
|
||||
appendChildElement(parent: ElementType | Container, child: ElementType): void;
|
||||
clearText(element: ElementType): void;
|
||||
|
||||
// 监听器相关
|
||||
addEventListener(element: ElementType, eventName: string, handler: (...args) => void, isCapture: boolean): void;
|
||||
removeEventListener(element: ElementType, eventName: string, handler: (...args) => void): void;
|
||||
|
||||
// 生命周期相关
|
||||
prepareForSubmit(): void;
|
||||
resetAfterSubmit(): void;
|
||||
/* submit 前对元素预处理,常用于 input 类元素将value值去掉避免重复刷新 */
|
||||
onSubmit(tag: CommonTagType, type: any, element: ElementType, newProps: any, changeList: any): void;
|
||||
|
||||
// input 相关
|
||||
updateInputValue(type: string, element: ElementType, props: Props): void;
|
||||
shouldTriggerChangeEvent(targetElement: ElementType, elementTag: string, evtName: string): boolean;
|
||||
/* 受控 input 传值处理 */
|
||||
handleControledInputElements(target: ElementType, type: string, props: Props): void;
|
||||
|
||||
// prop 相关
|
||||
/* 如何更新 props */
|
||||
setProps(element: ElementType, propName: string, value: any, isNativeTag: boolean, isInit: boolean): void;
|
||||
/* 如何处理 props */
|
||||
getProps(
|
||||
type: string,
|
||||
element: ElementType,
|
||||
rawProps: Record<string, any>,
|
||||
): Record<string, any>;
|
||||
onPropInit(element: ElementType, tagName: string, Props: Record<string, any>): void;
|
||||
}
|
||||
export interface InulaReconcilerType {
|
||||
hostConfig: HostConfigType;
|
||||
setHostConfig(config: Partial<HostConfigType>): void;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import type { ContextType } from '../../Types';
|
|||
import { TYPE_PROVIDER, TYPE_CONTEXT } from '../../../external/JSXElementType';
|
||||
import { Context } from '../../../types';
|
||||
|
||||
// export function createContext<T>(val: T): Context<T>;
|
||||
export function createContext<T>(val: T): Context<T>;
|
||||
export function createContext<T>(val: T): ContextType<T> | Context<T> {
|
||||
const context: ContextType<T> = {
|
||||
vtype: TYPE_CONTEXT,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
import type { VNode } from '../Types';
|
||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL, TYPE_STRICT_MODE } from '../../external/JSXElementType';
|
||||
import { Text, Portal, Fragment, Component } from '../vnode/VNodeTags';
|
||||
import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags';
|
||||
import {
|
||||
updateVNode,
|
||||
createVNodeFromElement,
|
||||
|
|
@ -137,7 +137,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
|
|||
let resultNode: VNode | null = null;
|
||||
switch (newNodeType) {
|
||||
case DiffCategory.TEXT_NODE: {
|
||||
if (oldNode === null || oldNode.tag !== Text) {
|
||||
if (oldNode === null || oldNode.tag !== DomText) {
|
||||
resultNode = createDomTextVNode(String(newChild));
|
||||
} else {
|
||||
resultNode = updateVNode(oldNode, String(newChild));
|
||||
|
|
@ -175,7 +175,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
|
|||
}
|
||||
break;
|
||||
} else if (newChild.vtype === TYPE_PORTAL) {
|
||||
if (oldNode === null || oldNode.tag !== Portal || oldNode.realNode !== newChild.realNode) {
|
||||
if (oldNode === null || oldNode.tag !== DomPortal || oldNode.realNode !== newChild.realNode) {
|
||||
resultNode = createPortalVNode(newChild);
|
||||
} else {
|
||||
resultNode = updateVNode(oldNode, newChild.children || []);
|
||||
|
|
@ -364,7 +364,7 @@ function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newC
|
|||
* 优化策略:首先克隆这些节点的共同父节点P,然后将父节点P从DOM树中删除,最后再将克隆的P节点添加回DOM树中。
|
||||
* 例外处理:当父节点为select时,克隆option子节点时会导致原父节点child变化,因此不适用与该优化,降级采用deleteVNodes。
|
||||
*/
|
||||
if (firstChild && parentNode.tag === Component && parentNode.type !== 'select' && newChildren.length === 0) {
|
||||
if (firstChild && parentNode.tag === DomComponent && parentNode.type !== 'select' && newChildren.length === 0) {
|
||||
FlagUtils.markClear(parentNode);
|
||||
parentNode.clearChild = firstChild;
|
||||
} else {
|
||||
|
|
@ -385,13 +385,13 @@ function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newC
|
|||
// 是否可以扩大至非dom类型节点待确认
|
||||
// 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点
|
||||
if (
|
||||
parentNode.tag === Component &&
|
||||
parentNode.tag === DomComponent &&
|
||||
parentNode.oldProps?.children?.length === 0 &&
|
||||
rightIdx - leftIdx === newChildren.length
|
||||
) {
|
||||
isDirectAdd = true;
|
||||
}
|
||||
const isAddition = parentNode.tag === Portal || !parentNode.isCreated;
|
||||
const isAddition = parentNode.tag === DomPortal || !parentNode.isCreated;
|
||||
for (; leftIdx < rightIdx; leftIdx++) {
|
||||
newNode = getNewNode(parentNode, newChildren[leftIdx], null);
|
||||
|
||||
|
|
@ -525,7 +525,7 @@ function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode
|
|||
let newTextNode: VNode | null = null;
|
||||
|
||||
// 第一个vNode是Text,则复用
|
||||
if (firstChildVNode !== null && firstChildVNode.tag === Text) {
|
||||
if (firstChildVNode !== null && firstChildVNode.tag === DomText) {
|
||||
newTextNode = updateVNode(firstChildVNode, String(newChild));
|
||||
deleteVNodes(parentNode, firstChildVNode.next);
|
||||
newTextNode.next = null;
|
||||
|
|
@ -598,7 +598,7 @@ function diffObjectNodeHandler(
|
|||
} else if (newChild.vtype === TYPE_PORTAL) {
|
||||
if (canReuseNode) {
|
||||
// 可以复用
|
||||
if (canReuseNode.tag === Portal && canReuseNode.realNode === newChild.realNode) {
|
||||
if (canReuseNode.tag === DomPortal && canReuseNode.realNode === newChild.realNode) {
|
||||
resultNode = updateVNode(canReuseNode, newChild.children || []);
|
||||
startDelVNode = canReuseNode.next;
|
||||
resultNode.next = null;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import { useLayoutEffectImpl } from './UseEffectHook';
|
|||
import { getHookStage } from './HookStage';
|
||||
import { throwNotInFuncError } from './BaseHook';
|
||||
import type { MutableRef } from './HookType';
|
||||
import { isNotNull } from '../../renderer/utils/common';
|
||||
import { isNotNull } from '../../dom/utils/Common';
|
||||
|
||||
function effectFunc<R>(func: () => R, ref: MutableRef<R> | ((any) => any) | null): (() => void) | void {
|
||||
if (typeof ref === 'function') {
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
import { defaultHostConfig } from '../dom';
|
||||
import { HostConfigType, InulaReconcilerType } from './Types';
|
||||
|
||||
export const InulaReconciler: InulaReconcilerType = {
|
||||
hostConfig: defaultHostConfig as HostConfigType,
|
||||
setHostConfig(config: HostConfigType) {
|
||||
this.hostConfig = { ...this.hostConfig, ...config };
|
||||
},
|
||||
};
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
import type { VNode } from '../Types';
|
||||
|
||||
import { ContextProvider, Component, Portal, TreeRoot, SuspenseComponent } from '../vnode/VNodeTags';
|
||||
import { ContextProvider, DomComponent, DomPortal, TreeRoot, SuspenseComponent } from '../vnode/VNodeTags';
|
||||
import { setContext, setNamespaceCtx } from '../ContextSaver';
|
||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
|
||||
|
|
@ -30,10 +30,10 @@ function setTreeContextValue(processing: VNode) {
|
|||
case TreeRoot:
|
||||
setNamespaceCtx(processing, processing.realNode);
|
||||
break;
|
||||
case Component:
|
||||
case DomComponent:
|
||||
setNamespaceCtx(processing);
|
||||
break;
|
||||
case Portal:
|
||||
case DomPortal:
|
||||
setNamespaceCtx(processing, processing.realNode);
|
||||
pushCurrentRoot(processing);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -13,36 +13,18 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import type { ElementType, VNode } from '../Types';
|
||||
import { Props } from '../Types';
|
||||
import type { VNode } from '../Types';
|
||||
import type { Props } from '../../dom/DOMOperator';
|
||||
|
||||
import { getNamespaceCtx, setNamespaceCtx, resetNamespaceCtx } from '../ContextSaver';
|
||||
import { saveVNode, updateVNodeProps } from '../../renderer/utils/InternalKeys';
|
||||
import { appendChildElement, newDom, initDomProps, getPropChangeList, isTextChild } from '../../dom/DOMOperator';
|
||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||
import { markRef } from './BaseComponent';
|
||||
import { Component, Portal, Text } from '../vnode/VNodeTags';
|
||||
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
|
||||
import { travelVNodeTree } from '../vnode/VNodeUtils';
|
||||
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
||||
import { InulaReconciler } from '..';
|
||||
import { getCurrentRoot } from '../RootStack';
|
||||
import { compareProps } from '../props/PropHandler';
|
||||
import { validateProps } from '../props/ValidateProps';
|
||||
import { initElementProps } from '../props/PropHandler';
|
||||
// 准备更新之前进行一系列校验,寻找属性差异等准备工作
|
||||
export function getPropChangeList(
|
||||
element: ElementType,
|
||||
type: string,
|
||||
lastRawProps: Props,
|
||||
nextRawProps: Props
|
||||
): Record<string, any> {
|
||||
// 校验两个对象的不同
|
||||
validateProps(type, nextRawProps);
|
||||
|
||||
// 重新定义的属性不需要参与对比,被代理的组件需要把这些属性覆盖到props中
|
||||
const oldProps = InulaReconciler.hostConfig.getProps(type, element, lastRawProps);
|
||||
const newProps = InulaReconciler.hostConfig.getProps(type, element, nextRawProps);
|
||||
return compareProps(oldProps, newProps);
|
||||
}
|
||||
function updateElement(processing: VNode, type: any, newProps: Props) {
|
||||
function updateDom(processing: VNode, type: any, newProps: Props) {
|
||||
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
||||
const oldProps = processing.oldProps;
|
||||
if (oldProps === newProps) {
|
||||
|
|
@ -50,9 +32,9 @@ function updateElement(processing: VNode, type: any, newProps: Props) {
|
|||
return;
|
||||
}
|
||||
|
||||
const element: ElementType = processing.realNode;
|
||||
const dom: Element = processing.realNode;
|
||||
|
||||
const changeList = getPropChangeList(element, type, oldProps, newProps);
|
||||
const changeList = getPropChangeList(dom, type, oldProps, newProps);
|
||||
|
||||
// 输入类型的直接标记更新
|
||||
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
||||
|
|
@ -69,12 +51,12 @@ function updateElement(processing: VNode, type: any, newProps: Props) {
|
|||
|
||||
export function bubbleRender(processing: VNode) {
|
||||
resetNamespaceCtx(processing);
|
||||
const {createElement} = InulaReconciler.hostConfig;
|
||||
|
||||
const type = processing.type;
|
||||
const newProps = processing.props;
|
||||
if (!processing.isCreated && processing.realNode !== null) {
|
||||
// 更新dom属性
|
||||
updateElement(processing, type, newProps);
|
||||
updateDom(processing, type, newProps);
|
||||
|
||||
if (processing.oldRef !== processing.ref) {
|
||||
FlagUtils.markRef(processing);
|
||||
|
|
@ -83,34 +65,30 @@ export function bubbleRender(processing: VNode) {
|
|||
const parentNamespace = getNamespaceCtx();
|
||||
|
||||
// 创建dom
|
||||
const rootElement = getCurrentRoot()?.realNode;
|
||||
const {element, props} = createElement(type, newProps, parentNamespace, rootElement);
|
||||
// 将 vNode 节点挂到 element 对象上
|
||||
saveVNode(processing, element);
|
||||
// 将属性挂到 element 对象上
|
||||
updateVNodeProps(element, props);
|
||||
// 把dom类型的子节点append到parent element中
|
||||
const dom = newDom(type, newProps, parentNamespace, processing);
|
||||
|
||||
// 把dom类型的子节点append到parent dom中
|
||||
const vNode = processing.child;
|
||||
if (vNode !== null) {
|
||||
// 向下递归它的子节点,查找所有终端节点。
|
||||
travelVNodeTree(
|
||||
vNode,
|
||||
node => {
|
||||
if (node.tag === Component || node.tag === Text) {
|
||||
InulaReconciler.hostConfig.appendChildElement(element, node.realNode);
|
||||
if (node.tag === DomComponent || node.tag === DomText) {
|
||||
appendChildElement(dom, node.realNode);
|
||||
}
|
||||
},
|
||||
node =>
|
||||
// 已经append到父节点,或者是Portal都不需要处理child了
|
||||
node.tag === Component || node.tag === Text || node.tag === Portal,
|
||||
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
||||
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal,
|
||||
processing,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
processing.realNode = element;
|
||||
processing.realNode = dom;
|
||||
|
||||
if (initElementProps(element, type, newProps)) {
|
||||
if (initDomProps(dom, type, newProps)) {
|
||||
FlagUtils.markUpdate(processing);
|
||||
}
|
||||
|
||||
|
|
@ -129,12 +107,12 @@ export function captureRender(processing: VNode): VNode | null {
|
|||
const oldProps = !processing.isCreated ? processing.oldProps : null;
|
||||
|
||||
let nextChildren = newProps.children;
|
||||
const isDirectTextChild = InulaReconciler.hostConfig.isTextChild(type, newProps);
|
||||
const isDirectTextChild = isTextChild(type, newProps);
|
||||
|
||||
if (isDirectTextChild) {
|
||||
// 如果为文本节点,则认为没有子节点
|
||||
nextChildren = null;
|
||||
} else if (oldProps !== null && InulaReconciler.hostConfig.isTextChild(type, oldProps)) {
|
||||
} else if (oldProps !== null && isTextChild(type, oldProps)) {
|
||||
// 将纯文本的子节点改为vNode节点
|
||||
FlagUtils.markContentReset(processing);
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
*/
|
||||
|
||||
import type { VNode } from '../Types';
|
||||
import { saveVNode } from '../utils/InternalKeys';
|
||||
|
||||
import { throwIfTrue } from '../utils/throwIfTrue';
|
||||
import { newTextDom } from '../../dom/DOMOperator';
|
||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||
import { InulaReconciler } from '..';
|
||||
|
||||
export function captureRender(): VNode | null {
|
||||
return null;
|
||||
|
|
@ -44,8 +44,6 @@ export function bubbleRender(processing: VNode) {
|
|||
);
|
||||
}
|
||||
// 获得对应节点
|
||||
const newTextNode = InulaReconciler.hostConfig.createText(newText);
|
||||
saveVNode(processing, newTextNode);
|
||||
processing.realNode = newTextNode;
|
||||
processing.realNode = newTextDom(newText, processing);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,10 +20,10 @@ import * as ContextProviderRender from './ContextProvider';
|
|||
import * as ForwardRefRender from './ForwardRef';
|
||||
import * as FragmentRender from './Fragment';
|
||||
import * as FunctionComponentRender from './FunctionComponent';
|
||||
import * as DomComponentRender from './Component';
|
||||
import * as DomPortalRender from './Portal';
|
||||
import * as DomComponentRender from './DomComponent';
|
||||
import * as DomPortalRender from './DomPortal';
|
||||
import * as TreeRootRender from './TreeRoot';
|
||||
import * as DomTextRender from './Text';
|
||||
import * as DomTextRender from './DomText';
|
||||
import * as LazyComponentRender from './LazyComponent';
|
||||
import * as MemoComponentRender from './MemoComponent';
|
||||
import * as SuspenseComponentRender from './SuspenseComponent';
|
||||
|
|
@ -35,10 +35,10 @@ import {
|
|||
ForwardRef,
|
||||
Fragment,
|
||||
FunctionComponent,
|
||||
Component,
|
||||
Portal,
|
||||
DomComponent,
|
||||
DomPortal,
|
||||
TreeRoot,
|
||||
Text,
|
||||
DomText,
|
||||
LazyComponent,
|
||||
MemoComponent,
|
||||
SuspenseComponent,
|
||||
|
|
@ -53,10 +53,10 @@ export default {
|
|||
[ForwardRef]: ForwardRefRender,
|
||||
[Fragment]: FragmentRender,
|
||||
[FunctionComponent]: FunctionComponentRender,
|
||||
[Component]: DomComponentRender,
|
||||
[Portal]: DomPortalRender,
|
||||
[DomComponent]: DomComponentRender,
|
||||
[DomPortal]: DomPortalRender,
|
||||
[TreeRoot]: TreeRootRender,
|
||||
[Text]: DomTextRender,
|
||||
[DomText]: DomTextRender,
|
||||
[LazyComponent]: LazyComponentRender,
|
||||
[MemoComponent]: MemoComponentRender,
|
||||
[SuspenseComponent]: SuspenseComponentRender,
|
||||
|
|
|
|||
|
|
@ -17,22 +17,32 @@
|
|||
* 该文件负责把更新应用到界面上 以及 和生命周期的相关调用
|
||||
*/
|
||||
|
||||
import { Container } from '../Types';
|
||||
import type { ElementType, RefType, VNode } from '../Types';
|
||||
import type { Container } from '../../dom/DOMOperator';
|
||||
import type { RefType, VNode } from '../Types';
|
||||
|
||||
import { listenToPromise, SuspenseChildStatus } from '../render/SuspenseComponent';
|
||||
import {
|
||||
FunctionComponent,
|
||||
ForwardRef,
|
||||
ClassComponent,
|
||||
TreeRoot,
|
||||
Component,
|
||||
Text,
|
||||
Portal,
|
||||
DomComponent,
|
||||
DomText,
|
||||
DomPortal,
|
||||
SuspenseComponent,
|
||||
MemoComponent,
|
||||
} from '../vnode/VNodeTags';
|
||||
import { FlagUtils, ResetText, Clear, Update, DirectAddition } from '../vnode/VNodeFlags';
|
||||
import { mergeDefaultProps } from '../render/LazyComponent';
|
||||
import {
|
||||
submitDomUpdate,
|
||||
clearText,
|
||||
appendChildElement,
|
||||
insertDomBefore,
|
||||
removeChildDom,
|
||||
hideDom,
|
||||
unHideDom,
|
||||
} from '../../dom/DOMOperator';
|
||||
import {
|
||||
callEffectRemove,
|
||||
callUseEffects,
|
||||
|
|
@ -41,37 +51,8 @@ import {
|
|||
} from './HookEffectHandler';
|
||||
import { handleSubmitError } from '../ErrorHandler';
|
||||
import { travelVNodeTree, clearVNode, isDomVNode, getSiblingDom } from '../vnode/VNodeUtils';
|
||||
import { shouldAutoFocus } from '../../renderer/utils/common';
|
||||
import { shouldAutoFocus } from '../../dom/utils/Common';
|
||||
import { BELONG_CLASS_VNODE_KEY } from '../vnode/VNode';
|
||||
import { saveVNode, updateVNodeProps } from '../utils/InternalKeys';
|
||||
import { InulaReconciler } from '..';
|
||||
import { isNativeElement } from '../props/PropHandler';
|
||||
import { setElementProps } from '../props/PropHandler';
|
||||
|
||||
function submitDomUpdate(tag: string, vNode: VNode) {
|
||||
const newProps = vNode.props;
|
||||
const element: ElementType | null = vNode.realNode;
|
||||
|
||||
if (tag === Component) {
|
||||
// DomComponent类型
|
||||
if (element !== null && element !== undefined) {
|
||||
const type = vNode.type;
|
||||
const changeList = vNode.changeList;
|
||||
vNode.changeList = null;
|
||||
|
||||
if (changeList !== null) {
|
||||
saveVNode(vNode, element);
|
||||
updateVNodeProps(element, newProps);
|
||||
InulaReconciler.hostConfig.onSubmit(tag, type, element, newProps, changeList);
|
||||
const isNativeTag = isNativeElement(type, newProps);
|
||||
setElementProps(element, changeList, isNativeTag, false);
|
||||
InulaReconciler.hostConfig.updateInputValue(type, element, newProps);
|
||||
}
|
||||
}
|
||||
} else if (tag === Text) {
|
||||
InulaReconciler.hostConfig.onSubmit('Text', '', element as ElementType, newProps, []);
|
||||
}
|
||||
}
|
||||
|
||||
function callComponentWillUnmount(vNode: VNode, instance: any) {
|
||||
try {
|
||||
|
|
@ -141,7 +122,7 @@ function callAfterSubmitLifeCycles(vNode: VNode): void {
|
|||
callStateCallback(vNode, instance);
|
||||
return;
|
||||
}
|
||||
case Component: {
|
||||
case DomComponent: {
|
||||
if (vNode.isCreated && (vNode.flags & Update) === Update) {
|
||||
// button、input、select、textarea、如果有 autoFocus 属性需要focus
|
||||
if (shouldAutoFocus(vNode.type, vNode.props)) {
|
||||
|
|
@ -160,11 +141,11 @@ function hideOrUnhideAllChildren(vNode, isHidden) {
|
|||
(node: VNode) => {
|
||||
const instance = node.realNode;
|
||||
|
||||
if (node.tag === Component || node.tag === Text) {
|
||||
if (node.tag === DomComponent || node.tag === DomText) {
|
||||
if (isHidden) {
|
||||
InulaReconciler.hostConfig.hideElement(node.tag, instance);
|
||||
hideDom(node.tag, instance);
|
||||
} else {
|
||||
InulaReconciler.hostConfig.unHideElement(node.tag, instance, node.props);
|
||||
unHideDom(node.tag, instance, node.props);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -211,7 +192,7 @@ function unmountNestedVNodes(vNode: VNode): void {
|
|||
},
|
||||
node =>
|
||||
// 如果是DomPortal,不需要遍历child
|
||||
node.tag === Portal,
|
||||
node.tag === DomPortal,
|
||||
vNode,
|
||||
null
|
||||
);
|
||||
|
|
@ -232,7 +213,7 @@ function unmountDomComponents(vNode: VNode): void {
|
|||
let tag;
|
||||
while (parent !== null) {
|
||||
tag = parent.tag;
|
||||
if (tag === Component || tag === TreeRoot || tag === Portal) {
|
||||
if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) {
|
||||
currentParent = parent.realNode;
|
||||
break;
|
||||
}
|
||||
|
|
@ -241,13 +222,13 @@ function unmountDomComponents(vNode: VNode): void {
|
|||
currentParentIsValid = true;
|
||||
}
|
||||
|
||||
if (node.tag === Component || node.tag === Text) {
|
||||
if (node.tag === DomComponent || node.tag === DomText) {
|
||||
// 卸载vNode,递归遍历子vNode
|
||||
unmountNestedVNodes(node);
|
||||
|
||||
// 在所有子项都卸载后,删除dom树中的节点
|
||||
InulaReconciler.hostConfig.removeChildElement(currentParent, node.realNode);
|
||||
} else if (node.tag === Portal) {
|
||||
removeChildDom(currentParent, node.realNode);
|
||||
} else if (node.tag === DomPortal) {
|
||||
if (node.child !== null) {
|
||||
currentParent = node.realNode;
|
||||
}
|
||||
|
|
@ -257,10 +238,10 @@ function unmountDomComponents(vNode: VNode): void {
|
|||
},
|
||||
node =>
|
||||
// 如果是dom不用再遍历child
|
||||
node.tag === Component || node.tag === Text,
|
||||
node.tag === DomComponent || node.tag === DomText,
|
||||
vNode,
|
||||
node => {
|
||||
if (node.tag === Portal) {
|
||||
if (node.tag === DomPortal) {
|
||||
// 当离开portal,需要重新设置parent
|
||||
currentParentIsValid = false;
|
||||
}
|
||||
|
|
@ -294,11 +275,11 @@ function unmountVNode(vNode: VNode): void {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case Component: {
|
||||
case DomComponent: {
|
||||
detachRef(vNode);
|
||||
break;
|
||||
}
|
||||
case Portal: {
|
||||
case DomPortal: {
|
||||
// 这里会递归
|
||||
unmountDomComponents(vNode);
|
||||
break;
|
||||
|
|
@ -311,9 +292,9 @@ function unmountVNode(vNode: VNode): void {
|
|||
|
||||
function insertDom(parent, realNode, beforeDom) {
|
||||
if (beforeDom) {
|
||||
InulaReconciler.hostConfig.insertElementBefore(parent, realNode, beforeDom);
|
||||
insertDomBefore(parent, realNode, beforeDom);
|
||||
} else {
|
||||
InulaReconciler.hostConfig.appendChildElement(parent, realNode);
|
||||
appendChildElement(parent, realNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -322,7 +303,7 @@ function insertOrAppendPlacementNode(node: VNode, beforeDom: Element | null, par
|
|||
|
||||
if (isDomVNode(node)) {
|
||||
insertDom(parent, realNode, beforeDom);
|
||||
} else if (tag === Portal) {
|
||||
} else if (tag === DomPortal) {
|
||||
// 这里不做处理,直接在portal中处理
|
||||
} else {
|
||||
// 插入子节点们
|
||||
|
|
@ -340,7 +321,7 @@ function submitAddition(vNode: VNode): void {
|
|||
let tag;
|
||||
while (parent !== null) {
|
||||
tag = parent.tag;
|
||||
if (tag === Component || tag === TreeRoot || tag === Portal) {
|
||||
if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) {
|
||||
parentDom = parent.realNode;
|
||||
break;
|
||||
}
|
||||
|
|
@ -349,7 +330,7 @@ function submitAddition(vNode: VNode): void {
|
|||
|
||||
if ((parent!.flags & ResetText) === ResetText) {
|
||||
// 在insert之前先reset
|
||||
InulaReconciler.hostConfig.clearText(parentDom);
|
||||
clearText(parentDom);
|
||||
FlagUtils.removeFlag(parent!, ResetText);
|
||||
}
|
||||
|
||||
|
|
@ -384,7 +365,7 @@ function submitClear(vNode: VNode): void {
|
|||
let tag;
|
||||
while (parent !== null) {
|
||||
tag = parent.tag;
|
||||
if (tag === Component || tag === TreeRoot || tag === Portal) {
|
||||
if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) {
|
||||
parentDom = parent.realNode;
|
||||
break;
|
||||
}
|
||||
|
|
@ -400,7 +381,7 @@ function submitClear(vNode: VNode): void {
|
|||
}
|
||||
|
||||
// 在所有子项都卸载后,删除dom树中的节点
|
||||
InulaReconciler.hostConfig.removeChildElement(parentDom, vNode.realNode);
|
||||
removeChildDom(parentDom, vNode.realNode);
|
||||
const realNodeNext = getSiblingDom(vNode);
|
||||
insertDom(parentDom, cloneDom, realNodeNext);
|
||||
vNode.realNode = cloneDom;
|
||||
|
|
@ -433,8 +414,8 @@ function submitUpdate(vNode: VNode): void {
|
|||
callUseLayoutEffectRemove(vNode);
|
||||
break;
|
||||
}
|
||||
case Component:
|
||||
case Text: {
|
||||
case DomComponent:
|
||||
case DomText: {
|
||||
submitDomUpdate(vNode.tag, vNode);
|
||||
break;
|
||||
}
|
||||
|
|
@ -450,7 +431,7 @@ function submitUpdate(vNode: VNode): void {
|
|||
}
|
||||
|
||||
function submitResetTextContent(vNode: VNode) {
|
||||
InulaReconciler.hostConfig.clearText(vNode.realNode);
|
||||
clearText(vNode.realNode);
|
||||
}
|
||||
|
||||
export {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
import type { VNode } from '../Types';
|
||||
|
||||
import { FlagUtils, Addition, Snapshot, ResetText, Ref, Update, Deletion, Clear, Callback } from '../vnode/VNodeFlags';
|
||||
import { prepareForSubmit, resetAfterSubmit } from '../../dom/DOMOperator';
|
||||
import { handleSubmitError } from '../ErrorHandler';
|
||||
import {
|
||||
attachRef,
|
||||
|
|
@ -32,7 +33,6 @@ import { tryRenderFromRoot } from '../TreeBuilder';
|
|||
import { InRender, copyExecuteMode, setExecuteMode, changeMode } from '../ExecuteMode';
|
||||
import { isSchedulingEffects, setSchedulingEffects } from './HookEffectHandler';
|
||||
import { getStartVNode } from '../GlobalVar';
|
||||
import { InulaReconciler } from '..';
|
||||
|
||||
let rootThrowError = null;
|
||||
|
||||
|
|
@ -179,14 +179,14 @@ export function submitToRender(treeRoot) {
|
|||
const preMode = copyExecuteMode();
|
||||
changeMode(InRender, true);
|
||||
|
||||
InulaReconciler.hostConfig.prepareForSubmit();
|
||||
prepareForSubmit();
|
||||
// before submit阶段
|
||||
beforeSubmit(dirtyNodes);
|
||||
|
||||
// submit阶段
|
||||
submit(dirtyNodes);
|
||||
|
||||
InulaReconciler.hostConfig.resetAfterSubmit();
|
||||
resetAfterSubmit();
|
||||
|
||||
// after submit阶段
|
||||
afterSubmit(dirtyNodes);
|
||||
|
|
|
|||
|
|
@ -1,109 +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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 文件整体功能:给dom节点赋 VNode 的结构体和事件初始化标记
|
||||
*/
|
||||
|
||||
import type { ElementType, VNode } from '../Types';
|
||||
import { Container } from '../Types';
|
||||
|
||||
import { Component as Component, Text as Text, TreeRoot } from '../vnode/VNodeTags';
|
||||
import { findDomVNode as findRealVNode } from '../vnode/VNodeUtils';
|
||||
|
||||
const randomKey = Math.random().toString(16).slice(2);
|
||||
const INTERNAL_VNODE = `_inula_VNode_${randomKey}`;
|
||||
const INTERNAL_PROPS = `_inula_Props_${randomKey}`;
|
||||
const INTERNAL_NONDELEGATEEVENTS = `_inula_nonDelegatedEvents_${randomKey}`;
|
||||
export const HANDLER_KEY = `_inula_valueChangeHandler_${randomKey}`;
|
||||
export const EVENT_KEY = `_inula_ev_${randomKey}`;
|
||||
|
||||
export type Props = Record<string, any> & {
|
||||
autoFocus?: boolean;
|
||||
children?: any;
|
||||
disabled?: boolean;
|
||||
hidden?: boolean;
|
||||
style?: { display?: string };
|
||||
};
|
||||
|
||||
|
||||
// 通过 VNode 实例获取 Element 节点
|
||||
export function getElement(vNode: VNode): ElementType | null {
|
||||
const { tag } = vNode;
|
||||
if (tag === Component || tag === Text) {
|
||||
return vNode.realNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 将 VNode 属性相关信息挂到对象的特定属性上
|
||||
export function saveVNode(vNode: VNode, element: ElementType | Text | Container): void {
|
||||
element[INTERNAL_VNODE] = vNode;
|
||||
}
|
||||
|
||||
// 用 Element 节点,来找其对应的 VNode 实例
|
||||
export function getVNode(element: ElementType | Container): VNode | null {
|
||||
const vNode = element[INTERNAL_VNODE] || (element as Container)._treeRoot;
|
||||
if (vNode) {
|
||||
const { tag } = vNode;
|
||||
if (tag === Component || tag === Text || tag === TreeRoot) {
|
||||
return vNode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 用 element 对象,来寻找其对应或者说是最近父级的 vNode
|
||||
export function getNearestVNode(element: ElementType): null | VNode {
|
||||
let elementNode: ElementType | null = element;
|
||||
// 寻找当前节点及其所有祖先节点是否有标记VNODE
|
||||
while (elementNode) {
|
||||
const vNode = elementNode[INTERNAL_VNODE];
|
||||
if (vNode) {
|
||||
return vNode;
|
||||
}
|
||||
elementNode = element.parentNode ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
export function findElementByClassInst(inst) {
|
||||
const vNode = inst._vNode;
|
||||
if (vNode === undefined) {
|
||||
throw new Error('Unable to find the vNode by class instance.');
|
||||
}
|
||||
|
||||
const elementVNode = findRealVNode(vNode);
|
||||
|
||||
return elementVNode !== null ? elementVNode.realNode : null;
|
||||
}
|
||||
// 获取 vNode 上的属性相关信息
|
||||
export function getVNodeProps(element: ElementType | Text): Props | null {
|
||||
return element[INTERNAL_PROPS] || null;
|
||||
}
|
||||
|
||||
// 将 Element 属性相关信息挂到 Element 对象的特定属性上
|
||||
export function updateVNodeProps(element: ElementType | Text, props: Props): void {
|
||||
element[INTERNAL_PROPS] = props;
|
||||
}
|
||||
|
||||
export function getNonDelegatedListenerMap(element: ElementType | Text): Map<string, EventListener> {
|
||||
let eventsMap = element[INTERNAL_NONDELEGATEEVENTS];
|
||||
if (!eventsMap) {
|
||||
eventsMap = new Map();
|
||||
element[INTERNAL_NONDELEGATEEVENTS] = eventsMap;
|
||||
}
|
||||
return eventsMap;
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
import { InulaReconciler } from '..';
|
||||
import { ElementType } from '../Types';
|
||||
import { Props } from './InternalKeys';
|
||||
|
||||
// button、input、select、textarea、如果有 autoFocus 属性需要focus
|
||||
export function shouldAutoFocus(tagName: string, props: Props): boolean {
|
||||
const { button, input, select, textarea } = InulaReconciler.hostConfig.elementConfig;
|
||||
const types = [button.nodeName, input.nodeName, select.nodeName, textarea.nodeName];
|
||||
|
||||
return types.includes(tagName) ? Boolean(props.autoFocus) : false;
|
||||
}
|
||||
|
||||
export function isNotNull(object: any): boolean {
|
||||
return object !== null && object !== undefined;
|
||||
}
|
||||
export function getTag(element: ElementType) {
|
||||
return element?.nodeName?.toLowerCase();
|
||||
}
|
||||
|
||||
export function isInputElement(element: ElementType): boolean {
|
||||
return getTag(element) === InulaReconciler.hostConfig.elementConfig.input.nodeName;
|
||||
}
|
||||
export function isElement(element: ElementType) {
|
||||
return element.nodeType === InulaReconciler.hostConfig.elementConfig.common.nodeType;
|
||||
}
|
||||
|
||||
export function isText(element: ElementType) {
|
||||
return element.nodeType === InulaReconciler.hostConfig.elementConfig.text.nodeType;
|
||||
}
|
||||
|
||||
export function isDocument(dom: ElementType) {
|
||||
return dom.nodeType === 9;
|
||||
}
|
||||
|
|
@ -20,13 +20,13 @@ import {
|
|||
TreeRoot,
|
||||
FunctionComponent,
|
||||
ClassComponent,
|
||||
Portal,
|
||||
Text,
|
||||
DomPortal,
|
||||
DomText,
|
||||
ContextConsumer,
|
||||
ForwardRef,
|
||||
SuspenseComponent,
|
||||
LazyComponent,
|
||||
Component,
|
||||
DomComponent,
|
||||
Fragment,
|
||||
ContextProvider,
|
||||
Profiler,
|
||||
|
|
@ -153,19 +153,19 @@ export class VNode {
|
|||
this.classComponentWillUnmount = null;
|
||||
this.src = null;
|
||||
break;
|
||||
case Portal:
|
||||
case DomPortal:
|
||||
this.realNode = null;
|
||||
this.context = null;
|
||||
this.delegatedEvents = new Set<string>();
|
||||
this.src = null;
|
||||
break;
|
||||
case Component:
|
||||
case DomComponent:
|
||||
this.realNode = null;
|
||||
this.changeList = null;
|
||||
this.context = null;
|
||||
this.src = null;
|
||||
break;
|
||||
case Text:
|
||||
case DomText:
|
||||
this.realNode = null;
|
||||
break;
|
||||
case SuspenseComponent:
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ import {
|
|||
ForwardRef,
|
||||
Fragment,
|
||||
FunctionComponent,
|
||||
Component,
|
||||
Portal,
|
||||
DomComponent,
|
||||
DomPortal,
|
||||
TreeRoot,
|
||||
Text,
|
||||
DomText,
|
||||
LazyComponent,
|
||||
MemoComponent,
|
||||
SuspenseComponent,
|
||||
|
|
@ -108,14 +108,14 @@ export function createFragmentVNode(fragmentKey, fragmentProps) {
|
|||
}
|
||||
|
||||
export function createDomTextVNode(content) {
|
||||
const vNode = newVirtualNode(Text, null, content);
|
||||
const vNode = newVirtualNode(DomText, null, content);
|
||||
vNode.shouldUpdate = true;
|
||||
return vNode;
|
||||
}
|
||||
|
||||
export function createPortalVNode(portal) {
|
||||
const children = portal.children ?? [];
|
||||
const vNode = newVirtualNode(Portal, portal.key, children);
|
||||
const vNode = newVirtualNode(DomPortal, portal.key, children);
|
||||
vNode.shouldUpdate = true;
|
||||
vNode.realNode = portal.realNode;
|
||||
return vNode;
|
||||
|
|
@ -130,7 +130,7 @@ export function createUndeterminedVNode(type, key, props, source: Source | null)
|
|||
vNodeTag = ClassComponent;
|
||||
}
|
||||
} else if (componentType === 'string') {
|
||||
vNodeTag = Component;
|
||||
vNodeTag = DomComponent;
|
||||
} else if (type === TYPE_SUSPENSE) {
|
||||
vNodeTag = SuspenseComponent;
|
||||
} else if (componentType === 'object' && type !== null && typeMap[type.vtype]) {
|
||||
|
|
@ -166,7 +166,7 @@ export function getElementTag(element: JSXElement): string {
|
|||
vNodeTag = ClassComponent;
|
||||
}
|
||||
} else if (componentType === 'string') {
|
||||
vNodeTag = Component;
|
||||
vNodeTag = DomComponent;
|
||||
} else if (type === TYPE_SUSPENSE) {
|
||||
vNodeTag = SuspenseComponent;
|
||||
} else if (componentType === 'object' && type !== null && typeMap[type.vtype]) {
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ export type VNodeTag = string;
|
|||
export const TreeRoot = 'TreeRoot'; // tree的根节点,用于存放一些tree级的变量
|
||||
export const FunctionComponent = 'FunctionComponent';
|
||||
export const ClassComponent = 'ClassComponent';
|
||||
export const Portal = 'Portal';
|
||||
export const Component = 'Component';
|
||||
export const Text = 'Text';
|
||||
export const DomPortal = 'DomPortal';
|
||||
export const DomComponent = 'DomComponent';
|
||||
export const DomText = 'DomText';
|
||||
export const Fragment = 'Fragment';
|
||||
export const ContextConsumer = 'ContextConsumer';
|
||||
export const ContextProvider = 'ContextProvider';
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
import type { VNode } from '../Types';
|
||||
|
||||
import { Component, Portal, Text, TreeRoot } from './VNodeTags';
|
||||
import { getNearestVNode } from '../../renderer/utils/InternalKeys';
|
||||
import { DomComponent, DomPortal, DomText, TreeRoot } from './VNodeTags';
|
||||
import { getNearestVNode } from '../../dom/DOMInternalKeys';
|
||||
import { Addition, InitFlag } from './VNodeFlags';
|
||||
import { BELONG_CLASS_VNODE_KEY } from './VNode';
|
||||
|
||||
|
|
@ -133,19 +133,19 @@ export function clearVNode(vNode: VNode) {
|
|||
|
||||
// 是dom类型的vNode
|
||||
export function isDomVNode(node: VNode) {
|
||||
return node.tag === Component || node.tag === Text;
|
||||
return node.tag === DomComponent || node.tag === DomText;
|
||||
}
|
||||
|
||||
// 是容器类型的vNode
|
||||
function isDomContainer(vNode: VNode): boolean {
|
||||
return vNode.tag === Component || vNode.tag === TreeRoot || vNode.tag === Portal;
|
||||
return vNode.tag === DomComponent || vNode.tag === TreeRoot || vNode.tag === DomPortal;
|
||||
}
|
||||
|
||||
export function findDomVNode(vNode: VNode): VNode | null {
|
||||
const ret = travelVNodeTree(
|
||||
vNode,
|
||||
node => {
|
||||
if (node.tag === Component || node.tag === Text) {
|
||||
if (node.tag === DomComponent || node.tag === DomText) {
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
|
|
@ -210,7 +210,7 @@ export function getSiblingDom(vNode: VNode): Element | null {
|
|||
}
|
||||
|
||||
// 没有子节点,或是DomPortal
|
||||
if (!node.child || node.tag === Portal) {
|
||||
if (!node.child || node.tag === DomPortal) {
|
||||
continue findSibling;
|
||||
} else {
|
||||
const childVNode = node.child;
|
||||
|
|
@ -227,11 +227,11 @@ export function getSiblingDom(vNode: VNode): Element | null {
|
|||
}
|
||||
|
||||
function isPortalRoot(vNode, targetContainer) {
|
||||
if (vNode.tag === Portal) {
|
||||
if (vNode.tag === DomPortal) {
|
||||
let topVNode = vNode.parent;
|
||||
while (topVNode !== null) {
|
||||
const grandTag = topVNode.tag;
|
||||
if (grandTag === TreeRoot || grandTag === Portal) {
|
||||
if (grandTag === TreeRoot || grandTag === DomPortal) {
|
||||
const topContainer = topVNode.realNode;
|
||||
// 如果topContainer是targetContainer,不需要在这里处理
|
||||
if (topContainer === targetContainer) {
|
||||
|
|
@ -250,7 +250,7 @@ export function findRoot(targetVNode, targetDom) {
|
|||
// 确认vNode节点是否准确,portal场景下可能祖先节点不准确
|
||||
let vNode = targetVNode;
|
||||
while (vNode !== null) {
|
||||
if (vNode.tag === TreeRoot || vNode.tag === Portal) {
|
||||
if (vNode.tag === TreeRoot || vNode.tag === DomPortal) {
|
||||
let dom = vNode.realNode;
|
||||
if (dom === targetDom) {
|
||||
break;
|
||||
|
|
@ -264,7 +264,7 @@ export function findRoot(targetVNode, targetDom) {
|
|||
if (parentNode === null) {
|
||||
return null;
|
||||
}
|
||||
if (parentNode.tag === Component || parentNode.tag === Text) {
|
||||
if (parentNode.tag === DomComponent || parentNode.tag === DomText) {
|
||||
return findRoot(parentNode, targetDom);
|
||||
}
|
||||
dom = dom.parentNode;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { Component } from './renderer/components/BaseClassComponent';
|
|||
import { MutableRef, RefCallBack, RefObject } from './renderer/hooks/HookType';
|
||||
|
||||
import * as Event from './EventTypes';
|
||||
import { BaseElement } from './jsx-type';
|
||||
|
||||
//
|
||||
// --------------------------------- Inula Base Types ----------------------------------
|
||||
|
|
@ -67,7 +68,6 @@ interface ConsumerProps<T> {
|
|||
export interface Context<T> {
|
||||
Provider: ExoticComponent<ProviderProps<T>>;
|
||||
Consumer: ExoticComponent<ConsumerProps<T>>;
|
||||
// 兼容React
|
||||
displayName?: string | undefined;
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +77,28 @@ export interface FunctionComponent<P = KVObject> {
|
|||
displayName?: string;
|
||||
}
|
||||
|
||||
export type ClassType<P, T extends Component<P, ComponentState>, C extends ComponentClass<P>> = C &
|
||||
(new (props: P, context?: any) => T);
|
||||
export interface ClassicComponent<P = KVObject, S = KVObject> extends Component<P, S> {
|
||||
replaceState(nextState: S, callback?: () => void): void;
|
||||
isMounted(): boolean;
|
||||
getInitialState?(): S;
|
||||
}
|
||||
|
||||
export type InulaCElement<P, T extends Component<P, ComponentState>> = ComponentElement<P, T>;
|
||||
interface ComponentElement<P, T extends Component<P, ComponentState>> extends InulaElement<P, ComponentClass<P>> {
|
||||
ref?: LegacyRef<T> | undefined;
|
||||
}
|
||||
|
||||
export interface ClassicComponentClass<P = KVObject> extends ComponentClass<P> {
|
||||
new (props: P, context?: any): ClassicComponent<P, ComponentState>;
|
||||
getDefaultProps?(): P;
|
||||
}
|
||||
|
||||
export interface FunctionComponentElement<P> extends InulaElement<P, FunctionComponent<P>> {
|
||||
ref?: ('ref' extends keyof P ? (P extends { ref?: infer R | undefined } ? R : never) : never) | undefined;
|
||||
}
|
||||
|
||||
export interface ComponentClass<P = KVObject, S = ComponentState> extends StaticLifecycle<P, S> {
|
||||
new (props: P, context?: unknown): Component<P, S>;
|
||||
|
||||
|
|
@ -119,7 +141,7 @@ export type PropsWithRef<P> = 'ref' extends keyof P
|
|||
: P
|
||||
: P;
|
||||
|
||||
type Attributes = {
|
||||
export type Attributes = {
|
||||
key?: Key | null | undefined;
|
||||
};
|
||||
|
||||
|
|
@ -272,7 +294,7 @@ interface InulaBaseEvent<E = unknown, Tr = unknown, Ta = unknown> {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
interface SyntheticEvent<T = Element, E = Event> extends InulaBaseEvent<E, EventTarget & T, EventTarget> {}
|
||||
export interface SyntheticEvent<T = Element, E = Event> extends InulaBaseEvent<E, EventTarget & T, EventTarget> {}
|
||||
|
||||
export interface ClipboardEvent<T = Element> extends SyntheticEvent<T, Event.DomClipboardEvent> {
|
||||
clipboardData: DataTransfer;
|
||||
|
|
@ -410,23 +432,59 @@ export interface MouseEvent<T = Element, E = Event.DomMouseEvent> extends UIEven
|
|||
|
||||
export type EventHandler<E extends SyntheticEvent<unknown>> = { bivarianceHack(event: E): void }['bivarianceHack'];
|
||||
|
||||
export type ClipboardEventHandler<T = Element> = EventHandler<ClipboardEvent<T>>;
|
||||
export type CompositionEventHandler<T = Element> = EventHandler<CompositionEvent<T>>;
|
||||
export type DragEventHandler<T = Element> = EventHandler<DragEvent<T>>;
|
||||
export type FocusEventHandler<T = Element> = EventHandler<FocusEvent<T>>;
|
||||
export type FormEventHandler<T = Element> = EventHandler<FormEvent<T>>;
|
||||
export type ChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;
|
||||
export type KeyboardEventHandler<T = Element> = EventHandler<KeyboardEvent<T>>;
|
||||
export type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;
|
||||
export type TouchEventHandler<T = Element> = EventHandler<TouchEvent<T>>;
|
||||
export type PointerEventHandler<T = Element> = EventHandler<PointerEvent<T>>;
|
||||
export type UIEventHandler<T = Element> = EventHandler<UIEvent<T>>;
|
||||
export type WheelEventHandler<T = Element> = EventHandler<WheelEvent<T>>;
|
||||
export type AnimationEventHandler<T = Element> = EventHandler<AnimationEvent<T>>;
|
||||
export type TransitionEventHandler<T = Element> = EventHandler<TransitionEvent<T>>;
|
||||
export type InulaClipboardEventHandler<T = Element> = EventHandler<ClipboardEvent<T>>;
|
||||
export type InulaCompositionEventHandler<T = Element> = EventHandler<CompositionEvent<T>>;
|
||||
export type InulaDragEventHandler<T = Element> = EventHandler<DragEvent<T>>;
|
||||
export type InulaFocusEventHandler<T = Element> = EventHandler<FocusEvent<T>>;
|
||||
export type InulaFormEventHandler<T = Element> = EventHandler<FormEvent<T>>;
|
||||
export type InulaChangeEventHandler<T = Element> = EventHandler<ChangeEvent<T>>;
|
||||
export type InulaKeyboardEventHandler<T = Element> = EventHandler<KeyboardEvent<T>>;
|
||||
export type InulaMouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;
|
||||
export type InulaTouchEventHandler<T = Element> = EventHandler<TouchEvent<T>>;
|
||||
export type InulaPointerEventHandler<T = Element> = EventHandler<PointerEvent<T>>;
|
||||
export type InulaUIEventHandler<T = Element> = EventHandler<UIEvent<T>>;
|
||||
export type InulaWheelEventHandler<T = Element> = EventHandler<WheelEvent<T>>;
|
||||
export type InulaAnimationEventHandler<T = Element> = EventHandler<AnimationEvent<T>>;
|
||||
export type InulaTransitionEventHandler<T = Element> = EventHandler<TransitionEvent<T>>;
|
||||
|
||||
//
|
||||
// --------------------------------- Css Props----------------------------------
|
||||
//
|
||||
|
||||
export type CSSProperties = Record<string | number, any>;
|
||||
|
||||
//
|
||||
// --------------------------------- VDOM ---------------------------------------
|
||||
//
|
||||
export type LegacyRef<T> = string | Ref<T>;
|
||||
export interface ClassAttributes<T> extends Attributes {
|
||||
ref?: LegacyRef<T> | undefined;
|
||||
}
|
||||
|
||||
export interface InulaCSSProperties extends CSSProperties {}
|
||||
|
||||
export type InulaBoolean = boolean | 'true' | 'false';
|
||||
|
||||
export type InulaEventHandler<T = Element> = EventHandler<SyntheticEvent<T>>;
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace JSX {
|
||||
interface IntrinsicAttributes extends Attributes {}
|
||||
interface Element extends InulaElement<any, any> {}
|
||||
|
||||
interface ElementClass extends Component<any> {
|
||||
render(): InulaNode;
|
||||
}
|
||||
|
||||
interface ElementAttributesProperty {
|
||||
props: KVObject;
|
||||
}
|
||||
interface ElementChildrenAttribute {
|
||||
children: KVObject;
|
||||
}
|
||||
interface IntrinsicClassAttributes<T> extends ClassAttributes<T> {}
|
||||
|
||||
type IntrinsicElements = BaseElement;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import * as Inula from '../../src/index';
|
|||
|
||||
describe('mouseenter和mouseleave事件测试', () => {
|
||||
let container;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
container = document.createElement('div');
|
||||
|
|
@ -253,6 +254,7 @@ describe('mouseenter和mouseleave事件测试', () => {
|
|||
const divRef = Inula.createRef();
|
||||
const otherDivRef = Inula.createRef();
|
||||
const onMouseEnter = jest.fn();
|
||||
|
||||
function Component() {
|
||||
return (
|
||||
<div ref={divRef}>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* See the Mulan PSL v2 for more details.
|
||||
*/
|
||||
|
||||
import { unmountComponentAtNode } from '../../src/renderer/External';
|
||||
import { unmountComponentAtNode } from '../../src/dom/DOMExternal';
|
||||
import { getLogUtils } from './testUtils';
|
||||
|
||||
const LogUtils = getLogUtils();
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
import { defineConfig } from 'father';
|
||||
|
||||
export default defineConfig({
|
||||
cjs: {
|
||||
output: 'dist',
|
||||
ignores: ['src/client/**'],
|
||||
},
|
||||
esm: {
|
||||
input: 'src/client',
|
||||
output: 'client/client',
|
||||
},
|
||||
});
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/node_modules
|
||||
/packages/**/node_modules
|
||||
/packages/**/dist
|
||||
/packages/**/tsconfig.tsbuildinfo
|
||||
/packages/**/src/**/fixtures/*/dist
|
||||
/packages/**/src/**/fixtures/*/.umi
|
||||
/packages/**/src/**/fixtures/*/.umi-production
|
||||
.umi
|
||||
.inula
|
||||
.umi-production
|
||||
.inula-production
|
||||
.umi-test
|
||||
.inula-test
|
||||
dist
|
||||
es
|
||||
lib
|
||||
.turbo
|
||||
.idea
|
||||
playwright-report
|
||||
/packages/inula/client
|
||||
.env.local
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# Inula
|
||||
|
||||
## 项目简介
|
||||
|
||||
inula-max 是一个关注业务需求,以开发体验为主的前端框架,集成 openInula 全生态。
|
||||
|
||||
## 快速开始
|
||||
|
||||
你可以通过以下步骤快速开始使用 Inula:
|
||||
|
||||
```base
|
||||
npx inula-max init [dir]
|
||||
```
|
||||
|
||||
初始化一个 Inula 项目,目录可选,一般操作是新建一个空白文件夹,再执行 `npx inula-max init` 即可。
|
||||
|
||||
## 特性
|
||||
|
||||
### openInula 官方组件
|
||||
|
||||
#### 状态管理器
|
||||
|
||||
Inula-X 是 openInula 默认提供的状态管理器,无需额外引入三方库,就可以简单实现跨组件/页面共享状态。
|
||||
|
||||
|
||||
#### 请求
|
||||
|
||||
Inula-request 涵盖常见的网络请求方式,并提供动态轮询钩子函数给用户更便捷的定制化请求体验。
|
||||
|
||||
#### 国际化
|
||||
|
||||
Inula-intl 提供了国际化功能,涵盖了基本的国际化组件和钩子函数,便于用户在构建国际化能力时方便操作。
|
||||
|
||||
### 其他能力
|
||||
|
||||
#### antd
|
||||
|
||||
Ant Design 是一个功能丰富的 UI 组件库。
|
||||
|
||||
#### ProComponents
|
||||
|
||||
ProComponents 是一个让中后台开发更简单的工具。
|
||||
|
||||
#### AIGC
|
||||
|
||||
AIGC 是一个使用 Azure Api 对接 OpenAI ChatGPT 4 模型的能力,可以快速使用 AIGC 助力业务开发。
|
||||
|
||||
## 更多信息
|
||||
|
||||
请访问 [OpenInula 文档](https://docs.openinula.net/) 获取更多详细信息。
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎贡献代码和提出问题!请查看 [贡献指南](CONTRIBUTING.md) 了解如何参与项目。
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目基于 [MIT](LICENSE) 许可证开源。
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
// setNodeTitle
|
||||
process.title = 'inula';
|
||||
// Use magic to suppress node deprecation warnings
|
||||
// See: https://github.com/nodejs/node/blob/master/lib/internal/process/warning.js#L77
|
||||
// @ts-ignore
|
||||
process.noDeprecation = '1';
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
require('../dist/cli')
|
||||
.run()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
export declare enum ApplyPluginsType {
|
||||
compose = "compose",
|
||||
modify = "modify",
|
||||
event = "event"
|
||||
}
|
||||
interface IPlugin {
|
||||
path?: string;
|
||||
apply: Record<string, any>;
|
||||
}
|
||||
export declare class PluginManager {
|
||||
opts: {
|
||||
validKeys: string[];
|
||||
};
|
||||
hooks: {
|
||||
[key: string]: any;
|
||||
};
|
||||
constructor(opts: {
|
||||
validKeys: string[];
|
||||
});
|
||||
register(plugin: IPlugin): void;
|
||||
getHooks(keyWithDot: string): any;
|
||||
applyPlugins({ key, type, initialValue, args, async, }: {
|
||||
key: string;
|
||||
type: ApplyPluginsType;
|
||||
initialValue?: any;
|
||||
args?: object;
|
||||
async?: boolean;
|
||||
}): any;
|
||||
static create(opts: {
|
||||
validKeys: string[];
|
||||
plugins: IPlugin[];
|
||||
}): PluginManager;
|
||||
}
|
||||
export {};
|
||||
//# sourceMappingURL=plugin.d.ts.map
|
||||
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/client/plugin.ts"],"names":[],"mappings":"AAEA,oBAAY,gBAAgB;IAC1B,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,KAAK,UAAU;CAChB;AAED,UAAU,OAAO;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,qBAAa,aAAa;IACxB,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC9B,KAAK,EAAE;QACL,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAM;gBACK,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE;IAIzC,QAAQ,CAAC,MAAM,EAAE,OAAO;IAaxB,QAAQ,CAAC,UAAU,EAAE,MAAM;IAqB3B,YAAY,CAAC,EACX,GAAG,EACH,IAAI,EACJ,YAAY,EACZ,IAAI,EACJ,KAAK,GACN,EAAE;QACD,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,gBAAgB,CAAC;QACvB,YAAY,CAAC,EAAE,GAAG,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;IAuFD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,EAAE,CAAA;KAAE;CAShE"}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +0,0 @@
|
|||
export declare function assert(value: unknown, message: string): void;
|
||||
export declare function compose({ fns, args, }: {
|
||||
fns: (Function | any)[];
|
||||
args?: object;
|
||||
}): any;
|
||||
export declare function isPromiseLike(obj: any): boolean;
|
||||
//# sourceMappingURL=utils.d.ts.map
|
||||
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/client/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,QAErD;AAED,wBAAgB,OAAO,CAAC,EACtB,GAAG,EACH,IAAI,GACL,EAAE;IACD,GAAG,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,OAMA;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,WAErC"}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
export function assert(value, message) {
|
||||
if (!value) throw new Error(message);
|
||||
}
|
||||
export function compose(_ref) {
|
||||
var fns = _ref.fns,
|
||||
args = _ref.args;
|
||||
if (fns.length === 1) {
|
||||
return fns[0];
|
||||
}
|
||||
var last = fns.pop();
|
||||
return fns.reduce(function (a, b) {
|
||||
return function () {
|
||||
return b(a, args);
|
||||
};
|
||||
}, last);
|
||||
}
|
||||
export function isPromiseLike(obj) {
|
||||
return !!obj && _typeof(obj) === 'object' && typeof obj.then === 'function';
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
import { defineConfig } from 'inula-max';
|
||||
|
||||
export default defineConfig({
|
||||
title: 'boilerplate',
|
||||
});
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"name": "@example/boilerplate",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "inula-max build",
|
||||
"build-analyze": "ANALYZE=1 inula-max build",
|
||||
"dev": "inula-max dev",
|
||||
"preview": "inula-max preview",
|
||||
"setup": "inula-max setup",
|
||||
"start": "npm run dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"inula-max": "link:.."
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import { useStore } from 'inula';
|
||||
|
||||
const Page = () => {
|
||||
const store = useStore('hello');
|
||||
return (
|
||||
<div>
|
||||
hello {store.title}
|
||||
<button
|
||||
onClick={() => {
|
||||
store.changeName();
|
||||
}}
|
||||
>
|
||||
改名字啦
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { createStore } from 'inula';
|
||||
|
||||
export default createStore({
|
||||
id: 'hello12',
|
||||
actions: {
|
||||
changeName: (state) => {
|
||||
state.title = 'openinula';
|
||||
},
|
||||
},
|
||||
state: {
|
||||
title: 'inulajs',
|
||||
},
|
||||
});
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import { createStore } from 'inula';
|
||||
|
||||
export default createStore({
|
||||
id: 'hello',
|
||||
actions: {
|
||||
changeName: (state) => {
|
||||
state.title = 'openinula';
|
||||
},
|
||||
},
|
||||
state: {
|
||||
title: 'inulajs',
|
||||
},
|
||||
});
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"extends": "./src/.inula-max/tsconfig.json",
|
||||
"compilerOptions":{
|
||||
"paths": {
|
||||
"inula-max": [
|
||||
"../../"
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
import "inula/typings";
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
try {
|
||||
require.resolve('@umijs/lint/package.json');
|
||||
} catch (err) {
|
||||
throw new Error('@umijs/lint is not built-in, please install it manually before run umi lint.');
|
||||
}
|
||||
|
||||
module.exports = process.env.LEGACY_ESLINT ? require('@umijs/lint/dist/config/eslint/legacy') : require('@umijs/lint/dist/config/eslint');
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// @ts-ignore
|
||||
export * from '@@/exports';
|
||||
export type {
|
||||
IApi,
|
||||
webpack,
|
||||
IRoute,
|
||||
UmiApiRequest,
|
||||
UmiApiResponse,
|
||||
} from '@aluni/types';
|
||||
export * from './dist';
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
{
|
||||
"name": "inula-max",
|
||||
"version": "0.0.1",
|
||||
"description": "A Inulajs framework based on umi.",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "index.d.ts",
|
||||
"bin": {
|
||||
"inula-max": "bin/inula.js"
|
||||
},
|
||||
"files": [
|
||||
"assets",
|
||||
"bin",
|
||||
"client",
|
||||
"dist",
|
||||
"index.d.ts",
|
||||
"plugin-utils.d.ts",
|
||||
"plugin-utils.js",
|
||||
"eslint.js",
|
||||
"prettier.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "father build",
|
||||
"dev": "father dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aluni/preset-inula": "0.0.5",
|
||||
"@aluni/types": "^0.0.5",
|
||||
"@umijs/bundler-utils": "4.0.88",
|
||||
"@umijs/bundler-vite": "4.0.88",
|
||||
"@umijs/bundler-webpack": "4.0.88",
|
||||
"@umijs/core": "4.0.88",
|
||||
"@umijs/lint": "4.0.88",
|
||||
"@umijs/openapi": "^1.13.0",
|
||||
"@umijs/preset-blocks": "0.0.4",
|
||||
"@umijs/preset-umi": "4.0.88",
|
||||
"@umijs/server": "4.0.88",
|
||||
"@umijs/utils": "4.0.88",
|
||||
"prettier": "^2.6.2",
|
||||
"prettier-plugin-organize-imports": "^3.2.2",
|
||||
"prettier-plugin-packagejson": "2.4.3",
|
||||
"rimraf": "^6.0.1",
|
||||
"openinula": "0.1.1",
|
||||
"serve-static": "^1.16.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"authors": [
|
||||
"chenxiaocong <xiaohuoni@gmail.com> (https://github.com/xiaohuoni)"
|
||||
],
|
||||
"devDependencies": {
|
||||
"father": "^4.5.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export * from './dist/pluginUtils';
|
||||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('./dist/pluginUtils');
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
module.exports = {
|
||||
printWidth: 80,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
proseWrap: 'never',
|
||||
endOfLine: 'lf',
|
||||
overrides: [{ files: '.prettierrc', options: { parser: 'json' } }],
|
||||
plugins: [
|
||||
require.resolve('prettier-plugin-packagejson'),
|
||||
require.resolve('prettier-plugin-organize-imports'),
|
||||
],
|
||||
pluginSearchDirs: false,
|
||||
};
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
import { deepmerge, logger, yParser } from '@umijs/utils';
|
||||
import { BUILD_COMMANDS, DEV_COMMAND } from './constants';
|
||||
import {
|
||||
checkLocal,
|
||||
checkVersion as checkNodeVersion,
|
||||
setNoDeprecation,
|
||||
setNodeTitle,
|
||||
} from './node';
|
||||
import { Service } from './service';
|
||||
|
||||
interface IOpts {
|
||||
args?: yParser.Arguments;
|
||||
}
|
||||
|
||||
export async function run(_opts?: IOpts) {
|
||||
checkNodeVersion();
|
||||
checkLocal();
|
||||
setNodeTitle();
|
||||
setNoDeprecation();
|
||||
|
||||
const args =
|
||||
_opts?.args ||
|
||||
yParser(process.argv.slice(2), {
|
||||
alias: {
|
||||
version: ['v'],
|
||||
help: ['h'],
|
||||
},
|
||||
boolean: ['version'],
|
||||
});
|
||||
const command = args._[0];
|
||||
|
||||
if (command === DEV_COMMAND) {
|
||||
process.env.NODE_ENV = 'development';
|
||||
} else if (BUILD_COMMANDS.includes(command)) {
|
||||
process.env.NODE_ENV = 'production';
|
||||
}
|
||||
|
||||
try {
|
||||
const service = new Service();
|
||||
|
||||
await service.run2({
|
||||
name: command,
|
||||
args: deepmerge({}, args),
|
||||
});
|
||||
|
||||
// handle restart for dev command
|
||||
if (command === DEV_COMMAND) {
|
||||
async function listener(data: any) {
|
||||
if (data?.type === 'RESTART') {
|
||||
// off self
|
||||
process.off('message', listener);
|
||||
|
||||
// restart
|
||||
run({ args });
|
||||
}
|
||||
}
|
||||
|
||||
process.on('message', listener);
|
||||
}
|
||||
} catch (e: any) {
|
||||
logger.error(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
import { ApplyPluginsType, PluginManager } from './plugin';
|
||||
|
||||
const delay = (ms: number) => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
test('PluginManager#applyPlugins in async=false mode', async () => {
|
||||
const pm = new PluginManager({
|
||||
validKeys: ['foo'],
|
||||
});
|
||||
|
||||
const asyncCall = jest.fn();
|
||||
const syncCall = jest.fn();
|
||||
|
||||
pm.register({
|
||||
apply: {
|
||||
foo: async () => {
|
||||
await delay(100);
|
||||
asyncCall();
|
||||
},
|
||||
},
|
||||
path: '/a',
|
||||
});
|
||||
pm.register({
|
||||
apply: {
|
||||
foo: syncCall,
|
||||
},
|
||||
path: '/a',
|
||||
});
|
||||
|
||||
await pm.applyPlugins({
|
||||
key: 'foo',
|
||||
type: ApplyPluginsType.event,
|
||||
async: false,
|
||||
});
|
||||
|
||||
expect(syncCall).toBeCalled();
|
||||
expect(asyncCall).not.toBeCalled();
|
||||
});
|
||||
|
||||
test('PluginManager#applyPlugins in async=true mode', async () => {
|
||||
const pm = new PluginManager({
|
||||
validKeys: ['foo'],
|
||||
});
|
||||
|
||||
const asyncCall = jest.fn();
|
||||
const syncCall = jest.fn();
|
||||
|
||||
pm.register({
|
||||
apply: {
|
||||
foo: async () => {
|
||||
await delay(100);
|
||||
asyncCall();
|
||||
},
|
||||
},
|
||||
path: '/a',
|
||||
});
|
||||
pm.register({
|
||||
apply: {
|
||||
foo: syncCall,
|
||||
},
|
||||
path: '/a',
|
||||
});
|
||||
|
||||
await pm.applyPlugins({
|
||||
key: 'foo',
|
||||
type: ApplyPluginsType.event,
|
||||
async: true,
|
||||
});
|
||||
|
||||
expect(syncCall).toBeCalled();
|
||||
expect(asyncCall).toBeCalled();
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue