efficient-shell 4.134.0 → 4.137.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/LICENSE +6 -17
  2. package/README.md +84 -8
  3. package/dist/Browser-ZX5OTOKK.js +43 -0
  4. package/dist/Calculator-4SQGOQFQ.js +29 -0
  5. package/dist/ConfirmDialog-NPKW2XHM.js +1 -0
  6. package/dist/CurrencyConverter-2KOM7L6V.js +21 -0
  7. package/dist/Documents-IZTIQYPG.js +52 -0
  8. package/dist/Files-B63KKXGZ.js +89 -0
  9. package/dist/Notepad-WA77V45J.js +25 -0
  10. package/dist/PdfViewer-RBRGEKWF.js +1 -0
  11. package/dist/PomodoroTimer-SDUBKXUS.js +99 -0
  12. package/dist/Preview-D4KOA4OI.js +187 -0
  13. package/dist/Sidebar-Y57LYXXI.js +23 -0
  14. package/dist/Spreadsheet-JX5E6WH6.js +37 -0
  15. package/dist/Stock-XAQ5WMUZ.js +16 -0
  16. package/dist/Weather-HLAGJ5LV.js +60 -0
  17. package/dist/WorldClock-IRI4VCTA.js +32 -0
  18. package/dist/apps/index.js +1 -151
  19. package/dist/brand.css +1 -1
  20. package/dist/chunk-3A46NCXK.js +29 -0
  21. package/dist/chunk-44UO7FYU.js +11 -0
  22. package/dist/chunk-466CM2TJ.js +1 -0
  23. package/dist/chunk-57MIENLJ.js +1 -0
  24. package/dist/chunk-5CRAF2AD.js +2 -0
  25. package/dist/chunk-A2OQLLYK.js +6 -0
  26. package/dist/chunk-B43AGQET.js +4 -0
  27. package/dist/chunk-BR22X7E5.js +1 -0
  28. package/dist/chunk-BUTSU7FO.js +1 -0
  29. package/dist/chunk-D65T4H6J.js +1 -0
  30. package/dist/chunk-ESL5TDNA.js +1 -0
  31. package/dist/chunk-FBDZGO3V.js +1 -0
  32. package/dist/chunk-FHTLC7HH.js +1 -0
  33. package/dist/chunk-FQLMX3IE.js +948 -0
  34. package/dist/chunk-H562R4GX.js +34 -0
  35. package/dist/chunk-JN4WXTWJ.js +106 -0
  36. package/dist/chunk-LVDRBRYU.js +1 -0
  37. package/dist/chunk-LWLCNQY7.js +1 -0
  38. package/dist/chunk-MAIHBBWT.js +1 -0
  39. package/dist/chunk-NPJH5MD7.js +13 -0
  40. package/dist/chunk-OCSOMMY2.js +1 -0
  41. package/dist/chunk-OQDWLHZI.js +1 -0
  42. package/dist/chunk-OWSAMA3I.js +23 -0
  43. package/dist/chunk-PH3PRIFP.js +5 -0
  44. package/dist/chunk-TAWKWSPN.js +9 -0
  45. package/dist/chunk-U4GTZPXP.js +1 -0
  46. package/dist/chunk-UB4JIOLD.js +2 -0
  47. package/dist/chunk-UZAJ5BF6.js +9 -0
  48. package/dist/chunk-VEGMDXT4.js +1 -0
  49. package/dist/chunk-VTVSMRFX.js +1 -0
  50. package/dist/chunk-VVAGSKW7.js +1 -0
  51. package/dist/chunk-XO43FJRM.js +19 -0
  52. package/dist/chunk-Y7BOLDRM.js +69 -0
  53. package/dist/file-intake/index.js +1 -4
  54. package/dist/{index-DZ7E7bCl.d.ts → index-DVI9DMSu.d.ts} +189 -18
  55. package/dist/index.d.ts +2 -2
  56. package/dist/index.js +639 -7473
  57. package/dist/map/index.js +20 -540
  58. package/dist/markdown/index.js +6 -184
  59. package/dist/markup/index.js +1 -135
  60. package/dist/page-tabs/index.js +21 -709
  61. package/dist/sounds-OMHXVVQ4.js +1 -0
  62. package/dist/ui/index.d.ts +1 -1
  63. package/dist/ui/index.js +1 -19
  64. package/dist/ui.css +78 -10
  65. package/package.json +4 -3
  66. package/dist/Browser-O3QZGUF2.js +0 -482
  67. package/dist/Browser-O3QZGUF2.js.map +0 -1
  68. package/dist/Calculator-L6N5X3KU.js +0 -192
  69. package/dist/Calculator-L6N5X3KU.js.map +0 -1
  70. package/dist/ConfirmDialog-LYSSZSUD.js +0 -4
  71. package/dist/ConfirmDialog-LYSSZSUD.js.map +0 -1
  72. package/dist/CurrencyConverter-64MKXB3D.js +0 -236
  73. package/dist/CurrencyConverter-64MKXB3D.js.map +0 -1
  74. package/dist/Documents-5WXXYCLI.js +0 -441
  75. package/dist/Documents-5WXXYCLI.js.map +0 -1
  76. package/dist/Files-AUURUUDN.js +0 -805
  77. package/dist/Files-AUURUUDN.js.map +0 -1
  78. package/dist/Notepad-GPXJVPB7.js +0 -410
  79. package/dist/Notepad-GPXJVPB7.js.map +0 -1
  80. package/dist/PdfViewer-HKO6P4SR.js +0 -5
  81. package/dist/PdfViewer-HKO6P4SR.js.map +0 -1
  82. package/dist/PomodoroTimer-4TQBWLP2.js +0 -633
  83. package/dist/PomodoroTimer-4TQBWLP2.js.map +0 -1
  84. package/dist/Preview-FOZYPKM2.js +0 -2959
  85. package/dist/Preview-FOZYPKM2.js.map +0 -1
  86. package/dist/Sidebar-BPU7RCZP.js +0 -291
  87. package/dist/Sidebar-BPU7RCZP.js.map +0 -1
  88. package/dist/Spreadsheet-3C66BBBF.js +0 -519
  89. package/dist/Spreadsheet-3C66BBBF.js.map +0 -1
  90. package/dist/Stock-IF4IHYLU.js +0 -158
  91. package/dist/Stock-IF4IHYLU.js.map +0 -1
  92. package/dist/Weather-725PFR7T.js +0 -431
  93. package/dist/Weather-725PFR7T.js.map +0 -1
  94. package/dist/WorldClock-UU4NZIQ7.js +0 -202
  95. package/dist/WorldClock-UU4NZIQ7.js.map +0 -1
  96. package/dist/apps/index.js.map +0 -1
  97. package/dist/chunk-2TPTHAKI.js +0 -316
  98. package/dist/chunk-2TPTHAKI.js.map +0 -1
  99. package/dist/chunk-4P44JXDS.js +0 -195
  100. package/dist/chunk-4P44JXDS.js.map +0 -1
  101. package/dist/chunk-5O42JXQE.js +0 -26
  102. package/dist/chunk-5O42JXQE.js.map +0 -1
  103. package/dist/chunk-72CQWN7O.js +0 -547
  104. package/dist/chunk-72CQWN7O.js.map +0 -1
  105. package/dist/chunk-7CCHEEYC.js +0 -94
  106. package/dist/chunk-7CCHEEYC.js.map +0 -1
  107. package/dist/chunk-BE7FZOFU.js +0 -17
  108. package/dist/chunk-BE7FZOFU.js.map +0 -1
  109. package/dist/chunk-D276EMXS.js +0 -57
  110. package/dist/chunk-D276EMXS.js.map +0 -1
  111. package/dist/chunk-D7PYW2QS.js +0 -265
  112. package/dist/chunk-D7PYW2QS.js.map +0 -1
  113. package/dist/chunk-DVZWYWSD.js +0 -26
  114. package/dist/chunk-DVZWYWSD.js.map +0 -1
  115. package/dist/chunk-ET6ID4LP.js +0 -102
  116. package/dist/chunk-ET6ID4LP.js.map +0 -1
  117. package/dist/chunk-GA35NEND.js +0 -56
  118. package/dist/chunk-GA35NEND.js.map +0 -1
  119. package/dist/chunk-GIGV2ZRW.js +0 -70
  120. package/dist/chunk-GIGV2ZRW.js.map +0 -1
  121. package/dist/chunk-IPXN646P.js +0 -14
  122. package/dist/chunk-IPXN646P.js.map +0 -1
  123. package/dist/chunk-IRWSRJ4K.js +0 -48
  124. package/dist/chunk-IRWSRJ4K.js.map +0 -1
  125. package/dist/chunk-IULP5BCD.js +0 -79
  126. package/dist/chunk-IULP5BCD.js.map +0 -1
  127. package/dist/chunk-MGGY74RY.js +0 -14
  128. package/dist/chunk-MGGY74RY.js.map +0 -1
  129. package/dist/chunk-OLJDJYSU.js +0 -13678
  130. package/dist/chunk-OLJDJYSU.js.map +0 -1
  131. package/dist/chunk-PIGDNN5F.js +0 -46
  132. package/dist/chunk-PIGDNN5F.js.map +0 -1
  133. package/dist/chunk-Q2MJVSJT.js +0 -7
  134. package/dist/chunk-Q2MJVSJT.js.map +0 -1
  135. package/dist/chunk-Q3LT745N.js +0 -3710
  136. package/dist/chunk-Q3LT745N.js.map +0 -1
  137. package/dist/chunk-QAGQRNKI.js +0 -145
  138. package/dist/chunk-QAGQRNKI.js.map +0 -1
  139. package/dist/chunk-QRL64J5F.js +0 -503
  140. package/dist/chunk-QRL64J5F.js.map +0 -1
  141. package/dist/chunk-QSKCQUZE.js +0 -1103
  142. package/dist/chunk-QSKCQUZE.js.map +0 -1
  143. package/dist/chunk-R4OQIQYX.js +0 -153
  144. package/dist/chunk-R4OQIQYX.js.map +0 -1
  145. package/dist/chunk-RT6DSB5Y.js +0 -143
  146. package/dist/chunk-RT6DSB5Y.js.map +0 -1
  147. package/dist/chunk-SHQM5CK3.js +0 -549
  148. package/dist/chunk-SHQM5CK3.js.map +0 -1
  149. package/dist/chunk-T4VQHMG4.js +0 -822
  150. package/dist/chunk-T4VQHMG4.js.map +0 -1
  151. package/dist/chunk-TRCWINHF.js +0 -105
  152. package/dist/chunk-TRCWINHF.js.map +0 -1
  153. package/dist/chunk-TW7LPMVR.js +0 -16
  154. package/dist/chunk-TW7LPMVR.js.map +0 -1
  155. package/dist/chunk-W622KQTD.js +0 -465
  156. package/dist/chunk-W622KQTD.js.map +0 -1
  157. package/dist/chunk-X4Q6G253.js +0 -416
  158. package/dist/chunk-X4Q6G253.js.map +0 -1
  159. package/dist/chunk-YNKK7NE3.js +0 -171
  160. package/dist/chunk-YNKK7NE3.js.map +0 -1
  161. package/dist/chunk-YPO6RDMX.js +0 -20
  162. package/dist/chunk-YPO6RDMX.js.map +0 -1
  163. package/dist/file-intake/index.js.map +0 -1
  164. package/dist/index.js.map +0 -1
  165. package/dist/map/index.js.map +0 -1
  166. package/dist/markdown/index.js.map +0 -1
  167. package/dist/markup/index.js.map +0 -1
  168. package/dist/page-tabs/index.js.map +0 -1
  169. package/dist/sounds-NT4DEZGD.js +0 -3
  170. package/dist/sounds-NT4DEZGD.js.map +0 -1
  171. package/dist/ui/index.js.map +0 -1
