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,154 @@
1
+ import { Point } from "../point";
2
+ import * as pointHash from "./point-hash";
3
+ import { PointSet } from "./point-set";
4
+
5
+ /**
6
+ * Immutable directed graph of points, where each point can have multiple
7
+ * edges to other points.
8
+ */
9
+ export class PointGraph {
10
+ private constructor(private forwards = new Map<string, PointSet>()) {}
11
+
12
+ /** Creates a new PointGraph instance from an array-like or iterable object */
13
+ static from(pairs: Iterable<[Point, PointSet]>): PointGraph {
14
+ const forwards = new Map<string, PointSet>();
15
+ for (const [node, edges] of pairs) {
16
+ forwards.set(pointHash.toString(node), edges);
17
+ }
18
+ return new PointGraph(forwards);
19
+ }
20
+
21
+ set(node: Point, edges: PointSet): PointGraph {
22
+ const newGraph = new PointGraph(new Map(this.forwards));
23
+ if (edges.size === 0) {
24
+ newGraph.forwards.delete(pointHash.toString(node));
25
+ return newGraph;
26
+ }
27
+ newGraph.forwards.set(pointHash.toString(node), edges);
28
+ return newGraph;
29
+ }
30
+
31
+ get(node: Point): PointSet {
32
+ return this.forwards.get(pointHash.toString(node)) || PointSet.from([]);
33
+ }
34
+
35
+ getBackwards(node: Point): PointSet {
36
+ let result = PointSet.from([]);
37
+ for (const [key, value] of this.forwards) {
38
+ if (value.has(node)) {
39
+ result = result.add(pointHash.fromString(key));
40
+ }
41
+ }
42
+ return result;
43
+ }
44
+
45
+ getBackwardsRecursive(
46
+ node: Point,
47
+ visited: PointSet = PointSet.from([])
48
+ ): PointSet {
49
+ let result = this.getBackwards(node);
50
+ let newVisited = visited;
51
+ for (const point of result) {
52
+ if (newVisited.has(point)) {
53
+ continue;
54
+ }
55
+ newVisited = newVisited.add(point);
56
+ result = result.union(this.getBackwardsRecursive(point, newVisited));
57
+ }
58
+ return result;
59
+ }
60
+
61
+ /** Determine whether the graph has a circular dependency, starting from given start point */
62
+ hasCircularDependency(startPoint: Point): boolean {
63
+ let visited = PointSet.from([]);
64
+ const stack: Point[] = [startPoint];
65
+
66
+ while (stack.length > 0) {
67
+ const current = stack.pop();
68
+ if (!current) {
69
+ continue;
70
+ }
71
+
72
+ if (visited.has(current)) {
73
+ return true;
74
+ }
75
+
76
+ visited = visited.add(current);
77
+
78
+ const dependents = this.get(current);
79
+
80
+ if (!dependents) {
81
+ continue;
82
+ }
83
+
84
+ for (const dependent of dependents) {
85
+ stack.push(dependent);
86
+ }
87
+ }
88
+
89
+ return false;
90
+ }
91
+
92
+ *[Symbol.iterator](): Iterator<[Point, PointSet]> {
93
+ const visitedHashes = new Set<string>();
94
+ for (const [key, values] of this.forwards) {
95
+ const point = pointHash.fromString(key);
96
+ visitedHashes.add(key);
97
+ yield [point, values];
98
+
99
+ // Make sure to include values that are not included in the forwards map keys
100
+ for (const value of values) {
101
+ const hash = pointHash.toString(value);
102
+ if (!visitedHashes.has(hash) && !this.forwards.has(hash)) {
103
+ visitedHashes.add(hash);
104
+ yield [value, PointSet.from([])];
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ /** Get the points in the graph in a breadth-first order */
111
+ *traverseBFSBackwards(): Generator<Point> {
112
+ // Create a Set to store the points that have been visited
113
+ let visited = PointSet.from([]);
114
+
115
+ // Create a queue to store the points that still need to be visited
116
+ const queue: Point[] = [];
117
+
118
+ // Iterate over all the points and add the ones with no dependencies to the queue
119
+ for (const [point, values] of this) {
120
+ if (values.size === 0) {
121
+ visited = visited.add(point);
122
+ queue.push(point);
123
+ }
124
+ }
125
+
126
+ // While there are points in the queue, remove the first one and yield it
127
+ while (queue.length > 0) {
128
+ const point = queue.shift();
129
+ if (!point) {
130
+ continue;
131
+ }
132
+ yield point;
133
+
134
+ // Get the set of points that depend on the current point
135
+ const dependents = this.getBackwards(point);
136
+
137
+ // If there are no dependents, skip to the next iteration
138
+ if (dependents.size === 0) {
139
+ continue;
140
+ }
141
+
142
+ // Otherwise, add the dependents to the queue if they have not yet been visited
143
+ for (const dependent of dependents) {
144
+ if (
145
+ !visited.has(dependent) &&
146
+ this.get(dependent).difference(visited).size === 0
147
+ ) {
148
+ queue.push(dependent);
149
+ visited = visited.add(dependent);
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
@@ -0,0 +1,10 @@
1
+ import { Point } from "../point";
2
+
3
+ export function toString(point: Point): string {
4
+ return `${point.row},${point.column}`;
5
+ }
6
+
7
+ export function fromString(point: string): Point {
8
+ const [row, column] = point.split(",");
9
+ return { row: Number(row), column: Number(column) };
10
+ }
@@ -0,0 +1,69 @@
1
+ import * as Point from "../point";
2
+ import * as pointHash from "./point-hash";
3
+
4
+ /**
5
+ * Immutable Set like interface of points
6
+ */
7
+ export class PointSet {
8
+ private constructor(private set: Set<string>) {}
9
+
10
+ /** Creates a new PointSet instance from an array-like or iterable object */
11
+ static from(points: Iterable<Point.Point>): PointSet {
12
+ const set = new Set<string>();
13
+ for (const point of points) {
14
+ set.add(pointHash.toString(point));
15
+ }
16
+ return new PointSet(set);
17
+ }
18
+
19
+ /** Returns a boolean asserting whether an point is present with the given value in the Set object or not */
20
+ has(point: Point.Point): boolean {
21
+ return this.set.has(pointHash.toString(point));
22
+ }
23
+
24
+ /** Returns the number of points in a PointSet object */
25
+ get size(): number {
26
+ return this.set.size;
27
+ }
28
+
29
+ /** Add the given point to given set */
30
+ add(point: Point.Point): PointSet {
31
+ const newSet = new Set(this.set);
32
+ newSet.add(pointHash.toString(point));
33
+ return new PointSet(newSet);
34
+ }
35
+
36
+ /** Remove the given point from the given set */
37
+ delete(point: Point.Point): PointSet {
38
+ const newSet = new Set(this.set);
39
+ if (!newSet.delete(pointHash.toString(point))) {
40
+ return this;
41
+ }
42
+ return new PointSet(newSet);
43
+ }
44
+
45
+ /** Returns a new PointSet with points common to the set and other */
46
+ difference(other: PointSet): PointSet {
47
+ let newSet = this as PointSet;
48
+ for (const point of other) {
49
+ newSet = newSet.delete(point);
50
+ }
51
+ return newSet;
52
+ }
53
+
54
+ /** Returns a new PointSet with all points in both sets */
55
+ union(other: PointSet): PointSet {
56
+ let newSet = this as PointSet;
57
+ for (const point of other) {
58
+ newSet = newSet.add(point);
59
+ }
60
+ return newSet;
61
+ }
62
+
63
+ /** Creates an iterator of points in the set */
64
+ *[Symbol.iterator](): Iterator<Point.Point> {
65
+ for (const value of this.set) {
66
+ yield pointHash.fromString(value);
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,48 @@
1
+ import Spreadsheet from "./Spreadsheet";
2
+ import DataEditor from "./DataEditor";
3
+ import DataViewer from "./DataViewer";
4
+
5
+ export default Spreadsheet;
6
+ export { Spreadsheet, DataEditor, DataViewer };
7
+ export type { Props } from "./Spreadsheet";
8
+ export { createEmpty as createEmptyMatrix } from "./matrix";
9
+ export type { Matrix } from "./matrix";
10
+ export {
11
+ Selection,
12
+ EmptySelection,
13
+ EntireAxisSelection,
14
+ EntireColumnsSelection,
15
+ EntireRowsSelection,
16
+ EntireSelection,
17
+ EntireWorksheetSelection,
18
+ InvalidIndexError,
19
+ RangeSelection,
20
+ } from "./selection";
21
+ export { PointRange } from "./point-range";
22
+ export type { Point } from "./point";
23
+ export type {
24
+ CellBase,
25
+ CellDescriptor,
26
+ Mode,
27
+ Dimensions,
28
+ CellChange,
29
+ CellComponentProps,
30
+ CellComponent,
31
+ DataViewerProps,
32
+ DataViewerComponent,
33
+ DataEditorProps,
34
+ DataEditorComponent,
35
+ ColumnIndicatorComponent,
36
+ ColumnIndicatorProps,
37
+ RowIndicatorComponent,
38
+ RowIndicatorProps,
39
+ CornerIndicatorComponent,
40
+ CornerIndicatorProps,
41
+ RowComponent,
42
+ RowProps,
43
+ TableComponent,
44
+ TableProps,
45
+ HeaderRowProps,
46
+ HeaderRowComponent,
47
+ } from "./types";
48
+ export { createFormulaParser, Model } from "./engine";
@@ -0,0 +1,388 @@
1
+ import * as Point from "./point";
2
+
3
+ /** A two-dimensional array of given type T in rows and columns */
4
+ export type Matrix<T> = Array<Array<T | undefined>>;
5
+
6
+ /**
7
+ * Creates an empty matrix with given rows and columns
8
+ * @param rows - integer, the amount of rows the matrix should have
9
+ * @param columns - integer, the amount of columns the matrix should have
10
+ * @returns an empty matrix with given rows and columns
11
+ */
12
+ export function createEmpty<T>(rows: number, columns: number): Matrix<T> {
13
+ const matrix = Array(rows);
14
+ for (let i = 0; i < rows; i++) {
15
+ matrix[i] = Array(columns);
16
+ }
17
+ return matrix;
18
+ }
19
+
20
+ /** Gets the value at row and column of matrix. */
21
+ export function get<T>(point: Point.Point, matrix: Matrix<T>): T | undefined {
22
+ const columns = matrix[point.row];
23
+ if (columns === undefined) {
24
+ return undefined;
25
+ }
26
+ return columns[point.column];
27
+ }
28
+
29
+ /** Creates a slice of matrix from startPoint up to, but not including, endPoint. */
30
+ export function slice<T>(
31
+ startPoint: Point.Point,
32
+ endPoint: Point.Point,
33
+ matrix: Matrix<T>
34
+ ): Matrix<T> {
35
+ const sliced: Matrix<T> = [];
36
+ const columns = endPoint.column - startPoint.column;
37
+ for (let row = startPoint.row; row <= endPoint.row; row++) {
38
+ const slicedRow = row - startPoint.row;
39
+ sliced[slicedRow] = sliced[slicedRow] || Array(columns);
40
+ for (let column = startPoint.column; column <= endPoint.column; column++) {
41
+ sliced[slicedRow][column - startPoint.column] = get(
42
+ { row, column },
43
+ matrix
44
+ );
45
+ }
46
+ }
47
+ return sliced;
48
+ }
49
+
50
+ /** Sets the value at row and column of matrix. If a row doesn't exist, it's created. */
51
+
52
+ export function set<T>(
53
+ point: Point.Point,
54
+ value: T,
55
+ matrix: Matrix<T>
56
+ ): Matrix<T> {
57
+ // Create a shallow copy of the matrix
58
+ const nextMatrix = [...matrix];
59
+
60
+ // Ensure the first row exists (initialize if undefined)
61
+ const firstRow = matrix[0] ?? [];
62
+ const nextFirstRow = [...firstRow];
63
+
64
+ // Ensure the first row has enough columns to accommodate the specified column
65
+ if (nextFirstRow.length <= point.column) {
66
+ nextFirstRow.length = point.column + 1; // Extend the first row if needed
67
+ }
68
+
69
+ // Set the modified first row back into the matrix
70
+ nextMatrix[0] = nextFirstRow;
71
+
72
+ // Ensure the specified row exists (initialize if undefined)
73
+ const nextRow = matrix[point.row] ?? [];
74
+ const nextRowCopy = [...nextRow];
75
+
76
+ // Set the value at the specified point
77
+ nextRowCopy[point.column] = value;
78
+
79
+ // Set the modified row back into the matrix
80
+ nextMatrix[point.row] = nextRowCopy;
81
+
82
+ return nextMatrix;
83
+ }
84
+
85
+
86
+ /** Like Matrix.set() but mutates the matrix */
87
+
88
+
89
+ export function mutableSet<T>(
90
+ point: Point.Point,
91
+ value: T,
92
+ matrix: Matrix<T>
93
+ ): void {
94
+ // Ensure that the first row exists, if not, create it
95
+ let firstRow = matrix[0];
96
+ if (!firstRow) {
97
+ firstRow = [];
98
+ matrix[0] = firstRow;
99
+ }
100
+
101
+ // Ensure the row at point.row exists, if not, create it
102
+ let row = matrix[point.row];
103
+ if (!row) {
104
+ row = [];
105
+ matrix[point.row] = row;
106
+ }
107
+
108
+ // Ensure that the first row has enough columns
109
+ if (firstRow.length <= point.column) {
110
+ firstRow.length = point.column + 1; // Extend the first row if needed
111
+ }
112
+
113
+ // Set the value at the specified point
114
+ row[point.column] = value;
115
+ }
116
+
117
+
118
+
119
+ /** Removes the coordinate of matrix */
120
+ // export function unset<T>(point: Point.Point, matrix: Matrix<T>): Matrix<T> {
121
+ // if (!has(point, matrix)) {
122
+ // return matrix;
123
+ // }
124
+ // const nextMatrix = [...matrix];
125
+ // const nextRow = [...matrix[point.row]];
126
+
127
+ // // Avoid deleting to preserve first row length
128
+ // nextRow[point.column] = undefined;
129
+ // nextMatrix[point.row] = nextRow;
130
+
131
+ // return nextMatrix;
132
+ // }
133
+
134
+ export function unset<T>(point: Point.Point, matrix: Matrix<T>): Matrix<T> {
135
+ // Check if the point exists in the matrix
136
+ if (!has(point, matrix)) {
137
+ return matrix;
138
+ }
139
+
140
+ // Create a shallow copy of the matrix
141
+ const nextMatrix = [...matrix];
142
+
143
+ // Check if the row exists before trying to copy it
144
+ const currentRow = matrix[point.row];
145
+ if (currentRow) {
146
+ // Create a shallow copy of the row
147
+ const nextRow = [...currentRow];
148
+ // Avoid deleting to preserve first row length
149
+ nextRow[point.column] = undefined;
150
+
151
+ // Update the matrix with the modified row
152
+ nextMatrix[point.row] = nextRow;
153
+ }
154
+
155
+ return nextMatrix;
156
+ }
157
+
158
+
159
+ /** Creates an array of values by running each element in collection thru iteratee. */
160
+ export function map<T, T2>(
161
+ func: (value: T | undefined, point: Point.Point) => T2,
162
+ matrix: Matrix<T>
163
+ ): Matrix<T2> {
164
+ const newMatrix: Matrix<T2> = [];
165
+ for (const [point, value] of entries(matrix)) {
166
+ mutableSet(point, func(value, point), newMatrix);
167
+ }
168
+ return newMatrix;
169
+ }
170
+
171
+ /** Create an iterator over the cells in the matrix */
172
+ export function* entries<T>(
173
+ matrix: Matrix<T>
174
+ ): IterableIterator<[Point.Point, T | undefined]> {
175
+ for (const [row, values] of matrix.entries()) {
176
+ for (const [column, value] of values.entries()) {
177
+ const point = { row, column };
178
+ yield [point, value];
179
+ }
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Converts all elements in row into a string separated by horizontalSeparator and each row string
185
+ * to string separated by verticalSeparator
186
+ */
187
+
188
+ export function join(
189
+ matrix: Matrix<unknown>,
190
+ horizontalSeparator = "\t",
191
+ verticalSeparator = "\n"
192
+ ): string {
193
+ let joined = "";
194
+ const { rows, columns } = getSize(matrix);
195
+
196
+ for (let row = 0; row < rows; row++) {
197
+ if (row) {
198
+ joined += verticalSeparator;
199
+ }
200
+
201
+ for (let column = 0; column < columns; column++) {
202
+ if (column) {
203
+ joined += horizontalSeparator;
204
+ }
205
+
206
+ // Ensure matrix[row] exists and matrix[row][column] is not undefined
207
+ const cellValue = matrix[row]?.[column];
208
+
209
+ // If cellValue is undefined, you can use a fallback value like an empty string
210
+ joined += cellValue !== undefined ? String(cellValue) : "";
211
+ }
212
+ }
213
+
214
+ return joined;
215
+ }
216
+
217
+
218
+ /**
219
+ * Parses a CSV separated by a horizontalSeparator and verticalSeparator into a
220
+ * Matrix using a transform function
221
+ */
222
+ export function split<T>(
223
+ csv: string,
224
+ transform: (value: string) => T,
225
+ horizontalSeparator = "\t",
226
+ verticalSeparator: string | RegExp = /\r\n|\n|\r/
227
+ ): Matrix<T> {
228
+ // Temporarily replace line breaks inside quotes
229
+ const replaced = csv.replace(/"([^"]*?)"/g, (_, p1) => {
230
+ return p1.replace(/\n/g, "\\n");
231
+ });
232
+ return replaced.split(verticalSeparator).map((row) =>
233
+ row
234
+ .split(horizontalSeparator)
235
+ .map((line) => {
236
+ // Restore original line breaks in each line
237
+ return line.replace(/\\n/g, "\n");
238
+ })
239
+ .map(transform)
240
+ );
241
+ }
242
+
243
+ /** Returns whether the point exists in the matrix or not. */
244
+ export function has(point: Point.Point, matrix: Matrix<unknown>): boolean {
245
+ const firstRow = matrix[0];
246
+ if (!firstRow) {
247
+ return false; // If first row is undefined, return false
248
+ }
249
+
250
+ // Perform validation checks
251
+ return (
252
+ point.row >= 0 &&
253
+ point.column >= 0 &&
254
+ Number.isInteger(point.row) &&
255
+ Number.isInteger(point.column) &&
256
+ point.column < firstRow.length &&
257
+ point.row < matrix.length
258
+ );
259
+ }
260
+
261
+
262
+ /** Counts of the rows and column in a matrix */
263
+ export type Size = {
264
+ /** Count of the rows in the matrix */
265
+ rows: number;
266
+ /** Count of the columns in the matrix */
267
+ columns: number;
268
+ };
269
+
270
+ /** Gets the count of rows and columns of given matrix */
271
+ export function getSize(matrix: Matrix<unknown>): Size {
272
+ return {
273
+ columns: getColumnsCount(matrix),
274
+ rows: getRowsCount(matrix),
275
+ };
276
+ }
277
+
278
+ /** Gets the count of rows of given matrix */
279
+ export function getRowsCount(matrix: Matrix<unknown>): number {
280
+ return matrix.length;
281
+ }
282
+
283
+ /** Gets the count of columns of given matrix */
284
+ export function getColumnsCount(matrix: Matrix<unknown>): number {
285
+ const firstRow = matrix[0];
286
+ return firstRow ? firstRow.length : 0;
287
+ }
288
+
289
+ /**
290
+ * Pads matrix with empty rows to match given total rows
291
+ * @param matrix - matrix to pad
292
+ * @param totalRows - number of rows the matrix should have
293
+ * @returns the updated matrix
294
+ */
295
+ export function padRows<T>(matrix: Matrix<T>, totalRows: number): Matrix<T> {
296
+ const { rows, columns } = getSize(matrix);
297
+
298
+ if (rows >= totalRows) {
299
+ return matrix;
300
+ }
301
+
302
+ const missingRows = totalRows - rows;
303
+ const emptyRow = Array(columns).fill(undefined);
304
+ const emptyRows = Array(missingRows).fill(emptyRow);
305
+ return [...matrix, ...emptyRows];
306
+ }
307
+
308
+ /**
309
+ * Pads matrix with empty columns to match given total columns
310
+ * @param matrix - matrix to pad
311
+ * @param size - minimum size of the matrix after padding.
312
+ * @returns the updated matrix
313
+ */
314
+ export function pad<T>(matrix: Matrix<T>, size: Size): Matrix<T> {
315
+ const { rows, columns } = getSize(matrix);
316
+
317
+ if (rows >= size.rows && columns >= size.columns) {
318
+ // Optimization, no padding required.
319
+ return matrix;
320
+ }
321
+
322
+ const resultSize: Size = {
323
+ rows: size.rows > rows ? size.rows : rows,
324
+ columns: size.columns > columns ? size.columns : columns,
325
+ };
326
+
327
+ let padded = [...matrix];
328
+ if (resultSize.columns > columns) {
329
+ const padColumns = resultSize.columns - columns;
330
+ padded = padded.map((row) => [
331
+ ...row,
332
+ ...Array(padColumns).fill(undefined),
333
+ ]);
334
+ }
335
+
336
+ if (resultSize.rows > rows) {
337
+ const padRows = resultSize.rows - rows;
338
+ const emptyRow = Array(resultSize.columns).fill(undefined);
339
+ padded = [...padded, ...Array(padRows).fill(emptyRow)];
340
+ }
341
+
342
+ return padded;
343
+ }
344
+
345
+ export function toArray<T>(matrix: Matrix<T>): T[];
346
+ export function toArray<T1, T2>(
347
+ matrix: Matrix<T1>,
348
+ transform: (cell: T1 | undefined, coords: Point.Point) => T2
349
+ ): T2[];
350
+
351
+ /**
352
+ * Flattens a matrix values to an array
353
+ * @param matrix - the matrix to flatten values from
354
+ * @param transform - optional transform function to apply to each value in the
355
+ * matrix
356
+ * @returns an array of the values from matrix, transformed if a transform
357
+ * function is passed
358
+ */
359
+ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
360
+
361
+ export function toArray<T1, T2>(
362
+ matrix: Matrix<T1>,
363
+ transform?: (cell: T1 | undefined, coords: Point.Point) => T2
364
+ ): T2[] {
365
+ const array: T2[] = [];
366
+
367
+ for (let row = 0; row < matrix.length; row++) {
368
+ const currentRow = matrix[row];
369
+
370
+ // Ensure the row is not undefined
371
+ if (currentRow !== undefined) {
372
+ for (let column = 0; column < currentRow.length; column++) {
373
+ const value = currentRow[column];
374
+ // If transform is provided, apply it; otherwise, use the value as is
375
+ array.push(transform ? transform(value, { row, column }) : value as T2);
376
+ }
377
+ }
378
+ }
379
+
380
+ return array;
381
+ }
382
+
383
+
384
+ /** Returns the maximum point in the matrix */
385
+ export function maxPoint(matrix: Matrix<unknown>): Point.Point {
386
+ const size = getSize(matrix);
387
+ return { row: size.rows - 1, column: size.columns - 1 };
388
+ }