@nemigo/svelte 2.10.0 → 2.10.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.
package/dist/tree.d.ts CHANGED
@@ -34,8 +34,14 @@ export declare abstract class SvelteTree<R extends TreeRecord, Item extends Tree
34
34
  items: ISvelteState<Item[]>;
35
35
  map: Map<string, Item>;
36
36
  size: ISvelteState<number>;
37
+ root_parent_id: string | null;
38
+ constructor(root_parent_id?: string | null);
37
39
  abstract toTreeItem(record: R): Item;
38
40
  abstract sort(a: Item, b: Item): number;
41
+ /** true, если запись относится к нашему поддереву (корень или потомок) */
42
+ __inScope(record: R): boolean;
43
+ /** является ли этот parent_id "корнем" нашего поддерева */
44
+ __isRootParent(parent_id: string | null): boolean;
39
45
  hooks: {
40
46
  create: (record: R) => void;
41
47
  update: (record: R, mods: any) => void;
package/dist/tree.js CHANGED
@@ -5,8 +5,27 @@ export class SvelteTree extends Emitter {
5
5
  items = createSvelteRawState([]);
6
6
  map = new Map();
7
7
  size = createSvelteRawState(0);
8
+ root_parent_id;
9
+ constructor(root_parent_id = null) {
10
+ super();
11
+ this.root_parent_id = root_parent_id;
12
+ }
13
+ /** true, если запись относится к нашему поддереву (корень или потомок) */
14
+ __inScope(record) {
15
+ // корневой уровень нашего поддерева
16
+ if (record.parent_id === this.root_parent_id)
17
+ return true;
18
+ // потомок — значит его родитель уже в map
19
+ return record.parent_id !== null && this.map.has(record.parent_id);
20
+ }
21
+ /** является ли этот parent_id "корнем" нашего поддерева */
22
+ __isRootParent(parent_id) {
23
+ return parent_id === this.root_parent_id;
24
+ }
8
25
  hooks = {
9
26
  create: (record) => {
27
+ if (!this.__inScope(record))
28
+ return;
10
29
  const item = this.toTreeItem(record);
11
30
  this.dispatch("before-create", item);
12
31
  this.map.set(record.id, item);
@@ -18,14 +37,26 @@ export class SvelteTree extends Emitter {
18
37
  },
19
38
  update: (record, mods) => {
20
39
  const item = this.map.get(record.id);
21
- if (!item)
22
- return;
23
- const preview = { ...item.record.signal, ...mods };
24
- if (isDataEqual(record, preview))
25
- return;
40
+ const preview = { ...(item?.record.signal ?? record), ...mods };
26
41
  const prev_parent_id = record.parent_id;
27
42
  const mod_parent_id = mods.parent_id;
28
43
  const isParentChange = mod_parent_id !== undefined && mod_parent_id !== prev_parent_id;
44
+ // --- элемент ещё не в поддереве ---
45
+ if (!item) {
46
+ // если после апдейта он попадает в наше поддерево — создаём
47
+ if (this.__inScope(preview)) {
48
+ this.hooks.create(preview);
49
+ }
50
+ return;
51
+ }
52
+ // --- элемент уже в поддереве ---
53
+ // если апдейт выталкивает его из поддерева (смена parent_id на "чужой") — удаляем
54
+ if (isParentChange && !this.__inScope(preview)) {
55
+ this.hooks.delete(record.id);
56
+ return;
57
+ }
58
+ if (isDataEqual(record, preview))
59
+ return;
29
60
  if (isParentChange) {
30
61
  this.dispatch("before-parent-update", {
31
62
  prev: prev_parent_id,
@@ -77,15 +108,15 @@ export class SvelteTree extends Emitter {
77
108
  },
78
109
  };
79
110
  __sort(items) {
80
- items.signal = items.signal.toSorted((a, b) => this.sort(a, b)); // Триггерем эффекты
111
+ items.signal = items.signal.toSorted((a, b) => this.sort(a, b));
81
112
  }
82
113
  __push(items, item) {
83
114
  items.signal.push(item);
84
- this.__sort(items); // Триггерем эффекты
115
+ this.__sort(items);
85
116
  }
86
117
  __splice(items, idx) {
87
118
  items.signal.splice(idx, 1);
88
- items.signal = items.signal.slice(); // Триггерем эффекты
119
+ items.signal = items.signal.slice();
89
120
  }
90
121
  __delete(items, item) {
91
122
  const idx = items.signal.indexOf(item);
@@ -94,14 +125,14 @@ export class SvelteTree extends Emitter {
94
125
  }
95
126
  __parent(item, call) {
96
127
  const parent_id = item.record.signal.parent_id;
97
- if (parent_id) {
128
+ if (this.__isRootParent(parent_id)) {
129
+ call(this.items);
130
+ }
131
+ else if (parent_id) {
98
132
  const parent = this.map.get(parent_id);
99
133
  if (parent)
100
134
  call(parent.child);
101
135
  }
102
- else {
103
- call(this.items);
104
- }
105
136
  }
106
137
  clear() {
107
138
  this.items.signal = [];
@@ -109,20 +140,42 @@ export class SvelteTree extends Emitter {
109
140
  this.size.signal = 0;
110
141
  }
111
142
  __build(records) {
112
- // Первый проход: создаём все элементы и строим Map
143
+ // 1. индексируем все записи, чтобы корректно определять принадлежность к поддереву
144
+ const byId = new Map();
113
145
  for (const r of records)
146
+ byId.set(r.id, r);
147
+ // определяем, входит ли запись в наше поддерево (поднимаемся до корня)
148
+ const inScope = (r) => {
149
+ let cur = r;
150
+ const seen = new Set();
151
+ while (cur) {
152
+ if (cur.parent_id === this.root_parent_id)
153
+ return true;
154
+ if (cur.parent_id === null)
155
+ return false;
156
+ if (seen.has(cur.id))
157
+ return false; // защита от циклов
158
+ seen.add(cur.id);
159
+ cur = byId.get(cur.parent_id);
160
+ }
161
+ return false;
162
+ };
163
+ const scoped = records.filter(inScope);
164
+ // 2. создаём элементы
165
+ for (const r of scoped)
114
166
  this.map.set(r.id, this.toTreeItem(r));
115
- // Второй проход: строим дерево
116
- for (const r of records) {
167
+ // 3. строим дерево
168
+ for (const r of scoped) {
117
169
  const item = this.map.get(r.id);
118
- const parent_id = r.parent_id;
119
- if (parent_id)
120
- this.map.get(parent_id)?.child.signal.push(item);
121
- else
170
+ if (this.__isRootParent(r.parent_id)) {
122
171
  this.items.signal.push(item);
172
+ }
173
+ else if (r.parent_id) {
174
+ this.map.get(r.parent_id)?.child.signal.push(item);
175
+ }
123
176
  }
124
- // Третий проход: всё сортируем
125
- for (const r of records) {
177
+ // 4. сортируем
178
+ for (const r of scoped) {
126
179
  const item = this.map.get(r.id);
127
180
  this.__sort(item.child);
128
181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nemigo/svelte",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
4
4
  "private": false,
5
5
  "license": "MPL-2.0",
6
6
  "author": {
@@ -26,14 +26,30 @@
26
26
  "types": "./dist/kit/navigation.d.ts",
27
27
  "svelte": "./dist/kit/navigation.js"
28
28
  },
29
+ "./heap": {
30
+ "types": "./dist/heap.d.ts",
31
+ "svelte": "./dist/heap.js"
32
+ },
33
+ "./list": {
34
+ "types": "./dist/list.d.ts",
35
+ "svelte": "./dist/list.js"
36
+ },
29
37
  "./loader": {
30
38
  "types": "./dist/loader.d.ts",
31
39
  "svelte": "./dist/loader.js"
32
40
  },
41
+ "./record": {
42
+ "types": "./dist/record.d.ts",
43
+ "svelte": "./dist/record.js"
44
+ },
33
45
  "./transitions": {
34
46
  "types": "./dist/transitions.d.ts",
35
47
  "default": "./dist/transitions.js"
36
48
  },
49
+ "./tree": {
50
+ "types": "./dist/tree.d.ts",
51
+ "default": "./dist/tree.js"
52
+ },
37
53
  "./types": {
38
54
  "types": "./dist/types.d.ts",
39
55
  "default": "./dist/types.js"