@geektech/tsone 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/dist/core/app.d.ts +92 -0
- package/dist/core/component/base.d.ts +53 -0
- package/dist/core/component/index.d.ts +4 -0
- package/dist/core/component.d.ts +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/reactive/types.d.ts +19 -0
- package/dist/core/reactive.d.ts +31 -0
- package/dist/core/renderer/props.d.ts +9 -0
- package/dist/core/renderer/types.d.ts +31 -0
- package/dist/core/renderer.d.ts +57 -0
- package/dist/core/template.d.ts +50 -0
- package/dist/core/vnode.d.ts +64 -0
- package/dist/index-3j2jsdpc.js +1498 -0
- package/dist/index-3j2jsdpc.js.map +20 -0
- package/dist/index-dgv88dz4.js +59 -0
- package/dist/index-dgv88dz4.js.map +10 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +248 -0
- package/dist/index.js.map +11 -0
- package/dist/router/history.d.ts +5 -0
- package/dist/router/index.d.ts +88 -0
- package/dist/router/index.js +16 -0
- package/dist/router/index.js.map +9 -0
- package/dist/router/instance.d.ts +26 -0
- package/dist/router/matcher.d.ts +7 -0
- package/dist/style/StyleManager.d.ts +16 -0
- package/dist/style/class-style.d.ts +0 -0
- package/dist/style/id-style.d.ts +0 -0
- package/dist/style/index.d.ts +1 -0
- package/dist/style/index.js +9 -0
- package/dist/style/index.js.map +9 -0
- package/dist/style/style.d.ts +0 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Geek Tech Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# TSone
|
|
2
|
+
|
|
3
|
+
轻量级纯 TypeScript 前端框架,提供响应式系统、类组件、策略化渲染和路由能力。
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- 纯 TypeScript 实现,公开 API 提供类型定义
|
|
8
|
+
- Bun 原生工具链:安装、测试、构建、示例服务和文档服务均由 Bun 驱动
|
|
9
|
+
- 响应式系统:`reactive`、`effect`、`computed`
|
|
10
|
+
- 面向对象组件模型:`Component<Props, State>`、生命周期、事件、插槽
|
|
11
|
+
- 策略模式渲染层:文本、元素、组件、插槽按 VNode 类型分发
|
|
12
|
+
- 内置路由:`createRouter`、`RouterView`、`RouterLink`
|
|
13
|
+
- 轻量级运行时,生产包无外部运行时依赖
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add @geektech/tsone
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @geektech/tsone
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 快速开始
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import {
|
|
29
|
+
Component,
|
|
30
|
+
VNode,
|
|
31
|
+
createApp,
|
|
32
|
+
computed,
|
|
33
|
+
reactive,
|
|
34
|
+
} from '@geektech/tsone';
|
|
35
|
+
|
|
36
|
+
interface AppState {
|
|
37
|
+
count: number;
|
|
38
|
+
version: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class App extends Component<Record<string, never>, AppState> {
|
|
42
|
+
protected initState(): AppState {
|
|
43
|
+
return {
|
|
44
|
+
count: 0,
|
|
45
|
+
version: '0.0.1',
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected initStyles(): void {}
|
|
50
|
+
|
|
51
|
+
protected render(): VNode {
|
|
52
|
+
return {
|
|
53
|
+
tag: 'main',
|
|
54
|
+
props: { className: 'app' },
|
|
55
|
+
children: [
|
|
56
|
+
{ tag: 'h1', children: ['TSone'] },
|
|
57
|
+
{ tag: 'p', children: [`version: '{{version}}'`] },
|
|
58
|
+
{
|
|
59
|
+
tag: 'button',
|
|
60
|
+
listeners: {
|
|
61
|
+
click: () => {
|
|
62
|
+
this.state.count += 1;
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
children: [`count: {{count}}`],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const state = reactive({ ready: true });
|
|
73
|
+
const status = computed(() => (state.ready ? 'ready' : 'pending'));
|
|
74
|
+
|
|
75
|
+
const app = createApp({ root: App, rootElement: '#app', state });
|
|
76
|
+
app.mount();
|
|
77
|
+
|
|
78
|
+
console.log(status.value);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 路由
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { Component, VNode, createApp } from '@geektech/tsone';
|
|
85
|
+
import { RouterLink, RouterView, createRouter } from '@geektech/tsone/router';
|
|
86
|
+
|
|
87
|
+
class Layout extends Component {
|
|
88
|
+
protected initState(): object {
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
protected initStyles(): void {}
|
|
93
|
+
|
|
94
|
+
protected render(): VNode {
|
|
95
|
+
return {
|
|
96
|
+
tag: 'main',
|
|
97
|
+
children: [
|
|
98
|
+
{
|
|
99
|
+
component: RouterLink,
|
|
100
|
+
props: { to: '/', children: ['首页'] },
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
component: RouterLink,
|
|
104
|
+
props: { to: '/users/42', children: ['用户'] },
|
|
105
|
+
},
|
|
106
|
+
{ component: RouterView },
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const router = createRouter({
|
|
113
|
+
mode: 'history',
|
|
114
|
+
routes: [
|
|
115
|
+
{ path: '/', component: HomePage },
|
|
116
|
+
{ path: '/users/:id', component: UserPage, meta: { title: '用户详情' } },
|
|
117
|
+
],
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
createApp({ root: Layout, rootElement: '#app' }).use(router).mount();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 开发命令
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
bun install
|
|
127
|
+
bun test
|
|
128
|
+
bun run build
|
|
129
|
+
bun run dev
|
|
130
|
+
bun run docs
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 公开 API
|
|
134
|
+
|
|
135
|
+
主入口 `@geektech/tsone`:
|
|
136
|
+
|
|
137
|
+
- `createApp(options)`
|
|
138
|
+
- `Component<Props, State>`
|
|
139
|
+
- `VNode`
|
|
140
|
+
- `h()` / `createComponent()` / `slot()`
|
|
141
|
+
- `reactive()` / `readonly()`
|
|
142
|
+
- `effect()` / `stop()`
|
|
143
|
+
- `computed()`
|
|
144
|
+
- `ref()` / `isRef()` / `unref()`
|
|
145
|
+
- `version`,当前为 `0.0.1`
|
|
146
|
+
|
|
147
|
+
路由入口 `@geektech/tsone/router`:
|
|
148
|
+
|
|
149
|
+
- `createRouter({ routes, mode, base })`
|
|
150
|
+
- `Router`
|
|
151
|
+
- `RouterView`
|
|
152
|
+
- `RouterLink`
|
|
153
|
+
- `useRouter()`
|
|
154
|
+
- `RouteRecord`
|
|
155
|
+
- `RouteLocation`
|
|
156
|
+
|
|
157
|
+
样式入口 `@geektech/tsone/style`:
|
|
158
|
+
|
|
159
|
+
- `StyleManager`
|
|
160
|
+
|
|
161
|
+
## 发布前检查
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
bun test
|
|
165
|
+
bunx tsc --noEmit
|
|
166
|
+
bun run build
|
|
167
|
+
bun pm pack --dry-run
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 贡献
|
|
171
|
+
|
|
172
|
+
欢迎提交 Issue 和 Pull Request。开源发布前请确保测试、类型检查和构建均通过。
|
|
173
|
+
|
|
174
|
+
## 许可证
|
|
175
|
+
|
|
176
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ComponentConstructor } from './component';
|
|
2
|
+
import type { Router } from '../router';
|
|
3
|
+
export interface Plugin {
|
|
4
|
+
install: (app: OneApp, ...args: unknown[]) => void;
|
|
5
|
+
onMounted?: (app: OneApp) => void;
|
|
6
|
+
onUpdated?: (app: OneApp) => void;
|
|
7
|
+
onBeforeUnmount?: (app: OneApp) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface AppOptions<TState = Record<string, unknown>, TConfig = Record<string, unknown>> {
|
|
10
|
+
/** 根组件构造函数 */
|
|
11
|
+
root?: ComponentConstructor;
|
|
12
|
+
/** 应用挂载点 */
|
|
13
|
+
rootElement?: string | Element;
|
|
14
|
+
/** 全局状态 */
|
|
15
|
+
state?: TState;
|
|
16
|
+
/** 全局配置 */
|
|
17
|
+
config?: TConfig;
|
|
18
|
+
}
|
|
19
|
+
export interface AppContext<TConfig = Record<string, unknown>> {
|
|
20
|
+
app: OneApp;
|
|
21
|
+
version: string;
|
|
22
|
+
config: TConfig;
|
|
23
|
+
router?: Router;
|
|
24
|
+
}
|
|
25
|
+
export declare class OneApp<TState extends object = Record<string, unknown>, TConfig extends object = Record<string, unknown>> {
|
|
26
|
+
private options;
|
|
27
|
+
private container;
|
|
28
|
+
private rootInstance;
|
|
29
|
+
private mounted;
|
|
30
|
+
private templateEngine;
|
|
31
|
+
private readonly appContext;
|
|
32
|
+
private plugins;
|
|
33
|
+
private unmountedCallback?;
|
|
34
|
+
router?: Router;
|
|
35
|
+
constructor(options?: AppOptions<TState, TConfig>);
|
|
36
|
+
private handleError;
|
|
37
|
+
/**
|
|
38
|
+
* 渲染错误UI
|
|
39
|
+
*/
|
|
40
|
+
private renderErrorUI;
|
|
41
|
+
/**
|
|
42
|
+
* 使用插件
|
|
43
|
+
*/
|
|
44
|
+
use(plugin: Plugin, ...args: unknown[]): this;
|
|
45
|
+
/**
|
|
46
|
+
* 挂载应用
|
|
47
|
+
*/
|
|
48
|
+
mount(): void;
|
|
49
|
+
/**
|
|
50
|
+
* 卸载应用
|
|
51
|
+
*/
|
|
52
|
+
unmount(): void;
|
|
53
|
+
/**
|
|
54
|
+
* 应用是否正在运行
|
|
55
|
+
*/
|
|
56
|
+
isRunning(): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* 更新根组件
|
|
59
|
+
*/
|
|
60
|
+
updateRootComponent(component: ComponentConstructor): void;
|
|
61
|
+
/**
|
|
62
|
+
* 更新应用状态
|
|
63
|
+
*/
|
|
64
|
+
update(state?: Partial<TState>): this;
|
|
65
|
+
/**
|
|
66
|
+
* 获取应用上下文
|
|
67
|
+
*/
|
|
68
|
+
getContext(): AppContext<TConfig>;
|
|
69
|
+
/**
|
|
70
|
+
* 获取应用状态
|
|
71
|
+
*/
|
|
72
|
+
getState(): TState | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* 设置应用状态
|
|
75
|
+
*/
|
|
76
|
+
setState(newState: TState): this;
|
|
77
|
+
/**
|
|
78
|
+
* 监听应用卸载
|
|
79
|
+
*/
|
|
80
|
+
onUnmounted(callback: () => void): this;
|
|
81
|
+
/**
|
|
82
|
+
* 解析根元素
|
|
83
|
+
*/
|
|
84
|
+
private resolveRootElement;
|
|
85
|
+
private onMounted;
|
|
86
|
+
private onUpdated;
|
|
87
|
+
private onBeforeUnmount;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 创建应用实例
|
|
91
|
+
*/
|
|
92
|
+
export declare function createApp<TState extends object = Record<string, unknown>, TConfig extends object = Record<string, unknown>>(options?: AppOptions<TState, TConfig>): OneApp<TState, TConfig>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { StyleManager } from '../../style/StyleManager';
|
|
2
|
+
import { ComponentInstance } from '../renderer';
|
|
3
|
+
import type { VNode } from '../vnode';
|
|
4
|
+
export type ComponentProps = object;
|
|
5
|
+
export type ComponentState = object;
|
|
6
|
+
export type ComponentEventListener = (...args: unknown[]) => void;
|
|
7
|
+
export type ComponentConstructor<TProps extends ComponentProps = ComponentProps, TState extends ComponentState = ComponentState> = new (props?: TProps) => Component<TProps, TState>;
|
|
8
|
+
export type AnyComponentConstructor = new (props?: never) => Component<ComponentProps, ComponentState>;
|
|
9
|
+
export declare abstract class Component<TProps extends ComponentProps = ComponentProps, TState extends ComponentState = ComponentState> implements ComponentInstance {
|
|
10
|
+
protected props: TProps;
|
|
11
|
+
private vnode;
|
|
12
|
+
private el;
|
|
13
|
+
private readonly renderer;
|
|
14
|
+
private readonly templateEngine;
|
|
15
|
+
private readonly childComponents;
|
|
16
|
+
private readonly eventListeners;
|
|
17
|
+
private readonly updateEffect;
|
|
18
|
+
private appContext;
|
|
19
|
+
protected styleManager: StyleManager;
|
|
20
|
+
state: TState;
|
|
21
|
+
mounted: boolean;
|
|
22
|
+
constructor(props?: TProps);
|
|
23
|
+
protected abstract initState(): TState;
|
|
24
|
+
protected abstract initStyles(): void;
|
|
25
|
+
protected abstract render(): VNode;
|
|
26
|
+
mount(container: HTMLElement): void;
|
|
27
|
+
mountToNode(): Node;
|
|
28
|
+
update(): void;
|
|
29
|
+
unmount(): void;
|
|
30
|
+
setProps(props: Partial<TProps>): void;
|
|
31
|
+
setState(state: Partial<TState>): void;
|
|
32
|
+
setAppContext(context: unknown): void;
|
|
33
|
+
getElement(): Node | null;
|
|
34
|
+
protected beforeMount(): void;
|
|
35
|
+
protected onMounted(): void;
|
|
36
|
+
protected beforeUpdate(): void;
|
|
37
|
+
protected onUpdated(): void;
|
|
38
|
+
protected beforeUnmount(): void;
|
|
39
|
+
protected onUnmounted(): void;
|
|
40
|
+
protected getContext(): unknown;
|
|
41
|
+
protected get router(): unknown;
|
|
42
|
+
protected emit(eventName: string, ...args: unknown[]): void;
|
|
43
|
+
on(eventName: string, listener: ComponentEventListener): void;
|
|
44
|
+
off(eventName: string, listener: ComponentEventListener): void;
|
|
45
|
+
private createRenderContext;
|
|
46
|
+
private collectSlots;
|
|
47
|
+
private getSlotName;
|
|
48
|
+
private normalizeSlotChild;
|
|
49
|
+
private trackStateProperties;
|
|
50
|
+
private getRouterFrom;
|
|
51
|
+
private getRouterFromGlobalApp;
|
|
52
|
+
private trackReactiveValue;
|
|
53
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Component } from './base';
|
|
2
|
+
import type { AnyComponentConstructor, ComponentConstructor, ComponentEventListener, ComponentProps, ComponentState } from './base';
|
|
3
|
+
export { Component };
|
|
4
|
+
export type { AnyComponentConstructor, ComponentConstructor, ComponentEventListener, ComponentProps, ComponentState, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './component/index';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ReactiveEffect<T = unknown> {
|
|
2
|
+
(): T | undefined;
|
|
3
|
+
deps: Set<ReactiveEffect>[];
|
|
4
|
+
id: number;
|
|
5
|
+
active: boolean;
|
|
6
|
+
scheduler?: (effect: ReactiveEffect) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ReactiveEffectOptions {
|
|
9
|
+
lazy?: boolean;
|
|
10
|
+
scheduler?: (effect: ReactiveEffect) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface ComputedRef<T> {
|
|
13
|
+
readonly value: T;
|
|
14
|
+
}
|
|
15
|
+
export declare const IS_REACTIVE: unique symbol;
|
|
16
|
+
export declare const IS_READONLY: unique symbol;
|
|
17
|
+
export declare const MUTATING_ARRAY_METHODS: readonly ["push", "pop", "shift", "unshift", "splice", "sort", "reverse"];
|
|
18
|
+
export declare function hasReactiveFlag(value: object, flag: typeof IS_REACTIVE | typeof IS_READONLY): boolean;
|
|
19
|
+
export declare function isObject(value: unknown): value is object;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ComputedRef, ReactiveEffect, ReactiveEffectOptions } from './reactive/types';
|
|
2
|
+
export type { ComputedRef, ReactiveEffect, ReactiveEffectOptions, } from './reactive/types';
|
|
3
|
+
export declare class ReactiveSystem {
|
|
4
|
+
private static instance;
|
|
5
|
+
private activeEffect;
|
|
6
|
+
private readonly effectStack;
|
|
7
|
+
private targetMap;
|
|
8
|
+
private reactiveMap;
|
|
9
|
+
private readonlyMap;
|
|
10
|
+
private constructor();
|
|
11
|
+
static getInstance(): ReactiveSystem;
|
|
12
|
+
reactive<T extends object>(target: T): T;
|
|
13
|
+
/**
|
|
14
|
+
* 创建响应式数组
|
|
15
|
+
*/
|
|
16
|
+
private createReactiveArray;
|
|
17
|
+
readonly<T extends object>(target: T): Readonly<T>;
|
|
18
|
+
effect<T = unknown>(fn: () => T, options?: ReactiveEffectOptions): ReactiveEffect<T>;
|
|
19
|
+
computed<T>(getter: () => T): ComputedRef<T>;
|
|
20
|
+
private cleanup;
|
|
21
|
+
private track;
|
|
22
|
+
private trigger;
|
|
23
|
+
stop(effect: ReactiveEffect): void;
|
|
24
|
+
}
|
|
25
|
+
export declare function reactive<T extends object>(target: T): T;
|
|
26
|
+
export declare function readonly<T extends object>(target: T): Readonly<T>;
|
|
27
|
+
export declare function effect<T = unknown>(fn: () => T, options?: ReactiveEffectOptions): ReactiveEffect<T>;
|
|
28
|
+
export declare function computed<T>(getter: () => T): ComputedRef<T>;
|
|
29
|
+
export declare function stop(effect: ReactiveEffect): void;
|
|
30
|
+
export declare function isReactive(value: unknown): boolean;
|
|
31
|
+
export declare function isReadonly(value: unknown): boolean;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ParsedEventName {
|
|
2
|
+
eventName: string;
|
|
3
|
+
modifiers: Set<string>;
|
|
4
|
+
}
|
|
5
|
+
export declare function isEventProp(key: string): boolean;
|
|
6
|
+
export declare function eventNameFromProp(key: string): string;
|
|
7
|
+
export declare function parseEventName(event: string): ParsedEventName;
|
|
8
|
+
export declare function wrapEventHandler(handler: (event: Event) => void, modifiers: Set<string>): EventListener;
|
|
9
|
+
export declare function setStyleValue(style: CSSStyleDeclaration, property: string, value: string | number): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TemplateEngine } from '../template';
|
|
2
|
+
import type { ComponentEventListener, ComponentProps } from '../component';
|
|
3
|
+
import type { VNode } from '../vnode';
|
|
4
|
+
export interface ComponentInstance {
|
|
5
|
+
mountToNode(): Node;
|
|
6
|
+
update(): void;
|
|
7
|
+
unmount(): void;
|
|
8
|
+
setProps(props: Partial<ComponentProps>): void;
|
|
9
|
+
setAppContext?(context: unknown): void;
|
|
10
|
+
getElement(): Node | null;
|
|
11
|
+
on(eventName: string, listener: ComponentEventListener): void;
|
|
12
|
+
}
|
|
13
|
+
export type Renderable = VNode | string;
|
|
14
|
+
export interface RendererHost {
|
|
15
|
+
mount(vnode: Renderable, context: RenderRuntimeContext): Node;
|
|
16
|
+
patch(oldVNode: Renderable, newVNode: Renderable, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
17
|
+
unmount(vnode: Renderable, currentNode: Node, context: RenderRuntimeContext): void;
|
|
18
|
+
}
|
|
19
|
+
export interface RenderRuntimeContext {
|
|
20
|
+
templateEngine: TemplateEngine;
|
|
21
|
+
appContext?: unknown;
|
|
22
|
+
renderer: RendererHost;
|
|
23
|
+
slots: Record<string, Array<VNode | string>>;
|
|
24
|
+
registerChild(component: ComponentInstance): void;
|
|
25
|
+
}
|
|
26
|
+
export interface RenderStrategy<T extends Renderable = Renderable> {
|
|
27
|
+
matches(vnode: Renderable): vnode is T;
|
|
28
|
+
mount(vnode: T, context: RenderRuntimeContext): Node;
|
|
29
|
+
patch(oldVNode: T, newVNode: T, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
30
|
+
unmount(vnode: T, currentNode: Node, context: RenderRuntimeContext): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ComponentNode, HTMLNode, SlotProvider } from './vnode';
|
|
2
|
+
export type { ComponentInstance, RenderRuntimeContext, RenderStrategy, Renderable, RendererHost, } from './renderer/types';
|
|
3
|
+
import type { RenderRuntimeContext, RenderStrategy, Renderable } from './renderer/types';
|
|
4
|
+
export declare class RendererContext {
|
|
5
|
+
private readonly strategies;
|
|
6
|
+
constructor();
|
|
7
|
+
mount(vnode: Renderable, context: RenderRuntimeContext): Node;
|
|
8
|
+
patch(oldVNode: Renderable, newVNode: Renderable, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
9
|
+
unmount(vnode: Renderable, currentNode: Node, context: RenderRuntimeContext): void;
|
|
10
|
+
private findStrategy;
|
|
11
|
+
}
|
|
12
|
+
export declare class TextRenderStrategy implements RenderStrategy<string> {
|
|
13
|
+
matches(vnode: Renderable): vnode is string;
|
|
14
|
+
mount(vnode: string, context: RenderRuntimeContext): Node;
|
|
15
|
+
patch(oldVNode: string, newVNode: string, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
16
|
+
unmount(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare class ComponentRenderStrategy implements RenderStrategy<ComponentNode> {
|
|
19
|
+
private readonly instances;
|
|
20
|
+
matches(vnode: Renderable): vnode is ComponentNode;
|
|
21
|
+
mount(vnode: ComponentNode, context: RenderRuntimeContext): Node;
|
|
22
|
+
patch(oldVNode: ComponentNode, newVNode: ComponentNode, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
23
|
+
unmount(_vnode: ComponentNode, currentNode: Node): void;
|
|
24
|
+
private createProps;
|
|
25
|
+
}
|
|
26
|
+
export declare class SlotRenderStrategy implements RenderStrategy<SlotProvider> {
|
|
27
|
+
private readonly renderedChildren;
|
|
28
|
+
matches(vnode: Renderable): vnode is SlotProvider;
|
|
29
|
+
mount(vnode: SlotProvider, context: RenderRuntimeContext): Node;
|
|
30
|
+
patch(oldVNode: SlotProvider, newVNode: SlotProvider, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
31
|
+
unmount(_vnode: SlotProvider, currentNode: Node, context: RenderRuntimeContext): void;
|
|
32
|
+
private resolveChildren;
|
|
33
|
+
private replaceSlotChildren;
|
|
34
|
+
private mountSlotChildren;
|
|
35
|
+
private unmountSlotChildren;
|
|
36
|
+
}
|
|
37
|
+
export declare class ElementRenderStrategy implements RenderStrategy<HTMLNode> {
|
|
38
|
+
private readonly listeners;
|
|
39
|
+
private readonly effects;
|
|
40
|
+
private readonly modelBindings;
|
|
41
|
+
matches(vnode: Renderable): vnode is HTMLNode;
|
|
42
|
+
mount(vnode: HTMLNode, context: RenderRuntimeContext): Node;
|
|
43
|
+
patch(oldVNode: HTMLNode, newVNode: HTMLNode, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
44
|
+
unmount(vnode: HTMLNode, currentNode: Node, context: RenderRuntimeContext): void;
|
|
45
|
+
private applyProps;
|
|
46
|
+
private applyDirections;
|
|
47
|
+
private updateChildren;
|
|
48
|
+
private updateKeyedChildren;
|
|
49
|
+
private hasKeyedChildren;
|
|
50
|
+
private getVNodeKey;
|
|
51
|
+
private collectListeners;
|
|
52
|
+
private updateListeners;
|
|
53
|
+
private setupReactiveAttribute;
|
|
54
|
+
private setupTwoWayBinding;
|
|
55
|
+
private getStateValue;
|
|
56
|
+
private trackEffect;
|
|
57
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ReactiveEffect } from './reactive';
|
|
2
|
+
export interface TemplateBinding {
|
|
3
|
+
node: Text;
|
|
4
|
+
originalText: string;
|
|
5
|
+
effect: ReactiveEffect;
|
|
6
|
+
}
|
|
7
|
+
export declare class TemplateEngine {
|
|
8
|
+
state: object;
|
|
9
|
+
private bindings;
|
|
10
|
+
private readonly templateRegex;
|
|
11
|
+
constructor(state: object);
|
|
12
|
+
/**
|
|
13
|
+
* 解析模板字符串,创建响应式的文本节点
|
|
14
|
+
* @param text 包含模板表达式的文本字符串
|
|
15
|
+
* @returns 创建的文本节点
|
|
16
|
+
*/
|
|
17
|
+
parseTemplate(text: string): Text;
|
|
18
|
+
/**
|
|
19
|
+
* 设置响应式绑定
|
|
20
|
+
*/
|
|
21
|
+
private setupReactiveBindings;
|
|
22
|
+
/**
|
|
23
|
+
* 计算模板文本的值
|
|
24
|
+
*/
|
|
25
|
+
private evaluateTemplate;
|
|
26
|
+
/**
|
|
27
|
+
* 从状态对象中获取值,支持嵌套属性访问
|
|
28
|
+
*/
|
|
29
|
+
private getValueFromState;
|
|
30
|
+
/**
|
|
31
|
+
* 清除所有模板绑定
|
|
32
|
+
*/
|
|
33
|
+
clearBindings(): void;
|
|
34
|
+
/**
|
|
35
|
+
* 获取当前的绑定数量
|
|
36
|
+
*/
|
|
37
|
+
getBindingCount(): number;
|
|
38
|
+
/**
|
|
39
|
+
* 检查模板是否包含表达式
|
|
40
|
+
*/
|
|
41
|
+
hasExpressions(text: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* 获取模板中的所有表达式键
|
|
44
|
+
*/
|
|
45
|
+
extractKeys(text: string): string[];
|
|
46
|
+
/**
|
|
47
|
+
* 计算模板值
|
|
48
|
+
*/
|
|
49
|
+
evaluateTemplateValue(text: string): string;
|
|
50
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AnyComponentConstructor, ComponentConstructor, ComponentEventListener, ComponentProps } from './component';
|
|
2
|
+
export interface ComponentType {
|
|
3
|
+
mount(container: HTMLElement): void;
|
|
4
|
+
unmount(): void;
|
|
5
|
+
on(eventName: string, listener: ComponentEventListener): void;
|
|
6
|
+
}
|
|
7
|
+
type VNodeComponentProps = ComponentProps;
|
|
8
|
+
export type VNodeComponentConstructor<P extends VNodeComponentProps = VNodeComponentProps> = ComponentConstructor<P> | AnyComponentConstructor;
|
|
9
|
+
export type HTMLPropValue = string | number | boolean | null | undefined | Record<string, string | number> | EventListener;
|
|
10
|
+
export interface HTMLProps {
|
|
11
|
+
[key: string]: HTMLPropValue;
|
|
12
|
+
class?: string;
|
|
13
|
+
className?: string;
|
|
14
|
+
style?: Record<string, string | number>;
|
|
15
|
+
}
|
|
16
|
+
export interface EventListeners {
|
|
17
|
+
[eventName: string]: (event: Event) => void;
|
|
18
|
+
}
|
|
19
|
+
export interface Directions {
|
|
20
|
+
model?: string;
|
|
21
|
+
if?: boolean;
|
|
22
|
+
show?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface HTMLNode {
|
|
25
|
+
tag: string;
|
|
26
|
+
props?: HTMLProps;
|
|
27
|
+
children?: Array<VNode | string>;
|
|
28
|
+
listeners?: EventListeners;
|
|
29
|
+
key?: string | number;
|
|
30
|
+
slot?: string;
|
|
31
|
+
directions?: Directions;
|
|
32
|
+
}
|
|
33
|
+
export interface ComponentNode<P extends VNodeComponentProps = VNodeComponentProps> {
|
|
34
|
+
component: VNodeComponentConstructor<P>;
|
|
35
|
+
props?: P;
|
|
36
|
+
children?: Array<VNode | string>;
|
|
37
|
+
emitters?: Record<string, ComponentEventListener>;
|
|
38
|
+
key?: string | number;
|
|
39
|
+
slot?: string;
|
|
40
|
+
directions?: Directions;
|
|
41
|
+
}
|
|
42
|
+
export interface SlotProvider {
|
|
43
|
+
tag: 'slot';
|
|
44
|
+
props: {
|
|
45
|
+
name: string;
|
|
46
|
+
};
|
|
47
|
+
children?: Array<VNode | string>;
|
|
48
|
+
key?: string | number;
|
|
49
|
+
directions?: Directions;
|
|
50
|
+
}
|
|
51
|
+
export interface SlotInjector {
|
|
52
|
+
tag: string;
|
|
53
|
+
slot: string;
|
|
54
|
+
key?: string | number;
|
|
55
|
+
directions?: Directions;
|
|
56
|
+
}
|
|
57
|
+
export type VNode = HTMLNode | ComponentNode | SlotProvider | SlotInjector;
|
|
58
|
+
export declare function isComponentNode(vnode: VNode): vnode is ComponentNode;
|
|
59
|
+
export declare function isHTMLNode(vnode: VNode): vnode is HTMLNode;
|
|
60
|
+
export declare function isSlotProvider(vnode: VNode): vnode is SlotProvider;
|
|
61
|
+
export declare function h(tag: string, props?: HTMLProps, children?: Array<VNode | string>, listeners?: EventListeners, key?: string | number, directions?: Directions): HTMLNode;
|
|
62
|
+
export declare function createComponent<P extends VNodeComponentProps>(componentClass: ComponentConstructor<P>, props?: P, children?: Array<VNode | string>, key?: string | number, directions?: Directions): ComponentNode<P>;
|
|
63
|
+
export declare function slot(name: string, key?: string | number, directions?: Directions): SlotProvider;
|
|
64
|
+
export {};
|