mimir-ui-kit 1.45.0 → 1.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/assets/CheckboxMimir.css +1 -1
  2. package/dist/assets/SelectSearch.css +1 -1
  3. package/dist/assets/useNestedSelection.css +1 -0
  4. package/dist/components/CheckboxMimir/CheckboxMimir.d.ts +2 -0
  5. package/dist/components/CheckboxMimir/CheckboxMimir.js +42 -41
  6. package/dist/components/MultiSelectSearch/MultiSelectSearch.d.ts +5 -1
  7. package/dist/components/MultiSelectSearch/MultiSelectSearch.js +277 -467
  8. package/dist/components/MultiSelectSearch/hooks/useChips.d.ts +18 -0
  9. package/dist/components/MultiSelectSearch/hooks/useChips.js +101 -0
  10. package/dist/components/MultiSelectSearch/hooks/useDataLoading.d.ts +10 -0
  11. package/dist/components/MultiSelectSearch/hooks/useDataLoading.js +21 -0
  12. package/dist/components/MultiSelectSearch/hooks/useEventHandling.d.ts +12 -0
  13. package/dist/components/MultiSelectSearch/hooks/useEventHandling.js +31 -0
  14. package/dist/components/MultiSelectSearch/hooks/useMenuPlacement.d.ts +19 -0
  15. package/dist/components/MultiSelectSearch/hooks/useMenuPlacement.js +38 -0
  16. package/dist/components/MultiSelectSearch/hooks/useMultiSelectState.d.ts +21 -0
  17. package/dist/components/MultiSelectSearch/hooks/useMultiSelectState.js +31 -0
  18. package/dist/components/MultiSelectSearch/hooks/useNestedSelection.d.ts +26 -0
  19. package/dist/components/MultiSelectSearch/hooks/useNestedSelection.js +12 -0
  20. package/dist/components/MultiSelectSearch/hooks/useRenderVirtualizedList.d.ts +30 -0
  21. package/dist/components/MultiSelectSearch/hooks/useRenderVirtualizedList.js +226 -0
  22. package/dist/components/MultiSelectSearch/hooks/useSearch.d.ts +17 -0
  23. package/dist/components/MultiSelectSearch/hooks/useSearch.js +68 -0
  24. package/dist/components/MultiSelectSearch/hooks/useVirtualization.d.ts +18 -0
  25. package/dist/components/MultiSelectSearch/hooks/useVirtualization.js +38 -0
  26. package/dist/components/MultiSelectSearch/types.d.ts +26 -0
  27. package/dist/components/MultiSelectSearch/utils.d.ts +32 -0
  28. package/dist/components/MultiSelectSearch/utils.js +145 -59
  29. package/dist/components/SelectSearch/SelectSearch.d.ts +1 -0
  30. package/dist/components/SelectSearch/SelectSearch.js +304 -324
  31. package/dist/components/SelectSearch/types.d.ts +5 -0
  32. package/dist/components/SelectSearch/utils.js +18 -17
  33. package/dist/useNestedSelection-bo9wXvE-.js +181 -0
  34. package/package.json +1 -1
  35. package/dist/assets/MultiSelectSearch.css +0 -1
