@archbase/kanban 4.0.37

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 (95) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +630 -0
  3. package/dist/archbase-kanban-4.0.37.tgz +0 -0
  4. package/dist/components/Card/Card.d.ts +26 -0
  5. package/dist/components/Card/index.d.ts +1 -0
  6. package/dist/components/CardSkeleton/CardSkeleton.d.ts +9 -0
  7. package/dist/components/CardSkeleton/index.d.ts +2 -0
  8. package/dist/components/Column/Column.d.ts +47 -0
  9. package/dist/components/Column/index.d.ts +1 -0
  10. package/dist/components/ColumnAdder/ColumnAdder.d.ts +6 -0
  11. package/dist/components/ColumnAdder/index.d.ts +1 -0
  12. package/dist/components/ColumnContent/ColumnContent.d.ts +24 -0
  13. package/dist/components/ColumnContent/index.d.ts +1 -0
  14. package/dist/components/ColumnHeader/ColumnHeader.d.ts +10 -0
  15. package/dist/components/ColumnHeader/index.d.ts +1 -0
  16. package/dist/components/DefaultCard/DefaultCard.d.ts +3 -0
  17. package/dist/components/DefaultCard/index.d.ts +1 -0
  18. package/dist/components/GenericItem/GenericItem.d.ts +26 -0
  19. package/dist/components/GenericItem/index.d.ts +1 -0
  20. package/dist/components/Kanban.d.ts +3 -0
  21. package/dist/components/index.d.ts +2 -0
  22. package/dist/components/types.d.ts +124 -0
  23. package/dist/context/KanbanContext.d.ts +5 -0
  24. package/dist/global/dnd/dropManager.d.ts +16 -0
  25. package/dist/global/dnd/useCardDnd.d.ts +22 -0
  26. package/dist/global/dnd/useColumnDnd.d.ts +29 -0
  27. package/dist/index.css +1 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.js +1041 -0
  30. package/dist/utils/columnsUtils.d.ts +4 -0
  31. package/dist/utils/getPrefix.d.ts +2 -0
  32. package/dist/utils/getSharedProps.d.ts +8 -0
  33. package/dist/utils/infinite-scroll.d.ts +4 -0
  34. package/dist/utils/mergeRefs.d.ts +5 -0
  35. package/dist/utils/scroll.d.ts +2 -0
  36. package/package.json +66 -0
  37. package/src/common/_index.scss +0 -0
  38. package/src/components/Card/Card.tsx +215 -0
  39. package/src/components/Card/_Card.scss +11 -0
  40. package/src/components/Card/_index.scss +1 -0
  41. package/src/components/Card/index.ts +1 -0
  42. package/src/components/CardSkeleton/CardSkeleton.tsx +45 -0
  43. package/src/components/CardSkeleton/_CardSkeleton.scss +245 -0
  44. package/src/components/CardSkeleton/_index.scss +1 -0
  45. package/src/components/CardSkeleton/index.ts +2 -0
  46. package/src/components/Column/Column.tsx +246 -0
  47. package/src/components/Column/_Column.scss +44 -0
  48. package/src/components/Column/_index.scss +1 -0
  49. package/src/components/Column/index.ts +1 -0
  50. package/src/components/ColumnAdder/ColumnAdder.tsx +18 -0
  51. package/src/components/ColumnAdder/_ColumnAdder.scss +0 -0
  52. package/src/components/ColumnAdder/_index.scss +1 -0
  53. package/src/components/ColumnAdder/index.ts +1 -0
  54. package/src/components/ColumnContent/ColumnContent.tsx +238 -0
  55. package/src/components/ColumnContent/_ColumnContent.scss +23 -0
  56. package/src/components/ColumnContent/_index.scss +1 -0
  57. package/src/components/ColumnContent/index.ts +1 -0
  58. package/src/components/ColumnHeader/ColumnHeader.tsx +43 -0
  59. package/src/components/ColumnHeader/_ColumnHeader.scss +26 -0
  60. package/src/components/ColumnHeader/_index.scss +1 -0
  61. package/src/components/ColumnHeader/index.ts +1 -0
  62. package/src/components/DefaultCard/DefaultCard.tsx +9 -0
  63. package/src/components/DefaultCard/_DefaultCard.scss +14 -0
  64. package/src/components/DefaultCard/_index.scss +1 -0
  65. package/src/components/DefaultCard/index.ts +1 -0
  66. package/src/components/GenericItem/GenericItem.tsx +132 -0
  67. package/src/components/GenericItem/_GenericItem.scss +4 -0
  68. package/src/components/GenericItem/_index.scss +1 -0
  69. package/src/components/GenericItem/index.ts +1 -0
  70. package/src/components/Kanban.tsx +102 -0
  71. package/src/components/_Kanban.scss +8 -0
  72. package/src/components/_index.scss +9 -0
  73. package/src/components/index.ts +2 -0
  74. package/src/components/types.ts +155 -0
  75. package/src/context/KanbanContext.tsx +19 -0
  76. package/src/global/_index.scss +3 -0
  77. package/src/global/assets/styles/abstracts/_breakpoints.scss +71 -0
  78. package/src/global/assets/styles/abstracts/_colors.scss +85 -0
  79. package/src/global/assets/styles/abstracts/_functions.scss +3 -0
  80. package/src/global/assets/styles/abstracts/_index.scss +5 -0
  81. package/src/global/assets/styles/abstracts/_mixins.scss +49 -0
  82. package/src/global/assets/styles/abstracts/_padding.scss +1 -0
  83. package/src/global/assets/styles/abstracts/_variables.scss +8 -0
  84. package/src/global/assets/styles/base/_index.scss +34 -0
  85. package/src/global/dnd/dropManager.ts +301 -0
  86. package/src/global/dnd/useCardDnd.tsx +225 -0
  87. package/src/global/dnd/useColumnDnd.tsx +231 -0
  88. package/src/global/theme-default.scss +137 -0
  89. package/src/index.ts +6 -0
  90. package/src/utils/columnsUtils.ts +19 -0
  91. package/src/utils/getPrefix.ts +7 -0
  92. package/src/utils/getSharedProps.ts +18 -0
  93. package/src/utils/infinite-scroll.ts +18 -0
  94. package/src/utils/mergeRefs.ts +23 -0
  95. package/src/utils/scroll.ts +34 -0
