apprun 3.33.9 → 3.35.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 (71) hide show
  1. package/.clinerules +1 -0
  2. package/LICENSE +1 -1
  3. package/README.md +1 -1
  4. package/WHATSNEW.md +106 -0
  5. package/apprun.d.ts +7 -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 +21 -4
  9. package/dist/apprun-html.esm.js.map +1 -1
  10. package/dist/apprun-html.js +1 -1
  11. package/dist/apprun-html.js.LICENSE.txt +6 -0
  12. package/dist/apprun-html.js.map +1 -1
  13. package/dist/apprun-play-html.esm.js +21 -4
  14. package/dist/apprun-play-html.esm.js.map +1 -1
  15. package/dist/apprun-play.js +1 -1
  16. package/dist/apprun-play.js.map +1 -1
  17. package/dist/apprun.esm.js +1 -1
  18. package/dist/apprun.esm.js.map +1 -1
  19. package/dist/apprun.js +1 -1
  20. package/dist/apprun.js.map +1 -1
  21. package/esm/app.js +38 -10
  22. package/esm/app.js.map +1 -1
  23. package/esm/apprun-code.js.map +1 -1
  24. package/esm/apprun-dev-tools-tests.js.map +1 -1
  25. package/esm/apprun-dev-tools.js.map +1 -1
  26. package/esm/apprun-html.js.map +1 -1
  27. package/esm/apprun-play.js.map +1 -1
  28. package/esm/apprun.js +65 -9
  29. package/esm/apprun.js.map +1 -1
  30. package/esm/component.js +59 -1
  31. package/esm/component.js.map +1 -1
  32. package/esm/decorator.js +33 -0
  33. package/esm/decorator.js.map +1 -1
  34. package/esm/directive.js +31 -0
  35. package/esm/directive.js.map +1 -1
  36. package/esm/router.js +27 -0
  37. package/esm/router.js.map +1 -1
  38. package/esm/types.js +28 -0
  39. package/esm/types.js.map +1 -1
  40. package/esm/vdom-lit-html.js +19 -17
  41. package/esm/vdom-lit-html.js.map +1 -1
  42. package/esm/vdom-my.js.map +1 -1
  43. package/esm/vdom-patch.js.map +1 -1
  44. package/esm/vdom-to-html.js.map +1 -1
  45. package/esm/vdom.js +24 -0
  46. package/esm/vdom.js.map +1 -1
  47. package/esm/web-component.js +32 -0
  48. package/esm/web-component.js.map +1 -1
  49. package/index.html +3 -2
  50. package/jest.config.js +63 -0
  51. package/jest.setup.js +47 -0
  52. package/jsx-runtime.js +1 -1
  53. package/jsx-runtime.js.map +1 -1
  54. package/package.json +16 -43
  55. package/react.js +0 -15
  56. package/rollup.config.js +27 -10
  57. package/src/app.ts +64 -30
  58. package/src/apprun.ts +94 -13
  59. package/src/component.ts +57 -1
  60. package/src/decorator.ts +34 -1
  61. package/src/directive.ts +33 -1
  62. package/src/global.d.ts +22 -0
  63. package/src/router.ts +28 -2
  64. package/src/types/apprun.d.ts +56 -0
  65. package/src/types.ts +30 -1
  66. package/src/vdom-lit-html.ts +21 -19
  67. package/src/vdom.ts +25 -2
  68. package/src/web-component.ts +33 -0
  69. package/tsconfig.jest.json +27 -3
  70. package/tsconfig.json +3 -3
  71. package/webpack.config.cjs +9 -2
