transone 0.3.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -10
- package/README.zh-CN.md +29 -0
- package/dist/core/app.d.ts +3 -3
- package/dist/core/component/base-component.d.ts +5 -0
- package/dist/core/component/base.d.ts +6 -1
- package/dist/core/component/index.d.ts +3 -2
- package/dist/core/index.d.ts +1 -0
- package/dist/core/vnode.d.ts +4 -4
- package/dist/index-5dxcnfw6.js +12 -0
- package/dist/{index-49z4707x.js.map → index-5dxcnfw6.js.map} +10 -9
- package/dist/index-dse0chhf.js +5 -0
- package/dist/index-dse0chhf.js.map +10 -0
- package/dist/index-fxpn7qkh.js +4 -0
- package/dist/index-fxpn7qkh.js.map +11 -0
- package/dist/{index-xp7y2crt.js → index-jq6fv0br.js} +4 -4
- package/dist/{index-xp7y2crt.js.map → index-jq6fv0br.js.map} +3 -3
- package/dist/index-ryj080w6.js +27 -0
- package/dist/{index-d5wsetxf.js.map → index-ryj080w6.js.map} +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +3 -3
- package/dist/platform/bindings.d.ts +3 -0
- package/dist/platform/decorators.d.ts +15 -0
- package/dist/platform/definitions.d.ts +32 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.js +4 -0
- package/dist/platform/index.js.map +9 -0
- package/dist/request/index.js +2 -2
- package/dist/request/index.js.map +1 -1
- package/dist/router/index.d.ts +2 -2
- package/dist/router/index.js +2 -2
- package/dist/router/index.js.map +1 -1
- package/dist/style/index.js +2 -2
- package/dist/style/index.js.map +1 -1
- package/dist/style/units.d.ts +3 -3
- package/package.json +6 -2
- package/dist/index-49z4707x.js +0 -12
- package/dist/index-d5wsetxf.js +0 -27
package/README.md
CHANGED
|
@@ -1,17 +1,257 @@
|
|
|
1
1
|
# transone
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**English** · [简体中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
- 面向对象组件:`Component<Props, State>`、生命周期、事件、插槽
|
|
7
|
-
- 策略化渲染:`RenderStrategy` 按 VNode 类型分发(文本 / 元素 / 组件 / 插槽)
|
|
8
|
-
- 内置路由:`createRouter`、`RouterView`、`RouterLink`
|
|
9
|
-
- 样式管理:`StyleManager`
|
|
5
|
+
TransOne core framework package — a cross-platform front-end framework that compiles **one TypeScript source** into Web and multi-platform mini-program native projects at build time. Emitted artifacts carry **no framework runtime**: code is statically transformed (transpile/transform), so the output stays small and close to native.
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
The core public API is same-origin with [TSone](https://github.com/geektech-team/tsone): Web output can directly reuse TSone rendering strategies and its component ecosystem. The multi-target compiler lives in [`transone-cli`](../transone-cli).
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Reactive system** — `reactive`, `readonly`, `effect`, `computed`, `ref`, `isRef`, `unref`, `stop`, `watch`, `nextTick`, `flushSync`, backed by a reactive scheduler
|
|
12
|
+
- **OOP component model** — `Component<Props, State>` with lifecycle hooks, custom events, slots, and `provide` / `inject`
|
|
13
|
+
- **Strategy-based renderer** — `RenderStrategy` dispatches by VNode type (text / element / component / slot)
|
|
14
|
+
- **Built-in router** — `createRouter`, `RouterView`, `RouterLink` with history / hash modes, base path, navigation guards, redirects and route metadata
|
|
15
|
+
- **Cross-platform request** — one unified API over `fetch` (Web), `wx.request` (WeChat), `my.request` (Alipay) and `tt.request` (ByteDance), with request / response interceptors and platform auto-detection
|
|
16
|
+
- **Style management** — `StyleManager` with class / id / sheet style units
|
|
17
|
+
- **DOM abstractions** — `createDomWindow`, `installDomGlobals`, `parseHtmlFragment` for headless and test environments
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bun add transone
|
|
23
|
+
# or npm / pnpm / yarn
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Requires Bun >= 1.3.0.
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
A counter component — the same source builds to every supported target:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { Component, VNode, createApp } from 'transone';
|
|
34
|
+
|
|
35
|
+
interface AppState {
|
|
36
|
+
count: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class App extends Component<Record<string, never>, AppState> {
|
|
40
|
+
protected initState(): AppState {
|
|
41
|
+
return { count: 0 };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected initStyles(): void {}
|
|
45
|
+
|
|
46
|
+
protected render(): VNode {
|
|
47
|
+
return {
|
|
48
|
+
tag: 'main',
|
|
49
|
+
children: [
|
|
50
|
+
{ tag: 'h1', children: ['TransOne'] },
|
|
51
|
+
{
|
|
52
|
+
tag: 'button',
|
|
53
|
+
listeners: {
|
|
54
|
+
click: () => {
|
|
55
|
+
this.state.count += 1;
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
children: [`count: {{count}}`],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const app = createApp({ root: App });
|
|
66
|
+
app.mount();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Build the same source to different targets with `transone-cli`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
transone build --target web # H5 site / SPA
|
|
73
|
+
transone build --target mp-weixin # WeChat mini-program project (WXML/WXSS/JS)
|
|
74
|
+
transone build --target mp-alipay # Alipay mini-program project (AXML/ACSS)
|
|
75
|
+
transone build --target mp-bytedance # ByteDance mini-program project (TTML/TTSS)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Platform component implementations
|
|
79
|
+
|
|
80
|
+
From framework 0.5.0 and CLI 0.8.0, a business component can extend `BaseComponent<Props, State>` and share its state/methods with platform subclasses. Decorate an exported subclass with `@WebMobile()`, `@WebPc()`, `@MiniprogramWeixin()` or `@AppIos()`; the framework's `Platform` enum supplies the matching values such as `web-mobile` and `app-ios`.
|
|
81
|
+
|
|
82
|
+
Pages keep referencing the business base through `createComponent({ component: CardComponent })`. Run `transone dev --target web-mobile` or `transone build --target app-ios` to select the implementation. Exact matches take priority, followed by the matching family implementation (`@Web()`, `@Miniprogram()` or `@App()`) and then a concrete base; ambiguous implementations and missing implementations for consumed abstract bases fail with diagnostics. Existing `Component` users and legacy target names remain supported. Generic mini-program and App markers select component implementations; builds still require concrete targets.
|
|
83
|
+
|
|
84
|
+
`transone create` generates a runnable shared Card example. See the [component implementation guide](../../docs/platform-components.md) for all platforms, discovery configuration, inheritance, explicit references and the native compiler's static subset.
|
|
85
|
+
|
|
86
|
+
## Reactivity
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { reactive, computed, effect, ref, watch, nextTick } from 'transone';
|
|
90
|
+
|
|
91
|
+
const state = reactive({ count: 0 });
|
|
92
|
+
|
|
93
|
+
const doubled = computed(() => state.count * 2);
|
|
94
|
+
|
|
95
|
+
effect(() => {
|
|
96
|
+
console.log(`count is ${state.count}, doubled is ${doubled.value}`);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
state.count += 1; // triggers the effect
|
|
100
|
+
|
|
101
|
+
const message = ref('hello');
|
|
102
|
+
watch(message, (value, oldValue) => {
|
|
103
|
+
console.log(`message changed: ${oldValue} -> ${value}`);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
await nextTick(); // flush pending reactive updates
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Component model
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { Component, h, type VNode } from 'transone';
|
|
113
|
+
|
|
114
|
+
interface GreetingProps {
|
|
115
|
+
name: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
class Greeting extends Component<GreetingProps, { shown: boolean }> {
|
|
119
|
+
protected initState() {
|
|
120
|
+
return { shown: false };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
protected initStyles(): void {}
|
|
124
|
+
|
|
125
|
+
protected onMounted(): void {
|
|
126
|
+
this.setState({ shown: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
protected render(): VNode {
|
|
130
|
+
return h('p', {}, [`Hello, ${this.props.name}!`]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Lifecycle hooks: `beforeMount`, `onMounted`, `beforeUpdate`, `onUpdated`, `onPropsChange`, `beforeUnmount`, `onUnmounted`, `onErrorCaptured`. Components communicate through custom events (`emit` / `on` / `off`) and dependency injection (`provide` / `inject`).
|
|
136
|
+
|
|
137
|
+
## Router
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { createRouter, RouterView, RouterLink } from 'transone/router';
|
|
141
|
+
|
|
142
|
+
const router = createRouter({
|
|
143
|
+
mode: 'history',
|
|
144
|
+
base: '/app',
|
|
145
|
+
routes: [
|
|
146
|
+
{ path: '/', component: Home, name: 'home' },
|
|
147
|
+
{ path: '/about', component: About, name: 'about' },
|
|
148
|
+
{ path: '/old', redirect: '/about' },
|
|
149
|
+
{ path: '/users/:id', component: UserDetail },
|
|
150
|
+
],
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
router.beforeEach((to, from) => {
|
|
154
|
+
// return false to cancel, a path string to redirect, or undefined to continue
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Render the matched route with `RouterView` and link with `RouterLink`:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { Component, h, createComponent, type VNode } from 'transone';
|
|
162
|
+
|
|
163
|
+
class Layout extends Component {
|
|
164
|
+
protected initStyles(): void {}
|
|
165
|
+
|
|
166
|
+
protected render(): VNode {
|
|
167
|
+
return h('div', {}, [
|
|
168
|
+
createComponent({
|
|
169
|
+
component: RouterLink,
|
|
170
|
+
props: { to: '/', activeClass: 'active' },
|
|
171
|
+
children: ['Home'],
|
|
172
|
+
}),
|
|
173
|
+
createComponent({ component: RouterView }),
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Cross-platform request
|
|
180
|
+
|
|
181
|
+
`transone/request` (also re-exported from the root entry) wraps each platform's request API: Web uses `fetch`, while WeChat / Alipay / ByteDance mini-programs use `wx.request` / `my.request` / `tt.request` respectively. The runtime detects the environment automatically, so one source works across targets without changes; you can also pin a platform explicitly or inject a custom adapter.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { createRequest, RequestError } from 'transone/request';
|
|
185
|
+
|
|
186
|
+
const http = createRequest({ baseURL: '/api', timeout: 10000 });
|
|
187
|
+
|
|
188
|
+
// Request interceptors run in registration order (e.g. inject auth state)
|
|
189
|
+
http.interceptors.request.use((config) => {
|
|
190
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
191
|
+
return config;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// Response interceptors: later-registered ones run first
|
|
195
|
+
http.interceptors.response.use(
|
|
196
|
+
(response) => {
|
|
197
|
+
if (response.data?.code !== 0) {
|
|
198
|
+
throw new RequestError({
|
|
199
|
+
code: 'BAD_REQUEST',
|
|
200
|
+
message: response.data?.message ?? 'Business error',
|
|
201
|
+
config: response.config,
|
|
202
|
+
response,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return response;
|
|
206
|
+
},
|
|
207
|
+
(error) => {
|
|
208
|
+
// error is a RequestError; branch on code: TIMEOUT / ABORTED / NETWORK_ERROR ...
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const res = await http.get<{ list: Item[] }>('/items', { params: { page: 1 } });
|
|
214
|
+
await http.post('/users', { name: 'a' });
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
A global default instance and per-target overrides are also available:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { request, detectPlatform } from 'transone/request';
|
|
221
|
+
|
|
222
|
+
await request.get('/ping'); // auto-detect target platform
|
|
223
|
+
await request.get('/x', { platform: 'weixin' }); // explicit platform
|
|
224
|
+
console.log(detectPlatform()); // 'web' | 'weixin' | 'alipay' | 'bytedance'
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Errors are normalized to `RequestError` (`code` / `config` / `response` / `cause`). HTTP 4xx / 5xx are not treated as exceptions (consistent with mini-program `success` semantics); inspect `statusCode` on the caller side.
|
|
228
|
+
|
|
229
|
+
## Sub-path exports
|
|
230
|
+
|
|
231
|
+
| Entry | Contents |
|
|
232
|
+
| --- | --- |
|
|
233
|
+
| `transone` | Core (reactivity, components, renderer) + router + request |
|
|
234
|
+
| `transone/router` | `createRouter`, `Router`, `RouterView`, `RouterLink`, `useRouter` |
|
|
235
|
+
| `transone/request` | `createRequest`, `request`, `Request`, `InterceptorManager`, `RequestError`, `detectPlatform` |
|
|
236
|
+
| `transone/style` | `StyleManager`, style sheets and units |
|
|
237
|
+
| `transone/dom` | DOM abstractions: `createDomWindow`, `installDomGlobals`, `parseHtmlFragment` |
|
|
238
|
+
| `transone/platform` | `Platform`, platform definitions and class decorators |
|
|
239
|
+
|
|
240
|
+
## Relationship with TSone
|
|
241
|
+
|
|
242
|
+
- **TransOne is the multi-target generalization of TSone**: TSone focuses on the Web runtime; TransOne compiles the same reactive / component / rendering model to multiple targets through compile-time transformation.
|
|
243
|
+
- TSone's `build --mp-weixin` served as the prototype for TransOne's WeChat target; its output shape and constraints migrate into TransOne's multi-target abstraction.
|
|
244
|
+
- The One family: `TSone` (front-end framework) · `TransOne` (cross-platform framework) · `BackOne` (back-end framework).
|
|
245
|
+
|
|
246
|
+
## Development
|
|
13
247
|
|
|
14
248
|
```bash
|
|
15
|
-
bun test #
|
|
16
|
-
bun run build #
|
|
249
|
+
bun test # run tests (Bun's test runner)
|
|
250
|
+
bun run build # build dist (ESM + .d.ts)
|
|
251
|
+
bun run build:types
|
|
252
|
+
bun run lint
|
|
17
253
|
```
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# transone
|
|
2
|
+
|
|
3
|
+
**简体中文** · [English](./README.md)
|
|
4
|
+
|
|
5
|
+
TransOne 核心框架包:一份 TypeScript 源码,跨端框架的核心运行时模型。
|
|
6
|
+
|
|
7
|
+
- 响应式系统:`reactive`、`readonly`、`effect`、`stop`、`computed`、`ref`、`watch`
|
|
8
|
+
- 面向对象组件:`Component<Props, State>`、生命周期、事件、插槽
|
|
9
|
+
- 策略化渲染:`RenderStrategy` 按 VNode 类型分发(文本 / 元素 / 组件 / 插槽)
|
|
10
|
+
- 内置路由:`createRouter`、`RouterView`、`RouterLink`
|
|
11
|
+
- 样式管理:`StyleManager`
|
|
12
|
+
|
|
13
|
+
与 TSone 同源:核心公开 API 复用 TSone,Web 产物可直接复用 TSone 渲染策略。
|
|
14
|
+
编译器见 [transone-cli](../transone-cli)。
|
|
15
|
+
|
|
16
|
+
框架 0.5.0 / CLI 0.8.0 支持业务组件与端实现:`CardComponent extends BaseComponent`
|
|
17
|
+
共享业务状态与方法,`@WebMobile()`、`@WebPc()`、`@MiniprogramWeixin()`、`@AppIos()`
|
|
18
|
+
标注子类。框架导出的 `Platform.WebMobile` 值为 `web-mobile`;
|
|
19
|
+
页面只引用 CardComponent,由 `dev/build --target web-mobile` 自动选择实现。
|
|
20
|
+
已有直接继承 Component 的用法继续有效。
|
|
21
|
+
|
|
22
|
+
默认精确端优先,再回退到所属平台族的通用实现(`@Web()` / `@Miniprogram()` / `@App()`),最后回退到可实例化业务基类;冲突或抽象基类缺少实现时报错。通用小程序与 App 装饰器仅用于组件选择,构建仍需指定具体端。
|
|
23
|
+
`transone create` 自带各端 Card 示例。完整 API、扫描配置和原生静态子集见
|
|
24
|
+
[业务组件与端实现](../../docs/platform-components.md)。
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun test # 测试
|
|
28
|
+
bun run build # 构建 dist(ESM + .d.ts)
|
|
29
|
+
```
|
package/dist/core/app.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ComponentReference, ComponentProps, InjectionKey, InjectionResult } from './component';
|
|
2
2
|
import { type HtmlDocumentBody, type HtmlDocumentOptions } from './document';
|
|
3
3
|
import type { Router } from '../router';
|
|
4
4
|
export interface Plugin {
|
|
@@ -13,7 +13,7 @@ export type AppDocumentOptions = Partial<Omit<HtmlDocumentOptions, 'body'>> & {
|
|
|
13
13
|
export type AppDocumentRenderOptions = AppDocumentOptions;
|
|
14
14
|
export interface AppOptions<TState = Record<string, unknown>, TConfig = Record<string, unknown>, TRootProps extends ComponentProps = ComponentProps> {
|
|
15
15
|
/** 根组件构造函数 */
|
|
16
|
-
root?:
|
|
16
|
+
root?: ComponentReference<TRootProps>;
|
|
17
17
|
/** 根组件 props */
|
|
18
18
|
rootProps?: TRootProps;
|
|
19
19
|
/** 应用挂载点,默认 #app */
|
|
@@ -67,7 +67,7 @@ export declare class OneApp<TState extends object = Record<string, unknown>, TCo
|
|
|
67
67
|
/**
|
|
68
68
|
* 更新根组件
|
|
69
69
|
*/
|
|
70
|
-
updateRootComponent(component:
|
|
70
|
+
updateRootComponent(component: ComponentReference<TRootProps>): void;
|
|
71
71
|
/**
|
|
72
72
|
* 更新应用状态
|
|
73
73
|
*/
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Component } from './base';
|
|
2
|
+
import type { ComponentProps, ComponentState } from './base';
|
|
3
|
+
/** Shared business component contract, with rendering supplied by target implementations. */
|
|
4
|
+
export declare abstract class BaseComponent<P extends ComponentProps = ComponentProps, S extends ComponentState = ComponentState> extends Component<P, S> {
|
|
5
|
+
}
|
|
@@ -12,11 +12,14 @@ export interface InjectionResult<T> {
|
|
|
12
12
|
value: T | undefined;
|
|
13
13
|
}
|
|
14
14
|
export type ComponentConstructor<TProps extends ComponentProps = ComponentProps, TState extends ComponentState = ComponentState> = new (props?: TProps) => Component<TProps, TState>;
|
|
15
|
+
/** A logical component reference may be abstract and resolved by the application bundle. */
|
|
16
|
+
export type ComponentReference<TProps extends ComponentProps = ComponentProps, TState extends ComponentState = ComponentState> = abstract new (props?: TProps) => Component<TProps, TState>;
|
|
17
|
+
export type AnyComponentReference = abstract new (props?: never) => Component<ComponentProps, ComponentState>;
|
|
15
18
|
export type AnyComponentConstructor = new (props?: never) => Component<ComponentProps, ComponentState>;
|
|
16
19
|
export declare abstract class Component<TProps extends ComponentProps = ComponentProps, TState extends ComponentState = ComponentState> implements ComponentInstance {
|
|
17
20
|
protected props: TProps;
|
|
18
21
|
private vnode;
|
|
19
|
-
|
|
22
|
+
protected el: Node | null;
|
|
20
23
|
private readonly renderer;
|
|
21
24
|
private readonly templateEngine;
|
|
22
25
|
private readonly childComponents;
|
|
@@ -52,6 +55,8 @@ export declare abstract class Component<TProps extends ComponentProps = Componen
|
|
|
52
55
|
protected onMounted(): void;
|
|
53
56
|
protected beforeUpdate(): void;
|
|
54
57
|
protected onUpdated(): void;
|
|
58
|
+
/** props 更新钩子:Web 端在每次更新(setProps/setState)后调用;小程序端由 observers 在 properties 变化时触发。 */
|
|
59
|
+
protected onPropsChange(): void;
|
|
55
60
|
protected beforeUnmount(): void;
|
|
56
61
|
protected onUnmounted(): void;
|
|
57
62
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Component } from './base';
|
|
2
|
-
import type { AnyComponentConstructor, ComponentConstructor, ComponentEventListener, InjectionKey, InjectionResult, ComponentProps, ComponentState } from './base';
|
|
2
|
+
import type { AnyComponentConstructor, AnyComponentReference, ComponentReference, ComponentConstructor, ComponentEventListener, InjectionKey, InjectionResult, ComponentProps, ComponentState } from './base';
|
|
3
3
|
export { Component };
|
|
4
|
-
export type { AnyComponentConstructor, ComponentConstructor, ComponentEventListener, InjectionKey, InjectionResult, ComponentProps, ComponentState, };
|
|
4
|
+
export type { AnyComponentConstructor, AnyComponentReference, ComponentReference, ComponentConstructor, ComponentEventListener, InjectionKey, InjectionResult, ComponentProps, ComponentState, };
|
|
5
|
+
export { BaseComponent } from './base-component';
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/vnode.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AnyComponentReference, ComponentReference, ComponentEventListener, ComponentProps } from './component';
|
|
2
2
|
import type { ModelBinding } from './model';
|
|
3
3
|
export interface ComponentType {
|
|
4
4
|
mount(container: HTMLElement): void;
|
|
@@ -6,7 +6,7 @@ export interface ComponentType {
|
|
|
6
6
|
on(eventName: string, listener: ComponentEventListener): () => void;
|
|
7
7
|
}
|
|
8
8
|
type VNodeComponentProps = ComponentProps;
|
|
9
|
-
export type VNodeComponentConstructor<P extends VNodeComponentProps = VNodeComponentProps> =
|
|
9
|
+
export type VNodeComponentConstructor<P extends VNodeComponentProps = VNodeComponentProps> = ComponentReference<P> | AnyComponentReference;
|
|
10
10
|
export type HTMLPropValue = string | number | boolean | null | undefined | Record<string, string | number> | EventListener;
|
|
11
11
|
export type Children = VNode | string | Array<VNode | string>;
|
|
12
12
|
/** 归一化 children 为数组(运行时渲染使用;h() 允许直接传单个节点或数组)。 */
|
|
@@ -102,7 +102,7 @@ export declare const Tr: ElementShortcut;
|
|
|
102
102
|
export declare const Th: ElementShortcut;
|
|
103
103
|
export declare const Td: ElementShortcut;
|
|
104
104
|
export interface ComponentDescriptor<P extends VNodeComponentProps> {
|
|
105
|
-
component:
|
|
105
|
+
component: ComponentReference<P>;
|
|
106
106
|
props?: P;
|
|
107
107
|
children?: Children;
|
|
108
108
|
key?: string | number;
|
|
@@ -110,7 +110,7 @@ export interface ComponentDescriptor<P extends VNodeComponentProps> {
|
|
|
110
110
|
emitters?: Record<string, ComponentEventListener>;
|
|
111
111
|
}
|
|
112
112
|
export declare function createComponent<P extends VNodeComponentProps>(options: ComponentDescriptor<P>): ComponentNode<P>;
|
|
113
|
-
export declare function createComponent<P extends VNodeComponentProps>(componentClass:
|
|
113
|
+
export declare function createComponent<P extends VNodeComponentProps>(componentClass: ComponentReference<P>, props?: P, children?: Children, key?: string | number, directions?: Directions): ComponentNode<P>;
|
|
114
114
|
export declare function slot(name: string, key?: string | number, directions?: Directions): SlotProvider;
|
|
115
115
|
export declare function each<T>(items: readonly T[], render: (item: T, index: number) => VNode | string, key?: (item: T, index: number) => string | number): VNode[];
|
|
116
116
|
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import{Da as te,Ea as de,Fa as G}from"./index-ryj080w6.js";import{gb as H}from"./index-dse0chhf.js";var C=Symbol("is_reactive"),d=Symbol("is_readonly"),V=Symbol("is_ref"),q=["push","pop","shift","unshift","splice","sort","reverse"];function f(e,t){return Boolean(Reflect.get(e,t))}function h(e){return e!==null&&typeof e==="object"}class B{pending=new Set;flushing=!1;flushPromise=null;flushResolve=null;enqueue(e){if(this.pending.has(e))return;if(this.pending.add(e),!this.flushing)queueMicrotask(()=>this.flush())}flush(){if(this.flushing)return;this.flushing=!0;try{while(this.pending.size>0){let e=Array.from(this.pending);this.pending.clear();for(let t of e)if(t.active)t()}}finally{this.flushing=!1;let e=this.flushResolve;this.flushResolve=null,this.flushPromise=null,e?.()}}nextTick(){if(!this.flushing&&this.pending.size===0)return Promise.resolve();if(this.flushPromise)return this.flushPromise;return this.flushPromise=new Promise((e)=>{this.flushResolve=e}),this.flushPromise}}var Re=0,x=new B;function ze(){return x.nextTick()}function Ye(){x.flush()}class m{static instance;activeEffect=null;effectStack=[];targetMap=new WeakMap;reactiveMap=new WeakMap;readonlyMap=new WeakMap;proxyMap=new WeakMap;constructor(){}static getInstance(){if(!m.instance)m.instance=new m;return m.instance}reactive(e){if(!h(e))return console.warn("reactive: target must be an object"),e;if(Ce(e))return e;if(this.reactiveMap.has(e))return this.reactiveMap.get(e);if(Array.isArray(e))return this.createReactiveArray(e);let t=new Proxy(e,{get:(n,r)=>{if(r===C)return!0;if(r===d)return!1;this.track(n,r);let o=Reflect.get(n,r);if(h(o)&&!f(o,d))return this.reactive(o);return o},set:(n,r,o)=>{if(f(n,d))return console.warn(`Cannot set property ${String(r)} on readonly object`),!1;let i=Reflect.get(n,r);if(h(o)&&!f(o,C)&&!f(o,d))o=this.reactive(o);let s=Reflect.set(n,r,o);if(i!==o)this.trigger(n,r);return s},deleteProperty:(n,r)=>{if(f(n,d))return console.warn(`Cannot delete property ${String(r)} on readonly object`),!1;let o=r in n,i=Reflect.deleteProperty(n,r);if(o)this.trigger(n,r);return i}});return this.reactiveMap.set(e,t),this.proxyMap.set(t,e),t}toRawValue(e){if(h(e)&&this.proxyMap.has(e))return this.proxyMap.get(e);return e}createReactiveArray(e){if(this.reactiveMap.has(e))return this.reactiveMap.get(e);let t=new Proxy(e,{get:(n,r)=>{if(r===C)return!0;if(r===d)return!1;this.track(n,r);let o=Reflect.get(n,r);if(typeof r==="string"&&(r==="includes"||r==="indexOf"||r==="lastIndexOf")){this.track(n,"length");for(let s=0;s<n.length;s++)this.track(n,String(s));let i=o;return(...s)=>{let a=i.apply(n,s);if(a===!1||a===-1){let c=n.map((u)=>this.toRawValue(u));return c[r].apply(c,s.map((u)=>this.toRawValue(u)))}return a}}if(typeof r==="string"&&q.includes(r))return(...i)=>{let a=o.apply(n,i);return this.trigger(n,"length"),this.trigger(n,r),a};if(h(o)&&!f(o,d))return this.reactive(o);return o},set:(n,r,o)=>{if(f(n,d))return console.warn(`Cannot set property ${String(r)} on readonly object`),!1;let i=Reflect.get(n,r);if(h(o)&&!f(o,C)&&!f(o,d))o=this.reactive(o);let s=Reflect.set(n,r,o);if(i!==o){if(this.trigger(n,r),typeof r==="string"&&!isNaN(Number(r)))this.trigger(n,"length")}return s},deleteProperty:(n,r)=>{if(f(n,d))return console.warn(`Cannot delete property ${String(r)} on readonly object`),!1;let o=r in n,i=Reflect.deleteProperty(n,r);if(o)this.trigger(n,r),this.trigger(n,"length");return i}});return this.reactiveMap.set(e,t),this.proxyMap.set(t,e),t}readonly(e){if(!h(e))return console.warn("readonly: target must be an object"),e;if(f(e,d))return e;if(this.readonlyMap.has(e))return this.readonlyMap.get(e);let t=new Proxy(e,{get:(n,r)=>{if(r===C)return!1;if(r===d)return!0;let o=Reflect.get(n,r);if(h(o))return this.readonly(o);return o},set:()=>(console.warn("Cannot set property on readonly object"),!1),deleteProperty:()=>(console.warn("Cannot delete property on readonly object"),!1)});return this.readonlyMap.set(e,t),t}effect(e,t){let{lazy:n=!1,scheduler:r,throwOnError:o=!1}=t||{},i=()=>{if(!i.active)return e();try{return this.cleanup(i),this.effectStack.push(i),this.activeEffect=i,e()}catch(s){if(o)throw s;console.error("Effect error:",s);return}finally{this.effectStack.pop(),this.activeEffect=this.effectStack[this.effectStack.length-1]??null}};if(i.id=Re++,i.deps=[],i.active=!0,i.scheduler=r,!n)i();return i}runWithEffect(e,t){this.effectStack.push(e),this.activeEffect=e;try{return t()}finally{this.effectStack.pop(),this.activeEffect=this.effectStack[this.effectStack.length-1]??null}}computed(e){let t=!0,n,r={},o=()=>{this.track(r,"value")},i=this.effect(()=>{n=e(),t=!1},{lazy:!0,scheduler:()=>{if(!t)t=!0,this.trigger(r,"value")}});return{get value(){if(t)i();return o(),n}}}cleanup(e){e.deps.forEach((t)=>{t.delete(e)}),e.deps.length=0}track(e,t){if(!this.activeEffect||!this.activeEffect.active)return;let n=this.targetMap.get(e);if(!n)n=new Map,this.targetMap.set(e,n);let r=n.get(t);if(!r)r=new Set,n.set(t,r);if(!r.has(this.activeEffect))r.add(this.activeEffect),this.activeEffect.deps.push(r)}trigger(e,t){let n=this.targetMap.get(e);if(!n)return;let r=n.get(t);if(!r)return;new Set(r).forEach((i)=>{if(i.active)if(i.scheduler)i.scheduler(i);else i()})}stop(e){if(e.active)this.cleanup(e),e.active=!1}}function D(e){return m.getInstance().reactive(e)}function Qe(e){return m.getInstance().readonly(e)}function g(e,t){return m.getInstance().effect(e,t)}function Ze(e){return m.getInstance().computed(e)}function Je(e){let t={value:e};return Object.defineProperty(t,V,{configurable:!1,enumerable:!1,value:!0}),D(t)}function z(e){return h(e)&&Boolean(Reflect.get(e,V))}function Xe(e){return z(e)?e.value:e}function R(e){m.getInstance().stop(e)}function _(e,t){if(!h(e)||t.has(e))return;if(t.add(e),Array.isArray(e)){e.forEach((n)=>_(n,t));return}Object.keys(e).forEach((n)=>{_(e[n],t)})}function et(e,t,n={}){let r=m.getInstance(),o=z(e)?()=>e.value:e,i,s=null,a=()=>{if(!l.active)return;s?.(),s=null;let u=c();t(u,i,(y)=>{s=y}),i=u},c=g(()=>{let u=o();if(n.deep&&h(u))_(u,new Set);return u},{lazy:!0,scheduler:()=>{if(n.sync)a();else x.enqueue(l)}}),l=g(()=>{a()},{lazy:!0});if(n.immediate)a();else i=c();return()=>{r.stop(c),r.stop(l)}}function Ce(e){return h(e)&&f(e,C)}function tt(e){return h(e)&&f(e,d)}function v(e){if(e===void 0||e===null)return[];return Array.isArray(e)?e:[e]}function Y(e){return typeof e==="object"&&e!==null&&"component"in e}function Q(e){return typeof e==="object"&&e!==null&&"tag"in e&&e.tag!=="slot"}function Z(e){return typeof e==="object"&&e!==null&&"tag"in e&&e.tag==="slot"}function rt(e,t,n,r,o,i){return{tag:e,props:t,children:n,listeners:r,key:o,directions:i}}function be(e,t={}){return{tag:e,...t}}function p(e){return(t={})=>be(e,t)}var P=p("div"),ot=p("span"),it=p("p"),st=p("button"),at=p("input"),pt=p("section"),ct=p("main"),ut=p("header"),lt=p("footer"),dt=p("nav"),ft=p("article"),ht=p("aside"),mt=p("h1"),gt=p("h2"),vt=p("h3"),yt=p("h4"),Rt=p("h5"),Ct=p("h6"),bt=p("strong"),Et=p("em"),xt=p("small"),Tt=p("pre"),wt=p("code"),St=p("blockquote"),Pt=p("ul"),Lt=p("ol"),Mt=p("li"),Nt=p("a"),At=p("img"),kt=p("form"),It=p("label"),Ht=p("textarea"),jt=p("select"),Ot=p("option"),Vt=p("table"),Bt=p("thead"),_t=p("tbody"),Dt=p("tr"),Ut=p("th"),$t=p("td");function Kt(e,t,n,r,o){if(typeof e==="function")return{component:e,props:t,children:n,key:r,directions:o};return{component:e.component,props:e.props,children:e.children,key:e.key,directions:e.directions,emitters:e.emitters}}function Wt(e,t,n){return{tag:"slot",props:{name:e},key:t,directions:n}}function Ft(e,t,n){return e.map((r,o)=>{let i=t(r,o);if(typeof i==="string")throw Error("each render callback must return a VNode");if(!n)return i;return{...i,key:n(r,o)}})}function X(e){let t=e.split(".");if(e.length===0||t.some((n)=>n.length===0||n==="__proto__"||n==="prototype"||n==="constructor"))throw Error(`Invalid model path "${e}"`);return t}function K(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function ee(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function Ee(e){return typeof e==="string"?e:e.path}function J(e,t){let n=e;for(let r of X(t)){if(!K(n))throw Error(`Invalid model path "${t}"`);if(!ee(n,r)){if(r in n)throw Error(`Invalid model path "${t}"`);return}n=n[r]}return n}function xe(e,t,n){let r=X(t),o=e;for(let s of r.slice(0,-1)){if(!ee(o,s)){if(s in o)throw Error(`Invalid model path "${t}"`);o[s]={}}else if(!K(o[s]))throw Error(`Invalid model path "${t}"`);let a=o[s];if(!K(a))throw Error(`Invalid model path "${t}"`);o=a}let i=r[r.length-1];o[i]=n}function U(e,t){if(typeof e!=="string"&&e.format)return e.format(t);return t===void 0||t===null?"":String(t)}function Te(e,t){if(typeof e!=="string"&&e.parse)return e.parse(t);return t}function we(e,t,n){if(e instanceof HTMLInputElement){if(e.type==="checkbox"){e.checked=Array.isArray(n)?n.some((r)=>String(r)===e.value):Boolean(n);return}if(e.type==="radio"){e.checked=n===e.value;return}e.value=U(t,n);return}if(e instanceof HTMLTextAreaElement){e.value=U(t,n);return}if(e instanceof HTMLSelectElement){if(e.multiple){let r=Array.isArray(n)?new Set(n.map(String)):new Set;for(let o=0;o<e.options.length;o+=1){let i=e.options.item(o);if(!i)continue;i.selected=r.has(i.value)}return}e.value=U(t,n)}}function Se(e,t){if(e instanceof HTMLInputElement){if(e.type==="checkbox"){if(Array.isArray(t)){let n=t.filter((r)=>String(r)!==e.value);return e.checked?[...n,e.value]:n}return e.checked}if(e.type==="radio")return e.checked?e.value:t;return e.value}if(e instanceof HTMLTextAreaElement)return e.value;if(e instanceof HTMLSelectElement){if(!e.multiple)return e.value;let n=[];for(let r=0;r<e.selectedOptions.length;r+=1){let o=e.selectedOptions.item(r);if(o)n.push(o.value)}return n}return}class W{bindings=new WeakMap;bind(e,t,n){if(!this.isSupportedControl(e))return;let r=this.bindings.get(e);if(r&&this.sameBinding(r,t))return;this.cleanup(e);let o=Ee(t),i=()=>we(e,t,J(n,o)),s=e instanceof HTMLTextAreaElement||e instanceof HTMLInputElement&&!["checkbox","radio"].includes(e.type)?"input":"change",a=()=>{let l=J(n,o);xe(n,o,Te(t,Se(e,l)))};e.addEventListener(s,a);let c=g(i);this.bindings.set(e,{binding:t,path:o,parse:typeof t==="string"?void 0:t.parse,format:typeof t==="string"?void 0:t.format,eventName:s,listener:a,effect:c})}cleanup(e){let t=this.bindings.get(e);if(!t)return;e.removeEventListener(t.eventName,t.listener),R(t.effect),this.bindings.delete(e)}isSupportedControl(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement}sameBinding(e,t){if(typeof e.binding==="string"||typeof t==="string")return e.binding===t;return e.path===t.path&&e.parse===t.parse&&e.format===t.format}}function M(e){return/^on[A-Z]/.test(e)||/^on[a-z]/.test(e)}function ne(e){return e.slice(2).toLowerCase()}function re(e){let[t,...n]=e.split(".");return{eventName:t,modifiers:new Set(n)}}function oe(e,t){let n=(r)=>{if(t.has("stop"))r.stopPropagation();if(t.has("prevent"))r.preventDefault();if(t.has("self")&&r.currentTarget!==r.target)return;if(t.has("once"))r.currentTarget.removeEventListener(r.type,n);e(r)};return n}function ie(e,t,n){let r=t.includes("-")?t:t.replace(/[A-Z]/g,(o)=>`-${o.toLowerCase()}`);e.setProperty(r,te(n))}var N=null;function se(e){if(!e||!(e instanceof A))throw Error("Invalid router instance");N=e}function Pe(){if(!N)throw Error("Router is not initialized. Please make sure you have installed the router plugin.");return N}function ae(){return N}var pe="http://www.w3.org/2000/svg",Le=new Set(["svg","g","defs","rect","circle","ellipse","line","polyline","polygon","path","text","tspan","textPath","use","symbol","marker","linearGradient","radialGradient","stop","pattern","mask","clipPath","foreignObject"]);class I{listeners=new WeakMap;effects=new WeakMap;modelBindings=new W;matches(e){return typeof e==="object"&&e!==null&&Q(e)}mount(e,t){if(e.directions?.if===!1)return document.createComment("if");let n=e.tag==="navigator",r=n?document.createElement("a"):Le.has(e.tag)?document.createElementNS(pe,e.tag):document.createElement(e.tag),o=e.props??{};if(n){let{url:i,openType:s,...a}=o,c=typeof i==="string"?i:"#";r.setAttribute("href",c),r.addEventListener("click",(l)=>{let u=ae();if(u)l.preventDefault(),u.push(r.getAttribute("href")??"#")}),this.applyProps(r,{},a,t)}else this.applyProps(r,{},o,t);return this.updateListeners(r,{},this.collectListeners(e)),this.mountChildren(r,e,t),this.applyDirections(r,void 0,e.directions,t),r}patch(e,t,n,r){if(e.tag!==t.tag||n.nodeType===Node.COMMENT_NODE){let i=this.mount(t,r);return n.parentNode?.replaceChild(i,n),this.unmount(e,n,r),i}if(!(n instanceof Element))return n;if(t.directions?.if===!1){let i=document.createComment("if");return n.parentNode?.replaceChild(i,n),this.unmount(e,n,r),i}if(t.tag==="navigator"||e.tag==="navigator"){let i=e.props??{},s=t.props??{},a=typeof i.url==="string"?i.url:"",c=typeof s.url==="string"?s.url:"";if(a!==c)n.setAttribute("href",c);let l={...s};delete l.url,delete l.openType,this.applyProps(n,i,l,r)}else this.applyProps(n,e.props??{},t.props??{},r);return this.updateListeners(n,this.collectListeners(e),this.collectListeners(t)),this.updateChildren(n,e,t,r),this.applyDirections(n,e.directions,t.directions,r),n}unmount(e,t,n){if(!(t instanceof Element))return;this.effects.get(t)?.forEach((r)=>R(r)),this.effects.delete(t),this.listeners.get(t)?.forEach(({eventName:r,listener:o})=>{t.removeEventListener(r,o)}),this.listeners.delete(t),this.modelBindings.cleanup(t),this.unmountChildren(t,e,n)}mountChildren(e,t,n){v(t.children).forEach((r)=>{e.appendChild(n.renderer.mount(r,n))})}updateChildren(e,t,n,r){this.updateOrdinaryChildren(e,v(t.children),v(n.children),r)}unmountChildren(e,t,n){v(t.children).forEach((r,o)=>{let i=e.childNodes[o];if(i)n.renderer.unmount(r,i,n)})}applyProps(e,t,n,r){Object.keys(t).forEach((o)=>{if(M(o)||o in n)return;if(o==="className"||o==="class")e.removeAttribute("class");else if(o==="style")e.removeAttribute("style");else if(o==="value"&&typeof e==="object"&&e!==null&&"value"in e)e.value="";else e.removeAttribute(k(o))}),Object.entries(n).forEach(([o,i])=>{if(M(o))return;if(t[o]===i)return;if(o==="className"||o==="class"){if(e.namespaceURI===pe)e.setAttribute("class",String(i??""));else e.className=String(i??"");return}if(o==="value"&&typeof e==="object"&&e!==null&&"value"in e){e.value=String(i??"");return}if(o==="style"&&typeof i==="object"&&i!==null){e.removeAttribute("style");let s=e.style;Object.entries(i).forEach(([a,c])=>{ie(s,a,c)});return}if(i===!1||i===void 0||i===null){e.removeAttribute(k(o));return}if(i===!0){e.setAttribute(k(o),"");return}if(typeof i==="string"&&r.templateEngine.hasExpressions(i)){this.setupReactiveAttribute(e,o,i,r);return}e.setAttribute(k(o),String(i))})}applyDirections(e,t,n,r){if(n&&"show"in n)e.style.display=n.show?"":"none";else if(t&&"show"in t)e.style.display="";if(!n?.model){this.modelBindings.cleanup(e);return}this.modelBindings.bind(e,n.model,r.templateEngine.state)}updateOrdinaryChildren(e,t,n,r){if(this.assertNoDuplicateKeys(t),this.assertNoDuplicateKeys(n),this.hasOnlyKeyedChildren(t,n)){this.updateKeyedChildren(e,t,n,r);return}let o=Math.min(t.length,n.length);for(let i=0;i<o;i+=1){let s=e.childNodes[i];if(!s){e.appendChild(r.renderer.mount(n[i],r));continue}r.renderer.patch(t[i],n[i],s,r)}for(let i=o;i<n.length;i+=1)e.appendChild(r.renderer.mount(n[i],r));for(let i=t.length-1;i>=n.length;i-=1){let s=e.childNodes[i];if(s){if(r.renderer.unmount(t[i],s,r),s.parentNode===e)e.removeChild(s)}}}updateKeyedChildren(e,t,n,r){let o=t.map((a,c)=>({vnode:a,node:e.childNodes[c],index:c})),i=new Map,s=new Set;o.forEach((a)=>{let c=this.getVNodeKey(a.vnode);if(c!==void 0&&a.node)i.set(c,{vnode:a.vnode,node:a.node,index:a.index})}),n.forEach((a,c)=>{let l=this.getVNodeKey(a),u=l===void 0?void 0:i.get(l),y;if(u)y=r.renderer.patch(u.vnode,a,u.node,r),s.add(u.index);else y=r.renderer.mount(a,r);let S=e.childNodes[c]??null;if(y!==S)e.insertBefore(y,S)}),o.forEach((a)=>{if(!a.node||s.has(a.index))return;if(r.renderer.unmount(a.vnode,a.node,r),a.node.parentNode===e)e.removeChild(a.node)})}hasOnlyKeyedChildren(e,t){return[...e,...t].every((n)=>this.getVNodeKey(n)!==void 0)}assertNoDuplicateKeys(e){let t=new Set;e.forEach((n)=>{let r=this.getVNodeKey(n);if(r===void 0)return;if(t.has(r))throw Error(`Duplicate key "${r}"`);t.add(r)})}getVNodeKey(e){if(typeof e==="string")return;return e.key}collectListeners(e){let t={};return Object.entries(e.props??{}).forEach(([n,r])=>{if(M(n)&&typeof r==="function")t[ne(n)]=r}),{...t,...e.listeners??{}}}updateListeners(e,t,n){let r=this.listeners.get(e)??new Map,o=new Set(Object.keys(t)),i=new Set(Object.keys(n));o.forEach((s)=>{if(!i.has(s)||t[s]!==n[s]){let a=r.get(s);if(a)e.removeEventListener(a.eventName,a.listener),r.delete(s)}}),i.forEach((s)=>{if(!o.has(s)||t[s]!==n[s]){let{eventName:a,modifiers:c}=re(s),l=typeof e.tagName==="string"&&e.tagName.toLowerCase()==="textarea",u=a==="confirm"&&!l?"keydown":a,y=oe((S)=>{if(u==="keydown"){if(S.key!=="Enter")return}n[s](S)},c);e.addEventListener(u,y),r.set(s,{eventName:u,listener:y})}}),this.listeners.set(e,r)}setupReactiveAttribute(e,t,n,r){let o=g(()=>{e.setAttribute(t,r.templateEngine.evaluateTemplateValue(n))});this.trackEffect(e,o)}trackEffect(e,t){let n=this.effects.get(e)??new Set;n.add(t),this.effects.set(e,n)}}function k(e){if(e.startsWith("data")&&e.length>4)return`data${e.slice(4).replace(/[A-Z]/g,(t)=>`-${t.toLowerCase()}`)}`;if(e==="tabIndex"||e==="colSpan"||e==="htmlFor")return e.toLowerCase();return e}class L{strategies;constructor(){this.strategies=[new ce,new ue,new le,new I]}mount(e,t){return this.findStrategy(e).mount(e,t)}patch(e,t,n,r){let o=this.findStrategy(e),i=this.findStrategy(t);if(o!==i){let s=i.mount(t,r);return n.parentNode?.replaceChild(s,n),o.unmount(e,n,r),s}return o.patch(e,t,n,r)}unmount(e,t,n){this.findStrategy(e).unmount(e,t,n)}findStrategy(e){let t=this.strategies.find((n)=>n.matches(e));if(!t)throw Error("No render strategy found for vnode");return t}}class ce{matches(e){return typeof e==="string"}mount(e,t){return t.templateEngine.parseTemplate(e)}patch(e,t,n,r){if(e===t)return n;let o=this.mount(t,r);return n.parentNode?.replaceChild(o,n),o}unmount(){}}class ue{instances=new WeakMap;instanceNodes=new Map;emitterUnsubscribers=new WeakMap;matches(e){return typeof e==="object"&&e!==null&&Y(e)}mount(e,t){if(e.directions?.if===!1)return document.createComment("if");let n=H(e.component,this.createProps(e));if(t.appContext&&n.setAppContext)n.setAppContext(t.appContext);this.syncEmitters(n,e.emitters??{}),t.registerChild(n);let r=n.mountToNode();return this.trackInstanceNode(n,r),n.setElementChangeListener?.((o,i)=>{this.trackInstanceNode(n,o),this.trackInstanceNode(n,i)}),r}patch(e,t,n,r){if(n.nodeType===Node.COMMENT_NODE){let s=this.mount(t,r);return n.parentNode?.replaceChild(s,n),s}if(t.directions?.if===!1){let s=document.createComment("if");return n.parentNode?.replaceChild(s,n),this.unmount(e,n,r),s}let o=this.instances.get(n);if(o&&e.component===t.component){this.syncEmitters(o,t.emitters??{}),o.setProps(this.createProps(t));let s=o.getElement()??n;return this.trackInstanceNode(o,s),s}let i=this.mount(t,r);return n.parentNode?.replaceChild(i,n),this.unmount(e,n,r),i}unmount(e,t,n){let r=this.instances.get(t);if(r)this.clearEmitters(r),r.unmount(),this.clearInstanceNodes(r),n.unregisterChild(r)}createProps(e){return{...e.props??{},children:v(e.children)}}syncEmitters(e,t){let n=this.emitterUnsubscribers.get(e)??new Map;n.forEach(({listener:r,unsubscribe:o},i)=>{let s=t[i];if(!s||s!==r)o(),n.delete(i)}),Object.entries(t).forEach(([r,o])=>{if(n.get(r)?.listener===o)return;n.set(r,{listener:o,unsubscribe:e.on(r,o)})}),this.emitterUnsubscribers.set(e,n)}clearEmitters(e){this.emitterUnsubscribers.get(e)?.forEach(({unsubscribe:t})=>{t()}),this.emitterUnsubscribers.delete(e)}trackInstanceNode(e,t){this.instances.set(t,e);let n=this.instanceNodes.get(e)??new Set;n.add(t),this.instanceNodes.set(e,n)}clearInstanceNodes(e){this.instanceNodes.get(e)?.forEach((t)=>{this.instances.delete(t)}),this.instanceNodes.delete(e)}}class le{renderedChildren=new WeakMap;matches(e){return typeof e==="object"&&e!==null&&Z(e)}mount(e,t){if(e.directions?.if===!1)return document.createComment("if");let n=document.createElement("div");return n.setAttribute("data-slot",e.props.name),this.mountSlotChildren(n,this.resolveChildren(e,t),t),n}patch(e,t,n,r){if(n.nodeType===Node.COMMENT_NODE){let o=this.mount(t,r);return n.parentNode?.replaceChild(o,n),o}if(t.directions?.if===!1){let o=document.createComment("if");return n.parentNode?.replaceChild(o,n),this.unmount(e,n,r),o}if(n instanceof HTMLElement)n.setAttribute("data-slot",t.props.name),this.replaceSlotChildren(n,e,t,r);return n}unmount(e,t,n){if(!(t instanceof HTMLElement))return;this.unmountSlotChildren(t,n),this.renderedChildren.delete(t)}resolveChildren(e,t){return t.slots[e.props.name]??v(e.children)}replaceSlotChildren(e,t,n,r){let o=this.renderedChildren.get(e)??[],i=this.resolveChildren(n,r),s=Math.min(o.length,i.length);for(let a=0;a<s;a+=1){let c=e.childNodes[a];if(!c){e.appendChild(r.renderer.mount(i[a],r));continue}r.renderer.patch(o[a],i[a],c,r)}for(let a=s;a<i.length;a+=1)e.appendChild(r.renderer.mount(i[a],r));for(let a=o.length-1;a>=i.length;a-=1){let c=e.childNodes[a];if(c){if(r.renderer.unmount(o[a],c,r),c.parentNode===e)e.removeChild(c)}}this.renderedChildren.set(e,i)}mountSlotChildren(e,t,n){t.forEach((r)=>{e.appendChild(n.renderer.mount(r,n))}),this.renderedChildren.set(e,t)}unmountSlotChildren(e,t){(this.renderedChildren.get(e)??[]).forEach((r,o)=>{let i=e.childNodes[o];if(i)t.renderer.unmount(r,i,t)})}}class b{state;bindings=[];templateRegex=/{{(.*?)}}/g;constructor(e){this.state=e;if(!e||typeof e!=="object")throw Error("TemplateEngine requires a valid state object")}parseTemplate(e){if(typeof e!=="string")e=String(e);let t=document.createTextNode("");this.templateRegex.lastIndex=0;let n=Array.from(e.matchAll(this.templateRegex));if(n&&n.length>0)this.setupReactiveBindings(t,e,n);else t.textContent=e;return t}setupReactiveBindings(e,t,n){let r=new Set,o=this.evaluateTemplate(t,n,r);e.textContent=o;let i=g(()=>{try{let s=this.evaluateTemplate(t,n,r);if(e.textContent!==s)e.textContent=s}catch(s){console.error("Template update error:",s),e.textContent=`Error: ${s instanceof Error?s.message:"Unknown error"}`}});this.bindings.push({node:e,originalText:t,effect:i})}evaluateTemplate(e,t,n){let r=e;return t.forEach((o)=>{let i=o[1]?.trim();if(i){n.add(i);let s=this.getValueFromState(i),a=s===void 0||s===null?"":String(s);r=r.replace(o[0],a)}}),r}getValueFromState(e){if(!e)return;let t=e.split("."),n=this.state;for(let r of t){if(!n||typeof n!=="object")return;n=n[r]}return n}clearBindings(){this.bindings.forEach((e)=>{R(e.effect)}),this.bindings=[]}getBindingCount(){return this.bindings.length}hasExpressions(e){return this.templateRegex.lastIndex=0,this.templateRegex.test(e)}extractKeys(e){let t=[],n,r=new RegExp(this.templateRegex,"g");while((n=r.exec(e))!==null){let o=n[1]?.trim();if(o)t.push(o)}return t}evaluateTemplateValue(e){this.templateRegex.lastIndex=0;let t=Array.from(e.matchAll(this.templateRegex));if(!t||t.length===0)return e;let n=new Set;return this.evaluateTemplate(e,t,n)}}class E{props;vnode=null;el=null;renderer=new L;templateEngine;childComponents=new Set;eventListeners={};providers=new Map;updateEffect;appContext=null;parentComponent=null;elementChangeListener=null;styleManager;state;mounted=!1;constructor(e={}){this.props=e;this.styleManager=new de,this.state=D(this.initState()??{}),this.templateEngine=new b(this.state),this.initStyles(),this.updateEffect=g(()=>{if(this.mounted)try{this.update()}catch(t){if(!this.dispatchError(t))throw t}},{throwOnError:!0,scheduler:(t)=>{x.enqueue(t)}})}mount(e){if(!e||!(e instanceof HTMLElement))throw Error("Invalid container element");try{e.appendChild(this.mountToNode())}catch(t){throw console.error("组件渲染错误:",t),t}}mountToNode(){if(this.mounted&&this.el)return this.el;return this.beforeMount(),this.el=m.getInstance().runWithEffect(this.updateEffect,()=>{try{return this.vnode=this.render(),this.renderer.mount(this.vnode,this.createRenderContext())}catch(e){if(this.dispatchError(e))return document.createComment("error-boundary");throw e}}),this.mounted=!0,this.onMounted(),this.el}update(){if(!this.el||!this.vnode)return;this.beforeUpdate();let e=this.vnode,t=this.el;if(this.el=m.getInstance().runWithEffect(this.updateEffect,()=>{let n=this.render(),r=this.renderer.patch(e,n,t,this.createRenderContext());return this.vnode=n,r}),t!==this.el)this.elementChangeListener?.(t,this.el);this.onUpdated(),this.onPropsChange()}unmount(){if(!this.mounted)return;if(this.beforeUnmount(),this.vnode&&this.el)this.renderer.unmount(this.vnode,this.el,this.createRenderContext());if(this.childComponents.clear(),Object.keys(this.eventListeners).forEach((e)=>{this.eventListeners[e].clear(),delete this.eventListeners[e]}),this.providers.clear(),this.parentComponent=null,this.elementChangeListener=null,this.templateEngine.clearBindings(),this.styleManager.destroy(),R(this.updateEffect),this.el?.parentNode)this.el.parentNode.removeChild(this.el);this.el=null,this.vnode=null,this.mounted=!1,this.onUnmounted()}setProps(e){if(this.props={...this.props,...e},this.mounted)x.enqueue(this.updateEffect)}setState(e){Object.assign(this.state,e)}setAppContext(e){this.appContext=e,this.childComponents.forEach((t)=>{t.setAppContext?.(e)})}setParentComponent(e){this.parentComponent=e}getParentComponent(){return this.parentComponent}setElementChangeListener(e){this.elementChangeListener=e}provide(e,t){this.providers.set(e,t)}inject(e,t){let n=this.resolveInjection(e);return n.found?n.value:t}resolveInjection(e){if(this.providers.has(e))return{found:!0,value:this.providers.get(e)};if(this.parentComponent?.resolveInjection)return this.parentComponent.resolveInjection(e);return this.resolveAppInjection(e)}getElement(){return this.el}beforeMount(){}onMounted(){}beforeUpdate(){}onUpdated(){}onPropsChange(){}beforeUnmount(){}onUnmounted(){}dispatchError(e){let t=this.getParentComponent();while(t){let n=t;if(typeof n.onErrorCaptured==="function"){if(n.onErrorCaptured(e,this)===!1)return!0}t=t.getParentComponent?.()??null}return!1}getContext(){return this.appContext}get router(){return this.getRouterFrom(this.appContext)??this.getRouterFromGlobalApp()}emit(e,...t){this.eventListeners[e]?.forEach((n)=>{n(...t)})}on(e,t){if(!this.eventListeners[e])this.eventListeners[e]=new Set;return this.eventListeners[e].add(t),()=>this.off(e,t)}off(e,t){this.eventListeners[e]?.delete(t)}createRenderContext(){return{appContext:this.appContext,templateEngine:this.templateEngine,renderer:this.renderer,slots:this.collectSlots(),registerChild:(e)=>{this.childComponents.add(e),e.setParentComponent?.(this),e.setAppContext?.(this.appContext)},unregisterChild:(e)=>{this.childComponents.delete(e),e.setParentComponent?.(null)}}}collectSlots(){let e={default:[]};return v(this.props.children).forEach((n)=>{let r=this.getSlotName(n);if(!e[r])e[r]=[];e[r].push(this.normalizeSlotChild(n))}),e}getSlotName(e){if(typeof e==="string")return"default";return"slot"in e&&typeof e.slot==="string"?e.slot:"default"}normalizeSlotChild(e){if(typeof e==="string"||!("slot"in e))return e;let t={...e};return delete t.slot,t}getRouterFrom(e){if(!e||typeof e!=="object"||!("router"in e))return;return e.router}getRouterFromGlobalApp(){let e=globalThis.__APP__;return this.getRouterFrom(e)}resolveAppInjection(e){if(!this.appContext||typeof this.appContext!=="object")return{found:!1,value:void 0};return this.appContext.app?.resolveInjection?.(e)??{found:!1,value:void 0}}}class fe extends E{}function T(e){if(!e.startsWith("/"))return`/${e}`;return e||"/"}function j(e,t){let n=T(t.split("?")[0]);for(let i of e){if(i.path==="*")continue;let s=Me(i.path,n);if(s)return{route:i,params:s}}let r=e.find((i)=>i.path==="*");if(r)return{route:r,params:{pathMatch:n}};let o=e.find((i)=>i.path==="/");return o?{route:o,params:{}}:null}function Me(e,t){let n=he(e),r=he(t);if(n.length!==r.length)return null;let o={};for(let i=0;i<n.length;i+=1){let s=n[i],a=r[i];if(s.startsWith(":")){let c=s.slice(1);if(!c)return null;o[decodeURIComponent(c)]=decodeURIComponent(a);continue}if(s!==a)return null}return o}function he(e){let t=T(e);if(t==="/")return[];return t.split("/").filter(Boolean)}function me(e,t,n){let r=T(e),o=n==="/"?r:n+r;return t==="hash"?`#${o}`:o}function ge(e,t){let n,r,o;if(e==="history")r=window.location.pathname+window.location.search,n=window.location.pathname,o=window.location.search;else{r=window.location.hash||"#/",n=r.startsWith("#")?r.slice(1):r;let s=n.indexOf("?");o=s>=0?n.slice(s+1):"",n=s>=0?n.slice(0,s):n}if(n.startsWith(t)&&t!=="/"&&n!=="/")n=n.slice(t.length);return n=T(n),{path:n,fullPath:r,query:Ne(o),params:{}}}function F(e,t,n,r){let o=T(e),i=r==="/"?o:r+o;if(n==="history"){if(t)window.history.replaceState({},"",i);else window.history.pushState({},"",i);return}if(t){let s=window.location.href.split("#")[0];window.location.replace(`${s}#${i}`);return}window.location.hash=i}function Ne(e){let t={},n=e.startsWith("?")?e.slice(1):e;if(!n)return t;return n.split("&").forEach((r)=>{let[o,i]=r.split("=");if(o)t[decodeURIComponent(o)]=i?decodeURIComponent(i):""}),t}function Ae(e){let t=e.indexOf("?");if(t<0)return{};let n=e.slice(t+1),r={};if(!n)return r;return n.split("&").forEach((o)=>{let[i,s]=o.split("=");if(i)r[decodeURIComponent(i)]=s?decodeURIComponent(s):""}),r}class A{currentRoute=null;currentLocation=null;routes=[];app=null;mode;base;routeChangeListeners=[];beforeGuards=[];afterHooks=[];removeWindowListener;constructor(e){let t=Array.isArray(e)?{routes:e}:e;this.routes=t.routes||[],this.mode=t.mode||"history",this.base=t.base||"/",this.validateRoutes(),this.initEvents(),this.resolveCurrentRoute()}install(e){this.app=e,e.router=this,se(this);let t=e.getContext();t.router=this,this.resolveCurrentRoute()}push(e){this.navigate(e,!1)}replace(e){this.navigate(e,!0)}forward(){window.history.forward()}back(){window.history.back()}go(e){window.history.go(e)}getCurrentRoute(){if(!this.currentLocation)this.resolveCurrentRoute();return this.currentLocation}getCurrentRouteRecord(){if(!this.currentRoute)this.resolveCurrentRoute();return this.currentRoute}onRouteChange(e){return this.routeChangeListeners.push(e),()=>{let t=this.routeChangeListeners.indexOf(e);if(t>-1)this.routeChangeListeners.splice(t,1)}}beforeEach(e){return this.beforeGuards.push(e),()=>{let t=this.beforeGuards.indexOf(e);if(t>-1)this.beforeGuards.splice(t,1)}}afterEach(e){return this.afterHooks.push(e),()=>{let t=this.afterHooks.indexOf(e);if(t>-1)this.afterHooks.splice(t,1)}}getRoutes(){return[...this.routes]}addRoute(e){if(this.routes.some((n)=>n.path===e.path))throw Error(`Route already exists: ${e.path}`);if(this.routes.push(e),this.getCurrentLocation().path===e.path)this.handleRouteChange()}createHref(e){return me(e,this.mode,this.base)}destroy(){if(this.removeWindowListener?.(),this.removeWindowListener=void 0,this.app?.router===this)this.app.router=void 0;this.app=null}navigate(e,t){if(!e||typeof e!=="string")throw Error("Path must be a non-empty string");let n=this.currentLocation,r=this.resolveTarget(e);if(!r)return;let o=r.location;for(let i of this.beforeGuards){let s=i(o,n);if(s===!1)return;if(typeof s==="string"&&s!==e){this.navigate(s,t);return}}if(n&&this.isSameLocation(n,o))return;F(r.path,t,this.mode,this.base),this.currentRoute=r.route,this.currentLocation=o,this.triggerRouteChangeListeners(o,n),this.afterHooks.forEach((i)=>{try{i(o,n)}catch(s){console.error("Route afterEach error:",s)}})}resolveTarget(e){let t=j(this.routes,e.split("?")[0]);if(!t)return null;let n=this.applyRedirect(t),r=n?.path??e,o=n?.route??t.route;return{path:r,route:o,location:{path:r.split("?")[0],query:Ae(r),params:n?.params??t.params,fullPath:r,name:o?.name,meta:o?.meta}}}applyRedirect(e){let t=new Set,n=e,r="";while(n.route.redirect){if(t.has(n.route.path))throw Error(`Redirect loop detected for route: ${n.route.path}`);t.add(n.route.path),r=n.route.redirect;let o=j(this.routes,r.split("?")[0]);if(!o)return null;n=o}return r?{route:n.route,params:n.params,path:r}:null}validateRoutes(){if(!Array.isArray(this.routes))throw Error("Router routes must be an array");let e=new Set;this.routes.forEach((t)=>{if(!t.component&&!t.redirect)throw Error(`Route ${t.path} must define a component or redirect`);if(e.has(t.path))throw Error(`Duplicate route path: ${t.path}`);e.add(t.path)})}initEvents(){if(typeof window>"u")return;let e=this.mode==="history"?"popstate":"hashchange",t=()=>{this.handleRouteChange()};window.addEventListener(e,t),this.removeWindowListener=()=>{window.removeEventListener(e,t)}}handleRouteChange(){let e=this.currentLocation,t=this.resolveCurrentRoute();if(!this.isSameLocation(e,t))this.triggerRouteChangeListeners(t,e)}resolveCurrentRoute(){let e=this.getCurrentLocation(),t=j(this.routes,e.path),n=t?this.applyRedirect(t):null,r=n?.route??t?.route??null;if(n&&n.path!==e.path)F(n.path,!0,this.mode,this.base);if(this.currentRoute=r,this.currentLocation={...e,params:n?.params??t?.params??{},name:r?.name,meta:r?.meta},this.afterHooks.length>0){let o=this.currentLocation;this.afterHooks.forEach((i)=>{try{i(o,null)}catch(s){console.error("Route afterEach error:",s)}})}return this.currentLocation}getCurrentLocation(){return ge(this.mode,this.base)}isSameLocation(e,t){return e?.fullPath===t?.fullPath&&e?.name===t?.name}triggerRouteChangeListeners(e,t){this.routeChangeListeners.forEach((n)=>{try{n(e,t)}catch(r){console.error("Route change listener error:",r)}})}}class ke extends E{unsubscribe;initState(){return{currentPath:this.router?.getCurrentRoute()?.path??window.location.pathname}}initStyles(){}onMounted(){let e=this.router;this.unsubscribe=e?.onRouteChange((t)=>{this.state.currentPath=t.path})}onUnmounted(){this.unsubscribe?.()}render(){let e=this.router,t=this.props.activeClass??"active",n=this.state.currentPath===this.props.to,r=[this.props.className,n?t:void 0].filter(Boolean).join(" ");return{tag:"a",props:{href:e?.createHref(this.props.to)??this.props.to,className:r},listeners:{click:(o)=>{if(o.preventDefault(),this.props.replace)e?.replace(this.props.to);else e?.push(this.props.to)}},children:this.props.children&&this.props.children.length>0?this.props.children:[this.props.to]}}}class Ie extends E{unsubscribe;initState(){let e=this.router;return{route:e?.getCurrentRoute()??null,record:e?.getCurrentRouteRecord()??null}}initStyles(){}onMounted(){let e=this.router;this.unsubscribe=e?.onRouteChange((t)=>{this.state.route=t,this.state.record=e.getCurrentRouteRecord()})}onUnmounted(){this.unsubscribe?.()}render(){let e=this.state.record??this.router?.getCurrentRouteRecord();return{tag:"div",props:{"data-router-view":""},children:e?.component?[{component:e.component}]:[]}}}function qn(e){return new A(e)}var He=new Set(["base","link","meta"]);function ve(e){let t=e.lang??"en",n=e.charset??"utf-8",r=e.viewport??"width=device-width, initial-scale=1",o=O({lang:t,...e.htmlAttributes??{}}),i=O(e.bodyAttributes),s=je(e.body);return["<!doctype html>",`<html${o}>`,"<head>",` <meta charset="${w(n)}">`,` <meta name="viewport" content="${w(r)}">`,` <title>${w(e.title)}</title>`,e.description?` <meta name="description" content="${w(e.description)}">`:"",...(e.head??[]).map((a)=>` ${Oe(a)}`),e.styles&&e.styles.length>0?` <style>${G(e.styles)}</style>`:"","</head>",`<body${i}>`,s,...(e.scripts??[]).map((a)=>` ${Ve(a)}`),"</body>","</html>"].filter((a)=>a!=="").join(`
|
|
2
|
+
`)}function je(e){if(typeof document>"u")throw Error("renderHtmlDocument requires a DOM-like document");let t=document.createElement("div"),n=new L,r=new Set,o=Array.isArray(e)?e:[e],i={templateEngine:new b({}),renderer:n,slots:{default:[]},registerChild:(a)=>{r.add(a)},unregisterChild:(a)=>{r.delete(a)}};o.forEach((a)=>{t.appendChild(n.mount(a,i))});let s=t.innerHTML;return r.forEach((a)=>{a.unmount()}),s}function Oe(e){let t=O(e.attributes);if(He.has(e.tag)&&!e.text)return`<${e.tag}${t}>`;return`<${e.tag}${t}>${w(e.text??"")}</${e.tag}>`}function Ve(e){return`<script${O({type:e.type,src:e.src,async:e.async,defer:e.defer,...e.attributes??{}})}></script>`}function O(e={}){let t=Object.entries(e).flatMap(([n,r])=>{if(r===!1||r===null||r===void 0)return[];return r===!0?[n]:[`${n}="${w(String(r))}"`]}).join(" ");return t?` ${t}`:""}function w(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}var ye="#app";class Be{options;container=null;rootInstance=null;mounted=!1;templateEngine=null;appContext;providers=new Map;plugins=[];unmountedCallback;router;constructor(e={}){this.options=e;this.appContext={app:this,version:"0.8.0",config:e.config||{}}}handleError(e){console.error("应用错误:",e),this.renderErrorUI(e)}renderErrorUI(e){if(!this.container)return;this.container.innerHTML=`
|
|
3
|
+
<div style="padding: 20px; background-color: #ffebee; color: #c62828; font-family: Arial, sans-serif;">
|
|
4
|
+
<h3>应用错误</h3>
|
|
5
|
+
<p>${e.message}</p>
|
|
6
|
+
<pre style="background-color: #fff; padding: 10px; border-radius: 4px; overflow: auto;">${e.stack}</pre>
|
|
7
|
+
</div>
|
|
8
|
+
`}use(e,...t){if(typeof e.install!=="function")throw Error("插件必须提供 install 方法");return e.install(this,...t),this.plugins.push({plugin:e,args:t}),this}mount(){if(this.mounted){console.warn("应用已经处于运行状态");return}let e=this.resolveMountContainer();if(!e)return;try{if(this.container=e,globalThis.__APP__=this,this.options.root){if(this.rootInstance=H(this.options.root,this.options.rootProps),"setAppContext"in this.rootInstance)this.rootInstance.setAppContext(this.appContext);if(this.options.state&&"setState"in this.rootInstance)this.rootInstance.setState(this.options.state);this.rootInstance.mount(this.container),this.templateEngine=new b(this.options.state||{})}this.mounted=!0,this.onMounted()}catch(t){this.handleError(t)}}unmount(){if(!this.mounted){console.warn("应用未处于运行状态");return}try{if(this.onBeforeUnmount(),this.rootInstance){if("unmount"in this.rootInstance)this.rootInstance.unmount();this.rootInstance=null,this.mounted=!1,delete globalThis.__APP__}if(this.templateEngine)this.templateEngine.clearBindings(),this.templateEngine=null;if(this.container)this.container.innerHTML="";if(this.unmountedCallback)this.unmountedCallback()}catch(e){console.error("Failed to unmount app:",e)}}isRunning(){return this.mounted}updateRootComponent(e){if(this.mounted)this.unmount();this.options.root=e,this.mount()}update(e){if(!this.mounted)return console.warn("Cannot update unmounted app"),this;try{if(e&&this.options.state){if(this.options.state={...this.options.state,...e},this.rootInstance&&"setState"in this.rootInstance)this.rootInstance.setState(e);if(this.templateEngine)this.templateEngine.state=this.options.state}this.onUpdated()}catch(t){console.error("Failed to update app:",t)}return this}getContext(){return this.appContext}provide(e,t){return this.providers.set(e,t),this}inject(e,t){let n=this.resolveInjection(e);return n.found?n.value:t}resolveInjection(e){if(!this.providers.has(e))return{found:!1,value:void 0};return{found:!0,value:this.providers.get(e)}}getState(){return this.options.state}setState(e){if(this.options.state=e,this.mounted)this.update();return this}onUnmounted(e){return this.unmountedCallback=e,this}renderHtmlDocument(e={}){let t=this.options.document??{},n=this.mergeDocumentScripts(t.scripts,e.scripts);return ve({...t,...e,title:e.title??t.title??"TransOne App",body:e.body??t.body??this.createMountDocumentBody(),scripts:n})}resolveRootElement(e){if(!e)return null;if(typeof e==="string"){if(typeof document>"u")return null;return document.querySelector(e)}return typeof Element<"u"&&e instanceof Element?e:null}resolveMountContainer(){if(typeof document>"u")return null;let e=this.resolveRootElement(this.options.rootElement??ye);return e instanceof HTMLElement?e:null}createMountDocumentBody(){let e=this.options.rootElement??ye;if(typeof e==="string")return this.createMountElementFromSelector(e);if(typeof Element<"u"&&e instanceof Element){let t={};if(e.id)t.id=e.id;if(e.className)t.className=e.className;return{tag:e.tagName.toLowerCase(),props:t}}return P({props:{id:"app"}})}createMountElementFromSelector(e){if(e.startsWith("#")&&e.length>1)return P({props:{id:e.slice(1)}});if(e.startsWith(".")&&e.length>1)return P({props:{className:e.slice(1)}});return P({props:{"data-transone-root":e}})}mergeDocumentScripts(e,t){if(!e&&!t)return;return[...e??[],...t??[]]}onMounted(){this.plugins.forEach(({plugin:e})=>{if(e&&typeof e.onMounted==="function")e.onMounted(this)})}onUpdated(){this.plugins.forEach(({plugin:e})=>{if(e&&typeof e.onUpdated==="function")e.onUpdated(this)})}onBeforeUnmount(){this.plugins.forEach(({plugin:e})=>{if(e&&typeof e.onBeforeUnmount==="function")e.onBeforeUnmount(this)})}}
|
|
9
|
+
export{x as a,ze as b,Ye as c,m as d,D as e,Qe as f,g,Ze as h,Je as i,z as j,Xe as k,R as l,et as m,Ce as n,tt as o,v as p,Y as q,Q as r,Z as s,rt as t,be as u,P as v,ot as w,it as x,st as y,at as z,pt as A,ct as B,ut as C,lt as D,dt as E,ft as F,ht as G,mt as H,gt as I,vt as J,yt as K,Rt as L,Ct as M,bt as N,Et as O,xt as P,Tt as Q,wt as R,St as S,Pt as T,Lt as U,Mt as V,Nt as W,At as X,kt as Y,It as Z,Ht as _,jt as $,Ot as aa,Vt as ba,Bt as ca,_t as da,Dt as ea,Ut as fa,$t as ga,Kt as ha,Wt as ia,Ft as ja,Ee as ka,J as la,xe as ma,W as na,A as oa,ke as pa,Ie as qa,qn as ra,Pe as sa,I as ta,L as ua,ce as va,ue as wa,le as xa,b as ya,E as za,fe as Aa,ve as Ba,Be as Ca};
|
|
10
|
+
|
|
11
|
+
//# debugId=9766D61D79EA1A8864756E2164756E21
|
|
12
|
+
//# sourceMappingURL=index-5dxcnfw6.js.map
|