@reformer/core 11.0.0-beta.1 → 11.0.0-beta.2

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.
@@ -1,4 +1,4 @@
1
- import { Signal } from '@preact/signals-core';
1
+ import { ReadonlySignal, Signal } from '@preact/signals-core';
2
2
  /**
3
3
  * Сигнал, который знает свой путь в модели (`'personalData.lastName'`).
4
4
  * Используется как «ручка поля»: и привязка value в схеме, и идентичность для testId/devtools.
@@ -81,8 +81,8 @@ export interface ModelArray<U> {
81
81
  [index: number]: ModelValue<U>;
82
82
  }
83
83
  /**
84
- * Дерево сигналов (escape-hatch `model.$`): листья → {@link PathAwareSignal},
85
- * объекты → вложенное дерево, массивы → индексируемое дерево под-сигналов.
84
+ * Карта под-сигналов объекта в дереве `model.$` (без свойств самого узла — их добавляет
85
+ * {@link ModelGroupSignals}).
86
86
  *
87
87
  * @group Model
88
88
  */
@@ -90,16 +90,41 @@ export type ModelSignals<T> = {
90
90
  [K in keyof T]: ModelSignalNode<T[K]>;
91
91
  };
92
92
  /**
93
- * Узел дерева сигналов `model.$`: массив → индексируемый узел под-сигналов, Opaque (Date/File/Blob)
94
- * и примитив → {@link PathAwareSignal}, объект → вложенное дерево {@link ModelSignals}. Для примитивных
95
- * и Opaque массивов элемент — сам сигнал листа (а не под-дерево), поэтому `model.$.tags[0]` — это
96
- * `PathAwareSignal<string>`, а не `ModelSignals<never>`.
93
+ * Свойства контейнерного узла дерева `$`, «поверх» карты детей. Ключи детей вырезаются из
94
+ * {@link ReadonlySignal}: доступ к полю формы всегда выигрывает у одноимённого свойства сигнала
95
+ * (так же ведёт себя рантайм), поэтому `{ value: string }` не порождает конфликта типов.
97
96
  * @internal
98
97
  */
99
- type ModelSignalNode<V> = NonNullable<V> extends ReadonlyArray<infer U> ? {
98
+ type ContainerSignal<T, TKeys extends PropertyKey> = Omit<ReadonlySignal<T>, TKeys>;
99
+ /**
100
+ * Узел-группа дерева `model.$`: доступ к под-сигналам полей ({@link ModelSignals}) И одновременно
101
+ * {@link ReadonlySignal} агрегированного значения группы — `.value`/`.peek()`/`.subscribe()`.
102
+ *
103
+ * ⚠️ Поле формы с именем `value`/`peek`/`subscribe`/`valueOf`/`toString`/`toJSON`/`brand` затеняет
104
+ * одноимённое свойство сигнала (редкий краевой случай); `subscribe` при этом продолжает работать.
105
+ *
106
+ * @group Model
107
+ */
108
+ export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>;
109
+ /**
110
+ * Узел-массив дерева `model.$`: индексируемый доступ к под-сигналам элементов, реактивная `length`
111
+ * и {@link ReadonlySignal} значения массива целиком (реагирует и на правку элемента, и на изменение
112
+ * состава — push/removeAt/move).
113
+ *
114
+ * @group Model
115
+ */
116
+ export type ModelArraySignals<U, V> = ContainerSignal<V, 'length'> & {
100
117
  readonly length: number;
101
118
  readonly [index: number]: ModelSignalNode<U>;
102
- } : NonNullable<V> extends Opaque ? PathAwareSignal<V> : NonNullable<V> extends object ? ModelSignals<NonNullable<V>> : PathAwareSignal<V>;
119
+ };
120
+ /**
121
+ * Узел дерева сигналов `model.$`: массив → {@link ModelArraySignals}, Opaque (Date/File/Blob)
122
+ * и примитив → {@link PathAwareSignal}, объект → {@link ModelGroupSignals}. Для примитивных
123
+ * и Opaque массивов элемент — сам сигнал листа (а не под-дерево), поэтому `model.$.tags[0]` — это
124
+ * `PathAwareSignal<string>`, а не `ModelGroupSignals<never>`.
125
+ * @internal
126
+ */
127
+ type ModelSignalNode<V> = NonNullable<V> extends ReadonlyArray<infer U> ? ModelArraySignals<U, NonNullable<V>> : NonNullable<V> extends Opaque ? PathAwareSignal<V> : NonNullable<V> extends object ? ModelGroupSignals<NonNullable<V>> : PathAwareSignal<V>;
103
128
  /**
104
129
  * API уровня модели (доступно на корне, под-моделях вложенных объектов-групп и элементов массива).
105
130
  *
@@ -109,8 +134,11 @@ type ModelSignalNode<V> = NonNullable<V> extends ReadonlyArray<infer U> ? {
109
134
  * @group Model
110
135
  */
