@hh.ru/magritte-ui-tree-selector 1.0.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.
Files changed (34) hide show
  1. package/collection/treeCollection.d.ts +70 -0
  2. package/collection/treeCollection.js +181 -0
  3. package/collection/treeCollection.js.map +1 -0
  4. package/collection/treeCollectionHelper.d.ts +20 -0
  5. package/collection/treeCollectionHelper.js +58 -0
  6. package/collection/treeCollectionHelper.js.map +1 -0
  7. package/collection/types.d.ts +27 -0
  8. package/collection/types.js +2 -0
  9. package/collection/types.js.map +1 -0
  10. package/index.d.ts +1 -0
  11. package/index.js +2 -0
  12. package/index.js.map +1 -0
  13. package/package.json +25 -0
  14. package/strategy/createSingleValueToggler.d.ts +6 -0
  15. package/strategy/createSingleValueToggler.js +46 -0
  16. package/strategy/createSingleValueToggler.js.map +1 -0
  17. package/strategy/createTreeCollectionToggler.d.ts +11 -0
  18. package/strategy/createTreeCollectionToggler.js +64 -0
  19. package/strategy/createTreeCollectionToggler.js.map +1 -0
  20. package/strategy/createTreeSelectionExcluder.d.ts +11 -0
  21. package/strategy/createTreeSelectionExcluder.js +52 -0
  22. package/strategy/createTreeSelectionExcluder.js.map +1 -0
  23. package/strategy/dummyToggle.d.ts +6 -0
  24. package/strategy/dummyToggle.js +17 -0
  25. package/strategy/dummyToggle.js.map +1 -0
  26. package/strategy/immutableSelectionStrategy.d.ts +21 -0
  27. package/strategy/immutableSelectionStrategy.js +42 -0
  28. package/strategy/immutableSelectionStrategy.js.map +1 -0
  29. package/strategy/selectionStrategy.d.ts +19 -0
  30. package/strategy/selectionStrategy.js +81 -0
  31. package/strategy/selectionStrategy.js.map +1 -0
  32. package/strategy/types.d.ts +13 -0
  33. package/strategy/types.js +2 -0
  34. package/strategy/types.js.map +1 -0
