@noraent/nora-datagrid 0.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.
Files changed (168) hide show
  1. package/README.md +80 -0
  2. package/lib/cjs/App.d.ts +10 -0
  3. package/lib/cjs/App.js +142 -0
  4. package/lib/cjs/DataGrid.d.ts +3 -0
  5. package/lib/cjs/DataGrid.js +37 -0
  6. package/lib/cjs/buildPackage.json +59 -0
  7. package/lib/cjs/common/constants/defaultProps.d.ts +4 -0
  8. package/lib/cjs/common/constants/defaultProps.js +4 -0
  9. package/lib/cjs/common/constants/index.d.ts +1 -0
  10. package/lib/cjs/common/constants/index.js +1 -0
  11. package/lib/cjs/common/constants/path.d.ts +31 -0
  12. package/lib/cjs/common/constants/path.js +45 -0
  13. package/lib/cjs/common/constants/utils.d.ts +0 -0
  14. package/lib/cjs/common/constants/utils.js +1 -0
  15. package/lib/cjs/common/foundation/index.d.ts +4 -0
  16. package/lib/cjs/common/foundation/index.js +4 -0
  17. package/lib/cjs/common/foundation/scale/color/color.d.ts +44 -0
  18. package/lib/cjs/common/foundation/scale/color/color.js +46 -0
  19. package/lib/cjs/common/foundation/scale/color/index.d.ts +1 -0
  20. package/lib/cjs/common/foundation/scale/color/index.js +1 -0
  21. package/lib/cjs/common/foundation/scale/index.d.ts +2 -0
  22. package/lib/cjs/common/foundation/scale/index.js +2 -0
  23. package/lib/cjs/common/foundation/scale/layout/breakpoints.d.ts +4 -0
  24. package/lib/cjs/common/foundation/scale/layout/breakpoints.js +6 -0
  25. package/lib/cjs/common/foundation/scale/layout/index.d.ts +1 -0
  26. package/lib/cjs/common/foundation/scale/layout/index.js +1 -0
  27. package/lib/cjs/common/foundation/scale/layout/size.d.ts +6 -0
  28. package/lib/cjs/common/foundation/scale/layout/size.js +7 -0
  29. package/lib/cjs/common/styled/assets/components/index.d.ts +1 -0
  30. package/lib/cjs/common/styled/assets/components/index.js +1 -0
  31. package/lib/cjs/common/styled/assets/components/loading/Loading.d.ts +2 -0
  32. package/lib/cjs/common/styled/assets/components/loading/Loading.js +2 -0
  33. package/lib/cjs/common/styled/assets/index.d.ts +1 -0
  34. package/lib/cjs/common/styled/assets/index.js +1 -0
  35. package/lib/cjs/common/styled/index.d.ts +44 -0
  36. package/lib/cjs/common/styled/index.js +57 -0
  37. package/lib/cjs/components/GridBasicRows.d.ts +6 -0
  38. package/lib/cjs/components/GridBasicRows.js +88 -0
  39. package/lib/cjs/components/NoraDataGrid.d.ts +12 -0
  40. package/lib/cjs/components/NoraDataGrid.js +50 -0
  41. package/lib/cjs/components/TwoDimensionalVirtualizedList.d.ts +5 -0
  42. package/lib/cjs/components/TwoDimensionalVirtualizedList.js +538 -0
  43. package/lib/cjs/components/cell/CellMode.d.ts +10 -0
  44. package/lib/cjs/components/cell/CellMode.js +33 -0
  45. package/lib/cjs/components/header/VirtualHorizontalHeader.d.ts +5 -0
  46. package/lib/cjs/components/header/VirtualHorizontalHeader.js +13 -0
  47. package/lib/cjs/components/ime/IMEComponent.d.ts +5 -0
  48. package/lib/cjs/components/ime/IMEComponent.js +149 -0
  49. package/lib/cjs/components/virtualized/_components/VirtualHeader.d.ts +4 -0
  50. package/lib/cjs/components/virtualized/_components/VirtualHeader.js +25 -0
  51. package/lib/cjs/components/virtualized/_constants/virtualHeaderConstants.d.ts +9 -0
  52. package/lib/cjs/components/virtualized/_constants/virtualHeaderConstants.js +1 -0
  53. package/lib/cjs/components/virtualized/_styled/index.d.ts +34 -0
  54. package/lib/cjs/components/virtualized/_styled/index.js +108 -0
  55. package/lib/cjs/hooks/external/usePublicTest.d.ts +3 -0
  56. package/lib/cjs/hooks/external/usePublicTest.js +20 -0
  57. package/lib/cjs/hooks/internal/useCellRange.d.ts +8 -0
  58. package/lib/cjs/hooks/internal/useCellRange.js +275 -0
  59. package/lib/cjs/hooks/internal/useInternalPrivateApi.d.ts +3 -0
  60. package/lib/cjs/hooks/internal/useInternalPrivateApi.js +127 -0
  61. package/lib/cjs/hooks/useGridApiContext.d.ts +4 -0
  62. package/lib/cjs/hooks/useGridApiContext.js +10 -0
  63. package/lib/cjs/hooks/useGridApiMethod.d.ts +8 -0
  64. package/lib/cjs/hooks/useGridApiMethod.js +18 -0
  65. package/lib/cjs/hooks/useGridInitialization.d.ts +3 -0
  66. package/lib/cjs/hooks/useGridInitialization.js +62 -0
  67. package/lib/cjs/index.d.ts +1 -0
  68. package/lib/cjs/index.js +1 -0
  69. package/lib/cjs/main.d.ts +0 -0
  70. package/lib/cjs/main.js +9 -0
  71. package/lib/cjs/provider/GridApiContext.d.ts +2 -0
  72. package/lib/cjs/provider/GridApiContext.js +5 -0
  73. package/lib/cjs/provider/GridStoreContent.d.ts +10 -0
  74. package/lib/cjs/provider/GridStoreContent.js +140 -0
  75. package/lib/cjs/types/classes/index.d.ts +1 -0
  76. package/lib/cjs/types/classes/index.js +1 -0
  77. package/lib/cjs/types/classes/styled.d.ts +55 -0
  78. package/lib/cjs/types/classes/styled.js +56 -0
  79. package/lib/cjs/types/dataGridCoreEnum.d.ts +6 -0
  80. package/lib/cjs/types/dataGridCoreEnum.js +7 -0
  81. package/lib/cjs/types/dataGridCoreProps.d.ts +71 -0
  82. package/lib/cjs/types/dataGridCoreProps.js +1 -0
  83. package/lib/cjs/types/dataGridProps.d.ts +148 -0
  84. package/lib/cjs/types/dataGridProps.js +54 -0
  85. package/lib/esm/App.d.ts +10 -0
  86. package/lib/esm/App.js +142 -0
  87. package/lib/esm/DataGrid.d.ts +3 -0
  88. package/lib/esm/DataGrid.js +37 -0
  89. package/lib/esm/buildPackage.json +59 -0
  90. package/lib/esm/common/constants/defaultProps.d.ts +4 -0
  91. package/lib/esm/common/constants/defaultProps.js +4 -0
  92. package/lib/esm/common/constants/index.d.ts +1 -0
  93. package/lib/esm/common/constants/index.js +1 -0
  94. package/lib/esm/common/constants/path.d.ts +31 -0
  95. package/lib/esm/common/constants/path.js +45 -0
  96. package/lib/esm/common/constants/utils.d.ts +0 -0
  97. package/lib/esm/common/constants/utils.js +1 -0
  98. package/lib/esm/common/foundation/index.d.ts +4 -0
  99. package/lib/esm/common/foundation/index.js +4 -0
  100. package/lib/esm/common/foundation/scale/color/color.d.ts +44 -0
  101. package/lib/esm/common/foundation/scale/color/color.js +46 -0
  102. package/lib/esm/common/foundation/scale/color/index.d.ts +1 -0
  103. package/lib/esm/common/foundation/scale/color/index.js +1 -0
  104. package/lib/esm/common/foundation/scale/index.d.ts +2 -0
  105. package/lib/esm/common/foundation/scale/index.js +2 -0
  106. package/lib/esm/common/foundation/scale/layout/breakpoints.d.ts +4 -0
  107. package/lib/esm/common/foundation/scale/layout/breakpoints.js +6 -0
  108. package/lib/esm/common/foundation/scale/layout/index.d.ts +1 -0
  109. package/lib/esm/common/foundation/scale/layout/index.js +1 -0
  110. package/lib/esm/common/foundation/scale/layout/size.d.ts +6 -0
  111. package/lib/esm/common/foundation/scale/layout/size.js +7 -0
  112. package/lib/esm/common/styled/assets/components/index.d.ts +1 -0
  113. package/lib/esm/common/styled/assets/components/index.js +1 -0
  114. package/lib/esm/common/styled/assets/components/loading/Loading.d.ts +2 -0
  115. package/lib/esm/common/styled/assets/components/loading/Loading.js +2 -0
  116. package/lib/esm/common/styled/assets/index.d.ts +1 -0
  117. package/lib/esm/common/styled/assets/index.js +1 -0
  118. package/lib/esm/common/styled/index.d.ts +44 -0
  119. package/lib/esm/common/styled/index.js +57 -0
  120. package/lib/esm/components/GridBasicRows.d.ts +6 -0
  121. package/lib/esm/components/GridBasicRows.js +88 -0
  122. package/lib/esm/components/NoraDataGrid.d.ts +12 -0
  123. package/lib/esm/components/NoraDataGrid.js +50 -0
  124. package/lib/esm/components/TwoDimensionalVirtualizedList.d.ts +5 -0
  125. package/lib/esm/components/TwoDimensionalVirtualizedList.js +538 -0
  126. package/lib/esm/components/cell/CellMode.d.ts +10 -0
  127. package/lib/esm/components/cell/CellMode.js +33 -0
  128. package/lib/esm/components/header/VirtualHorizontalHeader.d.ts +5 -0
  129. package/lib/esm/components/header/VirtualHorizontalHeader.js +13 -0
  130. package/lib/esm/components/ime/IMEComponent.d.ts +5 -0
  131. package/lib/esm/components/ime/IMEComponent.js +149 -0
  132. package/lib/esm/components/virtualized/_components/VirtualHeader.d.ts +4 -0
  133. package/lib/esm/components/virtualized/_components/VirtualHeader.js +25 -0
  134. package/lib/esm/components/virtualized/_constants/virtualHeaderConstants.d.ts +9 -0
  135. package/lib/esm/components/virtualized/_constants/virtualHeaderConstants.js +1 -0
  136. package/lib/esm/components/virtualized/_styled/index.d.ts +34 -0
  137. package/lib/esm/components/virtualized/_styled/index.js +108 -0
  138. package/lib/esm/hooks/external/usePublicTest.d.ts +3 -0
  139. package/lib/esm/hooks/external/usePublicTest.js +20 -0
  140. package/lib/esm/hooks/internal/useCellRange.d.ts +8 -0
  141. package/lib/esm/hooks/internal/useCellRange.js +275 -0
  142. package/lib/esm/hooks/internal/useInternalPrivateApi.d.ts +3 -0
  143. package/lib/esm/hooks/internal/useInternalPrivateApi.js +127 -0
  144. package/lib/esm/hooks/useGridApiContext.d.ts +4 -0
  145. package/lib/esm/hooks/useGridApiContext.js +10 -0
  146. package/lib/esm/hooks/useGridApiMethod.d.ts +8 -0
  147. package/lib/esm/hooks/useGridApiMethod.js +18 -0
  148. package/lib/esm/hooks/useGridInitialization.d.ts +3 -0
  149. package/lib/esm/hooks/useGridInitialization.js +62 -0
  150. package/lib/esm/index.d.ts +1 -0
  151. package/lib/esm/index.js +1 -0
  152. package/lib/esm/main.d.ts +0 -0
  153. package/lib/esm/main.js +9 -0
  154. package/lib/esm/provider/GridApiContext.d.ts +2 -0
  155. package/lib/esm/provider/GridApiContext.js +5 -0
  156. package/lib/esm/provider/GridStoreContent.d.ts +10 -0
  157. package/lib/esm/provider/GridStoreContent.js +140 -0
  158. package/lib/esm/types/classes/index.d.ts +1 -0
  159. package/lib/esm/types/classes/index.js +1 -0
  160. package/lib/esm/types/classes/styled.d.ts +55 -0
  161. package/lib/esm/types/classes/styled.js +56 -0
  162. package/lib/esm/types/dataGridCoreEnum.d.ts +6 -0
  163. package/lib/esm/types/dataGridCoreEnum.js +7 -0
  164. package/lib/esm/types/dataGridCoreProps.d.ts +71 -0
  165. package/lib/esm/types/dataGridCoreProps.js +1 -0
  166. package/lib/esm/types/dataGridProps.d.ts +148 -0
  167. package/lib/esm/types/dataGridProps.js +54 -0
  168. package/package.json +59 -0
