airx 0.4.0 → 0.7.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.md +247 -63
- package/output/app/app.d.ts +41 -0
- package/output/app/app.d.ts.map +1 -0
- package/output/app/app.js +51 -0
- package/output/app/app.js.map +1 -0
- package/output/app/index.d.ts +2 -0
- package/output/app/index.d.ts.map +1 -0
- package/output/app/index.js +2 -0
- package/output/app/index.js.map +1 -0
- package/output/element/element.d.ts +108 -0
- package/output/element/element.d.ts.map +1 -0
- package/output/element/element.js +106 -0
- package/output/element/element.js.map +1 -0
- package/output/element/index.d.ts +2 -0
- package/output/element/index.d.ts.map +1 -0
- package/output/element/index.js +2 -0
- package/output/element/index.js.map +1 -0
- package/output/index.d.ts +40 -0
- package/output/index.d.ts.map +1 -0
- package/output/index.js +36 -0
- package/output/index.js.map +1 -0
- package/output/jsx-dev-runtime.d.ts +4 -0
- package/output/jsx-dev-runtime.d.ts.map +1 -0
- package/output/jsx-dev-runtime.js +9 -0
- package/output/jsx-dev-runtime.js.map +1 -0
- package/output/jsx-runtime.d.ts +23 -0
- package/output/jsx-runtime.d.ts.map +1 -0
- package/output/jsx-runtime.js +24 -0
- package/output/jsx-runtime.js.map +1 -0
- package/output/logger/index.d.ts +2 -0
- package/output/logger/index.d.ts.map +1 -0
- package/output/logger/index.js +2 -0
- package/output/logger/index.js.map +1 -0
- package/output/{esm → logger}/logger.d.ts +1 -0
- package/output/logger/logger.d.ts.map +1 -0
- package/output/logger/logger.js +17 -0
- package/output/logger/logger.js.map +1 -0
- package/output/{esm/render/common/index.d.ts → render/basic/common.d.ts} +4 -3
- package/output/render/basic/common.d.ts.map +1 -0
- package/output/render/basic/common.js +436 -0
- package/output/render/basic/common.js.map +1 -0
- package/output/render/basic/hooks/hooks.d.ts +61 -0
- package/output/render/basic/hooks/hooks.d.ts.map +1 -0
- package/output/render/basic/hooks/hooks.js +72 -0
- package/output/render/basic/hooks/hooks.js.map +1 -0
- package/output/render/basic/hooks/index.d.ts +2 -0
- package/output/render/basic/hooks/index.d.ts.map +1 -0
- package/output/render/basic/hooks/index.js +2 -0
- package/output/render/basic/hooks/index.js.map +1 -0
- package/output/render/basic/index.d.ts +2 -0
- package/output/render/basic/index.d.ts.map +1 -0
- package/output/render/basic/index.js +2 -0
- package/output/render/basic/index.js.map +1 -0
- package/output/{umd/render/common/plugins → render/basic/plugins/context}/context.d.ts +2 -1
- package/output/render/basic/plugins/context/context.d.ts.map +1 -0
- package/output/render/basic/plugins/context/context.js +12 -0
- package/output/render/basic/plugins/context/context.js.map +1 -0
- package/output/render/basic/plugins/context/index.d.ts +2 -0
- package/output/render/basic/plugins/context/index.d.ts.map +1 -0
- package/output/render/basic/plugins/context/index.js +2 -0
- package/output/render/basic/plugins/context/index.js.map +1 -0
- package/output/render/basic/plugins/index.d.ts +3 -0
- package/output/render/basic/plugins/index.d.ts.map +1 -0
- package/output/render/basic/plugins/index.js +2 -0
- package/output/render/basic/plugins/index.js.map +1 -0
- package/output/{umd/render/common/plugins/internal → render/basic/plugins/internal/basic}/basic.d.ts +4 -3
- package/output/render/basic/plugins/internal/basic/basic.d.ts.map +1 -0
- package/output/render/basic/plugins/internal/basic/basic.js +158 -0
- package/output/render/basic/plugins/internal/basic/basic.js.map +1 -0
- package/output/render/basic/plugins/internal/basic/index.d.ts +2 -0
- package/output/render/basic/plugins/internal/basic/index.d.ts.map +1 -0
- package/output/render/basic/plugins/internal/basic/index.js +2 -0
- package/output/render/basic/plugins/internal/basic/index.js.map +1 -0
- package/output/render/basic/plugins/internal/inject/index.d.ts +2 -0
- package/output/render/basic/plugins/internal/inject/index.d.ts.map +1 -0
- package/output/render/basic/plugins/internal/inject/index.js +2 -0
- package/output/render/basic/plugins/internal/inject/index.js.map +1 -0
- package/output/{umd/render/common/plugins/internal → render/basic/plugins/internal/inject}/inject.d.ts +3 -2
- package/output/render/basic/plugins/internal/inject/inject.d.ts.map +1 -0
- package/output/render/basic/plugins/internal/inject/inject.js +25 -0
- package/output/render/basic/plugins/internal/inject/inject.js.map +1 -0
- package/output/{umd/render/common/plugins/index.d.ts → render/basic/plugins/plugin.d.ts} +3 -3
- package/output/render/basic/plugins/plugin.d.ts.map +1 -0
- package/output/render/basic/plugins/plugin.js +2 -0
- package/output/render/basic/plugins/plugin.js.map +1 -0
- package/output/{esm/render → render/browser}/browser.d.ts +4 -3
- package/output/render/browser/browser.d.ts.map +1 -0
- package/output/render/browser/browser.js +218 -0
- package/output/render/browser/browser.js.map +1 -0
- package/output/render/browser/index.d.ts +2 -0
- package/output/render/browser/index.d.ts.map +1 -0
- package/output/render/browser/index.js +2 -0
- package/output/render/browser/index.js.map +1 -0
- package/output/render/index.d.ts +5 -0
- package/output/render/index.d.ts.map +1 -0
- package/output/render/index.js +5 -0
- package/output/render/index.js.map +1 -0
- package/output/render/server/index.d.ts +2 -0
- package/output/render/server/index.d.ts.map +1 -0
- package/output/render/server/index.js +2 -0
- package/output/render/server/index.js.map +1 -0
- package/output/{umd/render → render/server}/server.d.ts +3 -2
- package/output/render/server/server.d.ts.map +1 -0
- package/output/render/server/server.js +314 -0
- package/output/render/server/server.js.map +1 -0
- package/output/signal/index.d.ts +4 -0
- package/output/signal/index.d.ts.map +1 -0
- package/output/signal/index.js +2 -0
- package/output/signal/index.js.map +1 -0
- package/output/{esm/signal/index.d.ts → signal/signal.d.ts} +1 -1
- package/output/signal/signal.d.ts.map +1 -0
- package/output/signal/signal.js +46 -0
- package/output/signal/signal.js.map +1 -0
- package/output/symbol/index.d.ts +2 -0
- package/output/symbol/index.d.ts.map +1 -0
- package/output/symbol/index.js +2 -0
- package/output/symbol/index.js.map +1 -0
- package/output/types/index.d.ts +2 -0
- package/output/types/index.d.ts.map +1 -0
- package/output/types/index.js +2 -0
- package/output/types/index.js.map +1 -0
- package/output/{esm → types}/types.d.ts +3 -1
- package/output/types/types.d.ts.map +1 -0
- package/output/types/types.js +2 -0
- package/output/types/types.js.map +1 -0
- package/package.json +42 -15
- package/output/esm/element.d.ts +0 -48
- package/output/esm/index.d.ts +0 -14
- package/output/esm/index.js +0 -1289
- package/output/esm/index.js.map +0 -1
- package/output/esm/render/common/hooks.d.ts +0 -10
- package/output/esm/render/common/plugins/context.d.ts +0 -5
- package/output/esm/render/common/plugins/index.d.ts +0 -19
- package/output/esm/render/common/plugins/internal/basic.d.ts +0 -10
- package/output/esm/render/common/plugins/internal/inject.d.ts +0 -6
- package/output/esm/render/index.d.ts +0 -4
- package/output/esm/render/server.d.ts +0 -5
- package/output/esm/symbol.d.ts +0 -2
- package/output/umd/element.d.ts +0 -48
- package/output/umd/index.d.ts +0 -14
- package/output/umd/index.js +0 -1304
- package/output/umd/index.js.map +0 -1
- package/output/umd/logger.d.ts +0 -3
- package/output/umd/render/browser.d.ts +0 -7
- package/output/umd/render/common/hooks.d.ts +0 -10
- package/output/umd/render/common/index.d.ts +0 -64
- package/output/umd/render/index.d.ts +0 -4
- package/output/umd/signal/index.d.ts +0 -6
- package/output/umd/symbol.d.ts +0 -2
- package/output/umd/types.d.ts +0 -1173
package/README.md
CHANGED
|
@@ -1,118 +1,302 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Airx ☁️
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/airx)
|
|
3
|
+
[](https://www.npmjs.com/package/airx)
|
|
4
|
+
[](https://github.com/airxjs/airx/actions/workflows/check.yml)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
> A lightweight, Signal-driven JSX web application framework
|
|
6
9
|
|
|
7
|
-
[中文文档](
|
|
8
|
-
|
|
|
9
|
-
[English Document](https://github.com/airxjs/airx/blob/main/README.md)
|
|
10
|
+
[中文文档](./README_CN.md) • [English Documentation](./README.md)
|
|
10
11
|
|
|
11
|
-
Airx is a frontend
|
|
12
|
+
Airx is a modern frontend framework built on **JSX** and **Signal** primitives, designed to provide a simple, performant, and intuitive solution for building reactive web applications.
|
|
12
13
|
|
|
13
|
-
## Features
|
|
14
|
+
## ✨ Features
|
|
14
15
|
|
|
15
|
-
- Seamlessly integrates with [Signal](https://github.com/tc39/proposal-signals)
|
|
16
|
-
- Developed entirely
|
|
17
|
-
-
|
|
18
|
-
- No hooks
|
|
19
|
-
- Minimal
|
|
16
|
+
- 🔄 **Signal-driven reactivity**: Seamlessly integrates with [TC39 Signal proposal](https://github.com/tc39/proposal-signals)
|
|
17
|
+
- 📝 **TypeScript-first**: Developed entirely in TypeScript with excellent type safety
|
|
18
|
+
- ⚡ **Functional components**: Define components using clean JSX functional syntax
|
|
19
|
+
- 🚫 **No hooks complexity**: Simple and straightforward API without React-style hooks
|
|
20
|
+
- 🪶 **Lightweight**: Minimal bundle size with zero dependencies
|
|
21
|
+
- 🔌 **Extensible**: Plugin system for advanced functionality
|
|
22
|
+
- 🌐 **Universal**: Works in both browser and server environments
|
|
20
23
|
|
|
21
|
-
##
|
|
24
|
+
## 🚀 Quick Start
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
### Installation
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
```shell
|
|
28
|
+
```bash
|
|
28
29
|
npm install airx
|
|
30
|
+
# or
|
|
31
|
+
yarn add airx
|
|
32
|
+
# or
|
|
33
|
+
pnpm add airx
|
|
29
34
|
```
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
### Basic Usage
|
|
32
37
|
|
|
33
|
-
```
|
|
38
|
+
```tsx
|
|
34
39
|
import * as airx from 'airx'
|
|
35
40
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
const
|
|
41
|
+
// Create reactive state using Signal
|
|
42
|
+
const count = new Signal.State(0)
|
|
43
|
+
const doubleCount = new Signal.Computed(() => count.get() * 2)
|
|
39
44
|
|
|
40
|
-
function
|
|
41
|
-
const
|
|
45
|
+
function Counter() {
|
|
46
|
+
const localState = new Signal.State(0)
|
|
42
47
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
const increment = () => {
|
|
49
|
+
count.set(count.get() + 1)
|
|
50
|
+
localState.set(localState.get() + 1)
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
// Return a
|
|
53
|
+
// Return a render function
|
|
49
54
|
return () => (
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
{
|
|
53
|
-
{
|
|
54
|
-
|
|
55
|
+
<div>
|
|
56
|
+
<h1>Counter App</h1>
|
|
57
|
+
<p>Global count: {count.get()}</p>
|
|
58
|
+
<p>Double count: {doubleCount.get()}</p>
|
|
59
|
+
<p>Local count: {localState.get()}</p>
|
|
60
|
+
<button onClick={increment}>
|
|
61
|
+
Click me!
|
|
62
|
+
</button>
|
|
63
|
+
</div>
|
|
55
64
|
)
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
app.
|
|
67
|
+
// Create and mount the app
|
|
68
|
+
const app = airx.createApp(<Counter />)
|
|
69
|
+
app.mount(document.getElementById('app'))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 📖 Core Concepts
|
|
73
|
+
|
|
74
|
+
### Components
|
|
75
|
+
|
|
76
|
+
Components in Airx are simple functions that return a render function:
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
function MyComponent() {
|
|
80
|
+
const state = new Signal.State('Hello')
|
|
81
|
+
|
|
82
|
+
return () => (
|
|
83
|
+
<div>{state.get()} World!</div>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### State Management
|
|
89
|
+
|
|
90
|
+
Airx leverages the Signal primitive for reactive state management:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// State
|
|
94
|
+
const count = new Signal.State(0)
|
|
95
|
+
|
|
96
|
+
// Computed values
|
|
97
|
+
const isEven = new Signal.Computed(() => count.get() % 2 === 0)
|
|
98
|
+
|
|
99
|
+
// Effects
|
|
100
|
+
const effect = new Signal.Effect(() => {
|
|
101
|
+
console.log('Count changed:', count.get())
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Context & Dependency Injection
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
const ThemeContext = Symbol('theme')
|
|
109
|
+
|
|
110
|
+
function App() {
|
|
111
|
+
// Provide values down the component tree
|
|
112
|
+
airx.provide(ThemeContext, 'dark')
|
|
113
|
+
|
|
114
|
+
return () => <Child />
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function Child() {
|
|
118
|
+
// Inject values from parent components
|
|
119
|
+
const theme = airx.inject(ThemeContext)
|
|
120
|
+
|
|
121
|
+
return () => (
|
|
122
|
+
<div className={`theme-${theme}`}>
|
|
123
|
+
Current theme: {theme}
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
60
127
|
```
|
|
61
128
|
|
|
62
|
-
|
|
129
|
+
### Lifecycle Hooks
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
function Component() {
|
|
133
|
+
airx.onMounted(() => {
|
|
134
|
+
console.log('Component mounted')
|
|
135
|
+
|
|
136
|
+
// Return cleanup function
|
|
137
|
+
return () => {
|
|
138
|
+
console.log('Component unmounted')
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
airx.onUnmounted(() => {
|
|
143
|
+
console.log('Component will unmount')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
return () => <div>My Component</div>
|
|
147
|
+
}
|
|
63
148
|
|
|
64
|
-
|
|
149
|
+
## 📚 API Reference
|
|
65
150
|
|
|
66
|
-
|
|
151
|
+
Airx follows a minimal API design philosophy. Here are the core APIs:
|
|
67
152
|
|
|
68
|
-
|
|
153
|
+
### `createApp(element)`
|
|
69
154
|
|
|
70
|
-
|
|
155
|
+
Creates an application instance.
|
|
71
156
|
|
|
72
|
-
```
|
|
73
|
-
|
|
157
|
+
```tsx
|
|
158
|
+
const app = airx.createApp(<App />)
|
|
159
|
+
app.mount(document.getElementById('root'))
|
|
74
160
|
```
|
|
75
161
|
|
|
76
|
-
|
|
162
|
+
### `provide<T>(key, value): ProvideUpdater<T>`
|
|
77
163
|
|
|
78
|
-
|
|
164
|
+
Provides a value down the component tree through context. Must be called synchronously within a component.
|
|
79
165
|
|
|
80
|
-
```
|
|
81
|
-
function
|
|
166
|
+
```tsx
|
|
167
|
+
function Parent() {
|
|
168
|
+
airx.provide('theme', 'dark')
|
|
169
|
+
return () => <Child />
|
|
170
|
+
}
|
|
82
171
|
```
|
|
83
172
|
|
|
84
|
-
|
|
173
|
+
### `inject<T>(key): T | undefined`
|
|
85
174
|
|
|
86
|
-
|
|
175
|
+
Retrieves a provided value from the component tree. Must be called synchronously within a component.
|
|
87
176
|
|
|
88
|
-
```
|
|
177
|
+
```tsx
|
|
178
|
+
function Child() {
|
|
179
|
+
const theme = airx.inject('theme')
|
|
180
|
+
return () => <div>Theme: {theme}</div>
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### `onMounted(listener): void`
|
|
185
|
+
|
|
186
|
+
Registers a callback for when the component is mounted to the DOM.
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
89
189
|
type MountedListener = () => (() => void) | void
|
|
90
|
-
|
|
190
|
+
|
|
191
|
+
airx.onMounted(() => {
|
|
192
|
+
console.log('Mounted!')
|
|
193
|
+
return () => console.log('Cleanup')
|
|
194
|
+
})
|
|
91
195
|
```
|
|
92
196
|
|
|
93
|
-
|
|
197
|
+
### `onUnmounted(listener): void`
|
|
94
198
|
|
|
95
|
-
|
|
199
|
+
Registers a callback for when the component is unmounted from the DOM.
|
|
96
200
|
|
|
97
|
-
```
|
|
201
|
+
```tsx
|
|
98
202
|
type UnmountedListener = () => void
|
|
99
|
-
|
|
203
|
+
|
|
204
|
+
airx.onUnmounted(() => {
|
|
205
|
+
console.log('Unmounted!')
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### `createElement(type, props, ...children)`
|
|
210
|
+
|
|
211
|
+
Creates virtual DOM elements (usually handled by JSX transpiler).
|
|
212
|
+
|
|
213
|
+
### `Fragment`
|
|
214
|
+
|
|
215
|
+
A component for grouping multiple elements without adding extra DOM nodes.
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
function App() {
|
|
219
|
+
return () => (
|
|
220
|
+
<airx.Fragment>
|
|
221
|
+
<div>First</div>
|
|
222
|
+
<div>Second</div>
|
|
223
|
+
</airx.Fragment>
|
|
224
|
+
)
|
|
225
|
+
}
|
|
100
226
|
```
|
|
101
227
|
|
|
102
|
-
|
|
228
|
+
## 🔧 Development
|
|
229
|
+
|
|
230
|
+
### Building from Source
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
# Clone the repository
|
|
234
|
+
git clone https://github.com/airxjs/airx.git
|
|
235
|
+
cd airx
|
|
236
|
+
|
|
237
|
+
# Install dependencies
|
|
238
|
+
npm install
|
|
239
|
+
|
|
240
|
+
# Build the project
|
|
241
|
+
npm run build
|
|
242
|
+
|
|
243
|
+
# Run tests
|
|
244
|
+
npm test
|
|
245
|
+
|
|
246
|
+
# Run tests with UI
|
|
247
|
+
npm run test:ui
|
|
248
|
+
|
|
249
|
+
# Run tests with coverage
|
|
250
|
+
npm run test:coverage
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Project Structure
|
|
254
|
+
|
|
255
|
+
```text
|
|
256
|
+
source/
|
|
257
|
+
├── app/ # Application creation and management
|
|
258
|
+
├── element/ # Virtual DOM and JSX handling
|
|
259
|
+
├── logger/ # Internal logging utilities
|
|
260
|
+
├── render/ # Rendering engine
|
|
261
|
+
│ ├── basic/ # Core rendering logic
|
|
262
|
+
│ ├── browser/ # Browser-specific rendering
|
|
263
|
+
│ └── server/ # Server-side rendering
|
|
264
|
+
├── signal/ # Signal integration
|
|
265
|
+
├── symbol/ # Internal symbols
|
|
266
|
+
└── types/ # TypeScript type definitions
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## 🤝 Contributing
|
|
270
|
+
|
|
271
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
272
|
+
|
|
273
|
+
### Development Workflow
|
|
274
|
+
|
|
275
|
+
1. Fork the repository
|
|
276
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
277
|
+
3. Make your changes
|
|
278
|
+
4. Add tests for your changes
|
|
279
|
+
5. Ensure all tests pass (`npm test`)
|
|
280
|
+
6. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
281
|
+
7. Push to the branch (`git push origin feature/amazing-feature`)
|
|
282
|
+
8. Open a Pull Request
|
|
103
283
|
|
|
104
|
-
## License
|
|
284
|
+
## 📄 License
|
|
105
285
|
|
|
106
|
-
This project
|
|
286
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
107
287
|
|
|
108
|
-
##
|
|
288
|
+
## 🙏 Acknowledgments
|
|
109
289
|
|
|
110
|
-
|
|
290
|
+
- Thanks to all contributors and supporters of the Airx project
|
|
291
|
+
- Inspired by the [TC39 Signal proposal](https://github.com/tc39/proposal-signals)
|
|
292
|
+
- Built with ❤️ by the Airx community
|
|
111
293
|
|
|
112
|
-
##
|
|
294
|
+
## 📞 Support
|
|
113
295
|
|
|
114
|
-
|
|
296
|
+
- 📖 [Documentation](https://github.com/airxjs/airx)
|
|
297
|
+
- 🐛 [Issue Tracker](https://github.com/airxjs/airx/issues)
|
|
298
|
+
- 💬 [Discussions](https://github.com/airxjs/airx/discussions)
|
|
115
299
|
|
|
116
300
|
---
|
|
117
301
|
|
|
118
|
-
|
|
302
|
+
Made with ☁️ by the Airx team
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Plugin } from '../render/index.js';
|
|
2
|
+
import { AirxComponent, AirxElement } from '../element/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Airx 应用实例。
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* import { createApp } from 'airx'
|
|
8
|
+
* import { App } from './App.js'
|
|
9
|
+
*
|
|
10
|
+
* createApp(App).mount(document.getElementById('root')!)
|
|
11
|
+
*/
|
|
12
|
+
export interface AirxApp {
|
|
13
|
+
mount: (container: HTMLElement) => AirxApp;
|
|
14
|
+
/** @deprecated WIP */
|
|
15
|
+
plugin: (...plugins: Plugin[]) => AirxApp;
|
|
16
|
+
/** @deprecated WIP */
|
|
17
|
+
renderToHTML: () => Promise<string>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 创建一个 Airx 应用。
|
|
21
|
+
*
|
|
22
|
+
* 支持直接传入组件函数,也支持传入已经创建好的元素。
|
|
23
|
+
*
|
|
24
|
+
* @param element 根组件或根元素。
|
|
25
|
+
* @returns 可继续链式调用的应用实例。
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* import { createApp } from 'airx'
|
|
29
|
+
* import { App } from './App.js'
|
|
30
|
+
*
|
|
31
|
+
* createApp(App).mount(document.getElementById('root')!)
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* import { createApp, createElement } from 'airx'
|
|
35
|
+
* import { App } from './App.js'
|
|
36
|
+
*
|
|
37
|
+
* const appElement = createElement(App, { title: 'Airx' })
|
|
38
|
+
* createApp(appElement).mount(document.getElementById('root')!)
|
|
39
|
+
*/
|
|
40
|
+
export declare function createApp(element: AirxElement<any> | AirxComponent): AirxApp;
|
|
41
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../source/app/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,MAAM,EAAiB,MAAM,oBAAoB,CAAA;AACvF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAiB,MAAM,qBAAqB,CAAA;AAE/E;;;;;;;;GAQG;AACH,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,CAAA;IAE1C,sBAAsB;IACtB,MAAM,EAAE,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAA;IACzC,sBAAsB;IACtB,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CACpC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,aAAa,GAAG,OAAO,CA+B5E"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { browserRender, serverRender, PluginContext } from '../render/index.js';
|
|
2
|
+
import { createElement } from '../element/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* 创建一个 Airx 应用。
|
|
5
|
+
*
|
|
6
|
+
* 支持直接传入组件函数,也支持传入已经创建好的元素。
|
|
7
|
+
*
|
|
8
|
+
* @param element 根组件或根元素。
|
|
9
|
+
* @returns 可继续链式调用的应用实例。
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* import { createApp } from 'airx'
|
|
13
|
+
* import { App } from './App.js'
|
|
14
|
+
*
|
|
15
|
+
* createApp(App).mount(document.getElementById('root')!)
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* import { createApp, createElement } from 'airx'
|
|
19
|
+
* import { App } from './App.js'
|
|
20
|
+
*
|
|
21
|
+
* const appElement = createElement(App, { title: 'Airx' })
|
|
22
|
+
* createApp(appElement).mount(document.getElementById('root')!)
|
|
23
|
+
*/
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
+
export function createApp(element) {
|
|
26
|
+
const appContext = new PluginContext();
|
|
27
|
+
const ensureAsElement = (element) => {
|
|
28
|
+
if (typeof element === 'function') {
|
|
29
|
+
return createElement(element, {});
|
|
30
|
+
}
|
|
31
|
+
return element;
|
|
32
|
+
};
|
|
33
|
+
const app = {
|
|
34
|
+
plugin: (...plugins) => {
|
|
35
|
+
appContext.registerPlugin(...plugins);
|
|
36
|
+
return app;
|
|
37
|
+
},
|
|
38
|
+
mount: (container) => {
|
|
39
|
+
container.innerHTML = ''; // 先清空再说
|
|
40
|
+
browserRender(appContext, ensureAsElement(element), container);
|
|
41
|
+
return app;
|
|
42
|
+
},
|
|
43
|
+
renderToHTML: () => {
|
|
44
|
+
return new Promise(resolve => {
|
|
45
|
+
serverRender(appContext, ensureAsElement(element), resolve);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return app;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../source/app/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAU,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvF,OAAO,EAA8B,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAoB/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,OAAyC;IACjE,MAAM,UAAU,GAAG,IAAI,aAAa,EAAE,CAAA;IAEtC,MAAM,eAAe,GAAG,CAAC,OAAoC,EAAe,EAAE;QAC5E,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAClC,OAAO,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QACnC,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC,CAAA;IAED,MAAM,GAAG,GAAY;QACnB,MAAM,EAAE,CAAC,GAAG,OAAiB,EAAE,EAAE;YAC/B,UAAU,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,CAAA;YACrC,OAAO,GAAG,CAAA;QACZ,CAAC;QAED,KAAK,EAAE,CAAC,SAAsB,EAAE,EAAE;YAChC,SAAS,CAAC,SAAS,GAAG,EAAE,CAAA,CAAC,QAAQ;YACjC,aAAa,CAAC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,CAAA;YAC9D,OAAO,GAAG,CAAA;QACZ,CAAC;QAED,YAAY,EAAE,GAAoB,EAAE;YAClC,OAAO,IAAI,OAAO,CAAS,OAAO,CAAC,EAAE;gBACnC,YAAY,CAAC,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAA;YAC7D,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;IAED,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/app/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/app/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import * as symbol from '../symbol/index.js';
|
|
2
|
+
type AirxElementType<P> = string | AirxComponent<P>;
|
|
3
|
+
export type Props = {
|
|
4
|
+
[propKey: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Airx 虚拟节点结构。
|
|
8
|
+
*
|
|
9
|
+
* - type: 标签名或组件函数
|
|
10
|
+
* - props: 组件参数或标签属性
|
|
11
|
+
* - props.children: 子节点列表
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* import { createElement, type AirxElement } from 'airx'
|
|
15
|
+
*
|
|
16
|
+
* const node: AirxElement = createElement('div', { id: 'app' }, 'hello')
|
|
17
|
+
*/
|
|
18
|
+
export interface AirxElement<P = any> {
|
|
19
|
+
type: AirxElementType<P>;
|
|
20
|
+
props: Props & P;
|
|
21
|
+
[symbol.airxElementSymbol]: true;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 组件可返回的子节点类型。
|
|
25
|
+
*/
|
|
26
|
+
export type AirxChildren = null | string | number | boolean | undefined | AirxElement | Array<AirxChildren> | AirxComponentRender;
|
|
27
|
+
/**
|
|
28
|
+
* 组件渲染函数类型。
|
|
29
|
+
*
|
|
30
|
+
* 组件函数返回值本身是一个 "render 函数",该函数最终返回子节点。
|
|
31
|
+
*/
|
|
32
|
+
export type AirxComponentRender = () => AirxChildren;
|
|
33
|
+
export type AirxComponent<P = unknown> = ReactiveComponent<P>;
|
|
34
|
+
export type ReactiveComponent<P = unknown> = (props: P) => AirxComponentRender;
|
|
35
|
+
/**
|
|
36
|
+
* 创建 Airx 虚拟节点。
|
|
37
|
+
*
|
|
38
|
+
* 可用于手写节点,也会被 JSX 转换后调用。
|
|
39
|
+
*
|
|
40
|
+
* @param type 标签名或组件函数。
|
|
41
|
+
* @param props 属性对象。
|
|
42
|
+
* @param children 可变子节点参数。
|
|
43
|
+
* @returns 标准化后的 AirxElement。
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* import { createElement } from 'airx'
|
|
47
|
+
*
|
|
48
|
+
* const view = createElement('div', { class: 'box' }, 'hello')
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* import { createElement } from 'airx'
|
|
52
|
+
*
|
|
53
|
+
* function Title(props: { text: string }) {
|
|
54
|
+
* return () => createElement('h1', null as never, props.text)
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* const node = createElement(Title, { text: 'Airx' })
|
|
58
|
+
*/
|
|
59
|
+
export declare function createElement<P = any>(type: AirxElementType<P>, props: {
|
|
60
|
+
[key: string]: unknown;
|
|
61
|
+
} & P, ...children: AirxChildren[]): AirxElement<P>;
|
|
62
|
+
/**
|
|
63
|
+
* 判断一个值是否是合法的 AirxElement。
|
|
64
|
+
*/
|
|
65
|
+
export declare function isValidElement(element: unknown): element is AirxElement;
|
|
66
|
+
/**
|
|
67
|
+
* JSX Fragment 对应的运行时实现。
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* function Card() {
|
|
71
|
+
* return () => (
|
|
72
|
+
* <>
|
|
73
|
+
* <h3>Title</h3>
|
|
74
|
+
* <p>Content</p>
|
|
75
|
+
* </>
|
|
76
|
+
* )
|
|
77
|
+
* }
|
|
78
|
+
*/
|
|
79
|
+
export declare function Fragment(props: {
|
|
80
|
+
children: AirxElement;
|
|
81
|
+
}): () => AirxElement<any>;
|
|
82
|
+
export type AirxComponentUnmountedListener = () => void;
|
|
83
|
+
export type AirxComponentMountedListener = () => (() => void) | void;
|
|
84
|
+
export interface AirxComponentLifecycle {
|
|
85
|
+
onMounted: (listener: AirxComponentMountedListener) => void;
|
|
86
|
+
onUnmounted: (listener: AirxComponentUnmountedListener) => void;
|
|
87
|
+
}
|
|
88
|
+
type ProvideUpdater<T = unknown> = (newValue: T | ((old: T) => T)) => void;
|
|
89
|
+
export type AirxComponentContext = AirxComponentLifecycle & {
|
|
90
|
+
provide: <T = unknown>(key: unknown, value: T) => ProvideUpdater<T>;
|
|
91
|
+
inject: <T = unknown>(key: unknown) => T | undefined;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* 为组件提供类型友好的包装。
|
|
95
|
+
*
|
|
96
|
+
* 主要用于在不使用 JSX 的场景下显式声明组件签名。
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* import { component, createElement } from 'airx'
|
|
100
|
+
*
|
|
101
|
+
* const Hello = component<{ name: string }>((props) => {
|
|
102
|
+
* return () => createElement('h1', null as never, `Hello ${props.name}`)
|
|
103
|
+
* })
|
|
104
|
+
*/
|
|
105
|
+
export declare function component<P = unknown>(comp: AirxComponent<P>): AirxComponent<P>;
|
|
106
|
+
export declare function createErrorRender(error: unknown): AirxComponentRender;
|
|
107
|
+
export {};
|
|
108
|
+
//# sourceMappingURL=element.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../../source/element/element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAG5C,KAAK,eAAe,CAAC,CAAC,IAAI,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;AAEnD,MAAM,MAAM,KAAK,GAAG;IAAE,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAA;AAElD;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,GAAG;IAClC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,CAAA;IACxB,KAAK,EAAE,KAAK,GAAG,CAAC,CAAA;IAChB,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,IAAI,GACJ,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,WAAW,GACX,KAAK,CAAC,YAAY,CAAC,GACnB,mBAAmB,CAAA;AAEvB;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,YAAY,CAAA;AACpD,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,OAAO,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAA;AAC7D,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,mBAAmB,CAAA;AAE9E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,wBAAgB,aAAa,CAAC,CAAC,GAAG,GAAG,EACnC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,EACxB,KAAK,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,GAAG,CAAC,EACrC,GAAG,QAAQ,EAAE,YAAY,EAAE,GAC1B,WAAW,CAAC,CAAC,CAAC,CAiBhB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI,WAAW,CAIvE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE;IAAE,QAAQ,EAAE,WAAW,CAAA;CAAE,0BAExD;AAED,MAAM,MAAM,8BAA8B,GAAG,MAAM,IAAI,CAAA;AACvD,MAAM,MAAM,4BAA4B,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;AAEpE,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,CAAC,QAAQ,EAAE,4BAA4B,KAAK,IAAI,CAAA;IAC3D,WAAW,EAAE,CAAC,QAAQ,EAAE,8BAA8B,KAAK,IAAI,CAAA;CAChE;AAED,KAAK,cAAc,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAA;AAE1E,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG;IAC1D,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,CAAA;IACnE,MAAM,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,SAAS,CAAA;CACrD,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAE/E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAwBrE"}
|