@@ -0,0 +1,68 @@
1
+ import { useCallback as M, useMemo as S } from "react";
2
+ import { flattenOptions as V } from "../utils.js";
3
+ const v = ({
4
+ filterOnSearch: h,
5
+ items: a,
6
+ internalSearchQuery: i,
7
+ selectedItems: l,
8
+ enableNestedSelection: u,
9
+ searchInNestedItems: d = !1,
10
+ displayValue: g,
11
+ groupBy: t,
12
+ searchInHeaderGroupItems: w = !1
13
+ }) => {
14
+ const f = M(
15
+ (e) => {
16
+ const r = e[g];
17
+ return typeof r == "string" ? r : String(r || "");
18
+ },
19
+ [g]
20
+ );
21
+ return {
22
+ filteredItems: S(() => {
23
+ if (!h) return a;
24
+ const e = i.toLowerCase();
25
+ if (l.length > 0) {
26
+ const r = l[l.length - 1];
27
+ if (f(r).toLowerCase() === e)
28
+ return a;
29
+ }
30
+ if (u && d) {
31
+ const C = V(a).filter(
32
+ (o) => f(o).toLowerCase().includes(e)
33
+ ), n = new Set(C), c = (o) => {
34
+ o.forEach((s) => {
35
+ s.children && s.children.length > 0 && (s.children.some(
36
+ (L) => n.has(L)
37
+ ) && n.add(s), c(s.children));
38
+ });
39
+ };
40
+ return c(a), Array.from(n);
41
+ }
42
+ if (t && w) {
43
+ const r = /* @__PURE__ */ new Set();
44
+ return a.forEach((n) => {
45
+ t && n[t] && String(n[t]).toLowerCase().includes(e) && r.add(n), n.children && n.children.length > 0 && n.children.forEach((c) => {
46
+ t && c[t] && String(c[t]).toLowerCase().includes(e) && (r.add(c), r.add(n));
47
+ });
48
+ }), Array.from(r);
49
+ }
50
+ return a.filter(
51
+ (r) => f(r).toLowerCase().includes(e)
52
+ );
53
+ }, [
54
+ h,
55
+ a,
56
+ i,
57
+ l,
58
+ u,
59
+ d,
60
+ f,
61
+ t,
62
+ w
63
+ ])
64
+ };
65
+ };
66
+ export {
67
+ v as useSearch
68
+ };
@@ -0,0 +1,18 @@
1
+ import { useVirtualizer } from '@tanstack/react-virtual';
2
+ import { RefObject } from 'react';
3
+ import { EMultiSelectSearchSize } from '../constants';
4
+ import { TMultiSelectOption } from '../types';
5
+
6
+ export type TUseVirtualizationProps = {
7
+ filteredItems: TMultiSelectOption[];
8
+ groupBy?: string;
9
+ getGroupTitle?: (value: string) => string;
10
+ size: EMultiSelectSearchSize;
11
+ parentRef: RefObject<Element | null>;
12
+ };
13
+ export type TUseVirtualizationReturn = {
14
+ virtualItems: TMultiSelectOption[];
15
+ stickyIndices: number[];
16
+ virtualizer: ReturnType<typeof useVirtualizer>;
17
+ };
18
+ export declare const useVirtualization: ({ filteredItems, groupBy, getGroupTitle, size, parentRef }: TUseVirtualizationProps) => TUseVirtualizationReturn;
@@ -0,0 +1,38 @@
1
+ import { u as E } from "../../../index-D5H8gPPn.js";
2
+ import { useMemo as n } from "react";
3
+ import { EMultiSelectSearchSize as S } from "../constants.js";
4
+ import { prepareGroupedItems as f } from "../utils.js";
5
+ const z = 10, s = {
6
+ M: 49,
7
+ L: 65
8
+ }, h = ({
9
+ filteredItems: e,
10
+ groupBy: o,
11
+ getGroupTitle: i,
12
+ size: c,
13
+ parentRef: u
14
+ }) => {
15
+ const r = n(() => o ? f(
16
+ e,
17
+ o,
18
+ i || ((t) => t)
19
+ ) : e, [e, o, i]), a = n(() => {
20
+ const t = [];
21
+ return r.forEach((l, p) => {
22
+ l.isGroupHeader && t.push(p);
23
+ }), t;
24
+ }, [r]), m = E({
25
+ count: r.length,
26
+ getScrollElement: () => u.current,
27
+ estimateSize: () => c === S.L ? s.L : s.M,
28
+ overscan: z
29
+ });
30
+ return {
31
+ virtualItems: r,
32
+ stickyIndices: a,
33
+ virtualizer: m
34
+ };
35
+ };
36
+ export {
37
+ h as useVirtualization
38
+ };
@@ -9,8 +9,14 @@ export type TMultiSelectOption = {
9
9
  bottom?: ReactNode;
10
10
  isGroupHeader?: boolean;
11
11
  originalValue?: string;
12
+ children?: TMultiSelectOption[];
12
13
  [index: string]: unknown;
13
14
  };
15
+ export type TChipItem = {
16
+ id: string | number;
17
+ name: string;
18
+ onClose: () => void;
19
+ };
14
20
  export type TMenuPlacement = 'top' | 'bottom';
15
21
  export type TLoadingIndicatorPlacement = 'input' | 'dropdown' | 'none';
