mantle-lit 0.1.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/LICENSE +21 -0
- package/README.md +600 -0
- package/dist/index.cjs +544 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +358 -0
- package/dist/index.d.ts +358 -0
- package/dist/index.js +500 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { TemplateResult, LitElement } from 'lit';
|
|
2
|
+
import { IObservableValue } from 'mobx';
|
|
3
|
+
|
|
4
|
+
/** Options for the watch method */
|
|
5
|
+
interface WatchOptions {
|
|
6
|
+
/** Debounce the callback by N milliseconds */
|
|
7
|
+
delay?: number;
|
|
8
|
+
/** Run callback immediately with current value */
|
|
9
|
+
fireImmediately?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Error context passed to the onError handler
|
|
13
|
+
*/
|
|
14
|
+
interface MantleErrorContext {
|
|
15
|
+
/** The lifecycle phase where the error occurred */
|
|
16
|
+
phase: 'onCreate' | 'onMount' | 'onUnmount' | 'watch';
|
|
17
|
+
/** The View or Behavior class name */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Whether the error came from a Behavior (true) or a View (false) */
|
|
20
|
+
isBehavior: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Global configuration options for mantle-lit
|
|
24
|
+
*/
|
|
25
|
+
interface MantleConfig {
|
|
26
|
+
/** Whether to automatically make View/Behavior instances observable (default: true) */
|
|
27
|
+
autoObservable?: boolean;
|
|
28
|
+
/** Global error handler for lifecycle errors. Defaults to console.error. */
|
|
29
|
+
onError?: (error: unknown, context: MantleErrorContext) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Configure global defaults for mantle-lit.
|
|
33
|
+
* Settings can still be overridden per-view in createView options.
|
|
34
|
+
*/
|
|
35
|
+
declare function configure(config: MantleConfig): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Base class for behaviors. Provides lifecycle method signatures for IDE autocomplete.
|
|
39
|
+
* Extend this class and wrap with createBehavior() to create a factory.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* class WindowSizeBehavior extends Behavior {
|
|
44
|
+
* width = window.innerWidth;
|
|
45
|
+
* onCreate(breakpoint = 768) { ... }
|
|
46
|
+
* onMount() { ... }
|
|
47
|
+
* }
|
|
48
|
+
* export const withWindowSize = createBehavior(WindowSizeBehavior);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare class Behavior {
|
|
52
|
+
/** @internal */
|
|
53
|
+
_watchDisposers: (() => void)[];
|
|
54
|
+
onCreate?(...args: any[]): void;
|
|
55
|
+
onMount?(): void | (() => void);
|
|
56
|
+
onUnmount?(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Watch a reactive expression and run a callback when it changes.
|
|
59
|
+
* Automatically disposed on unmount.
|
|
60
|
+
*
|
|
61
|
+
* @param expr - Reactive expression (getter) to watch
|
|
62
|
+
* @param callback - Called when the expression result changes
|
|
63
|
+
* @param options - Optional configuration (delay, fireImmediately)
|
|
64
|
+
* @returns Dispose function for early teardown
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* onCreate(url: string) {
|
|
69
|
+
* this.url = url;
|
|
70
|
+
* this.watch(() => this.url, () => this.fetchData());
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
watch<T>(expr: () => T, callback: (value: T, prevValue: T | undefined) => void, options?: WatchOptions): () => void;
|
|
75
|
+
/** @internal */
|
|
76
|
+
_disposeWatchers(): void;
|
|
77
|
+
}
|
|
78
|
+
/** @internal */
|
|
79
|
+
interface BehaviorEntry {
|
|
80
|
+
instance: any;
|
|
81
|
+
cleanup?: () => void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Extracts parameter types from onCreate method
|
|
85
|
+
*/
|
|
86
|
+
type OnCreateParams<T> = T extends {
|
|
87
|
+
onCreate(...args: infer A): any;
|
|
88
|
+
} ? A : [];
|
|
89
|
+
/**
|
|
90
|
+
* Extracts constructor parameter types
|
|
91
|
+
*/
|
|
92
|
+
type ConstructorParams<T> = T extends new (...args: infer A) => any ? A : [];
|
|
93
|
+
/**
|
|
94
|
+
* Determines the args for createBehavior:
|
|
95
|
+
* - If constructor has args, use those
|
|
96
|
+
* - Otherwise, if onCreate has args, use those
|
|
97
|
+
*/
|
|
98
|
+
type BehaviorArgs<T extends new (...args: any[]) => any> = ConstructorParams<T> extends [] ? OnCreateParams<InstanceType<T>> : ConstructorParams<T>;
|
|
99
|
+
/**
|
|
100
|
+
* Type that supports both `new` and direct call syntax
|
|
101
|
+
*/
|
|
102
|
+
type BehaviorFactory<Args extends any[], Instance> = {
|
|
103
|
+
new (...args: Args): Instance;
|
|
104
|
+
(...args: Args): Instance;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Creates a behavior factory with automatic observable wrapping and lifecycle management.
|
|
108
|
+
*
|
|
109
|
+
* Returns a factory function (not a class) — use without `new`:
|
|
110
|
+
*
|
|
111
|
+
* @example Defining a behavior
|
|
112
|
+
* ```ts
|
|
113
|
+
* class DragBehavior extends Behavior {
|
|
114
|
+
* ref!: HTMLElement | null;
|
|
115
|
+
*
|
|
116
|
+
* onCreate(ref: HTMLElement | null) {
|
|
117
|
+
* this.ref = ref;
|
|
118
|
+
* }
|
|
119
|
+
*
|
|
120
|
+
* onMount() {
|
|
121
|
+
* this.ref?.addEventListener('pointerdown', this.onPointerDown);
|
|
122
|
+
* return () => this.ref?.removeEventListener('pointerdown', this.onPointerDown);
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
*
|
|
126
|
+
* export const withDrag = createBehavior(DragBehavior);
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @example Using in a View
|
|
130
|
+
* ```ts
|
|
131
|
+
* class Editor extends View<Props> {
|
|
132
|
+
* canvasRef: HTMLCanvasElement | null = null;
|
|
133
|
+
*
|
|
134
|
+
* // No `new` keyword — factory function
|
|
135
|
+
* drag = withDrag(this.canvasRef);
|
|
136
|
+
* }
|
|
137
|
+
* export const EditorElement = createView(Editor, { tag: 'x-editor' });
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* The `with` prefix convention signals that the view manages this behavior's lifecycle.
|
|
141
|
+
*/
|
|
142
|
+
declare function createBehavior<T extends new (...args: any[]) => any>(Def: T, options?: {
|
|
143
|
+
autoObservable?: boolean;
|
|
144
|
+
}): BehaviorFactory<BehaviorArgs<T>, InstanceType<T>>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Decorator context type for TC39 decorators
|
|
148
|
+
*/
|
|
149
|
+
interface DecoratorContext {
|
|
150
|
+
kind: 'field' | 'method' | 'getter' | 'setter' | 'accessor' | 'class';
|
|
151
|
+
name: string | symbol;
|
|
152
|
+
metadata: Record<symbol, unknown>;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Marks a field as observable. No `accessor` keyword needed.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* class Counter extends View {
|
|
160
|
+
* @observable count = 0;
|
|
161
|
+
* }
|
|
162
|
+
* export const CounterElement = createView(Counter, { tag: 'x-counter' });
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
declare function observable(_value: undefined, context: DecoratorContext): void;
|
|
166
|
+
declare namespace observable {
|
|
167
|
+
var ref: (_value: undefined, context: DecoratorContext) => void;
|
|
168
|
+
var shallow: (_value: undefined, context: DecoratorContext) => void;
|
|
169
|
+
var struct: (_value: undefined, context: DecoratorContext) => void;
|
|
170
|
+
var deep: (_value: undefined, context: DecoratorContext) => void;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Marks a method as an action. Auto-bound by default.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* class Counter extends View {
|
|
178
|
+
* @observable count = 0;
|
|
179
|
+
*
|
|
180
|
+
* @action increment() {
|
|
181
|
+
* this.count++;
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* export const CounterElement = createView(Counter, { tag: 'x-counter' });
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
declare function action(_value: Function, context: DecoratorContext): void;
|
|
188
|
+
/**
|
|
189
|
+
* Marks a getter as computed.
|
|
190
|
+
* Note: Getters are automatically computed in autoObservable mode,
|
|
191
|
+
* but this decorator is useful for explicit annotation.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* class Counter extends View {
|
|
196
|
+
* @observable count = 0;
|
|
197
|
+
*
|
|
198
|
+
* @computed get doubled() {
|
|
199
|
+
* return this.count * 2;
|
|
200
|
+
* }
|
|
201
|
+
* }
|
|
202
|
+
* export const CounterElement = createView(Counter, { tag: 'x-counter' });
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
declare function computed(_value: Function, context: DecoratorContext): void;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Base class for Views. Extend this and use createView() to create a custom element.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* import { View, createView } from 'mantle-lit';
|
|
213
|
+
* import { html } from 'lit';
|
|
214
|
+
*
|
|
215
|
+
* class CounterView extends View<{ initial: number }> {
|
|
216
|
+
* count = 0;
|
|
217
|
+
*
|
|
218
|
+
* onCreate() {
|
|
219
|
+
* this.count = this.props.initial;
|
|
220
|
+
* }
|
|
221
|
+
*
|
|
222
|
+
* increment() {
|
|
223
|
+
* this.count++;
|
|
224
|
+
* }
|
|
225
|
+
*
|
|
226
|
+
* render() {
|
|
227
|
+
* return html`
|
|
228
|
+
* <button @click=${this.increment}>
|
|
229
|
+
* Count: ${this.count}
|
|
230
|
+
* </button>
|
|
231
|
+
* `;
|
|
232
|
+
* }
|
|
233
|
+
* }
|
|
234
|
+
*
|
|
235
|
+
* export const Counter = createView(CounterView, { tag: 'x-counter' });
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
declare class View<P extends object = {}> {
|
|
239
|
+
/** @internal */
|
|
240
|
+
_propsBox: IObservableValue<P>;
|
|
241
|
+
/** Access current props (reactive) */
|
|
242
|
+
get props(): P;
|
|
243
|
+
/** @internal — called by the element to update props */
|
|
244
|
+
_syncProps(value: P): void;
|
|
245
|
+
/** @internal */
|
|
246
|
+
_behaviors: BehaviorEntry[];
|
|
247
|
+
/** @internal */
|
|
248
|
+
_watchDisposers: (() => void)[];
|
|
249
|
+
/** @internal - MobX reaction disposer for auto-render */
|
|
250
|
+
_reactionDisposer?: () => void;
|
|
251
|
+
/** @internal - Callback to request a render from the element */
|
|
252
|
+
_requestRender?: () => void;
|
|
253
|
+
onCreate?(): void;
|
|
254
|
+
onMount?(): void | (() => void);
|
|
255
|
+
onUnmount?(): void;
|
|
256
|
+
/**
|
|
257
|
+
* Watch a reactive expression and run a callback when it changes.
|
|
258
|
+
* Automatically disposed on unmount.
|
|
259
|
+
*
|
|
260
|
+
* @param expr - Reactive expression (getter) to watch
|
|
261
|
+
* @param callback - Called when the expression result changes
|
|
262
|
+
* @param options - Optional configuration (delay, fireImmediately)
|
|
263
|
+
* @returns Dispose function for early teardown
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* onCreate() {
|
|
268
|
+
* this.watch(
|
|
269
|
+
* () => this.query,
|
|
270
|
+
* async (query) => {
|
|
271
|
+
* if (query.length > 2) {
|
|
272
|
+
* this.results = await searchApi(query);
|
|
273
|
+
* }
|
|
274
|
+
* },
|
|
275
|
+
* { delay: 300 }
|
|
276
|
+
* );
|
|
277
|
+
* }
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
watch<T>(expr: () => T, callback: (value: T, prevValue: T | undefined) => void, options?: WatchOptions): () => void;
|
|
281
|
+
/** @internal */
|
|
282
|
+
_disposeWatchers(): void;
|
|
283
|
+
/** @internal - Scan own properties for behavior instances and register them */
|
|
284
|
+
_collectBehaviors(): void;
|
|
285
|
+
/** @internal */
|
|
286
|
+
_mountBehaviors(): void;
|
|
287
|
+
/** @internal */
|
|
288
|
+
_unmountBehaviors(): void;
|
|
289
|
+
render?(): TemplateResult | null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
interface CreateViewOptions {
|
|
293
|
+
/** Custom element tag name (required, must contain a hyphen) */
|
|
294
|
+
tag: string;
|
|
295
|
+
/** Whether to automatically make View instances observable (default: true) */
|
|
296
|
+
autoObservable?: boolean;
|
|
297
|
+
/** Whether to use Shadow DOM (default: true). Set to false to render in light DOM. */
|
|
298
|
+
shadow?: boolean;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Creates a Lit custom element from a View class.
|
|
302
|
+
*
|
|
303
|
+
* @param ViewClass - The View class to wrap
|
|
304
|
+
* @param options - Configuration options including the tag name
|
|
305
|
+
* @returns The custom element class (also registers it)
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```ts
|
|
309
|
+
* class CounterView extends View<{ initial: number }> {
|
|
310
|
+
* count = 0;
|
|
311
|
+
*
|
|
312
|
+
* onCreate() {
|
|
313
|
+
* this.count = this.props.initial;
|
|
314
|
+
* }
|
|
315
|
+
*
|
|
316
|
+
* increment() {
|
|
317
|
+
* this.count++;
|
|
318
|
+
* }
|
|
319
|
+
*
|
|
320
|
+
* render() {
|
|
321
|
+
* return html`<button @click=${this.increment}>Count: ${this.count}</button>`;
|
|
322
|
+
* }
|
|
323
|
+
* }
|
|
324
|
+
*
|
|
325
|
+
* export const Counter = createView(CounterView, { tag: 'x-counter' });
|
|
326
|
+
*
|
|
327
|
+
* // Usage in HTML: <x-counter .initial=${5}></x-counter>
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
declare function createView<V extends View<any>>(ViewClass: new () => V, options: CreateViewOptions): typeof LitElement;
|
|
331
|
+
/**
|
|
332
|
+
* Helper type for defining props that will be passed as properties (not attributes).
|
|
333
|
+
* Use with .prop=${value} syntax in Lit templates.
|
|
334
|
+
*/
|
|
335
|
+
type Props<T> = T;
|
|
336
|
+
/**
|
|
337
|
+
* Mount a view to the DOM with props.
|
|
338
|
+
*
|
|
339
|
+
* @param tag - The custom element tag name
|
|
340
|
+
* @param props - Props to pass to the component
|
|
341
|
+
* @param container - DOM element or selector to mount into (default: document.body)
|
|
342
|
+
* @returns The created element
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* import { mount } from 'mantle-lit';
|
|
347
|
+
* import './Todo'; // registers x-todo
|
|
348
|
+
*
|
|
349
|
+
* mount('x-todo', {
|
|
350
|
+
* title: 'My Tasks',
|
|
351
|
+
* initialTodos: [{ id: 1, text: 'Learn mantle', done: false }],
|
|
352
|
+
* onCountChange: (count) => console.log(count)
|
|
353
|
+
* });
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
declare function mount<P extends object>(tag: string, props?: P, container?: Element | string): HTMLElement & P;
|
|
357
|
+
|
|
358
|
+
export { Behavior, type CreateViewOptions, type MantleConfig, type MantleErrorContext, type Props, View, View as ViewModel, type WatchOptions, action, computed, configure, createBehavior, createView, mount, observable };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { TemplateResult, LitElement } from 'lit';
|
|
2
|
+
import { IObservableValue } from 'mobx';
|
|
3
|
+
|
|
4
|
+
/** Options for the watch method */
|
|
5
|
+
interface WatchOptions {
|
|
6
|
+
/** Debounce the callback by N milliseconds */
|
|
7
|
+
delay?: number;
|
|
8
|
+
/** Run callback immediately with current value */
|
|
9
|
+
fireImmediately?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Error context passed to the onError handler
|
|
13
|
+
*/
|
|
14
|
+
interface MantleErrorContext {
|
|
15
|
+
/** The lifecycle phase where the error occurred */
|
|
16
|
+
phase: 'onCreate' | 'onMount' | 'onUnmount' | 'watch';
|
|
17
|
+
/** The View or Behavior class name */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Whether the error came from a Behavior (true) or a View (false) */
|
|
20
|
+
isBehavior: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Global configuration options for mantle-lit
|
|
24
|
+
*/
|
|
25
|
+
interface MantleConfig {
|
|
26
|
+
/** Whether to automatically make View/Behavior instances observable (default: true) */
|
|
27
|
+
autoObservable?: boolean;
|
|
28
|
+
/** Global error handler for lifecycle errors. Defaults to console.error. */
|
|
29
|
+
onError?: (error: unknown, context: MantleErrorContext) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Configure global defaults for mantle-lit.
|
|
33
|
+
* Settings can still be overridden per-view in createView options.
|
|
34
|
+
*/
|
|
35
|
+
declare function configure(config: MantleConfig): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Base class for behaviors. Provides lifecycle method signatures for IDE autocomplete.
|
|
39
|
+
* Extend this class and wrap with createBehavior() to create a factory.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* class WindowSizeBehavior extends Behavior {
|
|
44
|
+
* width = window.innerWidth;
|
|
45
|
+
* onCreate(breakpoint = 768) { ... }
|
|
46
|
+
* onMount() { ... }
|
|
47
|
+
* }
|
|
48
|
+
* export const withWindowSize = createBehavior(WindowSizeBehavior);
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare class Behavior {
|
|
52
|
+
/** @internal */
|
|
53
|
+
_watchDisposers: (() => void)[];
|
|
54
|
+
onCreate?(...args: any[]): void;
|
|
55
|
+
onMount?(): void | (() => void);
|
|
56
|
+
onUnmount?(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Watch a reactive expression and run a callback when it changes.
|
|
59
|
+
* Automatically disposed on unmount.
|
|
60
|
+
*
|
|
61
|
+
* @param expr - Reactive expression (getter) to watch
|
|
62
|
+
* @param callback - Called when the expression result changes
|
|
63
|
+
* @param options - Optional configuration (delay, fireImmediately)
|
|
64
|
+
* @returns Dispose function for early teardown
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* onCreate(url: string) {
|
|
69
|
+
* this.url = url;
|
|
70
|
+
* this.watch(() => this.url, () => this.fetchData());
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
watch<T>(expr: () => T, callback: (value: T, prevValue: T | undefined) => void, options?: WatchOptions): () => void;
|
|
75
|
+
/** @internal */
|
|
76
|
+
_disposeWatchers(): void;
|
|
77
|
+
}
|
|
78
|
+
/** @internal */
|
|
79
|
+
interface BehaviorEntry {
|
|
80
|
+
instance: any;
|
|
81
|
+
cleanup?: () => void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Extracts parameter types from onCreate method
|
|
85
|
+
*/
|
|
86
|
+
type OnCreateParams<T> = T extends {
|
|
87
|
+
onCreate(...args: infer A): any;
|
|
88
|
+
} ? A : [];
|
|
89
|
+
/**
|
|
90
|
+
* Extracts constructor parameter types
|
|
91
|
+
*/
|
|
92
|
+
type ConstructorParams<T> = T extends new (...args: infer A) => any ? A : [];
|
|
93
|
+
/**
|
|
94
|
+
* Determines the args for createBehavior:
|
|
95
|
+
* - If constructor has args, use those
|
|
96
|
+
* - Otherwise, if onCreate has args, use those
|
|
97
|
+
*/
|
|
98
|
+
type BehaviorArgs<T extends new (...args: any[]) => any> = ConstructorParams<T> extends [] ? OnCreateParams<InstanceType<T>> : ConstructorParams<T>;
|
|
99
|
+
/**
|
|
100
|
+
* Type that supports both `new` and direct call syntax
|
|
101
|
+
*/
|
|
102
|
+
type BehaviorFactory<Args extends any[], Instance> = {
|
|
103
|
+
new (...args: Args): Instance;
|
|
104
|
+
(...args: Args): Instance;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Creates a behavior factory with automatic observable wrapping and lifecycle management.
|
|
108
|
+
*
|
|
109
|
+
* Returns a factory function (not a class) — use without `new`:
|
|
110
|
+
*
|
|
111
|
+
* @example Defining a behavior
|
|
112
|
+
* ```ts
|
|
113
|
+
* class DragBehavior extends Behavior {
|
|
114
|
+
* ref!: HTMLElement | null;
|
|
115
|
+
*
|
|
116
|
+
* onCreate(ref: HTMLElement | null) {
|
|
117
|
+
* this.ref = ref;
|
|
118
|
+
* }
|
|
119
|
+
*
|
|
120
|
+
* onMount() {
|
|
121
|
+
* this.ref?.addEventListener('pointerdown', this.onPointerDown);
|
|
122
|
+
* return () => this.ref?.removeEventListener('pointerdown', this.onPointerDown);
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
*
|
|
126
|
+
* export const withDrag = createBehavior(DragBehavior);
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @example Using in a View
|
|
130
|
+
* ```ts
|
|
131
|
+
* class Editor extends View<Props> {
|
|
132
|
+
* canvasRef: HTMLCanvasElement | null = null;
|
|
133
|
+
*
|
|
134
|
+
* // No `new` keyword — factory function
|
|
135
|
+
* drag = withDrag(this.canvasRef);
|
|
136
|
+
* }
|
|
137
|
+
* export const EditorElement = createView(Editor, { tag: 'x-editor' });
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* The `with` prefix convention signals that the view manages this behavior's lifecycle.
|
|
141
|
+
*/
|
|
142
|
+
declare function createBehavior<T extends new (...args: any[]) => any>(Def: T, options?: {
|
|
143
|
+
autoObservable?: boolean;
|
|
144
|
+
}): BehaviorFactory<BehaviorArgs<T>, InstanceType<T>>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Decorator context type for TC39 decorators
|
|
148
|
+
*/
|
|
149
|
+
interface DecoratorContext {
|
|
150
|
+
kind: 'field' | 'method' | 'getter' | 'setter' | 'accessor' | 'class';
|
|
151
|
+
name: string | symbol;
|
|
152
|
+
metadata: Record<symbol, unknown>;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Marks a field as observable. No `accessor` keyword needed.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* class Counter extends View {
|
|
160
|
+
* @observable count = 0;
|
|
161
|
+
* }
|
|
162
|
+
* export const CounterElement = createView(Counter, { tag: 'x-counter' });
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
declare function observable(_value: undefined, context: DecoratorContext): void;
|
|
166
|
+
declare namespace observable {
|
|
167
|
+
var ref: (_value: undefined, context: DecoratorContext) => void;
|
|
168
|
+
var shallow: (_value: undefined, context: DecoratorContext) => void;
|
|
169
|
+
var struct: (_value: undefined, context: DecoratorContext) => void;
|
|
170
|
+
var deep: (_value: undefined, context: DecoratorContext) => void;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Marks a method as an action. Auto-bound by default.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* class Counter extends View {
|
|
178
|
+
* @observable count = 0;
|
|
179
|
+
*
|
|
180
|
+
* @action increment() {
|
|
181
|
+
* this.count++;
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* export const CounterElement = createView(Counter, { tag: 'x-counter' });
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
declare function action(_value: Function, context: DecoratorContext): void;
|
|
188
|
+
/**
|
|
189
|
+
* Marks a getter as computed.
|
|
190
|
+
* Note: Getters are automatically computed in autoObservable mode,
|
|
191
|
+
* but this decorator is useful for explicit annotation.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* class Counter extends View {
|
|
196
|
+
* @observable count = 0;
|
|
197
|
+
*
|
|
198
|
+
* @computed get doubled() {
|
|
199
|
+
* return this.count * 2;
|
|
200
|
+
* }
|
|
201
|
+
* }
|
|
202
|
+
* export const CounterElement = createView(Counter, { tag: 'x-counter' });
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
declare function computed(_value: Function, context: DecoratorContext): void;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Base class for Views. Extend this and use createView() to create a custom element.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```ts
|
|
212
|
+
* import { View, createView } from 'mantle-lit';
|
|
213
|
+
* import { html } from 'lit';
|
|
214
|
+
*
|
|
215
|
+
* class CounterView extends View<{ initial: number }> {
|
|
216
|
+
* count = 0;
|
|
217
|
+
*
|
|
218
|
+
* onCreate() {
|
|
219
|
+
* this.count = this.props.initial;
|
|
220
|
+
* }
|
|
221
|
+
*
|
|
222
|
+
* increment() {
|
|
223
|
+
* this.count++;
|
|
224
|
+
* }
|
|
225
|
+
*
|
|
226
|
+
* render() {
|
|
227
|
+
* return html`
|
|
228
|
+
* <button @click=${this.increment}>
|
|
229
|
+
* Count: ${this.count}
|
|
230
|
+
* </button>
|
|
231
|
+
* `;
|
|
232
|
+
* }
|
|
233
|
+
* }
|
|
234
|
+
*
|
|
235
|
+
* export const Counter = createView(CounterView, { tag: 'x-counter' });
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
declare class View<P extends object = {}> {
|
|
239
|
+
/** @internal */
|
|
240
|
+
_propsBox: IObservableValue<P>;
|
|
241
|
+
/** Access current props (reactive) */
|
|
242
|
+
get props(): P;
|
|
243
|
+
/** @internal — called by the element to update props */
|
|
244
|
+
_syncProps(value: P): void;
|
|
245
|
+
/** @internal */
|
|
246
|
+
_behaviors: BehaviorEntry[];
|
|
247
|
+
/** @internal */
|
|
248
|
+
_watchDisposers: (() => void)[];
|
|
249
|
+
/** @internal - MobX reaction disposer for auto-render */
|
|
250
|
+
_reactionDisposer?: () => void;
|
|
251
|
+
/** @internal - Callback to request a render from the element */
|
|
252
|
+
_requestRender?: () => void;
|
|
253
|
+
onCreate?(): void;
|
|
254
|
+
onMount?(): void | (() => void);
|
|
255
|
+
onUnmount?(): void;
|
|
256
|
+
/**
|
|
257
|
+
* Watch a reactive expression and run a callback when it changes.
|
|
258
|
+
* Automatically disposed on unmount.
|
|
259
|
+
*
|
|
260
|
+
* @param expr - Reactive expression (getter) to watch
|
|
261
|
+
* @param callback - Called when the expression result changes
|
|
262
|
+
* @param options - Optional configuration (delay, fireImmediately)
|
|
263
|
+
* @returns Dispose function for early teardown
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* onCreate() {
|
|
268
|
+
* this.watch(
|
|
269
|
+
* () => this.query,
|
|
270
|
+
* async (query) => {
|
|
271
|
+
* if (query.length > 2) {
|
|
272
|
+
* this.results = await searchApi(query);
|
|
273
|
+
* }
|
|
274
|
+
* },
|
|
275
|
+
* { delay: 300 }
|
|
276
|
+
* );
|
|
277
|
+
* }
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
watch<T>(expr: () => T, callback: (value: T, prevValue: T | undefined) => void, options?: WatchOptions): () => void;
|
|
281
|
+
/** @internal */
|
|
282
|
+
_disposeWatchers(): void;
|
|
283
|
+
/** @internal - Scan own properties for behavior instances and register them */
|
|
284
|
+
_collectBehaviors(): void;
|
|
285
|
+
/** @internal */
|
|
286
|
+
_mountBehaviors(): void;
|
|
287
|
+
/** @internal */
|
|
288
|
+
_unmountBehaviors(): void;
|
|
289
|
+
render?(): TemplateResult | null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
interface CreateViewOptions {
|
|
293
|
+
/** Custom element tag name (required, must contain a hyphen) */
|
|
294
|
+
tag: string;
|
|
295
|
+
/** Whether to automatically make View instances observable (default: true) */
|
|
296
|
+
autoObservable?: boolean;
|
|
297
|
+
/** Whether to use Shadow DOM (default: true). Set to false to render in light DOM. */
|
|
298
|
+
shadow?: boolean;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Creates a Lit custom element from a View class.
|
|
302
|
+
*
|
|
303
|
+
* @param ViewClass - The View class to wrap
|
|
304
|
+
* @param options - Configuration options including the tag name
|
|
305
|
+
* @returns The custom element class (also registers it)
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```ts
|
|
309
|
+
* class CounterView extends View<{ initial: number }> {
|
|
310
|
+
* count = 0;
|
|
311
|
+
*
|
|
312
|
+
* onCreate() {
|
|
313
|
+
* this.count = this.props.initial;
|
|
314
|
+
* }
|
|
315
|
+
*
|
|
316
|
+
* increment() {
|
|
317
|
+
* this.count++;
|
|
318
|
+
* }
|
|
319
|
+
*
|
|
320
|
+
* render() {
|
|
321
|
+
* return html`<button @click=${this.increment}>Count: ${this.count}</button>`;
|
|
322
|
+
* }
|
|
323
|
+
* }
|
|
324
|
+
*
|
|
325
|
+
* export const Counter = createView(CounterView, { tag: 'x-counter' });
|
|
326
|
+
*
|
|
327
|
+
* // Usage in HTML: <x-counter .initial=${5}></x-counter>
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
declare function createView<V extends View<any>>(ViewClass: new () => V, options: CreateViewOptions): typeof LitElement;
|
|
331
|
+
/**
|
|
332
|
+
* Helper type for defining props that will be passed as properties (not attributes).
|
|
333
|
+
* Use with .prop=${value} syntax in Lit templates.
|
|
334
|
+
*/
|
|
335
|
+
type Props<T> = T;
|
|
336
|
+
/**
|
|
337
|
+
* Mount a view to the DOM with props.
|
|
338
|
+
*
|
|
339
|
+
* @param tag - The custom element tag name
|
|
340
|
+
* @param props - Props to pass to the component
|
|
341
|
+
* @param container - DOM element or selector to mount into (default: document.body)
|
|
342
|
+
* @returns The created element
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* import { mount } from 'mantle-lit';
|
|
347
|
+
* import './Todo'; // registers x-todo
|
|
348
|
+
*
|
|
349
|
+
* mount('x-todo', {
|
|
350
|
+
* title: 'My Tasks',
|
|
351
|
+
* initialTodos: [{ id: 1, text: 'Learn mantle', done: false }],
|
|
352
|
+
* onCountChange: (count) => console.log(count)
|
|
353
|
+
* });
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
declare function mount<P extends object>(tag: string, props?: P, container?: Element | string): HTMLElement & P;
|
|
357
|
+
|
|
358
|
+
export { Behavior, type CreateViewOptions, type MantleConfig, type MantleErrorContext, type Props, View, View as ViewModel, type WatchOptions, action, computed, configure, createBehavior, createView, mount, observable };
|