@but212/atom-effect-jquery 0.25.0 → 0.27.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
@@ -12,46 +12,33 @@ import { untracked } from '@but212/atom-effect';
12
12
  import { WritableAtom } from '@but212/atom-effect';
13
13
 
14
14
  /**
15
- * Represents a value that can be a synchronous `ReactiveValue<T>`,
16
- * a `Promise<T>`, or an Atom yielding `T | Promise<T>`.
15
+ * An extension of ReactiveValue that also supports Promises and async functions.
16
+ * The binding system automatically handles the promise lifecycle, showing the
17
+ * latest resolved value and ignoring stale ones (race condition protection).
17
18
  */
18
19
  declare type AsyncReactiveValue<T> = T | ReadonlyAtom<T | Promise<T>> | Promise<T> | (() => T | Promise<T>);
19
20
 
20
21
  export { atom }
21
22
 
22
- export { batch }
23
-
24
23
  /**
25
- * Configuration options for `atomBind`.
26
- * @template T Type of the value for two-way binding (`val` field).
24
+ * Creates a two-way "lens" for a specific property path on an object-based atom.
27
25
  */
26
+ export declare function atomLens<T extends object, P extends Paths<T>>(atom: WritableAtom<T>, path: P): WritableAtom<PathValue<T, P>>;
27
+
28
+ export { batch }
29
+
28
30
  export declare interface BindingOptions<T = unknown> {
29
- /** Binds textContent to any reactive source. */
30
31
  text?: AsyncReactiveValue<unknown>;
31
- /** Binds innerHTML to a reactive string source (sanitized). */
32
32
  html?: AsyncReactiveValue<string>;
33
- /** Map of class names to reactive boolean conditions. */
34
33
  class?: Record<string, AsyncReactiveValue<boolean>>;
35
- /** Map of CSS properties to reactive values or [value, unit] tuples. */
36
34
  css?: CssBindings;
37
- /** Binds attributes with consistent primitive constraints. */
38
35
  attr?: Record<string, AsyncReactiveValue<PrimitiveValue>>;
39
- /** Binds DOM properties. */
40
36
  prop?: Record<string, AsyncReactiveValue<unknown>>;
41
- /** Direct visibility control (display: none). */
42
37
  show?: AsyncReactiveValue<boolean>;
43
- /** Inverse visibility control. */
44
38
  hide?: AsyncReactiveValue<boolean>;
45
- /**
46
- * Two-way binding for input values.
47
- * Pass an atom or a `[atom, options]` tuple.
48
- */
49
39
  val?: WritableAtom<T> | [atom: WritableAtom<T>, options: ValOptions<T>];
50
- /** Two-way binding for checkboxes and radio buttons. */
51
40
  checked?: WritableAtom<boolean>;
52
- /** Fully automated two-way form binding using name attributes. */
53
41
  form?: WritableAtom<T extends object ? T : unknown>;
54
- /** Event listeners with automatic batched execution and lifecycle-bound cleanup. */
55
42
  on?: Record<string, (e: JQuery.Event) => void>;
56
43
  }
57
44
 