16
22
  export type TMultiSelectSearchProps = Pick<TInputProps, 'withClearButton' | 'variant'> & {
@@ -106,4 +112,24 @@ export type TMultiSelectSearchProps = Pick<TInputProps, 'withClearButton' | 'var
106
112
  * @default false
107
113
  */
108
114
  highlightMatches?: boolean;
115
+ /**
116
+ * Включить поддержку вложенного выбора опций
117
+ * @default false
118
+ */
119
+ enableNestedSelection?: boolean;
120
+ /**
121
+ * Включить поиск во вложенных айтемах при enableNestedSelection = true
122
+ * @default false
123
+ */
124
+ searchInNestedItems?: boolean;
125
+ /**
126
+ * Использовать иконку вместо чекбокса для выбранных элементов
127
+ * @default false
128
+ */
129
+ useIconInsteadOfCheckbox?: boolean;
130
+ /**
131
+ * Включить поиск по хедерам группы вложенных элементов в режиме группировки
132
+ * @default false
133
+ */
134
+ searchInHeaderGroupItems?: boolean;
109
135
  };
@@ -27,3 +27,35 @@ export declare const highlightReactNode: (node: ReactNode, searchQuery: string,
27
27
  * @returns Массив частей текста, где совпадения обернуты в span с классом.
28
28
  */
29
29
  export declare const highlightText: (text: string, searchQuery: string, highlightClassName: string) => (string | ReactElement)[];
30
+ /**
31
+ * Рекурсивно получает все дочерние ID для опции.
32
+ */
33
+ export declare const getAllChildrenIds: (option: TMultiSelectOption, allOptions: TMultiSelectOption[]) => (number | string)[];
34
+ /**
35
+ * Получает плоский список всех опций, включая вложенные.
36
+ */
37
+ export declare const flattenOptions: (options: TMultiSelectOption[]) => TMultiSelectOption[];
38
+ /**
39
+ * Проверяет, выбрана ли опция, учитывая дочерние.
40
+ */
41
+ export declare const isOptionSelected: (option: TMultiSelectOption, selectedIds: (number | string)[]) => boolean;
42
+ /**
43
+ * Получает количество выбранных дочерних опций.
44
+ */
45
+ export declare const getSelectedChildrenCount: (option: TMultiSelectOption, selectedIds: (number | string)[]) => number;
46
+ /**
47
+ * Получает общее количество дочерних опций.
48
+ */
49
+ export declare const getTotalChildrenCount: (option: TMultiSelectOption) => number;
50
+ /**
51
+ * Форматирует отображение опции с счетчиком выбранных дочерних.
52
+ */
53
+ export declare const formatOptionWithCount: (option: TMultiSelectOption, selectedIds: (number | string)[], displayValue: string) => string;
54
+ /**
55
+ * Обрабатывает изменение выбора для nested selection.
56
+ */
57
+ export declare const processNestedSelectionChange: (newValue: TMultiSelectOption[], selectedItems: TMultiSelectOption[], items: TMultiSelectOption[]) => TMultiSelectOption[];
58
+ /**
59
+ * Обновляет значение input после изменения выбора.
60
+ */
61
+ export declare const updateInputValueAfterChange: (updatedValue: TMultiSelectOption[], enableNestedSelection: boolean, items: TMultiSelectOption[], displayValue: string) => string;
@@ -1,89 +1,175 @@
1
- import { createElement as u, Fragment as l, isValidElement as m, cloneElement as w } from "react";
2
- import { EMultiSelectSearchSize as s, MOBILE_MENU_HEIGHT as g, DESKTOP_MENU_HEIGHT as f } from "./constants.js";
1
+ import { createElement as a, Fragment as I, isValidElement as E, cloneElement as S } from "react";
2
+ import { EMultiSelectSearchSize as h, MOBILE_MENU_HEIGHT as C, DESKTOP_MENU_HEIGHT as A } from "./constants.js";
3
3
  import "../../Input-IzZ6B9kw.js";
4
- import { EInputSize as c } from "../Input/constants.js";
5
- const T = (t) => {
4
+ import { EInputSize as f } from "../Input/constants.js";
5
+ const v = (t) => {
6
6
  switch (t) {
7
- case s.M:
8
- return c.M;
9
- case s.L:
10
- return c.L;
7
+ case h.M:
8
+ return f.M;
9
+ case h.L:
10
+ return f.L;
11
11
  default:
12
- return c.M;
12
+ return f.M;
13
13
  }
14
- }, x = (t, r) => t ? r === s.L ? "DropdownArrowUp24px" : "DropdownArrowUp16px" : r === s.L ? "DropdownArrowDown24px" : "DropdownArrowBottom16px", A = (t, r) => t && t.length > 0 ? t.map((e) => e[r]).join(", ") : "", H = (t, r) => t.map((e) => e[r]).join(", "), h = "multiselectOpen", D = (t) => {
15
- window.dispatchEvent(new CustomEvent(h, { detail: t }));
16
- }, L = (t, r) => {
14
+ }, G = (t, n) => t ? n === h.L ? "DropdownArrowUp24px" : "DropdownArrowUp16px" : n === h.L ? "DropdownArrowDown24px" : "DropdownArrowBottom16px", U = (t, n) => t && t.length > 0 ? t.map((r) => r[n]).join(", ") : "", M = (t, n) => t.map((r) => r[n]).join(", "), T = "multiselectOpen", j = (t) => {
15
+ window.dispatchEvent(new CustomEvent(T, { detail: t }));
16
+ }, R = (t, n) => {
17
17
  if (!t.current) return !1;
18
- const e = t.current.getBoundingClientRect(), n = window.innerHeight, p = r === s.M ? g : f, o = n - e.bottom, i = e.top;
19
- return o >= p ? !1 : i > o;
20
- }, O = (t, r, e) => {
21
- if (!t.length || !r) return t;
22
- const n = [], p = /* @__PURE__ */ new Set();
23
- for (const o of t) {
24
- const i = String(o[r] || "Без группы");
25
- p.has(i) || (p.add(i), n.push({
26
- id: `group-header-${i}`,
27
- name: e(i),
18
+ const r = t.current.getBoundingClientRect(), e = window.innerHeight, i = n === h.M ? C : A, s = e - r.bottom, c = r.top;
19
+ return s >= i ? !1 : c > s;
20
+ }, z = (t, n, r) => {
21
+ if (!t.length || !n) return t;
22
+ const e = [], i = /* @__PURE__ */ new Set();
23
+ for (const s of t) {
24
+ const c = String(s[n] || "Без группы");
25
+ i.has(c) || (i.add(c), e.push({
26
+ id: `group-header-${c}`,
27
+ name: r(c),
28
28
  isGroupHeader: !0,
29
- originalValue: i
30
- })), n.push(o);
29
+ originalValue: c
30
+ })), e.push(s);
31
31
  }
32
- return n;
33
- }, a = (t, r, e) => {
34
- if (!r.trim())
32
+ return e;
33
+ }, m = (t, n, r) => {
34
+ if (!n.trim())
35
35
  return t;
36
36
  if (typeof t == "string") {
37
- const n = E(
37
+ const e = O(
38
38
  t,
39
- r,
40
- e
39
+ n,
40
+ r
41
41
  );
42
- return u(
42
+ return a(
43
43
  "span",
44
44
  { className: "highlighted-text-wrapper" },
45
- n
45
+ e
46
46
  );
47
47
  }
48
48
  return Array.isArray(t) ? t.map(
49
- (n, p) => u(
50
- l,
51
- { key: p },
52
- a(n, r, e)
49
+ (e, i) => a(
50
+ I,
51
+ { key: i },
52
+ m(e, n, r)
53
53
  )
54
- ) : m(t) ? w(t, {
54
+ ) : E(t) ? S(t, {
55
55
  ...t.props,
56
- children: a(
56
+ children: m(
57
57
  t.props.children,
58
- r,
59
- e
58
+ n,
59
+ r
60
60
  )
61
61
  }) : t;
62
- }, E = (t, r, e) => {
63
- if (!r.trim())
62
+ }, O = (t, n, r) => {
63
+ if (!n.trim())
64
64
  return [t];
65
- const n = new RegExp(
66
- `(${r.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`,
65
+ const e = new RegExp(
66
+ `(${n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")})`,
67
67
  "gi"
68
68
  );
69
- return t.split(n).map((o, i) => n.test(o) ? u(
69
+ return t.split(e).map((s, c) => e.test(s) ? a(
70
70
  "span",
71
71
  {
72
- key: i,
73
- className: e
72
+ key: c,
73
+ className: r,
74
+ "data-testid": "highlighted-match"
74
75
  },
75
- o
76
- ) : o);
76
+ s
77
+ ) : s);
78
+ }, p = (t, n) => {
79
+ const r = [];
80
+ if (t.children)
81
+ for (const e of t.children)
82
+ r.push(e.id), r.push(...p(e));
83
+ return r;
84
+ }, x = (t) => {
85
+ const n = [], r = (e) => {
86
+ for (const i of e)
87
+ n.push(i), i.children && r(i.children);
88
+ };
89
+ return r(t), n;
90
+ }, B = (t, n) => n.includes(t.id) ? !0 : p(t).some((e) => n.includes(e)), g = (t, n) => p(t).filter((e) => n.includes(e)).length, H = (t) => p(t).length, D = (t, n, r) => {
91
+ const e = g(t, n), i = H(t);
92
+ return i === 0 ? String(t[r] || "") : `${t[r]} (${e} из ${i})`;
93
+ }, P = (t, n, r) => {
94
+ let e = t;
95
+ const i = t.filter(
96
+ (o) => !n.some((d) => d.id === o.id)
97
+ ), s = n.filter(
98
+ (o) => !t.some((d) => d.id === o.id)
99
+ );
100
+ for (const o of i)
101
+ if (o.children && o.children.length > 0) {
102
+ const d = p(o), l = x(r).filter(
103
+ (u) => d.includes(u.id)
104
+ );
105
+ e = [...e, ...l];
106
+ } else {
107
+ const d = r.find(
108
+ (l) => {
109
+ var u;
110
+ return (u = l.children) == null ? void 0 : u.some((w) => w.id === o.id);
111
+ }
112
+ );
113
+ d && !e.some((l) => l.id === d.id) && (e = [...e, d]);
114
+ }
115
+ for (const o of s) {
116
+ const d = p(o);
117
+ e = e.filter((l) => !d.includes(l.id));
118
+ }
119
+ e = e.filter(
120
+ (o, d, l) => d === l.findIndex((u) => u.id === o.id)
121
+ );
122
+ const c = [];
123
+ for (const o of e)
124
+ o.children && o.children.length > 0 && g(
125
+ o,
126
+ e.map((l) => l.id)
127
+ ) === 0 && c.push(o.id);
128
+ return e = e.filter(
129
+ (o) => !c.includes(o.id)
130
+ ), e;
131
+ }, b = (t, n, r, e) => {
132
+ if (n) {
133
+ const i = /* @__PURE__ */ new Set();
134
+ for (const s of t)
135
+ if (s.children && s.children.length > 0)
136
+ i.add(s);
137
+ else {
138
+ const c = r.find(
139
+ (o) => {
140
+ var d;
141
+ return (d = o.children) == null ? void 0 : d.some((l) => l.id === s.id);
142
+ }
143
+ );
144
+ c ? i.add(c) : i.add(s);
145
+ }
146
+ return Array.from(i).map(
147
+ (s) => D(
148
+ s,
149
+ t.map((c) => c.id),
150
+ e
151
+ )
152
+ ).join(", ");
153
+ }
154
+ return M(t, e);
77
155
  };
78
156
  export {
79
- h as MULTISELECT_OPEN_EVENT,
80
- D as dispatchMultiselectOpen,
81
- x as getDropdownArrowIcon,
82
- A as getInitialInputValue,
83
- a as highlightReactNode,
84
- E as highlightText,
85
- H as joinSelectedItems,
86
- T as mapSizeToInputSize,
87
- O as prepareGroupedItems,
88
- L as shouldShowMenuOnTop
157
+ T as MULTISELECT_OPEN_EVENT,
158
+ j as dispatchMultiselectOpen,
159
+ x as flattenOptions,
160
+ D as formatOptionWithCount,
161
+ p as getAllChildrenIds,
162
+ G as getDropdownArrowIcon,
163
+ U as getInitialInputValue,
164
+ g as getSelectedChildrenCount,
165
+ H as getTotalChildrenCount,
166
+ m as highlightReactNode,
167
+ O as highlightText,
168
+ B as isOptionSelected,
169
+ M as joinSelectedItems,
170
+ v as mapSizeToInputSize,
171
+ z as prepareGroupedItems,
172
+ P as processNestedSelectionChange,
173
+ R as shouldShowMenuOnTop,
174
+ b as updateInputValueAfterChange
89
175
  };
@@ -32,4 +32,5 @@ export declare const SelectSearch: import('react').ForwardRefExoticComponent<Pic
32
32
  autoPlacement?: boolean;
33
33
  borderRadius?: ESelectSearchBorderRadius | `${ESelectSearchBorderRadius}`;
34
34
  highlightMatches?: boolean;
35
+ searchInHeaderGroupItems?: boolean;
35
36
  } & import('react').RefAttributes<HTMLElement>>;