@@ -0,0 +1,538 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useState, useMemo, useCallback, useEffect, useRef } from "react";
3
+ import ReactDOM from "react-dom";
4
+ import useGridApiContext from "../hooks/useGridApiContext";
5
+ import { BottomScrollBar, RightScrollBar, TableBody, TableCell, TableRow } from "./virtualized/_styled";
6
+ import { classes } from "../types/classes";
7
+ import { cx } from "@emotion/css";
8
+ import VirtualHorizontalHeader from "./header/VirtualHorizontalHeader";
9
+ import { useSelector, useStore } from "../provider/GridStoreContent";
10
+ import { EditStatus } from "../types/dataGridCoreEnum";
11
+ import CellMode from "./cell/CellMode";
12
+ import ImeComponent from "./ime/IMEComponent";
13
+ const initialWindowWidth = 800;
14
+ export const initialWindowHeight = 500;
15
+ const initialBodyHeight = initialWindowHeight - 34;
16
+ const overscanTopRow = 4;
17
+ const overscanBottomRow = 10;
18
+ const overscanColumn = 1;
19
+ const targetFPS = 60;
20
+ const frameInterval = 1000 / targetFPS;
21
+ const DynamicVirtualScroll = React.memo(({ children }) => {
22
+ const prevScrollTop = useRef(0);
23
+ const prevScrollLeft = useRef(0);
24
+ const [scrollTop, setScrollTop] = useState(0);
25
+ const [scrollLeft, setScrollLeft] = useState(0);
26
+ const [windowSize, setWindowSize] = useState({
27
+ width: initialWindowWidth,
28
+ height: initialWindowHeight,
29
+ });
30
+ const gridRef = useGridApiContext();
31
+ const rightScrollRef = useRef(null);
32
+ const bottomScrollRef = useRef(null);
33
+ useEffect(() => {
34
+ const handleResize = () => {
35
+ var _a, _b, _c, _d, _f, _g;
36
+ const store = gridRef.current.store;
37
+ const width = (_c = (_b = (_a = store === null || store === void 0 ? void 0 : store.gridContainer.current) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.clientWidth) !== null && _c !== void 0 ? _c : 0;
38
+ const height = (_g = (_f = (_d = store === null || store === void 0 ? void 0 : store.gridContainer.current) === null || _d === void 0 ? void 0 : _d.parentElement) === null || _f === void 0 ? void 0 : _f.clientHeight) !== null && _g !== void 0 ? _g : 0;
39
+ setWindowSize({ width, height });
40
+ };
41
+ handleResize();
42
+ window.addEventListener("resize", handleResize);
43
+ window.addEventListener("focusout", (event) => {
44
+ var _a;
45
+ if (((_a = event.target.nextElementSibling) === null || _a === void 0 ? void 0 : _a.className) === "nora-data-grid-container") {
46
+ console.log("???", gridRef.current.store.gridContainer.current);
47
+ }
48
+ });
49
+ return () => {
50
+ window.removeEventListener("resize", handleResize);
51
+ };
52
+ }, []);
53
+ const { columns } = useSelector((store) => ({
54
+ columns: store.state.columns,
55
+ }));
56
+ const { dataSource } = useSelector((store) => ({
57
+ dataSource: store.state.dataSource,
58
+ }));
59
+ const totalHeight = useMemo(() => dataSource.reduce((sum, item) => sum + item.height, 0), [dataSource]);
60
+ const totalWidth = useMemo(() => columns.reduce((sum, column) => sum + Number(column.width), 0) || 0, [columns]);
61
+ const binarySearchIndex = useCallback((items, target) => {
62
+ let low = 0;
63
+ let high = items.length - 1;
64
+ while (low <= high) {
65
+ const mid = Math.floor((low + high) / 2);
66
+ if (items[mid] > target) {
67
+ high = mid - 1;
68
+ }
69
+ else if (items[mid] < target) {
70
+ low = mid + 1;
71
+ }
72
+ else {
73
+ return mid;
74
+ }
75
+ }
76
+ return Math.max(0, low - 1);
77
+ }, []);
78
+ const cumulativeHeights = useMemo(() => {
79
+ const heights = [0];
80
+ for (let i = 0; i < dataSource.length; i++) {
81
+ heights.push(heights[i] + dataSource[i].height);
82
+ }
83
+ return heights;
84
+ }, [dataSource]);
85
+ const cumulativeWidths = useMemo(() => {
86
+ const widths = [0];
87
+ for (let i = 0; i < columns.length || 0; i++) {
88
+ widths.push(widths[i] + Number(columns[i].width));
89
+ }
90
+ return widths;
91
+ }, [columns]);
92
+ const getItemRange = useCallback(() => {
93
+ const start = Math.max(0, binarySearchIndex(cumulativeHeights, scrollTop) - overscanTopRow);
94
+ let end = Math.min(start + overscanBottomRow, dataSource.length);
95
+ let startAdjust = start ? start + overscanTopRow : start;
96
+ while (end < dataSource.length && cumulativeHeights[end] - cumulativeHeights[startAdjust] <= initialBodyHeight) {
97
+ end++;
98
+ }
99
+ end = Math.min(end + overscanBottomRow, dataSource.length);
100
+ return { start, end };
101
+ }, [dataSource, scrollTop, cumulativeHeights, windowSize.height, binarySearchIndex]);
102
+ const { start, end } = getItemRange();
103
+ const visibleItems = useMemo(() => {
104
+ const result = [];
105
+ const rowIndex = gridRef.current.getCellFocus()[0];
106
+ // 포함 안되어있으면 추가
107
+ if (rowIndex && rowIndex <= start) {
108
+ result.push(dataSource[rowIndex - 1]); // fixedIndex가 범위에 포함되지 않으면 첫 번째에 추가
109
+ }
110
+ for (let i = start; i < end; i++) {
111
+ result.push(dataSource[i]);
112
+ }
113
+ // 포함 안되어있으면 추가
114
+ if (rowIndex && rowIndex >= end) {
115
+ result.push(dataSource[rowIndex - 1]); // fixedIndex가 범위에 포함되지 않으면 첫 번째에 추가
116
+ }
117
+ return result;
118
+ }, [dataSource, start, end]);
119
+ const startColumnIndex = useMemo(() => Math.max(0, binarySearchIndex(cumulativeWidths, scrollLeft) - overscanColumn), [columns, cumulativeWidths, scrollLeft, binarySearchIndex, overscanColumn]);
120
+ const offsetTop = useMemo(() => cumulativeHeights[start] || 0, [cumulativeHeights, start]);
121
+ const offsetLeft = useMemo(() => cumulativeWidths[startColumnIndex] || 0, [cumulativeWidths, startColumnIndex]);
122
+ const domRef = React.useRef(null);
123
+ const updateScroll = useCallback((newScrollTop, newScrollLeft) => {
124
+ newScrollTop !== undefined && setScrollTop(newScrollTop);
125
+ newScrollLeft !== undefined && setScrollLeft(newScrollLeft);
126
+ if (newScrollTop !== undefined)
127
+ prevScrollTop.current = newScrollTop;
128
+ if (newScrollLeft !== undefined)
129
+ prevScrollLeft.current = newScrollLeft;
130
+ }, []);
131
+ const handleScroll = useCallback((e) => {
132
+ if (isSyncingRef.current)
133
+ return;
134
+ isSyncingRef.current = true;
135
+ const domScroll = domRef.current;
136
+ const rightScroll = rightScrollRef.current;
137
+ const bottomScroll = bottomScrollRef.current;
138
+ const { scrollTop, scrollLeft } = e.currentTarget;
139
+ requestAnimationFrame(() => {
140
+ if (domScroll && rightScroll && bottomScroll) {
141
+ ReactDOM.flushSync(() => {
142
+ rightScroll.scrollTop = scrollTop;
143
+ bottomScroll.scrollLeft = scrollLeft;
144
+ scrollTop !== undefined && setScrollTop(scrollTop);
145
+ scrollLeft !== undefined && setScrollLeft(scrollLeft);
146
+ });
147
+ }
148
+ isSyncingRef.current = false;
149
+ });
150
+ }, [updateScroll, frameInterval]);
151
+ const binarySearchColumnIndex = useCallback((items, start, scrollLeft) => {
152
+ let high = items.length - 1;
153
+ let target = windowSize.width;
154
+ let end = start;
155
+ for (let i = start; i <= high; i++) {
156
+ if (Math.max(0, items[i] - scrollLeft) > target) {
157
+ end = i + overscanColumn;
158
+ return end;
159
+ }
160
+ }
161
+ return items.length - 1;
162
+ }, [windowSize.width]);
163
+ const columnEndIndex = useMemo(() => binarySearchColumnIndex(cumulativeWidths, startColumnIndex, scrollLeft), [cumulativeWidths, startColumnIndex, scrollLeft, windowSize.width]);
164
+ const isSyncingRef = useRef(false);
165
+ const handleScrollController = useCallback((e) => {
166
+ if (isSyncingRef.current)
167
+ return;
168
+ isSyncingRef.current = true;
169
+ const domScroll = domRef.current;
170
+ const rightScroll = rightScrollRef.current;
171
+ const currentTarget = e.currentTarget;
172
+ ReactDOM.flushSync(() => {
173
+ if (domScroll && rightScroll) {
174
+ domScroll.scrollTop = currentTarget.scrollTop;
175
+ }
176
+ isSyncingRef.current = false;
177
+ });
178
+ }, []);
179
+ const handleScrollBottomController = useCallback((e) => {
180
+ if (isSyncingRef.current)
181
+ return;
182
+ isSyncingRef.current = true;
183
+ const domScroll = domRef.current;
184
+ const bottomScroll = bottomScrollRef.current;
185
+ const currentTarget = e.currentTarget;
186
+ ReactDOM.flushSync(() => {
187
+ if (domScroll && bottomScroll) {
188
+ domScroll.scrollLeft = currentTarget.scrollLeft;
189
+ }
190
+ isSyncingRef.current = false;
191
+ });
192
+ }, [updateScroll, gridRef]);
193
+ useEffect(() => {
194
+ console.log("start, end!", start, end);
195
+ gridRef.current.store.state.renderedRowStartEnd = [start, end];
196
+ }, [start, end]);
197
+ return (_jsxs("div", { style: { position: "relative" }, children: [_jsx("div", { style: {
198
+ height: `${windowSize.height}px`,
199
+ width: `${windowSize.width}px`,
200
+ }, children: _jsxs(TableBody, { ref: domRef, style: {
201
+ height: "100%",
202
+ position: "relative",
203
+ display: "flex",
204
+ flexDirection: "column",
205
+ overflow: "scroll",
206
+ scrollbarWidth: "none",
207
+ }, className: classes.TableClasses.body.scroll.root, onScroll: handleScroll, children: [_jsx(VirtualHorizontalHeader, { offsetLeft: offsetLeft, startColumnIndex: startColumnIndex, cumulativeWidths: cumulativeWidths, windowSize: windowSize, columnEndIndex: columnEndIndex }), _jsx("div", { style: {
208
+ flexBasis: `${totalHeight}px`,
209
+ flexShrink: 0,
210
+ }, children: _jsx("div", { style: {
211
+ willChange: "transform, opacity",
212
+ transform: `translate3d(${offsetLeft}px, ${offsetTop}px, 0px)`,
213
+ position: "absolute",
214
+ }, children: children(React.useMemo(() => ({
215
+ visibleItems,
216
+ startColumnIndex,
217
+ cumulativeWidths,
218
+ windowSize,
219
+ columnEndIndex,
220
+ }), [visibleItems, startColumnIndex, cumulativeWidths, windowSize, columnEndIndex])) }) })] }) }), _jsx(RightScrollBar, { ref: rightScrollRef, style: { height: initialBodyHeight - 20, right: "0px" }, onScroll: handleScrollController, children: _jsx("div", { style: { width: "14px", height: `${totalHeight}px` } }) }), _jsx(BottomScrollBar, { ref: bottomScrollRef, style: { width: windowSize.width }, onScroll: handleScrollBottomController, children: _jsx("div", { style: { height: "14px", width: `${totalWidth}px` } }) })] }));
221
+ });
222
+ const VirtualListItem = React.memo(({ item, startColumnIndex, cumulativeWidths, windowSize, columnEndIndex, isColIndex, editStatus }) => {
223
+ const { columns, dataSource } = useSelector((store) => ({
224
+ columns: store.state.columns,
225
+ dataSource: store.state.dataSource,
226
+ }));
227
+ const row = dataSource[item.__dataRowindex];
228
+ const getItemRange = useCallback(() => {
229
+ const start = startColumnIndex;
230
+ let end = columnEndIndex;
231
+ return { start, end };
232
+ }, [startColumnIndex, cumulativeWidths, windowSize, columnEndIndex]);
233
+ const { start, end } = getItemRange();
234
+ const visibleColumns = useMemo(() => columns.slice(start, end + 1), [start, end, columns]);
235
+ const cellStyle = useMemo(() => ({ height: `${item.height}px` }), [item.height]);
236
+ if (item.__dataRowindex === 0)
237
+ console.log("row", row);
238
+ return (_jsx(TableRow, { "aria-rowindex": item.__ariaRowindex, style: cellStyle, className: classes.TableClasses.body.row.root, children: visibleColumns.map((column) => (_jsx(VirtualItem, { column: column, row: row, rowIndex: item.__dataRowindex, isFocus: isColIndex === column.__ariaColindex, editStatus: isColIndex === column.__ariaColindex ? editStatus : undefined }, column.__uuid))) }, item.id));
239
+ });
240
+ const VirtualItem = React.memo(({ column, row, isFocus, editStatus, rowIndex, }) => {
241
+ const cellStyle = useMemo(() => ({ width: `${column.width}px` }), [column.width]);
242
+ const cellClassName = useMemo(() => cx(classes.TableClasses.body.row.cell.root, classes.TableClasses.body.row.cell.classes), [classes.TableClasses.body.row.cell.root, classes.TableClasses.body.row.cell.classes]);
243
+ return (_jsx(TableCell, { "aria-colindex": column.__ariaColindex, tabIndex: isFocus ? 0 : -1, style: cellStyle, className: cellClassName, children: _jsx(CellMode, { column: column, value: row[column.fieldId], editStatus: editStatus, rowIndex: rowIndex }) }, column.__uuid));
244
+ });
245
+ export const TwoDimensionalVirtualizedList = React.memo(() => {
246
+ // 마우스 다운 시작지점점
247
+ const gridRef = useGridApiContext();
248
+ const mouseDownStartPointRef = useRef(0);
249
+ const mouseDownStartWidthRef = useRef(0);
250
+ const colIndexRef = useRef(0);
251
+ const mouseDownRef = useRef(false);
252
+ // 클릭시 타임 측정
253
+ const clickTimer = useRef(null);
254
+ const [imeDefaultValue, setImeDefaultValue] = React.useState("");
255
+ const handleMousedown = useCallback((e) => {
256
+ var _a;
257
+ if (!mouseDownRef.current) {
258
+ if (e.target) {
259
+ const divElement = e.target;
260
+ if ((_a = divElement.getAttribute("class")) === null || _a === void 0 ? void 0 : _a.includes(classes.TableClasses.title.header.resize.root)) {
261
+ const parentElement = divElement.parentElement;
262
+ if (!parentElement)
263
+ return;
264
+ mouseDownRef.current = true;
265
+ const width = parentElement.getAttribute("data-width");
266
+ const colindex = parentElement.getAttribute("aria-colindex");
267
+ mouseDownStartPointRef.current = e.clientX;
268
+ mouseDownStartWidthRef.current = Number(width);
269
+ colIndexRef.current = Number(colindex) - 1;
270
+ }
271
+ }
272
+ // 셀 포커스 지정
273
+ if (e.button !== 0)
274
+ return;
275
+ if (e.target) {
276
+ const divElement = e.target;
277
+ const cell = divElement.closest(`.${classes.TableClasses.body.row.cell.root}`);
278
+ const row = divElement.closest(`.${classes.TableClasses.body.row.root}`);
279
+ if (cell && row) {
280
+ // e.preventDefault();
281
+ const colIndex = Number(cell.getAttribute("aria-colindex"));
282
+ const rowIndex = Number(row.getAttribute("aria-rowindex"));
283
+ const currentColIndex = gridRef.current.store.state.cellFocus[0];
284
+ const currentRowIndex = gridRef.current.store.state.cellFocus[1];
285
+ // if (!(currentColIndex === rowIndex && currentRowIndex === colIndex)) {
286
+ // // IME 문제가 있어 EditStatus.EDITING으로 변경
287
+ // gridRef.current.setEditStatus(EditStatus.EDITABLE).then((editState) => {
288
+ // store.setState(["state", "editStatus"], editState);
289
+ // });
290
+ // } else {
291
+ // gridRef.current.setEditStatus(EditStatus.EDITING).then((editState) => {
292
+ // store.setState(["state", "editStatus"], editState);
293
+ // });
294
+ // }
295
+ if (clickTimer.current) {
296
+ clearTimeout(clickTimer.current); // 더블 클릭 발생 시 실행 취소
297
+ }
298
+ clickTimer.current = setTimeout(() => {
299
+ if (gridRef.current.store.state.editStatus !== EditStatus.EDITING) {
300
+ gridRef.current.setCellFocus(rowIndex, colIndex).then((res) => {
301
+ store.setState(["state", "cellFocus"], res);
302
+ gridRef.current.setEditStatus(EditStatus.IME_EDITING).then((editState) => {
303
+ var _a;
304
+ (_a = textAreaRef.current) === null || _a === void 0 ? void 0 : _a.focus(); // ime 활성화
305
+ });
306
+ });
307
+ }
308
+ }, 250); // 더블 클릭 판별 시간 (기본적으로 250ms 정도 사용)
309
+ gridRef.current.setCellFocus(rowIndex, colIndex).then((res) => {
310
+ store.setState(["state", "cellFocus"], res);
311
+ });
312
+ }
313
+ }
314
+ // ime position init
315
+ if (!textAreaRef.current)
316
+ return;
317
+ textAreaRef.current.style.top = `-${32000}px`;
318
+ textAreaRef.current.style.left = `-${32000}px`;
319
+ textAreaRef.current.value = "";
320
+ setImeDefaultValue("");
321
+ }
322
+ }, []);
323
+ const store = useStore();
324
+ const handleMousemove = useCallback((e) => {
325
+ if (mouseDownRef.current) {
326
+ requestAnimationFrame(() => {
327
+ const diffX = e.clientX - mouseDownStartPointRef.current;
328
+ const startWidth = mouseDownStartWidthRef.current;
329
+ const colIndex = colIndexRef.current;
330
+ const updatedColumns = gridRef.current.store.state.columns.map((v, i) => {
331
+ if (i === colIndex) {
332
+ return Object.assign(Object.assign({}, v), { width: startWidth + diffX });
333
+ }
334
+ return v;
335
+ });
336
+ gridRef.current.store.state.columns = updatedColumns;
337
+ store.setState(["state", "columns"], updatedColumns);
338
+ });
339
+ }
340
+ }, []);
341
+ const handleMouseleave = useCallback(() => {
342
+ mouseDownRef.current = false;
343
+ }, []);
344
+ const handleMouseUp = useCallback((_e) => {
345
+ mouseDownRef.current = false;
346
+ }, []);
347
+ const handleEditEvent = React.useCallback((e) => {
348
+ if (e.key === "ArrowUp" ||
349
+ e.key === "ArrowLeft" ||
350
+ e.key === "ArrowRight" ||
351
+ e.key === "ArrowDown" ||
352
+ e.key === "Tab" ||
353
+ e.key === "Alt" ||
354
+ e.key === "Shift" ||
355
+ e.ctrlKey ||
356
+ (e.ctrlKey && e.key === "c")) {
357
+ return;
358
+ }
359
+ if (e.key === "Enter") {
360
+ gridRef.current.setEditStatus(EditStatus.NON_EDITABLE).then((editState) => {
361
+ store.setState(["state", "editStatus"], editState);
362
+ });
363
+ const divElement = e.target;
364
+ const cell = divElement.closest(`.${classes.TableClasses.body.row.cell.root}`);
365
+ const row = divElement.closest(`.${classes.TableClasses.body.row.root}`);
366
+ if (cell && row) {
367
+ const colIndex = Number(cell.getAttribute("aria-colindex"));
368
+ const rowIndex = Number(row.getAttribute("aria-rowindex"));
369
+ gridRef.current.setCellFocus(Math.min(rowIndex + 1, gridRef.current.store.state.dataSource.length), colIndex).then((res) => {
370
+ store.setState(["state", "cellFocus"], res);
371
+ });
372
+ }
373
+ return;
374
+ }
375
+ if (e.key === "Escape") {
376
+ gridRef.current.setEditStatus(EditStatus.NON_EDITABLE).then((editState) => {
377
+ store.setState(["state", "editStatus"], editState);
378
+ // gridRef.current.scrollToRowIndex(
379
+ // gridRef.current.store.state.cellFocus[0]
380
+ // );
381
+ //
382
+ // const parent = gridRef.current.store.gridContainer.current;
383
+ // const test = gridRef.current.store.gridContainer.current
384
+ // ?.querySelector(`.${classes.TableClasses.body.scroll.root}`)
385
+ // ?.querySelector(
386
+ // `[aria-rowindex="${gridRef.current.store.state.cellFocus[0]}"]`
387
+ // );
388
+ // const observer = new IntersectionObserver(
389
+ // (entries) => {
390
+ // const visible = entries;
391
+ // entries.forEach((entry) => {
392
+ // if (!entry.isIntersecting) {
393
+ // // gridRef.current.scrollToRowIndex(
394
+ // // gridRef.current.store.state.cellFocus[0]
395
+ // // );
396
+ // e.preventDefault();
397
+ // }
398
+ // });
399
+ // },
400
+ // {
401
+ // root: parent,
402
+ // threshold: 0.1, // 요소가 10% 이상 보일 때 트리거
403
+ // }
404
+ // );
405
+ // if (test) observer.observe(test);
406
+ //
407
+ // e.preventDefault();
408
+ });
409
+ return;
410
+ }
411
+ // if (gridRef.current.store.state.editStatus === EditStatus.EDITING) return;
412
+ // gridRef.current.setEditStatus(EditStatus.EDITING).then((editState) => {
413
+ // store.setState(["state", "editStatus"], editState);
414
+ // });
415
+ }, []);
416
+ const handleArrowKey = React.useCallback((e) => {
417
+ var _a;
418
+ const { key } = e;
419
+ if (gridRef.current.store.state.editStatus === EditStatus.EDITING) {
420
+ if (!(key === "Tab" || e.ctrlKey)) {
421
+ return;
422
+ }
423
+ }
424
+ const { setCellFocus } = gridRef.current;
425
+ const { gridContainer } = gridRef.current.store;
426
+ const { cellFocus, columns, dataSource, renderedRowStartEnd } = gridRef.current.store.state;
427
+ if (!cellFocus || (key !== "ArrowRight" && key !== "ArrowLeft" && key !== "ArrowDown" && key !== "ArrowUp" && key !== "Tab"))
428
+ return;
429
+ e.preventDefault();
430
+ const direction = (key === "Tab" && !e.shiftKey) || ["ArrowRight", "ArrowDown"].includes(key) ? 1 : -1;
431
+ // const direction = ["ArrowRight", "ArrowDown", "Tab"].includes(key) ? 1 : -1;
432
+ if (!cellFocus[1])
433
+ return;
434
+ if (!cellFocus[0])
435
+ return;
436
+ let newColumnIndex = cellFocus[1] + direction;
437
+ let newRowIndex = cellFocus[0] + direction;
438
+ let isRowIndex = false;
439
+ let isColIndex = false;
440
+ const widths = new Array(columns.length + 1).fill(0); // 초기 크기 설정
441
+ const sumWidths = new Array(columns.length + 1).fill(0);
442
+ const dataSourceEnd = renderedRowStartEnd ? Math.min(renderedRowStartEnd[1] + 100, dataSource.length) : dataSource.length;
443
+ const heights = new Array(dataSourceEnd + 1).fill(0); // 초기 크기 설정
444
+ const sumHeights = new Array(dataSourceEnd + 1).fill(0);
445
+ for (let i = 0; i < columns.length; i++) {
446
+ const width = Number(columns[i].width); // 변환 1회만 수행
447
+ widths[i + 1] = width;
448
+ sumWidths[i + 1] = sumWidths[i] + width; // 이전 합계를 변수로 사용
449
+ }
450
+ for (let i = 0; i < dataSourceEnd; i++) {
451
+ const height = Number(dataSource[i].height); // 변환 1회만 수행
452
+ heights[i + 1] = height;
453
+ sumHeights[i + 1] = sumHeights[i] + height; // 이전 합계를 변수로 사용
454
+ }
455
+ switch (key) {
456
+ case "ArrowLeft":
457
+ case "ArrowRight":
458
+ case "Tab":
459
+ isColIndex = true;
460
+ break;
461
+ case "ArrowDown":
462
+ case "ArrowUp":
463
+ isRowIndex = true;
464
+ }
465
+ const bodyElement = (_a = gridContainer.current) === null || _a === void 0 ? void 0 : _a.querySelector(`.${classes.TableClasses.body.scroll.root}`);
466
+ const rowIndex = isRowIndex ? newRowIndex : newRowIndex - direction;
467
+ const colIndex = isColIndex ? newColumnIndex : newColumnIndex - direction;
468
+ setCellFocus(rowIndex, colIndex).then((res) => {
469
+ ReactDOM.flushSync(() => {
470
+ store.setState(["state", "cellFocus"], res);
471
+ if (bodyElement) {
472
+ const scrollThreshold = Math.max(0, sumWidths[newColumnIndex - 1] - 1200);
473
+ const scrollRowThreshold = Math.max(0, sumHeights[newRowIndex - 1] - 450);
474
+ if (key === "ArrowRight" || (!e.shiftKey && key === "Tab" && bodyElement.scrollLeft < scrollThreshold)) {
475
+ bodyElement.scrollLeft = scrollThreshold;
476
+ }
477
+ if (key === "ArrowLeft" || (e.shiftKey && key === "Tab" && bodyElement)) {
478
+ const targetStart = sumWidths[newColumnIndex - 1];
479
+ const scrollStart = bodyElement.scrollLeft;
480
+ if (scrollStart >= targetStart) {
481
+ bodyElement.scrollLeft = targetStart - widths[newColumnIndex - 1];
482
+ }
483
+ }
484
+ if (key === "ArrowDown" && bodyElement.scrollTop < scrollRowThreshold) {
485
+ bodyElement.scrollTop = scrollRowThreshold;
486
+ }
487
+ if (key === "ArrowUp" && bodyElement) {
488
+ const targetStart = sumHeights[newRowIndex];
489
+ const scrollStart = bodyElement.scrollTop;
490
+ if (scrollStart >= targetStart) {
491
+ bodyElement.scrollTop = targetStart - heights[newRowIndex];
492
+ }
493
+ }
494
+ }
495
+ });
496
+ });
497
+ }, []);
498
+ const handleKeydown = useCallback((e) => {
499
+ handleArrowKey(e);
500
+ handleEditEvent(e);
501
+ }, []);
502
+ const handleDbClick = useCallback(() => {
503
+ gridRef.current.setEditStatus(EditStatus.EDITING).then((editState) => {
504
+ store.setState(["state", "editStatus"], editState);
505
+ });
506
+ if (clickTimer.current) {
507
+ clearTimeout(clickTimer.current); // 더블 클릭 발생 시 mousedown 실행 방지
508
+ }
509
+ }, []);
510
+ useEffect(() => {
511
+ window.addEventListener("mousedown", handleMousedown);
512
+ window.addEventListener("mousemove", handleMousemove);
513
+ window.addEventListener("mouseleave", handleMouseleave);
514
+ window.addEventListener("mouseup", handleMouseUp);
515
+ window.addEventListener("keydown", handleKeydown);
516
+ window.addEventListener("dblclick", handleDbClick);
517
+ return () => {
518
+ window.removeEventListener("mousedown", handleMousedown);
519
+ window.removeEventListener("mousemove", handleMousemove);
520
+ window.removeEventListener("mouseleave", handleMouseleave);
521
+ window.removeEventListener("mouseup", handleMouseUp);
522
+ window.removeEventListener("dblclick", handleDbClick);
523
+ };
524
+ }, []);
525
+ const { cellFocus } = useSelector((store) => {
526
+ return {
527
+ cellFocus: store.state.cellFocus,
528
+ };
529
+ });
530
+ const { editStatus } = useSelector((store) => ({
531
+ editStatus: store.state.editStatus,
532
+ }));
533
+ const rowFocus = cellFocus && cellFocus[0];
534
+ const colFocus = cellFocus && cellFocus[1];
535
+ const textAreaRef = React.useRef(null);
536
+ return (_jsxs(_Fragment, { children: [_jsx(DynamicVirtualScroll, { children: ({ visibleItems, startColumnIndex, cumulativeWidths, windowSize, columnEndIndex }) => (_jsx(_Fragment, { children: visibleItems.map((item) => (_jsx(VirtualListItem, { item: item, startColumnIndex: startColumnIndex, cumulativeWidths: cumulativeWidths, windowSize: windowSize, columnEndIndex: columnEndIndex, isColIndex: rowFocus === item.__ariaRowindex ? colFocus : undefined, editStatus: rowFocus === item.__ariaRowindex ? editStatus : undefined }, item.id))) })) }), _jsx(ImeComponent, { ref: textAreaRef, defaultValue: imeDefaultValue })] }));
537
+ });
538
+ export default React.memo(TwoDimensionalVirtualizedList);
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { EditStatus } from "../../types/dataGridCoreEnum";
3
+ import { DataGridPrivateColumnModel, DataGridPrivateDataSourceModel } from "../../types/dataGridCoreProps";
4
+ declare const _default: React.MemoExoticComponent<({ column, value, editStatus, rowIndex, }: {
5
+ column: DataGridPrivateColumnModel;
6
+ value: keyof DataGridPrivateDataSourceModel;
7
+ editStatus: EditStatus | undefined;
8
+ rowIndex: number;
9
+ }) => import("react/jsx-runtime").JSX.Element>;
10
+ export default _default;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { useStore } from "../../provider/GridStoreContent";
4
+ import { EditStatus } from "../../types/dataGridCoreEnum";
5
+ import useGridApiContext from "../../hooks/useGridApiContext";
6
+ import { Input } from "../virtualized/_styled";
7
+ const CellMode = ({ column, value, editStatus, rowIndex, }) => {
8
+ const gridRef = useGridApiContext();
9
+ const [inputValue, setInputValue] = React.useState(value);
10
+ const inputRef = React.useRef(null);
11
+ React.useEffect(() => {
12
+ if (editStatus === EditStatus.EDITING || editStatus === EditStatus.EDITABLE) {
13
+ const tick = setTimeout(() => {
14
+ var _a;
15
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
16
+ }, 10);
17
+ return () => clearTimeout(tick);
18
+ }
19
+ }, [editStatus]);
20
+ const store = useStore();
21
+ const handleInputChange = React.useCallback((e) => {
22
+ console.log("handleInputChange", rowIndex, e, e.target.value);
23
+ setInputValue(e.target.value);
24
+ const dataSource = gridRef.current.cellByRowIndex(rowIndex, column.fieldId, e.target.value);
25
+ store.setState(["state", "dataSource"], dataSource, false);
26
+ }, [rowIndex]);
27
+ if (editStatus === EditStatus.EDITING)
28
+ return _jsx(Input, { autoFocus: true, ref: inputRef, value: inputValue, onChange: handleInputChange }, 1);
29
+ if (editStatus === EditStatus.NON_EDITABLE)
30
+ return _jsx(React.Fragment, { children: value });
31
+ return _jsx(React.Fragment, { children: value });
32
+ };
33
+ export default React.memo(CellMode);
@@ -0,0 +1,5 @@
1
+ import { VirtualHeaderProps } from "../virtualized/_constants/virtualHeaderConstants";
2
+ declare const _default: import("react").MemoExoticComponent<(props: VirtualHeaderProps & {
3
+ offsetLeft: number;
4
+ }) => import("react/jsx-runtime").JSX.Element>;
5
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo } from "react";
3
+ import VirtualHeader from "../virtualized/_components/VirtualHeader";
4
+ import { TableHeaderRoot } from "../virtualized/_styled";
5
+ import { classes } from "../../types/classes";
6
+ const VirtualHorizontalHeader = (props) => {
7
+ return (_jsx(TableHeaderRoot, { className: classes.TableClasses.title.header.root, style: {
8
+ transform: `translate3d(${props.offsetLeft}px, 0px, 0px)`,
9
+ position: "sticky",
10
+ top: "0px",
11
+ }, children: _jsx(VirtualHeader, Object.assign({}, props)) }));
12
+ };
13
+ export default memo(VirtualHorizontalHeader);
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<{
3
+ defaultValue: string;
4
+ } & React.RefAttributes<HTMLTextAreaElement>>>;
5
+ export default _default;