111
136
  export interface ModelApi<T> {
112
- /** Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`. */
113
- readonly $: ModelSignals<T>;
137
+ /**
138
+ * Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`.
139
+ * Сам узел — {@link ReadonlySignal} модели целиком: `model.$.subscribe(v => …)`.
140
+ */
141
+ readonly $: ModelGroupSignals<T>;
114
142
  /** Снимок значений (без подписки) — для submit. */
115
143
  get(): T;
116
144
  /**
package/dist/state.js CHANGED
@@ -1,21 +1,21 @@
1
- import { c as s } from "./form-model-DYCzGGKF.js";
2
- import { c as o, a as t, r as c, b as i, d as m, e as d, f, s as l, t as n, w as u } from "./behaviors-value-C7dSEhCc.js";
3
- import { i as b, m as k, u as v } from "./derived-registry-CluZCQ7U.js";
4
- import { S as D } from "./subscription-manager-705bls97.js";
1
+ import { c as s, a as r, i as o, m as i, u as t } from "./form-model-DhW2HZOB.js";
2
+ import { c as n, a as d, r as l, b as m, d as f, e as u, f as p, s as b, t as k, w as v } from "./behaviors-value-C7dSEhCc.js";
3
+ import { S as F } from "./subscription-manager-705bls97.js";
5
4
  export {
6
- D as SubscriptionManager,
7
- o as computeFrom,
8
- t as copyFrom,
5
+ F as SubscriptionManager,
6
+ n as computeFrom,
7
+ d as copyFrom,
9
8
  s as createModel,
10
- b as isDerived,
11
- k as markDerived,
12
- c as resetWhen,
13
- i as revalidateWhen,
14
- m as runOutsideEffect,
15
- d as safeCallback,
16
- f as safeDebouncedCallback,
17
- l as syncFields,
18
- n as transformValue,
19
- v as unmarkDerived,
20
- u as watchField
9
+ r as isDerived,
10
+ o as isModelContainerSignal,
11
+ i as markDerived,
12
+ l as resetWhen,
13
+ m as revalidateWhen,
14
+ f as runOutsideEffect,
15
+ u as safeCallback,
16
+ p as safeDebouncedCallback,
17
+ b as syncFields,
18
+ k as transformValue,
19
+ t as unmarkDerived,
20
+ v as watchField
21
21
  };
@@ -1,5 +1,5 @@
1
1
  import { signal as M, effect as E } from "@preact/signals-core";
2
- import { e as L } from "./form-model-DYCzGGKF.js";
2
+ import { e as L } from "./form-model-DhW2HZOB.js";
3
3
  import { g as p } from "./signal-node-registry-tiwel-TV.js";
4
4
  let v = null;
5
5
  function f(e) {
@@ -29,9 +29,38 @@ model.$.email.peek(); // нереактивный снимок
29
29
  model.$.address.city.value; // сигнал вложенного поля (≡ model.address.$.city у под-модели)
30
30
 
31
31
  // весь объект
32
- model.get(); // снимок { email, address: { city }, ... } — для submit
32
+ model.get(); // НЕреактивный снимок { email, address: { city }, ... } — для submit
33
33
  ```
34
34
 
35
+ > ⚠️ `model.get()` и `model.isDirty()` читают через `peek()` — внутри `effect`/`computed` они НЕ
36
+ > создают зависимостей. `computed(() => model.get())` никогда не пересчитается. Для реактивного
37
+ > чтения всего объекта — узел дерева `$` (ниже).
38
+
39
+ ### Подписка на группу и на модель целиком
40
+
41
+ Каждый узел дерева `$` — сигнал: лист отдаёт `PathAwareSignal`, а корень, вложенные объекты-группы
42
+ и массивы — `ReadonlySignal` агрегированного значения поддерева. Поэтому подписаться можно на любом
43
+ уровне, а не только на конкретном поле.
44
+
45
+ ```typescript
46
+ model.$.subscribe((all) => autosave(all)); // любое изменение модели; all: T целиком
47
+ model.$.address.subscribe((addr) => ...); // только поддерево address
48
+ model.$.address.value; // реактивный снимок группы
49
+ model.$.address.peek(); // нереактивный снимок группы
50
+ model.$.items.subscribe((rows) => ...); // массив: и правка элемента, и push/removeAt/move
51
+
52
+ // узел — обычный ReadonlySignal, поэтому принимается операциями слоя данных
53
+ watchField(model.$.address, (addr) => geocode(addr));
54
+ ```
55
+
56
+ Дети узла доступны как раньше — `model.$.address.city` по-прежнему сигнал поля. Подписчик вызывается
57
+ сразу с текущим значением (семантика `Signal.subscribe`), а `model.set(...)`/`model.reset()`
58
+ уведомляют один раз, а не по разу на поле.
59
+
60
+ > ⚠️ Доступ к полю выигрывает у свойства сигнала: если в форме есть поле с именем `value`, `peek`,
61
+ > `subscribe`, `valueOf`, `toString`, `toJSON` или `brand`, то `model.$.<группа>.<это имя>` вернёт
62
+ > сигнал поля. `subscribe` при этом продолжает работать.
63
+
35
64
  ### В behaviors — читаем model напрямую
36
65
 
37
66
  `compute`/`onChange`/условия `when` читают значения из value-модели (`model.field`) —
@@ -121,6 +121,14 @@ import { watchField } from '@reformer/core';
121
121
  const stop = watchField(model.$.country, () => { model.city = ''; });
122
122
  ```
123
123
 
124
+ Источником может быть не только поле: узлы-контейнеры дерева `$` (корень, группы, массивы) — тоже
125
+ `ReadonlySignal`, поэтому за поддеревом целиком следят без перечисления полей.
126
+
127
+ ```typescript
128
+ watchField(model.$.address, (addr) => geocode(addr)); // любое поле address
129
+ watchField(model.$, (all) => autosave(all)); // любое поле формы
130
+ ```
131
+
124
132
  ### Rule of Thumb
125
133
 
126
134
  | Scenario | Use |
@@ -129,6 +137,7 @@ const stop = watchField(model.$.country, () => { model.city = ''; });
129
137
  | Производное с явными зависимостями | `computeFrom` |
130
138
  | Async-реакция, обновление componentProps | `onChange` (debounce + AbortSignal) |
131
139
  | Простая синхронная реакция (примитив) | `watchField` |
140
+ | Реакция на любое изменение группы/формы | `watchField(model.$.<группа>)` или `.subscribe` |
132
141
 
133
142
  ### Chained computeds
134
143
 
package/llms.txt CHANGED
@@ -2259,9 +2259,38 @@ model.$.email.peek(); // нереактивный снимок
2259
2259
  model.$.address.city.value; // сигнал вложенного поля (≡ model.address.$.city у под-модели)
2260
2260
 
2261
2261
  // весь объект
2262
- model.get(); // снимок { email, address: { city }, ... } — для submit
2262
+ model.get(); // НЕреактивный снимок { email, address: { city }, ... } — для submit
2263
2263
  ```
2264
2264
 
2265
+ > ⚠️ `model.get()` и `model.isDirty()` читают через `peek()` — внутри `effect`/`computed` они НЕ
2266
+ > создают зависимостей. `computed(() => model.get())` никогда не пересчитается. Для реактивного
2267
+ > чтения всего объекта — узел дерева `$` (ниже).
2268
+
2269
+ ### Подписка на группу и на модель целиком
2270
+
2271
+ Каждый узел дерева `$` — сигнал: лист отдаёт `PathAwareSignal`, а корень, вложенные объекты-группы
2272
+ и массивы — `ReadonlySignal` агрегированного значения поддерева. Поэтому подписаться можно на любом
2273
+ уровне, а не только на конкретном поле.
2274
+
2275
+ ```typescript
2276
+ model.$.subscribe((all) => autosave(all)); // любое изменение модели; all: T целиком
2277
+ model.$.address.subscribe((addr) => ...); // только поддерево address
2278
+ model.$.address.value; // реактивный снимок группы
2279
+ model.$.address.peek(); // нереактивный снимок группы
2280
+ model.$.items.subscribe((rows) => ...); // массив: и правка элемента, и push/removeAt/move
2281
+
2282
+ // узел — обычный ReadonlySignal, поэтому принимается операциями слоя данных
2283
+ watchField(model.$.address, (addr) => geocode(addr));
2284
+ ```
2285
+
2286
+ Дети узла доступны как раньше — `model.$.address.city` по-прежнему сигнал поля. Подписчик вызывается
2287
+ сразу с текущим значением (семантика `Signal.subscribe`), а `model.set(...)`/`model.reset()`
2288
+ уведомляют один раз, а не по разу на поле.
2289
+
2290
+ > ⚠️ Доступ к полю выигрывает у свойства сигнала: если в форме есть поле с именем `value`, `peek`,
2291
+ > `subscribe`, `valueOf`, `toString`, `toJSON` или `brand`, то `model.$.<группа>.<это имя>` вернёт
2292
+ > сигнал поля. `subscribe` при этом продолжает работать.
2293
+
2265
2294
  ### В behaviors — читаем model напрямую
2266
2295
 
2267
2296
  `compute`/`onChange`/условия `when` читают значения из value-модели (`model.field`) —
@@ -2411,6 +2440,14 @@ import { watchField } from '@reformer/core';
2411
2440
  const stop = watchField(model.$.country, () => { model.city = ''; });
2412
2441
  ```
2413
2442
 
2443
+ Источником может быть не только поле: узлы-контейнеры дерева `$` (корень, группы, массивы) — тоже
2444
+ `ReadonlySignal`, поэтому за поддеревом целиком следят без перечисления полей.
2445
+
2446
+ ```typescript
2447
+ watchField(model.$.address, (addr) => geocode(addr)); // любое поле address
2448
+ watchField(model.$, (all) => autosave(all)); // любое поле формы
2449
+ ```
2450
+
2414
2451
  ### Rule of Thumb
2415
2452
 
2416
2453
  | Scenario | Use |
@@ -2419,6 +2456,7 @@ const stop = watchField(model.$.country, () => { model.city = ''; });
2419
2456
  | Производное с явными зависимостями | `computeFrom` |
2420
2457
  | Async-реакция, обновление componentProps | `onChange` (debounce + AbortSignal) |
2421
2458
  | Простая синхронная реакция (примитив) | `watchField` |
2459
+ | Реакция на любое изменение группы/формы | `watchField(model.$.<группа>)` или `.subscribe` |
2422
2460
 
2423
2461
  ### Chained computeds
2424
2462
 
@@ -6077,6 +6115,29 @@ if (isGroupNode(node)) {
6077
6115
 
6078
6116
  _Source: src/form/type-guards.ts_
6079
6117
 
6118
+ ### isModelContainerSignal
6119
+
6120
+ **Kind:** `function`
6121
+
6122
+ Узел дерева `model.$` — контейнер (группа/массив), а не лист?
6123
+
6124
+ Контейнерный узел структурно совместим с `ReadonlySignal` (`peek`/`value`/`subscribe`), поэтому
6125
+ duck-typing «есть `peek` ⇒ это лист» на нём даёт ложное срабатывание. Этот guard — надёжный
6126
+ способ различить: обходчикам дерева нужно спускаться в контейнер, а не читать его целиком.
6127
+
6128
+ **Signature:**
6129
+ ```typescript
6130
+ export function isModelContainerSignal(value: unknown): boolean
6131
+ ```
6132
+
6133
+ **Examples:**
6134
+
6135
+ ```typescript
6136
+ const isLeaf = (v: unknown) => isSignalLike(v) && !isModelContainerSignal(v);
6137
+ ```
6138
+
6139
+ _Source: src/state/form-model.ts_
6140
+
6080
6141
  ### markDerived
6081
6142
 
6082
6143
  **Kind:** `function`
@@ -6125,8 +6186,11 @@ API уровня модели (доступно на корне, под-моде
6125
6186
  **Signature:**
6126
6187
  ```typescript
6127
6188
  export interface ModelApi<T> {
6128
- /** Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`. */
6129
- readonly $: ModelSignals<T>;
6189
+ /**
6190
+ * Escape-hatch к сигналам: `model.$.loanType` → `PathAwareSignal<LoanType>`.
6191
+ * Сам узел — {@link ReadonlySignal} модели целиком: `model.$.subscribe(v => …)`.
6192
+ */
6193
+ readonly $: ModelGroupSignals<T>;
6130
6194
  /** Снимок значений (без подписки) — для submit. */
6131
6195
  get(): T;
6132
6196
  /**
@@ -6270,6 +6334,41 @@ rows.length.value; // 1 (реактивная длина)
6270
6334
 
6271
6335
  _Source: src/form/nodes/model-array-node.ts_
6272
6336
 
6337
+ ### ModelArraySignals
6338
+
6339
+ **Kind:** `type`
6340
+
6341
+ Узел-массив дерева `model.$`: индексируемый доступ к под-сигналам элементов, реактивная `length`
6342
+ и {@link ReadonlySignal} значения массива целиком (реагирует и на правку элемента, и на изменение
6343
+ состава — push/removeAt/move).
6344
+
6345
+ **Signature:**
6346
+ ```typescript
6347
+ export type ModelArraySignals<U, V> = ContainerSignal<V, 'length'> & {
6348
+ readonly length: number;
6349
+ readonly [index: number]: ModelSignalNode<U>;
6350
+ };
6351
+ ```
6352
+
6353
+ _Source: src/state/types.ts_
6354
+
6355
+ ### ModelGroupSignals
6356
+
6357
+ **Kind:** `type`
6358
+
6359
+ Узел-группа дерева `model.$`: доступ к под-сигналам полей ({@link ModelSignals}) И одновременно
6360
+ {@link ReadonlySignal} агрегированного значения группы — `.value`/`.peek()`/`.subscribe()`.
6361
+
6362
+ ⚠️ Поле формы с именем `value`/`peek`/`subscribe`/`valueOf`/`toString`/`toJSON`/`brand` затеняет
6363
+ одноимённое свойство сигнала (редкий краевой случай); `subscribe` при этом продолжает работать.
6364
+
6365
+ **Signature:**
6366
+ ```typescript
6367
+ export type ModelGroupSignals<T> = ModelSignals<T> & ContainerSignal<T, keyof T>;
6368
+ ```
6369
+
6370
+ _Source: src/state/types.ts_
6371
+
6273
6372
  ### ModelObject
6274
6373
 
6275
6374
  **Kind:** `type`
@@ -6291,8 +6390,8 @@ _Source: src/state/types.ts_
6291
6390
 
6292
6391
  **Kind:** `type`
6293
6392
 
6294
- Дерево сигналов (escape-hatch `model.$`): листья → {@link PathAwareSignal},
6295
- объекты → вложенное дерево, массивы → индексируемое дерево под-сигналов.
6393
+ Карта под-сигналов объекта в дереве `model.$` (без свойств самого узла — их добавляет
6394
+ {@link ModelGroupSignals}).
6296
6395
 
6297
6396
  **Signature:**
6298
6397
  ```typescript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reformer/core",
3
- "version": "11.0.0-beta.1",
3
+ "version": "11.0.0-beta.2",
4
4
  "description": "Reactive form state management library for React with signals-based architecture",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,16 +0,0 @@
1
- const t = /* @__PURE__ */ new WeakMap();
2
- function n(e) {
3
- t.set(e, (t.get(e) ?? 0) + 1);
4
- }
5
- function i(e) {
6
- const r = t.get(e);
7
- r !== void 0 && (r <= 1 ? t.delete(e) : t.set(e, r - 1));
8
- }
9
- function o(e) {
10
- return t.has(e);
11
- }
12
- export {
13
- o as i,
14
- n as m,
15
- i as u
16
- };
@@ -1,286 +0,0 @@
1
- import { signal as k } from "@preact/signals-core";
2
- import { i as b } from "./derived-registry-CluZCQ7U.js";
3
- const h = (e) => !(e === null || typeof e != "object" || Array.isArray(e) || e instanceof Date || typeof Blob < "u" && e instanceof Blob || typeof File < "u" && e instanceof File), a = (e, i) => e === "" ? String(i) : `${e}.${i}`, p = (e) => /^\d+$/.test(e), o = (e) => {
4
- if (Array.isArray(e)) return e.map(o);
5
- if (h(e)) {
6
- const i = {};
7
- for (const t of Object.keys(e)) i[t] = o(e[t]);
8
- return i;
9
- }
10
- return e;
11
- }, u = (e, i) => {
12
- if (e === i) return !0;
13
- if (Array.isArray(e) && Array.isArray(i))
14
- return e.length !== i.length ? !1 : e.every((t, r) => u(t, i[r]));
15
- if (h(e) && h(i)) {
16
- const t = Object.keys(e), r = Object.keys(i);
17
- return t.length !== r.length ? !1 : t.every((n) => u(e[n], i[n]));
18
- }
19
- return !1;
20
- };
21
- class x {
22
- constructor(i, t) {
23
- this.path = t;
24
- const r = k(i);
25
- r.__path = t, this.signal = r, this.initial = o(i);
26
- }
27
- kind = "leaf";
28
- signal;
29
- initial;
30
- rebase(i) {
31
- this.path = i, this.signal.__path = i;
32
- }
33
- /** Реактивное чтение (внутри effect/computed создаёт зависимость). */
34
- read() {
35
- return this.signal.value;
36
- }
37
- /** Нереактивный снимок. */
38
- peek() {
39
- return this.signal.peek();
40
- }
41
- set(i) {
42
- this.signal.value = i;
43
- }
44
- resetToInitial() {
45
- this.signal.value = o(this.initial);
46
- }
47
- captureInitial() {
48
- this.initial = o(this.signal.peek());
49
- }
50
- dirty() {
51
- return !u(this.signal.peek(), this.initial);
52
- }
53
- }
54
- class A {
55
- constructor(i, t) {
56
- this.path = t;
57
- for (const r of Object.keys(i))
58
- this.children.set(r, c(i[r], a(t, r)));
59
- }
60
- kind = "group";
61
- children = /* @__PURE__ */ new Map();
62
- rebase(i) {
63
- this.path = i;
64
- for (const [t, r] of this.children) r.rebase(a(i, t));
65
- }
66
- peek() {
67
- const i = {};
68
- for (const [t, r] of this.children) i[t] = r.peek();
69
- return i;
70
- }
71
- set(i) {
72
- if (i == null || typeof i != "object") return;
73
- const t = i;
74
- for (const [r, n] of this.children)
75
- r in t && (n.kind === "leaf" && b(n.signal) || n.set(t[r]));
76
- }
77
- resetToInitial() {
78
- for (const i of this.children.values()) i.resetToInitial();
79
- }
80
- captureInitial() {
81
- for (const i of this.children.values()) i.captureInitial();
82
- }
83
- dirty() {
84
- for (const i of this.children.values()) if (i.dirty()) return !0;
85
- return !1;
86
- }
87
- }
88
- class I {
89
- constructor(i, t) {
90
- this.path = t, this.items = k(i.map((r, n) => c(r, a(t, n)))), this.initial = o(i);
91
- }
92
- kind = "array";
93
- items;
94
- initial;
95
- rebase(i) {
96
- this.path = i, this.items.peek().forEach((t, r) => t.rebase(a(i, r)));
97
- }
98
- reindex() {
99
- this.items.peek().forEach((i, t) => i.rebase(a(this.path, t)));
100
- }
101
- push(i) {
102
- const t = this.items.peek();
103
- this.items.value = [...t, c(i, a(this.path, t.length))];
104
- }
105
- insertAt(i, t) {
106
- const r = [...this.items.peek()];
107
- r.splice(i, 0, c(t, a(this.path, i))), this.items.value = r, this.reindex();
108
- }
109
- removeAt(i) {
110
- const t = [...this.items.peek()];
111
- t.splice(i, 1), this.items.value = t, this.reindex();
112
- }
113
- move(i, t) {
114
- const r = [...this.items.peek()], [n] = r.splice(i, 1);
115
- n && r.splice(t, 0, n), this.items.value = r, this.reindex();
116
- }
117
- swap(i, t) {
118
- const r = [...this.items.peek()];
119
- i < 0 || t < 0 || i >= r.length || t >= r.length || i === t || ([r[i], r[t]] = [r[t], r[i]], this.items.value = r, this.reindex());
120
- }
121
- clear() {
122
- this.items.value = [];
123
- }
124
- peek() {
125
- return this.items.peek().map((i) => i.peek());
126
- }
127
- set(i) {
128
- const t = Array.isArray(i) ? i : [];
129
- this.items.value = t.map((r, n) => c(r, a(this.path, n)));
130
- }
131
- resetToInitial() {
132
- this.set(o(this.initial));
133
- }
134
- captureInitial() {
135
- this.initial = o(this.peek());
136
- }
137
- dirty() {
138
- return !u(this.peek(), this.initial);
139
- }
140
- }
141
- function c(e, i) {
142
- return Array.isArray(e) ? new I(e, i) : h(e) ? new A(e, i) : new x(e, i);
143
- }
144
- function l(e) {
145
- if (e)
146
- return e.kind === "group" ? _(e) : e.kind === "array" ? P(e) : e.read();
147
- }
148
- function P(e) {
149
- const i = {
150
- get length() {
151
- return e.items.value.length;
152
- },
153
- push: (t) => e.push(t),
154
- insertAt: (t, r) => e.insertAt(t, r),
155
- removeAt: (t) => e.removeAt(t),
156
- move: (t, r) => e.move(t, r),
157
- swap: (t, r) => e.swap(t, r),
158
- clear: () => e.clear(),
159
- at: (t) => l(e.items.value[t]),
160
- map: (t) => e.items.value.map((r, n) => t(l(r), n)),
161
- forEach: (t) => e.items.value.forEach((r, n) => t(l(r), n)),
162
- toArray: () => e.peek(),
163
- [Symbol.iterator]: function* () {
164
- const t = e.items.value;
165
- for (let r = 0; r < t.length; r++) yield l(t[r]);
166
- }
167
- };
168
- return new Proxy(i, {
169
- get: (t, r, n) => r === "__path" ? e.path : typeof r == "string" && p(r) ? l(e.items.value[Number(r)]) : Reflect.get(t, r, n),
170
- has: (t, r) => typeof r == "string" && p(r) ? Number(r) < e.items.value.length : Reflect.has(t, r)
171
- });
172
- }
173
- function d(e) {
174
- if (e.kind === "leaf") return e.signal;
175
- if (e.kind === "group")
176
- return new Proxy(
177
- {},
178
- {
179
- get: (t, r) => {
180
- if (r === "__path") return e.path;
181
- if (typeof r != "string") return;
182
- const n = e.children.get(r);
183
- return n ? d(n) : void 0;
184
- },
185
- has: (t, r) => typeof r == "string" && e.children.has(r),
186
- ownKeys: () => [...e.children.keys()],
187
- getOwnPropertyDescriptor: (t, r) => typeof r == "string" && e.children.has(r) ? { enumerable: !0, configurable: !0 } : void 0
188
- }
189
- );
190
- const i = e;
191
- return new Proxy(
192
- {
193
- get length() {
194
- return i.items.value.length;
195
- }
196
- },
197
- {
198
- get: (t, r, n) => {
199
- if (r === "__path") return i.path;
200
- if (typeof r == "string" && p(r)) {
201
- const s = i.items.value[Number(r)];
202
- return s ? d(s) : void 0;
203
- }
204
- return Reflect.get(t, r, n);
205
- }
206
- }
207
- );
208
- }
209
- function j(e, i) {
210
- if (!i) return;
211
- let t = e;
212
- for (const r of i.split(".")) {
213
- if (!t) return;
214
- if (t.kind === "group") t = t.children.get(r);
215
- else if (t.kind === "array") t = t.items.peek()[Number(r)];
216
- else return;
217
- }
218
- return t && t.kind === "leaf" ? t.signal : void 0;
219
- }
220
- const y = /* @__PURE__ */ new Set([
221
- "$",
222
- "get",
223
- "set",
224
- "patch",
225
- "isDirty",
226
- "reset",
227
- "captureInitial",
228
- "signalAt"
229
- ]), v = /* @__PURE__ */ new WeakMap(), w = /* @__PURE__ */ new WeakMap();
230
- function _(e) {
231
- const i = v.get(e);
232
- if (i) return i;
233
- const t = {
234
- $: d(e),
235
- get: () => e.peek(),
236
- set: (n) => e.set(n),
237
- patch: (n) => e.set(n),
238
- isDirty: () => e.dirty(),
239
- reset: () => e.resetToInitial(),
240
- captureInitial: () => e.captureInitial(),
241
- signalAt: (n) => j(e, n)
242
- }, r = new Proxy(
243
- {},
244
- {
245
- get: (n, s) => {
246
- if (s === "__path") return e.path;
247
- if (typeof s != "string") return;
248
- const f = e.children.get(s);
249
- if (f) return l(f);
250
- if (y.has(s)) return t[s];
251
- },
252
- set: (n, s, f) => {
253
- if (typeof s != "string") return !1;
254
- const g = e.children.get(s);
255
- return g ? (g.set(f), !0) : !1;
256
- },
257
- has: (n, s) => typeof s == "string" && (e.children.has(s) || y.has(s)),
258
- ownKeys: () => [...e.children.keys()],
259
- getOwnPropertyDescriptor: (n, s) => typeof s == "string" && e.children.has(s) ? { enumerable: !0, configurable: !0 } : void 0
260
- }
261
- );
262
- return v.set(e, r), w.set(r, e), r;
263
- }
264
- function m(e, i) {
265
- if (e.kind === "leaf") {
266
- i(e.signal);
267
- return;
268
- }
269
- if (e.kind === "group") {
270
- for (const t of e.children.values()) m(t, i);
271
- return;
272
- }
273
- for (const t of e.items.value) m(t, i);
274
- }
275
- function D(e, i) {
276
- const t = w.get(e);
277
- t && m(t, i);
278
- }
279
- function O(e) {
280
- const i = new A(e, "");
281
- return _(i);
282
- }
283
- export {
284
- O as c,
285
- D as e
286
- };