@but212/atom-effect-jquery 0.21.2 → 0.22.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/dist/index.d.ts CHANGED
@@ -5,6 +5,8 @@ import { ComputedAtom } from '@but212/atom-effect';
5
5
  import { default as default_2 } from 'jquery';
6
6
  import { effect } from '@but212/atom-effect';
7
7
  import { EffectObject } from '@but212/atom-effect';
8
+ import { isAtom } from '@but212/atom-effect';
9
+ import { isComputed } from '@but212/atom-effect';
8
10
  import { ReadonlyAtom } from '@but212/atom-effect';
9
11
  import { untracked } from '@but212/atom-effect';
10
12
  import { WritableAtom } from '@but212/atom-effect';
@@ -16,40 +18,54 @@ export { batch }
16
18
  /**
17
19
  * Configuration options for `atomBind`.
18
20
  */
19
- export declare interface BindingOptions<T> {
20
- text?: ReactiveValue<T>;
21
+ export declare interface BindingOptions {
22
+ /** Binds textContent to any reactive source (usually string/number). */
23
+ text?: ReactiveValue<unknown>;
24
+ /** Binds innerHTML to a reactive string source (sanitized). */
21
25
  html?: ReactiveValue<string>;
26
+ /** Map of class names to reactive boolean conditions. */
22
27
  class?: Record<string, ReactiveValue<boolean>>;
28
+ /** Map of CSS properties to reactive values or [value, unit] tuples. */
23
29
  css?: CssBindings;
24
- attr?: Record<string, ReactiveValue<string | boolean | null>>;
25
- prop?: Record<string, ReactiveValue<T>>;
30
+ /** Binds attributes with consistent primitive constraints. */
31
+ attr?: Record<string, ReactiveValue<PrimitiveValue>>;
32
+ /** Binds DOM properties. */
33
+ prop?: Record<string, ReactiveValue<unknown>>;
34
+ /** Direct visibility control (display: none). */
26
35
  show?: ReactiveValue<boolean>;
36
+ /** Inverse visibility control. */
27
37
  hide?: ReactiveValue<boolean>;
28
- val?: WritableAtom<T> | [atom: WritableAtom<T>, options: ValOptions<T>];
38
+ /**
39
+ * Two-way binding for input values.
40
+ * Pass a bare atom or a `[atom, options]` tuple to customise parse/format/debounce.
41
+ */
42
+ val?: WritableAtom<unknown> | [atom: WritableAtom<unknown>, options: ValOptions<unknown>];
43
+ /** Two-way binding for checkboxes and radio buttons. */
29
44
  checked?: WritableAtom<boolean>;
45
+ /** Event listeners with automatic batched execution and lifecycle-bound cleanup. */
30
46
  on?: Record<string, (e: JQuery.Event) => void>;
31
47
  }
32
48
 
33
49
  /**
34
- * Binding Registry
50
+ * Central registry mapping DOM elements to their reactive binding records.
35
51
  *
36
- * Highly optimized for performance:
37
- * - Uses WeakMap for zero-leak DOM associations.
38
- * - Minimal allocations in the tracking path.
39
- * - Efficient tree traversal for cleanup.
52
+ * Design goals:
53
+ * - Zero memory leaks: all collections use WeakMap/WeakSet keyed by Element.
54
+ * - Minimal allocations in the hot tracking path.
55
+ * - O(bound-descendants) cleanup via a single querySelectorAll pass.
40
56
  */
41
57
  declare class BindingRegistry {
42
58
  private records;
43
- private boundElements;
44
59
  private preservedNodes;
45
60
  private ignoredNodes;
46
61
  keep(node: Node): void;
47
62
  isKept(node: Node): boolean;
48
63
  markIgnored(node: Node): void;
49
64
  isIgnored(node: Node): boolean;
50
- private _getOrCreateRecord;
65
+ private getOrCreateRecord;
51
66
  trackEffect(el: Element, fx: EffectObject): void;
52
67
  trackCleanup(el: Element, fn: () => void): void;
68
+ setComponentCleanup(el: Element, fn: (() => void) | undefined): void;
53
69
  hasBind(el: Element): boolean;
54
70
  cleanup(el: Element): void;
55
71
  cleanupDescendants(el: Element): void;
@@ -58,8 +74,11 @@ declare class BindingRegistry {
58
74
 
59
75
  /**
60
76
  * Functional Component type.
77
+ * A function that initializes logic on a jQuery element and returns an optional cleanup function.
78
+ * `P` defaults to `object` (empty props) — use `P = Record<string, never>` for strictly no-props
79
+ * components.
61
80
  */
62
- export declare type ComponentFn<P = {}> = ($el: JQuery, props: P) => undefined | (() => void);
81
+ export declare type ComponentFn<P = object> = ($el: JQuery, props: P) => EffectResult;
63
82
 
64
83
  export { computed }
65
84
 
@@ -68,119 +87,313 @@ export { ComputedAtom }
68
87
  /**
69
88
  * CSS bindings map property names to CSS values.
70
89
  */
71
- declare type CssBindings = Record<string, CssValue>;
90
+ export declare type CssBindings = Record<string, CssValue>;
72
91
 
73
92
  /**
74
- * CSS value: either a direct reactive value or a tuple of [source, unit].
75
- * Named type provides clear bone structure for CSS binding configurations.
93
+ * CSS value: either a direct reactive value or a numeric tuple of [source, unit].
94
+ *
95
+ * The tuple form `[source, unit]` only accepts numeric sources because appending
96
+ * a unit suffix to a string value (e.g. `"100%" + "px"`) is semantically
97
+ * meaningless. Use `ReactiveValue<string>` directly when the full CSS value is
98
+ * already a string (e.g. `fontFamilyAtom`).
76
99
  */
77
- declare type CssValue = ReactiveValue<string | number> | [source: ReactiveValue<string | number>, unit: string];
100
+ export declare type CssValue = ReactiveValue<string | number> | [source: ReactiveValue<number>, unit: string];
78
101
 
79
102
  export default default_2;
80
103
 
104
+ /**
105
+ * Stops the MutationObserver started by `enableAutoCleanup`.
106
+ */
81
107
  export declare function disableAutoCleanup(): void;
82
108
 
109
+ /**
110
+ * Restores all jQuery methods patched by `enablejQueryOverrides()`.
111
+ * Primarily useful in test environments to reset state between suites.
112
+ */
113
+ export declare function disablejQueryOverrides(): void;
114
+
83
115
  export { effect }
84
116
 
85
- export declare function enableAutoCleanup(root?: Element): void;
117
+ /**
118
+ * Cleanup function returned by effects or components.
119
+ */
120
+ export declare type EffectCleanup = () => void;
86
121
 
87
122
  /**
88
- * Patches jQuery methods to integrate with the reactive system.
123
+ * Result of a reactive factory or component mount.
124
+ */
125
+ export declare type EffectResult = undefined | EffectCleanup;
126
+
127
+ /**
128
+ * Starts observing `root` for removed elements and automatically disposes
129
+ * their reactive bindings when they leave the DOM.
130
+ *
131
+ * The `root` parameter is required (no default) to make the caller explicit
132
+ * about which subtree is being observed — `document.body` can be null if the
133
+ * script runs before the body is parsed.
134
+ *
135
+ * Idempotent: calling more than once with the same root before
136
+ * `disableAutoCleanup` has no effect. Calling with a different root while
137
+ * already active emits a warning and returns without re-observing.
138
+ */
139
+ export declare function enableAutoCleanup(root: Element): void;
140
+
141
+ /**
142
+ * Patches jQuery's `.on()`, `.off()`, `.remove()`, `.empty()`, and `.detach()`
143
+ * to integrate with the reactive system:
144
+ * - Event handlers are wrapped in `batch()` for efficient atom flushing.
145
+ * - DOM removal triggers reactive binding cleanup.
146
+ * - `.detach()` preserves bindings for re-attachment.
147
+ *
148
+ * Idempotent — calling more than once has no effect.
149
+ * Call `disablejQueryOverrides()` to restore original methods.
89
150
  */
90
151
  export declare function enablejQueryOverrides(): void;
91
152
 
153
+ /**
154
+ * Generic equality predicate shared by `ValOptions` and any future consumer.
155
+ * Extracted as a named type to avoid duplicating the inline function signature.
156
+ */
157
+ export declare type EqualFn<T> = (a: T, b: T) => boolean;
158
+
159
+ /**
160
+ * Configuration options for `atomFetch`.
161
+ */
162
+ export declare interface FetchOptions<T> {
163
+ /**
164
+ * Value exposed by the atom before the first fetch resolves.
165
+ * Also returned while a subsequent fetch is in flight.
166
+ */
167
+ defaultValue: T;
168
+ /**
169
+ * HTTP method forwarded to `$.ajax` (default: `'GET'`).
170
+ * Takes precedence over the same field in `ajaxOptions`.
171
+ * Accepts any string for non-standard methods; common values are
172
+ * auto-completed: `'GET'`, `'POST'`, `'PUT'`, `'PATCH'`, `'DELETE'`.
173
+ */
174
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | (string & {});
175
+ /**
176
+ * HTTP headers forwarded to `$.ajax`.
177
+ * Takes precedence over the same field in `ajaxOptions`.
178
+ */
179
+ headers?: Record<string, string>;
180
+ /**
181
+ * Transforms the raw `$.ajax` response into `T`.
182
+ *
183
+ * When omitted the raw response is cast to `T` with no runtime validation.
184
+ * Provide this function whenever the server response shape is not
185
+ * guaranteed to match `T` at runtime.
186
+ */
187
+ transform?: (raw: unknown) => T;
188
+ /**
189
+ * Additional `$.ajax` settings.
190
+ * Top-level fields (`url`, `method`, `headers`) always override the same
191
+ * fields here, so avoid duplicating them to prevent silent conflicts.
192
+ */
193
+ ajaxOptions?: JQuery.AjaxSettings;
194
+ /**
195
+ * Called when the fetch fails with a non-abort error.
196
+ * Receives the raw rejection value from `$.ajax`.
197
+ * Does not suppress the error — the computed atom still enters its error
198
+ * state and `hasError` becomes true.
199
+ */
200
+ onError?: (err: unknown) => void;
201
+ /**
202
+ * When `true` (default), the first fetch starts immediately on creation.
203
+ * When `false`, the fetch is deferred until `atom.value` is first accessed.
204
+ */
205
+ eager?: boolean;
206
+ }
207
+
208
+ export { isAtom }
209
+
210
+ export { isComputed }
211
+
212
+ /**
213
+ * Checks if a given value is a reactive node (Atom or Computed).
214
+ *
215
+ * `isAtom` returns `true` for both plain atoms and computed atoms because
216
+ * `ComputedAtomImpl` carries `ATOM_BRAND` in addition to `COMPUTED_BRAND`.
217
+ * A separate `isComputed` check would therefore be redundant.
218
+ */
219
+ export declare function isReactive(value: unknown): value is ReadonlyAtom<unknown>;
220
+
92
221
  /**
93
222
  * Configuration options for `atomList`.
94
223
  */
95
224
  export declare interface ListOptions<T> {
225
+ /** Key to track items (property name or extractor function). */
96
226
  key: keyof T | ((item: T, index: number) => string | number);
227
+ /** Render function for each item. */
97
228
  render: (item: T, index: number) => string | Element | DocumentFragment | JQuery;
229
+ /** Optional post-render binding logic. */
98
230
  bind?: ($el: JQuery, item: T, index: number) => void;
231
+ /** Optional update logic when item data changes but DOM is reused. */
99
232
  update?: ($el: JQuery, item: T, index: number) => void;
233
+ /** Lifecycle hook: called when an element is added to the list. */
100
234
  onAdd?: ($el: JQuery) => void;
235
+ /** Lifecycle hook: called when an element is about to be removed. Supports async transitions. */
101
236
  onRemove?: ($el: JQuery) => Promise<void> | void;
237
+ /** Content to show when the list is empty. */
102
238
  empty?: string | Element | DocumentFragment | JQuery;
103
239
  }
104
240
 
105
241
  /**
106
- * Represents a value that can be either dynamic (Atom/Computed) or static.
242
+ * Resolves after all pending microtask-scheduled reactive effects have flushed.
243
+ *
244
+ * Implementation uses `setTimeout(0)` (a macrotask) which always runs after
245
+ * the current microtask queue is drained. This is intentional: core's
246
+ * scheduler enqueues effects as microtasks, so by the time the macrotask
247
+ * fires, all pending reactive propagation for the current turn is complete.
248
+ *
249
+ * Note: browsers may enforce a minimum 4 ms delay for nested `setTimeout`
250
+ * calls. For unit tests this is typically not an issue. If sub-millisecond
251
+ * resolution is needed, use `Promise.resolve()` directly to wait for a single
252
+ * microtask tick instead.
253
+ *
254
+ * **Caveats**: A single `await nextTick()` covers one reactive propagation
255
+ * wave. Chains of computed → effect → atom → effect may require multiple
256
+ * awaits — one per propagation step.
257
+ */
258
+ export declare function nextTick(): Promise<void>;
259
+
260
+ /**
261
+ * Values allowed for DOM properties and attributes.
262
+ */
263
+ export declare type PrimitiveValue = string | number | boolean | null | undefined;
264
+
265
+ /**
266
+ * Represents a value that can be either a reactive node (Atom or Computed)
267
+ * or a plain static value of the same type.
268
+ *
269
+ * `ComputedAtom<T>` is a structural sub-type of `ReadonlyAtom<T>`, so it is
270
+ * already covered by `ReadonlyAtom<T>` — listing it separately would be
271
+ * redundant and misleading.
107
272
  */
108
- declare type ReactiveValue<T> = T | ReadonlyAtom<T> | ComputedAtom<T>;
273
+ export declare type ReactiveValue<T> = T | ReadonlyAtom<T>;
109
274
 
110
275
  export { ReadonlyAtom }
111
276
 
112
277
  export declare const registry: BindingRegistry;
113
278
 
114
279
  /**
115
- * Route using a custom render function.
280
+ * Route that renders content via a custom function.
116
281
  */
117
- declare interface RenderRoute extends RouteLifecycle {
118
- /** Custom render function */
282
+ export declare interface RenderRoute extends RouteLifecycle {
283
+ /** Custom render function providing full control over the container DOM. */
119
284
  render: (container: HTMLElement, route: string, params: Record<string, string>) => void;
120
285
  template?: never;
121
286
  }
122
287
 
123
288
  /**
124
- * Configuration for $.route()
289
+ * Configuration for `$.route()`.
125
290
  */
126
291
  export declare interface RouteConfig {
127
- /** Target element selector for rendering route content */
292
+ /** CSS selector of the element into which route content is rendered. */
128
293
  target: string;
129
- /** Default route name */
294
+ /** Route name used when the URL has no explicit route segment. */
130
295
  default: string;
131
- /** Route definitions map */
296
+ /** Map of route names to their definitions. */
132
297
  routes: Record<string, RouteDefinition>;
133
- /** Routing mode. 'hash' uses location.hash, 'history' uses pushState. Default: 'hash' */
298
+ /**
299
+ * Routing strategy. Default: `'hash'`.
300
+ * - `'hash'` — reads/writes `location.hash` (`#routeName`).
301
+ * - `'history'` — reads/writes `location.pathname` via `history.pushState`.
302
+ */
134
303
  mode?: 'hash' | 'history';
135
- /** Base path for history mode (e.g., '/app'). Ignored in hash mode. Default: '' */
304
+ /**
305
+ * Path prefix stripped from `location.pathname` in history mode.
306
+ * A trailing slash is normalized away internally.
307
+ * Has no effect in hash mode.
308
+ */
136
309
  basePath?: string;
137
- /** Route name to use for 404/not found */
310
+ /** Route name to render when the requested route is not found (404 fallback). */
138
311
  notFound?: string;
139
- /** Automatically bind links with data-route attribute */
312
+ /**
313
+ * When `true`, clicks on `[data-route]` elements are intercepted and
314
+ * handled via `navigate()` instead of triggering a full page load.
315
+ * Default: `false`.
316
+ */
140
317
  autoBindLinks?: boolean;
141
- /** CSS class to add to active links */
318
+ /**
319
+ * CSS class added to `[data-route]` links that match the current route.
320
+ * Also sets `aria-current="page"` on the active link.
321
+ * Default: `'active'`.
322
+ */
142
323
  activeClass?: string;
143
- /** Called before transitioning between routes */
324
+ /**
325
+ * Called before each route transition.
326
+ * `from` is `''` on the very first render (no previous route).
327
+ */
144
328
  beforeTransition?: (from: string, to: string) => void;
145
- /** Called after transitioning between routes */
329
+ /**
330
+ * Called after each route transition completes.
331
+ * `from` is `''` on the very first render (no previous route).
332
+ */
146
333
  afterTransition?: (from: string, to: string) => void;
147
334
  }
148
335
 
149
336
  /**
150
337
  * Route definition for a single route.
151
- * Either template OR render must be provided, but not both.
338
+ * Exactly one of `template` or `render` must be provided.
339
+ *
340
+ * Use `isTemplateRoute` / `isRenderRoute` from `utils.ts` for safe narrowing
341
+ * instead of direct property access.
152
342
  */
153
343
  export declare type RouteDefinition = TemplateRoute | RenderRoute;
154
344
 
155
345
  /**
156
- * Shared route lifecycle hooks.
346
+ * Shared route lifecycle hooks available on every route definition.
157
347
  */
158
- declare interface RouteLifecycle {
159
- /** Called when entering this route. Can return additional params. */
348
+ export declare interface RouteLifecycle {
349
+ /**
350
+ * Called when entering this route. May return additional params to merge
351
+ * into the params object passed to `render` / `onMount`.
352
+ */
160
353
  onEnter?: (params: Record<string, string>) => Record<string, string> | undefined;
161
- /** Called when leaving this route. Return false to prevent navigation. */
354
+ /**
355
+ * Called when leaving this route.
356
+ * Return `false` to block navigation; returning `void` (or nothing) allows it.
357
+ */
162
358
  onLeave?: () => boolean | undefined;
359
+ /** Called when the same route is re-activated with new query parameters. */
360
+ onParamsChange?: (params: Record<string, string>) => void;
163
361
  }
164
362
 
165
363
  /**
166
- * Router instance returned by $.route()
364
+ * Router instance returned by `$.route()`.
365
+ *
366
+ * `currentRoute` and `queryParams` reflect the current URL state reactively:
367
+ * - In `'hash'` mode, `queryParams` is parsed from the query string after `?`
368
+ * in the hash fragment (e.g., `#home?page=2` → `{ page: '2' }`).
369
+ * - In `'history'` mode, `queryParams` is parsed from `location.search`.
167
370
  */
168
371
  export declare interface Router {
169
- /** Reactive atom containing current route name */
170
- currentRoute: WritableAtom<string>;
171
- /** Navigate to a different route */
372
+ /**
373
+ * Reactive atom containing the current route name.
374
+ * Read-only — use `navigate()` to change routes so that the URL stays in sync.
375
+ */
376
+ currentRoute: ReadonlyAtom<string>;
377
+ /**
378
+ * Reactive atom containing the current query parameters as a plain object.
379
+ * Updated automatically on URL changes; reset to `{}` on programmatic navigation.
380
+ */
381
+ queryParams: ReadonlyAtom<Record<string, string>>;
382
+ /** Navigate programmatically to the named route. */
172
383
  navigate: (route: string) => void;
173
- /** Cleanup and destroy the router */
384
+ /** Destroy the router, removing all event listeners and reactive effects. */
174
385
  destroy: () => void;
175
386
  }
176
387
 
177
388
  /**
178
- * Route using a template selector.
389
+ * Route that renders content by cloning a `<template>` element.
179
390
  */
180
- declare interface TemplateRoute extends RouteLifecycle {
181
- /** Template selector (e.g., '#tmpl-home') */
391
+ export declare interface TemplateRoute extends RouteLifecycle {
392
+ /** CSS selector for a `<template>` element (e.g., `'#tmpl-home'`). */
182
393
  template: string;
183
394
  render?: never;
395
+ /** Called after template content is appended to the container. */
396
+ onMount?: ($content: JQuery) => void;
184
397
  }
185
398
 
186
399
  export { untracked }
@@ -188,13 +401,17 @@ export { untracked }
188
401
  /**
189
402
  * Configuration options for `atomVal`.
190
403
  */
191
- declare interface ValOptions<T> {
404
+ export declare interface ValOptions<T> {
405
+ /** Delay in milliseconds before syncing DOM input to Atom. */
192
406
  debounce?: number;
407
+ /** DOM event to trigger sync (default: 'input'). */
193
408
  event?: string;
409
+ /** Parser to convert string input to Atom type T. */
194
410
  parse?: (v: string) => T;
411
+ /** Formatter to convert Atom type T to string for DOM display. */
195
412
  format?: (v: T) => string;
196
413
  /** Custom equality check for comparing parsed values. Defaults to Object.is. */
197
- equal?: (a: T, b: T) => boolean;
414
+ equal?: EqualFn<T>;
198
415
  }
199
416
 
200
417
  export { WritableAtom }