@@ -0,0 +1,70 @@
1
+ import { AdditionalDefault, TreeModel, WalkCallback, ModelPredicate, ModelData } from '../collection/types';
2
+ /**
3
+ * Многоцелевая иерархическая коллекция,
4
+ * свободная от специфического поведения компонентов
5
+ */
6
+ declare class TreeCollection<A extends AdditionalDefault = never> {
7
+ protected models: TreeModel<A>[];
8
+ protected topLevelModels: TreeModel<A>[];
9
+ protected modelsById: Record<string, TreeModel<A>>;
10
+ protected childrenById: Record<string, string[]>;
11
+ protected parentsById: Record<string, string[]>;
12
+ /**
13
+ * Создаёт из объекта модель и добавляет в коллекцию.
14
+ * Не добавляет модель в коллекцию, если модель с таким id уже существует
15
+ */
16
+ addModel(attrs: TreeModel<A>, parentId?: string): void;
17
+ toList(): TreeModel<A>[];
18
+ getTopLevel(): TreeModel<A>[];
19
+ /** Возвращает модель по ID или `undefined` */
20
+ getModel(id: string): TreeModel<A> | undefined;
21
+ /** Возвращает существующие в коллекции модели по IDs */
22
+ getExistModels(ids: string[]): TreeModel<A>[];
23
+ /** Возвращает ID родителя по ID модели или `undefined` */
24
+ getParentId(id: string): string | undefined;
25
+ /**
26
+ * Возвращает модель первого родителя по ID или `undefined`.
27
+ */
28
+ getParent(id: string): TreeModel<A> | undefined;
29
+ /** Возвращает массив IDs ближайших родителей по ID модели */
30
+ getParentIdsDuplicates(id: string): string[];
31
+ /** Возвращает массив ID родителей от ближних к дальним */
32
+ getParentIds(id: string, resultIds?: string[]): string[];
33
+ /** Возвращает массив моделей родителей от ближнего к дальнему */
34
+ getParents(id: string): TreeModel<A>[];
35
+ /** Возвращает наличие дочерних моделей по ID родителя */
36
+ hasChildren(id: string): boolean;
37
+ /** Возвращает список ID дочерних по ID родителя */
38
+ getChildrenIds(id: string): string[];
39
+ /** Возвращает список дочерних моделей по ID родителя */
40
+ getChildren(id: string): TreeModel<A>[];
41
+ /**
42
+ * Рекурсивно проходит по списку моделей, применяет к каждой модели переданную функцию.
43
+ * items Список моделей для обработки.
44
+ * callback Вызываемая функция.
45
+ * [parents] Массив моделей родителей от ближнего к дальнему.
46
+ * Используется в случаях, когда на вход поступают модели из середины дерева, имеющие своих родителей.
47
+ */
48
+ _walk(items: TreeModel<A>[], callback: WalkCallback<A>, parents?: TreeModel<A>[]): void;
49
+ /** Рекурсивно проходит по дереву, применяет к каждой модели переданную функцию */
50
+ walk(callback: WalkCallback<A>): void;
51
+ /**
52
+ * Рекурсивно проходит по дочерним элементам указанной модели, применяет к каждому переданную функцию.
53
+ * id ID модели, с которой начинать обход.
54
+ * callback Вызываемая функция.
55
+ */
56
+ walkChildren(id: string, callback: WalkCallback<A>): void;
57
+ /**
58
+ * Проходит по родителям модели до самого верха, применяет к каждому указанную функцию.
59
+ * id ID текущей модели.
60
+ * callback Вызываемая функция.
61
+ */
62
+ walkParents(id: string, callback: WalkCallback<A>): void;
63
+ /**
64
+ * Возвращает коллекцию в виде дерева.
65
+ * filter Функция-фильтр.
66
+ * Если указана, оставляет в дереве только те элементы, для которых вернулось `true`.
67
+ */
68
+ toTree(filter?: ModelPredicate): ModelData<A>[];
69
+ }
70
+ export default TreeCollection;
@@ -0,0 +1,181 @@
1
+ const createModel = (attrs) => {
2
+ const id = attrs.id;
3
+ if (typeof id !== 'string') {
4
+ throw new Error(`Invalid ID: "${JSON.stringify(id)}"`);
5
+ }
6
+ const model = {
7
+ id: attrs.id,
8
+ text: attrs.text,
9
+ ...('additional' in attrs ? { additional: attrs.additional } : {}),
10
+ };
11
+ return model;
12
+ };
13
+ /**
14
+ * Многоцелевая иерархическая коллекция,
15
+ * свободная от специфического поведения компонентов
16
+ */
17
+ class TreeCollection {
18
+ models = [];
19
+ topLevelModels = [];
20
+ modelsById = {};
21
+ childrenById = {};
22
+ parentsById = {};
23
+ /**
24
+ * Создаёт из объекта модель и добавляет в коллекцию.
25
+ * Не добавляет модель в коллекцию, если модель с таким id уже существует
26
+ */
27
+ addModel(attrs, parentId) {
28
+ const model = createModel(attrs);
29
+ const id = model.id;
30
+ if (typeof this.getModel(id) === 'undefined') {
31
+ this.models.push(model);
32
+ this.modelsById[id] = model;
33
+ }
34
+ if (parentId) {
35
+ this.parentsById[id] = this.parentsById[id] || [];
36
+ this.parentsById[id].push(parentId);
37
+ this.childrenById[parentId] = this.childrenById[parentId] || [];
38
+ this.childrenById[parentId].push(id);
39
+ }
40
+ else {
41
+ this.topLevelModels.push(model);
42
+ }
43
+ }
44
+ toList() {
45
+ return this.models.slice();
46
+ }
47
+ getTopLevel() {
48
+ return this.topLevelModels.slice();
49
+ }
50
+ /** Возвращает модель по ID или `undefined` */
51
+ getModel(id) {
52
+ return this.modelsById.hasOwnProperty(id) ? this.modelsById[id] : undefined;
53
+ }
54
+ /** Возвращает существующие в коллекции модели по IDs */
55
+ getExistModels(ids) {
56
+ return ids.reduce((result, id) => {
57
+ const model = this.getModel(id);
58
+ if (model) {
59
+ result.push(model);
60
+ }
61
+ return result;
62
+ }, []);
63
+ }
64
+ /** Возвращает ID родителя по ID модели или `undefined` */
65
+ getParentId(id) {
66
+ return this.parentsById.hasOwnProperty(id) ? this.parentsById[id][0] : undefined;
67
+ }
68
+ /**
69
+ * Возвращает модель первого родителя по ID или `undefined`.
70
+ */
71
+ getParent(id) {
72
+ const parentId = this.getParentId(id);
73
+ return parentId ? this.getModel(parentId) : undefined;
74
+ }
75
+ /** Возвращает массив IDs ближайших родителей по ID модели */
76
+ getParentIdsDuplicates(id) {
77
+ return this.parentsById.hasOwnProperty(id) ? this.parentsById[id] : [];
78
+ }
79
+ /** Возвращает массив ID родителей от ближних к дальним */
80
+ getParentIds(id, resultIds = []) {
81
+ const parentId = this.getParentIdsDuplicates(id);
82
+ if (parentId.length) {
83
+ resultIds.push(...parentId);
84
+ parentId.forEach((id) => this.getParentIds(id, resultIds));
85
+ }
86
+ return resultIds;
87
+ }
88
+ /** Возвращает массив моделей родителей от ближнего к дальнему */
89
+ getParents(id) {
90
+ const parendIds = this.getParentIds(id);
91
+ return this.getExistModels(parendIds);
92
+ }
93
+ /** Возвращает наличие дочерних моделей по ID родителя */
94
+ hasChildren(id) {
95
+ return this.childrenById.hasOwnProperty(id);
96
+ }
97
+ /** Возвращает список ID дочерних по ID родителя */
98
+ getChildrenIds(id) {
99
+ return this.hasChildren(id) ? this.childrenById[id].slice() : [];
100
+ }
101
+ /** Возвращает список дочерних моделей по ID родителя */
102
+ getChildren(id) {
103
+ const childrenIds = this.getChildrenIds(id);
104
+ return this.getExistModels(childrenIds);
105
+ }
106
+ /**
107
+ * Рекурсивно проходит по списку моделей, применяет к каждой модели переданную функцию.
108
+ * items Список моделей для обработки.
109
+ * callback Вызываемая функция.
110
+ * [parents] Массив моделей родителей от ближнего к дальнему.
111
+ * Используется в случаях, когда на вход поступают модели из середины дерева, имеющие своих родителей.
112
+ */
113
+ _walk(items, callback, parents) {
114
+ const currentParents = parents ? parents.slice() : [];
115
+ items.forEach((item) => {
116
+ callback(item, currentParents);
117
+ const children = this.getChildren(item.id);
118
+ if (children && children.length) {
119
+ this._walk(children, callback, [item].concat(currentParents));
120
+ }
121
+ });
122
+ }
123
+ /** Рекурсивно проходит по дереву, применяет к каждой модели переданную функцию */
124
+ walk(callback) {
125
+ this._walk(this.getTopLevel(), callback);
126
+ }
127
+ /**
128
+ * Рекурсивно проходит по дочерним элементам указанной модели, применяет к каждому переданную функцию.
129
+ * id ID модели, с которой начинать обход.
130
+ * callback Вызываемая функция.
131
+ */
132
+ walkChildren(id, callback) {
133
+ const children = this.getChildren(id);
134
+ if (children.length) {
135
+ const parents = this.getExistModels([id]).concat(this.getParents(id));
136
+ this._walk(children, callback, parents);
137
+ }
138
+ }
139
+ /**
140
+ * Проходит по родителям модели до самого верха, применяет к каждому указанную функцию.
141
+ * id ID текущей модели.
142
+ * callback Вызываемая функция.
143
+ */
144
+ walkParents(id, callback) {
145
+ const parents = this.getParents(id);
146
+ while (parents.length) {
147
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
148
+ const firstParent = parents.shift();
149
+ callback(firstParent, parents.slice());
150
+ }
151
+ }
152
+ /**
153
+ * Возвращает коллекцию в виде дерева.
154
+ * filter Функция-фильтр.
155
+ * Если указана, оставляет в дереве только те элементы, для которых вернулось `true`.
156
+ */
157
+ toTree(filter) {
158
+ const filteredTree = [];
159
+ const modelsById = {};
160
+ this.walk((model, parents) => {
161
+ if (!filter || filter(model)) {
162
+ const treeItem = { ...model };
163
+ modelsById[model.id] = treeItem;
164
+ if (parents.length === 0) {
165
+ filteredTree.push(treeItem);
166
+ }
167
+ else {
168
+ const parent = modelsById[parents[0].id];
169
+ if (!parent.items) {
170
+ parent.items = [];
171
+ }
172
+ parent.items.push(treeItem);
173
+ }
174
+ }
175
+ });
176
+ return filteredTree;
177
+ }
178
+ }
179
+
180
+ export { TreeCollection as default };
181
+ //# sourceMappingURL=treeCollection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeCollection.js","sources":["../../src/collection/treeCollection.ts"],"sourcesContent":["import {\n AdditionalDefault,\n TreeModel,\n WalkCallback,\n ModelPredicate,\n ModelData,\n} from '@hh.ru/magritte-ui-tree-selector/collection/types';\n\nconst createModel = <A extends AdditionalDefault>(attrs: TreeModel<A>): TreeModel<A> => {\n const id = attrs.id;\n if (typeof id !== 'string') {\n throw new Error(`Invalid ID: \"${JSON.stringify(id)}\"`);\n }\n const model: TreeModel<A> = {\n id: attrs.id,\n text: attrs.text,\n ...('additional' in attrs ? { additional: attrs.additional } : {}),\n };\n return model;\n};\n\n/**\n * Многоцелевая иерархическая коллекция,\n * свободная от специфического поведения компонентов\n */\nclass TreeCollection<A extends AdditionalDefault = never> {\n protected models: TreeModel<A>[] = [];\n protected topLevelModels: TreeModel<A>[] = [];\n\n protected modelsById: Record<string, TreeModel<A>> = {};\n protected childrenById: Record<string, string[]> = {};\n\n protected parentsById: Record<string, string[]> = {};\n\n /**\n * Создаёт из объекта модель и добавляет в коллекцию.\n * Не добавляет модель в коллекцию, если модель с таким id уже существует\n */\n addModel(attrs: TreeModel<A>, parentId?: string): void {\n const model = createModel(attrs);\n const id = model.id;\n if (typeof this.getModel(id) === 'undefined') {\n this.models.push(model);\n this.modelsById[id] = model;\n }\n if (parentId) {\n this.parentsById[id] = this.parentsById[id] || [];\n this.parentsById[id].push(parentId);\n this.childrenById[parentId] = this.childrenById[parentId] || [];\n this.childrenById[parentId].push(id);\n } else {\n this.topLevelModels.push(model);\n }\n }\n\n toList(): TreeModel<A>[] {\n return this.models.slice();\n }\n\n getTopLevel(): TreeModel<A>[] {\n return this.topLevelModels.slice();\n }\n\n /** Возвращает модель по ID или `undefined` */\n getModel(id: string): TreeModel<A> | undefined {\n return this.modelsById.hasOwnProperty(id) ? this.modelsById[id] : undefined;\n }\n\n /** Возвращает существующие в коллекции модели по IDs */\n getExistModels(ids: string[]): TreeModel<A>[] {\n return ids.reduce((result: TreeModel<A>[], id) => {\n const model = this.getModel(id);\n if (model) {\n result.push(model);\n }\n return result;\n }, []);\n }\n\n /** Возвращает ID родителя по ID модели или `undefined` */\n getParentId(id: string): string | undefined {\n return this.parentsById.hasOwnProperty(id) ? this.parentsById[id][0] : undefined;\n }\n\n /**\n * Возвращает модель первого родителя по ID или `undefined`.\n */\n getParent(id: string): TreeModel<A> | undefined {\n const parentId = this.getParentId(id);\n return parentId ? this.getModel(parentId) : undefined;\n }\n\n /** Возвращает массив IDs ближайших родителей по ID модели */\n getParentIdsDuplicates(id: string): string[] {\n return this.parentsById.hasOwnProperty(id) ? this.parentsById[id] : [];\n }\n\n /** Возвращает массив ID родителей от ближних к дальним */\n getParentIds(id: string, resultIds: string[] = []): string[] {\n const parentId = this.getParentIdsDuplicates(id);\n if (parentId.length) {\n resultIds.push(...parentId);\n parentId.forEach((id) => this.getParentIds(id, resultIds));\n }\n return resultIds;\n }\n\n /** Возвращает массив моделей родителей от ближнего к дальнему */\n getParents(id: string): TreeModel<A>[] {\n const parendIds = this.getParentIds(id);\n return this.getExistModels(parendIds);\n }\n\n /** Возвращает наличие дочерних моделей по ID родителя */\n hasChildren(id: string): boolean {\n return this.childrenById.hasOwnProperty(id);\n }\n\n /** Возвращает список ID дочерних по ID родителя */\n getChildrenIds(id: string): string[] {\n return this.hasChildren(id) ? this.childrenById[id].slice() : [];\n }\n\n /** Возвращает список дочерних моделей по ID родителя */\n getChildren(id: string): TreeModel<A>[] {\n const childrenIds = this.getChildrenIds(id);\n return this.getExistModels(childrenIds);\n }\n\n /**\n * Рекурсивно проходит по списку моделей, применяет к каждой модели переданную функцию.\n * items Список моделей для обработки.\n * callback Вызываемая функция.\n * [parents] Массив моделей родителей от ближнего к дальнему.\n * Используется в случаях, когда на вход поступают модели из середины дерева, имеющие своих родителей.\n */\n _walk(items: TreeModel<A>[], callback: WalkCallback<A>, parents?: TreeModel<A>[]): void {\n const currentParents = parents ? parents.slice() : [];\n items.forEach((item) => {\n callback(item, currentParents);\n const children = this.getChildren(item.id);\n if (children && children.length) {\n this._walk(children, callback, [item].concat(currentParents));\n }\n });\n }\n\n /** Рекурсивно проходит по дереву, применяет к каждой модели переданную функцию */\n walk(callback: WalkCallback<A>): void {\n this._walk(this.getTopLevel(), callback);\n }\n\n /**\n * Рекурсивно проходит по дочерним элементам указанной модели, применяет к каждому переданную функцию.\n * id ID модели, с которой начинать обход.\n * callback Вызываемая функция.\n */\n walkChildren(id: string, callback: WalkCallback<A>): void {\n const children = this.getChildren(id);\n if (children.length) {\n const parents = this.getExistModels([id]).concat(this.getParents(id));\n this._walk(children, callback, parents);\n }\n }\n\n /**\n * Проходит по родителям модели до самого верха, применяет к каждому указанную функцию.\n * id ID текущей модели.\n * callback Вызываемая функция.\n */\n walkParents(id: string, callback: WalkCallback<A>): void {\n const parents = this.getParents(id);\n while (parents.length) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const firstParent = parents.shift()!;\n callback(firstParent, parents.slice());\n }\n }\n\n /**\n * Возвращает коллекцию в виде дерева.\n * filter Функция-фильтр.\n * Если указана, оставляет в дереве только те элементы, для которых вернулось `true`.\n */\n toTree(filter?: ModelPredicate): ModelData<A>[] {\n const filteredTree: ModelData<A>[] = [];\n const modelsById: Record<string, ModelData<A>> = {};\n this.walk((model, parents) => {\n if (!filter || filter(model)) {\n const treeItem = { ...model };\n modelsById[model.id] = treeItem;\n if (parents.length === 0) {\n filteredTree.push(treeItem);\n } else {\n const parent = modelsById[parents[0].id];\n if (!parent.items) {\n parent.items = [];\n }\n parent.items.push(treeItem);\n }\n }\n });\n return filteredTree;\n }\n}\n\nexport default TreeCollection;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import TreeCollection from '../collection/treeCollection';
2
+ import { AdditionalDefault, WalkCallback, ModelData } from '../collection/types';
3
+ /**
4
+ * Рекурсивно проходит по списку моделей, применяет к каждой модели переданную функцию.
5
+ */
6
+ export declare const walk: <A extends AdditionalDefault>(tree: ModelData<A>[], callback: WalkCallback<A>, parents?: ModelData<A>[] | undefined) => void;
7
+ /**
8
+ * Возвращает коллекцию, созданную из дерева.
9
+ * @param tree
10
+ * @param [callback] Функция, вызываемая на каждом элементе.
11
+ */
12
+ export declare const fromTree: <A extends AdditionalDefault = never>(tree: ModelData<A>[], callback?: WalkCallback<A> | undefined) => TreeCollection<A>;
13
+ /**
14
+ * Возвращает только те ID, которые присутствуют в коллекции
15
+ */
16
+ export declare const filterMissingIds: <A extends AdditionalDefault>(collection: TreeCollection<A>, ids: string[]) => string[];
17
+ /**
18
+ * Возвращает ID только тех элементов, у которых нет потомков.
19
+ */
20
+ export declare const filterParents: <A extends AdditionalDefault>(collection: TreeCollection<A>, ids: string[]) => string[];
@@ -0,0 +1,58 @@
1
+ import TreeCollection from './treeCollection.js';
2
+
3
+ /**
4
+ * Рекурсивно проходит по списку моделей, применяет к каждой модели переданную функцию.
5
+ */
6
+ const walk = (
7
+ /** Дерево для обработки. */
8
+ tree,
9
+ /** Вызываемая функция. */
10
+ callback,
11
+ /** Массив моделей родителей от ближнего к дальнему. */
12
+ parents) => {
13
+ const currentParents = parents ? parents.slice() : [];
14
+ tree.forEach((item) => {
15
+ callback(item, currentParents);
16
+ if (item.items && item.items.length) {
17
+ walk(item.items, callback, [item].concat(currentParents));
18
+ }
19
+ });
20
+ };
21
+ /**
22
+ * Возвращает коллекцию, созданную из дерева.
23
+ * @param tree
24
+ * @param [callback] Функция, вызываемая на каждом элементе.
25
+ */
26
+ const fromTree = (tree, callback) => {
27
+ const collection = new TreeCollection();
28
+ walk(tree, (item, parents) => {
29
+ if (typeof callback === 'function') {
30
+ callback(item, parents);
31
+ }
32
+ collection.addModel(item, parents.length ? parents[0].id : undefined);
33
+ });
34
+ return collection;
35
+ };
36
+ /**
37
+ * Возвращает только те ID, которые присутствуют в коллекции
38
+ */
39
+ const filterMissingIds = (collection, ids) => {
40
+ const filteredIds = [];
41
+ ids.forEach((id) => {
42
+ if (collection.getModel(id)) {
43
+ filteredIds.push(id);
44
+ }
45
+ });
46
+ return filteredIds;
47
+ };
48
+ /**
49
+ * Возвращает ID только тех элементов, у которых нет потомков.
50
+ */
51
+ const filterParents = (collection, ids) => {
52
+ return ids.filter((id) => {
53
+ return collection.getChildrenIds(id).length === 0;
54
+ });
55
+ };
56
+
57
+ export { filterMissingIds, filterParents, fromTree, walk };
58
+ //# sourceMappingURL=treeCollectionHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeCollectionHelper.js","sources":["../../src/collection/treeCollectionHelper.ts"],"sourcesContent":["import TreeCollection from '@hh.ru/magritte-ui-tree-selector/collection/treeCollection';\nimport { AdditionalDefault, WalkCallback, ModelData } from '@hh.ru/magritte-ui-tree-selector/collection/types';\n\n/**\n * Рекурсивно проходит по списку моделей, применяет к каждой модели переданную функцию.\n */\nexport const walk = <A extends AdditionalDefault>(\n /** Дерево для обработки. */\n tree: ModelData<A>[],\n /** Вызываемая функция. */\n callback: WalkCallback<A>,\n /** Массив моделей родителей от ближнего к дальнему. */\n parents?: ModelData<A>[]\n): void => {\n const currentParents = parents ? parents.slice() : [];\n tree.forEach((item) => {\n callback(item, currentParents);\n if (item.items && item.items.length) {\n walk(item.items, callback, [item].concat(currentParents));\n }\n });\n};\n\n/**\n * Возвращает коллекцию, созданную из дерева.\n * @param tree\n * @param [callback] Функция, вызываемая на каждом элементе.\n */\nexport const fromTree = <A extends AdditionalDefault = never>(\n tree: ModelData<A>[],\n callback?: WalkCallback<A>\n): TreeCollection<A> => {\n const collection = new TreeCollection<A>();\n walk(tree, (item, parents): void => {\n if (typeof callback === 'function') {\n callback(item, parents);\n }\n collection.addModel(item, parents.length ? parents[0].id : undefined);\n });\n return collection;\n};\n\n/**\n * Возвращает только те ID, которые присутствуют в коллекции\n */\nexport const filterMissingIds = <A extends AdditionalDefault>(\n collection: TreeCollection<A>,\n ids: string[]\n): string[] => {\n const filteredIds: string[] = [];\n ids.forEach((id) => {\n if (collection.getModel(id)) {\n filteredIds.push(id);\n }\n });\n return filteredIds;\n};\n\n/**\n * Возвращает ID только тех элементов, у которых нет потомков.\n */\nexport const filterParents = <A extends AdditionalDefault>(collection: TreeCollection<A>, ids: string[]): string[] => {\n return ids.filter((id) => {\n return collection.getChildrenIds(id).length === 0;\n });\n};\n"],"names":[],"mappings":";;AAGA;;AAEG;AACU,MAAA,IAAI,GAAG;AAChB;AACA,IAAoB;AACpB;AACA,QAAyB;AACzB;AACA,OAAwB,KAClB;AACN,IAAA,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;AACtD,IAAA,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,KAAI;AAClB,QAAA,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;AACjC,YAAA,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC;AAC7D,SAAA;AACL,KAAC,CAAC,CAAC;AACP,EAAE;AAEF;;;;AAIG;MACU,QAAQ,GAAG,CACpB,IAAoB,EACpB,QAA0B,KACP;AACnB,IAAA,MAAM,UAAU,GAAG,IAAI,cAAc,EAAK,CAAC;IAC3C,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAU;AAC/B,QAAA,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;AAChC,YAAA,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC3B,SAAA;QACD,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC;AAC1E,KAAC,CAAC,CAAC;AACH,IAAA,OAAO,UAAU,CAAC;AACtB,EAAE;AAEF;;AAEG;MACU,gBAAgB,GAAG,CAC5B,UAA6B,EAC7B,GAAa,KACH;IACV,MAAM,WAAW,GAAa,EAAE,CAAC;AACjC,IAAA,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,KAAI;AACf,QAAA,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;AACzB,YAAA,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxB,SAAA;AACL,KAAC,CAAC,CAAC;AACH,IAAA,OAAO,WAAW,CAAC;AACvB,EAAE;AAEF;;AAEG;MACU,aAAa,GAAG,CAA8B,UAA6B,EAAE,GAAa,KAAc;AACjH,IAAA,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,KAAI;QACrB,OAAO,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACtD,KAAC,CAAC,CAAC;AACP;;;;"}
@@ -0,0 +1,27 @@
1
+ import TreeCollection from '../collection/treeCollection';
2
+ export type AdditionalDefault = Record<string, never>;
3
+ export interface TreeModel<A extends AdditionalDefault = never> {
4
+ id: string;
5
+ text: string;
6
+ additional?: A;
7
+ }
8
+ export interface ModelData<A extends AdditionalDefault = never> extends TreeModel<A> {
9
+ items?: ModelData<A>[];
10
+ [x: string]: unknown;
11
+ }
12
+ /**
13
+ * Коллбек, вызываемый на каждой модели при обходе дерева.
14
+ */
15
+ export interface WalkCallback<A extends AdditionalDefault> {
16
+ (
17
+ /** Модель текущего узла. */
18
+ item: TreeModel<A>,
19
+ /** Массив моделей родителей от ближнего к дальнему. */
20
+ currentParents: TreeModel<A>[]): void;
21
+ }
22
+ export interface ModelPredicate {
23
+ <A extends AdditionalDefault>(item: TreeModel<A>): boolean;
24
+ }
25
+ export interface IdCollectionPredicate {
26
+ <A extends AdditionalDefault>(id: string, collection: TreeCollection<A>): boolean;
27
+ }
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@hh.ru/magritte-ui-tree-selector",
3
+ "version": "1.0.2",
4
+ "main": "index.js",
5
+ "types": "index.d.ts",
6
+ "sideEffects": [
7
+ "index.css"
8
+ ],
9
+ "scripts": {
10
+ "build": "yarn root:build $(pwd)",
11
+ "build-test-branch": "yarn root:build-test-branch $(pwd)",
12
+ "changelog": "yarn root:changelog $(pwd)",
13
+ "prepack": "yarn root:prepack $(pwd)",
14
+ "postpublish": "yarn root:postpublish $(pwd)",
15
+ "stylelint-test": "yarn root:stylelint-test $(pwd)",
16
+ "eslint-test": "yarn root:eslint-test $(pwd)",
17
+ "ts-config": "yarn root:ts-config $(pwd)",
18
+ "ts-check": "yarn root:ts-check $(pwd)",
19
+ "test": "yarn root:test $(pwd)"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "gitHead": "b660dd64fca3eaad5ec44ea9a73f92bb0d9694aa"
25
+ }
@@ -0,0 +1,6 @@
1
+ import { Toggler } from '../strategy/types';
2
+ /**
3
+ * Создаёт переключатель для набора с возможностью выбора только одного элемента.
4
+ */
5
+ declare const createSingleValueToggler: () => Toggler;
6
+ export default createSingleValueToggler;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Создаёт переключатель для набора с возможностью выбора только одного элемента.
3
+ */
4
+ const createSingleValueToggler = () => {
5
+ /**
6
+ * Переключает элемент в наборе, при необходимости сбрасывая предыдущий выбранный.
7
+ * @param set Исходный набор
8
+ * @param id Переключаемый элемент
9
+ * @param state Новое состояние переключаемого элемента (true — в наборе, false — нет)
10
+ * @returns Признак того, что набор изменился.
11
+ */
12
+ return (set, id, state) => {
13
+ /**
14
+ * Всего возможно 6 случаев:
15
+ * 1. toggle([2], 2, true) => [2], return false
16
+ * 2. toggle([1], 2, true) => [2], return true
17
+ * 3. toggle([ ], 2, true) => [2], return true
18
+ * 4. toggle([2], 2, false) => [ ], return true
19
+ * 5. toggle([1], 2, false) => [1], return false
20
+ * 6. toggle([ ], 2, false) => [ ], return false
21
+ */
22
+ if (state) {
23
+ if (set.has(id)) {
24
+ // 1
25
+ return false;
26
+ }
27
+ if (set.size) {
28
+ // 2
29
+ set.clear();
30
+ }
31
+ // 3
32
+ set.add(id);
33
+ return true;
34
+ }
35
+ else if (set.has(id)) {
36
+ // 4
37
+ set.delete(id);
38
+ return true;
39
+ }
40
+ // 5, 6
41
+ return false;
42
+ };
43
+ };
44
+
45
+ export { createSingleValueToggler as default };
46
+ //# sourceMappingURL=createSingleValueToggler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSingleValueToggler.js","sources":["../../src/strategy/createSingleValueToggler.ts"],"sourcesContent":["import { Toggler } from '@hh.ru/magritte-ui-tree-selector/strategy/types';\n\n/**\n * Создаёт переключатель для набора с возможностью выбора только одного элемента.\n */\nconst createSingleValueToggler = (): Toggler => {\n /**\n * Переключает элемент в наборе, при необходимости сбрасывая предыдущий выбранный.\n * @param set Исходный набор\n * @param id Переключаемый элемент\n * @param state Новое состояние переключаемого элемента (true — в наборе, false — нет)\n * @returns Признак того, что набор изменился.\n */\n return (set: Set<string>, id: string, state: boolean) => {\n /**\n * Всего возможно 6 случаев:\n * 1. toggle([2], 2, true) => [2], return false\n * 2. toggle([1], 2, true) => [2], return true\n * 3. toggle([ ], 2, true) => [2], return true\n * 4. toggle([2], 2, false) => [ ], return true\n * 5. toggle([1], 2, false) => [1], return false\n * 6. toggle([ ], 2, false) => [ ], return false\n */\n if (state) {\n if (set.has(id)) {\n // 1\n return false;\n }\n if (set.size) {\n // 2\n set.clear();\n }\n // 3\n set.add(id);\n return true;\n } else if (set.has(id)) {\n // 4\n set.delete(id);\n return true;\n }\n // 5, 6\n return false;\n };\n};\n\nexport default createSingleValueToggler;\n"],"names":[],"mappings":"AAEA;;AAEG;AACG,MAAA,wBAAwB,GAAG,MAAc;AAC3C;;;;;;AAMG;AACH,IAAA,OAAO,CAAC,GAAgB,EAAE,EAAU,EAAE,KAAc,KAAI;AACpD;;;;;;;;AAQG;AACH,QAAA,IAAI,KAAK,EAAE;AACP,YAAA,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;;AAEb,gBAAA,OAAO,KAAK,CAAC;AAChB,aAAA;YACD,IAAI,GAAG,CAAC,IAAI,EAAE;;gBAEV,GAAG,CAAC,KAAK,EAAE,CAAC;AACf,aAAA;;AAED,YAAA,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACZ,YAAA,OAAO,IAAI,CAAC;AACf,SAAA;AAAM,aAAA,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;;AAEpB,YAAA,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACf,YAAA,OAAO,IAAI,CAAC;AACf,SAAA;;AAED,QAAA,OAAO,KAAK,CAAC;AACjB,KAAC,CAAC;AACN;;;;"}
@@ -0,0 +1,11 @@
1
+ import TreeCollection from '../collection/treeCollection';
2
+ import { AdditionalDefault, IdCollectionPredicate } from '../collection/types';
3
+ import { Toggler, StrategyOptions } from '../strategy/types';
4
+ /**
5
+ * Создаёт переключатель элементов в наборе с учётом иерархии элементов:
6
+ * — если выбран или сброшен родитель, выбираются или сбрасываются все его потомки;
7
+ * — если выбраны все потомки родителя, выбирается и родитель;
8
+ * — если сброшен хотя бы один потомок выбранного родителя, сбрасывается и родитель.
9
+ */
10
+ declare const createTreeCollectionToggler: <A extends AdditionalDefault>(collection: TreeCollection<A>, checkSelectable: IdCollectionPredicate, options: StrategyOptions) => Toggler;
11
+ export default createTreeCollectionToggler;
@@ -0,0 +1,64 @@
1
+ import toggle from './dummyToggle.js';
2
+
3
+ /**
4
+ * Создаёт переключатель элементов в наборе с учётом иерархии элементов:
5
+ * — если выбран или сброшен родитель, выбираются или сбрасываются все его потомки;
6
+ * — если выбраны все потомки родителя, выбирается и родитель;
7
+ * — если сброшен хотя бы один потомок выбранного родителя, сбрасывается и родитель.
8
+ */
9
+ const createTreeCollectionToggler = (collection, checkSelectable, options) => {
10
+ /**
11
+ * Определение состояния по дочерним элементам
12
+ */
13
+ const _getCumulativeParentState = (set, id) => {
14
+ let hasSelectableChild = false;
15
+ const allSelectableChildrenAreSelected = collection.getChildren(id).every((model) => {
16
+ const isSelectable = checkSelectable(model.id, collection);
17
+ hasSelectableChild = hasSelectableChild || isSelectable;
18
+ return set.has(model.id) || !isSelectable;
19
+ });
20
+ return hasSelectableChild ? allSelectableChildrenAreSelected : set.has(id);
21
+ };
22
+ /**
23
+ * Простановка состояния всем дочерним элементам
24
+ */
25
+ const _setStateForAllChildren = (set, id, state) => {
26
+ collection.walkChildren(id, (model) => {
27
+ if (checkSelectable(model.id, collection)) {
28
+ toggle(set, model.id, state);
29
+ }
30
+ });
31
+ };
32
+ const _toggleOtherParents = (set, id) => {
33
+ // когда добавляем-убираем родительскую модель надо проверить и проставить статус другим родителям,
34
+ // у которых есть общие модели-потомки с первоночальной родительской моделью
35
+ if (collection.hasChildren(id)) {
36
+ const childrenIds = collection.getChildrenIds(id);
37
+ const otherParentsIds = childrenIds.reduce((result, childrenId) => {
38
+ const parentIds = collection
39
+ .getParentIdsDuplicates(childrenId)
40
+ .filter((parentId) => parentId !== id && !result.includes(parentId) && checkSelectable(parentId, collection));
41
+ return result.concat(parentIds);
42
+ }, []);
43
+ otherParentsIds.forEach((parentId) => toggle(set, parentId, _getCumulativeParentState(set, parentId)));
44
+ }
45
+ };
46
+ /**
47
+ * Переключение состояния модели, её родителей и потомков.
48
+ */
49
+ return (set, id, state) => {
50
+ const toggleResult = toggle(set, id, state);
51
+ if (toggleResult && !options.withExcluded) {
52
+ collection.walkParents(id, (parent) => {
53
+ if (checkSelectable(parent.id, collection)) {
54
+ toggle(set, parent.id, _getCumulativeParentState(set, parent.id));
55
+ }
56
+ });
57
+ }
58
+ _setStateForAllChildren(set, id, state);
59
+ _toggleOtherParents(set, id);
60
+ };
61
+ };
62
+
63
+ export { createTreeCollectionToggler as default };
64
+ //# sourceMappingURL=createTreeCollectionToggler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTreeCollectionToggler.js","sources":["../../src/strategy/createTreeCollectionToggler.ts"],"sourcesContent":["import TreeCollection from '@hh.ru/magritte-ui-tree-selector/collection/treeCollection';\nimport { AdditionalDefault, IdCollectionPredicate } from '@hh.ru/magritte-ui-tree-selector/collection/types';\nimport dummyToggle from '@hh.ru/magritte-ui-tree-selector/strategy/dummyToggle';\nimport { Toggler, StrategyOptions } from '@hh.ru/magritte-ui-tree-selector/strategy/types';\n\n/**\n * Создаёт переключатель элементов в наборе с учётом иерархии элементов:\n * — если выбран или сброшен родитель, выбираются или сбрасываются все его потомки;\n * — если выбраны все потомки родителя, выбирается и родитель;\n * — если сброшен хотя бы один потомок выбранного родителя, сбрасывается и родитель.\n */\n\nconst createTreeCollectionToggler = <A extends AdditionalDefault>(\n collection: TreeCollection<A>,\n checkSelectable: IdCollectionPredicate,\n options: StrategyOptions\n): Toggler => {\n /**\n * Определение состояния по дочерним элементам\n */\n const _getCumulativeParentState = (set: Set<string>, id: string) => {\n let hasSelectableChild = false;\n const allSelectableChildrenAreSelected = collection.getChildren(id).every((model) => {\n const isSelectable = checkSelectable(model.id, collection);\n hasSelectableChild = hasSelectableChild || isSelectable;\n return set.has(model.id) || !isSelectable;\n });\n return hasSelectableChild ? allSelectableChildrenAreSelected : set.has(id);\n };\n\n /**\n * Простановка состояния всем дочерним элементам\n */\n const _setStateForAllChildren = (set: Set<string>, id: string, state: boolean) => {\n collection.walkChildren(id, (model) => {\n if (checkSelectable(model.id, collection)) {\n dummyToggle(set, model.id, state);\n }\n });\n };\n\n const _toggleOtherParents = (set: Set<string>, id: string) => {\n // когда добавляем-убираем родительскую модель надо проверить и проставить статус другим родителям,\n // у которых есть общие модели-потомки с первоночальной родительской моделью\n if (collection.hasChildren(id)) {\n const childrenIds = collection.getChildrenIds(id);\n const otherParentsIds = childrenIds.reduce<string[]>((result, childrenId) => {\n const parentIds = collection\n .getParentIdsDuplicates(childrenId)\n .filter(\n (parentId) =>\n parentId !== id && !result.includes(parentId) && checkSelectable(parentId, collection)\n );\n return result.concat(parentIds);\n }, []);\n otherParentsIds.forEach((parentId) => dummyToggle(set, parentId, _getCumulativeParentState(set, parentId)));\n }\n };\n\n /**\n * Переключение состояния модели, её родителей и потомков.\n */\n return (set: Set<string>, id: string, state: boolean) => {\n const toggleResult = dummyToggle(set, id, state);\n\n if (toggleResult && !options.withExcluded) {\n collection.walkParents(id, (parent) => {\n if (checkSelectable(parent.id, collection)) {\n dummyToggle(set, parent.id, _getCumulativeParentState(set, parent.id));\n }\n });\n }\n _setStateForAllChildren(set, id, state);\n _toggleOtherParents(set, id);\n };\n};\n\nexport default createTreeCollectionToggler;\n"],"names":["dummyToggle"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import TreeCollection from '../collection/treeCollection';
2
+ import type { AdditionalDefault, IdCollectionPredicate } from '../collection/types';
3
+ import type { Excluder } from '../strategy/types';
4
+ /**
5
+ * Создаёт исключатель элементов в наборе, учитывая набор выбранных элементов (вызывать с готовыми выбранными элементами):
6
+ * — если элемент был выбран, то мы либо удаляем его из "исключенных", либо ничего не делаем;
7
+ * — во всех случаях, когда меняется статус родителя, все его дети исключаются из "исключенных";
8
+ * — если элемент "отключили", то переводим его в "исключенные", но только в том случае, если его родитель выбран
9
+ */
10
+ declare const createTreeCollectionExcluder: <A extends AdditionalDefault>(_collection: TreeCollection<A>, _checkSelectable: IdCollectionPredicate) => Excluder;
11
+ export default createTreeCollectionExcluder;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Проверяет был ли выбран родитель переданного элемента или находится в списке исключенных
3
+ */
4
+ const isParentSelectedOrExcluded = (collection, selectedIds, childId, excluded = []) => {
5
+ const parentId = collection.getParentId(childId);
6
+ return {
7
+ isParentSelected: parentId ? selectedIds.includes(parentId) : false,
8
+ isParentExcluded: Boolean(parentId && excluded.includes(parentId)),
9
+ };
10
+ };
11
+ /**
12
+ * Создаёт исключатель элементов в наборе, учитывая набор выбранных элементов (вызывать с готовыми выбранными элементами):
13
+ * — если элемент был выбран, то мы либо удаляем его из "исключенных", либо ничего не делаем;
14
+ * — во всех случаях, когда меняется статус родителя, все его дети исключаются из "исключенных";
15
+ * — если элемент "отключили", то переводим его в "исключенные", но только в том случае, если его родитель выбран
16
+ */
17
+ const createTreeCollectionExcluder = (_collection, _checkSelectable) => {
18
+ function exclude(items, excluded, ids) {
19
+ if (!items.length) {
20
+ excluded.clear();
21
+ return;
22
+ }
23
+ ids.forEach((id) => {
24
+ if (!_checkSelectable(id, _collection)) {
25
+ return;
26
+ }
27
+ if (excluded.has(id)) {
28
+ excluded.delete(id);
29
+ _collection.walkChildren(id, ({ id: childId }) => _excludeOperationWithChild({ excluded, ids, items, childId, isAdding: false }));
30
+ }
31
+ else {
32
+ const { isParentExcluded, isParentSelected } = isParentSelectedOrExcluded(_collection, items, id, [
33
+ ...excluded,
34
+ ]);
35
+ const isAdding = isParentSelected || isParentExcluded;
36
+ if (isAdding) {
37
+ excluded.add(id);
38
+ }
39
+ _collection.walkChildren(id, ({ id: childId }) => _excludeOperationWithChild({ excluded, ids, items, childId, isAdding }));
40
+ }
41
+ });
42
+ }
43
+ function _excludeOperationWithChild({ excluded, ids, items, childId, isAdding, }) {
44
+ return (!ids.includes(childId) &&
45
+ (isAdding ? !excluded.has(childId) : excluded.has(childId)) &&
46
+ exclude(items, excluded, [childId]));
47
+ }
48
+ return exclude;
49
+ };
50
+
51
+ export { createTreeCollectionExcluder as default };
52
+ //# sourceMappingURL=createTreeSelectionExcluder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTreeSelectionExcluder.js","sources":["../../src/strategy/createTreeSelectionExcluder.ts"],"sourcesContent":["import TreeCollection from '@hh.ru/magritte-ui-tree-selector/collection/treeCollection';\nimport type { AdditionalDefault, IdCollectionPredicate } from '@hh.ru/magritte-ui-tree-selector/collection/types';\nimport type { Excluder } from '@hh.ru/magritte-ui-tree-selector/strategy/types';\n\n/**\n * Проверяет был ли выбран родитель переданного элемента или находится в списке исключенных\n */\nconst isParentSelectedOrExcluded = <A extends AdditionalDefault = never>(\n collection: TreeCollection<A>,\n selectedIds: string[],\n childId: string,\n excluded: string[] = []\n): { isParentSelected: boolean; isParentExcluded: boolean } => {\n const parentId = collection.getParentId(childId);\n\n return {\n isParentSelected: parentId ? selectedIds.includes(parentId) : false,\n isParentExcluded: Boolean(parentId && excluded.includes(parentId)),\n };\n};\n\n/**\n * Создаёт исключатель элементов в наборе, учитывая набор выбранных элементов (вызывать с готовыми выбранными элементами):\n * — если элемент был выбран, то мы либо удаляем его из \"исключенных\", либо ничего не делаем;\n * — во всех случаях, когда меняется статус родителя, все его дети исключаются из \"исключенных\";\n * — если элемент \"отключили\", то переводим его в \"исключенные\", но только в том случае, если его родитель выбран\n */\nconst createTreeCollectionExcluder = <A extends AdditionalDefault>(\n _collection: TreeCollection<A>,\n _checkSelectable: IdCollectionPredicate\n): Excluder => {\n function exclude(items: string[], excluded: Set<string>, ids: string[]) {\n if (!items.length) {\n excluded.clear();\n return;\n }\n\n ids.forEach((id) => {\n if (!_checkSelectable(id, _collection)) {\n return;\n }\n\n if (excluded.has(id)) {\n excluded.delete(id);\n\n _collection.walkChildren(id, ({ id: childId }) =>\n _excludeOperationWithChild({ excluded, ids, items, childId, isAdding: false })\n );\n } else {\n const { isParentExcluded, isParentSelected } = isParentSelectedOrExcluded(_collection, items, id, [\n ...excluded,\n ]);\n\n const isAdding = isParentSelected || isParentExcluded;\n\n if (isAdding) {\n excluded.add(id);\n }\n\n _collection.walkChildren(id, ({ id: childId }) =>\n _excludeOperationWithChild({ excluded, ids, items, childId, isAdding })\n );\n }\n });\n }\n\n function _excludeOperationWithChild({\n excluded,\n ids,\n items,\n childId,\n isAdding,\n }: {\n excluded: Set<string>;\n ids: string[];\n items: string[];\n childId: string;\n isAdding: boolean;\n }) {\n return (\n !ids.includes(childId) &&\n (isAdding ? !excluded.has(childId) : excluded.has(childId)) &&\n exclude(items, excluded, [childId])\n );\n }\n\n return exclude;\n};\n\nexport default createTreeCollectionExcluder;\n"],"names":[],"mappings":"AAIA;;AAEG;AACH,MAAM,0BAA0B,GAAG,CAC/B,UAA6B,EAC7B,WAAqB,EACrB,OAAe,EACf,QAAA,GAAqB,EAAE,KACmC;IAC1D,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAEjD,OAAO;AACH,QAAA,gBAAgB,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,KAAK;QACnE,gBAAgB,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;KACrE,CAAC;AACN,CAAC,CAAC;AAEF;;;;;AAKG;AACH,MAAM,4BAA4B,GAAG,CACjC,WAA8B,EAC9B,gBAAuC,KAC7B;AACV,IAAA,SAAS,OAAO,CAAC,KAAe,EAAE,QAAqB,EAAE,GAAa,EAAA;AAClE,QAAA,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YACf,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO;AACV,SAAA;AAED,QAAA,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,KAAI;AACf,YAAA,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE;gBACpC,OAAO;AACV,aAAA;AAED,YAAA,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;AAClB,gBAAA,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEpB,gBAAA,WAAW,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KACzC,0BAA0B,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CACjF,CAAC;AACL,aAAA;AAAM,iBAAA;AACH,gBAAA,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,GAAG,0BAA0B,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,EAAE;AAC9F,oBAAA,GAAG,QAAQ;AACd,iBAAA,CAAC,CAAC;AAEH,gBAAA,MAAM,QAAQ,GAAG,gBAAgB,IAAI,gBAAgB,CAAC;AAEtD,gBAAA,IAAI,QAAQ,EAAE;AACV,oBAAA,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACpB,iBAAA;AAED,gBAAA,WAAW,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,KACzC,0BAA0B,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAC1E,CAAC;AACL,aAAA;AACL,SAAC,CAAC,CAAC;KACN;AAED,IAAA,SAAS,0BAA0B,CAAC,EAChC,QAAQ,EACR,GAAG,EACH,KAAK,EACL,OAAO,EACP,QAAQ,GAOX,EAAA;AACG,QAAA,QACI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;aACrB,QAAQ,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC3D,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,EACrC;KACL;AAED,IAAA,OAAO,OAAO,CAAC;AACnB;;;;"}
@@ -0,0 +1,6 @@
1
+ import { Toggler } from '../strategy/types';
2
+ /**
3
+ * Переключает элемент в наборе.
4
+ */
5
+ declare const toggle: Toggler;
6
+ export default toggle;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Переключает элемент в наборе.
3
+ */
4
+ const toggle = (set, item, state) => {
5
+ if (state && !set.has(item)) {
6
+ set.add(item);
7
+ return true;
8
+ }
9
+ else if (!state && set.has(item)) {
10
+ set.delete(item);
11
+ return true;
12
+ }
13
+ return false;
14
+ };
15
+
16
+ export { toggle as default };
17
+ //# sourceMappingURL=dummyToggle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dummyToggle.js","sources":["../../src/strategy/dummyToggle.ts"],"sourcesContent":["import { Toggler } from '@hh.ru/magritte-ui-tree-selector/strategy/types';\n\n/**\n * Переключает элемент в наборе.\n */\nconst toggle: Toggler = (set, item, state) => {\n if (state && !set.has(item)) {\n set.add(item);\n return true;\n } else if (!state && set.has(item)) {\n set.delete(item);\n return true;\n }\n return false;\n};\n\nexport default toggle;\n"],"names":[],"mappings":"AAEA;;AAEG;AACG,MAAA,MAAM,GAAY,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,KAAI;IACzC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AACzB,QAAA,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACd,QAAA,OAAO,IAAI,CAAC;AACf,KAAA;SAAM,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;AAChC,QAAA,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACjB,QAAA,OAAO,IAAI,CAAC;AACf,KAAA;AACD,IAAA,OAAO,KAAK,CAAC;AACjB;;;;"}
@@ -0,0 +1,21 @@
1
+ import TreeCollection from '../collection/treeCollection';
2
+ import { AdditionalDefault } from '../collection/types';
3
+ import { StrategyOptions } from '../strategy/types';
4
+ declare class ImmutableSelectionStrategy<A extends AdditionalDefault = never> {
5
+ private strategy;
6
+ constructor(collection: TreeCollection<A>, options: StrategyOptions);
7
+ /**
8
+ * Возвращает новый набор, в котором к `items` добавлены `addedItems`.
9
+ * @param items Текущий набор.
10
+ * @param addedItems Добавляемые элементы.
11
+ */
12
+ add(items: string[], addedItems: string[]): string[];
13
+ exclude(items: string[], excludedItems: string[], processedItems: string[]): string[];
14
+ /**
15
+ * Возвращает новый набор, в котором из `items` удалены `removedItems`.
16
+ * @param items Текущий набор.
17
+ * @param removedItems Удаляемые элементы.
18
+ */
19
+ remove(items: string[], removedItems: string[]): string[];
20
+ }
21
+ export default ImmutableSelectionStrategy;
@@ -0,0 +1,42 @@
1
+ import SelectionStrategy from './selectionStrategy.js';
2
+ import '../collection/treeCollectionHelper.js';
3
+ import '../collection/treeCollection.js';
4
+ import './createSingleValueToggler.js';
5
+ import './createTreeCollectionToggler.js';
6
+ import './dummyToggle.js';
7
+ import './createTreeSelectionExcluder.js';
8
+
9
+ class ImmutableSelectionStrategy {
10
+ strategy;
11
+ constructor(collection, options) {
12
+ this.strategy = new SelectionStrategy(collection, options);
13
+ }
14
+ /**
15
+ * Возвращает новый набор, в котором к `items` добавлены `addedItems`.
16
+ * @param items Текущий набор.
17
+ * @param addedItems Добавляемые элементы.
18
+ */
19
+ add(items, addedItems) {
20
+ const result = new Set(items);
21
+ this.strategy.add(result, addedItems);
22
+ return [...result];
23
+ }
24
+ exclude(items, excludedItems, processedItems) {
25
+ const excluded = new Set(excludedItems);
26
+ this.strategy.exclude(items, excluded, processedItems);
27
+ return [...excluded];
28
+ }
29
+ /**
30
+ * Возвращает новый набор, в котором из `items` удалены `removedItems`.
31
+ * @param items Текущий набор.
32
+ * @param removedItems Удаляемые элементы.
33
+ */
34
+ remove(items, removedItems) {
35
+ const result = new Set(items);
36
+ this.strategy.remove(result, removedItems);
37
+ return [...result];
38
+ }
39
+ }
40
+
41
+ export { ImmutableSelectionStrategy as default };
42
+ //# sourceMappingURL=immutableSelectionStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"immutableSelectionStrategy.js","sources":["../../src/strategy/immutableSelectionStrategy.ts"],"sourcesContent":["import TreeCollection from '@hh.ru/magritte-ui-tree-selector/collection/treeCollection';\nimport { AdditionalDefault } from '@hh.ru/magritte-ui-tree-selector/collection/types';\nimport SelectionStrategy from '@hh.ru/magritte-ui-tree-selector/strategy/selectionStrategy';\nimport { StrategyOptions } from '@hh.ru/magritte-ui-tree-selector/strategy/types';\n\nclass ImmutableSelectionStrategy<A extends AdditionalDefault = never> {\n private strategy: SelectionStrategy<A>;\n\n constructor(collection: TreeCollection<A>, options: StrategyOptions) {\n this.strategy = new SelectionStrategy<A>(collection, options);\n }\n\n /**\n * Возвращает новый набор, в котором к `items` добавлены `addedItems`.\n * @param items Текущий набор.\n * @param addedItems Добавляемые элементы.\n */\n add(items: string[], addedItems: string[]): string[] {\n const result = new Set(items);\n this.strategy.add(result, addedItems);\n return [...result];\n }\n\n exclude(items: string[], excludedItems: string[], processedItems: string[]): string[] {\n const excluded = new Set(excludedItems);\n this.strategy.exclude(items, excluded, processedItems);\n return [...excluded];\n }\n\n /**\n * Возвращает новый набор, в котором из `items` удалены `removedItems`.\n * @param items Текущий набор.\n * @param removedItems Удаляемые элементы.\n */\n remove(items: string[], removedItems: string[]): string[] {\n const result = new Set(items);\n this.strategy.remove(result, removedItems);\n return [...result];\n }\n}\n\nexport default ImmutableSelectionStrategy;\n"],"names":[],"mappings":";;;;;;;;AAKA,MAAM,0BAA0B,CAAA;AACpB,IAAA,QAAQ,CAAuB;IAEvC,WAAY,CAAA,UAA6B,EAAE,OAAwB,EAAA;QAC/D,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,CAAI,UAAU,EAAE,OAAO,CAAC,CAAC;KACjE;AAED;;;;AAIG;IACH,GAAG,CAAC,KAAe,EAAE,UAAoB,EAAA;AACrC,QAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AACtC,QAAA,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;KACtB;AAED,IAAA,OAAO,CAAC,KAAe,EAAE,aAAuB,EAAE,cAAwB,EAAA;AACtE,QAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;AACvD,QAAA,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;KACxB;AAED;;;;AAIG;IACH,MAAM,CAAC,KAAe,EAAE,YAAsB,EAAA;AAC1C,QAAA,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAC3C,QAAA,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;KACtB;AACJ;;;;"}
@@ -0,0 +1,19 @@
1
+ import TreeCollection from '../collection/treeCollection';
2
+ import { AdditionalDefault } from '../collection/types';
3
+ import { StrategyOptions } from '../strategy/types';
4
+ /**
5
+ * Стратегия переключения флага `selected` для иерархической коллекции.
6
+ */
7
+ declare class SelectionStrategy<A extends AdditionalDefault = never> {
8
+ private collection;
9
+ private options;
10
+ private checkSelectable;
11
+ private toggle;
12
+ private runExcluder;
13
+ constructor(collection: TreeCollection<A>, options: StrategyOptions);
14
+ add(items: Set<string>, ids: string[]): void;
15
+ remove(items: Set<string>, ids: string[]): void;
16
+ exclude(items: string[], excluded: Set<string>, ids: string[]): void;
17
+ set(items: Set<string>, ids: string[]): void;
18
+ }
19
+ export default SelectionStrategy;
@@ -0,0 +1,81 @@
1
+ import { filterMissingIds, filterParents } from '../collection/treeCollectionHelper.js';
2
+ import createSingleValueToggler from './createSingleValueToggler.js';
3
+ import createTreeCollectionToggler from './createTreeCollectionToggler.js';
4
+ import createTreeCollectionExcluder from './createTreeSelectionExcluder.js';
5
+ import toggle from './dummyToggle.js';
6
+ import '../collection/treeCollection.js';
7
+
8
+ const _filterSelectable = (collection, ids, checkSelectable) => {
9
+ return ids.filter((id) => checkSelectable(id, collection));
10
+ };
11
+ const defaultCheckSelectable = () => true;
12
+ /**
13
+ * Оставляет в массиве только последний ID
14
+ */
15
+ const _filterMultipleIds = (ids) => {
16
+ if (ids.length > 1) {
17
+ return [ids[ids.length - 1]];
18
+ }
19
+ return ids;
20
+ };
21
+ /**
22
+ * Стратегия переключения флага `selected` для иерархической коллекции.
23
+ */
24
+ class SelectionStrategy {
25
+ collection;
26
+ options;
27
+ checkSelectable;
28
+ toggle;
29
+ runExcluder;
30
+ constructor(collection, options) {
31
+ this.collection = collection;
32
+ this.options = options;
33
+ this.checkSelectable = options.checkSelectable || defaultCheckSelectable;
34
+ this.toggle = options.singleChoice
35
+ ? createSingleValueToggler()
36
+ : createTreeCollectionToggler(collection, this.checkSelectable, { withExcluded: options.withExcluded });
37
+ this.runExcluder = createTreeCollectionExcluder(collection, this.checkSelectable);
38
+ }
39
+ add(items, ids) {
40
+ let filteredIds = filterMissingIds(this.collection, ids);
41
+ if (this.options.singleChoice) {
42
+ filteredIds = _filterMultipleIds(filteredIds);
43
+ }
44
+ if (this.options.leavesOnly) {
45
+ filteredIds = filterParents(this.collection, filteredIds);
46
+ }
47
+ if (this.options.checkSelectable) {
48
+ filteredIds = _filterSelectable(this.collection, filteredIds, this.options.checkSelectable);
49
+ }
50
+ if (this.options.leavesOnly && !this.options.singleChoice) {
51
+ // Тут не нужно выбирать или сбрасывать родителей
52
+ filteredIds.forEach((id) => {
53
+ toggle(items, id, true);
54
+ });
55
+ }
56
+ else {
57
+ filteredIds.forEach((id) => {
58
+ this.toggle(items, id, true);
59
+ });
60
+ }
61
+ }
62
+ remove(items, ids) {
63
+ const filteredIds = filterMissingIds(this.collection, ids);
64
+ filteredIds.forEach((id) => {
65
+ this.toggle(items, id, false);
66
+ });
67
+ }
68
+ exclude(items, excluded, ids) {
69
+ const filteredIds = this.options.checkSelectable
70
+ ? _filterSelectable(this.collection, filterMissingIds(this.collection, ids), this.options.checkSelectable)
71
+ : filterMissingIds(this.collection, ids);
72
+ this.runExcluder(items, excluded, filteredIds);
73
+ }
74
+ set(items, ids) {
75
+ items.clear();
76
+ this.add(items, ids);
77
+ }
78
+ }
79
+
80
+ export { SelectionStrategy as default };
81
+ //# sourceMappingURL=selectionStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectionStrategy.js","sources":["../../src/strategy/selectionStrategy.ts"],"sourcesContent":["import TreeCollection from '@hh.ru/magritte-ui-tree-selector/collection/treeCollection';\nimport { filterMissingIds, filterParents } from '@hh.ru/magritte-ui-tree-selector/collection/treeCollectionHelper';\nimport { AdditionalDefault, IdCollectionPredicate } from '@hh.ru/magritte-ui-tree-selector/collection/types';\nimport createSingleValueToggler from '@hh.ru/magritte-ui-tree-selector/strategy/createSingleValueToggler';\nimport createTreeCollectionToggler from '@hh.ru/magritte-ui-tree-selector/strategy/createTreeCollectionToggler';\nimport createTreeSelectionExcluder from '@hh.ru/magritte-ui-tree-selector/strategy/createTreeSelectionExcluder';\nimport dummyToggle from '@hh.ru/magritte-ui-tree-selector/strategy/dummyToggle';\nimport { StrategyOptions, Toggler, Excluder } from '@hh.ru/magritte-ui-tree-selector/strategy/types';\n\nconst _filterSelectable = <A extends AdditionalDefault>(\n collection: TreeCollection<A>,\n ids: string[],\n checkSelectable: IdCollectionPredicate\n) => {\n return ids.filter((id) => checkSelectable(id, collection));\n};\n\nconst defaultCheckSelectable = () => true;\n\n/**\n * Оставляет в массиве только последний ID\n */\nconst _filterMultipleIds = (ids: string[]) => {\n if (ids.length > 1) {\n return [ids[ids.length - 1]];\n }\n return ids;\n};\n\n/**\n * Стратегия переключения флага `selected` для иерархической коллекции.\n */\nclass SelectionStrategy<A extends AdditionalDefault = never> {\n private collection: TreeCollection<A>;\n private options: StrategyOptions;\n private checkSelectable: IdCollectionPredicate;\n private toggle: Toggler;\n private runExcluder: Excluder;\n\n constructor(collection: TreeCollection<A>, options: StrategyOptions) {\n this.collection = collection;\n this.options = options;\n this.checkSelectable = options.checkSelectable || defaultCheckSelectable;\n this.toggle = options.singleChoice\n ? createSingleValueToggler()\n : createTreeCollectionToggler(collection, this.checkSelectable, { withExcluded: options.withExcluded });\n this.runExcluder = createTreeSelectionExcluder(collection, this.checkSelectable);\n }\n\n add(items: Set<string>, ids: string[]): void {\n let filteredIds = filterMissingIds(this.collection, ids);\n\n if (this.options.singleChoice) {\n filteredIds = _filterMultipleIds(filteredIds);\n }\n if (this.options.leavesOnly) {\n filteredIds = filterParents(this.collection, filteredIds);\n }\n if (this.options.checkSelectable) {\n filteredIds = _filterSelectable(this.collection, filteredIds, this.options.checkSelectable);\n }\n\n if (this.options.leavesOnly && !this.options.singleChoice) {\n // Тут не нужно выбирать или сбрасывать родителей\n filteredIds.forEach((id) => {\n dummyToggle(items, id, true);\n });\n } else {\n filteredIds.forEach((id) => {\n this.toggle(items, id, true);\n });\n }\n }\n\n remove(items: Set<string>, ids: string[]): void {\n const filteredIds = filterMissingIds(this.collection, ids);\n\n filteredIds.forEach((id) => {\n this.toggle(items, id, false);\n });\n }\n\n exclude(items: string[], excluded: Set<string>, ids: string[]): void {\n const filteredIds = this.options.checkSelectable\n ? _filterSelectable(this.collection, filterMissingIds(this.collection, ids), this.options.checkSelectable)\n : filterMissingIds(this.collection, ids);\n\n this.runExcluder(items, excluded, filteredIds);\n }\n\n set(items: Set<string>, ids: string[]): void {\n items.clear();\n this.add(items, ids);\n }\n}\n\nexport default SelectionStrategy;\n"],"names":["createTreeSelectionExcluder","dummyToggle"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { IdCollectionPredicate } from '../collection/types';
2
+ export interface StrategyOptions {
3
+ checkSelectable?: IdCollectionPredicate;
4
+ singleChoice?: boolean;
5
+ withExcluded?: boolean;
6
+ leavesOnly?: boolean;
7
+ }
8
+ export interface Toggler {
9
+ (set: Set<string>, id: string, state: boolean): void | boolean;
10
+ }
11
+ export interface Excluder {
12
+ (items: string[], excluded: Set<string>, ids: string[]): void;
13
+ }
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}