@geektech/tsone 0.0.2 → 0.1.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-zh.md +405 -0
- package/README.md +199 -52
- package/dist/core/animation/TransitionGroup.d.ts +7 -0
- package/dist/core/animation/index.d.ts +2 -0
- package/dist/core/animation/list-animation-controller.d.ts +16 -0
- package/dist/core/animation/transition-group-strategy.d.ts +15 -0
- package/dist/core/animation/types.d.ts +25 -0
- package/dist/core/app.d.ts +25 -8
- package/dist/core/index.d.ts +1 -0
- package/dist/core/renderer/element-strategy.d.ts +25 -0
- package/dist/core/renderer.d.ts +2 -21
- package/dist/core/vnode.d.ts +36 -0
- package/dist/{index-ycmc7ga1.js → index-wv9gyjqt.js} +628 -334
- package/dist/index-wv9gyjqt.js.map +25 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +258 -105
- package/dist/index.js.map +6 -5
- package/dist/router/index.js +1 -1
- package/package.json +2 -2
- package/dist/index-ycmc7ga1.js.map +0 -21
package/README.md
CHANGED
|
@@ -1,34 +1,44 @@
|
|
|
1
1
|
# TSone
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
English | [简体中文](./README-zh.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A lightweight frontend framework written entirely in TypeScript, with
|
|
6
|
+
reactivity, class-based components, strategy-driven rendering, and routing.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- Bun 原生工具链:安装、测试、构建、示例服务和文档服务均由 Bun 驱动
|
|
9
|
-
- 文档内容由 TSone 的 TypeScript typed content registry 提供
|
|
10
|
-
- 响应式系统:`reactive`、`effect`、`computed`
|
|
11
|
-
- 面向对象组件模型:`Component<Props, State>`、生命周期、事件、插槽
|
|
12
|
-
- 策略模式渲染层:文本、元素、组件、插槽按 VNode 类型分发
|
|
13
|
-
- 内置路由:`createRouter`、`RouterView`、`RouterLink`
|
|
14
|
-
- 轻量级运行时,生产包无外部运行时依赖
|
|
8
|
+
## Features
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
- TypeScript-first implementation with typed public APIs
|
|
11
|
+
- Bun-native tooling for installation, testing, builds, playgrounds, and docs
|
|
12
|
+
- Documentation backed by a TypeScript typed-content registry
|
|
13
|
+
- Reactive primitives: `reactive`, `effect`, and `computed`
|
|
14
|
+
- Object-oriented components with `Component<Props, State>`, lifecycle hooks,
|
|
15
|
+
events, and slots
|
|
16
|
+
- Strategy-based rendering that dispatches text, elements, components, and
|
|
17
|
+
slots by VNode type
|
|
18
|
+
- Built-in routing with `createRouter`, `RouterView`, and `RouterLink`
|
|
19
|
+
- Lightweight runtime with no external production dependencies
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
根目录命令会代理到该包,包内仍保留自己的源码、测试、示例、文档和发布配置。
|
|
21
|
+
## Repository Structure
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
This repository is a Bun workspace monorepo with two published packages:
|
|
24
|
+
`packages/tsone/` contains the browser framework `@geektech/tsone`, and
|
|
25
|
+
`packages/tsone-cli/` contains the Bun-native development tooling
|
|
26
|
+
`@geektech/tsone-cli`. Standalone example projects live in the root
|
|
27
|
+
`playground/` directory.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
22
30
|
|
|
23
31
|
```bash
|
|
24
|
-
bun add @geektech/tsone
|
|
32
|
+
bun add @geektech/tsone @geektech/tsone-cli
|
|
25
33
|
```
|
|
26
34
|
|
|
27
35
|
```bash
|
|
28
|
-
pnpm add @geektech/tsone
|
|
36
|
+
pnpm add @geektech/tsone @geektech/tsone-cli
|
|
29
37
|
```
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
The framework and CLI require Bun `>=1.3.0` for the documented workflow.
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
32
42
|
|
|
33
43
|
```typescript
|
|
34
44
|
import {
|
|
@@ -78,13 +88,73 @@ class App extends Component<Record<string, never>, AppState> {
|
|
|
78
88
|
const state = reactive({ ready: true });
|
|
79
89
|
const status = computed(() => (state.ready ? 'ready' : 'pending'));
|
|
80
90
|
|
|
81
|
-
const app = createApp({ root: App,
|
|
91
|
+
const app = createApp({ root: App, state });
|
|
82
92
|
app.mount();
|
|
83
93
|
|
|
84
94
|
console.log(status.value);
|
|
85
95
|
```
|
|
86
96
|
|
|
87
|
-
|
|
97
|
+
`createApp` uses `#app` as its default mount target, so an application can call
|
|
98
|
+
`app.mount()` immediately after creation. If the target is not currently in the
|
|
99
|
+
document, `mount()` safely skips that attempt. Pass `rootElement` only when you
|
|
100
|
+
need to override the default target.
|
|
101
|
+
|
|
102
|
+
## Development Tooling
|
|
103
|
+
|
|
104
|
+
The separate `@geektech/tsone-cli` package provides `tsone dev` and
|
|
105
|
+
`tsone build`. Its default entry is `src/main.ts`; that module must expose the
|
|
106
|
+
application as `export const app`, and the value must provide
|
|
107
|
+
`renderHtmlDocument()`.
|
|
108
|
+
|
|
109
|
+
Create an optional `tsone.config.ts` at the project root:
|
|
110
|
+
|
|
111
|
+
The config file supports only a plain-object default export; functional or
|
|
112
|
+
function-valued config is not supported.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { defineConfig } from '@geektech/tsone-cli';
|
|
116
|
+
|
|
117
|
+
export default defineConfig({
|
|
118
|
+
server: {
|
|
119
|
+
proxy: {
|
|
120
|
+
'/api': {
|
|
121
|
+
target: 'http://localhost:3000',
|
|
122
|
+
changeOrigin: true,
|
|
123
|
+
rewrite: (path) => path.replace(/^\/api/, ''),
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
build: { outDir: 'dist' },
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The string proxy shorthand is also supported, for example
|
|
132
|
+
`{ '/backend': 'http://localhost:4000' }`. Defaults are `src/main.ts`,
|
|
133
|
+
`127.0.0.1`, port `52211`, an empty `server.proxy`, and `dist`.
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
tsone dev [--host <host>] [--port <port>]
|
|
137
|
+
tsone build [--out-dir <path>]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`dev` accepts host/port overrides and `build` accepts the output-directory
|
|
141
|
+
override; both `--port 3000` and `--port=3000` forms are valid. Build output
|
|
142
|
+
must remain a safe child directory inside the project root.
|
|
143
|
+
|
|
144
|
+
Programmatic tooling is imported from `@geektech/tsone-cli`, not from the
|
|
145
|
+
framework root. It exports `defineConfig`, `resolveConfig`, `startDevServer`,
|
|
146
|
+
and `build`. The dev server is owned by the caller, which must call
|
|
147
|
+
`server.stop()`; `build()` returns absolute `root` and `outDir` values plus
|
|
148
|
+
`assetsBuilt`.
|
|
149
|
+
|
|
150
|
+
The development server serves HTTP only. Proxy targets may use HTTP or HTTPS.
|
|
151
|
+
Rules use literal prefix matching with the longest match first, retain
|
|
152
|
+
query/body/end-to-end headers, optionally apply `changeOrigin` and `rewrite`,
|
|
153
|
+
and return `502 Bad Gateway` when the upstream is unreachable. CLI v1 has no
|
|
154
|
+
config plugins, WebSocket, HMR, SSR, functional config, `public/` copying, or
|
|
155
|
+
public minify/sourcemap settings.
|
|
156
|
+
|
|
157
|
+
## Routing
|
|
88
158
|
|
|
89
159
|
```typescript
|
|
90
160
|
import { Component, VNode, createApp } from '@geektech/tsone';
|
|
@@ -103,11 +173,11 @@ class Layout extends Component {
|
|
|
103
173
|
children: [
|
|
104
174
|
{
|
|
105
175
|
component: RouterLink,
|
|
106
|
-
props: { to: '/', children: ['
|
|
176
|
+
props: { to: '/', children: ['Home'] },
|
|
107
177
|
},
|
|
108
178
|
{
|
|
109
179
|
component: RouterLink,
|
|
110
|
-
props: { to: '/users/42', children: ['
|
|
180
|
+
props: { to: '/users/42', children: ['User'] },
|
|
111
181
|
},
|
|
112
182
|
{ component: RouterView },
|
|
113
183
|
],
|
|
@@ -119,14 +189,18 @@ const router = createRouter({
|
|
|
119
189
|
mode: 'history',
|
|
120
190
|
routes: [
|
|
121
191
|
{ path: '/', component: HomePage },
|
|
122
|
-
{
|
|
192
|
+
{
|
|
193
|
+
path: '/users/:id',
|
|
194
|
+
component: UserPage,
|
|
195
|
+
meta: { title: 'User Details' },
|
|
196
|
+
},
|
|
123
197
|
],
|
|
124
198
|
});
|
|
125
199
|
|
|
126
|
-
createApp({ root: Layout
|
|
200
|
+
createApp({ root: Layout }).use(router).mount();
|
|
127
201
|
```
|
|
128
202
|
|
|
129
|
-
##
|
|
203
|
+
## Development Commands
|
|
130
204
|
|
|
131
205
|
```bash
|
|
132
206
|
bun install
|
|
@@ -137,18 +211,47 @@ bun run docs
|
|
|
137
211
|
bun run docs:build
|
|
138
212
|
```
|
|
139
213
|
|
|
140
|
-
|
|
214
|
+
The root `playground/` directory contains two standalone projects:
|
|
141
215
|
|
|
142
|
-
|
|
216
|
+
```bash
|
|
217
|
+
bun run dev
|
|
218
|
+
bun run dev:site
|
|
219
|
+
bun run dev:admin
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
- `playground/official-site`: product website example
|
|
223
|
+
- `playground/admin-dashboard`: admin dashboard example
|
|
224
|
+
|
|
225
|
+
Documentation content is maintained in the typed-content registry. Chinese
|
|
226
|
+
content lives in `packages/tsone/docs/app/content/zh/`, while English content
|
|
227
|
+
lives in `packages/tsone/docs/app/content/en/`. Every logical route must exist
|
|
228
|
+
in both directories.
|
|
229
|
+
|
|
230
|
+
Chinese and English catalogs each contain exactly 14 logical routes. Add or
|
|
231
|
+
remove a route in both catalogs in the same change.
|
|
232
|
+
|
|
233
|
+
Content links stay locale-neutral: never write `/en/` manually. Chinese public
|
|
234
|
+
routes are unprefixed, while English routes use `/en/`. Browser-language
|
|
235
|
+
detection runs only at `/`; manual selection takes precedence and persists for
|
|
236
|
+
later visits.
|
|
237
|
+
|
|
238
|
+
Build the static documentation site with:
|
|
143
239
|
|
|
144
240
|
```bash
|
|
145
241
|
bun run docs:build
|
|
146
242
|
```
|
|
147
243
|
|
|
148
|
-
|
|
244
|
+
The build fails strictly for missing, extra, duplicate, empty, or
|
|
245
|
+
mixed-language pages.
|
|
246
|
+
|
|
247
|
+
The base HTML document shell can also be generated from `createApp`. It emits a
|
|
248
|
+
`#app` mount node by default; pass `rootElement` only to use a different target.
|
|
249
|
+
When a custom `body` is needed, pass a component or VNode rather than an HTML
|
|
250
|
+
string. This API renders the mount node through TSone's renderer. In a Bun or
|
|
251
|
+
Node static-generation environment, provide a DOM-like document first:
|
|
149
252
|
|
|
150
253
|
```typescript
|
|
151
|
-
import {
|
|
254
|
+
import { createApp, type StyleSheet } from '@geektech/tsone';
|
|
152
255
|
|
|
153
256
|
const styles: StyleSheet = [
|
|
154
257
|
{
|
|
@@ -157,38 +260,55 @@ const styles: StyleSheet = [
|
|
|
157
260
|
},
|
|
158
261
|
];
|
|
159
262
|
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
263
|
+
const app = createApp({
|
|
264
|
+
root: App,
|
|
265
|
+
document: {
|
|
266
|
+
lang: 'en',
|
|
267
|
+
title: 'TSone App',
|
|
268
|
+
styles,
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const html = app.renderHtmlDocument({
|
|
165
273
|
scripts: [{ type: 'module', src: '/assets/app.js' }],
|
|
166
274
|
});
|
|
167
275
|
```
|
|
168
276
|
|
|
169
|
-
##
|
|
277
|
+
## Public API
|
|
170
278
|
|
|
171
|
-
|
|
279
|
+
The main `@geektech/tsone` entry point exports:
|
|
172
280
|
|
|
173
281
|
- `createApp(options)`
|
|
282
|
+
- `createApp({ root, rootProps })`
|
|
174
283
|
- `Component<Props, State>`
|
|
284
|
+
- `TransitionGroup` / `TransitionGroupProps` / `TransitionAnimationType`
|
|
175
285
|
- `VNode`
|
|
176
286
|
- `h()` / `createComponent()` / `slot()` / `each()`
|
|
287
|
+
- `Tag(tag, options)` for arbitrary HTML elements
|
|
177
288
|
- `Div()` / `Span()` / `P()` / `Button()` / `Input()`
|
|
289
|
+
- `Section()` / `Main()` / `Header()` / `Footer()` / `Nav()` / `Article()` /
|
|
290
|
+
`Aside()`
|
|
291
|
+
- `H1()` through `H6()` / `Strong()` / `Em()` / `Small()` / `Pre()` /
|
|
292
|
+
`Code()` / `Blockquote()`
|
|
293
|
+
- `Ul()` / `Ol()` / `Li()` / `A()` / `Img()`
|
|
294
|
+
- `Form()` / `Label()` / `Textarea()` / `Select()` / `Option()`
|
|
295
|
+
- `Table()` / `Thead()` / `Tbody()` / `Tr()` / `Th()` / `Td()`
|
|
178
296
|
- `Directions` / `ModelBinding`
|
|
179
|
-
- `InjectionKey
|
|
297
|
+
- `InjectionKey` and component/application `provide()` / `inject()`
|
|
180
298
|
- `createForm()` / `required()` / `minLength()` / `validate()`
|
|
299
|
+
- `createApp(options).renderHtmlDocument(options)`
|
|
181
300
|
- `renderHtmlDocument(options)`
|
|
182
301
|
- `StyleSheet` / `renderStyleSheet(styles)`
|
|
183
302
|
- `reactive()` / `readonly()`
|
|
184
303
|
- `effect()` / `stop()`
|
|
185
304
|
- `computed()`
|
|
186
305
|
- `ref()` / `isRef()` / `unref()`
|
|
187
|
-
- `version
|
|
306
|
+
- `version`, currently `0.0.2`
|
|
188
307
|
|
|
189
|
-
##
|
|
308
|
+
## Rendering, Communication, and Forms
|
|
190
309
|
|
|
191
|
-
`directions.if`
|
|
310
|
+
`directions.if` controls whether an element, component, or slot is mounted. The
|
|
311
|
+
node is unmounted when the condition is false:
|
|
192
312
|
|
|
193
313
|
```typescript
|
|
194
314
|
{
|
|
@@ -197,7 +317,8 @@ const html = renderHtmlDocument({
|
|
|
197
317
|
}
|
|
198
318
|
```
|
|
199
319
|
|
|
200
|
-
`each()`
|
|
320
|
+
`each()` creates stable keys for list items so the renderer can reuse nodes
|
|
321
|
+
during reordering, insertion, and removal:
|
|
201
322
|
|
|
202
323
|
```typescript
|
|
203
324
|
const items = each(
|
|
@@ -207,7 +328,30 @@ const items = each(
|
|
|
207
328
|
);
|
|
208
329
|
```
|
|
209
330
|
|
|
210
|
-
|
|
331
|
+
`TransitionGroup` animates the enter and exit of direct keyed children:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
{
|
|
335
|
+
component: TransitionGroup,
|
|
336
|
+
props: { tag: 'ul', type: 'fade', duration: 300 },
|
|
337
|
+
children: each(
|
|
338
|
+
this.state.items,
|
|
339
|
+
(item) => Li({ children: [item.label] }),
|
|
340
|
+
(item) => item.id
|
|
341
|
+
),
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The animation types are `fade`, `slide-up`, `slide-down`, `slide-left`,
|
|
346
|
+
`slide-right`, and `scale`. The defaults are a `div` wrapper, `fade`, and
|
|
347
|
+
`300` ms with `ease` easing. Every direct child must have a unique key. Initial
|
|
348
|
+
children animate in, and removed children stay mounted until their exit ends.
|
|
349
|
+
TSone automatically disables these animations for
|
|
350
|
+
`prefers-reduced-motion: reduce` or when Web Animations is unavailable.
|
|
351
|
+
Reordering reuses and moves existing nodes without a reorder or FLIP animation.
|
|
352
|
+
|
|
353
|
+
Component events return an unsubscribe function, while component VNodes can
|
|
354
|
+
declare parent listeners through `emitters`:
|
|
211
355
|
|
|
212
356
|
```typescript
|
|
213
357
|
const stopListening = child.on('saved', (payload) => console.log(payload));
|
|
@@ -215,7 +359,8 @@ stopListening();
|
|
|
215
359
|
// { component: Editor, emitters: { saved: (payload) => this.save(payload) } }
|
|
216
360
|
```
|
|
217
361
|
|
|
218
|
-
|
|
362
|
+
Dependency injection resolves values from the current component, then its
|
|
363
|
+
parents, and finally the application instance:
|
|
219
364
|
|
|
220
365
|
```typescript
|
|
221
366
|
const THEME: InjectionKey<{ mode: string }> = Symbol('theme');
|
|
@@ -223,7 +368,8 @@ app.provide(THEME, { mode: 'dark' });
|
|
|
223
368
|
const theme = this.inject(THEME, { mode: 'light' });
|
|
224
369
|
```
|
|
225
370
|
|
|
226
|
-
`directions.model`
|
|
371
|
+
`directions.model` supports dot-separated paths and conversion functions.
|
|
372
|
+
Native input, textarea, checkbox, radio, and select controls stay synchronized:
|
|
227
373
|
|
|
228
374
|
```typescript
|
|
229
375
|
Input({
|
|
@@ -238,13 +384,13 @@ Input({
|
|
|
238
384
|
});
|
|
239
385
|
```
|
|
240
386
|
|
|
241
|
-
|
|
387
|
+
Validation uses pure functions and does not own error UI or submission:
|
|
242
388
|
|
|
243
389
|
```typescript
|
|
244
390
|
const form = createForm(this.state, {
|
|
245
|
-
'profile.name': [required('
|
|
391
|
+
'profile.name': [required('Name is required'), minLength(2)],
|
|
246
392
|
'profile.age': [
|
|
247
|
-
validate((value) => Number(value) >= 18 || '
|
|
393
|
+
validate((value) => Number(value) >= 18 || 'Age must be at least 18'),
|
|
248
394
|
],
|
|
249
395
|
});
|
|
250
396
|
|
|
@@ -252,7 +398,7 @@ const result = form.validate();
|
|
|
252
398
|
form.resetErrors();
|
|
253
399
|
```
|
|
254
400
|
|
|
255
|
-
|
|
401
|
+
The `@geektech/tsone/router` entry point exports:
|
|
256
402
|
|
|
257
403
|
- `createRouter({ routes, mode, base })`
|
|
258
404
|
- `Router`
|
|
@@ -262,12 +408,12 @@ form.resetErrors();
|
|
|
262
408
|
- `RouteRecord`
|
|
263
409
|
- `RouteLocation`
|
|
264
410
|
|
|
265
|
-
|
|
411
|
+
The `@geektech/tsone/style` entry point exports:
|
|
266
412
|
|
|
267
413
|
- `StyleManager`
|
|
268
414
|
- `StyleSheet` / `renderStyleSheet(styles)`
|
|
269
415
|
|
|
270
|
-
##
|
|
416
|
+
## Pre-Publish Checklist
|
|
271
417
|
|
|
272
418
|
```bash
|
|
273
419
|
bun test
|
|
@@ -276,10 +422,11 @@ bun run build
|
|
|
276
422
|
bun pm pack --cwd packages/tsone --dry-run
|
|
277
423
|
```
|
|
278
424
|
|
|
279
|
-
##
|
|
425
|
+
## Contributing
|
|
280
426
|
|
|
281
|
-
|
|
427
|
+
Issues and pull requests are welcome. Before publishing an open-source release,
|
|
428
|
+
make sure the tests, type checks, and build all pass.
|
|
282
429
|
|
|
283
|
-
##
|
|
430
|
+
## License
|
|
284
431
|
|
|
285
432
|
[MIT](LICENSE)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Component } from '../component';
|
|
2
|
+
import { type TransitionGroupNode, type TransitionGroupProps } from './types';
|
|
3
|
+
export declare class TransitionGroup extends Component<TransitionGroupProps> {
|
|
4
|
+
protected initState(): object;
|
|
5
|
+
protected initStyles(): void;
|
|
6
|
+
protected render(): TransitionGroupNode;
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TransitionGroupOptions } from './types';
|
|
2
|
+
export interface ListAnimationRun {
|
|
3
|
+
animation: Animation;
|
|
4
|
+
token: symbol;
|
|
5
|
+
keyframes: Keyframe[];
|
|
6
|
+
options: KeyframeAnimationOptions;
|
|
7
|
+
finished: Promise<'finished' | 'cancelled'>;
|
|
8
|
+
}
|
|
9
|
+
export declare class ListAnimationController {
|
|
10
|
+
private readonly runs;
|
|
11
|
+
playEnter(element: HTMLElement, options: TransitionGroupOptions): ListAnimationRun | null;
|
|
12
|
+
playExit(element: HTMLElement, options: TransitionGroupOptions): ListAnimationRun | null;
|
|
13
|
+
cancel(element: HTMLElement): void;
|
|
14
|
+
private play;
|
|
15
|
+
private canAnimate;
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ElementRenderStrategy } from '../renderer/element-strategy';
|
|
2
|
+
import type { RenderRuntimeContext, Renderable } from '../renderer/types';
|
|
3
|
+
import { type TransitionGroupNode } from './types';
|
|
4
|
+
export declare class TransitionGroupRenderStrategy extends ElementRenderStrategy<TransitionGroupNode> {
|
|
5
|
+
private readonly entries;
|
|
6
|
+
private readonly animations;
|
|
7
|
+
matches(vnode: Renderable): vnode is TransitionGroupNode;
|
|
8
|
+
protected mountChildren(element: HTMLElement, groupVNode: TransitionGroupNode, context: RenderRuntimeContext): void;
|
|
9
|
+
protected updateChildren(element: HTMLElement, _oldVNode: TransitionGroupNode, newVNode: TransitionGroupNode, context: RenderRuntimeContext): void;
|
|
10
|
+
protected unmountChildren(element: HTMLElement, vnode: TransitionGroupNode, context: RenderRuntimeContext): void;
|
|
11
|
+
private playEnter;
|
|
12
|
+
private startExit;
|
|
13
|
+
private finishExit;
|
|
14
|
+
private placeActiveEntries;
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type EventListeners, type HTMLNode, type HTMLProps, type VNode } from '../vnode';
|
|
2
|
+
export declare const TRANSITION_ANIMATION_TYPES: readonly ["fade", "slide-up", "slide-down", "slide-left", "slide-right", "scale"];
|
|
3
|
+
export type TransitionAnimationType = (typeof TRANSITION_ANIMATION_TYPES)[number];
|
|
4
|
+
export interface TransitionGroupOptions {
|
|
5
|
+
type: TransitionAnimationType;
|
|
6
|
+
duration: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TransitionGroupProps {
|
|
9
|
+
tag?: string;
|
|
10
|
+
type?: TransitionAnimationType;
|
|
11
|
+
duration?: number;
|
|
12
|
+
elementProps?: HTMLProps;
|
|
13
|
+
listeners?: EventListeners;
|
|
14
|
+
children?: VNode[];
|
|
15
|
+
}
|
|
16
|
+
export interface TransitionGroupNode extends HTMLNode {
|
|
17
|
+
transitionGroup: TransitionGroupOptions;
|
|
18
|
+
children?: VNode[];
|
|
19
|
+
}
|
|
20
|
+
export type KeyedTransitionChild = VNode & {
|
|
21
|
+
key: string | number;
|
|
22
|
+
};
|
|
23
|
+
export declare function normalizeTransitionGroupProps(props: TransitionGroupProps): Required<Pick<TransitionGroupProps, 'tag' | 'type' | 'duration'>>;
|
|
24
|
+
export declare function validateTransitionGroupChildren(children: Array<VNode | string>): KeyedTransitionChild[];
|
|
25
|
+
export declare function isTransitionGroupNode(vnode: unknown): vnode is TransitionGroupNode;
|
package/dist/core/app.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ComponentConstructor, InjectionKey, InjectionResult } from './component';
|
|
1
|
+
import { ComponentConstructor, ComponentProps, InjectionKey, InjectionResult } from './component';
|
|
2
|
+
import { type HtmlDocumentBody, type HtmlDocumentOptions } from './document';
|
|
2
3
|
import type { Router } from '../router';
|
|
3
4
|
export interface Plugin {
|
|
4
5
|
install: (app: OneApp, ...args: unknown[]) => void;
|
|
@@ -6,15 +7,23 @@ export interface Plugin {
|
|
|
6
7
|
onUpdated?: (app: OneApp) => void;
|
|
7
8
|
onBeforeUnmount?: (app: OneApp) => void;
|
|
8
9
|
}
|
|
9
|
-
export
|
|
10
|
+
export type AppDocumentOptions = Partial<Omit<HtmlDocumentOptions, 'body'>> & {
|
|
11
|
+
body?: HtmlDocumentBody;
|
|
12
|
+
};
|
|
13
|
+
export type AppDocumentRenderOptions = AppDocumentOptions;
|
|
14
|
+
export interface AppOptions<TState = Record<string, unknown>, TConfig = Record<string, unknown>, TRootProps extends ComponentProps = ComponentProps> {
|
|
10
15
|
/** 根组件构造函数 */
|
|
11
|
-
root?: ComponentConstructor
|
|
12
|
-
/**
|
|
16
|
+
root?: ComponentConstructor<TRootProps>;
|
|
17
|
+
/** 根组件 props */
|
|
18
|
+
rootProps?: TRootProps;
|
|
19
|
+
/** 应用挂载点,默认 #app */
|
|
13
20
|
rootElement?: string | Element;
|
|
14
21
|
/** 全局状态 */
|
|
15
22
|
state?: TState;
|
|
16
23
|
/** 全局配置 */
|
|
17
24
|
config?: TConfig;
|
|
25
|
+
/** HTML 文档壳配置,用于 dev/build 生成入口页面 */
|
|
26
|
+
document?: AppDocumentOptions;
|
|
18
27
|
}
|
|
19
28
|
export interface AppContext<TConfig = Record<string, unknown>> {
|
|
20
29
|
app: OneApp;
|
|
@@ -22,7 +31,7 @@ export interface AppContext<TConfig = Record<string, unknown>> {
|
|
|
22
31
|
config: TConfig;
|
|
23
32
|
router?: Router;
|
|
24
33
|
}
|
|
25
|
-
export declare class OneApp<TState extends object = Record<string, unknown>, TConfig extends object = Record<string, unknown
|
|
34
|
+
export declare class OneApp<TState extends object = Record<string, unknown>, TConfig extends object = Record<string, unknown>, TRootProps extends ComponentProps = ComponentProps> {
|
|
26
35
|
private options;
|
|
27
36
|
private container;
|
|
28
37
|
private rootInstance;
|
|
@@ -33,7 +42,7 @@ export declare class OneApp<TState extends object = Record<string, unknown>, TCo
|
|
|
33
42
|
private plugins;
|
|
34
43
|
private unmountedCallback?;
|
|
35
44
|
router?: Router;
|
|
36
|
-
constructor(options?: AppOptions<TState, TConfig>);
|
|
45
|
+
constructor(options?: AppOptions<TState, TConfig, TRootProps>);
|
|
37
46
|
private handleError;
|
|
38
47
|
/**
|
|
39
48
|
* 渲染错误UI
|
|
@@ -58,7 +67,7 @@ export declare class OneApp<TState extends object = Record<string, unknown>, TCo
|
|
|
58
67
|
/**
|
|
59
68
|
* 更新根组件
|
|
60
69
|
*/
|
|
61
|
-
updateRootComponent(component: ComponentConstructor): void;
|
|
70
|
+
updateRootComponent(component: ComponentConstructor<TRootProps>): void;
|
|
62
71
|
/**
|
|
63
72
|
* 更新应用状态
|
|
64
73
|
*/
|
|
@@ -83,10 +92,18 @@ export declare class OneApp<TState extends object = Record<string, unknown>, TCo
|
|
|
83
92
|
* 监听应用卸载
|
|
84
93
|
*/
|
|
85
94
|
onUnmounted(callback: () => void): this;
|
|
95
|
+
/**
|
|
96
|
+
* 生成应用入口 HTML 文档
|
|
97
|
+
*/
|
|
98
|
+
renderHtmlDocument(options?: AppDocumentRenderOptions): string;
|
|
86
99
|
/**
|
|
87
100
|
* 解析根元素
|
|
88
101
|
*/
|
|
89
102
|
private resolveRootElement;
|
|
103
|
+
private resolveMountContainer;
|
|
104
|
+
private createMountDocumentBody;
|
|
105
|
+
private createMountElementFromSelector;
|
|
106
|
+
private mergeDocumentScripts;
|
|
90
107
|
private onMounted;
|
|
91
108
|
private onUpdated;
|
|
92
109
|
private onBeforeUnmount;
|
|
@@ -94,4 +111,4 @@ export declare class OneApp<TState extends object = Record<string, unknown>, TCo
|
|
|
94
111
|
/**
|
|
95
112
|
* 创建应用实例
|
|
96
113
|
*/
|
|
97
|
-
export declare function createApp<TState extends object = Record<string, unknown>, TConfig extends object = Record<string, unknown
|
|
114
|
+
export declare function createApp<TState extends object = Record<string, unknown>, TConfig extends object = Record<string, unknown>, TRootProps extends ComponentProps = ComponentProps>(options?: AppOptions<TState, TConfig, TRootProps>): OneApp<TState, TConfig, TRootProps>;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HTMLNode } from '../vnode';
|
|
2
|
+
import type { RenderRuntimeContext, RenderStrategy, Renderable } from './types';
|
|
3
|
+
export declare class ElementRenderStrategy<TNode extends HTMLNode = HTMLNode> implements RenderStrategy<TNode> {
|
|
4
|
+
private readonly listeners;
|
|
5
|
+
private readonly effects;
|
|
6
|
+
private readonly modelBindings;
|
|
7
|
+
matches(vnode: Renderable): vnode is TNode;
|
|
8
|
+
mount(vnode: TNode, context: RenderRuntimeContext): Node;
|
|
9
|
+
patch(oldVNode: TNode, newVNode: TNode, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
10
|
+
unmount(vnode: TNode, currentNode: Node, context: RenderRuntimeContext): void;
|
|
11
|
+
protected mountChildren(element: HTMLElement, vnode: TNode, context: RenderRuntimeContext): void;
|
|
12
|
+
protected updateChildren(element: HTMLElement, oldVNode: TNode, newVNode: TNode, context: RenderRuntimeContext): void;
|
|
13
|
+
protected unmountChildren(element: HTMLElement, vnode: TNode, context: RenderRuntimeContext): void;
|
|
14
|
+
private applyProps;
|
|
15
|
+
private applyDirections;
|
|
16
|
+
private updateOrdinaryChildren;
|
|
17
|
+
private updateKeyedChildren;
|
|
18
|
+
private hasOnlyKeyedChildren;
|
|
19
|
+
private assertNoDuplicateKeys;
|
|
20
|
+
private getVNodeKey;
|
|
21
|
+
private collectListeners;
|
|
22
|
+
private updateListeners;
|
|
23
|
+
private setupReactiveAttribute;
|
|
24
|
+
private trackEffect;
|
|
25
|
+
}
|
package/dist/core/renderer.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ComponentNode,
|
|
1
|
+
import { ComponentNode, SlotProvider } from './vnode';
|
|
2
|
+
export { ElementRenderStrategy } from './renderer/element-strategy';
|
|
2
3
|
export type { ComponentInstance, RenderRuntimeContext, RenderStrategy, Renderable, RendererHost, } from './renderer/types';
|
|
3
4
|
import type { RenderRuntimeContext, RenderStrategy, Renderable } from './renderer/types';
|
|
4
5
|
export declare class RendererContext {
|
|
@@ -40,23 +41,3 @@ export declare class SlotRenderStrategy implements RenderStrategy<SlotProvider>
|
|
|
40
41
|
private mountSlotChildren;
|
|
41
42
|
private unmountSlotChildren;
|
|
42
43
|
}
|
|
43
|
-
export declare class ElementRenderStrategy implements RenderStrategy<HTMLNode> {
|
|
44
|
-
private readonly listeners;
|
|
45
|
-
private readonly effects;
|
|
46
|
-
private readonly modelBindings;
|
|
47
|
-
matches(vnode: Renderable): vnode is HTMLNode;
|
|
48
|
-
mount(vnode: HTMLNode, context: RenderRuntimeContext): Node;
|
|
49
|
-
patch(oldVNode: HTMLNode, newVNode: HTMLNode, currentNode: Node, context: RenderRuntimeContext): Node;
|
|
50
|
-
unmount(vnode: HTMLNode, currentNode: Node, context: RenderRuntimeContext): void;
|
|
51
|
-
private applyProps;
|
|
52
|
-
private applyDirections;
|
|
53
|
-
private updateChildren;
|
|
54
|
-
private updateKeyedChildren;
|
|
55
|
-
private hasOnlyKeyedChildren;
|
|
56
|
-
private assertNoDuplicateKeys;
|
|
57
|
-
private getVNodeKey;
|
|
58
|
-
private collectListeners;
|
|
59
|
-
private updateListeners;
|
|
60
|
-
private setupReactiveAttribute;
|
|
61
|
-
private trackEffect;
|
|
62
|
-
}
|
package/dist/core/vnode.d.ts
CHANGED
|
@@ -57,11 +57,47 @@ export declare function isComponentNode(vnode: VNode): vnode is ComponentNode;
|
|
|
57
57
|
export declare function isHTMLNode(vnode: VNode): vnode is HTMLNode;
|
|
58
58
|
export declare function isSlotProvider(vnode: VNode): vnode is SlotProvider;
|
|
59
59
|
export declare function h(tag: string, props?: HTMLProps, children?: Array<VNode | string>, listeners?: EventListeners, key?: string | number, directions?: Directions): HTMLNode;
|
|
60
|
+
export declare function Tag(tag: string, options?: ElementShortcutOptions): HTMLNode;
|
|
60
61
|
export declare const Div: ElementShortcut;
|
|
61
62
|
export declare const Span: ElementShortcut;
|
|
62
63
|
export declare const P: ElementShortcut;
|
|
63
64
|
export declare const Button: ElementShortcut;
|
|
64
65
|
export declare const Input: ElementShortcut;
|
|
66
|
+
export declare const Section: ElementShortcut;
|
|
67
|
+
export declare const Main: ElementShortcut;
|
|
68
|
+
export declare const Header: ElementShortcut;
|
|
69
|
+
export declare const Footer: ElementShortcut;
|
|
70
|
+
export declare const Nav: ElementShortcut;
|
|
71
|
+
export declare const Article: ElementShortcut;
|
|
72
|
+
export declare const Aside: ElementShortcut;
|
|
73
|
+
export declare const H1: ElementShortcut;
|
|
74
|
+
export declare const H2: ElementShortcut;
|
|
75
|
+
export declare const H3: ElementShortcut;
|
|
76
|
+
export declare const H4: ElementShortcut;
|
|
77
|
+
export declare const H5: ElementShortcut;
|
|
78
|
+
export declare const H6: ElementShortcut;
|
|
79
|
+
export declare const Strong: ElementShortcut;
|
|
80
|
+
export declare const Em: ElementShortcut;
|
|
81
|
+
export declare const Small: ElementShortcut;
|
|
82
|
+
export declare const Pre: ElementShortcut;
|
|
83
|
+
export declare const Code: ElementShortcut;
|
|
84
|
+
export declare const Blockquote: ElementShortcut;
|
|
85
|
+
export declare const Ul: ElementShortcut;
|
|
86
|
+
export declare const Ol: ElementShortcut;
|
|
87
|
+
export declare const Li: ElementShortcut;
|
|
88
|
+
export declare const A: ElementShortcut;
|
|
89
|
+
export declare const Img: ElementShortcut;
|
|
90
|
+
export declare const Form: ElementShortcut;
|
|
91
|
+
export declare const Label: ElementShortcut;
|
|
92
|
+
export declare const Textarea: ElementShortcut;
|
|
93
|
+
export declare const Select: ElementShortcut;
|
|
94
|
+
export declare const Option: ElementShortcut;
|
|
95
|
+
export declare const Table: ElementShortcut;
|
|
96
|
+
export declare const Thead: ElementShortcut;
|
|
97
|
+
export declare const Tbody: ElementShortcut;
|
|
98
|
+
export declare const Tr: ElementShortcut;
|
|
99
|
+
export declare const Th: ElementShortcut;
|
|
100
|
+
export declare const Td: ElementShortcut;
|
|
65
101
|
export declare function createComponent<P extends VNodeComponentProps>(componentClass: ComponentConstructor<P>, props?: P, children?: Array<VNode | string>, key?: string | number, directions?: Directions): ComponentNode<P>;
|
|
66
102
|
export declare function slot(name: string, key?: string | number, directions?: Directions): SlotProvider;
|
|
67
103
|
export declare function each<T>(items: readonly T[], render: (item: T, index: number) => VNode | string, key: (item: T, index: number) => string | number): VNode[];
|