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.
Files changed (93) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +143 -25
  3. package/WHATSNEW.md +29 -12
  4. package/apprun-book.jpg +0 -0
  5. package/apprun.d.ts +136 -46
  6. package/cli/app.js +29 -0
  7. package/cli/index.html +13 -0
  8. package/{apprun-cli.js → cli/index.js} +8 -14
  9. package/dist/apprun-code.js +2 -0
  10. package/dist/apprun-code.js.map +1 -0
  11. package/dist/apprun-dev-tools.js +1 -2
  12. package/dist/apprun-dev-tools.js.map +1 -1
  13. package/dist/apprun-html.esm.js +7 -7
  14. package/dist/apprun-html.esm.js.map +1 -1
  15. package/dist/apprun-html.js +1 -1
  16. package/dist/apprun-html.js.map +1 -1
  17. package/dist/apprun-play-html.esm.js +7 -7
  18. package/dist/apprun-play-html.esm.js.map +1 -1
  19. package/dist/apprun-play.js +1 -1
  20. package/dist/apprun-play.js.map +1 -1
  21. package/dist/apprun.esm.js +1 -1
  22. package/dist/apprun.esm.js.map +1 -1
  23. package/dist/apprun.js +1 -1
  24. package/dist/apprun.js.map +1 -1
  25. package/dist/createState.js +2 -0
  26. package/dist/createState.js.map +1 -0
  27. package/esm/add-components.js +90 -0
  28. package/esm/add-components.js.map +1 -0
  29. package/esm/app.js +15 -8
  30. package/esm/app.js.map +1 -1
  31. package/esm/apprun-code.js +51 -16
  32. package/esm/apprun-code.js.map +1 -1
  33. package/esm/apprun-dev-tools.js +32 -32
  34. package/esm/apprun-dev-tools.js.map +1 -1
  35. package/esm/apprun-play.js +50 -17
  36. package/esm/apprun-play.js.map +1 -1
  37. package/esm/apprun.js +42 -11
  38. package/esm/apprun.js.map +1 -1
  39. package/esm/component.js +17 -20
  40. package/esm/component.js.map +1 -1
  41. package/esm/createState.js +9 -0
  42. package/esm/createState.js.map +1 -0
  43. package/esm/decorator.js.map +1 -1
  44. package/esm/directive.js +1 -1
  45. package/esm/directive.js.map +1 -1
  46. package/esm/router.js +241 -18
  47. package/esm/router.js.map +1 -1
  48. package/esm/shadow.js +1 -1
  49. package/esm/shadow.js.map +1 -1
  50. package/esm/type-utils.js +2 -3
  51. package/esm/type-utils.js.map +1 -1
  52. package/esm/vdom-my-new.js +327 -0
  53. package/esm/vdom-my-new.js.map +1 -0
  54. package/esm/vdom-my-prop-attr.js +227 -0
  55. package/esm/vdom-my-prop-attr.js.map +1 -0
  56. package/esm/vdom-my.js +114 -150
  57. package/esm/vdom-my.js.map +1 -1
  58. package/esm/vdom-patch.js +1 -1
  59. package/esm/vdom-patch.js.map +1 -1
  60. package/esm/version.js +1 -1
  61. package/esm/web-component.js +3 -4
  62. package/esm/web-component.js.map +1 -1
  63. package/index.html +5 -2
  64. package/jest.config.js +2 -2
  65. package/jest.setup.js +29 -3
  66. package/jsx-runtime.js +1 -1
  67. package/jsx-runtime.js.map +1 -1
  68. package/package.json +14 -14
  69. package/src/add-components.ts +103 -0
  70. package/src/app.ts +10 -19
  71. package/src/apprun-code.tsx +48 -10
  72. package/src/apprun-dev-tools.tsx +23 -27
  73. package/src/apprun-play.tsx +46 -9
  74. package/src/apprun.ts +49 -40
  75. package/src/component.ts +15 -8
  76. package/src/createState.ts +11 -0
  77. package/src/decorator.ts +2 -1
  78. package/src/router.ts +261 -17
  79. package/src/shadow.tsx +1 -1
  80. package/src/tsconfig.json +2 -2
  81. package/src/types.ts +62 -2
  82. package/src/vdom-my-new.ts +311 -0
  83. package/src/vdom-my-prop-attr.ts +241 -0
  84. package/src/vdom-my.ts +109 -134
  85. package/src/version.ts +1 -1
  86. package/src/web-component.ts +4 -10
  87. package/tsconfig.jest.json +15 -6
  88. package/tsconfig.json +3 -3
  89. package/webpack.config.cjs +3 -1
  90. package/cli/export.js +0 -92
  91. package/cli/import.js +0 -68
  92. package/plan/plan-apprun-bugfixes.md +0 -207
  93. 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 [![Build][travis-image]][travis-url] [![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]
1
+ # AppRun
2
2
 
3
- ## News
3
+ [![AppRun Docs](https://img.shields.io/badge/docs-website-blue.svg)](https://apprun.js.org/docs)
4
+ [![AppRun Playground](https://img.shields.io/badge/playground-online-green.svg)](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 just released [AppRun 3.36.0](https://github.com/yysun/apprun/releases/tag/v3.36.0). See [whats new](WHATSNEW.md) for details.
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 alternative to other frameworks and libraries. 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.
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
- Use a _Counter_ as an example.
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
- * AppRun is lightweight, only 6KB gzipped, but includes state management, rendering, event handling, and routing.
48
+ With [directives](https://apprun.js.org/docs/directives/) syntax sugar you can write more concise code:
38
49
 
39
- * With only three functions: `app.start`, `app.run`, and `app.on` in its API makes it easy to learn and use. And no worries about the incompatibility of version upgrades.
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
- * One more thing, you can [use AppRun with React](https://apprun.js.org/docs/react) to simplify state management and routing of your React applications.
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
- At its core, AppRun harnesses the power of the [event PubsSub]([Publish-Subscribe](https://apprun.js.org/docs/event-pubsub/)) pattern to streamline your application’s state handling and routing. The result? Cleaner, more maintainable code and a smoother development experience.
67
+ // start the app
68
+ app.start(document.body, state, view, update);
69
+ ```
70
+ <apprun-code></apprun-code>
44
71
 
45
- ## AppRun Benefits
72
+ Alternatively, you can invoke state update functions without events for local state updates:
46
73
 
47
- * Clean architecture that needs less code
48
- * State management and routing included
49
- * No proprietary syntax to learn (no hooks, no reducers, no signals)
50
- * Use directly in the browser or with a compiler/bundler
51
- * Advanced features: JSX, Web Components, Dev Tools, SSR, etc.
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
- You can also load AppRun directly from the unpkg.com CDN:
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 view = state => `<div>${state}</div>`;
69
- app.start(document.body, 'hello AppRun', view);
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, or with a compiler/bundler like Webpack or Vite.
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 get started with [AppRun Docs](https://apprun.js.org/docs) and [the AppRun Playground](https://apprun.js.org/#play).
218
+ You can read [AppRun Docs](https://apprun.js.org/docs).
101
219
 
102
220
  ### AppRun Book from Apress
103
221
 
104
- [![Order from Amazon](https://images-na.ssl-images-amazon.com/images/I/51cr-t1pdSL._SX348_BO1,204,203,200_.jpg)](https://www.amazon.com/Practical-Application-Development-AppRun-High-Performance/dp/1484240685/)
222
+ [![Order from Amazon](apprun-book.jpg)](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
- const state = {};
67
- const view = state => html`
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
- async function* getComic() { // async generator function returns loading flag and then the comic object
73
- yield { loading: true };
74
- const response = await fetch('https://my-xkcd-api.glitch.me');
75
- const comic = await response.json();
76
- yield { comic };
77
- }
78
-
79
- app.start(document.body, state, view);
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 => {
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
- export type VDOM = false | string | VNode | Array<VNode | string> | any; // TemplateResult from lit-html
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 Route = (url: string, ...args: any[]) => any;
16
- export type EventOptions<T = any> = {
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
- export type CustomElementOptions = {
60
+
61
+ export type ActionOptions = {
22
62
  render?: boolean;
23
- shadow?: boolean;
24
- history?: boolean;
25
- global_event?: boolean;
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, history?, global_event?: 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[], state: T) => T | void;
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
- start<T, E = any>(element?: Element | string, model?: T, view?: View<T>, update?: Update<T, E>,
46
- options?: AppStartOptions<T>): Component<T, E>;
47
- on(name: string, fn: (...args: any[]) => void, options?: any): void;
48
- once(name: string, fn: (...args: any[]) => void, options?: any): void;
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
- query(name: string, ...args): Promise<any[]>; // obsolete
53
- runAsync(name: string, ...args): Promise<any[]>;
54
- h(tag: string | Function, ...children: any[]): VNode | VNode[];
55
- createElement(tag: string | Function, ...children: any[]): VNode | VNode[];
56
- render(element: Element | string, node: VDOM): void;
57
- Fragment(props: any[], ...children: any[]): any[];
58
- route?: Route;
59
- webComponent(name: string, componentClass, options?: CustomElementOptions): void;
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
- setState(state: T, options?: { render?: boolean, history?: boolean }): void;
70
- mount(element?: Element | string, options?: MountOptions): Component<T, E>;
71
- start(element?: Element | string, options?: MountOptions): Component<T, E>;
72
- on(name: E, fn: (...args: any[]) => void, options?: any): void;
73
- run(name: E, ...args: any[]): number;
74
- query(name: string, ...args): Promise<any[]>; // obsolete
75
- runAsync(name: string, ...args): Promise<any[]>;
76
- rendered: (state: T) => void;
77
- mounted: (props: any, children: any[], state: T) => T | void;
78
- unmount: () => void;
79
- unload: (state: T) => void;
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
- export const app: IApp
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('./cli/colors');
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().mount(element);
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.0.0')
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
- console.log(`\nPlease use ${yellow('npm create apprun-app')} to create AppRun projects.\n`);
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
+ }