apprun 3.38.0 → 6.0.0-rc.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 (113) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +18 -10
  3. package/apprun.d.ts +67 -23
  4. package/dist/apprun-code.js +1 -1
  5. package/dist/apprun-code.js.map +1 -1
  6. package/dist/apprun-dev-tools.js +1 -1
  7. package/dist/apprun-dev-tools.js.map +1 -1
  8. package/dist/apprun-html.esm.js +7 -7
  9. package/dist/apprun-html.esm.js.map +1 -1
  10. package/dist/apprun-html.js +1 -1
  11. package/dist/apprun-html.js.map +1 -1
  12. package/dist/apprun-play.js +1 -1
  13. package/dist/apprun-play.js.map +1 -1
  14. package/dist/apprun.esm.js +1 -1
  15. package/dist/apprun.esm.js.map +1 -1
  16. package/dist/apprun.js +1 -1
  17. package/dist/apprun.js.map +1 -1
  18. package/esm/add-components.js +7 -7
  19. package/esm/add-components.js.map +1 -1
  20. package/esm/app.js +81 -32
  21. package/esm/app.js.map +1 -1
  22. package/esm/apprun-code.js +8 -2
  23. package/esm/apprun-code.js.map +1 -1
  24. package/esm/apprun-html.js +14 -9
  25. package/esm/apprun-html.js.map +1 -1
  26. package/esm/apprun-play.js +7 -1
  27. package/esm/apprun-play.js.map +1 -1
  28. package/esm/apprun.js +38 -19
  29. package/esm/apprun.js.map +1 -1
  30. package/esm/component.js +90 -37
  31. package/esm/component.js.map +1 -1
  32. package/esm/directive.js +1 -1
  33. package/esm/directive.js.map +1 -1
  34. package/esm/router.js +73 -19
  35. package/esm/router.js.map +1 -1
  36. package/esm/types.js +2 -1
  37. package/esm/types.js.map +1 -1
  38. package/esm/vdom-my.js +52 -52
  39. package/esm/vdom-my.js.map +1 -1
  40. package/esm/vdom-to-html.js +8 -1
  41. package/esm/vdom-to-html.js.map +1 -1
  42. package/esm/vdom.js +3 -3
  43. package/esm/vdom.js.map +1 -1
  44. package/esm/version.js +1 -1
  45. package/esm/version.js.map +1 -1
  46. package/esm/web-component.js +23 -6
  47. package/esm/web-component.js.map +1 -1
  48. package/jsx-runtime.js +1 -1
  49. package/jsx-runtime.js.map +1 -1
  50. package/package.json +62 -2
  51. package/.clinerules +0 -1
  52. package/.travis.yml +0 -10
  53. package/BACKERS.md +0 -8
  54. package/CNAME +0 -1
  55. package/WHATSNEW.md +0 -367
  56. package/ai/apprun-html.prompt.md +0 -290
  57. package/ai/apprun.prompt.md +0 -602
  58. package/apprun-book.jpg +0 -0
  59. package/dist/apprun-dev-tools-tests.js +0 -1
  60. package/dist/apprun-dev-tools.js.LICENSE.txt +0 -1
  61. package/dist/apprun-play-html.esm.js +0 -34
  62. package/dist/apprun-play-html.esm.js.map +0 -1
  63. package/error.log +0 -0
  64. package/esm/apprun-play-html.js +0 -210
  65. package/esm/apprun-play-html.js.map +0 -1
  66. package/esm/shadow.js +0 -8
  67. package/esm/shadow.js.map +0 -1
  68. package/esm/vdom-html.js +0 -22
  69. package/esm/vdom-html.js.map +0 -1
  70. package/esm/vdom-my-new.js +0 -327
  71. package/esm/vdom-my-new.js.map +0 -1
  72. package/esm/vdom-patch.js +0 -103
  73. package/esm/vdom-patch.js.map +0 -1
  74. package/index.html +0 -87
  75. package/jest.config.js +0 -57
  76. package/jest.setup.js +0 -73
  77. package/logo.png +0 -0
  78. package/react.js +0 -13
  79. package/rollup.config.js +0 -62
  80. package/src/add-components.ts +0 -103
  81. package/src/app.ts +0 -173
  82. package/src/apprun-code.tsx +0 -177
  83. package/src/apprun-dev-tools-tests.tsx +0 -101
  84. package/src/apprun-dev-tools.tsx +0 -307
  85. package/src/apprun-html.ts +0 -25
  86. package/src/apprun-play.tsx +0 -249
  87. package/src/apprun.ts +0 -238
  88. package/src/component.ts +0 -388
  89. package/src/createState.ts +0 -11
  90. package/src/decorator.ts +0 -98
  91. package/src/directive.ts +0 -303
  92. package/src/global.d.ts +0 -22
  93. package/src/router.ts +0 -311
  94. package/src/shadow.tsx +0 -8
  95. package/src/tsconfig.json +0 -16
  96. package/src/type-utils.ts +0 -130
  97. package/src/types.ts +0 -151
  98. package/src/vdom-html.ts_ +0 -20
  99. package/src/vdom-lit-html.ts +0 -67
  100. package/src/vdom-my-new.ts +0 -311
  101. package/src/vdom-my-prop-attr.ts +0 -241
  102. package/src/vdom-my.ts +0 -286
  103. package/src/vdom-patch.ts +0 -108
  104. package/src/vdom-to-html.tsx +0 -49
  105. package/src/vdom.ts +0 -28
  106. package/src/version.ts +0 -16
  107. package/src/web-component.ts +0 -154
  108. package/tsconfig.jest.json +0 -49
  109. package/tsconfig.json +0 -16
  110. package/tslint.json +0 -114
  111. package/typescriptreact.json +0 -87
  112. package/viewEngine.js +0 -54
  113. package/webpack.config.cjs +0 -41