@@ -1,822 +0,0 @@
1
- import { escapeHtml } from './chunk-MGGY74RY.js';
2
- import { useShellStrings } from './chunk-72CQWN7O.js';
3
- import { useBrowserLayoutEffect } from './chunk-IRWSRJ4K.js';
4
- import { useRef, useState, useEffect, useCallback, useMemo } from 'react';
5
- import { createPortal } from 'react-dom';
6
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
-
8
- function rangeContains(anchor, end, row, col) {
9
- const r1 = Math.min(anchor.row, end.row), r2 = Math.max(anchor.row, end.row);
10
- const c1 = Math.min(anchor.col, end.col), c2 = Math.max(anchor.col, end.col);
11
- return row >= r1 && row <= r2 && col >= c1 && col <= c2;
12
- }
13
- function withSpareRow(rows, colCount) {
14
- const last = rows[rows.length - 1];
15
- if (last && !last.some((cell) => cell.trim())) return rows;
16
- return [...rows, Array(colCount).fill("")];
17
- }
18
- function CellText({ text, ...props }) {
19
- const html = useMemo(() => ({ __html: escapeHtml(text) }), [text]);
20
- return /* @__PURE__ */ jsx("div", { ...props, dangerouslySetInnerHTML: html });
21
- }
22
- function EditableGrid({ columns, data, onChange, onColumnsChange, fixedRows = false, minRows = 15, maxHeight = "260px", cellStyles, onFocusChange, onSelectionChange }) {
23
- const tableRef = useRef(null);
24
- const strings = useShellStrings().grid;
25
- const [focus, setFocus] = useState(null);
26
- useEffect(() => {
27
- onFocusChange?.(focus);
28
- }, [focus, onFocusChange]);
29
- const [colWidths, setColWidths] = useState({});
30
- const resizing = useRef(null);
31
- const [rowHeights, setRowHeights] = useState({});
32
- const rowResizing = useRef(null);
33
- const [dragRow, setDragRow] = useState(null);
34
- const [dragOverRow, setDragOverRow] = useState(null);
35
- const [dragCol, setDragCol] = useState(null);
36
- const [dragOverCol, setDragOverCol] = useState(null);
37
- const [editingCell, setEditingCell] = useState(null);
38
- const caretToEnd = useRef(null);
39
- useBrowserLayoutEffect(() => {
40
- const pos = caretToEnd.current;
41
- if (!pos || pos.row !== editingCell?.row || pos.col !== editingCell?.col) return;
42
- caretToEnd.current = null;
43
- const el = tableRef.current?.querySelector(`[data-row="${pos.row}"][data-col="${pos.col}"]`);
44
- if (!el) return;
45
- el.focus();
46
- const range = document.createRange();
47
- range.selectNodeContents(el);
48
- range.collapse(false);
49
- const sel = window.getSelection();
50
- sel?.removeAllRanges();
51
- sel?.addRange(range);
52
- }, [editingCell]);
53
- const [selAnchor, setSelAnchor] = useState(null);
54
- const [selEnd, setSelEnd] = useState(null);
55
- useEffect(() => {
56
- onSelectionChange?.(selAnchor && selEnd ? { anchor: selAnchor, end: selEnd } : null);
57
- }, [selAnchor, selEnd, onSelectionChange]);
58
- const dragging = useRef(false);
59
- const [fillTarget, setFillTarget] = useState(null);
60
- const filling = useRef(false);
61
- const selRefForFill = useRef({ a: null, e: null });
62
- selRefForFill.current = { a: selAnchor, e: selEnd };
63
- const hasRange = selAnchor && selEnd && (selAnchor.row !== selEnd.row || selAnchor.col !== selEnd.col);
64
- const rows = [...data];
65
- if (!fixedRows) {
66
- while (rows.length < minRows) rows.push(Array(columns.length).fill(""));
67
- }
68
- const updateCell = useCallback((row, col, value) => {
69
- const next = rows.map((r) => [...r]);
70
- while (next.length <= row) next.push(Array(columns.length).fill(""));
71
- while (next[row].length < columns.length) next[row].push("");
72
- next[row][col] = value;
73
- onChange(next);
74
- }, [rows, columns.length, onChange]);
75
- const handleMouseDown = useCallback((e, row, col) => {
76
- if (e.button !== 0) return;
77
- const active = document.activeElement;
78
- if (active?.dataset?.row && active?.dataset?.col) {
79
- const ar = parseInt(active.dataset.row);
80
- const ac = parseInt(active.dataset.col);
81
- const val = active.textContent || "";
82
- if (val !== (rows[ar]?.[ac] || "")) {
83
- const next = rows.map((r) => [...r]);
84
- if (next[ar]) {
85
- next[ar][ac] = val;
86
- onChange(next);
87
- }
88
- }
89
- }
90
- dragging.current = true;
91
- if (e.shiftKey && selAnchor) {
92
- setSelEnd({ row, col });
93
- } else {
94
- setSelAnchor({ row, col });
95
- setSelEnd({ row, col });
96
- }
97
- }, [rows, onChange, selAnchor]);
98
- const handleMouseEnter = useCallback((row, col) => {
99
- if (dragging.current) {
100
- setSelEnd({ row, col });
101
- }
102
- }, []);
103
- useEffect(() => {
104
- const handleMouseUp = () => {
105
- dragging.current = false;
106
- };
107
- window.addEventListener("mouseup", handleMouseUp);
108
- return () => window.removeEventListener("mouseup", handleMouseUp);
109
- }, []);
110
- useEffect(() => {
111
- const handler = (e) => {
112
- if (!(e.ctrlKey || e.metaKey) || e.key !== "c") return;
113
- if (!selAnchor || !selEnd) return;
114
- const nativeSel = window.getSelection();
115
- if (nativeSel && nativeSel.toString().length > 0 && !hasRange) return;
116
- const r1 = Math.min(selAnchor.row, selEnd.row), r2 = Math.max(selAnchor.row, selEnd.row);
117
- const c1 = Math.min(selAnchor.col, selEnd.col), c2 = Math.max(selAnchor.col, selEnd.col);
118
- const text = [];
119
- for (let r = r1; r <= r2; r++) {
120
- const rowCells = [];
121
- for (let c = c1; c <= c2; c++) {
122
- rowCells.push(rows[r]?.[c] || "");
123
- }
124
- text.push(rowCells.join(" "));
125
- }
126
- const tsv = text.join("\n");
127
- if (tsv) {
128
- e.preventDefault();
129
- navigator.clipboard.writeText(tsv);
130
- }
131
- };
132
- window.addEventListener("keydown", handler);
133
- return () => window.removeEventListener("keydown", handler);
134
- }, [selAnchor, selEnd, rows, hasRange]);
135
- useEffect(() => {
136
- const handler = (e) => {
137
- if (!focus) return;
138
- const active = document.activeElement;
139
- if (active?.isContentEditable) return;
140
- if (!tableRef.current?.contains(active)) return;
141
- const text = e.clipboardData?.getData("text/plain");
142
- if (!text) return;
143
- e.preventDefault();
144
- const pastedRows = text.split("\n").filter((l) => l).map((line) => line.split(" "));
145
- const next = rows.map((r) => [...r]);
146
- for (let r = 0; r < pastedRows.length; r++) {
147
- const targetRow = focus.row + r;
148
- while (next.length <= targetRow) next.push(Array(columns.length).fill(""));
149
- while (next[targetRow].length < columns.length) next[targetRow].push("");
150
- for (let c = 0; c < pastedRows[r].length; c++) {
151
- const targetCol = focus.col + c;
152
- if (targetCol >= columns.length) break;
153
- if (columns[targetCol].readOnly) continue;
154
- next[targetRow][targetCol] = pastedRows[r][c].trim();
155
- }
156
- }
157
- onChange(fixedRows ? next : withSpareRow(next, columns.length));
158
- setSelAnchor({ row: focus.row, col: focus.col });
159
- setSelEnd({ row: Math.min(focus.row + pastedRows.length - 1, next.length - 1), col: Math.min(focus.col + (pastedRows[0]?.length || 1) - 1, columns.length - 1) });
160
- };
161
- window.addEventListener("paste", handler);
162
- return () => window.removeEventListener("paste", handler);
163
- }, [focus, rows, columns, onChange, fixedRows]);
164
- const handlePaste = useCallback((e, startRow, startCol) => {
165
- const text = e.clipboardData.getData("text/plain");
166
- if (!text) return;
167
- const pastedRows = text.split("\n").map((line) => line.split(" "));
168
- if (pastedRows.length <= 1 && pastedRows[0]?.length <= 1) return;
169
- e.preventDefault();
170
- const next = rows.map((r) => [...r]);
171
- for (let r = 0; r < pastedRows.length; r++) {
172
- const targetRow = startRow + r;
173
- while (next.length <= targetRow) next.push(Array(columns.length).fill(""));
174
- while (next[targetRow].length < columns.length) next[targetRow].push("");
175
- for (let c = 0; c < pastedRows[r].length; c++) {
176
- const targetCol = startCol + c;
177
- if (targetCol >= columns.length) break;
178
- if (columns[targetCol].readOnly) continue;
179
- next[targetRow][targetCol] = pastedRows[r][c].trim();
180
- }
181
- }
182
- onChange(fixedRows ? next : withSpareRow(next, columns.length));
183
- }, [rows, columns, onChange, fixedRows]);
184
- const handleKeyDown = useCallback((e, row, col) => {
185
- let nextRow = row;
186
- let nextCol = col;
187
- if (e.key === "Tab") {
188
- e.preventDefault();
189
- nextCol = e.shiftKey ? col - 1 : col + 1;
190
- if (nextCol >= columns.length) {
191
- nextCol = 0;
192
- nextRow = row + 1;
193
- }
194
- if (nextCol < 0) {
195
- nextCol = columns.length - 1;
196
- nextRow = row - 1;
197
- }
198
- } else if (e.key === "Enter") {
199
- e.preventDefault();
200
- nextRow = e.shiftKey ? row - 1 : row + 1;
201
- } else if (e.key === "ArrowDown") {
202
- e.preventDefault();
203
- nextRow = row + 1;
204
- } else if (e.key === "ArrowUp") {
205
- e.preventDefault();
206
- nextRow = row - 1;
207
- } else if (e.key === "ArrowLeft") {
208
- e.preventDefault();
209
- nextCol = col - 1;
210
- } else if (e.key === "ArrowRight") {
211
- e.preventDefault();
212
- nextCol = col + 1;
213
- } else if (e.key === "Delete" || e.key === "Backspace") {
214
- const target = e.target;
215
- if (target.isContentEditable) {
216
- if (target.textContent && window.getSelection()?.toString() === target.textContent) {
217
- e.preventDefault();
218
- updateCell(row, col, "");
219
- }
220
- return;
221
- }
222
- e.preventDefault();
223
- if (selAnchor && selEnd) {
224
- const r1 = Math.min(selAnchor.row, selEnd.row), r2 = Math.max(selAnchor.row, selEnd.row);
225
- const c1 = Math.min(selAnchor.col, selEnd.col), c2 = Math.max(selAnchor.col, selEnd.col);
226
- const next = rows.map((r) => [...r]);
227
- for (let r = r1; r <= r2; r++) for (let c = c1; c <= c2; c++) {
228
- if (next[r] && !columns[c]?.readOnly) next[r][c] = "";
229
- }
230
- onChange(next);
231
- } else {
232
- updateCell(row, col, "");
233
- }
234
- return;
235
- } else {
236
- return;
237
- }
238
- while (nextCol >= 0 && nextCol < columns.length && columns[nextCol].readOnly) {
239
- nextCol += e.key === "Tab" && e.shiftKey ? -1 : 1;
240
- }
241
- if (nextRow >= 0 && nextRow < rows.length && nextCol >= 0 && nextCol < columns.length) {
242
- const cell = tableRef.current?.querySelector(`[data-row="${nextRow}"][data-col="${nextCol}"]`);
243
- if (cell) {
244
- cell.focus({ preventScroll: true });
245
- cell.scrollIntoView({ block: "nearest", inline: "nearest" });
246
- setFocus({ row: nextRow, col: nextCol });
247
- setEditingCell(null);
248
- setSelAnchor({ row: nextRow, col: nextCol });
249
- setSelEnd({ row: nextRow, col: nextCol });
250
- }
251
- }
252
- }, [columns, rows, rows.length, updateCell, selAnchor, selEnd, onChange]);
253
- const ensureRows = useCallback((row) => {
254
- if (fixedRows) return;
255
- if (row >= rows.length - 2) {
256
- const next = rows.map((r) => [...r]);
257
- for (let i = 0; i < 5; i++) next.push(Array(columns.length).fill(""));
258
- onChange(next);
259
- }
260
- }, [fixedRows, rows, columns.length, onChange]);
261
- const [ctxMenu, setCtxMenu] = useState(null);
262
- useEffect(() => {
263
- if (!ctxMenu) return;
264
- const handler = () => setCtxMenu(null);
265
- window.addEventListener("pointerdown", handler);
266
- return () => window.removeEventListener("pointerdown", handler);
267
- }, [ctxMenu]);
268
- const insertRow = useCallback((at) => {
269
- const next = rows.map((r) => [...r]);
270
- next.splice(at, 0, Array(columns.length).fill(""));
271
- onChange(next);
272
- }, [rows, columns.length, onChange]);
273
- const deleteRow = useCallback((at) => {
274
- if (rows.length <= 1) return;
275
- const next = rows.filter((_, i) => i !== at);
276
- onChange(next);
277
- }, [rows, onChange]);
278
- const insertCol = useCallback((at) => {
279
- const next = rows.map((r) => {
280
- const nr = [...r];
281
- nr.splice(at, 0, "");
282
- return nr;
283
- });
284
- onChange(next);
285
- }, [rows, onChange]);
286
- const deleteCol = useCallback((at) => {
287
- if (columns.length <= 1) return;
288
- const next = rows.map((r) => {
289
- const nr = [...r];
290
- nr.splice(at, 1);
291
- return nr;
292
- });
293
- onChange(next);
294
- }, [rows, columns.length, onChange]);
295
- const handleRowCtx = useCallback((e, ri) => {
296
- e.preventDefault();
297
- if (fixedRows) return;
298
- setCtxMenu({ x: e.clientX, y: e.clientY, items: [
299
- { label: strings.insertRowAbove, onClick: () => {
300
- insertRow(ri);
301
- setCtxMenu(null);
302
- } },
303
- { label: strings.insertRowBelow, onClick: () => {
304
- insertRow(ri + 1);
305
- setCtxMenu(null);
306
- } },
307
- { label: strings.deleteRow(ri + 1), onClick: () => {
308
- deleteRow(ri);
309
- setCtxMenu(null);
310
- } }
311
- ] });
312
- }, [fixedRows, insertRow, deleteRow, strings]);
313
- const handleColCtx = useCallback((e, ci) => {
314
- e.preventDefault();
315
- if (fixedRows) return;
316
- setCtxMenu({ x: e.clientX, y: e.clientY, items: [
317
- { label: strings.insertColumnLeft, onClick: () => {
318
- insertCol(ci);
319
- setCtxMenu(null);
320
- } },
321
- { label: strings.insertColumnRight, onClick: () => {
322
- insertCol(ci + 1);
323
- setCtxMenu(null);
324
- } },
325
- { label: strings.deleteColumn(String(columns[ci]?.title || ci + 1)), onClick: () => {
326
- deleteCol(ci);
327
- setCtxMenu(null);
328
- } }
329
- ] });
330
- }, [fixedRows, columns, insertCol, deleteCol, strings]);
331
- const getColWidth = (ci) => colWidths[ci] ?? columns[ci]?.width ?? 150;
332
- useEffect(() => {
333
- const handleMouseMove = (e) => {
334
- if (!resizing.current) return;
335
- const diff = e.clientX - resizing.current.startX;
336
- const newW = Math.max(40, resizing.current.startW + diff);
337
- setColWidths((prev) => ({ ...prev, [resizing.current.col]: newW }));
338
- };
339
- const handleMouseUp = () => {
340
- if (resizing.current && onColumnsChange) {
341
- const updated = columns.map((c, i) => ({ ...c, width: colWidths[i] ?? c.width }));
342
- updated[resizing.current.col] = { ...updated[resizing.current.col], width: colWidths[resizing.current.col] ?? columns[resizing.current.col].width };
343
- onColumnsChange(updated);
344
- }
345
- resizing.current = null;
346
- document.body.style.cursor = "";
347
- };
348
- window.addEventListener("mousemove", handleMouseMove);
349
- window.addEventListener("mouseup", handleMouseUp);
350
- return () => {
351
- window.removeEventListener("mousemove", handleMouseMove);
352
- window.removeEventListener("mouseup", handleMouseUp);
353
- };
354
- }, [columns, colWidths, onColumnsChange]);
355
- const startColResize = (e, ci) => {
356
- e.preventDefault();
357
- e.stopPropagation();
358
- resizing.current = { col: ci, startX: e.clientX, startW: getColWidth(ci) };
359
- document.body.style.cursor = "col-resize";
360
- };
361
- const getRowHeight = (ri) => rowHeights[ri] ?? 28;
362
- useEffect(() => {
363
- const handleMove = (e) => {
364
- if (!rowResizing.current) return;
365
- const diff = e.clientY - rowResizing.current.startY;
366
- const newH = Math.max(20, rowResizing.current.startH + diff);
367
- setRowHeights((prev) => ({ ...prev, [rowResizing.current.row]: newH }));
368
- };
369
- const handleUp = () => {
370
- rowResizing.current = null;
371
- document.body.style.cursor = "";
372
- };
373
- window.addEventListener("mousemove", handleMove);
374
- window.addEventListener("mouseup", handleUp);
375
- return () => {
376
- window.removeEventListener("mousemove", handleMove);
377
- window.removeEventListener("mouseup", handleUp);
378
- };
379
- }, []);
380
- const startRowResize = (e, ri) => {
381
- e.preventDefault();
382
- e.stopPropagation();
383
- rowResizing.current = { row: ri, startY: e.clientY, startH: getRowHeight(ri) };
384
- document.body.style.cursor = "row-resize";
385
- };
386
- const autoFitColumn = useCallback((ci) => {
387
- const canvas = document.createElement("canvas");
388
- const ctx = canvas.getContext("2d");
389
- if (!ctx) return;
390
- ctx.font = "12px ui-monospace, SFMono-Regular, Menlo, monospace";
391
- let maxW = 0;
392
- for (const row of rows) {
393
- const plain = String(row[ci] ?? "").replace(/<[^>]*>/g, "");
394
- const w = ctx.measureText(plain).width;
395
- if (w > maxW) maxW = w;
396
- }
397
- const headerW = ctx.measureText(columns[ci]?.title ?? "").width;
398
- if (headerW > maxW) maxW = headerW;
399
- const finalW = Math.max(40, Math.ceil(maxW + 24));
400
- setColWidths((prev) => ({ ...prev, [ci]: finalW }));
401
- if (onColumnsChange) {
402
- const updated = columns.map((c, i) => ({ ...c, width: i === ci ? finalW : colWidths[i] ?? c.width }));
403
- onColumnsChange(updated);
404
- }
405
- }, [rows, columns, colWidths, onColumnsChange]);
406
- const autoFitRow = useCallback((ri) => {
407
- setRowHeights((prev) => {
408
- const next = { ...prev };
409
- delete next[ri];
410
- return next;
411
- });
412
- }, []);
413
- const applyFill = useCallback((target) => {
414
- const { a: sa, e: se } = selRefForFill.current;
415
- if (!sa || !se) return;
416
- const r1 = Math.min(sa.row, se.row);
417
- const r2 = Math.max(sa.row, se.row);
418
- const c1 = Math.min(sa.col, se.col);
419
- const c2 = Math.max(sa.col, se.col);
420
- let nr1 = r1, nr2 = r2, nc1 = c1, nc2 = c2;
421
- if (target.row > r2) nr2 = target.row;
422
- else if (target.row < r1) nr1 = target.row;
423
- if (target.col > c2) nc2 = target.col;
424
- else if (target.col < c1) nc1 = target.col;
425
- const selH = r2 - r1 + 1;
426
- const selW = c2 - c1 + 1;
427
- const next = rows.map((r) => [...r]);
428
- while (next.length <= nr2) next.push(Array(columns.length).fill(""));
429
- for (const row of next) while (row.length <= nc2) row.push("");
430
- function asSeries(values) {
431
- const nums = values.map((v) => parseFloat(v));
432
- if (nums.length < 2 || nums.some((n) => Number.isNaN(n))) return null;
433
- const step = nums[1] - nums[0];
434
- for (let i = 2; i < nums.length; i++) {
435
- if (Math.abs(nums[i] - nums[i - 1] - step) > 1e-9) return null;
436
- }
437
- return { step };
438
- }
439
- for (let r = nr1; r <= nr2; r++) {
440
- for (let c = nc1; c <= nc2; c++) {
441
- if (r >= r1 && r <= r2 && c >= c1 && c <= c2) continue;
442
- let value;
443
- if (selW === 1 && nc1 === c1 && nc2 === c2) {
444
- const colVals = Array.from({ length: selH }, (_, i) => next[r1 + i]?.[c] ?? "");
445
- const series = asSeries(colVals);
446
- if (series) {
447
- const last = parseFloat(next[r2]?.[c] ?? "0");
448
- const first = parseFloat(next[r1]?.[c] ?? "0");
449
- const offset = r > r2 ? r - r2 : -(r1 - r);
450
- value = String((r > r2 ? last : first) + series.step * offset);
451
- } else {
452
- const dr = ((r - r1) % selH + selH) % selH;
453
- value = next[r1 + dr]?.[c] ?? "";
454
- }
455
- } else if (selH === 1 && nr1 === r1 && nr2 === r2) {
456
- const rowVals = Array.from({ length: selW }, (_, i) => next[r]?.[c1 + i] ?? "");
457
- const series = asSeries(rowVals);
458
- if (series) {
459
- const last = parseFloat(next[r]?.[c2] ?? "0");
460
- const first = parseFloat(next[r]?.[c1] ?? "0");
461
- const offset = c > c2 ? c - c2 : -(c1 - c);
462
- value = String((c > c2 ? last : first) + series.step * offset);
463
- } else {
464
- const dc = ((c - c1) % selW + selW) % selW;
465
- value = next[r]?.[c1 + dc] ?? "";
466
- }
467
- } else {
468
- const dr = ((r - r1) % selH + selH) % selH;
469
- const dc = ((c - c1) % selW + selW) % selW;
470
- value = next[r1 + dr]?.[c1 + dc] ?? "";
471
- }
472
- next[r][c] = value;
473
- }
474
- }
475
- onChange(next);
476
- setSelAnchor({ row: nr1, col: nc1 });
477
- setSelEnd({ row: nr2, col: nc2 });
478
- }, [rows, columns.length, onChange]);
479
- useEffect(() => {
480
- const handleMove = (e) => {
481
- if (!filling.current) return;
482
- const el = document.elementFromPoint(e.clientX, e.clientY);
483
- const inner = el?.closest?.("[data-row][data-col]");
484
- if (!inner) return;
485
- const r = parseInt(inner.dataset.row);
486
- const c = parseInt(inner.dataset.col);
487
- setFillTarget({ row: r, col: c });
488
- };
489
- const handleUp = () => {
490
- if (filling.current && fillTarget) applyFill(fillTarget);
491
- filling.current = false;
492
- setFillTarget(null);
493
- document.body.style.cursor = "";
494
- };
495
- window.addEventListener("mousemove", handleMove);
496
- window.addEventListener("mouseup", handleUp);
497
- return () => {
498
- window.removeEventListener("mousemove", handleMove);
499
- window.removeEventListener("mouseup", handleUp);
500
- };
501
- }, [fillTarget, applyFill]);
502
- const startFill = (e) => {
503
- e.preventDefault();
504
- e.stopPropagation();
505
- filling.current = true;
506
- document.body.style.cursor = "crosshair";
507
- };
508
- const handleRowDragStart = (ri) => setDragRow(ri);
509
- const handleRowDragOver = (e, ri) => {
510
- e.preventDefault();
511
- setDragOverRow(ri);
512
- };
513
- const handleRowDrop = (ri) => {
514
- if (dragRow === null || dragRow === ri) {
515
- setDragRow(null);
516
- setDragOverRow(null);
517
- return;
518
- }
519
- const next = rows.map((r) => [...r]);
520
- const [moved] = next.splice(dragRow, 1);
521
- next.splice(ri, 0, moved);
522
- onChange(next);
523
- setDragRow(null);
524
- setDragOverRow(null);
525
- };
526
- const handleColDragStart = (ci) => setDragCol(ci);
527
- const handleColDragOver = (e, ci) => {
528
- e.preventDefault();
529
- setDragOverCol(ci);
530
- };
531
- const handleColDrop = (ci) => {
532
- if (dragCol === null || dragCol === ci) {
533
- setDragCol(null);
534
- setDragOverCol(null);
535
- return;
536
- }
537
- const next = rows.map((r) => {
538
- const nr = [...r];
539
- const [moved] = nr.splice(dragCol, 1);
540
- nr.splice(ci, 0, moved);
541
- return nr;
542
- });
543
- onChange(next);
544
- if (onColumnsChange) {
545
- const newCols = [...columns];
546
- const [moved] = newCols.splice(dragCol, 1);
547
- newCols.splice(ci, 0, moved);
548
- onColumnsChange(newCols);
549
- }
550
- setDragCol(null);
551
- setDragOverCol(null);
552
- };
553
- const ROW_HEIGHT = 28;
554
- const BUFFER = 20;
555
- const containerRef = useRef(null);
556
- const [scrollTop, setScrollTop] = useState(0);
557
- const [containerHeight, setContainerHeight] = useState(800);
558
- useEffect(() => {
559
- const el = containerRef.current;
560
- if (!el) return;
561
- const measure = () => setContainerHeight(el.clientHeight || 800);
562
- measure();
563
- const observer = new ResizeObserver(measure);
564
- observer.observe(el);
565
- return () => observer.disconnect();
566
- }, []);
567
- const useVirtualization = rows.length > 100;
568
- const visibleStart = useVirtualization ? Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - BUFFER) : 0;
569
- const visibleEnd = useVirtualization ? Math.min(rows.length, Math.ceil((scrollTop + containerHeight) / ROW_HEIGHT) + BUFFER) : rows.length;
570
- const visibleRows = useMemo(() => rows.slice(visibleStart, visibleEnd), [rows, visibleStart, visibleEnd]);
571
- const topPad = visibleStart * ROW_HEIGHT;
572
- const bottomPad = (rows.length - visibleEnd) * ROW_HEIGHT;
573
- const thCls = "px-2 py-1.5 text-left text-xs font-medium text-gray-500 uppercase bg-gray-100 border-b border-r border-gray-200 select-none";
574
- const tdCls = "px-0 py-0 border-b border-r border-gray-200 text-sm";
575
- return /* @__PURE__ */ jsxs(
576
- "div",
577
- {
578
- ref: containerRef,
579
- className: "border border-gray-300 rounded overflow-scroll grid-scroll",
580
- style: { maxHeight, height: maxHeight },
581
- onScroll: (e) => setScrollTop(e.target.scrollTop),
582
- children: [
583
- /* @__PURE__ */ jsxs("table", { ref: tableRef, className: "border-collapse select-none", style: { tableLayout: "fixed", minWidth: 36 + columns.reduce((s, c) => s + getColWidth(columns.indexOf(c)), 0) }, children: [
584
- /* @__PURE__ */ jsxs("colgroup", { children: [
585
- /* @__PURE__ */ jsx("col", { style: { width: 36 } }),
586
- columns.map((c, ci) => /* @__PURE__ */ jsx("col", { style: { width: getColWidth(ci) } }, c.key))
587
- ] }),
588
- /* @__PURE__ */ jsx("thead", { className: "sticky top-0 z-10", children: /* @__PURE__ */ jsxs("tr", { children: [
589
- /* @__PURE__ */ jsx(
590
- "th",
591
- {
592
- className: thCls + " text-center w-9 cursor-pointer hover:bg-gray-200",
593
- onClick: () => {
594
- setSelAnchor({ row: 0, col: 0 });
595
- setSelEnd({ row: rows.length - 1, col: columns.length - 1 });
596
- },
597
- title: strings.selectAll,
598
- children: "#"
599
- }
600
- ),
601
- columns.map((c, ci) => {
602
- const colSelected = selAnchor && selEnd && Math.min(selAnchor.col, selEnd.col) <= ci && ci <= Math.max(selAnchor.col, selEnd.col) && Math.min(selAnchor.row, selEnd.row) === 0 && Math.max(selAnchor.row, selEnd.row) === rows.length - 1;
603
- return /* @__PURE__ */ jsxs(
604
- "th",
605
- {
606
- className: `${thCls} cursor-pointer hover:bg-gray-200 relative${colSelected ? " !bg-blue-200" : ""}${dragOverCol === ci ? " !bg-blue-100" : ""}`,
607
- style: { width: getColWidth(ci) },
608
- draggable: true,
609
- onDragStart: () => handleColDragStart(ci),
610
- onDragOver: (e) => handleColDragOver(e, ci),
611
- onDrop: () => handleColDrop(ci),
612
- onDragEnd: () => {
613
- setDragCol(null);
614
- setDragOverCol(null);
615
- },
616
- onClick: (e) => {
617
- if (e.shiftKey && selAnchor) {
618
- setSelEnd({ row: rows.length - 1, col: ci });
619
- } else {
620
- setSelAnchor({ row: 0, col: ci });
621
- setSelEnd({ row: rows.length - 1, col: ci });
622
- }
623
- },
624
- onContextMenu: (e) => handleColCtx(e, ci),
625
- children: [
626
- c.title,
627
- /* @__PURE__ */ jsx(
628
- "div",
629
- {
630
- className: "absolute -right-1 top-0 bottom-0 w-2 cursor-col-resize z-20",
631
- onMouseDown: (e) => startColResize(e, ci),
632
- onDoubleClick: (e) => {
633
- e.stopPropagation();
634
- autoFitColumn(ci);
635
- },
636
- title: strings.resize
637
- }
638
- )
639
- ]
640
- },
641
- c.key
642
- );
643
- })
644
- ] }) }),
645
- /* @__PURE__ */ jsxs("tbody", { children: [
646
- topPad > 0 && /* @__PURE__ */ jsx("tr", { style: { height: topPad } }),
647
- visibleRows.map((row, vi) => {
648
- const ri = visibleStart + vi;
649
- const rowSelected = selAnchor && selEnd && Math.min(selAnchor.row, selEnd.row) <= ri && ri <= Math.max(selAnchor.row, selEnd.row) && Math.min(selAnchor.col, selEnd.col) === 0 && Math.max(selAnchor.col, selEnd.col) === columns.length - 1;
650
- return /* @__PURE__ */ jsxs("tr", { style: { height: getRowHeight(ri) }, children: [
651
- /* @__PURE__ */ jsxs(
652
- "td",
653
- {
654
- className: `relative px-1 py-1 text-center text-[10px] text-gray-400 border-b border-r border-gray-200 bg-gray-50 select-none cursor-pointer hover:bg-gray-200${rowSelected ? " !bg-blue-200 !text-gray-700" : ""}${dragOverRow === ri ? " !bg-blue-100" : ""}`,
655
- draggable: true,
656
- onDragStart: () => handleRowDragStart(ri),
657
- onDragOver: (e) => handleRowDragOver(e, ri),
658
- onDrop: () => handleRowDrop(ri),
659
- onDragEnd: () => {
660
- setDragRow(null);
661
- setDragOverRow(null);
662
- },
663
- onClick: (e) => {
664
- if (e.shiftKey && selAnchor) {
665
- setSelEnd({ row: ri, col: columns.length - 1 });
666
- } else {
667
- setSelAnchor({ row: ri, col: 0 });
668
- setSelEnd({ row: ri, col: columns.length - 1 });
669
- }
670
- },
671
- onContextMenu: (e) => handleRowCtx(e, ri),
672
- children: [
673
- ri + 1,
674
- /* @__PURE__ */ jsx(
675
- "div",
676
- {
677
- className: "absolute -bottom-1 left-0 right-0 h-2 cursor-row-resize z-20",
678
- onMouseDown: (e) => startRowResize(e, ri),
679
- onDoubleClick: (e) => {
680
- e.stopPropagation();
681
- autoFitRow(ri);
682
- },
683
- title: strings.resize
684
- }
685
- )
686
- ]
687
- }
688
- ),
689
- columns.map((col, ci) => {
690
- const inRange = selAnchor && selEnd && rangeContains(selAnchor, selEnd, ri, ci);
691
- const isEditing = editingCell?.row === ri && editingCell?.col === ci && !col.readOnly;
692
- const isFocused = focus?.row === ri && focus?.col === ci;
693
- const cellStyle = cellStyles?.[`${ri}:${ci}`];
694
- const selR2 = selAnchor && selEnd ? Math.max(selAnchor.row, selEnd.row) : -1;
695
- const selC2 = selAnchor && selEnd ? Math.max(selAnchor.col, selEnd.col) : -1;
696
- const isFillCorner = selAnchor && selEnd && ri === selR2 && ci === selC2;
697
- const inFillPreview = filling.current && fillTarget && selAnchor && selEnd && (() => {
698
- const r1 = Math.min(selAnchor.row, selEnd.row), r2 = Math.max(selAnchor.row, selEnd.row);
699
- const c1 = Math.min(selAnchor.col, selEnd.col), c2 = Math.max(selAnchor.col, selEnd.col);
700
- let nr1 = r1, nr2 = r2, nc1 = c1, nc2 = c2;
701
- if (fillTarget.row > r2) nr2 = fillTarget.row;
702
- else if (fillTarget.row < r1) nr1 = fillTarget.row;
703
- if (fillTarget.col > c2) nc2 = fillTarget.col;
704
- else if (fillTarget.col < c1) nc1 = fillTarget.col;
705
- return ri >= nr1 && ri <= nr2 && ci >= nc1 && ci <= nc2 && !(ri >= r1 && ri <= r2 && ci >= c1 && ci <= c2);
706
- })();
707
- const fontSizeCls = cellStyle?.fontSize === "sm" ? "text-[11px]" : cellStyle?.fontSize === "lg" ? "text-sm" : cellStyle?.fontSize === "xl" ? "text-base" : "text-xs";
708
- const styleCls = `${cellStyle?.bold ? " font-bold" : ""}${cellStyle?.italic ? " italic" : ""}${cellStyle?.underline ? " underline" : ""}`;
709
- return /* @__PURE__ */ jsxs(
710
- "td",
711
- {
712
- className: `relative ${tdCls}${col.readOnly ? " bg-gray-50 text-gray-500 cursor-default" : " cursor-cell"}${inRange ? " !bg-blue-100" : ""}${isFocused && !inRange ? " ring-2 ring-inset ring-blue-400" : ""}${inFillPreview ? " !bg-blue-50 ring-1 ring-inset ring-blue-300" : ""}`,
713
- onMouseDown: (e) => {
714
- if (e.target === e.currentTarget) {
715
- handleMouseDown(e, ri, ci);
716
- const inner = e.currentTarget.querySelector("[data-row][data-col]");
717
- inner?.focus();
718
- }
719
- },
720
- onMouseEnter: () => handleMouseEnter(ri, ci),
721
- onClick: (e) => {
722
- if (e.target === e.currentTarget) {
723
- const inner = e.currentTarget.querySelector("[data-row][data-col]");
724
- inner?.focus();
725
- }
726
- },
727
- onDoubleClick: (e) => {
728
- if (e.target === e.currentTarget && !col.readOnly) setEditingCell({ row: ri, col: ci });
729
- },
730
- children: [
731
- /* @__PURE__ */ jsx(
732
- CellText,
733
- {
734
- contentEditable: isEditing,
735
- suppressContentEditableWarning: true,
736
- tabIndex: 0,
737
- "data-row": ri,
738
- "data-col": ci,
739
- className: `w-full h-full px-2 py-1 rosh-focus-ring whitespace-nowrap overflow-hidden ${col.align === "right" ? "text-right" : col.align === "center" ? "text-center" : ""} ${col.readOnly ? "cursor-default" : "cursor-cell"} font-mono ${fontSizeCls}${styleCls}`,
740
- onMouseDown: (e) => handleMouseDown(e, ri, ci),
741
- onMouseEnter: () => handleMouseEnter(ri, ci),
742
- onDoubleClick: () => {
743
- if (!col.readOnly) setEditingCell({ row: ri, col: ci });
744
- },
745
- onFocus: () => {
746
- setFocus({ row: ri, col: ci });
747
- if (!dragging.current) {
748
- setSelAnchor({ row: ri, col: ci });
749
- setSelEnd({ row: ri, col: ci });
750
- }
751
- },
752
- onBlur: (e) => {
753
- const val = e.currentTarget.textContent || "";
754
- if (val !== (row[ci] || "")) updateCell(ri, ci, val);
755
- setEditingCell(null);
756
- },
757
- onInput: () => ensureRows(ri),
758
- onPaste: (e) => handlePaste(e, ri, ci),
759
- onKeyDown: (e) => {
760
- if (!isEditing && !col.readOnly && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
761
- e.preventDefault();
762
- updateCell(ri, ci, e.key);
763
- caretToEnd.current = { row: ri, col: ci };
764
- setEditingCell({ row: ri, col: ci });
765
- return;
766
- }
767
- handleKeyDown(e, ri, ci);
768
- },
769
- text: row[ci] || ""
770
- }
771
- ),
772
- isFillCorner && /* @__PURE__ */ jsx(
773
- "div",
774
- {
775
- onMouseDown: startFill,
776
- title: strings.fill,
777
- className: "absolute -bottom-[3px] -right-[3px] w-[7px] h-[7px] bg-blue-500 border border-white cursor-crosshair z-30 hover:bg-blue-600"
778
- }
779
- )
780
- ]
781
- },
782
- ci
783
- );
784
- })
785
- ] }, ri);
786
- }),
787
- bottomPad > 0 && /* @__PURE__ */ jsx("tr", { style: { height: bottomPad } })
788
- ] })
789
- ] }),
790
- ctxMenu && createPortal(
791
- /* @__PURE__ */ jsxs(Fragment, { children: [
792
- /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[200]", onPointerDown: () => setCtxMenu(null) }),
793
- /* @__PURE__ */ jsx(
794
- "div",
795
- {
796
- className: "fixed z-[201] bg-white rounded-lg shadow-lg border border-gray-200 py-1 min-w-[160px]",
797
- style: { left: ctxMenu.x, top: ctxMenu.y },
798
- children: ctxMenu.items.map((item, i) => /* @__PURE__ */ jsx(
799
- "button",
800
- {
801
- onPointerDown: (e) => {
802
- e.stopPropagation();
803
- item.onClick();
804
- },
805
- className: "w-full text-left px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100",
806
- children: item.label
807
- },
808
- i
809
- ))
810
- }
811
- )
812
- ] }),
813
- document.body
814
- )
815
- ]
816
- }
817
- );
818
- }
819
-
820
- export { EditableGrid, withSpareRow };
821
- //# sourceMappingURL=chunk-T4VQHMG4.js.map
822
- //# sourceMappingURL=chunk-T4VQHMG4.js.map