pixel-react 1.1.8 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. package/lib/components/AddButton/AddButton.d.ts +5 -0
  2. package/lib/components/AddButton/AddButton.stories.d.ts +6 -0
  3. package/lib/components/AddButton/index.d.ts +1 -0
  4. package/lib/components/AddButton/types.d.ts +4 -0
  5. package/lib/components/AppHeader/types.d.ts +7 -7
  6. package/lib/components/Drawer/Drawer.stories.d.ts +2 -0
  7. package/lib/components/Drawer/Types.d.ts +11 -0
  8. package/lib/components/ExcelFile/ChangeExcelStyles.d.ts +14 -0
  9. package/lib/components/ExcelFile/ColorBarSelector/ColorBarSelector.d.ts +8 -0
  10. package/lib/components/ExcelFile/ContextMenu/ContextMenu.d.ts +4 -0
  11. package/lib/components/ExcelFile/ExcelFile/Excel/ActiveCell.d.ts +7 -0
  12. package/lib/components/ExcelFile/ExcelFile/Excel/Cell.d.ts +4 -0
  13. package/lib/components/ExcelFile/ExcelFile/Excel/ColumnIndicator.d.ts +5 -0
  14. package/lib/components/ExcelFile/ExcelFile/Excel/Copied.d.ts +3 -0
  15. package/lib/components/ExcelFile/ExcelFile/Excel/CornerIndicator.d.ts +5 -0
  16. package/lib/components/ExcelFile/ExcelFile/Excel/DataEditor.d.ts +5 -0
  17. package/lib/components/ExcelFile/ExcelFile/Excel/DataViewer.d.ts +8 -0
  18. package/lib/components/ExcelFile/ExcelFile/Excel/FloatingRect.d.ts +10 -0
  19. package/lib/components/ExcelFile/ExcelFile/Excel/HeaderRow.d.ts +3 -0
  20. package/lib/components/ExcelFile/ExcelFile/Excel/Row.d.ts +3 -0
  21. package/lib/components/ExcelFile/ExcelFile/Excel/RowIndicator.d.ts +5 -0
  22. package/lib/components/ExcelFile/ExcelFile/Excel/Selected.d.ts +3 -0
  23. package/lib/components/ExcelFile/ExcelFile/Excel/Spreadsheet.d.ts +81 -0
  24. package/lib/components/ExcelFile/ExcelFile/Excel/Table.d.ts +3 -0
  25. package/lib/components/ExcelFile/ExcelFile/Excel/actions.d.ts +130 -0
  26. package/lib/components/ExcelFile/ExcelFile/Excel/areModelsEqual.d.ts +1 -0
  27. package/lib/components/ExcelFile/ExcelFile/Excel/context.d.ts +8 -0
  28. package/lib/components/ExcelFile/ExcelFile/Excel/engine/engine.d.ts +22 -0
  29. package/lib/components/ExcelFile/ExcelFile/Excel/engine/formula.d.ts +17 -0
  30. package/lib/components/ExcelFile/ExcelFile/Excel/engine/index.d.ts +2 -0
  31. package/lib/components/ExcelFile/ExcelFile/Excel/engine/point-graph.d.ts +21 -0
  32. package/lib/components/ExcelFile/ExcelFile/Excel/engine/point-hash.d.ts +3 -0
  33. package/lib/components/ExcelFile/ExcelFile/Excel/engine/point-set.d.ts +24 -0
  34. package/lib/components/ExcelFile/ExcelFile/Excel/index.d.ts +13 -0
  35. package/lib/components/ExcelFile/ExcelFile/Excel/matrix.d.ts +67 -0
  36. package/lib/components/ExcelFile/ExcelFile/Excel/point-range.d.ts +22 -0
  37. package/lib/components/ExcelFile/ExcelFile/Excel/point.d.ts +11 -0
  38. package/lib/components/ExcelFile/ExcelFile/Excel/reducer.d.ts +27 -0
  39. package/lib/components/ExcelFile/ExcelFile/Excel/selection.d.ts +95 -0
  40. package/lib/components/ExcelFile/ExcelFile/Excel/types.d.ts +215 -0
  41. package/lib/components/ExcelFile/ExcelFile/Excel/use-dispatch.d.ts +3 -0
  42. package/lib/components/ExcelFile/ExcelFile/Excel/use-selector.d.ts +3 -0
  43. package/lib/components/ExcelFile/ExcelFile/Excel/util.d.ts +45 -0
  44. package/lib/components/ExcelFile/ExcelFile/ExcelFile.d.ts +3 -0
  45. package/lib/components/ExcelFile/ExcelFile.stories.d.ts +6 -0
  46. package/lib/components/ExcelFile/ExcelSheetBar/ExcelSheetBar.d.ts +15 -0
  47. package/lib/components/ExcelFile/ExcelToolBar/ExcelToolBar.d.ts +3 -0
  48. package/lib/components/ExcelFile/ImportExcelStyles.d.ts +24 -0
  49. package/lib/components/ExcelFile/Types.d.ts +176 -0
  50. package/lib/components/ExcelFile/index.d.ts +1 -0
  51. package/lib/components/Icon/Icon.stories.d.ts +1 -0
  52. package/lib/components/Icon/types.d.ts +1 -0
  53. package/lib/components/IconRadioGroup/IconRadioGroup.d.ts +5 -0
  54. package/lib/components/IconRadioGroup/IconRadioGroup.stories.d.ts +7 -0
  55. package/lib/components/IconRadioGroup/index.d.ts +1 -0
  56. package/lib/components/IconRadioGroup/type.d.ts +41 -0
  57. package/lib/components/Table/Table.d.ts +1 -1
  58. package/lib/components/Table/Table.stories.d.ts +2 -0
  59. package/lib/components/Table/Types.d.ts +16 -0
  60. package/lib/index.d.ts +81 -9
  61. package/lib/index.esm.js +739 -248
  62. package/lib/index.esm.js.map +1 -1
  63. package/lib/index.js +739 -247
  64. package/lib/index.js.map +1 -1
  65. package/lib/tsconfig.tsbuildinfo +1 -1
  66. package/lib/utils/find/findAndInsert.d.ts +7 -0
  67. package/lib/utils/find/findAndInsert.stories.d.ts +7 -0
  68. package/package.json +4 -2
  69. package/src/assets/Themes/BaseTheme.scss +4 -0
  70. package/src/assets/Themes/DarkTheme.scss +4 -0
  71. package/src/assets/icons/all_borders.svg +3 -0
  72. package/src/assets/icons/bold.svg +3 -0
  73. package/src/assets/icons/border_bottom.svg +3 -0
  74. package/src/assets/icons/border_left.svg +3 -0
  75. package/src/assets/icons/border_right.svg +3 -0
  76. package/src/assets/icons/border_top.svg +3 -0
  77. package/src/assets/icons/clone_icon.svg +3 -0
  78. package/src/assets/icons/double_underline.svg +5 -0
  79. package/src/assets/icons/eye_closed.svg +3 -0
  80. package/src/assets/icons/fill_color.svg +7 -0
  81. package/src/assets/icons/formate_painter.svg +5 -0
  82. package/src/assets/icons/full_access_icon.svg +4 -0
  83. package/src/assets/icons/history_icon.svg +19 -0
  84. package/src/assets/icons/italic.svg +3 -0
  85. package/src/assets/icons/jira.svg +3 -0
  86. package/src/assets/icons/linked_defects.svg +11 -0
  87. package/src/assets/icons/move_icon.svg +5 -0
  88. package/src/assets/icons/no_access_icon.svg +4 -0
  89. package/src/assets/icons/no_border.svg +3 -0
  90. package/src/assets/icons/strike_through.svg +3 -0
  91. package/src/assets/icons/text_align_center.svg +3 -0
  92. package/src/assets/icons/text_align_left.svg +3 -0
  93. package/src/assets/icons/text_align_right.svg +3 -0
  94. package/src/assets/icons/text_color.svg +3 -0
  95. package/src/assets/icons/underline.svg +4 -0
  96. package/src/assets/icons/view_access_icon.svg +4 -0
  97. package/src/components/AppHeader/AppHeader.scss +23 -10
  98. package/src/components/AppHeader/AppHeader.stories.tsx +29 -28
  99. package/src/components/AppHeader/AppHeader.tsx +18 -16
  100. package/src/components/AppHeader/types.ts +7 -7
  101. package/src/components/Button/Button.scss +1 -0
  102. package/src/components/Checkbox/Checkbox.tsx +1 -1
  103. package/src/components/Drawer/Drawer.scss +13 -9
  104. package/src/components/Drawer/Drawer.stories.tsx +28 -0
  105. package/src/components/Drawer/Drawer.tsx +29 -6
  106. package/src/components/Drawer/Types.ts +11 -0
  107. package/src/components/ExcelFile/ChangeExcelStyles.tsx +78 -0
  108. package/src/components/ExcelFile/ColorBarselector/ColorBarSelector.scss +13 -0
  109. package/src/components/ExcelFile/ColorBarselector/ColorBarSelector.tsx +43 -0
  110. package/src/components/ExcelFile/ContextMenu/ContextMenu.scss +102 -0
  111. package/src/components/ExcelFile/ContextMenu/ContextMenu.tsx +104 -0
  112. package/src/components/ExcelFile/ExcelFile/Excel/ActiveCell.tsx +131 -0
  113. package/src/components/ExcelFile/ExcelFile/Excel/Cell.tsx +201 -0
  114. package/src/components/ExcelFile/ExcelFile/Excel/ColumnIndicator.tsx +123 -0
  115. package/src/components/ExcelFile/ExcelFile/Excel/Copied.tsx +25 -0
  116. package/src/components/ExcelFile/ExcelFile/Excel/CornerIndicator.tsx +49 -0
  117. package/src/components/ExcelFile/ExcelFile/Excel/DataEditor.tsx +37 -0
  118. package/src/components/ExcelFile/ExcelFile/Excel/DataViewer.tsx +46 -0
  119. package/src/components/ExcelFile/ExcelFile/Excel/FloatingRect.tsx +31 -0
  120. package/src/components/ExcelFile/ExcelFile/Excel/HeaderRow.tsx +5 -0
  121. package/src/components/ExcelFile/ExcelFile/Excel/Row.tsx +5 -0
  122. package/src/components/ExcelFile/ExcelFile/Excel/RowIndicator.tsx +102 -0
  123. package/src/components/ExcelFile/ExcelFile/Excel/Selected.tsx +32 -0
  124. package/src/components/ExcelFile/ExcelFile/Excel/Spreadsheet.css +144 -0
  125. package/src/components/ExcelFile/ExcelFile/Excel/Spreadsheet.tsx +494 -0
  126. package/src/components/ExcelFile/ExcelFile/Excel/Table.tsx +19 -0
  127. package/src/components/ExcelFile/ExcelFile/Excel/actions.ts +302 -0
  128. package/src/components/ExcelFile/ExcelFile/Excel/areModelsEqual.ts +18 -0
  129. package/src/components/ExcelFile/ExcelFile/Excel/context.ts +12 -0
  130. package/src/components/ExcelFile/ExcelFile/Excel/engine/engine.ts +200 -0
  131. package/src/components/ExcelFile/ExcelFile/Excel/engine/formula.ts +137 -0
  132. package/src/components/ExcelFile/ExcelFile/Excel/engine/index.ts +2 -0
  133. package/src/components/ExcelFile/ExcelFile/Excel/engine/point-graph.ts +154 -0
  134. package/src/components/ExcelFile/ExcelFile/Excel/engine/point-hash.ts +10 -0
  135. package/src/components/ExcelFile/ExcelFile/Excel/engine/point-set.ts +69 -0
  136. package/src/components/ExcelFile/ExcelFile/Excel/index.ts +48 -0
  137. package/src/components/ExcelFile/ExcelFile/Excel/matrix.ts +388 -0
  138. package/src/components/ExcelFile/ExcelFile/Excel/point-range.ts +82 -0
  139. package/src/components/ExcelFile/ExcelFile/Excel/point.ts +15 -0
  140. package/src/components/ExcelFile/ExcelFile/Excel/reducer.ts +682 -0
  141. package/src/components/ExcelFile/ExcelFile/Excel/selection.ts +257 -0
  142. package/src/components/ExcelFile/ExcelFile/Excel/types.ts +269 -0
  143. package/src/components/ExcelFile/ExcelFile/Excel/typings/fast-formula-parser.d.ts +58 -0
  144. package/src/components/ExcelFile/ExcelFile/Excel/use-dispatch.ts +8 -0
  145. package/src/components/ExcelFile/ExcelFile/Excel/use-selector.ts +9 -0
  146. package/src/components/ExcelFile/ExcelFile/Excel/util.ts +173 -0
  147. package/src/components/ExcelFile/ExcelFile/ExcelFile.scss +27 -0
  148. package/src/components/ExcelFile/ExcelFile/ExcelFile.tsx +520 -0
  149. package/src/components/ExcelFile/ExcelFile.stories.tsx +132 -0
  150. package/src/components/ExcelFile/ExcelSheetBar/ExcelSheetBar.scss +16 -0
  151. package/src/components/ExcelFile/ExcelSheetBar/ExcelSheetBar.tsx +79 -0
  152. package/src/components/ExcelFile/ExcelToolBar/ExcelToolBar.scss +22 -0
  153. package/src/components/ExcelFile/ExcelToolBar/ExcelToolBar.tsx +271 -0
  154. package/src/components/ExcelFile/ImportExcelStyles.tsx +86 -0
  155. package/src/components/ExcelFile/Types.ts +241 -0
  156. package/src/components/ExcelFile/index.ts +1 -0
  157. package/src/components/Icon/Icon.stories.tsx +27 -0
  158. package/src/components/Icon/Icon.tsx +5 -1
  159. package/src/components/Icon/Icons.scss +15 -5
  160. package/src/components/Icon/iconList.ts +52 -1
  161. package/src/components/Icon/types.ts +1 -0
  162. package/src/components/IconRadioGroup/IconRadioGroup.scss +60 -0
  163. package/src/components/IconRadioGroup/IconRadioGroup.stories.tsx +108 -0
  164. package/src/components/IconRadioGroup/IconRadioGroup.tsx +72 -0
  165. package/src/components/IconRadioGroup/index.ts +1 -0
  166. package/src/components/IconRadioGroup/type.ts +50 -0
  167. package/src/components/Modal/Modal.tsx +8 -1
  168. package/src/components/Modal/modal.scss +10 -2
  169. package/src/components/Table/Table.scss +16 -4
  170. package/src/components/Table/Table.stories.tsx +36 -12
  171. package/src/components/Table/Table.tsx +33 -16
  172. package/src/components/Table/Types.ts +121 -105
  173. package/src/index.ts +2 -0