package/src/apprun.ts DELETED
@@ -1,238 +0,0 @@
1
- /**
2
- * Main AppRun framework entry point
3
- *
4
- * This file:
5
- * 1. Assembles core AppRun modules into a complete framework
6
- * 2. Exports public API and types
7
- * 3. Initializes global app instance with:
8
- * - Virtual DOM rendering
9
- * - Component system
10
- * - Router with improved null safety
11
- * - Web component support
12
- * - Type-safe React integration
13
- * - Component batch mounting system
14
- *
15
- * Key exports:
16
- * - app: Global event system instance
17
- * - Component: Base component class
18
- * - Decorators: @on, @update, @customElement
19
- * - Router events and configuration
20
- * - Web component registration
21
- *
22
- * Features:
23
- * - Event-driven architecture with pub/sub pattern
24
- * - Virtual DOM rendering with multiple renderer support
25
- * - Component lifecycle management
26
- * - Client-side routing with hash/path support
27
- * - Web Components integration
28
- * - React compatibility layer
29
- * - TypeScript support with strong typing
30
- * - Batch component mounting with addComponents(element, components)
31
- *
32
- * Type Safety Improvements (v3.35.1):
33
- * - Added null checks for DOM event targets
34
- * - Improved global window object assignments with proper typing
35
- * - Enhanced React integration parameter validation
36
- * - Better error handling for invalid event handlers
37
- * - Safer element access with proper type assertions
38
- *
39
- * Recent Changes:
40
- * - Modified addComponents to accept (element, components) where components is a key-value object with routes as keys and components as values
41
- * - Simplified component mounting API for better usability
42
- *
43
- * Usage:
44
- * ```ts
45
- * import { app, Component } from 'apprun';
46
- *
47
- * // Create components
48
- * class MyComponent extends Component {
49
- * state = // Initial state
50
- * view = state => // Render view
51
- * update = {
52
- * 'event': (state, ...args) => // Handle events
53
- * }
54
- * }
55
- *
56
- * // Mount multiple components
57
- * app.addComponents(document.body, {
58
- * '/home': MyComponent,
59
- * '/about': AnotherComponent
60
- * });
61
- * ```
62
- */
63
-
64
- import _app, { App } from './app';
65
- import { createElement, render, Fragment, safeHTML } from './vdom';
66
- import { Component } from './component';
67
- import { IApp, VNode, State, View, Action, Update, EventOptions, ActionOptions, MountOptions, AppStartOptions, CustomElementOptions } from './types';
68
- import { on, update, customElement } from './decorator';
69
- import { route, ROUTER_EVENT, ROUTER_404_EVENT } from './router';
70
- import webComponent from './web-component';
71
- import addComponents from './add-components';
72
- import { APPRUN_VERSION } from './version';
73
-
74
- export type StatelessComponent<T = {}> = (args: T) => string | VNode | void;
75
- type OnDecorator = {
76
- <T = unknown>(options?: any): (constructor: Function) => void;
77
- <E = string>(events?: E, options?: any): (target: any, key: string) => void;
78
- };
79
-
80
- const app: IApp = _app as unknown as IApp;
81
- export default app as IApp;
82
-
83
- export {
84
- App,
85
- app,
86
- Component,
87
- View,
88
- Action,
89
- Update,
90
- on,
91
- update,
92
- EventOptions,
93
- ActionOptions,
94
- MountOptions,
95
- Fragment,
96
- safeHTML
97
- }
98
- export { update as event };
99
- export { ROUTER_EVENT, ROUTER_404_EVENT };
100
- export { customElement, CustomElementOptions, AppStartOptions };
101
-
102
- if (!app.start) {
103
-
104
- app.version = APPRUN_VERSION;
105
-
106
- app.h = app.createElement = createElement;
107
- app.render = render;
108
- app.Fragment = Fragment;
109
- app.webComponent = webComponent;
110
- app.safeHTML = safeHTML;
111
-
112
- app.start = <T, E = unknown>(element?: Element | string, state?: State<T>, view?: View<T>, update?: Update<T, E>,
113
- options?: AppStartOptions<T>): Component<T, E> => {
114
- const opts = { render: true, global_event: true, ...options };
115
- const component = new Component<T, E>(state, view, update);
116
- if (options && options.rendered) component.rendered = options.rendered;
117
- if (options && options.mounted) component.mounted = options.mounted;
118
- component.start(element, opts);
119
- return component;
120
- };
121
-
122
- // Deprecated: app.query is deprecated in favor of app.runAsync
123
- app.query = app.query || app.runAsync;
124
-
125
- const NOOP = _ => {/* Intentionally empty */ }
126
- app.on('/', NOOP);
127
- app.on('debug', _ => NOOP);
128
- app.on(ROUTER_EVENT, NOOP);
129
- app.on(ROUTER_404_EVENT, NOOP);
130
- app.route = route;
131
- app.on('route', url => app['route'] && app['route'](url));
132
-
133
- if (typeof document === 'object') {
134
- document.addEventListener("DOMContentLoaded", () => {
135
- const no_init_route = document.body.hasAttribute('apprun-no-init') || app['no-init-route'] || false;
136
- const use_hash = app.find('#') || app.find('#/') || false;
137
-
138
- // console.log(`AppRun ${app.version} started with ${use_hash ? 'hash' : 'path'} routing. Initial load: ${init_load ? 'disabled' : 'enabled'}.`);
139
- window.addEventListener('hashchange', () => route(location.hash));
140
- window.addEventListener('popstate', () => route(location.pathname));
141
-
142
- if (use_hash) {
143
- !no_init_route && route(location.hash);
144
- } else {
145
- !no_init_route && (() => {
146
- const basePath = app.basePath || '';
147
- let initialPath = location.pathname;
148
-
149
- // Strip base path if present
150
- if (basePath && initialPath.startsWith(basePath)) {
151
- initialPath = initialPath.substring(basePath.length);
152
- if (!initialPath.startsWith('/')) initialPath = '/' + initialPath;
153
- }
154
-
155
- route(initialPath);
156
- })();
157
- document.body.addEventListener('click', e => {
158
- const element = e.target as HTMLElement;
159
- if (!element) return;
160
-
161
- const menu = (element.tagName === 'A' ? element : element.closest('a')) as HTMLAnchorElement;
162
- if (menu &&
163
- menu.origin === location.origin &&
164
- menu.pathname) {
165
- e.preventDefault();
166
-
167
- // Handle base path for navigation
168
- const basePath = app.basePath || '';
169
- const fullPath = basePath + menu.pathname;
170
-
171
- history.pushState(null, '', fullPath);
172
- route(menu.pathname); // Route with relative path (without base path)
173
- }
174
- });
175
- }
176
- });
177
- }
178
-
179
- if (typeof window === 'object') {
180
- const globalWindow = window as any;
181
- globalWindow['Component'] = Component;
182
- globalWindow['_React'] = globalWindow['React'];
183
- globalWindow['React'] = app;
184
- globalWindow['on'] = on as OnDecorator;
185
- globalWindow['customElement'] = customElement;
186
- globalWindow['safeHTML'] = safeHTML;
187
- }
188
-
189
- app.use_render = (render, mode = 0) => {
190
- if (mode === 0) {
191
- app.render = (el, vdom) => render(vdom, el); // react style
192
- } else {
193
- app.render = (el, vdom) => render(el, vdom); // apprun style
194
- }
195
- };
196
-
197
- app.use_react = (React, ReactDOM) => {
198
- if (!React || !ReactDOM) {
199
- console.error('AppRun use_react: React and ReactDOM parameters are required');
200
- return;
201
- }
202
-
203
- if (typeof React.createElement !== 'function') {
204
- console.error('AppRun use_react: Invalid React object - createElement method not found');
205
- return;
206
- }
207
-
208
- if (!React.Fragment) {
209
- console.error('AppRun use_react: Invalid React object - Fragment not found');
210
- return;
211
- }
212
-
213
- app.h = app.createElement = React.createElement;
214
- app.Fragment = React.Fragment;
215
-
216
- // React 18+ uses createRoot API
217
- if (React.version && React.version.startsWith('18')) {
218
- if (!ReactDOM.createRoot || typeof ReactDOM.createRoot !== 'function') {
219
- console.error('AppRun use_react: ReactDOM.createRoot not found in React 18+');
220
- return;
221
- }
222
- app.render = (el, vdom) => {
223
- if (!el || vdom === undefined) return;
224
- if (!(el as any)._root) (el as any)._root = ReactDOM.createRoot(el);
225
- (el as any)._root.render(vdom);
226
- }
227
- } else {
228
- // Legacy React versions
229
- if (!ReactDOM.render || typeof ReactDOM.render !== 'function') {
230
- console.error('AppRun use_react: ReactDOM.render not found in legacy React');
231
- return;
232
- }
233
- app.render = (el, vdom) => ReactDOM.render(vdom, el);
234
- }
235
- }
236
-
237
- app.addComponents = addComponents;
238
- }
package/src/component.ts DELETED
@@ -1,388 +0,0 @@
1
- /**
2
- * AppRun Component System Implementation
3
- *
4
- * This file provides the Component class which is the foundation for:
5
- * 1. State Management
6
- * - Maintains component state with history support
7
- * - Handles state updates with async/iterator support
8
- * - Supports state history navigation (prev/next)
9
- * - Promise and async iterator state handling
10
- *
11
- * 2. View Rendering
12
- * - Renders virtual DOM to real DOM with directives
13
- * - Handles component lifecycle (mounted, rendered, unload)
14
- * - Supports shadow DOM and web components
15
- * - DOM change tracking with MutationObserver
16
- * - View transition API support
17
- *
18
- * 3. Event Handling
19
- * - Local and global event subscription management
20
- * - Event handler registration via decorators
21
- * - Action to state updates with error handling
22
- * - Support for event options (delay, once, global)
23
- *
24
- * Features:
25
- * - Component caching for debugging
26
- * - Element tracking for cleanup
27
- * - History navigation support
28
- * - Global vs local event routing
29
- * - Async state handling
30
- * - Memory leak prevention
31
- * - Component unmounting with cleanup
32
- *
33
- * Type Safety Improvements (v3.35.1):
34
- * - Enhanced element access with null checks and warnings
35
- * - Improved action validation and error handling
36
- * - Better error reporting in component actions
37
- * - Safer DOM element queries with fallback warnings
38
- *
39
- * Usage:
40
- * ```ts
41
- * class MyComponent extends Component {
42
- * state = // Initial state
43
- * view = state => // Return virtual DOM
44
- * update = {
45
- * 'event': (state, ...args) => // Return new state
46
- * }
47
- * }
48
- *
49
- * // Mount component
50
- * new MyComponent().mount('element-id');
51
- * ```
52
- */
53
-
54
- import _app, { App } from './app';
55
-
56
-
57
- import { Reflect } from './decorator'
58
- import { State, View, Update, ActionDef, ActionOptions, MountOptions, EventOptions, IApp } from './types';
59
- import directive from './directive';
60
- import { safeQuerySelector, safeGetElementById } from './type-utils';
61
-
62
- // const componentCache = new Map();
63
- // if (!app.find('get-components')) app.on('get-components', o => o.components = componentCache);
64
-
65
- export const REFRESH = state => state;
66
-
67
- const app = _app as unknown as IApp;
68
-
69
- export class Component<T = unknown, E = unknown> {
70
- static __isAppRunComponent = true;
71
- private _app = new App();
72
- private _actions = [];
73
- private _global_events = [];
74
- private _state;
75
- private _history = [];
76
- private _history_idx = -1;
77
- private enable_history;
78
- private global_event;
79
- public element;
80
- public rendered;
81
- public mounted;
82
- public unload;
83
- private tracking_id;
84
- private observer;
85
-
86
-
87
- private renderState(state: T, vdom = null) {
88
- if (!this.view) return;
89
- let html = vdom || this.view(state);
90
- app['debug'] && app.run('debug', {
91
- component: this,
92
- _: html ? '.' : '-',
93
- state,
94
- vdom: html,
95
- el: this.element
96
- });
97
-
98
- if (typeof document !== 'object') return;
99
-
100
- const el = (typeof this.element === 'string' && this.element) ?
101
- safeGetElementById(this.element) || safeQuerySelector(this.element) : this.element;
102
-
103
- if (!el) {
104
- console.warn(`Component element not found: ${this.element}`);
105
- return;
106
- }
107
- const tracking_attr = '_c';
108
- if (!this.unload) {
109
- el.removeAttribute && el.removeAttribute(tracking_attr);
110
- } else if (el['_component'] !== this || el.getAttribute(tracking_attr) !== this.tracking_id) {
111
- this.tracking_id = new Date().valueOf().toString();
112
- el.setAttribute(tracking_attr, this.tracking_id);
113
- if (typeof MutationObserver !== 'undefined') {
114
- if (!this.observer) this.observer = new MutationObserver(changes => {
115
- if (changes[0].oldValue === this.tracking_id || !document.body.contains(el)) {
116
- this.unload(this.state);
117
- this.observer.disconnect();
118
- this.observer = null;
119
- }
120
- });
121
- this.observer.observe(document.body, {
122
- childList: true, subtree: true,
123
- attributes: true, attributeOldValue: true, attributeFilter: [tracking_attr]
124
- });
125
- }
126
- }
127
- el['_component'] = this;
128
-
129
- if (!vdom && html) {
130
- html = directive(html, this);
131
- if (this.options.transition && document && document['startViewTransition']) {
132
- document['startViewTransition'](() => app.render(el, html, this));
133
- } else {
134
- app.render(el, html, this);
135
- }
136
- }
137
- this.rendered && this.rendered(this.state);
138
- }
139
-
140
- public setState(state: T, options: ActionOptions & EventOptions
141
- = { render: true, history: false }) {
142
-
143
- const handleAsyncIterator = async (iterator: AsyncIterator<T>) => {
144
- try {
145
- while (true) {
146
- const { value, done } = await iterator.next();
147
- if (done) break;
148
- this.setState(value, options);
149
- }
150
- } catch (e) {
151
- console.error('Error in async iterator:', e);
152
- }
153
- };
154
-
155
- const result = state as any;
156
- if (result?.[Symbol.asyncIterator]) {
157
- // handleAsyncIterator(result[Symbol.asyncIterator]());
158
- this.setState(handleAsyncIterator(result[Symbol.asyncIterator]()) as any, options);
159
- return;
160
- } else if (result?.[Symbol.iterator] && typeof result.next === "function") {
161
- for (const value of result) {
162
- this.setState(value, options);
163
- }
164
- return;
165
- } else if (state && state instanceof Promise) {
166
- // Promise will not be saved or rendered
167
- // state will be saved and rendered when promise is resolved
168
- Promise.resolve(state).then(v => {
169
- this.setState(v, options);
170
- this._state = state;
171
- });
172
- } else {
173
- this._state = state;
174
- if (state == null) return;
175
- this.state = state;
176
- if (options.render !== false) {
177
- // before render state
178
- if (options.transition && document && document['startViewTransition']) {
179
- document['startViewTransition'](() => this.renderState(state));
180
- } else {
181
- this.renderState(state);
182
- }
183
- }
184
- if (options.history !== false && this.enable_history) {
185
- this._history = [...this._history, state];
186
- this._history_idx = this._history.length - 1;
187
- }
188
- if (typeof options.callback === 'function') options.callback(this.state);
189
- }
190
- }
191
-
192
- private _history_prev = () => {
193
- this._history_idx--;
194
- if (this._history_idx >= 0) {
195
- this.setState(this._history[this._history_idx], { render: true, history: false });
196
- }
197
- else {
198
- this._history_idx = 0;
199
- }
200
- };
201
-
202
- private _history_next = () => {
203
- this._history_idx++;
204
- if (this._history_idx < this._history.length) {
205
- this.setState(this._history[this._history_idx], { render: true, history: false });
206
- }
207
- else {
208
- this._history_idx = this._history.length - 1;
209
- }
210
- };
211
-
212
- constructor(
213
- protected state?: State<T>,
214
- protected view?: View<T>,
215
- protected update?: Update<T, E>,
216
- protected options?) {
217
- }
218
-
219
- start = (element = null, options?: MountOptions): Component<T, E> => {
220
- this.mount(element, { render: true, ...options });
221
- if (this.mounted && typeof this.mounted === 'function') {
222
- const new_state = this.mounted({}, [], this.state);
223
- (typeof new_state !== 'undefined') && this.setState(new_state);
224
- }
225
- return this;
226
- }
227
-
228
- public mount(element = null, options?: MountOptions): Component<T, E> {
229
- console.assert(!this.element, 'Component already mounted.')
230
- this.options = options = { ...this.options, ...options };
231
- this.element = element;
232
- this.global_event = options.global_event;
233
- this.enable_history = !!options.history;
234
-
235
- if (this.enable_history) {
236
- this.on(options.history.prev || 'history-prev', this._history_prev);
237
- this.on(options.history.next || 'history-next', this._history_next);
238
- }
239
-
240
- if (options.route) {
241
- this.update = this.update || {};
242
- if (!this.update[options.route]) this.update[options.route] = REFRESH;
243
- }
244
-
245
- this.add_actions();
246
- this.state = this.state ?? this['model'] ?? {};
247
- if (typeof this.state === 'function') this.state = (this.state as Function)();
248
- this.setState(this.state as T, { render: !!options.render, history: true });
249
- if (app['debug'] && app.find('debug-create-component')?.length) {
250
- app.run('debug-create-component', this);
251
- }
252
- return this;
253
- }
254
-
255
- is_global_event(name: string): boolean {
256
- return name && (
257
- this.global_event ||
258
- this._global_events.indexOf(name) >= 0 ||
259
- name.startsWith('#') || name.startsWith('/') || name.startsWith('@'));
260
- }
261
-
262
- add_action(name: string, action, options: ActionOptions = {}) {
263
- if (!action || typeof action !== 'function') {
264
- console.warn(`Component action for '${name}' is not a valid function:`, action);
265
- return;
266
- }
267
- if (options.global) this._global_events.push(name);
268
- this.on(name as any, (...p) => {
269
-
270
- app['debug'] && app.run('debug', {
271
- component: this,
272
- _: '>',
273
- event: name, p,
274
- current_state: this.state,
275
- options
276
- });
277
-
278
- try {
279
- const newState = action(this.state, ...p);
280
-
281
- app['debug'] && app.run('debug', {
282
- component: this,
283
- _: '<',
284
- event: name, p,
285
- newState,
286
- state: this.state,
287
- options
288
- });
289
-
290
- this.setState(newState, options);
291
- } catch (error) {
292
- console.error(`Error in component action '${name}':`, error);
293
- app['debug'] && app.run('debug', {
294
- component: this,
295
- _: '!',
296
- event: name, p,
297
- error,
298
- state: this.state,
299
- options
300
- });
301
- }
302
- }, options);
303
- }
304
-
305
- add_actions() {
306
- const actions = this.update || {};
307
- Reflect.getMetadataKeys(this).forEach(key => {
308
- if (key.startsWith('apprun-update:')) {
309
- const meta = Reflect.getMetadata(key, this)
310
- actions[meta.name] = [this[meta.key].bind(this), meta.options];
311
- }
312
- })
313
-
314
- const all = {};
315
- if (Array.isArray(actions)) {
316
- actions.forEach(act => {
317
- const [name, action, opts] = act as ActionDef<T, E>;
318
- const names = name.toString();
319
- names.split(',').forEach(n => all[n.trim()] = [action, opts])
320
- })
321
- } else {
322
- Object.keys(actions).forEach(name => {
323
- const action = actions[name];
324
- if (typeof action === 'function' || Array.isArray(action)) {
325
- name.split(',').forEach(n => all[n.trim()] = action)
326
- }
327
- })
328
- }
329
-
330
- if (!all['.']) all['.'] = REFRESH;
331
- Object.keys(all).forEach(name => {
332
- const action = all[name];
333
- if (typeof action === 'function') {
334
- this.add_action(name, action);
335
- } else if (Array.isArray(action)) {
336
- this.add_action(name, action[0], action[1]);
337
- }
338
- });
339
- }
340
-
341
- public run(event: E, ...args) {
342
- if (this.state instanceof Promise) {
343
- return Promise.resolve(this.state).then(state => {
344
- this.state = state;
345
- this.run(event, ...args)
346
- });
347
- } else {
348
- const name = event.toString();
349
- return this.is_global_event(name) ?
350
- app.run(name, ...args) :
351
- this._app.run(name, ...args);
352
- }
353
- }
354
-
355
- public on(event: E, fn: (...args) => void, options?: any) {
356
- const name = event.toString();
357
- this._actions.push({ name, fn });
358
- return this.is_global_event(name) ?
359
- app.on(name, fn, options) :
360
- this._app.on(name, fn, options);
361
- }
362
-
363
- public runAsync(event: E, ...args) {
364
- const name = event.toString();
365
- return this.is_global_event(name) ?
366
- app.runAsync(name, ...args) :
367
- this._app.runAsync(name, ...args);
368
- }
369
-
370
- // obsolete
371
- /**
372
- * @deprecated Use runAsync() instead. query() will be removed in a future version.
373
- */
374
- public query(event: E, ...args) {
375
- console.warn('component.query() is deprecated. Use component.runAsync() instead.');
376
- return this.runAsync(event, ...args);
377
- }
378
-
379
- public unmount() {
380
- this.observer?.disconnect();
381
- this._actions.forEach(action => {
382
- const { name, fn } = action;
383
- this.is_global_event(name) ?
384
- app.off(name, fn) :
385
- this._app.off(name, fn);
386
- });
387
- }
388
- }
@@ -1,11 +0,0 @@
1
- import { produce, Draft } from 'immer';
2
-
3
- export function createState<T = unknown>(
4
- fn: (draft: Draft<T>, ...args: any[]) => void
5
- ): (state: T, ...args: any[]) => T {
6
- return (state: T, ...args: any[]): T => {
7
- return produce(state, (draft) => {
8
- fn(draft, ...args);
9
- });
10
- };
11
- }