apprun 3.36.0 → 3.37.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/CHANGELOG.md +28 -0
- package/README.md +143 -25
- package/WHATSNEW.md +29 -12
- package/apprun-book.jpg +0 -0
- package/apprun.d.ts +136 -46
- package/cli/app.js +29 -0
- package/cli/index.html +13 -0
- package/{apprun-cli.js → cli/index.js} +8 -14
- package/dist/apprun-code.js +2 -0
- package/dist/apprun-code.js.map +1 -0
- package/dist/apprun-dev-tools.js +1 -2
- package/dist/apprun-dev-tools.js.map +1 -1
- package/dist/apprun-html.esm.js +7 -7
- package/dist/apprun-html.esm.js.map +1 -1
- package/dist/apprun-html.js +1 -1
- package/dist/apprun-html.js.map +1 -1
- package/dist/apprun-play-html.esm.js +7 -7
- package/dist/apprun-play-html.esm.js.map +1 -1
- package/dist/apprun-play.js +1 -1
- package/dist/apprun-play.js.map +1 -1
- package/dist/apprun.esm.js +1 -1
- package/dist/apprun.esm.js.map +1 -1
- package/dist/apprun.js +1 -1
- package/dist/apprun.js.map +1 -1
- package/dist/createState.js +2 -0
- package/dist/createState.js.map +1 -0
- package/esm/add-components.js +90 -0
- package/esm/add-components.js.map +1 -0
- package/esm/app.js +15 -8
- package/esm/app.js.map +1 -1
- package/esm/apprun-code.js +51 -16
- package/esm/apprun-code.js.map +1 -1
- package/esm/apprun-dev-tools.js +32 -32
- package/esm/apprun-dev-tools.js.map +1 -1
- package/esm/apprun-play.js +50 -17
- package/esm/apprun-play.js.map +1 -1
- package/esm/apprun.js +42 -11
- package/esm/apprun.js.map +1 -1
- package/esm/component.js +17 -20
- package/esm/component.js.map +1 -1
- package/esm/createState.js +9 -0
- package/esm/createState.js.map +1 -0
- package/esm/decorator.js.map +1 -1
- package/esm/directive.js +1 -1
- package/esm/directive.js.map +1 -1
- package/esm/router.js +241 -18
- package/esm/router.js.map +1 -1
- package/esm/shadow.js +1 -1
- package/esm/shadow.js.map +1 -1
- package/esm/type-utils.js +2 -3
- package/esm/type-utils.js.map +1 -1
- package/esm/vdom-my-new.js +327 -0
- package/esm/vdom-my-new.js.map +1 -0
- package/esm/vdom-my-prop-attr.js +227 -0
- package/esm/vdom-my-prop-attr.js.map +1 -0
- package/esm/vdom-my.js +114 -150
- package/esm/vdom-my.js.map +1 -1
- package/esm/vdom-patch.js +1 -1
- package/esm/vdom-patch.js.map +1 -1
- package/esm/version.js +1 -1
- package/esm/web-component.js +3 -4
- package/esm/web-component.js.map +1 -1
- package/index.html +5 -2
- package/jest.config.js +2 -2
- package/jest.setup.js +29 -3
- package/jsx-runtime.js +1 -1
- package/jsx-runtime.js.map +1 -1
- package/package.json +14 -14
- package/src/add-components.ts +103 -0
- package/src/app.ts +10 -19
- package/src/apprun-code.tsx +48 -10
- package/src/apprun-dev-tools.tsx +23 -27
- package/src/apprun-play.tsx +46 -9
- package/src/apprun.ts +49 -40
- package/src/component.ts +15 -8
- package/src/createState.ts +11 -0
- package/src/decorator.ts +2 -1
- package/src/router.ts +261 -17
- package/src/shadow.tsx +1 -1
- package/src/tsconfig.json +2 -2
- package/src/types.ts +62 -2
- package/src/vdom-my-new.ts +311 -0
- package/src/vdom-my-prop-attr.ts +241 -0
- package/src/vdom-my.ts +109 -134
- package/src/version.ts +1 -1
- package/src/web-component.ts +4 -10
- package/tsconfig.jest.json +15 -6
- package/tsconfig.json +3 -3
- package/webpack.config.cjs +3 -1
- package/cli/export.js +0 -92
- package/cli/import.js +0 -68
- package/plan/plan-apprun-bugfixes.md +0 -207
- package/src/types/apprun.d.ts +0 -56
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## Releases
|
|
4
4
|
|
|
5
|
+
## 3.36.1
|
|
6
|
+
|
|
7
|
+
* Continue code review with AI
|
|
8
|
+
* Use property-information to improve property and attribute handling
|
|
9
|
+
* Performance improvements in virtual DOM handling, see [analysis reports](docs/done/framework-reordering-comparison.md)
|
|
10
|
+
* New hierarchical matching behavior, see [hierarchical routing requirements](docs/requirements/req-hierarchical-routing.md)
|
|
11
|
+
|
|
12
|
+
## 3.36.0
|
|
13
|
+
|
|
14
|
+
* Code review by using Copilot and Claude Sonnet 4, see [plan-apprun-bugfixes.md](docs/plan/plan-apprun-bugfixes.md) for details.
|
|
15
|
+
* Enhanced type definitions (apprun.d.ts) for better TypeScript support
|
|
16
|
+
* Fixed minor bugs and edge cases in virtual DOM handling
|
|
17
|
+
* Fixed bugs in router initialization logic
|
|
18
|
+
|
|
19
|
+
## 3.35.0
|
|
20
|
+
|
|
21
|
+
* Support auto use router for pretty links
|
|
22
|
+
* AppRun now supports pretty links with components subscribing to route events like '/about'
|
|
23
|
+
* Routing component events with pretty links
|
|
24
|
+
* Fallback to hash-based routing when components subscribe to '#' or '#/'
|
|
25
|
+
|
|
26
|
+
## 3.33.10
|
|
27
|
+
|
|
28
|
+
* Support async generator for event handlers
|
|
29
|
+
* Async generator functions can return multiple values rendered in order
|
|
30
|
+
* Use lit-html V3 for apprun-html.js
|
|
31
|
+
* Standalone version of AppRun using lit-html for rendering without JSX
|
|
32
|
+
|
|
5
33
|
## 3.30.0
|
|
6
34
|
|
|
7
35
|
* Add React-safe apprun-play-html
|
package/README.md
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
# AppRun
|
|
1
|
+
# AppRun
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://apprun.js.org/docs)
|
|
4
|
+
[](https://apprun.js.org/#play)
|
|
5
|
+
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][downloads-url] [![License][license-image]][license-url] [![twitter][twitter-badge]][twitter] [![Discord Chat][discord-image]][discord-invite]
|
|
4
6
|
|
|
5
|
-
We
|
|
6
|
-
|
|
7
|
-
In this release we had a code review by using Copilot and Claude Sonnet 4, which found and fixed minor bugs and edge cases in virtual DOM handling, as well as bugs in router initialization logic. Also improved overall code quality and stability.
|
|
7
|
+
🚀 July 2025, We have started to improve the codebase using AI. See [whats new](#new) for details.
|
|
8
8
|
|
|
9
9
|
## Introduction
|
|
10
10
|
|
|
11
|
-
AppRun is a lightweight
|
|
11
|
+
AppRun is a lightweight framework for building web apps. It has a [unique architecture](https://apprun.js.org/docs/architecture/) inspired by the Elm architecture that can help you manage states, routing, and other essential aspects of your web application, leveraging the power of the [event publish-subscribe](https://apprun.js.org/docs/event-pubsub/) pattern.
|
|
12
|
+
|
|
13
|
+
## AppRun Benefits
|
|
14
|
+
|
|
15
|
+
* Clean architecture that needs minimal setup and boilerplate code.
|
|
16
|
+
* Decoupled architecture that is test friendly.
|
|
17
|
+
* No proprietary syntax to learn (no hooks, no reducers, no signals)
|
|
18
|
+
* State management and routing included
|
|
19
|
+
* Use directly in the browser or with a compiler/bundler
|
|
20
|
+
* Advanced features: JSX, Web Components, Dev Tools, SSR, etc.
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
12
23
|
|
|
13
|
-
|
|
24
|
+
Let's use a _Counter_ as an example to demonstrate the AppRun architecture:
|
|
14
25
|
|
|
15
26
|
```js
|
|
16
27
|
// define the initial state
|
|
@@ -34,21 +45,122 @@ app.start(document.body, state, view, update);
|
|
|
34
45
|
```
|
|
35
46
|
<apprun-code></apprun-code>
|
|
36
47
|
|
|
37
|
-
|
|
48
|
+
With [directives](https://apprun.js.org/docs/directives/) syntax sugar you can write more concise code:
|
|
38
49
|
|
|
39
|
-
|
|
50
|
+
```js
|
|
51
|
+
// define the initial state
|
|
52
|
+
const state = 0;
|
|
53
|
+
|
|
54
|
+
// view is a function to display the state (JSX)
|
|
55
|
+
const view = state => <div>
|
|
56
|
+
<h1>{state}</h1>
|
|
57
|
+
<button $onclick="-1">-1</button>
|
|
58
|
+
<button $onclick="+1">+1</button>
|
|
59
|
+
</div>;
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
// update is a collection of event handlers
|
|
62
|
+
const update = {
|
|
63
|
+
'+1': state => state + 1,
|
|
64
|
+
'-1': state => state - 1
|
|
65
|
+
};
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
// start the app
|
|
68
|
+
app.start(document.body, state, view, update);
|
|
69
|
+
```
|
|
70
|
+
<apprun-code></apprun-code>
|
|
44
71
|
|
|
45
|
-
|
|
72
|
+
Alternatively, you can invoke state update functions without events for local state updates:
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
```js
|
|
75
|
+
// define the initial state
|
|
76
|
+
const state = 0;
|
|
77
|
+
|
|
78
|
+
// state update function
|
|
79
|
+
const add = (state, value) => state + value;
|
|
80
|
+
|
|
81
|
+
// view is a function to display the state (JSX)
|
|
82
|
+
const view = state => <div>
|
|
83
|
+
<h1>{state}</h1>
|
|
84
|
+
<button $onclick={[add, -1]}>-1</button>
|
|
85
|
+
<button $onclick={[add, 1]}>+1</button>
|
|
86
|
+
</div>;
|
|
87
|
+
|
|
88
|
+
// start the app
|
|
89
|
+
app.start(document.body, state, view);
|
|
90
|
+
```
|
|
91
|
+
<apprun-code></apprun-code>
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
One cool feature of AppRun is that you can use async generator functions for event handlers to return multiple values. AppRun will render each value in the order they are generated.
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
const state = {};
|
|
98
|
+
const view = state => html`
|
|
99
|
+
<div><button @click=${run(getComic)}>fetch ...</button></div>
|
|
100
|
+
${state.loading && html`<div>loading ... </div>`}
|
|
101
|
+
${state.comic && html`<img src=${state.comic.img} />`}
|
|
102
|
+
`;
|
|
103
|
+
async function* getComic() { // async generator function returns loading flag and then the comic object
|
|
104
|
+
yield { loading: true };
|
|
105
|
+
const response = await fetch('https://xkcd-api.netlify.app');
|
|
106
|
+
const comic = await response.json();
|
|
107
|
+
yield { comic };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
app.start(document.body, state, view);
|
|
111
|
+
```
|
|
112
|
+
<apprun-code></apprun-code>
|
|
113
|
+
|
|
114
|
+
And, of course, you can use Components to encapsulate the logic blocks, e.g., SPA pages. Each component can have its own state, view, and update functions. Each component has its own handlers to handle the routing events. AppRun routes `/<path>`, `#<path>`, and `#/<path>` URLs to components. AppRun also does this with [hierarchical routing](docs/requirements/req-hierarchical-routing.md).
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
class Home extends Component {
|
|
118
|
+
view = () => <div>Home</div>;
|
|
119
|
+
update = {'/, /home': state => state };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class Contact extends Component {
|
|
123
|
+
view = () => <div>Contact</div>;
|
|
124
|
+
update = {'/contact': state => state };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
class About extends Component {
|
|
128
|
+
view = () => <div>About</div>;
|
|
129
|
+
update = {'/about': state => state };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const App = () => <>
|
|
133
|
+
<div id="menus">
|
|
134
|
+
<a href="/home">Home</a>{' | '}
|
|
135
|
+
<a href="/contact">Contact</a>{' | '}
|
|
136
|
+
<a href="/about">About</a></div>
|
|
137
|
+
<div id="pages"></div>
|
|
138
|
+
</>
|
|
139
|
+
|
|
140
|
+
app.render(document.body, <App />);
|
|
141
|
+
[About, Contact, Home].map(C => new C().start('pages'));
|
|
142
|
+
```
|
|
143
|
+
<apprun-code></apprun-code>
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
Finally, you can use AppRun with [React](https://reactjs.org/). The `app.use_react` function allows you to use React for rendering the view.
|
|
147
|
+
|
|
148
|
+
```js
|
|
149
|
+
import React from 'react'
|
|
150
|
+
import ReactDOM from 'react-dom/client'
|
|
151
|
+
import app from 'apprun';
|
|
152
|
+
use_react(React, ReactDOM);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The `app.use_render` function allows you to use a other render library for rendering the view. Enjoy the rich ecosystem of React.
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
import { render } from 'preact'
|
|
159
|
+
import app from 'apprun';
|
|
160
|
+
app.use_render(render);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
There are many more examples and interactive demos available in [the AppRun Playground](https://apprun.js.org/#play).
|
|
52
164
|
|
|
53
165
|
|
|
54
166
|
## Getting Started
|
|
@@ -58,15 +170,23 @@ AppRun is distributed on npm. To get it, run:
|
|
|
58
170
|
```sh
|
|
59
171
|
npm install apprun
|
|
60
172
|
```
|
|
61
|
-
|
|
173
|
+
|
|
174
|
+
When you want to do a rapid prototyping or demo, you can use AppRun directly in the browser without JSX or any build step. The `app`, `html` and `run` functions are available globally. The `html` is a HTML template from lit-html. The `run` function is a equivalent to the `$on` directive, which can be used to invoke state update functions.
|
|
62
175
|
|
|
63
176
|
```js
|
|
64
177
|
<html>
|
|
65
178
|
<body>
|
|
66
179
|
<script src="https://unpkg.com/apprun/dist/apprun-html.js"></script>
|
|
67
180
|
<script>
|
|
68
|
-
const
|
|
69
|
-
|
|
181
|
+
const add = (state, delta) => state + delta;
|
|
182
|
+
const view = state => {
|
|
183
|
+
return html`<div>
|
|
184
|
+
<h1>${state}</h1>
|
|
185
|
+
<button @click=${run(add, -1)}>-1</button>
|
|
186
|
+
<button @click=${run(add, +1)}>+1</button>
|
|
187
|
+
</div>`;
|
|
188
|
+
};
|
|
189
|
+
app.start(document.body, 0, view);
|
|
70
190
|
</script>
|
|
71
191
|
</body>
|
|
72
192
|
</html>
|
|
@@ -87,9 +207,7 @@ Or, use the ESM version:
|
|
|
87
207
|
```
|
|
88
208
|
<apprun-code style="height:200px"></apprun-code>
|
|
89
209
|
|
|
90
|
-
In addition to run directly in the browser,
|
|
91
|
-
|
|
92
|
-
You can run the `npm create apprun-app` command to create an AppRun project.
|
|
210
|
+
In addition to run directly in the browser, you can run the `npm create apprun-app` command to create an AppRun project for using a compiler/bundler like Webpack, esbuild or Vite.
|
|
93
211
|
|
|
94
212
|
```sh
|
|
95
213
|
npm create apprun-app [my-app]
|
|
@@ -97,11 +215,11 @@ npm create apprun-app [my-app]
|
|
|
97
215
|
|
|
98
216
|
### Learn More
|
|
99
217
|
|
|
100
|
-
You can
|
|
218
|
+
You can read [AppRun Docs](https://apprun.js.org/docs).
|
|
101
219
|
|
|
102
220
|
### AppRun Book from Apress
|
|
103
221
|
|
|
104
|
-
[](https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/)
|
|
105
223
|
|
|
106
224
|
* [Order from Amazon](https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/)
|
|
107
225
|
|
package/WHATSNEW.md
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
## What's New
|
|
2
2
|
|
|
3
|
+
> July 22, 2025, V3.37.0
|
|
4
|
+
|
|
5
|
+
- Introduced `createState` helper for simplified immutable state updates using Immer [create-state-immer](#docs/done/blog-create-state-immer.md)
|
|
6
|
+
- Added `addComponents` function for adding components to routes [add-components](#docs/done/blog-addcomponents-feature.md)
|
|
7
|
+
- Improved type definitions for better TypeScript support
|
|
8
|
+
- Moved the component to dev-tools
|
|
9
|
+
- Fixed routing basePath initialization issue
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
> July 15, 2025, V3.36.1
|
|
13
|
+
|
|
14
|
+
- Continue code review with AI
|
|
15
|
+
- Use property-information to improve property and attribute handling
|
|
16
|
+
- Performance improvements in virtual DOM handling, see [analysis reports](#docs/done/framework-reordering-comparison.md)
|
|
17
|
+
- New hierarchical matching behavior, see [hierarchical routing document](#docs/requirements/req-hierarchical-routing.md)
|
|
18
|
+
|
|
19
|
+
|
|
3
20
|
> July 12, 2025, V3.36.0
|
|
4
21
|
|
|
5
|
-
Code review by using Copilot and Claude Sonnet 4
|
|
22
|
+
Code review by using Copilot and Claude Sonnet 4, see [plan-apprun-bugfixes.md](#docs/plan/plan-apprun-bugfixes.md) for details.
|
|
6
23
|
- Enhanced type definitions (apprun.d.ts) for better TypeScript support
|
|
7
24
|
- Fixed minor bugs and edge cases in virtual DOM handling
|
|
8
25
|
- Fixed bugs in router initialization logic
|
|
@@ -63,20 +80,20 @@ If you have components subscribe to '#', or '#/', Apprun will fallback to the ha
|
|
|
63
80
|
You can now use async generator functions for event handlers. The async generator function can return multiple values. AppRun will render each value in the order they are generated.
|
|
64
81
|
|
|
65
82
|
```js
|
|
66
|
-
|
|
67
|
-
|
|
83
|
+
const state = {};
|
|
84
|
+
const view = state => html`
|
|
68
85
|
<div><button @click=${run(getComic)}>fetch ...</button></div>
|
|
69
86
|
${state.loading && html`<div>loading ... </div>`}
|
|
70
87
|
${state.comic && html`<img src=${state.comic.img} />`}
|
|
71
88
|
`;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
async function* getComic() { // async generator function returns loading flag and then the comic object
|
|
90
|
+
yield { loading: true };
|
|
91
|
+
const response = await fetch('https://xkcd-api.netlify.app');
|
|
92
|
+
const comic = await response.json();
|
|
93
|
+
yield { comic };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
app.start(document.body, state, view);
|
|
80
97
|
```
|
|
81
98
|
<apprun-code></apprun-code>
|
|
82
99
|
|
|
@@ -93,7 +110,7 @@ The `apprun-html.js` now uses `lit-html` V3 for rendering the view. The `apprun-
|
|
|
93
110
|
<title>Counter</title>
|
|
94
111
|
</head>
|
|
95
112
|
<body>
|
|
96
|
-
<script src="https://unpkg.com/dist/apprun-html"></script>
|
|
113
|
+
<script src="https://unpkg.com/apprun/dist/apprun-html"></script>
|
|
97
114
|
<script>
|
|
98
115
|
const add = (state, delta) => state + delta;
|
|
99
116
|
const view = state => {
|
package/apprun-book.jpg
ADDED
|
Binary file
|
package/apprun.d.ts
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppRun TypeScript Declaration File
|
|
3
|
+
*
|
|
4
|
+
* This file provides TypeScript declarations for the AppRun framework:
|
|
5
|
+
* 1. Core Framework Types
|
|
6
|
+
* - Component lifecycle (View, Action, Update)
|
|
7
|
+
* - Virtual DOM (VNode, VDOM)
|
|
8
|
+
* - Event system with comprehensive options
|
|
9
|
+
*
|
|
10
|
+
* 2. Application Interfaces
|
|
11
|
+
* - IApp: Main framework interface
|
|
12
|
+
*
|
|
13
|
+
* 3. Configuration Options
|
|
14
|
+
* - EventOptions: Event handling configuration
|
|
15
|
+
* - ActionOptions: Action behavior settings
|
|
16
|
+
* - MountOptions: Component mounting configuration
|
|
17
|
+
* - CustomElementOptions: Web component settings
|
|
18
|
+
*
|
|
19
|
+
* 4. Integration Support
|
|
20
|
+
* - React integration types
|
|
21
|
+
* - Lit-html TemplateResult support
|
|
22
|
+
* - JSX namespace declarations
|
|
23
|
+
* - State management with createState
|
|
24
|
+
*
|
|
25
|
+
* Updated in v3.35.1:
|
|
26
|
+
* - Consolidated types from types.ts implementation
|
|
27
|
+
* - Enhanced type safety with better generic constraints
|
|
28
|
+
* - Improved lifecycle hook typing with proper signatures
|
|
29
|
+
* - Added routing system types with ComponentRoute
|
|
30
|
+
* - Better integration with external libraries
|
|
31
|
+
* - Comprehensive options typing matching implementation
|
|
32
|
+
* - Added proper deprecation warnings
|
|
33
|
+
* - Enhanced error handling and validation
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { TemplateResult } from 'lit-html';
|
|
37
|
+
|
|
1
38
|
declare module 'apprun' {
|
|
2
39
|
|
|
3
40
|
export type Element = HTMLElement | string;
|
|
@@ -7,93 +44,138 @@ declare module 'apprun' {
|
|
|
7
44
|
props: {},
|
|
8
45
|
children: Array<VNode | string>
|
|
9
46
|
};
|
|
10
|
-
|
|
47
|
+
|
|
48
|
+
export type VDOM = false | string | VNode | Array<VNode | string> | TemplateResult;
|
|
11
49
|
export type View<T> = (state: T) => VDOM | void;
|
|
12
50
|
export type Action<T> = (state: T, ...p: any[]) => T | Promise<T> | void;
|
|
13
51
|
export type ActionDef<T, E> = (readonly [E, Action<T>, {}?]);
|
|
14
52
|
export type Update<T, E = any> = ActionDef<T, E>[] | { [name: string]: Action<T> | {}[] } | (E | Action<T> | {})[];
|
|
15
|
-
export type
|
|
16
|
-
|
|
53
|
+
export type Router = (url: string, ...args: any[]) => any;
|
|
54
|
+
|
|
55
|
+
export type EventOptions = {
|
|
17
56
|
once?: boolean;
|
|
18
57
|
transition?: boolean;
|
|
19
58
|
delay?: number;
|
|
20
59
|
} | any;
|
|
21
|
-
|
|
60
|
+
|
|
61
|
+
export type ActionOptions = {
|
|
22
62
|
render?: boolean;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
observedAttributes?: string[];
|
|
63
|
+
history?;
|
|
64
|
+
global?: boolean;
|
|
65
|
+
callback?: (state: any) => void;
|
|
27
66
|
};
|
|
28
67
|
|
|
29
68
|
export type MountOptions = {
|
|
30
|
-
render?: boolean
|
|
69
|
+
render?: boolean;
|
|
70
|
+
history?;
|
|
71
|
+
global_event?: boolean;
|
|
72
|
+
route?: string;
|
|
31
73
|
transition?: boolean;
|
|
32
|
-
route?: string
|
|
33
74
|
};
|
|
34
75
|
|
|
35
76
|
export type AppStartOptions<T> = {
|
|
36
77
|
render?: boolean;
|
|
37
|
-
transition?: boolean;
|
|
38
78
|
history?;
|
|
79
|
+
transition?: boolean;
|
|
39
80
|
route?: string;
|
|
40
81
|
rendered?: (state: T) => void;
|
|
41
|
-
mounted?: (props: any, children: any
|
|
82
|
+
mounted?: (props: any, children: any, state: T) => T;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export type CustomElementOptions = {
|
|
86
|
+
render?: boolean;
|
|
87
|
+
shadow?: boolean;
|
|
88
|
+
history?: boolean;
|
|
89
|
+
global_event?: boolean;
|
|
90
|
+
observedAttributes?: string[];
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type ComponentRoute = {
|
|
94
|
+
[route: string]: any;
|
|
42
95
|
};
|
|
43
96
|
|
|
44
97
|
export interface IApp {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
off(name: string, fn: (...args: any[]) => void): void;
|
|
98
|
+
// Event system methods
|
|
99
|
+
on(name: string, fn: (...args: any[]) => any, options?: EventOptions): void;
|
|
100
|
+
once(name: string, fn: (...args: any[]) => any, options?: EventOptions): void;
|
|
101
|
+
off(name: string, fn: (...args: any[]) => any): void;
|
|
50
102
|
find(name: string): any;
|
|
51
103
|
run(name: string, ...args: any[]): number;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
104
|
+
runAsync(name: string, ...args: any[]): Promise<any[]>;
|
|
105
|
+
|
|
106
|
+
/** @deprecated Use runAsync() instead. query() will be removed in a future version. */
|
|
107
|
+
query(name: string, ...args: any[]): Promise<any[]>;
|
|
108
|
+
|
|
109
|
+
start<T, E = any>(element?: Element | string, model?: T, view?: View<T>, update?: Update<T, E>,
|
|
110
|
+
options?: AppStartOptions<T>): Component<T, E>;
|
|
111
|
+
|
|
112
|
+
h(tag: string | Function, props?: any, ...children: any[]): VNode | VNode[];
|
|
113
|
+
createElement(tag: string | Function, props?: any, ...children: any[]): VNode | VNode[];
|
|
114
|
+
render(element: Element | ShadowRoot, node: VNode, component?: {}): void;
|
|
115
|
+
Fragment(props: any, ...children: any[]): any[];
|
|
116
|
+
|
|
117
|
+
route: Router;
|
|
118
|
+
basePath?: string;
|
|
119
|
+
addComponents: (element: Element | string, components: ComponentRoute) => void;
|
|
120
|
+
|
|
121
|
+
webComponent(name: string, componentClass: any, options?: CustomElementOptions): void;
|
|
60
122
|
safeHTML(html: string): any[];
|
|
61
|
-
use_render(render, mode?: 0 | 1);
|
|
62
|
-
use_react(React, ReactDOM);
|
|
123
|
+
use_render(render: any, mode?: 0 | 1): void;
|
|
124
|
+
use_react(React: any, ReactDOM: any): void;
|
|
63
125
|
version: string;
|
|
64
126
|
}
|
|
65
127
|
|
|
66
128
|
export class Component<T = any, E = any> {
|
|
67
|
-
constructor(state?: T, view?: View<T>, update?: Update<T, E
|
|
129
|
+
constructor(state?: T, view?: View<T>, update?: Update<T, E>, options?: any);
|
|
130
|
+
readonly element: Element;
|
|
68
131
|
readonly state: T;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
132
|
+
view?: View<T>;
|
|
133
|
+
update?: Update<T, E>;
|
|
134
|
+
|
|
135
|
+
// Lifecycle hooks
|
|
136
|
+
rendered?: (state: T) => void;
|
|
137
|
+
mounted?: (props: any, children: any[], state: T) => T | void;
|
|
138
|
+
unload?: (state: T) => void;
|
|
139
|
+
|
|
140
|
+
// Component lifecycle methods
|
|
141
|
+
mount(element?: Element, options?: MountOptions): Component<T, E>;
|
|
142
|
+
start(element?: Element, options?: MountOptions): Component<T, E>;
|
|
143
|
+
unmount(): void;
|
|
144
|
+
|
|
145
|
+
// State management
|
|
146
|
+
setState(state: T, options?: ActionOptions & EventOptions): void;
|
|
147
|
+
|
|
148
|
+
// Event system
|
|
149
|
+
on(event: E, fn: (...args: any[]) => void, options?: EventOptions): void;
|
|
150
|
+
run(event: E, ...args: any[]): any;
|
|
151
|
+
runAsync(event: E, ...args: any[]): Promise<any[]>;
|
|
152
|
+
|
|
153
|
+
/** @deprecated Use runAsync() instead. query() will be removed in a future version. */
|
|
154
|
+
query(event: E, ...args: any[]): Promise<any[]>;
|
|
155
|
+
|
|
156
|
+
// Action management
|
|
157
|
+
add_action(name: string, action: Action<T>, options?: ActionOptions): void;
|
|
158
|
+
is_global_event(name: string): boolean;
|
|
80
159
|
}
|
|
81
160
|
|
|
82
161
|
export function on<E>(name?: E, options?: EventOptions): any;
|
|
83
|
-
// obsolete
|
|
84
|
-
export function update<E>(name?: E, options?: EventOptions): any;
|
|
85
|
-
export function event<E>(name?: E, options?: EventOptions): any;
|
|
86
162
|
export function customElement(name: string, options?: CustomElementOptions):
|
|
87
163
|
<T extends { new(...args: any[]): {} }>(constructor: T) => T;
|
|
88
164
|
|
|
89
|
-
|
|
165
|
+
// Deprecated exports (kept for backward compatibility)
|
|
166
|
+
/** @deprecated Use on() instead */
|
|
167
|
+
export function update<E>(name?: E, options?: EventOptions): any;
|
|
168
|
+
/** @deprecated Use on() instead */
|
|
169
|
+
export function event<E>(name?: E, options?: EventOptions): any;
|
|
170
|
+
|
|
171
|
+
export const app: IApp;
|
|
90
172
|
export default app;
|
|
91
173
|
export const App: IApp;
|
|
92
174
|
|
|
93
175
|
export const ROUTER_EVENT: string;
|
|
94
176
|
export const ROUTER_404_EVENT: string;
|
|
95
|
-
export const safeHTML;
|
|
96
|
-
export function Fragment(props, ...children): [];
|
|
177
|
+
export const safeHTML: (html: string) => any[];
|
|
178
|
+
export function Fragment(props: any, ...children: any[]): any[];
|
|
97
179
|
}
|
|
98
180
|
|
|
99
181
|
declare namespace JSX {
|
|
@@ -104,5 +186,13 @@ declare namespace JSX {
|
|
|
104
186
|
|
|
105
187
|
declare module 'apprun/react' {
|
|
106
188
|
import { Component } from 'apprun';
|
|
107
|
-
export default function toReact(componentClass: Component): Function;
|
|
189
|
+
export default function toReact<T = any>(componentClass: Component<T>): Function;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
declare module 'apprun/createState' {
|
|
193
|
+
type Draft<T> = T;
|
|
194
|
+
export default function createState<T = any>(
|
|
195
|
+
state: T,
|
|
196
|
+
updater: (draft: Draft<T>) => void
|
|
197
|
+
): Promise<T> | T;
|
|
108
198
|
}
|
package/cli/app.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const { app, html } = window["apprun"];
|
|
2
|
+
|
|
3
|
+
// Routing (component event)
|
|
4
|
+
class Home extends Component {
|
|
5
|
+
view = () => html`<div>Home</div>`;
|
|
6
|
+
update = { '/, /home': state => state };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
class Contact extends Component {
|
|
10
|
+
view = () => html`<div>Contact</div>`;
|
|
11
|
+
update = { '/contact': state => state };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class About extends Component {
|
|
15
|
+
view = () => html`<div>About</div>`;
|
|
16
|
+
update = { '/about': state => state };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const App = () => html`<div id="menus">
|
|
20
|
+
<a href="/home">Home</a> |
|
|
21
|
+
<a href="/contact">Contact</a> |
|
|
22
|
+
<a href="/about">About</a></div>
|
|
23
|
+
<div id="pages"></div>
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
// app.basePath = '/'; // Uncomment this line if you want to set a base path for routing
|
|
27
|
+
app.start('#app', {}, App);
|
|
28
|
+
|
|
29
|
+
[About, Contact, Home].map(C => new C().start('pages'));
|
package/cli/index.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>AppRun App</title>
|
|
7
|
+
<script src="https://unpkg.com/apprun/dist/apprun-html.js"></script>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="app.js"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { program } = require('commander');
|
|
4
|
-
const { existsSync, writeFileSync, mkdirSync } = require('fs');
|
|
4
|
+
const { existsSync, writeFileSync, mkdirSync, copyFileSync } = require('fs');
|
|
5
5
|
const { resolve, dirname } = require('path');
|
|
6
|
-
const { red, green, yellow } = require('./
|
|
6
|
+
const { red, green, yellow } = require('./colors');
|
|
7
|
+
const execSync = require('child_process').execSync;
|
|
7
8
|
|
|
8
9
|
const component_template = `import {app, Component} from 'apprun';
|
|
9
10
|
|
|
@@ -26,31 +27,28 @@ import #name from './#fn';
|
|
|
26
27
|
describe('component', () => {
|
|
27
28
|
it('should render state upon route event', () => {
|
|
28
29
|
const element = document.createElement('div');
|
|
29
|
-
const component = new #name().
|
|
30
|
-
//app.run('/#name');
|
|
31
|
-
component.run('.');
|
|
30
|
+
const component = new #name().start(element);
|
|
32
31
|
expect(element.textContent).toBe('#name');
|
|
33
32
|
})
|
|
34
33
|
})
|
|
35
34
|
`;
|
|
36
35
|
|
|
37
36
|
program
|
|
38
|
-
.version('3.
|
|
37
|
+
.version('3.36.0')
|
|
39
38
|
.description('AppRun CLI')
|
|
40
39
|
.option('-i, --init', 'Initialize AppRun Project')
|
|
41
40
|
.option('-c, --component <name>', 'Create a component')
|
|
42
41
|
.option('-t, --test <name>', 'Create a component spec')
|
|
43
42
|
.option('-p, --pages [directory]', 'Create example pages')
|
|
44
43
|
|
|
45
|
-
|
|
46
44
|
program.parse(process.argv);
|
|
47
45
|
|
|
48
46
|
const options = program.opts();
|
|
49
47
|
if (options.init) {
|
|
50
|
-
|
|
51
|
-
return;
|
|
48
|
+
execSync('npm create apprun-app@latest', { stdio: 'inherit' });
|
|
52
49
|
}
|
|
53
50
|
|
|
51
|
+
|
|
54
52
|
function createTestFile(fn, name) {
|
|
55
53
|
const component_name = name || fn.split('/').pop();
|
|
56
54
|
const component_file = fn.split('/').pop();
|
|
@@ -95,8 +93,4 @@ if (options.pages) {
|
|
|
95
93
|
createTestFile(`${pages}/About/index`, 'About');
|
|
96
94
|
createComponent(`${pages}/Contact/index`, 'Contact');
|
|
97
95
|
createTestFile(`${pages}/Contact/index`, 'Contact');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
96
|
+
}
|