@@ -0,0 +1,231 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { BoardItem, DndState } from "@/components/types";
3
+ import { withPrefix } from "@/utils/getPrefix";
4
+ import {
5
+ draggable,
6
+ dropTargetForElements,
7
+ } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
8
+ import {
9
+ attachClosestEdge,
10
+ extractClosestEdge,
11
+ type Edge,
12
+ } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
13
+ import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
14
+ import { preserveOffsetOnSource } from "@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source";
15
+ import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
16
+ import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
17
+ import { useKanbanContext } from "@/context/KanbanContext";
18
+
19
+ // ── Column DnD State ──────────────────────────────────────────────────
20
+
21
+ export type TColumnState =
22
+ | { type: "idle" }
23
+ | { type: "is-dragging" }
24
+ | { type: "is-dragging-and-left-self" }
25
+ | { type: "is-card-over"; isOverChildCard: boolean; dragging: DOMRect }
26
+ | { type: "is-column-over"; closestEdge: Edge; rect: DOMRect }
27
+ | { type: "preview"; container: HTMLElement; dragging: DOMRect };
28
+
29
+ const isCardData = (data: any) => data.type === "card";
30
+ const isColumnData = (data: any) => data.type === "column";
31
+ const idle: TColumnState = { type: "idle" };
32
+
33
+ export const useColumnDnd = (
34
+ data: BoardItem,
35
+ index: number,
36
+ items: BoardItem[],
37
+ onColumnDndStateChange?: (info: DndState) => void,
38
+ allowColumnDrag?: boolean,
39
+ hasCustomPreview?: boolean,
40
+ ) => {
41
+ const { viewOnly } = useKanbanContext();
42
+ const isColumnDraggable =
43
+ !viewOnly && allowColumnDrag !== false && data.isDraggable !== false;
44
+
45
+ const headerRef = useRef<HTMLDivElement>(null);
46
+ const outerFullHeightRef = useRef<HTMLDivElement | null>(null);
47
+ const innerRef = useRef<HTMLDivElement | null>(null);
48
+ const [state, setState] = useState<TColumnState>(idle);
49
+
50
+ const cardOverShadowCount =
51
+ state.type === "is-card-over" && !state.isOverChildCard ? 1 : 0;
52
+ const totalTasksCount = data.totalChildrenCount + cardOverShadowCount;
53
+
54
+ const setIsCardOver = useCallback(
55
+ ({ data, location }: { data: any; location: any }) => {
56
+ const innerMost = location.current.dropTargets[0];
57
+ const isOverChildCard = Boolean(innerMost?.data["card-drop-target"]);
58
+
59
+ const proposed: TColumnState = {
60
+ type: "is-card-over",
61
+ dragging: data.rect,
62
+ isOverChildCard,
63
+ };
64
+
65
+ setState((current) => {
66
+ if (
67
+ current.type === proposed.type &&
68
+ current.isOverChildCard === proposed.isOverChildCard &&
69
+ current.dragging === proposed.dragging
70
+ ) {
71
+ return current;
72
+ }
73
+ return proposed;
74
+ });
75
+ },
76
+ [],
77
+ );
78
+
79
+ useEffect(() => {
80
+ const outer = outerFullHeightRef.current;
81
+ const inner = innerRef.current;
82
+ const header = headerRef.current;
83
+ if (!outer || !inner || !header) return;
84
+
85
+ const scroller = outer.querySelector(
86
+ `.${withPrefix("column-content-list")}`,
87
+ );
88
+
89
+ const columnData = {
90
+ type: "column",
91
+ columnId: data.id,
92
+ column: data,
93
+ index,
94
+ };
95
+
96
+ return combine(
97
+ draggable({
98
+ element: header,
99
+ getInitialData: () => columnData,
100
+ canDrag: () => isColumnDraggable,
101
+
102
+ onGenerateDragPreview({ location, nativeSetDragImage }) {
103
+ const rect = outer.getBoundingClientRect();
104
+
105
+ setCustomNativeDragPreview({
106
+ nativeSetDragImage,
107
+ getOffset: preserveOffsetOnSource({
108
+ element: outer,
109
+ input: location.current.input,
110
+ }),
111
+ render({ container }) {
112
+ if (hasCustomPreview) {
113
+ setState({ type: "preview", container, dragging: rect });
114
+ } else {
115
+ const clone = outer.cloneNode(true) as HTMLElement;
116
+ clone.style.width = `${rect.width}px`;
117
+ clone.style.height = `${rect.height}px`;
118
+ clone.style.transform = "rotate(4deg)";
119
+ clone.style.boxShadow = "0 8px 24px rgba(0,0,0,0.15)";
120
+ container.appendChild(clone);
121
+ }
122
+ },
123
+ });
124
+ },
125
+
126
+ onDragStart() {
127
+ setState({ type: "is-dragging" });
128
+ },
129
+
130
+ onDrop() {
131
+ setState(idle);
132
+ },
133
+ }),
134
+
135
+ dropTargetForElements({
136
+ element: outer,
137
+
138
+ getData({ input, element }) {
139
+ return attachClosestEdge(columnData, {
140
+ input,
141
+ element,
142
+ allowedEdges: ["left", "right"],
143
+ });
144
+ },
145
+
146
+ canDrop({ source }) {
147
+ return isCardData(source.data) || isColumnData(source.data);
148
+ },
149
+
150
+ getIsSticky: () => true,
151
+
152
+ onDragStart({ source, location }) {
153
+ if (isCardData(source.data)) {
154
+ setIsCardOver({ data: source.data, location });
155
+ }
156
+ },
157
+
158
+ onDragEnter({ source, location, self }) {
159
+ if (isCardData(source.data)) {
160
+ setIsCardOver({ data: source.data, location });
161
+ return;
162
+ }
163
+ if (isColumnData(source.data) && source.data.columnId !== data.id) {
164
+ const closestEdge = extractClosestEdge(self.data);
165
+ if (!closestEdge) return;
166
+ const rect = outer.getBoundingClientRect();
167
+ setState({ type: "is-column-over", closestEdge, rect });
168
+ }
169
+ },
170
+
171
+ onDrag({ source, self }) {
172
+ if (!isColumnData(source.data)) return;
173
+ if (source.data.columnId === data.id) return;
174
+
175
+ const closestEdge = extractClosestEdge(self.data);
176
+ if (!closestEdge) return;
177
+
178
+ setState((current) => {
179
+ if (
180
+ current.type === "is-column-over" &&
181
+ current.closestEdge === closestEdge
182
+ ) {
183
+ return current;
184
+ }
185
+ const rect = outer.getBoundingClientRect();
186
+ return { type: "is-column-over", closestEdge, rect };
187
+ });
188
+ },
189
+
190
+ onDropTargetChange({ source, location }) {
191
+ if (isCardData(source.data)) {
192
+ setIsCardOver({ data: source.data, location });
193
+ }
194
+ },
195
+
196
+ onDragLeave({ source }) {
197
+ if (isColumnData(source.data) && source.data.columnId === data.id) {
198
+ setState({ type: "is-dragging-and-left-self" });
199
+ return;
200
+ }
201
+ setState(idle);
202
+ },
203
+
204
+ onDrop() {
205
+ setState(idle);
206
+ },
207
+ }),
208
+
209
+ autoScrollForElements({
210
+ canScroll({ source }) {
211
+ return isCardData(source.data);
212
+ },
213
+ getConfiguration: () => ({ maxScrollSpeed: "standard" as const }),
214
+ element: scroller,
215
+ }),
216
+ );
217
+ }, [data, index, items?.length, isColumnDraggable, hasCustomPreview]);
218
+
219
+ useEffect(() => {
220
+ onColumnDndStateChange?.({ state, column: data });
221
+ }, [state, onColumnDndStateChange]);
222
+
223
+ return {
224
+ headerRef,
225
+ outerFullHeightRef,
226
+ innerRef,
227
+ state,
228
+ cardOverShadowCount,
229
+ totalTasksCount,
230
+ };
231
+ };
@@ -0,0 +1,137 @@
1
+ :root {
2
+ --vf-font-familly: "Raleway", sans-serif;
3
+ --vf-prefix-class: "vf";
4
+
5
+ //COLORS
6
+
7
+ --vf-color-white: #fff;
8
+ --vf-color-black: #000;
9
+
10
+ --vf-color-primary: #5f55ee;
11
+ --vf-color-primary-50: #fcf9ff;
12
+ --vf-color-primary-100: #f5eefa;
13
+ --vf-color-primary-200: #e0ccef;
14
+ --vf-color-primary-300: #c198e0;
15
+ --vf-color-primary-400: #ad76d5;
16
+ --vf-color-primary-500: #9854cb;
17
+ --vf-color-primary-600: #7a43a2;
18
+ --vf-color-primary-700: #5b327a;
19
+ --vf-color-primary-800: #3d2251;
20
+ --vf-color-primary-900: #301942;
21
+ --vf-color-primary-950: #1e1129;
22
+
23
+ --vf-color-secondary: #fdb022;
24
+ --vf-color-secondary-50: #fffcf5;
25
+ --vf-color-secondary-100: #fffaeb;
26
+ --vf-color-secondary-200: #fef0c7;
27
+ --vf-color-secondary-300: #fedf89;
28
+ --vf-color-secondary-400: #fec84b;
29
+ --vf-color-secondary-500: #fdb022;
30
+ --vf-color-secondary-600: #f79009;
31
+ --vf-color-secondary-700: #dc6803;
32
+ --vf-color-secondary-800: #b54708;
33
+ --vf-color-secondary-900: #92330a;
34
+ --vf-color-secondary-950: #6c2304;
35
+
36
+ --vf-color-red: #ff4141;
37
+ --vf-color-red-50: #fff4f4;
38
+ --vf-color-red-100: #ffe8e8;
39
+ --vf-color-red-200: #ffd4d4;
40
+ --vf-color-red-300: #ffb4b4;
41
+ --vf-color-red-400: #ff8383;
42
+ --vf-color-red-500: #ff4141;
43
+ --vf-color-red-600: #ff1616;
44
+ --vf-color-red-700: #d80000;
45
+ --vf-color-red-800: #b50000;
46
+ --vf-color-red-900: #7e040e;
47
+ --vf-color-red-950: #64020a;
48
+
49
+ --vf-color-gray: #9d9d9d;
50
+ --vf-color-gray-50: #ffffff;
51
+ --vf-color-gray-100: #f0f0f0;
52
+ --vf-color-gray-200: #dadada;
53
+ --vf-color-gray-300: #cecece;
54
+ --vf-color-gray-400: #b6b6b6;
55
+ --vf-color-gray-500: #9d9d9d;
56
+ --vf-color-gray-600: #6a6a6a;
57
+ --vf-color-gray-700: #545454;
58
+ --vf-color-gray-800: #373737;
59
+ --vf-color-gray-900: #1c1c1c;
60
+ --vf-color-gray-950: #000000;
61
+
62
+ --vf-color-green: #29b58b;
63
+ --vf-color-green-50: #f1fffb;
64
+ --vf-color-green-100: #e2fff6;
65
+ --vf-color-green-200: #ccfff0;
66
+ --vf-color-green-300: #a3edd7;
67
+ --vf-color-green-400: #52c8a4;
68
+ --vf-color-green-500: #29b58b;
69
+ --vf-color-green-600: #00a372;
70
+ --vf-color-green-700: #00825b;
71
+ --vf-color-green-800: #006346;
72
+ --vf-color-green-900: #00412e;
73
+ --vf-color-green-950: #002117;
74
+
75
+ --vf-color-orange: #29b58b;
76
+ --vf-color-orange-50: #fffdf6;
77
+ --vf-color-orange-100: #fffaea;
78
+ --vf-color-orange-200: #fff5d4;
79
+ --vf-color-orange-300: #ffecaa;
80
+ --vf-color-orange-400: #ffe27f;
81
+ --vf-color-orange-500: #ffcf2b;
82
+ --vf-color-orange-600: #e6ba27;
83
+ --vf-color-orange-700: #bf9b20;
84
+ --vf-color-orange-800: #806716;
85
+ --vf-color-orange-900: #4d3f0d;
86
+ --vf-color-orange-950: #342a08;
87
+ --vf-color-orange-1000: #fa8900;
88
+
89
+ --vf-color-ashgrey: #b3afa1;
90
+ --vf-color-ashgrey-50: #fdfdfc;
91
+ --vf-color-ashgrey-100: #fbfbf9;
92
+ --vf-color-ashgrey-200: #f7f6f2;
93
+ --vf-color-ashgrey-300: #f0efea;
94
+ --vf-color-ashgrey-400: #dddad0;
95
+ --vf-color-ashgrey-500: #b3afa1;
96
+ --vf-color-ashgrey-600: #858071;
97
+ --vf-color-ashgrey-700: #5e5267;
98
+ --vf-color-ashgrey-800: #676252;
99
+ --vf-color-ashgrey-900: #39321d;
100
+ --vf-color-ashgrey-950: #282210;
101
+
102
+ --vf-color-snow: #b3afa1;
103
+ --vf-color-snow-50: #fdfcfd;
104
+ --vf-color-snow-100: #faf9fb;
105
+ --vf-color-snow-200: #f5f2f7;
106
+ --vf-color-snow-300: #edeaf0;
107
+ --vf-color-snow-400: #d7d0dd;
108
+ --vf-color-snow-500: #aba1b3;
109
+ --vf-color-snow-600: #7c7185;
110
+ --vf-color-snow-700: #5e5267;
111
+ --vf-color-snow-800: #463454;
112
+ --vf-color-snow-900: #2d1d39;
113
+ --vf-color-snow-950: #1e1028;
114
+
115
+ --vf-color-gray-0: #fff;
116
+ --vf-color-yellow-50: #ffb300;
117
+ --vf-color-cyan-50: #00bcd4;
118
+ --vf-color-blue-50: #2196f3;
119
+ --vf-color-violet-50: #673ab7;
120
+
121
+ --vf-color-info: #1677ff;
122
+ --vf-color-success: #52c41a;
123
+ --vf-color-warning: #faad14;
124
+ --vf-color-error: #ff4d4f;
125
+
126
+ --vf-control-bar-height: 48px;
127
+
128
+ --vf-border-radius: 12px;
129
+
130
+ --vf-progress-bar-bg: #fff3;
131
+ --vf-progress-bar-load-bg: #fff6;
132
+ --vf-progress-bar-play-bg: var(--vf-color-primary);
133
+
134
+ --vf-dropdown-menu-item-hover: #ffffff1a;
135
+ --vf-sound-icon-size: 18px;
136
+ --vf-sound-icon-color: #fff;
137
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ import "./components/_index.scss";
2
+ import { dropHandler, dropColumnHandler } from "./global/dnd/dropManager";
3
+
4
+ export type { BoardProps, BoardItem, BoardData } from "./components/types";
5
+ export { default as Kanban } from "./components/Kanban";
6
+ export { dropHandler, dropColumnHandler };
@@ -0,0 +1,19 @@
1
+ import { BoardData, BoardItem } from "@/components";
2
+
3
+ export const getColumnsFromDataSource = (dataSource: BoardData) => {
4
+ if (!dataSource?.root) return [];
5
+ return dataSource.root.children?.map((child) => dataSource[child]) || [];
6
+ };
7
+
8
+ export const getColumnChildren = (column: BoardItem, dataSource: BoardData) => {
9
+ if (!column) return [];
10
+ return column.children?.map((child) => dataSource[child]) || [];
11
+ };
12
+
13
+ export const getHeaderHeight = (header: HTMLDivElement): number => {
14
+ if (!header) return 0;
15
+ const style = window.getComputedStyle(header);
16
+ const marginTop = parseFloat(style.marginTop) || 0;
17
+ const marginBottom = parseFloat(style.marginBottom) || 0;
18
+ return header.offsetHeight + marginTop + marginBottom;
19
+ };
@@ -0,0 +1,7 @@
1
+ export const prefix = "rkk";
2
+
3
+ export const withPrefix = (string: string | string[], separator = " ") => {
4
+ if (Array.isArray(string))
5
+ return string.map((item) => `${prefix}-${item}`).join(separator);
6
+ return `${prefix}-${string}`;
7
+ };
@@ -0,0 +1,18 @@
1
+ import { BoardProps } from "@/components";
2
+
3
+ export const getSharedProps = (props: BoardProps) => {
4
+ const {
5
+ viewOnly = false,
6
+ virtualization = true,
7
+ cardsGap = 8,
8
+ allowColumnAdder = true,
9
+ allowListFooter,
10
+ } = props;
11
+ return {
12
+ viewOnly,
13
+ virtualization,
14
+ cardsGap,
15
+ allowColumnAdder,
16
+ allowListFooter,
17
+ };
18
+ };
@@ -0,0 +1,18 @@
1
+ import { withPrefix } from "./getPrefix";
2
+
3
+ export const checkIfSkeletonIsVisible = ({ columnId, limit = 20 }): boolean => {
4
+ const skeletons = document.querySelectorAll(
5
+ `.${withPrefix("generic-item-skeleton")}[data-rkk-column="${columnId}"]`
6
+ );
7
+
8
+ if (!skeletons.length) return false;
9
+
10
+ const skeletonsToCheck = Array.from(skeletons).slice(0, limit);
11
+
12
+ const isVisible = skeletonsToCheck.some((skeleton) => {
13
+ const { top, bottom } = skeleton.getBoundingClientRect();
14
+ return top <= window.innerHeight && bottom >= 0;
15
+ });
16
+
17
+ return isVisible;
18
+ };
@@ -0,0 +1,23 @@
1
+ import React from "react";
2
+
3
+ type CallbackRef<T> = (ref: T | null) => void;
4
+ type Ref<T> = React.MutableRefObject<T> | CallbackRef<T>;
5
+
6
+ const toFnRef = <T>(ref?: Ref<T | null> | null) =>
7
+ !ref || typeof ref === "function"
8
+ ? ref
9
+ : (value: T | null) => {
10
+ ref.current = value;
11
+ };
12
+
13
+ export default function mergeRefs<T>(
14
+ refA?: Ref<T | null> | null,
15
+ refB?: Ref<T | null> | null
16
+ ): React.RefCallback<T> {
17
+ const a = toFnRef(refA);
18
+ const b = toFnRef(refB);
19
+ return (value: T | null) => {
20
+ if (typeof a === "function") a(value);
21
+ if (typeof b === "function") b(value);
22
+ };
23
+ }
@@ -0,0 +1,34 @@
1
+ import { BoardItem, ScrollEvent } from "@/components";
2
+ import { withPrefix } from "./getPrefix";
3
+
4
+ export const handleScroll = (
5
+ e: React.UIEvent<HTMLDivElement> | number,
6
+ virtualization: boolean,
7
+ onScroll: (e: ScrollEvent, column: BoardItem) => void,
8
+ column: BoardItem
9
+ ) => {
10
+ const scrollContainer = document.querySelector(
11
+ `.${withPrefix("column-content-list")}`
12
+ );
13
+ if (!scrollContainer) return;
14
+
15
+ const { scrollHeight, clientHeight } = scrollContainer;
16
+ let offset: number;
17
+ if (virtualization) {
18
+ offset = typeof e === "number" ? e : 0;
19
+ } else {
20
+ const target = (e as React.UIEvent<HTMLDivElement>)
21
+ .target as HTMLDivElement;
22
+ offset = target.scrollTop;
23
+ }
24
+
25
+ const syntheticEvent = {
26
+ target: {
27
+ scrollTop: offset,
28
+ scrollHeight,
29
+ clientHeight,
30
+ },
31
+ };
32
+
33
+ onScroll?.(syntheticEvent, column);
34
+ };