pixel-react 1.1.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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;