@fibery/ui-kit 1.42.0 → 2.0.1
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/.oxlintrc.json +24 -0
- package/CHANGELOG.md +20 -0
- package/eslint.config.mjs +1 -1
- package/jest.config.cjs +36 -0
- package/package.json +12 -52
- package/src/@types/css.d.ts +1 -0
- package/src/actions-menu/actions-menu-checkbox-item.tsx +74 -0
- package/src/actions-menu/contexts/actions-menu-context.tsx +1 -0
- package/src/actions-menu/index.tsx +1 -0
- package/src/animated-number.tsx +2 -2
- package/src/antd/AutoComplete.d.ts +1 -0
- package/src/app-icon-with-fallback.tsx +4 -4
- package/src/app-icon.tsx +4 -4
- package/src/appIcons.json +1227 -1227
- package/src/avatar.tsx +44 -5
- package/src/box.tsx +10 -17
- package/src/button/make-button-colors.ts +13 -13
- package/src/checkbox.tsx +3 -3
- package/src/collapsible-section.tsx +1 -1
- package/src/context-menu/index.tsx +4 -0
- package/src/date-picker/date-range-picker.tsx +1 -1
- package/src/date-picker/relative-date-picker.tsx +3 -0
- package/src/date-picker/single-date-picker.tsx +10 -9
- package/src/design-system/alpha.ts +9 -0
- package/src/design-system/colors-css.test.ts +1 -9
- package/src/design-system/colors-css.ts +1 -1
- package/src/design-system/colors.ts +351 -313
- package/src/design-system/layout.ts +1 -1
- package/src/design-system/theme.ts +4 -1
- package/src/design-system/vars.test.ts +4 -0
- package/src/design-system.test.ts +1 -0
- package/src/design-system.ts +1 -1
- package/src/dropdown-menu/index.tsx +4 -0
- package/src/emoji-picker/primitives/emoji.tsx +12 -0
- package/src/emoji-picker/primitives/grid.tsx +100 -104
- package/src/emoji.tsx +1 -0
- package/src/file-item.tsx +308 -265
- package/src/icons/ast/AddDatabase.ts +1 -1
- package/src/icons/ast/AddIntegration.ts +1 -1
- package/src/icons/ast/ArrowsRightLeft.ts +1 -1
- package/src/icons/ast/ChatBubble.ts +1 -1
- package/src/icons/ast/ChatFloat.ts +1 -1
- package/src/icons/ast/ChatSidebar.ts +1 -1
- package/src/icons/ast/Clean.ts +1 -1
- package/src/icons/ast/Create.ts +1 -1
- package/src/icons/ast/ItemsTimeline.ts +1 -1
- package/src/icons/ast/Key.ts +1 -1
- package/src/icons/ast/NetworkAdd.ts +1 -1
- package/src/icons/ast/Print.ts +1 -1
- package/src/icons/ast/Success.ts +1 -1
- package/src/icons/ast/SuggestIntegration.ts +1 -1
- package/src/icons/ast/WarningTriangle.ts +1 -1
- package/src/icons/ast/Windows.ts +1 -1
- package/src/icons/svg/add-database.svg +1 -1
- package/src/icons/svg/add-integration.svg +1 -1
- package/src/icons/svg/arrows-right-left.svg +1 -1
- package/src/icons/svg/chat-bubble.svg +1 -1
- package/src/icons/svg/chat-float.svg +1 -1
- package/src/icons/svg/chat-sidebar.svg +3 -3
- package/src/icons/svg/clean.svg +1 -1
- package/src/icons/svg/create.svg +1 -1
- package/src/icons/svg/items-timeline.svg +1 -1
- package/src/icons/svg/key.svg +1 -1
- package/src/icons/svg/network-add.svg +1 -1
- package/src/icons/svg/print.svg +1 -1
- package/src/icons/svg/success.svg +1 -1
- package/src/icons/svg/suggest-integration.svg +1 -1
- package/src/icons/svg/warning-triangle.svg +1 -1
- package/src/icons/svg/windows.svg +1 -1
- package/src/images-gallery/images-gallery.tsx +24 -0
- package/src/lists/actions-menu-row-surface.tsx +2 -1
- package/src/logo.tsx +14 -13
- package/src/modal-menu/index.tsx +1 -0
- package/src/modal-menu/modal-menu-checkbox-item.tsx +50 -0
- package/src/online-users.tsx +45 -46
- package/src/palettes/slate-arch.colors-snapshot.test.ts +7 -7
- package/src/palettes/slate-user.colors-snapshot.test.ts +11 -11
- package/src/palettes/warm-arch.colors-snapshot.test.ts +7 -7
- package/src/palettes/warm-user.colors-snapshot.test.ts +7 -7
- package/src/popover/index.tsx +91 -203
- package/src/popover/popover-old.tsx +113 -0
- package/src/popover/popup-modifiers-context.ts +1 -1
- package/src/scale-generator.ts +2 -2
- package/src/select/components/clear-indicator.tsx +1 -1
- package/src/select/components/drop-down-indicator.tsx +2 -2
- package/src/select/components/group-heading.tsx +2 -2
- package/src/select/components/menu-list-virtualized.tsx +1 -1
- package/src/select/components/option.tsx +1 -1
- package/src/select/index.tsx +34 -37
- package/src/select/select-in-popover.tsx +34 -202
- package/src/select/select.tsx +5 -4
- package/src/select/styles.ts +3 -0
- package/src/thematic-state.ts +1 -1
- package/src/theme-provider.tsx +14 -2
- package/src/theme-styles.ts +14 -7
- package/src/toggle-button/toggle-button.tsx +48 -35
- package/src/tree-utils.test.ts +166 -0
- package/src/tree-utils.ts +107 -0
- package/src/file-item/use-register-in-image-gallery.tsx +0 -70
- package/src/file-item-2.tsx +0 -357
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {css, cx} from "@linaria/core";
|
|
1
|
+
import {css, cx, CSSProperties} from "@linaria/core";
|
|
2
2
|
import {Toggle, ToggleProps} from "@radix-ui/react-toggle";
|
|
3
3
|
import {forwardRef} from "react";
|
|
4
4
|
import {border, space, textStyles, themeVars} from "../design-system";
|
|
@@ -18,15 +18,15 @@ export const toggleButtonCss = css`
|
|
|
18
18
|
transition-property: border, background-color, color, opacity, box-shadow;
|
|
19
19
|
transition-duration: 0.15s;
|
|
20
20
|
|
|
21
|
-
color:
|
|
22
|
-
${iconColorVar}:
|
|
21
|
+
color: var(--fibery-toggle-button-default-text-color);
|
|
22
|
+
${iconColorVar}: var(--fibery-toggle-button-default-icon-color);
|
|
23
23
|
|
|
24
|
-
border: 1.5px solid
|
|
25
|
-
background-color:
|
|
24
|
+
border: 1.5px solid var(--fibery-toggle-button-default-border-color);
|
|
25
|
+
background-color: var(--fibery-toggle-button-default-color);
|
|
26
26
|
|
|
27
27
|
&[aria-readonly="true"] {
|
|
28
|
-
background-color:
|
|
29
|
-
border-color:
|
|
28
|
+
background-color: var(--fibery-toggle-button-default-hover-color);
|
|
29
|
+
border-color: var(--fibery-toggle-button-default-hover-color);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
cursor: pointer;
|
|
@@ -59,19 +59,11 @@ export const toggleButtonCss = css`
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
&:not(:disabled, [aria-readonly="true"]) {
|
|
62
|
-
&:hover
|
|
63
|
-
background-color: ${themeVars.colorBgReactionsHover};
|
|
64
|
-
border-color: ${themeVars.colorBorderReactionsHover};
|
|
65
|
-
}
|
|
66
|
-
|
|
62
|
+
&:hover,
|
|
67
63
|
&:is(:active, [aria-expanded="true"]) {
|
|
68
|
-
background-color:
|
|
69
|
-
border-color:
|
|
70
|
-
|
|
71
|
-
&:is([aria-pressed="true"], [aria-checked="true"]) {
|
|
72
|
-
background-color: ${themeVars.colorBgReactionsSelectedHover};
|
|
73
|
-
border-color: ${themeVars.colorBorderReactionsSelectedHover};
|
|
74
|
-
}
|
|
64
|
+
background-color: var(--fibery-toggle-button-default-hover-color);
|
|
65
|
+
border-color: var(--fibery-toggle-button-default-border-color);
|
|
66
|
+
color: var(--fibery-toggle-button-default-hover-text-color);
|
|
75
67
|
}
|
|
76
68
|
}
|
|
77
69
|
|
|
@@ -85,30 +77,27 @@ export const toggleButtonCss = css`
|
|
|
85
77
|
}
|
|
86
78
|
|
|
87
79
|
&:focus-visible {
|
|
88
|
-
background-color:
|
|
89
|
-
outline: 2px solid
|
|
80
|
+
background-color: var(--fibery-toggle-button-default-hover-color);
|
|
81
|
+
outline: 2px solid var(--fibery-toggle-button-default-border-color);
|
|
90
82
|
}
|
|
91
83
|
|
|
92
84
|
&:is([aria-pressed="true"], [aria-checked="true"]) {
|
|
93
|
-
color:
|
|
94
|
-
${iconColorVar}:
|
|
95
|
-
background-color:
|
|
96
|
-
border-color:
|
|
85
|
+
color: var(--fibery-toggle-button-pressed-text-color);
|
|
86
|
+
${iconColorVar}: var(--fibery-toggle-button-pressed-icon-color);
|
|
87
|
+
background-color: var(--fibery-toggle-button-pressed-color);
|
|
88
|
+
border-color: var(--fibery-toggle-button-pressed-border-color);
|
|
97
89
|
|
|
98
90
|
&[aria-readonly="true"] {
|
|
99
|
-
background-color:
|
|
100
|
-
border-color:
|
|
91
|
+
background-color: var(--fibery-toggle-button-pressed-color);
|
|
92
|
+
border-color: var(--fibery-toggle-button-pressed-color);
|
|
101
93
|
}
|
|
102
94
|
|
|
103
95
|
&:not(:disabled, [aria-readonly="true"]) {
|
|
104
|
-
&:hover
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
&:active {
|
|
110
|
-
background-color: ${themeVars.colorBgReactionsSelectedDefault};
|
|
111
|
-
border-color: ${themeVars.colorBorderReactionsSelectedHover};
|
|
96
|
+
&:hover,
|
|
97
|
+
&:is(:active, [aria-expanded="true"]) {
|
|
98
|
+
background-color: var(--fibery-toggle-button-pressed-hover-color);
|
|
99
|
+
border-color: var(--fibery-toggle-button-pressed-hover-border-color);
|
|
100
|
+
color: var(--fibery-toggle-button-pressed-hover-text-color);
|
|
112
101
|
}
|
|
113
102
|
}
|
|
114
103
|
}
|
|
@@ -138,6 +127,26 @@ export const toggleButtonContent = css`
|
|
|
138
127
|
overflow: hidden;
|
|
139
128
|
`;
|
|
140
129
|
|
|
130
|
+
const getColors = (): CSSProperties => {
|
|
131
|
+
return {
|
|
132
|
+
"--fibery-toggle-button-default-color": themeVars.colorBgReactionsDefault,
|
|
133
|
+
"--fibery-toggle-button-default-text-color": themeVars.colorTextButtonGhostNeutral,
|
|
134
|
+
"--fibery-toggle-button-default-icon-color": themeVars.colorIconButtonGhostNeutral,
|
|
135
|
+
"--fibery-toggle-button-default-border-color": themeVars.colorBorderReactionsHover,
|
|
136
|
+
"--fibery-toggle-button-default-hover-color": themeVars.colorBgReactionsHover,
|
|
137
|
+
"--fibery-toggle-button-default-hover-text-color": themeVars.colorTextButtonGhostNeutral,
|
|
138
|
+
"--fibery-toggle-button-default-hover-border-color": themeVars.colorBorderReactionsHover,
|
|
139
|
+
|
|
140
|
+
"--fibery-toggle-button-pressed-color": themeVars.colorBgReactionsSelectedDefault,
|
|
141
|
+
"--fibery-toggle-button-pressed-text-color": themeVars.colorTextReactionsSelected,
|
|
142
|
+
"--fibery-toggle-button-pressed-icon-color": themeVars.colorIconButtonGhostAccent,
|
|
143
|
+
"--fibery-toggle-button-pressed-border-color": themeVars.colorBorderReactionsSelectedDefault,
|
|
144
|
+
"--fibery-toggle-button-pressed-hover-color": themeVars.colorBgReactionsSelectedHover,
|
|
145
|
+
"--fibery-toggle-button-pressed-hover-text-color": themeVars.colorTextReactionsSelected,
|
|
146
|
+
"--fibery-toggle-button-pressed-hover-border-color": themeVars.colorBorderReactionsSelectedHover,
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
|
|
141
150
|
export type ToggleButtonVariant = "outline";
|
|
142
151
|
export type ToggleButtonSize = "small" | "medium" | "large";
|
|
143
152
|
|
|
@@ -156,14 +165,18 @@ export const ToggleButton = forwardRef<HTMLButtonElement, ToggleButtonProps>(
|
|
|
156
165
|
size = "small",
|
|
157
166
|
variant = "outline",
|
|
158
167
|
children,
|
|
168
|
+
style,
|
|
159
169
|
"aria-readonly": ariaReadonly,
|
|
160
170
|
readOnly = ariaReadonly,
|
|
161
171
|
...props
|
|
162
172
|
},
|
|
163
173
|
ref
|
|
164
174
|
): JSX.Element => {
|
|
175
|
+
const colors = getColors();
|
|
176
|
+
|
|
165
177
|
return (
|
|
166
178
|
<Toggle
|
|
179
|
+
style={{...colors, ...style}}
|
|
167
180
|
ref={ref}
|
|
168
181
|
className={cx(toggleButtonCss, iconStart && toggleButtonCssWithIconStart, className)}
|
|
169
182
|
data-variant={variant}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import {flattenTree, mutateTree, TreeData} from "./tree-utils";
|
|
2
|
+
|
|
3
|
+
const makeTree = (): TreeData => ({
|
|
4
|
+
rootId: "root",
|
|
5
|
+
items: {
|
|
6
|
+
root: {id: "root", children: ["a", "b"]},
|
|
7
|
+
a: {id: "a", children: ["a1", "a2"], isExpanded: false},
|
|
8
|
+
a1: {id: "a1", children: []},
|
|
9
|
+
a2: {id: "a2", children: []},
|
|
10
|
+
b: {id: "b", children: [], isExpanded: false},
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe("flattenTree", () => {
|
|
15
|
+
it("returns empty array when rootId is missing from items", () => {
|
|
16
|
+
const tree: TreeData = {rootId: "missing", items: {}};
|
|
17
|
+
expect(flattenTree(tree)).toEqual([]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns top-level children with correct paths", () => {
|
|
21
|
+
const tree = makeTree();
|
|
22
|
+
const result = flattenTree(tree);
|
|
23
|
+
|
|
24
|
+
expect(result).toHaveLength(2);
|
|
25
|
+
expect(result[0].item.id).toBe("a");
|
|
26
|
+
expect(result[0].path).toEqual([0]);
|
|
27
|
+
expect(result[1].item.id).toBe("b");
|
|
28
|
+
expect(result[1].path).toEqual([1]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("does not include children of collapsed nodes", () => {
|
|
32
|
+
const tree = makeTree();
|
|
33
|
+
const result = flattenTree(tree);
|
|
34
|
+
|
|
35
|
+
const ids = result.map((r) => r.item.id);
|
|
36
|
+
expect(ids).not.toContain("a1");
|
|
37
|
+
expect(ids).not.toContain("a2");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("includes children of expanded nodes", () => {
|
|
41
|
+
const tree = makeTree();
|
|
42
|
+
tree.items["a"] = {...tree.items["a"], isExpanded: true};
|
|
43
|
+
|
|
44
|
+
const result = flattenTree(tree);
|
|
45
|
+
const ids = result.map((r) => r.item.id);
|
|
46
|
+
|
|
47
|
+
expect(ids).toEqual(["a", "a1", "a2", "b"]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("assigns correct nested paths for expanded children", () => {
|
|
51
|
+
const tree = makeTree();
|
|
52
|
+
tree.items["a"] = {...tree.items["a"], isExpanded: true};
|
|
53
|
+
|
|
54
|
+
const result = flattenTree(tree);
|
|
55
|
+
|
|
56
|
+
expect(result[1].item.id).toBe("a1");
|
|
57
|
+
expect(result[1].path).toEqual([0, 0]);
|
|
58
|
+
expect(result[2].item.id).toBe("a2");
|
|
59
|
+
expect(result[2].path).toEqual([0, 1]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("handles multiple levels of expansion", () => {
|
|
63
|
+
const tree: TreeData = {
|
|
64
|
+
rootId: "root",
|
|
65
|
+
items: {
|
|
66
|
+
root: {id: "root", children: ["a"]},
|
|
67
|
+
a: {id: "a", children: ["a1"], isExpanded: true},
|
|
68
|
+
a1: {id: "a1", children: ["a1a"], isExpanded: true},
|
|
69
|
+
a1a: {id: "a1a", children: []},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const result = flattenTree(tree);
|
|
74
|
+
expect(result.map((r) => r.item.id)).toEqual(["a", "a1", "a1a"]);
|
|
75
|
+
expect(result[2].path).toEqual([0, 0, 0]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("returns empty array when root has no children", () => {
|
|
79
|
+
const tree: TreeData = {
|
|
80
|
+
rootId: "root",
|
|
81
|
+
items: {root: {id: "root", children: []}},
|
|
82
|
+
};
|
|
83
|
+
expect(flattenTree(tree)).toEqual([]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("preserves original path prefix when called with initial path", () => {
|
|
87
|
+
const tree: TreeData = {
|
|
88
|
+
rootId: "root",
|
|
89
|
+
items: {
|
|
90
|
+
root: {id: "root", children: ["a"]},
|
|
91
|
+
a: {id: "a", children: []},
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const result = flattenTree(tree, [5, 3]);
|
|
96
|
+
expect(result[0].path).toEqual([5, 3, 0]);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe("mutateTree", () => {
|
|
101
|
+
it("returns the same tree reference when itemId is not found", () => {
|
|
102
|
+
const tree = makeTree();
|
|
103
|
+
const result = mutateTree(tree, "nonexistent", {isExpanded: true});
|
|
104
|
+
expect(result).toBe(tree);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("preserves rootId", () => {
|
|
108
|
+
const tree = makeTree();
|
|
109
|
+
const result = mutateTree(tree, "a", {isExpanded: true});
|
|
110
|
+
expect(result.rootId).toBe(tree.rootId);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("applies mutation to the target item", () => {
|
|
114
|
+
const tree = makeTree();
|
|
115
|
+
const result = mutateTree(tree, "a", {isExpanded: true});
|
|
116
|
+
expect(result.items["a"].isExpanded).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("does not mutate the original tree", () => {
|
|
120
|
+
const tree = makeTree();
|
|
121
|
+
mutateTree(tree, "a", {isExpanded: true});
|
|
122
|
+
expect(tree.items["a"].isExpanded).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("does not change other items references", () => {
|
|
126
|
+
const tree = makeTree();
|
|
127
|
+
const result = mutateTree(tree, "a", {isExpanded: true});
|
|
128
|
+
expect(result.items["b"]).toBe(tree.items["b"]);
|
|
129
|
+
expect(result.items["a1"]).toBe(tree.items["a1"]);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("merges partial mutation fields", () => {
|
|
133
|
+
const tree = makeTree();
|
|
134
|
+
tree.items["a"] = {...tree.items["a"], hasChildren: true, isExpanded: false};
|
|
135
|
+
|
|
136
|
+
const result = mutateTree(tree, "a", {isExpanded: true});
|
|
137
|
+
expect(result.items["a"].hasChildren).toBe(true);
|
|
138
|
+
expect(result.items["a"].isExpanded).toBe(true);
|
|
139
|
+
expect(result.items["a"].children).toEqual(["a1", "a2"]);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("can update children array", () => {
|
|
143
|
+
const tree = makeTree();
|
|
144
|
+
const result = mutateTree(tree, "b", {children: ["new-child"]});
|
|
145
|
+
expect(result.items["b"].children).toEqual(["new-child"]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("can update data field", () => {
|
|
149
|
+
const tree = makeTree();
|
|
150
|
+
const data = {name: "Node A"};
|
|
151
|
+
const result = mutateTree(tree, "a", {data});
|
|
152
|
+
expect(result.items["a"].data).toBe(data);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("returns a new items object reference", () => {
|
|
156
|
+
const tree = makeTree();
|
|
157
|
+
const result = mutateTree(tree, "a", {isExpanded: true});
|
|
158
|
+
expect(result.items).not.toBe(tree.items);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("returns a new item object reference for the mutated item", () => {
|
|
162
|
+
const tree = makeTree();
|
|
163
|
+
const result = mutateTree(tree, "a", {isExpanded: true});
|
|
164
|
+
expect(result.items["a"]).not.toBe(tree.items["a"]);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import {$TSFixMe} from "@fibery/ui-kit/src/tsfixme";
|
|
2
|
+
|
|
3
|
+
export type ItemId = string | number;
|
|
4
|
+
export interface TreeData {
|
|
5
|
+
rootId: ItemId;
|
|
6
|
+
items: Record<ItemId, TreeItem>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type TreeItemData = $TSFixMe;
|
|
10
|
+
export type TreeItem = {
|
|
11
|
+
id: ItemId;
|
|
12
|
+
children: ItemId[];
|
|
13
|
+
hasChildren?: boolean;
|
|
14
|
+
isExpanded?: boolean;
|
|
15
|
+
isChildrenLoading?: boolean;
|
|
16
|
+
data?: TreeItemData;
|
|
17
|
+
};
|
|
18
|
+
export type FlattenedTree = FlattenedItem[];
|
|
19
|
+
export type Path = number[];
|
|
20
|
+
export type FlattenedItem = {
|
|
21
|
+
item: TreeItem;
|
|
22
|
+
path: Path;
|
|
23
|
+
};
|
|
24
|
+
export type TreeSourcePosition = {
|
|
25
|
+
parentId: ItemId;
|
|
26
|
+
index: number;
|
|
27
|
+
};
|
|
28
|
+
export type TreeDestinationPosition = {
|
|
29
|
+
parentId: ItemId;
|
|
30
|
+
index?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type TreeItemMutation = {
|
|
34
|
+
id?: ItemId;
|
|
35
|
+
children?: ItemId[];
|
|
36
|
+
hasChildren?: boolean;
|
|
37
|
+
isExpanded?: boolean;
|
|
38
|
+
isChildrenLoading?: boolean;
|
|
39
|
+
data?: TreeItemData;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
Transforms tree structure into flat list of items for rendering purposes.
|
|
44
|
+
We recursively go through all the elements and its children first on each level
|
|
45
|
+
*/
|
|
46
|
+
export const flattenTree = (tree: TreeData, path: Path = []): FlattenedTree =>
|
|
47
|
+
tree.items[tree.rootId]
|
|
48
|
+
? tree.items[tree.rootId].children.reduce<FlattenedTree>((accum, itemId, index) => {
|
|
49
|
+
// iterating through all the children on the given level
|
|
50
|
+
const item = tree.items[itemId];
|
|
51
|
+
const currentPath = [...path, index]; // we create a flattened item for the current item
|
|
52
|
+
|
|
53
|
+
const currentItem = createFlattenedItem(item, currentPath); // we flatten its children
|
|
54
|
+
|
|
55
|
+
const children = flattenChildren(tree, item, currentPath); // append to the accumulator
|
|
56
|
+
|
|
57
|
+
return [...accum, currentItem, ...children];
|
|
58
|
+
}, [])
|
|
59
|
+
: [];
|
|
60
|
+
/*
|
|
61
|
+
Constructs a new FlattenedItem
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
const createFlattenedItem = (item: TreeItem, currentPath: Path) => {
|
|
65
|
+
return {
|
|
66
|
+
item,
|
|
67
|
+
path: currentPath,
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
/*
|
|
71
|
+
Flatten the children of the given subtree
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
const flattenChildren = (tree: TreeData, item: TreeItem, currentPath: Path) => {
|
|
75
|
+
return item.isExpanded
|
|
76
|
+
? flattenTree(
|
|
77
|
+
{
|
|
78
|
+
rootId: item.id,
|
|
79
|
+
items: tree.items,
|
|
80
|
+
},
|
|
81
|
+
currentPath
|
|
82
|
+
)
|
|
83
|
+
: [];
|
|
84
|
+
};
|
|
85
|
+
/*
|
|
86
|
+
Changes the tree data structure with minimal reference changes.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
export const mutateTree = (tree: TreeData, itemId: ItemId, mutation: TreeItemMutation) => {
|
|
90
|
+
const itemToChange = tree.items[itemId];
|
|
91
|
+
|
|
92
|
+
if (!itemToChange) {
|
|
93
|
+
// Item not found
|
|
94
|
+
return tree;
|
|
95
|
+
} // Returning a clone of the tree structure and overwriting the field coming in mutation
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
// rootId should not change
|
|
99
|
+
rootId: tree.rootId,
|
|
100
|
+
items: {
|
|
101
|
+
// copy all old items
|
|
102
|
+
...tree.items,
|
|
103
|
+
// overwriting only the item being changed
|
|
104
|
+
[itemId]: {...itemToChange, ...mutation},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {useCallback, useEffect, useState} from "react";
|
|
2
|
-
import {useImagesGalleryMethods, useImagesGalleryRegistry} from "../images-gallery/images-gallery";
|
|
3
|
-
import {FilePreviewActions} from "./file-preview-actions";
|
|
4
|
-
import {PreviewData} from "./types";
|
|
5
|
-
|
|
6
|
-
export function useRegisterInImageGallery({
|
|
7
|
-
preview,
|
|
8
|
-
name,
|
|
9
|
-
onDownloadClick,
|
|
10
|
-
}: {
|
|
11
|
-
preview: PreviewData | null;
|
|
12
|
-
name: string;
|
|
13
|
-
onDownloadClick?: () => void;
|
|
14
|
-
}) {
|
|
15
|
-
const [zoomed, setZoomed] = useState(false);
|
|
16
|
-
const imagesRegistry = useImagesGalleryRegistry();
|
|
17
|
-
const galleryMethods = useImagesGalleryMethods();
|
|
18
|
-
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
if (!preview) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
imagesRegistry.set(preview.originalSrc, {
|
|
25
|
-
type: preview.type,
|
|
26
|
-
src: preview.originalSrc,
|
|
27
|
-
label: name,
|
|
28
|
-
zoomed: false,
|
|
29
|
-
setZoomed,
|
|
30
|
-
actions: <FilePreviewActions url={preview.originalSrc} name={name} onDownloadClick={onDownloadClick} />,
|
|
31
|
-
});
|
|
32
|
-
}, [imagesRegistry, name, preview, onDownloadClick]);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (!preview) {
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (zoomed) {
|
|
40
|
-
galleryMethods.setActivated(true);
|
|
41
|
-
}
|
|
42
|
-
const imageData = imagesRegistry.get(preview.originalSrc);
|
|
43
|
-
if (imageData) {
|
|
44
|
-
imageData.zoomed = zoomed;
|
|
45
|
-
} else {
|
|
46
|
-
imagesRegistry.set(preview.originalSrc, {
|
|
47
|
-
type: preview.type,
|
|
48
|
-
src: preview.originalSrc,
|
|
49
|
-
label: name,
|
|
50
|
-
zoomed,
|
|
51
|
-
setZoomed,
|
|
52
|
-
actions: <FilePreviewActions url={preview.originalSrc} name={name} onDownloadClick={onDownloadClick} />,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return () => {
|
|
57
|
-
imagesRegistry.delete(preview.originalSrc);
|
|
58
|
-
};
|
|
59
|
-
}, [galleryMethods, zoomed, preview, imagesRegistry, name, onDownloadClick]);
|
|
60
|
-
|
|
61
|
-
const openGallery = useCallback(() => {
|
|
62
|
-
if (preview) {
|
|
63
|
-
setZoomed(true);
|
|
64
|
-
} else {
|
|
65
|
-
onDownloadClick?.();
|
|
66
|
-
}
|
|
67
|
-
}, [preview, onDownloadClick]);
|
|
68
|
-
|
|
69
|
-
return {openGallery};
|
|
70
|
-
}
|