@@ -0,0 +1,494 @@
1
+ import * as React from "react";
2
+ import classNames from "classnames";
3
+ import * as Types from "./types";
4
+ import * as Actions from "./actions";
5
+ import * as Matrix from "./matrix";
6
+ import * as Point from "./point";
7
+ import { Selection } from "./selection";
8
+ import reducer, { INITIAL_STATE, hasKeyDownHandler } from "./reducer";
9
+ import context from "./context";
10
+ import { Model, createFormulaParser } from "./engine";
11
+ import {
12
+ range,
13
+ readTextFromClipboard,
14
+ writeTextToClipboard,
15
+ calculateSpreadsheetSize,
16
+ getCSV,
17
+ shouldHandleClipboardEvent,
18
+ isFocusedWithin,
19
+ } from "./util";
20
+
21
+ import DefaultTable from "./Table";
22
+ import DefaultRow from "./Row";
23
+ import DefaultHeaderRow from "./HeaderRow";
24
+ import DefaultCornerIndicator, {
25
+ enhance as enhanceCornerIndicator,
26
+ } from "./CornerIndicator";
27
+ import DefaultColumnIndicator, {
28
+ enhance as enhanceColumnIndicator,
29
+ } from "./ColumnIndicator";
30
+ import DefaultRowIndicator, {
31
+ enhance as enhanceRowIndicator,
32
+ } from "./RowIndicator";
33
+ import { Cell as DefaultCell, enhance as enhanceCell } from "./Cell";
34
+ import DefaultDataViewer from "./DataViewer";
35
+ import DefaultDataEditor from "./DataEditor";
36
+ import ActiveCell from "./ActiveCell";
37
+ import Selected from "./Selected";
38
+ import Copied from "./Copied";
39
+ import "./Spreadsheet.css";
40
+
41
+ /** The Spreadsheet component props */
42
+ export type Props<CellType extends Types.CellBase> = {
43
+ /** The spreadsheet's data */
44
+ data: Matrix.Matrix<CellType>;
45
+ /** Class name to be added to the spreadsheet's root element */
46
+ className?: string;
47
+ /**
48
+ * Use dark colors that complement dark mode
49
+ * @defaultValue `false`
50
+ */
51
+ darkMode?: boolean;
52
+ /**
53
+ * Function used to create the formula parser (instance of
54
+ * "fast-formula-parser") used by the Spreadsheet by getting the spreadsheet's
55
+ * data.
56
+ * @defaultValue function which creates a formula parser bound to the
57
+ * Spreadsheet's data.
58
+ * @see `createFormulaParser`
59
+ * @see https://www.npmjs.com/package/fast-formula-parser
60
+ */
61
+ createFormulaParser?: Types.CreateFormulaParser;
62
+ /**
63
+ * Labels to use in column indicators.
64
+ * @defaultValue alphabetical labels.
65
+ */
66
+ columnLabels?: string[];
67
+ /**
68
+ * Labels to use in row indicators.
69
+ * @defaultValue row index labels.
70
+ */
71
+ rowLabels?: string[];
72
+ /**
73
+ * If set to true, hides the row indicators of the spreadsheet.
74
+ * @defaultValue `false`.
75
+ */
76
+ hideRowIndicators?: boolean;
77
+ /**
78
+ * If set to true, hides the column indicators of the spreadsheet.
79
+ * @defaultValue `false`.
80
+ */
81
+ hideColumnIndicators?: boolean;
82
+ /** The selected cells in the worksheet. */
83
+ selected?: Selection;
84
+ // Custom Components
85
+ /** Component rendered above each column. */
86
+ ColumnIndicator?: Types.ColumnIndicatorComponent;
87
+ /** Component rendered in the corner of row and column indicators. */
88
+ CornerIndicator?: Types.CornerIndicatorComponent;
89
+ /** Component rendered next to each row. */
90
+ RowIndicator?: Types.RowIndicatorComponent;
91
+ /** The Spreadsheet's table component. */
92
+ Table?: Types.TableComponent;
93
+ /** The Spreadsheet's row component. */
94
+ Row?: Types.RowComponent;
95
+ /** The spreadsheet's header row component */
96
+ HeaderRow?: Types.HeaderRowComponent;
97
+ /** The Spreadsheet's cell component. */
98
+ Cell?: Types.CellComponent<CellType>;
99
+ /** Component rendered for cells in view mode. */
100
+ DataViewer?: Types.DataViewerComponent<CellType>;
101
+ /** Component rendered for cells in edit mode. */
102
+ DataEditor?: Types.DataEditorComponent<CellType>;
103
+ // Handlers
104
+ /** Callback called on key down inside the spreadsheet. */
105
+ onKeyDown?: (event: React.KeyboardEvent) => void;
106
+ /** Callback called when the Spreadsheet's selection changes. */
107
+ onSelect?: (selected: Selection) => void;
108
+ /** Callback called when Spreadsheet's active cell changes. */
109
+ onActivate?: (active: Point.Point) => void;
110
+ /** Callback called when the Spreadsheet's evaluated data changes. */
111
+ onEvaluatedDataChange?: (data: Matrix.Matrix<CellType>) => void;
112
+ };
113
+
114
+ /**
115
+ * The Spreadsheet component
116
+ */
117
+ const Spreadsheet = <CellType extends Types.CellBase>(
118
+ props: Props<CellType>
119
+ ): React.ReactElement => {
120
+ const {
121
+ className,
122
+ darkMode,
123
+ columnLabels,
124
+ rowLabels,
125
+ // hideColumnIndicators,
126
+ // hideRowIndicators,
127
+ onKeyDown,
128
+ Table = DefaultTable,
129
+ Row = DefaultRow,
130
+ HeaderRow = DefaultHeaderRow,
131
+ DataEditor = DefaultDataEditor,
132
+ DataViewer = DefaultDataViewer,
133
+ // onChange = () => {},
134
+ // onModeChange = () => {},
135
+ onSelect = () => {},
136
+ onActivate = () => {},
137
+ // onBlur = () => {},
138
+ // onCellCommit = () => {},
139
+ onEvaluatedDataChange = () => {},
140
+ } = props;
141
+ type State = Types.StoreState<CellType>;
142
+
143
+ const initialState = React.useMemo(() => {
144
+ const createParser = (props.createFormulaParser ||
145
+ createFormulaParser) as Types.CreateFormulaParser;
146
+ const model = new Model(createParser, props.data);
147
+ return {
148
+ ...INITIAL_STATE,
149
+ model,
150
+ selected: props.selected || INITIAL_STATE.selected,
151
+ } as State;
152
+ }, [props.createFormulaParser, props.data, props.selected]);
153
+
154
+ const reducerElements = React.useReducer(
155
+ reducer as unknown as React.Reducer<State, Actions.Action>,
156
+ initialState
157
+ );
158
+ const [state, dispatch] = reducerElements;
159
+
160
+ const size = React.useMemo(() => {
161
+ return calculateSpreadsheetSize(state.model.data, rowLabels, columnLabels);
162
+ }, [state.model.data, rowLabels, columnLabels]);
163
+
164
+ const mode = state.mode;
165
+
166
+ const rootRef = React.useRef<HTMLDivElement>(null);
167
+
168
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
169
+ const useAction = <T extends (...args: any[]) => Actions.Action>(
170
+ action: T
171
+ ) => {
172
+ return React.useCallback(
173
+ (...args: Parameters<T>) => dispatch(action(...args)),
174
+ [action]
175
+ );
176
+ };
177
+
178
+ const cut = useAction(Actions.cut);
179
+ const copy = useAction(Actions.copy);
180
+ const paste = useAction(Actions.paste);
181
+ const onKeyDownAction = useAction(Actions.keyDown);
182
+ const onKeyPress = useAction(Actions.keyPress);
183
+ const onDragStart = useAction(Actions.dragStart);
184
+ const onDragEnd = useAction(Actions.dragEnd);
185
+ const setData = useAction(Actions.setData);
186
+ const setCreateFormulaParser = useAction(Actions.setCreateFormulaParser);
187
+ const setSelection = useAction(Actions.setSelection);
188
+
189
+ // Track active
190
+ const prevActiveRef = React.useRef<Point.Point | null>(state.active);
191
+ React.useEffect(() => {
192
+ if (state.active !== prevActiveRef.current) {
193
+ if (state.active) {
194
+ onActivate(state.active);
195
+ } else {
196
+ const root = rootRef.current;
197
+ if (root && isFocusedWithin(root) && document.activeElement) {
198
+ (document.activeElement as HTMLElement).blur();
199
+ }
200
+ }
201
+ }
202
+
203
+ prevActiveRef.current = state.active;
204
+ }, [onActivate, state.active]);
205
+
206
+ const prevEvaluatedDataRef = React.useRef<Matrix.Matrix<CellType>>(
207
+ state.model.evaluatedData
208
+ );
209
+ React.useEffect(() => {
210
+ if (state?.model?.evaluatedData !== prevEvaluatedDataRef?.current) {
211
+ onEvaluatedDataChange(state?.model?.evaluatedData);
212
+ }
213
+
214
+ prevEvaluatedDataRef.current = state.model.evaluatedData;
215
+ }, [state?.model?.evaluatedData, onEvaluatedDataChange]);
216
+
217
+ // Listen to selection changes
218
+ const prevSelectedRef = React.useRef<Selection>(state.selected);
219
+ React.useEffect(() => {
220
+ if (!state.selected.equals(prevSelectedRef.current)) {
221
+ // Call on select only if the selection change internal
222
+ if (!props.selected || !state.selected.equals(props.selected)) {
223
+ onSelect(state.selected);
224
+ }
225
+ }
226
+
227
+ prevSelectedRef.current = state.selected;
228
+ }, [state.selected, onSelect, props.selected]);
229
+
230
+ // Update selection when props.selected changes
231
+ const prevSelectedPropRef = React.useRef<Selection | undefined>(
232
+ props.selected
233
+ );
234
+ React.useEffect(() => {
235
+ if (
236
+ props.selected &&
237
+ prevSelectedPropRef.current &&
238
+ !props.selected.equals(prevSelectedPropRef.current)
239
+ ) {
240
+ setSelection(props.selected);
241
+ }
242
+ prevSelectedPropRef.current = props.selected;
243
+ }, [props.selected, setSelection]);
244
+
245
+ // Update data when props.data changes
246
+ const prevDataPropRef = React.useRef<Matrix.Matrix<CellType> | undefined>(
247
+ props.data
248
+ );
249
+ React.useEffect(() => {
250
+ if (props.data !== prevDataPropRef.current) {
251
+ setData(props.data);
252
+ }
253
+ prevDataPropRef.current = props.data;
254
+ }, [props.data, setData]);
255
+
256
+ // Update createFormulaParser when props.createFormulaParser changes
257
+ const prevCreateFormulaParserPropRef = React.useRef<
258
+ Types.CreateFormulaParser | undefined
259
+ >(props.createFormulaParser);
260
+ React.useEffect(() => {
261
+ if (
262
+ props.createFormulaParser !== prevCreateFormulaParserPropRef.current &&
263
+ props.createFormulaParser
264
+ )
265
+ setCreateFormulaParser(props.createFormulaParser);
266
+ prevCreateFormulaParserPropRef.current = props.createFormulaParser;
267
+ }, [props.createFormulaParser, setCreateFormulaParser]);
268
+
269
+ const writeDataToClipboard = React.useCallback(
270
+ (event: ClipboardEvent): void => {
271
+ const { model, selected } = state;
272
+ const { data } = model;
273
+ const range = selected.toRange(data);
274
+ if (range) {
275
+ const selectedData = Matrix.slice(range.start, range.end, data);
276
+ const csv = getCSV(selectedData);
277
+ writeTextToClipboard(event, csv);
278
+ }
279
+ },
280
+ [state]
281
+ );
282
+
283
+ const handleCut = React.useCallback(
284
+ (event: ClipboardEvent) => {
285
+ if (shouldHandleClipboardEvent(rootRef.current, mode)) {
286
+ event.preventDefault();
287
+ event.stopPropagation();
288
+ writeDataToClipboard(event);
289
+ cut();
290
+ }
291
+ },
292
+ [mode, writeDataToClipboard, cut]
293
+ );
294
+
295
+ const handleCopy = React.useCallback(
296
+ (event: ClipboardEvent) => {
297
+ if (shouldHandleClipboardEvent(rootRef.current, mode)) {
298
+ event.preventDefault();
299
+ event.stopPropagation();
300
+ writeDataToClipboard(event);
301
+ copy();
302
+ }
303
+ },
304
+ [mode, writeDataToClipboard, copy]
305
+ );
306
+
307
+ const handlePaste = React.useCallback(
308
+ (event: ClipboardEvent) => {
309
+ if (shouldHandleClipboardEvent(rootRef.current, mode)) {
310
+ event.preventDefault();
311
+ event.stopPropagation();
312
+ if (event.clipboardData) {
313
+ const text = readTextFromClipboard(event);
314
+ paste(text);
315
+ }
316
+ }
317
+ },
318
+ [mode, paste]
319
+ );
320
+
321
+ const handleKeyDown = React.useCallback(
322
+ (event: React.KeyboardEvent) => {
323
+ event.persist();
324
+ if (onKeyDown) {
325
+ onKeyDown(event);
326
+ }
327
+ // Do not use event in case preventDefault() was called inside onKeyDown
328
+ if (!event.defaultPrevented) {
329
+ // Only disable default behavior if an handler exist
330
+ if (hasKeyDownHandler(state, event)) {
331
+ event.nativeEvent.preventDefault();
332
+ }
333
+ onKeyDownAction(event);
334
+ }
335
+ },
336
+ [state, onKeyDown, onKeyDownAction]
337
+ );
338
+
339
+ const handleMouseUp = React.useCallback(() => {
340
+ onDragEnd();
341
+ document.removeEventListener("mouseup", handleMouseUp);
342
+ }, [onDragEnd]);
343
+
344
+ const handleMouseMove = React.useCallback(
345
+ (event: React.MouseEvent) => {
346
+ if (!state.dragging && event.buttons === 1) {
347
+ onDragStart();
348
+ document.addEventListener("mouseup", handleMouseUp);
349
+ }
350
+ },
351
+ [state, onDragStart, handleMouseUp]
352
+ );
353
+
354
+ const Cell = React.useMemo(() => {
355
+ // @ts-ignore
356
+ return enhanceCell(props.Cell || DefaultCell);
357
+ }, [props.Cell]);
358
+
359
+ const CornerIndicator = React.useMemo(
360
+ () =>
361
+ enhanceCornerIndicator(props.CornerIndicator || DefaultCornerIndicator),
362
+ [props.CornerIndicator]
363
+ );
364
+
365
+ const RowIndicator = React.useMemo(
366
+ () => enhanceRowIndicator(props.RowIndicator || DefaultRowIndicator),
367
+ [props.RowIndicator]
368
+ );
369
+
370
+ const ColumnIndicator = React.useMemo(
371
+ () =>
372
+ enhanceColumnIndicator(props.ColumnIndicator || DefaultColumnIndicator),
373
+ [props.ColumnIndicator]
374
+ );
375
+
376
+ React.useEffect(() => {
377
+ document.addEventListener("cut", handleCut);
378
+ document.addEventListener("copy", handleCopy);
379
+ document.addEventListener("paste", handlePaste);
380
+
381
+ return () => {
382
+ document.removeEventListener("cut", handleCut);
383
+ document.removeEventListener("copy", handleCopy);
384
+ document.removeEventListener("paste", handlePaste);
385
+ };
386
+ }, [handleCut, handleCopy, handlePaste]);
387
+
388
+ const tableNode = React.useMemo(
389
+ () => (
390
+ <Table columns={size.columns}>
391
+ <HeaderRow>
392
+ {<CornerIndicator />}
393
+ {
394
+ range(size.columns).map((columnNumber) =>
395
+ columnLabels ? (
396
+ <ColumnIndicator
397
+ key={columnNumber}
398
+ column={columnNumber}
399
+ label={
400
+ columnNumber in columnLabels
401
+ ? columnLabels[columnNumber]
402
+ : null
403
+ }
404
+ />
405
+ ) : (
406
+ <ColumnIndicator key={columnNumber} column={columnNumber} />
407
+ )
408
+ )}
409
+ </HeaderRow>
410
+ {range(size.rows).map((rowNumber) => (
411
+ <Row key={rowNumber} row={rowNumber}>
412
+ {
413
+ (rowLabels ? (
414
+ <RowIndicator
415
+ key={rowNumber}
416
+ row={rowNumber}
417
+ label={rowNumber in rowLabels ? rowLabels[rowNumber] : null}
418
+ />
419
+ ) : (
420
+ <RowIndicator key={rowNumber} row={rowNumber} />
421
+ ))}
422
+ {range(size.columns).map((columnNumber) => (
423
+ <Cell
424
+ key={columnNumber}
425
+ row={rowNumber}
426
+ column={columnNumber}
427
+ // @ts-ignore
428
+ DataViewer={DataViewer}
429
+ />
430
+ ))}
431
+ </Row>
432
+ ))}
433
+ </Table>
434
+ ),
435
+ [
436
+ Table,
437
+ size.rows,
438
+ size.columns,
439
+ Row,
440
+ HeaderRow,
441
+ CornerIndicator,
442
+ columnLabels,
443
+ ColumnIndicator,
444
+ rowLabels,
445
+ RowIndicator,
446
+ Cell,
447
+ DataViewer,
448
+ ]
449
+ );
450
+
451
+ const activeCellNode = React.useMemo(
452
+ () => (
453
+ <ActiveCell
454
+ // @ts-ignore
455
+ DataEditor={DataEditor}
456
+ />
457
+ ),
458
+ [DataEditor]
459
+ );
460
+
461
+ const rootNode = React.useMemo(
462
+ () => (
463
+ <div
464
+ ref={rootRef}
465
+ className={classNames("Spreadsheet", className, {
466
+ "Spreadsheet--dark-mode": darkMode,
467
+ })}
468
+ onKeyPress={onKeyPress}
469
+ onKeyDown={handleKeyDown}
470
+ onMouseMove={handleMouseMove}
471
+ >
472
+ {tableNode}
473
+ {activeCellNode}
474
+ <Selected />
475
+ <Copied />
476
+ </div>
477
+ ),
478
+ [
479
+ className,
480
+ darkMode,
481
+ onKeyPress,
482
+ handleKeyDown,
483
+ handleMouseMove,
484
+ tableNode,
485
+ activeCellNode,
486
+ ]
487
+ );
488
+
489
+ return (
490
+ <context.Provider value={reducerElements}>{rootNode}</context.Provider>
491
+ );
492
+ };
493
+
494
+ export default Spreadsheet;
@@ -0,0 +1,19 @@
1
+ import * as Types from "./types";
2
+ import { range } from "./util";
3
+
4
+ const Table: Types.TableComponent = ({
5
+ children,
6
+ columns,
7
+ hideColumnIndicators,
8
+ }) => {
9
+ const columnCount = columns + (hideColumnIndicators ? 0 : 1);
10
+ const columnNodes = range(columnCount).map((i) => <col key={i} />);
11
+ return (
12
+ <table className="Spreadsheet__table">
13
+ <colgroup>{columnNodes}</colgroup>
14
+ <tbody>{children}</tbody>
15
+ </table>
16
+ );
17
+ };
18
+
19
+ export default Table;