@@ -72,8 +59,26 @@ declare class BindingRegistry {
72
59
  markIgnored(node: Node): void;
73
60
  isIgnored(node: Node): boolean;
74
61
  private getOrCreateRecord;
62
+ /**
63
+ * Registers a reactive effect with an element's record.
64
+ * Effects are automatically disposed when the element is removed from the DOM.
65
+ *
66
+ * @param el - The DOM element to bind the effect to.
67
+ * @param fx - The reactive effect instance.
68
+ */
75
69
  trackEffect(el: Element, fx: EffectObject): void;
70
+ /**
71
+ * Registers an arbitrary cleanup function with an element's record.
72
+ * Cleanups are executed when the element is removed from the DOM.
73
+ *
74
+ * @param el - The DOM element to bind the cleanup to.
75
+ * @param fn - The cleanup function (e.g., event unbinding, timer clear).
76
+ */
76
77
  trackCleanup(el: Element, fn: () => void): void;
78
+ /**
79
+ * Assigns a component-level cleanup function (e.g., from atomMount).
80
+ * Unlike generic cleanups, there can only be one component cleanup per element.
81
+ */
77
82
  setComponentCleanup(el: Element, fn: (() => void) | undefined): void;
78
83
  hasBind(el: Element): boolean;
79
84
  cleanup(el: Element | Node): void;
@@ -81,25 +86,19 @@ declare class BindingRegistry {
81
86
  cleanupTree(el: Element | Node): void;
82
87
  }
83
88
 
89
+ export declare type ComponentFn<P = Record<string, unknown>> = ($el: JQuery, props: P) => EffectResult;
90
+
84
91
  /**
85
- * A function that initializes logic on a jQuery element and returns an optional cleanup function.
86
- * `P` defaults to `Record<string, unknown>` for convenience. Use `P = Record<string, never>`
87
- * for strictly no-props components.
92
+ * Composes an existing lens with a sub-path to create a deeper lens.
88
93
  */
89
- export declare type ComponentFn<P = Record<string, unknown>> = ($el: JQuery, props: P) => EffectResult;
94
+ export declare const composeLens: <T extends object, P extends Paths<T>>(lens: WritableAtom<T>, path: P) => WritableAtom<PathValue<T, P>>;
90
95
 
91
96
  export { computed }
92
97
 
93
98
  export { ComputedAtom }
94
99
 
95
- /**
96
- * CSS bindings map property names to CSS values.
97
- */
98
100
  export declare type CssBindings = Record<string, CssValue>;
99
101
 
100
- /**
101
- * CSS value: either a direct reactive value or a numeric tuple of [source, unit].
102
- */
103
102
  export declare type CssValue = AsyncReactiveValue<string | number> | [source: AsyncReactiveValue<number>, unit: string];
104
103
 
105
104
  export default default_2;
@@ -117,15 +116,8 @@ export declare function disablejQueryOverrides(): void;
117
116
 
118
117
  export { effect }
119
118
 
120
- /**
121
- * Cleanup function returned by effects or components.
122
- */
123
119
  export declare type EffectCleanup = () => void;
124
120
 
125
- /**
126
- * Result of a reactive factory or component mount.
127
- * Returns `void` (no cleanup) or an `EffectCleanup` function.
128
- */
129
121
  export declare type EffectResult = undefined | EffectCleanup;
130
122
 
131
123
  /**
@@ -140,41 +132,17 @@ export declare type EffectResult = undefined | EffectCleanup;
140
132
  */
141
133
  export declare function enableAutoCleanup(root: Element): void;
142
134
 
143
- /**
144
- * Patches jQuery's `.on()`, `.off()`, `.remove()`, `.empty()`, and `.detach()`
145
- * to integrate with the reactive system:
146
- * - Event handlers are wrapped in `batch()` for efficient atom flushing.
147
- * - DOM removal triggers reactive binding cleanup.
148
- * - `.detach()` preserves bindings for re-attachment.
149
- *
150
- * Idempotent — calling more than once has no effect.
151
- * Call `disablejQueryOverrides()` to restore original methods.
152
- */
153
135
  export declare function enablejQueryOverrides(): void;
154
136
 
155
- /**
156
- * Generic equality predicate shared by `ValOptions` and any future consumer.
157
- * Extracted as a named type to avoid duplicating the inline function signature.
158
- */
159
137
  export declare type EqualFn<T> = (a: T, b: T) => boolean;
160
138
 
161
- /**
162
- * Configuration options for `atomFetch`.
163
- */
164
139
  export declare interface FetchOptions<T> {
165
- /** Initial value before the first fetch resolves. */
166
140
  defaultValue: T;
167
- /** HTTP method (default: 'GET'). */
168
141
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | (string & {});
169
- /** HTTP headers. */
170
142
  headers?: Record<string, string>;
171
- /** Transforms the raw response into T. */
172
143
  transform?: (raw: unknown) => T;
173
- /** Additional `$.ajax` settings. Can be a getter function for reactive data tracking. */
174
144
  ajaxOptions?: JQuery.AjaxSettings | (() => JQuery.AjaxSettings);
175
- /** Error callback. */
176
145
  onError?: (err: unknown) => void;
177
- /** Whether to fetch immediately (default: true). */
178
146
  eager?: boolean;
179
147
  }
180
148
 
@@ -182,92 +150,71 @@ export { isAtom }
182
150
 
183
151
  export { isComputed }
184
152
 
185
- /**
186
- * Checks if a given value is a reactive node (Atom or Computed).
187
- *
188
- * `isAtom` returns `true` for both plain atoms and computed atoms because
189
- * `ComputedAtomImpl` carries `ATOM_BRAND` in addition to `COMPUTED_BRAND`.
190
- * A separate `isComputed` check would therefore be redundant.
191
- */
192
- export declare function isReactive(value: unknown): value is ReadonlyAtom<unknown>;
153
+ /** Checks if a given value is a reactive node (Atom or Computed). */
154
+ export declare const isReactive: (v: unknown) => v is ReadonlyAtom<unknown>;
193
155
 
194
- /**
195
- * Helper to extract keys of T whose values extend V.
196
- * Used to ensure `key` property refers to valid ID-like values.
197
- */
198
156
  declare type KeysOfType<T, V> = {
199
157
  [K in keyof T]: T[K] extends V ? K : never;
200
158
  }[keyof T];
201
159
 
202
- /** Key type for Map/Set inside list.ts */
160
+ /**
161
+ * Creates a lens factory bound to a specific atom.
162
+ */
163
+ export declare const lensFor: <T extends object>(atom: WritableAtom<T>) => <P extends Paths<T>>(path: P) => WritableAtom<PathValue<T, P>>;
164
+
203
165
  declare type ListKey = string | number;
204
166
 
205
- /** Key extractor function signature. */
206
167
  declare type ListKeyFn<T> = (item: T, index: number) => ListKey;
207
168
 
208
- /**
209
- * Configuration options for `atomList`.
210
- */
211
169
  export declare interface ListOptions<T> {
212
- /**
213
- * Key to track items. Must be a property name whose value is a string|number,
214
- * or a key extractor function.
215
- */
216
170
  key: KeysOfType<T, ListKey> | ListKeyFn<T>;
217
- /** Render function for each item. */
218
171
  render: (item: T, index: number) => ListRenderResult;
219
- /** Optional post-render binding logic. */
220
172
  bind?: ($el: JQuery, item: T, index: number) => void;
221
- /** Optional update logic when item data changes but DOM is reused. */
222
173
  update?: ($el: JQuery, item: T, index: number) => void;
223
- /** Lifecycle hook: called when an element is added to the list. */
224
174
  onAdd?: ($el: JQuery) => void;
225
- /** Lifecycle hook: called when an element is about to be removed. */
226
175
  onRemove?: ($el: JQuery) => Promise<void> | void;
227
- /** Content to show when the list is empty. */
228
176
  empty?: ListRenderResult;
229
- /** Delegated event handlers attached to the container. */
230
177
  events?: Record<string, (item: T, index: number, e: JQuery.TriggeredEvent) => void>;
231
- /**
232
- * Custom equality checker to determine if an item has changed.
233
- * Defaults to `shallowEqual`. If it returns false, the item is re-rendered (unless `update` is provided).
234
- */
235
178
  isEqual?: (a: T, b: T) => boolean;
236
179
  }
237
180
 
238
- /** Possible return types for render() / empty */
239
181
  declare type ListRenderResult = string | Element | DocumentFragment | JQuery;
240
182
 
183
+ /** Max recursion depth for dot-paths. */
184
+ declare type MaxDepth = 8;
185
+
186
+ /** Resolves after microtask effects flush. Fast Promise-based scheduling. */
187
+ export declare const nextTick: () => Promise<void>;
188
+
241
189
  /**
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.
190
+ * Generates a union of all possible dot-separated paths for a given type T.
248
191
  *
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.
192
+ * Used for `atomLens` to provide IDE autocomplete and type safety when
193
+ * zooming into deeply nested reactive objects.
253
194
  *
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.
195
+ * @example
196
+ * type User = { profile: { name: string } };
197
+ * type P = Paths<User>; // "profile" | "profile.name"
257
198
  */
258
- export declare function nextTick(): Promise<void>;
199
+ export declare type Paths<T, D extends unknown[] = []> = D['length'] extends MaxDepth ? never : T extends object ? {
200
+ [K in keyof T & (string | number)]-?: `${K}` | (T[K] extends object ? `${K}.${Paths<T[K], [...D, 1]>}` : never);
201
+ }[keyof T & (string | number)] : never;
259
202
 
260
203
  /**
261
- * Values allowed for DOM properties and attributes.
204
+ * Resolves the type of a value at a specific dot-path P within type T.
205
+ *
206
+ * Works in tandem with `Paths<T>` to ensure that lensed atoms have
207
+ * the correct inferred type for the member they point to.
262
208
  */
209
+ export declare type PathValue<T, P extends string> = P extends `${infer K}.${infer Rest}` ? StringKeyToNumber<K> extends keyof T ? PathValue<T[StringKeyToNumber<K> & keyof T], Rest> : never : StringKeyToNumber<P> extends keyof T ? T[StringKeyToNumber<P> & keyof T] : never;
210
+
263
211
  export declare type PrimitiveValue = string | number | boolean | null | undefined;
264
212
 
265
213
  /**
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>`.
214
+ * Represents a value that can be tracked by the reactive system.
215
+ * - T: Static value (one-time bind)
216
+ * - ReadonlyAtom<T>: Reactive value (updates DOM when atom changes)
217
+ * - () => T: Reactive function (updates DOM when any atom read inside changes)
271
218
  */
272
219
  export declare type ReactiveValue<T> = T | ReadonlyAtom<T> | (() => T);
273
220
 
@@ -295,7 +242,6 @@ export declare interface RouteConfig {
295
242
 
296
243
  export declare type RouteDefinition = TemplateRoute | RenderRoute;
297
244
 
298
- /** Shared route lifecycle hooks. */
299
245
  export declare interface RouteLifecycle {
300
246
  onEnter?: (params: Record<string, string>, router: Router) => Record<string, string> | undefined;
301
247
  onLeave?: (router: Router) => boolean | undefined;
@@ -308,6 +254,9 @@ export declare interface Router {
308
254
  destroy: () => void;
309
255
  }
310
256
 
257
+ /** Helper to convert numeric string to number for array indexing. */
258
+ declare type StringKeyToNumber<S extends string> = S extends `${infer N extends number}` ? N : S;
259
+
311
260
  export declare interface TemplateRoute extends RouteLifecycle {
312
261
  template: string;
313
262
  render?: never;
@@ -317,18 +266,18 @@ export declare interface TemplateRoute extends RouteLifecycle {
317
266
  export { untracked }
318
267
 
319
268
  /**
320
- * Configuration options for `atomVal`.
269
+ * Options for `atomVal`, `atomChecked`, and `atomForm` bindings.
321
270
  */
322
271
  export declare interface ValOptions<T> {
323
- /** Delay in milliseconds before syncing DOM input to Atom. */
272
+ /** Debounce duration in milliseconds for DOM -> Atom sync. Defaults to 0. */
324
273
  debounce?: number;
325
- /** DOM event to trigger sync (default: 'input'). */
274
+ /** jQuery event name(s) to listen to. Defaults to "input". */
326
275
  event?: string;
327
- /** Parser to convert string input to Atom type T. */
276
+ /** Custom function to parse DOM string to atom type T. */
328
277
  parse?: (v: string) => T;
329
- /** Formatter to convert Atom type T to string for DOM display. */
278
+ /** Custom function to format atom type T to DOM string. */
330
279
  format?: (v: T) => string;
331
- /** Custom equality check for comparing parsed values. Defaults to Object.is. */
280
+ /** Custom equality check to prevent redundant atom updates. */
332
281
  equal?: EqualFn<T>;
333
282
  }
334
283