package/src/app.ts CHANGED
@@ -1,28 +1,60 @@
1
- import { EventOptions} from './types'
1
+ /**
2
+ * Core AppRun application class and singleton instance
3
+ *
4
+ * This file provides:
5
+ * 1. App class - The core event system implementation with pub/sub capabilities
6
+ * - on(): Subscribe to events
7
+ * - off(): Unsubscribe from events
8
+ * - run(): Publish events synchronously
9
+ * - runAsync(): Publish events asynchronously
10
+ * - query(): Alias for runAsync
11
+ *
12
+ * 2. Default app singleton - Global event bus instance
13
+ * - Created once and reused across the application
14
+ * - Stored in global scope (window/global)
15
+ * - Version tracked to prevent duplicate instances
16
+ *
17
+ * Usage:
18
+ * ```ts
19
+ * // Subscribe to events
20
+ * app.on('event-name', (state, ...args) => {
21
+ * // Handle event
22
+ * });
23
+ *
24
+ * // Publish events
25
+ * app.run('event-name', ...args);
26
+ * ```
27
+ */
28
+
29
+ import { EventOptions } from './types'
30
+
2
31
  export class App {
3
32
 
4
- _events: Object;
33
+ _events: { [key: string]: Array<{ fn: (...args: any[]) => any, options: EventOptions }> };
34
+
35
+ public start: any;
36
+ public h: any;
37
+ public createElement: any;
38
+ public render: any;
39
+ public Fragment: any;
40
+ public webComponent: any;
41
+ public safeHTML: any;
42
+ public use_render: any;
43
+ public use_react: any;
44
+ public route: any;
5
45
 
6
- public start;
7
- public h;
8
- public createElement;
9
- public render;
10
- public Fragment;
11
- public webComponent;
12
- public safeHTML;
13
- public use_render;
14
- public use_react;
46
+ public version: string;
15
47
 
16
48
  constructor() {
17
- this._events = {};
49
+ this._events = {} as { [key: string]: Array<{ fn: (...args: any[]) => any, options: EventOptions }> };
18
50
  }
19
51
 
20
- on(name: string, fn: (...args) => void, options: EventOptions = {}): void {
52
+ on(name: string, fn: (...args: any[]) => any, options: EventOptions = {}): void {
21
53
  this._events[name] = this._events[name] || [];
22
54
  this._events[name].push({ fn, options });
23
55
  }
24
56
 
25
- off(name: string, fn: (...args) => void): void {
57
+ off(name: string, fn: (...args: any[]) => any): void {
26
58
  const subscribers = this._events[name] || [];
27
59
 
28
60
  this._events[name] = subscribers.filter((sub) => sub.fn !== fn);
@@ -32,7 +64,7 @@ export class App {
32
64
  return this._events[name];
33
65
  }
34
66
 
35
- run(name: string, ...args): number {
67
+ run(name: string, ...args: any[]): number {
36
68
  const subscribers = this.getSubscribers(name, this._events);
37
69
  console.assert(subscribers && subscribers.length > 0, 'No subscriber for event: ' + name);
38
70
  subscribers.forEach((sub) => {
@@ -48,11 +80,11 @@ export class App {
48
80
  return subscribers.length;
49
81
  }
50
82
 
51
- once(name: string, fn, options: EventOptions = {}): void {
83
+ once(name: string, fn: (...args: any[]) => any, options: EventOptions = {}): void {
52
84
  this.on(name, fn, { ...options, once: true });
53
85
  }
54
86
 
55
- private delay(name, fn, args, options): void {
87
+ private delay(name: string, fn: (...args: any[]) => any, args: any[], options: EventOptions): void {
56
88
  if (options._t) clearTimeout(options._t);
57
89
  options._t = setTimeout(() => {
58
90
  clearTimeout(options._t);
@@ -60,7 +92,7 @@ export class App {
60
92
  }, options.delay);
61
93
  }
62
94
 
63
- runAsync(name: string, ...args): Promise<any[]> {
95
+ runAsync(name: string, ...args: any[]): Promise<any[]> {
64
96
  const subscribers = this.getSubscribers(name, this._events);
65
97
  console.assert(subscribers && subscribers.length > 0, 'No subscriber for event: ' + name);
66
98
  const promises = subscribers.map(sub => {
@@ -70,11 +102,11 @@ export class App {
70
102
  return Promise.all(promises);
71
103
  }
72
104
 
73
- query(name: string, ...args): Promise<any[]> {
105
+ query(name: string, ...args: any[]): Promise<any[]> {
74
106
  return this.runAsync(name, ...args);
75
107
  }
76
108
 
77
- private getSubscribers(name: string, events) {
109
+ private getSubscribers(name: string, events: { [key: string]: Array<{ fn: (...args: any[]) => any, options: EventOptions }> }): Array<{ fn: (...args: any[]) => any, options: EventOptions }> {
78
110
  const subscribers = events[name] || [];
79
111
 
80
112
  // Update the list of subscribers by pulling out those which will run once.
@@ -93,15 +125,17 @@ export class App {
93
125
  }
94
126
  }
95
127
 
96
- const AppRunVersions = 'AppRun-3';
97
- let app: App;
98
- const root = (typeof self === 'object' && self.self === self && self) ||
99
- (typeof global === 'object' && global.global === global && global)
100
- if (root['app'] && root['_AppRunVersions']) {
101
- app = root['app'];
128
+ const AppRunVersions = 'AppRun-3.3.11';
129
+ let _app: App;
130
+ const root = (typeof window !== 'undefined' ? window :
131
+ typeof global !== 'undefined' ? global :
132
+ typeof self !== 'undefined' ? self : {}) as any;
133
+
134
+ if (root.app && root._AppRunVersions) {
135
+ _app = root.app;
102
136
  } else {
103
- app = new App();
104
- root['app'] = app;
105
- root['_AppRunVersions'] = AppRunVersions;
137
+ _app = new App();
138
+ root.app = _app;
139
+ root._AppRunVersions = AppRunVersions;
106
140
  }
107
- export default app;
141
+ export default _app;
package/src/apprun.ts CHANGED
@@ -1,3 +1,37 @@
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
11
+ * - Web component support
12
+ *
13
+ * Key exports:
14
+ * - app: Global event system instance
15
+ * - Component: Base component class
16
+ * - Decorators: @on, @update, @customElement
17
+ * - Router events and configuration
18
+ * - Web component registration
19
+ *
20
+ * Usage:
21
+ * ```ts
22
+ * import { app, Component } from 'apprun';
23
+ *
24
+ * // Create components
25
+ * class MyComponent extends Component {
26
+ * state = // Initial state
27
+ * view = state => // Render view
28
+ * update = {
29
+ * 'event': (state, ...args) => // Handle events
30
+ * }
31
+ * }
32
+ * ```
33
+ */
34
+
1
35
  import app, { App } from './app';
2
36
  import { createElement, render, Fragment, safeHTML } from './vdom';
3
37
  import { Component } from './component';
@@ -7,7 +41,26 @@ import webComponent, { CustomElementOptions } from './web-component';
7
41
  import { Route, route, ROUTER_EVENT, ROUTER_404_EVENT } from './router';
8
42
 
9
43
  export type StatelessComponent<T = {}> = (args: T) => string | VNode | void;
10
- export { App, app, Component, View, Action, Update, on, update, EventOptions, ActionOptions, MountOptions, Fragment, safeHTML }
44
+ type OnDecorator = {
45
+ <T = any>(options?: any): (constructor: Function) => void;
46
+ <E = string>(events?: E, options?: any): (target: any, key: string) => void;
47
+ };
48
+
49
+ export {
50
+ App,
51
+ app,
52
+ Component,
53
+ View,
54
+ Action,
55
+ Update,
56
+ on,
57
+ update,
58
+ EventOptions,
59
+ ActionOptions,
60
+ MountOptions,
61
+ Fragment,
62
+ safeHTML
63
+ }
11
64
  export { update as event };
12
65
  export { ROUTER_EVENT, ROUTER_404_EVENT };
13
66
  export { customElement, CustomElementOptions, AppStartOptions };
@@ -32,6 +85,9 @@ export interface IApp {
32
85
  }
33
86
 
34
87
  if (!app.start) {
88
+
89
+ app.version = '3.35.0';
90
+
35
91
  app.h = app.createElement = createElement;
36
92
  app.render = render;
37
93
  app.Fragment = Fragment;
@@ -49,35 +105,60 @@ if (!app.start) {
49
105
  };
50
106
 
51
107
  const NOOP = _ => {/* Intentionally empty */ }
52
- app.on('$', NOOP);
108
+ // app.on('$', NOOP);
53
109
  app.on('debug', _ => NOOP);
54
110
  app.on(ROUTER_EVENT, NOOP);
55
- app.on('#', NOOP);
56
- app['route'] = route;
111
+ app.on(ROUTER_404_EVENT, NOOP);
112
+ app.route = route;
57
113
  app.on('route', url => app['route'] && app['route'](url));
58
114
 
59
115
  if (typeof document === 'object') {
60
116
  document.addEventListener("DOMContentLoaded", () => {
61
- if (app['route'] === route) {
62
- window.onpopstate = () => route(location.hash);
63
- document.body.hasAttribute('apprun-no-init') || app['no-init-route'] || route(location.hash);
117
+ const init_load = document.body.hasAttribute('apprun-no-init') || app['no-init-route'] || false;
118
+ const use_hash = app.find('#') || app.find('#/') || false;
119
+
120
+ // console.log(`AppRun ${app.version} started with ${use_hash ? 'hash' : 'path'} routing. Initial load: ${init_load ? 'disabled' : 'enabled'}.`);
121
+ window.addEventListener('hashchange', () => route(location.hash));
122
+ window.addEventListener('popstate', () => route(location.pathname));
123
+
124
+ if (use_hash) {
125
+ init_load && route(location.hash);
126
+ } else {
127
+ init_load && route(location.pathname);
128
+ document.body.addEventListener('click', e => {
129
+ const element = e.target as HTMLElement;
130
+ const menu = (element.tagName === 'A' ? element : element.closest('a')) as HTMLAnchorElement;
131
+ if (menu &&
132
+ menu.origin === location.origin) {
133
+ e.preventDefault();
134
+ history.pushState(null, '', menu.pathname);
135
+ route(menu.pathname);
136
+ }
137
+ });
64
138
  }
65
139
  });
66
140
  }
67
141
 
142
+ type ComponentType = typeof Component & {
143
+ <T = any>(options?: any): (constructor: Function) => void;
144
+ };
145
+
68
146
  if (typeof window === 'object') {
69
- window['Component'] = Component;
147
+ window['Component'] = Component as ComponentType;
70
148
  window['_React'] = window['React'];
71
149
  window['React'] = app;
72
- window['on'] = on;
150
+ window['on'] = on as OnDecorator;
73
151
  window['customElement'] = customElement;
74
152
  window['safeHTML'] = safeHTML;
75
153
  }
76
154
 
77
- app.use_render = (render, mode = 0) =>
78
- mode === 0 ?
79
- app.render = (el, vdom) => render(vdom, el) : // react style
80
- app.render = (el, vdom) => render(el, vdom); // apprun style
155
+ app.use_render = (render, mode = 0) => {
156
+ if (mode === 0) {
157
+ app.render = (el, vdom) => render(vdom, el); // react style
158
+ } else {
159
+ app.render = (el, vdom) => render(el, vdom); // apprun style
160
+ }
161
+ };
81
162
 
82
163
  app.use_react = (React, ReactDOM) => {
83
164
  app.h = app.createElement = React.createElement;
package/src/component.ts CHANGED
@@ -1,3 +1,36 @@
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
7
+ * - Handles state updates
8
+ * - Supports state history
9
+ *
10
+ * 2. View Rendering
11
+ * - Renders virtual DOM to real DOM
12
+ * - Handles component lifecycle (mounted, rendered, unload)
13
+ * - Supports shadow DOM and web components
14
+ *
15
+ * 3. Event Handling
16
+ * - Local and global event subscription
17
+ * - Event handler registration via decorators
18
+ * - Action to state updates
19
+ *
20
+ * Usage:
21
+ * ```ts
22
+ * class MyComponent extends Component {
23
+ * state = // Initial state
24
+ * view = state => // Return virtual DOM
25
+ * update = {
26
+ * 'event': (state, ...args) => // Return new state
27
+ * }
28
+ * }
29
+ *
30
+ * // Mount component
31
+ * new MyComponent().mount('element-id');
32
+ * ```
33
+ */
1
34
 
2
35
  import app, { App } from './app';
3
36
  import { Reflect } from './decorator'
@@ -79,7 +112,30 @@ export class Component<T = any, E = any> {
79
112
 
80
113
  public setState(state: T, options: ActionOptions & EventOptions
81
114
  = { render: true, history: false }) {
82
- if (state instanceof Promise) {
115
+
116
+ const handleAsyncIterator = async (iterator: AsyncIterator<T>) => {
117
+ try {
118
+ while (true) {
119
+ const { value, done } = await iterator.next();
120
+ if (done) break;
121
+ this.setState(value, options);
122
+ }
123
+ } catch (e) {
124
+ console.error('Error in async iterator:', e);
125
+ }
126
+ };
127
+
128
+ const result = state as any;
129
+ if (result?.[Symbol.asyncIterator]) {
130
+ // handleAsyncIterator(result[Symbol.asyncIterator]());
131
+ this.setState(handleAsyncIterator(result[Symbol.asyncIterator]()) as any, options);
132
+ return;
133
+ } else if (result?.[Symbol.iterator] && typeof result.next === "function") {
134
+ for (const value of result) {
135
+ this.setState(value, options);
136
+ }
137
+ return;
138
+ } else if (state && state instanceof Promise) {
83
139
  // Promise will not be saved or rendered
84
140
  // state will be saved and rendered when promise is resolved
85
141
  Promise.resolve(state).then(v => {
package/src/decorator.ts CHANGED
@@ -1,5 +1,39 @@
1
1
  import webComponent, { CustomElementOptions } from './web-component';
2
2
 
3
+ /**
4
+ * TypeScript Decorators for AppRun Components
5
+ *
6
+ * This file provides decorators that enable:
7
+ * 1. Event Handler Registration
8
+ * - @on(): Subscribe to events with options
9
+ * - @update(): Define state updates with metadata
10
+ *
11
+ * 2. Web Component Integration
12
+ * - @customElement(): Register as custom element with options
13
+ * - Handles shadow DOM and attribute observation
14
+ *
15
+ * 3. Metadata Management
16
+ * - Custom Reflect implementation for decorator metadata
17
+ * - Stores event handler and update metadata
18
+ * - Supports runtime reflection for dynamic behavior
19
+ *
20
+ * Usage:
21
+ * ```ts
22
+ * @customElement('my-element')
23
+ * class MyComponent extends Component {
24
+ * @on('event')
25
+ * handler(state, ...args) {
26
+ * // Handle event
27
+ * }
28
+ *
29
+ * @update('event')
30
+ * updater(state, ...args) {
31
+ * // Update state
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+
3
37
  // tslint:disable:no-invalid-this
4
38
  export const Reflect = {
5
39
 
@@ -44,4 +78,3 @@ export function customElement(name: string, options?: CustomElementOptions) {
44
78
  return constructor;
45
79
  }
46
80
  }
47
-
package/src/directive.ts CHANGED
@@ -1,3 +1,35 @@
1
+ /**
2
+ * Component Directives Implementation
3
+ *
4
+ * This file provides built-in directives for components:
5
+ * 1. Event Binding
6
+ * - $on: Bind DOM events to component events
7
+ * - Supports event delegation and parameters
8
+ * - Handles function, string, and array event handlers
9
+ *
10
+ * 2. Two-way Data Binding
11
+ * - $bind: Sync form elements with component state
12
+ * - Handles input types: text, checkbox, radio, select
13
+ * - Automatic value type conversion
14
+ * - Support for complex property paths
15
+ *
16
+ * 3. Custom Directives
17
+ * - Extensible directive system
18
+ * - Processes virtual DOM during rendering
19
+ * - Supports custom attribute directives
20
+ *
21
+ * Usage:
22
+ * ```tsx
23
+ * // Event binding
24
+ * <button $onclick="event-name">Click</button>
25
+ * <input $oninput={e => setState(e.target.value)} />
26
+ *
27
+ * // Two-way binding
28
+ * <input $bind="state.property" />
29
+ * <select $bind="selected">...</select>
30
+ * ```
31
+ */
32
+
1
33
  import app from './app';
2
34
 
3
35
  const getStateValue = (component, name) => {
@@ -92,4 +124,4 @@ const directive = (vdom, component) => {
92
124
  }
93
125
  }
94
126
 
95
- export default directive;
127
+ export default directive;
@@ -0,0 +1,22 @@
1
+ import { App } from './app';
2
+ import { Component } from './component';
3
+
4
+ declare global {
5
+ var app: App;
6
+ var _AppRunVersions: string;
7
+ interface Window {
8
+ app: App;
9
+ _AppRunVersions: string;
10
+ Component: typeof Component & {
11
+ <T = any>(options?: any): (constructor: Function) => void;
12
+ };
13
+ _React: any;
14
+ React: App;
15
+ on: {
16
+ <T = any>(options?: any): (constructor: Function) => void;
17
+ <E = string>(events?: E, options?: any): (target: any, key: string) => void;
18
+ };
19
+ customElement: (name: string) => (constructor: Function) => void;
20
+ safeHTML: (html: string) => any[];
21
+ }
22
+ }
package/src/router.ts CHANGED
@@ -1,11 +1,37 @@
1
+ /**
2
+ * AppRun Router Implementation
3
+ *
4
+ * This file provides URL routing capabilities:
5
+ * 1. Hash-based routing (#/path)
6
+ * 2. Path-based routing (/path)
7
+ * 3. Event-based navigation
8
+ *
9
+ * Features:
10
+ * - Automatic route event firing
11
+ * - 404 handling via ROUTER_404_EVENT
12
+ * - History API integration
13
+ * - Route parameter parsing
14
+ *
15
+ * Usage:
16
+ * ```ts
17
+ * // Handle routes
18
+ * app.on('#/home', () => // Show home page);
19
+ * app.on('#/users/:id', (id) => // Show user profile);
20
+ *
21
+ * // Navigate programmatically
22
+ * app.run('route', '#/home');
23
+ * ```
24
+ */
25
+
1
26
  import app from './app';
2
27
 
3
28
  export type Route = (url: string, ...args: any[]) => any;
4
29
 
5
30
  export const ROUTER_EVENT: string = '//';
6
31
  export const ROUTER_404_EVENT: string = '///';
7
-
8
32
  export const route: Route = (url: string) => {
33
+ if (app['lastUrl'] === url) return; // Prevent duplicate routing
34
+ app['lastUrl'] = url;
9
35
  if (!url) url = '#';
10
36
  if (url.startsWith('#')) {
11
37
  const [name, ...rest] = url.split('/');
@@ -20,4 +46,4 @@ export const route: Route = (url: string) => {
20
46
  app.run(ROUTER_EVENT, url);
21
47
  }
22
48
  }
23
- export default route;
49
+ export default route;
@@ -0,0 +1,56 @@
1
+ declare type VNode = {
2
+ tag: string;
3
+ props?: Record<string, any>;
4
+ children?: Array<VNode | string | number>;
5
+ } | string | number;
6
+
7
+ declare type VDOM = VNode | VNode[];
8
+
9
+ declare type View<T = any> = (state: T) => VDOM | void;
10
+ declare type Action<T = any> = (state: T, ...p: any[]) => T | void | Promise<T>;
11
+ declare type ActionDef<T = any> = [Action<T>, object?];
12
+ declare type Update<T = any> = { [name: string]: Action<T> | ActionDef<T> | Array<Action<T> | ActionDef<T>> };
13
+
14
+ declare interface IApp {
15
+ start<T>(element?: Element | string | null, model?: T, view?: View<T>, update?: Update<T>, options?: AppStartOptions): Component<T>;
16
+ on(name: string, fn: (...args: any[]) => void, options?: any): void;
17
+ run(name: string, ...args: any[]): void;
18
+ createElement(tag: string | Function, props?: any, ...children: any[]): VNode;
19
+ render(element: Element, node: VNode): void;
20
+ }
21
+
22
+ declare interface Component<T = any> {
23
+ readonly state: T;
24
+ setState(state: T, options?: any): void;
25
+ mount(element?: Element | string | null, options?: any): Component<T>;
26
+ start(element?: Element | string | null, options?: any): Component<T>;
27
+ run(name: string, ...args: any[]): void;
28
+ rendered?: (state: T) => void;
29
+ view?: View<T>;
30
+ update?: Update<T>;
31
+ element?: Element;
32
+ }
33
+
34
+ declare interface CustomElementOptions {
35
+ render?: boolean;
36
+ shadow?: boolean;
37
+ history?: boolean | { prev: string; next: string };
38
+ global_event?: boolean;
39
+ route?: string;
40
+ }
41
+
42
+ declare interface AppStartOptions extends CustomElementOptions {
43
+ render?: boolean;
44
+ history?: boolean | { prev: string; next: string };
45
+ global_event?: boolean;
46
+ route?: string;
47
+ }
48
+
49
+ declare interface Route {
50
+ (url: string): void;
51
+ push(url: string, notify?: boolean): void;
52
+ }
53
+
54
+ declare const app: IApp;
55
+ declare function on<T = any>(name?: string, options?: any): (target: any, key: string) => void;
56
+ declare function Component<T = any>(options?: any): (constructor: Function) => void;
package/src/types.ts CHANGED
@@ -1,3 +1,32 @@
1
+ /**
2
+ * Core TypeScript Type Definitions
3
+ *
4
+ * This file defines the fundamental types used across AppRun:
5
+ * 1. Component Types
6
+ * - View: Function that renders state to VDOM
7
+ * - Action: Function that updates state
8
+ * - Update: Collection of actions
9
+ *
10
+ * 2. Virtual DOM Types
11
+ * - VNode: Virtual DOM node structure
12
+ * - VDOM: Union of possible VDOM types
13
+ * - Element: DOM element references
14
+ *
15
+ * 3. Configuration Types
16
+ * - EventOptions: Event handler options (once, delay, etc)
17
+ * - ActionOptions: Action behavior options (render, history, etc)
18
+ * - MountOptions: Component mounting options (global events, routing)
19
+ * - AppStartOptions: Application startup configuration
20
+ *
21
+ * Usage:
22
+ * ```ts
23
+ * class MyComponent implements Component<State> {
24
+ * view: View<State>;
25
+ * update: Update<State>;
26
+ * }
27
+ * ```
28
+ */
29
+
1
30
  import { TemplateResult } from 'lit-html';
2
31
  export type Element = HTMLElement | string;
3
32
  export type VNode = {
@@ -31,4 +60,4 @@ export type AppStartOptions<T> = {
31
60
  route?: string;
32
61
  rendered?: (state: T) => void
33
62
  mounted?: (props:any, children:any, state: T) => T
34
- };
63
+ };
@@ -1,9 +1,9 @@
1
1
  import { createElement, updateElement, Fragment } from './vdom-my';
2
2
 
3
3
 
4
- import { render, svg, html, noChange, nothing } from 'lit-html';
5
- import { directive, Directive, Part, PartInfo, PartType, EventPart } from 'lit-html/directive.js';
6
- import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
4
+ import { render, svg, html, noChange, nothing } from 'lit';
5
+ import { directive, Directive, PartInfo, ElementPart, DirectiveResult, EventPart, PartType } from 'lit/directive.js';
6
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
7
7
  import app from './apprun';
8
8
 
9
9
  function _render(element, vdom, parent?) {
@@ -26,32 +26,35 @@ export class RunDirective extends Directive {
26
26
  constructor(partInfo: PartInfo) {
27
27
  super(partInfo);
28
28
  // When necessary, validate part in constructor using `part.type`
29
- if (partInfo.type !== PartType.EVENT) {
30
- throw new Error('${run} can only be used in event handlers');
29
+ if (partInfo.type !== PartType.EVENT) { // In lit v3, use PartType.EVENT
30
+ throw new Error('run() can only be used in event handlers');
31
31
  }
32
32
  }
33
- // Optional: override update to perform any direct DOM manipulation
34
- update(part: Part, params) {
33
+ // Override update to perform any direct DOM manipulation
34
+ update(part: EventPart, props: Array<any>): DirectiveResult {
35
35
  /* Any imperative updates to DOM/parts would go here */
36
-
37
- let { element, name } = part as EventPart;
36
+ const element = part.element;
37
+ const name = part.name;
38
+ const [eventOrFn, ...args] = props;
39
+
38
40
  const getComponent = () => {
39
- let component = element['_component'];
40
- while (!component && element) {
41
- element = element.parentElement;
42
- component = element && element['_component'];
41
+ let el = element;
42
+ let component = el['_component'];
43
+ while (!component && el) {
44
+ el = el.parentElement;
45
+ component = el && el['_component'];
43
46
  }
44
47
  console.assert(!!component, 'Component not found.');
45
48
  return component;
46
49
  }
47
- const [event, ...args] = params;
48
- if (typeof event === 'string') {
50
+
51
+ if (typeof eventOrFn === 'string') {
49
52
  element[`on${name}`] = e => {
50
53
  const component = getComponent();
51
- component ? component.run(event, ...args, e) : app.run(event, ...args, e)
54
+ component ? component.run(eventOrFn, ...args, e) : app.run(eventOrFn, ...args, e)
52
55
  }
53
- } else if (typeof event === 'function') {
54
- element[`on${name}`] = e => getComponent().setState(event(getComponent().state, ...args, e));
56
+ } else if (typeof eventOrFn === 'function') {
57
+ element[`on${name}`] = e => getComponent().setState(eventOrFn(getComponent().state, ...args, e));
55
58
  }
56
59
  return this.render();
57
60
  }
@@ -62,4 +65,3 @@ export class RunDirective extends Directive {
62
65
 
63
66
  const run = directive(RunDirective) as any;
64
67
  export { createElement, Fragment, html, svg, _render as render, run };
65
-