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,682 @@
1
+ import { PointRange } from "./point-range";
2
+ import * as Matrix from "./matrix";
3
+ import * as Types from "./types";
4
+ import * as Point from "./point";
5
+ import {
6
+ Selection,
7
+ EmptySelection,
8
+ RangeSelection,
9
+ EntireColumnsSelection,
10
+ EntireRowsSelection,
11
+ EntireWorksheetSelection,
12
+ } from "./selection";
13
+ import { isActive } from "./util";
14
+ import * as Actions from "./actions";
15
+ import { Model, updateCellValue, createFormulaParser } from "./engine";
16
+
17
+ export const INITIAL_STATE: Types.StoreState = {
18
+ active: null,
19
+ mode: "view",
20
+ rowDimensions: {},
21
+ columnDimensions: {},
22
+ lastChanged: null,
23
+ hasPasted: false,
24
+ cut: false,
25
+ dragging: false,
26
+ model: new Model(createFormulaParser, []),
27
+ selected: new EmptySelection(),
28
+ copied: null,
29
+ lastCommit: null,
30
+ };
31
+
32
+ export default function reducer(
33
+ state: Types.StoreState,
34
+ action: Actions.Action
35
+ ): Types.StoreState {
36
+ switch (action.type) {
37
+ case Actions.SET_DATA: {
38
+ const { data } = action.payload;
39
+ const nextActive =
40
+ state.active && Matrix.has(state.active, data) ? state.active : null;
41
+ const nextSelected = state.selected.normalizeTo(data);
42
+ return {
43
+ ...state,
44
+ model: new Model(state.model.createFormulaParser, data),
45
+ active: nextActive,
46
+ selected: nextSelected,
47
+ };
48
+ }
49
+ case Actions.SET_CREATE_FORMULA_PARSER: {
50
+ const { createFormulaParser } = action.payload;
51
+ return {
52
+ ...state,
53
+ model: new Model(createFormulaParser, state.model.data),
54
+ };
55
+ }
56
+ case Actions.SELECT_ENTIRE_ROW: {
57
+ const { row, extend } = action.payload;
58
+ const { active } = state;
59
+
60
+ return {
61
+ ...state,
62
+ selected:
63
+ extend && active
64
+ ? new EntireRowsSelection(active.row, row)
65
+ : new EntireRowsSelection(row, row),
66
+ active: extend && active ? active : { ...Point.ORIGIN, row },
67
+ mode: "view",
68
+ };
69
+ }
70
+ case Actions.SELECT_ENTIRE_COLUMN: {
71
+ const { column, extend } = action.payload;
72
+ const { active } = state;
73
+
74
+ return {
75
+ ...state,
76
+ selected:
77
+ extend && active
78
+ ? new EntireColumnsSelection(active.column, column)
79
+ : new EntireColumnsSelection(column, column),
80
+ active: extend && active ? active : { ...Point.ORIGIN, column },
81
+ mode: "view",
82
+ };
83
+ }
84
+ case Actions.SELECT_ENTIRE_WORKSHEET: {
85
+ return {
86
+ ...state,
87
+ selected: new EntireWorksheetSelection(),
88
+ active: Point.ORIGIN,
89
+ mode: "view",
90
+ };
91
+ }
92
+ case Actions.SET_SELECTION: {
93
+ const { selection } = action.payload;
94
+ const range = selection.toRange(state.model.data);
95
+ const active =
96
+ state.active && selection.has(state.model.data, state.active)
97
+ ? state.active
98
+ : range?.start;
99
+ return {
100
+ ...state,
101
+ selected: selection,
102
+ active: active || null,
103
+ mode: "view",
104
+ };
105
+ }
106
+ case Actions.SELECT: {
107
+ const { point } = action.payload;
108
+ if (state.active && !isActive(state.active, point)) {
109
+ return {
110
+ ...state,
111
+ selected: new RangeSelection(new PointRange(point, state.active)),
112
+ mode: "view",
113
+ };
114
+ }
115
+ return state;
116
+ }
117
+ case Actions.ACTIVATE: {
118
+ const { point } = action.payload;
119
+ return {
120
+ ...state,
121
+ selected: new RangeSelection(new PointRange(point, point)),
122
+ active: point,
123
+ mode: isActive(state.active, point) ? "edit" : "view",
124
+ };
125
+ }
126
+ case Actions.SET_CELL_DATA: {
127
+ const { active, data: cellData } = action.payload;
128
+ if (isActiveReadOnly(state)) {
129
+ return state;
130
+ }
131
+ return {
132
+ ...state,
133
+ model: updateCellValue(state.model, active, cellData),
134
+ lastChanged: active,
135
+ };
136
+ }
137
+ case Actions.SET_CELL_DIMENSIONS: {
138
+ const { point, dimensions } = action.payload;
139
+ const prevRowDimensions = state.rowDimensions[point.row];
140
+ const prevColumnDimensions = state.columnDimensions[point.column];
141
+ if (
142
+ prevRowDimensions &&
143
+ prevColumnDimensions &&
144
+ prevRowDimensions.top === dimensions.top &&
145
+ prevRowDimensions.height === dimensions.height &&
146
+ prevColumnDimensions.left === dimensions.left &&
147
+ prevColumnDimensions.width === dimensions.width
148
+ ) {
149
+ return state;
150
+ }
151
+ return {
152
+ ...state,
153
+ rowDimensions: {
154
+ ...state.rowDimensions,
155
+ [point.row]: { top: dimensions.top, height: dimensions.height },
156
+ },
157
+ columnDimensions: {
158
+ ...state.columnDimensions,
159
+ [point.column]: { left: dimensions.left, width: dimensions.width },
160
+ },
161
+ };
162
+ }
163
+ case Actions.COPY:
164
+ case Actions.CUT: {
165
+ const selectedRange = state.selected.toRange(state.model.data);
166
+ return {
167
+ ...state,
168
+ copied: selectedRange,
169
+ cut: action.type === Actions.CUT,
170
+ hasPasted: false,
171
+ };
172
+ }
173
+
174
+ case Actions.PASTE: {
175
+ const { data: text } = action.payload;
176
+ const { active } = state;
177
+
178
+ if (!active) {
179
+ return state;
180
+ }
181
+
182
+ const copied = Matrix.split(text, (value) => ({ value }));
183
+ const copiedSize = Matrix.getSize(copied);
184
+
185
+ const selectedRange = state.selected.toRange(state.model.data);
186
+ if (selectedRange && copiedSize.rows === 1 && copiedSize.columns === 1) {
187
+ const cell = Matrix.get({ row: 0, column: 0 }, copied);
188
+ let newData =
189
+ state.cut && state.copied
190
+ ? Matrix.unset(state.copied.start, state.model.data)
191
+ : state.model.data;
192
+ const commit: Types.StoreState["lastCommit"] = [];
193
+ for (const point of selectedRange || []) {
194
+ const currentCell = Matrix.get(point, state.model.data);
195
+ commit.push({
196
+ prevCell: currentCell || null,
197
+ nextCell: cell || null,
198
+ });
199
+ newData = Matrix.set(point, cell, newData);
200
+ }
201
+
202
+ return {
203
+ ...state,
204
+ model: new Model(createFormulaParser, newData),
205
+ copied: null,
206
+ cut: false,
207
+ hasPasted: true,
208
+ mode: "view",
209
+ lastCommit: commit,
210
+ };
211
+ }
212
+
213
+ const requiredSize: Matrix.Size = {
214
+ rows: active.row + copiedSize.rows,
215
+ columns: active.column + copiedSize.columns,
216
+ };
217
+ const paddedData = Matrix.pad(state.model.data, requiredSize);
218
+
219
+ let acc: {
220
+ data: Types.StoreState["model"]["data"];
221
+ commit: Types.StoreState["lastCommit"];
222
+ } = { data: paddedData, commit: [] };
223
+ for (const [point, cell] of Matrix.entries(copied)) {
224
+ let commit = acc.commit || [];
225
+ const nextPoint: Point.Point = {
226
+ row: point.row + active.row,
227
+ column: point.column + active.column,
228
+ };
229
+
230
+ let nextData = acc.data;
231
+
232
+ if (state.cut) {
233
+ if (state.copied) {
234
+ const prevPoint: Point.Point = {
235
+ row: point.row + state.copied.start.row,
236
+ column: point.column + state.copied.start.column,
237
+ };
238
+ nextData = Matrix.unset(prevPoint, acc.data);
239
+ }
240
+
241
+ commit = [...commit, { prevCell: cell || null, nextCell: null }];
242
+ }
243
+
244
+ if (!Matrix.has(nextPoint, paddedData)) {
245
+ acc = { data: nextData, commit };
246
+ }
247
+
248
+ const currentCell = Matrix.get(nextPoint, nextData) || null;
249
+
250
+ commit = [
251
+ ...commit,
252
+ {
253
+ prevCell: currentCell,
254
+ nextCell: cell || null,
255
+ },
256
+ ];
257
+
258
+ acc.data = Matrix.set(
259
+ nextPoint,
260
+ { value: undefined, ...currentCell, ...cell },
261
+ nextData
262
+ );
263
+ acc.commit = commit;
264
+ }
265
+
266
+ return {
267
+ ...state,
268
+ model: new Model(createFormulaParser, acc.data),
269
+ selected: new RangeSelection(
270
+ new PointRange(active, {
271
+ row: active.row + copiedSize.rows - 1,
272
+ column: active.column + copiedSize.columns - 1,
273
+ })
274
+ ),
275
+ copied: null,
276
+ cut: false,
277
+ hasPasted: true,
278
+ mode: "view",
279
+ lastCommit: acc.commit,
280
+ };
281
+ }
282
+
283
+ case Actions.EDIT: {
284
+ return edit(state);
285
+ }
286
+
287
+ case Actions.VIEW: {
288
+ return view(state);
289
+ }
290
+
291
+ case Actions.CLEAR: {
292
+ return clear(state);
293
+ }
294
+
295
+ case Actions.BLUR: {
296
+ return blur(state);
297
+ }
298
+
299
+ case Actions.KEY_PRESS: {
300
+ const { event } = action.payload;
301
+ if (isActiveReadOnly(state) || event.metaKey) {
302
+ return state;
303
+ }
304
+ if (state.mode === "view" && state.active) {
305
+ const selectedRange = state.selected.toRange(state.model.data);
306
+ if (selectedRange?.size() === 1) {
307
+ return edit(clear(state));
308
+ }
309
+ return edit(state);
310
+ }
311
+ return state;
312
+ }
313
+
314
+ case Actions.KEY_DOWN: {
315
+ const { event } = action.payload;
316
+ const handler = getKeyDownHandler(state, event);
317
+ if (handler) {
318
+ return { ...state, ...handler(state, event) };
319
+ }
320
+ return state;
321
+ }
322
+
323
+ case Actions.DRAG_START: {
324
+ return { ...state, dragging: true };
325
+ }
326
+
327
+ case Actions.DRAG_END: {
328
+ return { ...state, dragging: false };
329
+ }
330
+
331
+ case Actions.COMMIT: {
332
+ const { changes } = action.payload;
333
+ return { ...state, ...commit(changes) };
334
+ }
335
+
336
+ default:
337
+ throw new Error("Unknown action");
338
+ }
339
+ }
340
+
341
+ // const reducer = createReducer(INITIAL_STATE, (builder) => {
342
+ // builder.addMatcher(
343
+ // (action) =>
344
+ // action.type === Actions.copy.type || action.type === Actions.cut.type,
345
+ // (state, action) => {
346
+
347
+ // }
348
+ // );
349
+ // });
350
+
351
+ // // Shared reducers
352
+
353
+ function edit(state: Types.StoreState): Types.StoreState {
354
+ if (isActiveReadOnly(state)) {
355
+ return state;
356
+ }
357
+ return { ...state, mode: "edit" };
358
+ }
359
+
360
+ function clear(state: Types.StoreState): Types.StoreState {
361
+ if (!state.active) {
362
+ return state;
363
+ }
364
+
365
+ const canClearCell = (cell: Types.CellBase | undefined) =>
366
+ cell && !cell.readOnly;
367
+ const clearCell = (cell: Types.CellBase | undefined) => {
368
+ if (!canClearCell(cell)) {
369
+ return cell;
370
+ }
371
+ return Object.assign({}, cell, { value: undefined });
372
+ };
373
+
374
+ const selectedRange = state.selected.toRange(state.model.data);
375
+
376
+ const changes: Types.CommitChanges = [];
377
+ let newData = state.model.data;
378
+
379
+ for (const point of selectedRange || []) {
380
+ const cell = Matrix.get(point, state.model.data);
381
+ const clearedCell = clearCell(cell);
382
+ changes.push({
383
+ prevCell: cell || null,
384
+ nextCell: clearedCell || null,
385
+ });
386
+ newData = Matrix.set(point, clearedCell, newData);
387
+ }
388
+
389
+ return {
390
+ ...state,
391
+ model: new Model(createFormulaParser, newData),
392
+ ...commit(changes),
393
+ };
394
+ }
395
+
396
+ function blur(state: Types.StoreState): Types.StoreState {
397
+ return { ...state, active: null, selected: new EmptySelection() };
398
+ }
399
+
400
+ function view(state: Types.StoreState): Types.StoreState {
401
+ return { ...state, mode: "view" };
402
+ }
403
+
404
+ function commit(changes: Types.CommitChanges): Partial<Types.StoreState> {
405
+ return { lastCommit: changes };
406
+ }
407
+
408
+ // Utility
409
+
410
+ export const go =
411
+ (rowDelta: number, columnDelta: number): KeyDownHandler =>
412
+ (state) => {
413
+ if (!state.active) {
414
+ return;
415
+ }
416
+ const size = Matrix.getSize(state.model.data);
417
+ const newColumn = state.active.column + columnDelta;
418
+ const shouldWrap = newColumn >= size.columns;
419
+ const nextActive = {
420
+ row: state.active.row + rowDelta + (shouldWrap ? 1 : 0),
421
+ column: (state.active.column + columnDelta) % size.columns,
422
+ };
423
+ if (!Matrix.has(nextActive, state.model.data)) {
424
+ return { ...state, mode: "view" };
425
+ }
426
+ return {
427
+ ...state,
428
+ active: nextActive,
429
+ selected: new RangeSelection(new PointRange(nextActive, nextActive)),
430
+ mode: "view",
431
+ };
432
+ };
433
+
434
+ // Key Bindings
435
+
436
+ export type KeyDownHandler = (
437
+ state: Types.StoreState,
438
+ event: React.KeyboardEvent
439
+ ) => Types.StoreState | void;
440
+
441
+ type KeyDownHandlers = {
442
+ [K in string]: KeyDownHandler|undefined;
443
+ };
444
+
445
+ const keyDownHandlers: KeyDownHandlers = {
446
+ ArrowUp: go(-1, 0),
447
+ ArrowDown: go(+1, 0),
448
+ ArrowLeft: go(0, -1),
449
+ ArrowRight: go(0, +1),
450
+ Tab: go(0, +1),
451
+ Enter: edit,
452
+ Backspace: clear,
453
+ Delete: clear,
454
+ Escape: blur,
455
+ };
456
+
457
+ const editKeyDownHandlers: KeyDownHandlers = {
458
+ Escape: view,
459
+ Tab: keyDownHandlers.Tab,
460
+ Enter: keyDownHandlers.ArrowDown,
461
+ };
462
+
463
+ const editShiftKeyDownHandlers: KeyDownHandlers = {
464
+ Tab: go(0, -1),
465
+ };
466
+
467
+ export enum Direction {
468
+ Left = "Left",
469
+ Right = "Right",
470
+ Top = "Top",
471
+ Bottom = "Bottom",
472
+ }
473
+
474
+ const shiftKeyDownHandlers: KeyDownHandlers = {
475
+ ArrowUp: (state) => ({
476
+ ...state,
477
+ selected: modifyEdge(
478
+ state.selected,
479
+ state.active,
480
+ state.model.data,
481
+ Direction.Top
482
+ ),
483
+ }),
484
+ ArrowDown: (state) => ({
485
+ ...state,
486
+ selected: modifyEdge(
487
+ state.selected,
488
+ state.active,
489
+ state.model.data,
490
+ Direction.Bottom
491
+ ),
492
+ }),
493
+ ArrowLeft: (state) => ({
494
+ ...state,
495
+ selected: modifyEdge(
496
+ state.selected,
497
+ state.active,
498
+ state.model.data,
499
+ Direction.Left
500
+ ),
501
+ }),
502
+ ArrowRight: (state) => ({
503
+ ...state,
504
+ selected: modifyEdge(
505
+ state.selected,
506
+ state.active,
507
+ state.model.data,
508
+ Direction.Right
509
+ ),
510
+ }),
511
+ Tab: go(0, -1),
512
+ };
513
+
514
+ const shiftMetaKeyDownHandlers: KeyDownHandlers = {};
515
+ const metaKeyDownHandlers: KeyDownHandlers = {};
516
+
517
+ export function getKeyDownHandler(
518
+ state: Types.StoreState,
519
+ event: React.KeyboardEvent
520
+ ): KeyDownHandler | undefined {
521
+ const { key } = event;
522
+ let handlers;
523
+ // Order matters
524
+ if (state.mode === "edit") {
525
+ if (event.shiftKey) {
526
+ handlers = editShiftKeyDownHandlers;
527
+ } else {
528
+ handlers = editKeyDownHandlers;
529
+ }
530
+ } else if (event.shiftKey && event.metaKey) {
531
+ handlers = shiftMetaKeyDownHandlers;
532
+ } else if (event.shiftKey) {
533
+ handlers = shiftKeyDownHandlers;
534
+ } else if (event.metaKey) {
535
+ handlers = metaKeyDownHandlers;
536
+ } else {
537
+ handlers = keyDownHandlers;
538
+ }
539
+
540
+ return handlers[key];
541
+ }
542
+
543
+ /** Returns whether the reducer has a handler for the given keydown event */
544
+ export function hasKeyDownHandler(
545
+ state: Types.StoreState,
546
+ event: React.KeyboardEvent
547
+ ): boolean {
548
+ return getKeyDownHandler(state, event) !== undefined;
549
+ }
550
+
551
+ /** Returns whether the active cell is read only */
552
+ export function isActiveReadOnly(state: Types.StoreState): boolean {
553
+ const activeCell = getActive(state);
554
+ return Boolean(activeCell?.readOnly);
555
+ }
556
+
557
+ /** Gets active cell from given state */
558
+ export function getActive(state: Types.StoreState): Types.CellBase | null {
559
+ const activeCell = state.active && Matrix.get(state.active, state.model.data);
560
+ return activeCell || null;
561
+ }
562
+
563
+ /** Modify given edge according to given active point and data */
564
+ export function modifyEdge<T extends Selection>(
565
+ selection: T,
566
+ active: Point.Point | null,
567
+ data: Matrix.Matrix<unknown>,
568
+ direction: Direction
569
+ ): T {
570
+ if (!active) {
571
+ return selection;
572
+ }
573
+ if (selection instanceof RangeSelection) {
574
+ const nextSelection = modifyRangeSelectionEdge(
575
+ selection,
576
+ active,
577
+ data,
578
+ direction
579
+ );
580
+ // @ts-expect-error
581
+ return nextSelection;
582
+ }
583
+ if (selection instanceof EntireColumnsSelection) {
584
+ // @ts-expect-error
585
+ return modifyEntireColumnsSelection(selection, active, data, direction);
586
+ }
587
+ if (selection instanceof EntireRowsSelection) {
588
+ // @ts-expect-error
589
+ return modifyEntireRowsSelection(selection, active, data, direction);
590
+ }
591
+ return selection;
592
+ }
593
+
594
+ export function modifyRangeSelectionEdge(
595
+ rangeSelection: RangeSelection,
596
+ active: Point.Point,
597
+ data: Matrix.Matrix<unknown>,
598
+ edge: Direction
599
+ ): RangeSelection {
600
+ const field =
601
+ edge === Direction.Left || edge === Direction.Right ? "column" : "row";
602
+
603
+ const key =
604
+ edge === Direction.Left || edge === Direction.Top ? "start" : "end";
605
+ const delta = key === "start" ? -1 : 1;
606
+
607
+ const edgeOffsets = rangeSelection.range.has({
608
+ ...active,
609
+ [field]: active[field] + delta * -1,
610
+ });
611
+
612
+ const keyToModify = edgeOffsets ? (key === "start" ? "end" : "start") : key;
613
+
614
+ const nextRange = new PointRange(
615
+ rangeSelection.range.start,
616
+ rangeSelection.range.end
617
+ );
618
+
619
+ nextRange[keyToModify][field] += delta;
620
+
621
+ const nextSelection = new RangeSelection(nextRange).normalizeTo(data);
622
+
623
+ return nextSelection;
624
+ }
625
+
626
+ export function modifyEntireRowsSelection(
627
+ selection: EntireRowsSelection,
628
+ active: Point.Point,
629
+ data: Matrix.Matrix<unknown>,
630
+ edge: Direction
631
+ ): EntireRowsSelection {
632
+ if (edge === Direction.Left || edge === Direction.Right) {
633
+ return selection;
634
+ }
635
+ const delta = edge === Direction.Top ? -1 : 1;
636
+ const property = edge === Direction.Top ? "start" : "end";
637
+ const oppositeProperty = property === "start" ? "end" : "start";
638
+ const newSelectionData = { ...selection };
639
+ if (
640
+ edge === Direction.Top
641
+ ? selection.end > active.row
642
+ : selection.start < active.row
643
+ ) {
644
+ newSelectionData[oppositeProperty] = selection[oppositeProperty] + delta;
645
+ } else {
646
+ newSelectionData[property] = selection[property] + delta;
647
+ }
648
+ const nextSelection = new EntireRowsSelection(
649
+ Math.max(newSelectionData.start, 0),
650
+ Math.max(newSelectionData.end, 0)
651
+ );
652
+ return nextSelection.normalizeTo(data);
653
+ }
654
+
655
+ export function modifyEntireColumnsSelection(
656
+ selection: EntireColumnsSelection,
657
+ active: Point.Point,
658
+ data: Matrix.Matrix<unknown>,
659
+ edge: Direction
660
+ ): EntireColumnsSelection {
661
+ if (edge === Direction.Top || edge === Direction.Bottom) {
662
+ return selection;
663
+ }
664
+ const delta = edge === Direction.Left ? -1 : 1;
665
+ const property = edge === Direction.Left ? "start" : "end";
666
+ const oppositeProperty = property === "start" ? "end" : "start";
667
+ const newSelectionData = { ...selection };
668
+ if (
669
+ edge === Direction.Left
670
+ ? selection.end > active.row
671
+ : selection.start < active.row
672
+ ) {
673
+ newSelectionData[oppositeProperty] = selection[oppositeProperty] + delta;
674
+ } else {
675
+ newSelectionData[property] = selection[property] + delta;
676
+ }
677
+ const nextSelection = new EntireColumnsSelection(
678
+ Math.max(newSelectionData.start, 0),
679
+ Math.max(newSelectionData.end, 0)
680
+ );
681
+ return nextSelection.normalizeTo(data);
682
+ }