@geektech/tsone 0.0.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh.md +424 -0
- package/README.md +222 -53
- 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/dom/index.d.ts +534 -0
- package/dist/dom/index.js +2181 -0
- package/dist/dom/index.js.map +10 -0
- package/dist/{index-ycmc7ga1.js → index-1x4ectvr.js} +1031 -396
- package/dist/index-1x4ectvr.js.map +27 -0
- package/dist/{index-8wjswsye.js → index-ffzday7h.js} +31 -3
- package/dist/{index-8wjswsye.js.map → index-ffzday7h.js.map} +5 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.js +151 -337
- package/dist/index.js.map +5 -6
- package/dist/router/index.js +7 -7
- package/dist/router/index.js.map +1 -1
- package/dist/style/index.js +5 -7
- package/dist/style/index.js.map +1 -1
- package/package.json +11 -2
- package/dist/index-vpx80nq5.js +0 -32
- package/dist/index-vpx80nq5.js.map +0 -10
- 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 {
|
|
@@ -48,7 +58,7 @@ class App extends Component<Record<string, never>, AppState> {
|
|
|
48
58
|
protected initState(): AppState {
|
|
49
59
|
return {
|
|
50
60
|
count: 0,
|
|
51
|
-
version: '0.
|
|
61
|
+
version: '0.2.1',
|
|
52
62
|
};
|
|
53
63
|
}
|
|
54
64
|
|
|
@@ -78,13 +88,95 @@ 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`, `dist`, and no additional
|
|
134
|
+
pages.
|
|
135
|
+
|
|
136
|
+
Multi-page applications map routes to page entries in the same config file;
|
|
137
|
+
each page entry exposes `app` with `renderHtmlDocument()` exactly like the root
|
|
138
|
+
entry:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
export default defineConfig({
|
|
142
|
+
entry: 'src/main.ts',
|
|
143
|
+
pages: {
|
|
144
|
+
'/about': 'src/about.ts',
|
|
145
|
+
'/docs/guide': 'src/guide.ts',
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`pages` keys must start with `/` and may nest; the root `/` is served by
|
|
151
|
+
`entry`. During development each page is served at its route, and `tsone build`
|
|
152
|
+
emits one HTML document per page (`index.html`, `about.html`,
|
|
153
|
+
`docs/guide.html`) with page-relative asset URLs.
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
tsone dev [--host <host>] [--port <port>] [--no-watch]
|
|
157
|
+
tsone build [--out-dir <path>]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`dev` accepts host/port overrides and `--no-watch`; `build` accepts the
|
|
161
|
+
output-directory override; both `--port 3000` and `--port=3000` forms are
|
|
162
|
+
valid. `tsone dev` watches the project by default and notifies browsers to
|
|
163
|
+
reload over `/__tsone/reload` when a watched file changes. Build output must
|
|
164
|
+
remain a safe child directory inside the project root.
|
|
165
|
+
|
|
166
|
+
Programmatic tooling is imported from `@geektech/tsone-cli`, not from the
|
|
167
|
+
framework root. It exports `defineConfig`, `resolveConfig`, `startDevServer`,
|
|
168
|
+
and `build`. The dev server is owned by the caller, which must call
|
|
169
|
+
`server.stop()`; `build()` returns absolute `root` and `outDir` values plus
|
|
170
|
+
`assetsBuilt`.
|
|
171
|
+
|
|
172
|
+
The development server serves HTTP only. Proxy targets may use HTTP or HTTPS.
|
|
173
|
+
Rules use literal prefix matching with the longest match first, retain
|
|
174
|
+
query/body/end-to-end headers, optionally apply `changeOrigin` and `rewrite`,
|
|
175
|
+
and return `502 Bad Gateway` when the upstream is unreachable. CLI v1 has no
|
|
176
|
+
config plugins, WebSocket, HMR, SSR, functional config, `public/` copying, or
|
|
177
|
+
public minify/sourcemap settings.
|
|
178
|
+
|
|
179
|
+
## Routing
|
|
88
180
|
|
|
89
181
|
```typescript
|
|
90
182
|
import { Component, VNode, createApp } from '@geektech/tsone';
|
|
@@ -103,11 +195,11 @@ class Layout extends Component {
|
|
|
103
195
|
children: [
|
|
104
196
|
{
|
|
105
197
|
component: RouterLink,
|
|
106
|
-
props: { to: '/', children: ['
|
|
198
|
+
props: { to: '/', children: ['Home'] },
|
|
107
199
|
},
|
|
108
200
|
{
|
|
109
201
|
component: RouterLink,
|
|
110
|
-
props: { to: '/users/42', children: ['
|
|
202
|
+
props: { to: '/users/42', children: ['User'] },
|
|
111
203
|
},
|
|
112
204
|
{ component: RouterView },
|
|
113
205
|
],
|
|
@@ -119,14 +211,18 @@ const router = createRouter({
|
|
|
119
211
|
mode: 'history',
|
|
120
212
|
routes: [
|
|
121
213
|
{ path: '/', component: HomePage },
|
|
122
|
-
{
|
|
214
|
+
{
|
|
215
|
+
path: '/users/:id',
|
|
216
|
+
component: UserPage,
|
|
217
|
+
meta: { title: 'User Details' },
|
|
218
|
+
},
|
|
123
219
|
],
|
|
124
220
|
});
|
|
125
221
|
|
|
126
|
-
createApp({ root: Layout
|
|
222
|
+
createApp({ root: Layout }).use(router).mount();
|
|
127
223
|
```
|
|
128
224
|
|
|
129
|
-
##
|
|
225
|
+
## Development Commands
|
|
130
226
|
|
|
131
227
|
```bash
|
|
132
228
|
bun install
|
|
@@ -137,18 +233,47 @@ bun run docs
|
|
|
137
233
|
bun run docs:build
|
|
138
234
|
```
|
|
139
235
|
|
|
140
|
-
|
|
236
|
+
The root `playground/` directory contains two standalone projects:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
bun run dev
|
|
240
|
+
bun run dev:site
|
|
241
|
+
bun run dev:admin
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
- `playground/official-site`: product website example
|
|
245
|
+
- `playground/admin-dashboard`: admin dashboard example
|
|
246
|
+
|
|
247
|
+
Documentation content is maintained in the typed-content registry. Chinese
|
|
248
|
+
content lives in `packages/tsone/docs/app/content/zh/`, while English content
|
|
249
|
+
lives in `packages/tsone/docs/app/content/en/`. Every logical route must exist
|
|
250
|
+
in both directories.
|
|
251
|
+
|
|
252
|
+
Chinese and English catalogs each contain exactly 14 logical routes. Add or
|
|
253
|
+
remove a route in both catalogs in the same change.
|
|
254
|
+
|
|
255
|
+
Content links stay locale-neutral: never write `/en/` manually. Chinese public
|
|
256
|
+
routes are unprefixed, while English routes use `/en/`. Browser-language
|
|
257
|
+
detection runs only at `/`; manual selection takes precedence and persists for
|
|
258
|
+
later visits.
|
|
141
259
|
|
|
142
|
-
|
|
260
|
+
Build the static documentation site with:
|
|
143
261
|
|
|
144
262
|
```bash
|
|
145
263
|
bun run docs:build
|
|
146
264
|
```
|
|
147
265
|
|
|
148
|
-
|
|
266
|
+
The build fails strictly for missing, extra, duplicate, empty, or
|
|
267
|
+
mixed-language pages.
|
|
268
|
+
|
|
269
|
+
The base HTML document shell can also be generated from `createApp`. It emits a
|
|
270
|
+
`#app` mount node by default; pass `rootElement` only to use a different target.
|
|
271
|
+
When a custom `body` is needed, pass a component or VNode rather than an HTML
|
|
272
|
+
string. This API renders the mount node through TSone's renderer. In a Bun or
|
|
273
|
+
Node static-generation environment, provide a DOM-like document first:
|
|
149
274
|
|
|
150
275
|
```typescript
|
|
151
|
-
import {
|
|
276
|
+
import { createApp, type StyleSheet } from '@geektech/tsone';
|
|
152
277
|
|
|
153
278
|
const styles: StyleSheet = [
|
|
154
279
|
{
|
|
@@ -157,38 +282,55 @@ const styles: StyleSheet = [
|
|
|
157
282
|
},
|
|
158
283
|
];
|
|
159
284
|
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
285
|
+
const app = createApp({
|
|
286
|
+
root: App,
|
|
287
|
+
document: {
|
|
288
|
+
lang: 'en',
|
|
289
|
+
title: 'TSone App',
|
|
290
|
+
styles,
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const html = app.renderHtmlDocument({
|
|
165
295
|
scripts: [{ type: 'module', src: '/assets/app.js' }],
|
|
166
296
|
});
|
|
167
297
|
```
|
|
168
298
|
|
|
169
|
-
##
|
|
299
|
+
## Public API
|
|
170
300
|
|
|
171
|
-
|
|
301
|
+
The main `@geektech/tsone` entry point exports:
|
|
172
302
|
|
|
173
303
|
- `createApp(options)`
|
|
304
|
+
- `createApp({ root, rootProps })`
|
|
174
305
|
- `Component<Props, State>`
|
|
306
|
+
- `TransitionGroup` / `TransitionGroupProps` / `TransitionAnimationType`
|
|
175
307
|
- `VNode`
|
|
176
308
|
- `h()` / `createComponent()` / `slot()` / `each()`
|
|
309
|
+
- `Tag(tag, options)` for arbitrary HTML elements
|
|
177
310
|
- `Div()` / `Span()` / `P()` / `Button()` / `Input()`
|
|
311
|
+
- `Section()` / `Main()` / `Header()` / `Footer()` / `Nav()` / `Article()` /
|
|
312
|
+
`Aside()`
|
|
313
|
+
- `H1()` through `H6()` / `Strong()` / `Em()` / `Small()` / `Pre()` /
|
|
314
|
+
`Code()` / `Blockquote()`
|
|
315
|
+
- `Ul()` / `Ol()` / `Li()` / `A()` / `Img()`
|
|
316
|
+
- `Form()` / `Label()` / `Textarea()` / `Select()` / `Option()`
|
|
317
|
+
- `Table()` / `Thead()` / `Tbody()` / `Tr()` / `Th()` / `Td()`
|
|
178
318
|
- `Directions` / `ModelBinding`
|
|
179
|
-
- `InjectionKey
|
|
319
|
+
- `InjectionKey` and component/application `provide()` / `inject()`
|
|
180
320
|
- `createForm()` / `required()` / `minLength()` / `validate()`
|
|
321
|
+
- `createApp(options).renderHtmlDocument(options)`
|
|
181
322
|
- `renderHtmlDocument(options)`
|
|
182
323
|
- `StyleSheet` / `renderStyleSheet(styles)`
|
|
183
324
|
- `reactive()` / `readonly()`
|
|
184
325
|
- `effect()` / `stop()`
|
|
185
326
|
- `computed()`
|
|
186
327
|
- `ref()` / `isRef()` / `unref()`
|
|
187
|
-
- `version
|
|
328
|
+
- `version`, currently `0.2.1`
|
|
188
329
|
|
|
189
|
-
##
|
|
330
|
+
## Rendering, Communication, and Forms
|
|
190
331
|
|
|
191
|
-
`directions.if`
|
|
332
|
+
`directions.if` controls whether an element, component, or slot is mounted. The
|
|
333
|
+
node is unmounted when the condition is false:
|
|
192
334
|
|
|
193
335
|
```typescript
|
|
194
336
|
{
|
|
@@ -197,7 +339,8 @@ const html = renderHtmlDocument({
|
|
|
197
339
|
}
|
|
198
340
|
```
|
|
199
341
|
|
|
200
|
-
`each()`
|
|
342
|
+
`each()` creates stable keys for list items so the renderer can reuse nodes
|
|
343
|
+
during reordering, insertion, and removal:
|
|
201
344
|
|
|
202
345
|
```typescript
|
|
203
346
|
const items = each(
|
|
@@ -207,7 +350,30 @@ const items = each(
|
|
|
207
350
|
);
|
|
208
351
|
```
|
|
209
352
|
|
|
210
|
-
|
|
353
|
+
`TransitionGroup` animates the enter and exit of direct keyed children:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
{
|
|
357
|
+
component: TransitionGroup,
|
|
358
|
+
props: { tag: 'ul', type: 'fade', duration: 300 },
|
|
359
|
+
children: each(
|
|
360
|
+
this.state.items,
|
|
361
|
+
(item) => Li({ children: [item.label] }),
|
|
362
|
+
(item) => item.id
|
|
363
|
+
),
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
The animation types are `fade`, `slide-up`, `slide-down`, `slide-left`,
|
|
368
|
+
`slide-right`, and `scale`. The defaults are a `div` wrapper, `fade`, and
|
|
369
|
+
`300` ms with `ease` easing. Every direct child must have a unique key. Initial
|
|
370
|
+
children animate in, and removed children stay mounted until their exit ends.
|
|
371
|
+
TSone automatically disables these animations for
|
|
372
|
+
`prefers-reduced-motion: reduce` or when Web Animations is unavailable.
|
|
373
|
+
Reordering reuses and moves existing nodes without a reorder or FLIP animation.
|
|
374
|
+
|
|
375
|
+
Component events return an unsubscribe function, while component VNodes can
|
|
376
|
+
declare parent listeners through `emitters`:
|
|
211
377
|
|
|
212
378
|
```typescript
|
|
213
379
|
const stopListening = child.on('saved', (payload) => console.log(payload));
|
|
@@ -215,7 +381,8 @@ stopListening();
|
|
|
215
381
|
// { component: Editor, emitters: { saved: (payload) => this.save(payload) } }
|
|
216
382
|
```
|
|
217
383
|
|
|
218
|
-
|
|
384
|
+
Dependency injection resolves values from the current component, then its
|
|
385
|
+
parents, and finally the application instance:
|
|
219
386
|
|
|
220
387
|
```typescript
|
|
221
388
|
const THEME: InjectionKey<{ mode: string }> = Symbol('theme');
|
|
@@ -223,7 +390,8 @@ app.provide(THEME, { mode: 'dark' });
|
|
|
223
390
|
const theme = this.inject(THEME, { mode: 'light' });
|
|
224
391
|
```
|
|
225
392
|
|
|
226
|
-
`directions.model`
|
|
393
|
+
`directions.model` supports dot-separated paths and conversion functions.
|
|
394
|
+
Native input, textarea, checkbox, radio, and select controls stay synchronized:
|
|
227
395
|
|
|
228
396
|
```typescript
|
|
229
397
|
Input({
|
|
@@ -238,13 +406,13 @@ Input({
|
|
|
238
406
|
});
|
|
239
407
|
```
|
|
240
408
|
|
|
241
|
-
|
|
409
|
+
Validation uses pure functions and does not own error UI or submission:
|
|
242
410
|
|
|
243
411
|
```typescript
|
|
244
412
|
const form = createForm(this.state, {
|
|
245
|
-
'profile.name': [required('
|
|
413
|
+
'profile.name': [required('Name is required'), minLength(2)],
|
|
246
414
|
'profile.age': [
|
|
247
|
-
validate((value) => Number(value) >= 18 || '
|
|
415
|
+
validate((value) => Number(value) >= 18 || 'Age must be at least 18'),
|
|
248
416
|
],
|
|
249
417
|
});
|
|
250
418
|
|
|
@@ -252,7 +420,7 @@ const result = form.validate();
|
|
|
252
420
|
form.resetErrors();
|
|
253
421
|
```
|
|
254
422
|
|
|
255
|
-
|
|
423
|
+
The `@geektech/tsone/router` entry point exports:
|
|
256
424
|
|
|
257
425
|
- `createRouter({ routes, mode, base })`
|
|
258
426
|
- `Router`
|
|
@@ -262,12 +430,12 @@ form.resetErrors();
|
|
|
262
430
|
- `RouteRecord`
|
|
263
431
|
- `RouteLocation`
|
|
264
432
|
|
|
265
|
-
|
|
433
|
+
The `@geektech/tsone/style` entry point exports:
|
|
266
434
|
|
|
267
435
|
- `StyleManager`
|
|
268
436
|
- `StyleSheet` / `renderStyleSheet(styles)`
|
|
269
437
|
|
|
270
|
-
##
|
|
438
|
+
## Pre-Publish Checklist
|
|
271
439
|
|
|
272
440
|
```bash
|
|
273
441
|
bun test
|
|
@@ -276,10 +444,11 @@ bun run build
|
|
|
276
444
|
bun pm pack --cwd packages/tsone --dry-run
|
|
277
445
|
```
|
|
278
446
|
|
|
279
|
-
##
|
|
447
|
+
## Contributing
|
|
280
448
|
|
|
281
|
-
|
|
449
|
+
Issues and pull requests are welcome. Before publishing an open-source release,
|
|
450
|
+
make sure the tests, type checks, and build all pass.
|
|
282
451
|
|
|
283
|
-
##
|
|
452
|
+
## License
|
|
284
453
|
|
|
285
454
|
[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
|
-
}
|