sheetgl 0.0.0-stage → 2.0.2
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.
- package/LICENSE +21 -0
- package/README.md +167 -2
- package/bin/cli.mjs +370 -0
- package/dist/lib/sheetgl.cjs +5 -0
- package/dist/lib/sheetgl.cjs.map +1 -0
- package/dist/lib/sheetgl.js +14972 -0
- package/dist/lib/sheetgl.js.map +1 -0
- package/dist/lib/types/columns/ColumnTypeRegistry.d.ts +9 -0
- package/dist/lib/types/columns/ColumnTypeRegistry.d.ts.map +1 -0
- package/dist/lib/types/columns/IColumnTypePlugin.d.ts +68 -0
- package/dist/lib/types/columns/IColumnTypePlugin.d.ts.map +1 -0
- package/dist/lib/types/columns/initPlugins.d.ts +2 -0
- package/dist/lib/types/columns/initPlugins.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ActionColumn/ActionPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/ActionColumn/ActionPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ActionColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/ActionColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/BooleanColumn/BooleanPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/BooleanColumn/BooleanPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/BooleanColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/BooleanColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ColorColumn/ColorEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/ColorColumn/ColorEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ColorColumn/index.d.ts +4 -0
- package/dist/lib/types/columns/types/ColorColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/CurrencyColumn/CurrencyPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/CurrencyColumn/CurrencyPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/CurrencyColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/CurrencyColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DateColumn/DateEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/DateColumn/DateEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DateColumn/DatePainter.d.ts +3 -0
- package/dist/lib/types/columns/types/DateColumn/DatePainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DateColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/DateColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DateTimeColumn/DateTimeEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/DateTimeColumn/DateTimeEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DateTimeColumn/DateTimePainter.d.ts +7 -0
- package/dist/lib/types/columns/types/DateTimeColumn/DateTimePainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DateTimeColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/DateTimeColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DropdownColumn/DropdownPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/DropdownColumn/DropdownPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/DropdownColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/DropdownColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/EmailColumn/index.d.ts +4 -0
- package/dist/lib/types/columns/types/EmailColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/LookupColumn/LookupEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/LookupColumn/LookupEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/LookupColumn/LookupPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/LookupColumn/LookupPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/LookupColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/LookupColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/MultiSelectColumn/MultiSelectEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/MultiSelectColumn/MultiSelectEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/MultiSelectColumn/MultiSelectPainter.d.ts +4 -0
- package/dist/lib/types/columns/types/MultiSelectColumn/MultiSelectPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/MultiSelectColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/MultiSelectColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/NumberColumn/NumberEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/NumberColumn/NumberEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/NumberColumn/NumberPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/NumberColumn/NumberPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/NumberColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/NumberColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ObjectColumn/ObjectEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/ObjectColumn/ObjectEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ObjectColumn/ObjectPainter.d.ts +5 -0
- package/dist/lib/types/columns/types/ObjectColumn/ObjectPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ObjectColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/ObjectColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/PdfColumn/PdfPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/PdfColumn/PdfPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/PdfColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/PdfColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/PercentColumn/index.d.ts +5 -0
- package/dist/lib/types/columns/types/PercentColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/PhoneColumn/index.d.ts +4 -0
- package/dist/lib/types/columns/types/PhoneColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ProgressColumn/ProgressPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/ProgressColumn/ProgressPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/ProgressColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/ProgressColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/RatingColumn/RatingPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/RatingColumn/RatingPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/RatingColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/RatingColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/SelectColumn/SelectEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/SelectColumn/SelectEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/SelectColumn/SelectPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/SelectColumn/SelectPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/SelectColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/SelectColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/SparklineColumn/SparklinePainter.d.ts +3 -0
- package/dist/lib/types/columns/types/SparklineColumn/SparklinePainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/SparklineColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/SparklineColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/TextColumn/TextEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/TextColumn/TextEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/TextColumn/TextPainter.d.ts +3 -0
- package/dist/lib/types/columns/types/TextColumn/TextPainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/TextColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/TextColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/TimeColumn/TimeEditor.d.ts +4 -0
- package/dist/lib/types/columns/types/TimeColumn/TimeEditor.d.ts.map +1 -0
- package/dist/lib/types/columns/types/TimeColumn/TimePainter.d.ts +3 -0
- package/dist/lib/types/columns/types/TimeColumn/TimePainter.d.ts.map +1 -0
- package/dist/lib/types/columns/types/TimeColumn/index.d.ts +3 -0
- package/dist/lib/types/columns/types/TimeColumn/index.d.ts.map +1 -0
- package/dist/lib/types/columns/types/UrlColumn/index.d.ts +4 -0
- package/dist/lib/types/columns/types/UrlColumn/index.d.ts.map +1 -0
- package/dist/lib/types/core/FilterEngine.d.ts +33 -0
- package/dist/lib/types/core/FilterEngine.d.ts.map +1 -0
- package/dist/lib/types/core/GeometryEngine.d.ts +65 -0
- package/dist/lib/types/core/GeometryEngine.d.ts.map +1 -0
- package/dist/lib/types/core/GridApi.d.ts +66 -0
- package/dist/lib/types/core/GridApi.d.ts.map +1 -0
- package/dist/lib/types/core/GroupingEngine.d.ts +8 -0
- package/dist/lib/types/core/GroupingEngine.d.ts.map +1 -0
- package/dist/lib/types/core/HistoryManager.d.ts +18 -0
- package/dist/lib/types/core/HistoryManager.d.ts.map +1 -0
- package/dist/lib/types/core/SelectionModel.d.ts +17 -0
- package/dist/lib/types/core/SelectionModel.d.ts.map +1 -0
- package/dist/lib/types/core/SortEngine.d.ts +7 -0
- package/dist/lib/types/core/SortEngine.d.ts.map +1 -0
- package/dist/lib/types/core/ValidationEngine.d.ts +33 -0
- package/dist/lib/types/core/ValidationEngine.d.ts.map +1 -0
- package/dist/lib/types/data/BlockCache.d.ts +12 -0
- package/dist/lib/types/data/BlockCache.d.ts.map +1 -0
- package/dist/lib/types/data/LocalDataStore.d.ts +85 -0
- package/dist/lib/types/data/LocalDataStore.d.ts.map +1 -0
- package/dist/lib/types/data/RemoteDataStore.d.ts +94 -0
- package/dist/lib/types/data/RemoteDataStore.d.ts.map +1 -0
- package/dist/lib/types/hooks/useGridGeometry.d.ts +65 -0
- package/dist/lib/types/hooks/useGridGeometry.d.ts.map +1 -0
- package/dist/lib/types/hooks/useGridSelection.d.ts +43 -0
- package/dist/lib/types/hooks/useGridSelection.d.ts.map +1 -0
- package/dist/lib/types/i18n/IGridLocale.d.ts +25 -0
- package/dist/lib/types/i18n/IGridLocale.d.ts.map +1 -0
- package/dist/lib/types/i18n/LocaleEngine.d.ts +10 -0
- package/dist/lib/types/i18n/LocaleEngine.d.ts.map +1 -0
- package/dist/lib/types/i18n/locales/enUS.d.ts +3 -0
- package/dist/lib/types/i18n/locales/enUS.d.ts.map +1 -0
- package/dist/lib/types/i18n/locales/trTR.d.ts +3 -0
- package/dist/lib/types/i18n/locales/trTR.d.ts.map +1 -0
- package/dist/lib/types/index.d.ts +44 -0
- package/dist/lib/types/index.d.ts.map +1 -0
- package/dist/lib/types/overlays/BatchChangesModal.d.ts +19 -0
- package/dist/lib/types/overlays/BatchChangesModal.d.ts.map +1 -0
- package/dist/lib/types/overlays/ContextMenuOverlay.d.ts +44 -0
- package/dist/lib/types/overlays/ContextMenuOverlay.d.ts.map +1 -0
- package/dist/lib/types/overlays/DeleteConfirmProgressModal.d.ts +14 -0
- package/dist/lib/types/overlays/DeleteConfirmProgressModal.d.ts.map +1 -0
- package/dist/lib/types/overlays/DynamicCellEditor.d.ts +15 -0
- package/dist/lib/types/overlays/DynamicCellEditor.d.ts.map +1 -0
- package/dist/lib/types/overlays/HeaderFilterPopover.d.ts +33 -0
- package/dist/lib/types/overlays/HeaderFilterPopover.d.ts.map +1 -0
- package/dist/lib/types/overlays/PdfPreviewModalOverlay.d.ts +18 -0
- package/dist/lib/types/overlays/PdfPreviewModalOverlay.d.ts.map +1 -0
- package/dist/lib/types/overlays/SparklineModalOverlay.d.ts +18 -0
- package/dist/lib/types/overlays/SparklineModalOverlay.d.ts.map +1 -0
- package/dist/lib/types/renderer/CanvasRenderer.d.ts +45 -0
- package/dist/lib/types/renderer/CanvasRenderer.d.ts.map +1 -0
- package/dist/lib/types/renderer/GroupRowPainter.d.ts +10 -0
- package/dist/lib/types/renderer/GroupRowPainter.d.ts.map +1 -0
- package/dist/lib/types/renderer/SkeletonPainter.d.ts +5 -0
- package/dist/lib/types/renderer/SkeletonPainter.d.ts.map +1 -0
- package/dist/lib/types/theme/ColumnColorEngine.d.ts +52 -0
- package/dist/lib/types/theme/ColumnColorEngine.d.ts.map +1 -0
- package/dist/lib/types/theme/IGridTheme.d.ts +47 -0
- package/dist/lib/types/theme/IGridTheme.d.ts.map +1 -0
- package/dist/lib/types/theme/ThemeEngine.d.ts +10 -0
- package/dist/lib/types/theme/ThemeEngine.d.ts.map +1 -0
- package/dist/lib/types/theme/presets/appleDark.d.ts +3 -0
- package/dist/lib/types/theme/presets/appleDark.d.ts.map +1 -0
- package/dist/lib/types/theme/presets/appleLight.d.ts +3 -0
- package/dist/lib/types/theme/presets/appleLight.d.ts.map +1 -0
- package/dist/lib/types/theme/presets/googleDark.d.ts +3 -0
- package/dist/lib/types/theme/presets/googleDark.d.ts.map +1 -0
- package/dist/lib/types/theme/presets/googleLight.d.ts +3 -0
- package/dist/lib/types/theme/presets/googleLight.d.ts.map +1 -0
- package/dist/lib/types/types/filter.d.ts +28 -0
- package/dist/lib/types/types/filter.d.ts.map +1 -0
- package/dist/lib/types/types/grid.d.ts +464 -0
- package/dist/lib/types/types/grid.d.ts.map +1 -0
- package/dist/lib/types/types/group.d.ts +31 -0
- package/dist/lib/types/types/group.d.ts.map +1 -0
- package/dist/lib/types/types/store.d.ts +102 -0
- package/dist/lib/types/types/store.d.ts.map +1 -0
- package/dist/lib/types/ui/FormulaBar.d.ts +28 -0
- package/dist/lib/types/ui/FormulaBar.d.ts.map +1 -0
- package/dist/lib/types/ui/MaterialIcon.d.ts +28 -0
- package/dist/lib/types/ui/MaterialIcon.d.ts.map +1 -0
- package/dist/lib/types/ui/SheetGL.d.ts +73 -0
- package/dist/lib/types/ui/SheetGL.d.ts.map +1 -0
- package/dist/lib/types/ui/SheetGLLogo.d.ts +10 -0
- package/dist/lib/types/ui/SheetGLLogo.d.ts.map +1 -0
- package/dist/lib/types/ui/SummaryFooter.d.ts +31 -0
- package/dist/lib/types/ui/SummaryFooter.d.ts.map +1 -0
- package/dist/lib/types/ui/ToolBar.d.ts +48 -0
- package/dist/lib/types/ui/ToolBar.d.ts.map +1 -0
- package/dist/lib/types/version.d.ts +2 -0
- package/dist/lib/types/version.d.ts.map +1 -0
- package/package.json +77 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SheetGL Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,168 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SheetGL v2.0.2 ⚡
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Next-Generation High-Performance WebGL & Canvas Excel DataGrid for React**
|
|
4
|
+
> Combining **GPU-Accelerated Canvas Virtualization** and **Microsoft Excel UX** with **Enterprise DataGrid Architecture** (Full Event Lifecycle, Async Cascading Backend Lookups, Dynamic Summaries, Batch CRUD, and Role-Based Permissions). Zero dependencies, zero DOM bloat, **100% Free under the MIT License**.
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/sheetgl)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://react.dev)
|
|
9
|
+
[](https://www.typescriptlang.org)
|
|
10
|
+
[](#)
|
|
11
|
+
[](#)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 🌟 Key Highlights in v2.0.2
|
|
16
|
+
|
|
17
|
+
- 🏎️ **Ultra-Fast Canvas Virtualization:** Renders 10,000–100,000+ rows and dozens of columns on a single high-DPI `<canvas>` element with right-side live scroll indicators, quick jump controls (`⤒` / `⤓`), and automatic edge-scrolling during drag operations.
|
|
18
|
+
- 📐 **Complete Microsoft Excel UX:**
|
|
19
|
+
- **Bottom-Right Fill Handle & Smart AutoFill:** Drag the corner square across rows or columns to duplicate values or auto-increment sequential codes (`ACC-100001` → `ACC-100002`).
|
|
20
|
+
- **Right-Side Quick Cell Duplicate Handle (`+`):** Click or drag the right-edge `+` pill on any active selection to duplicate cell values.
|
|
21
|
+
- **Right-Click Context Menu:** Full context menu on cells, row numbers, and column headers (`Duplicate Row`, `Duplicate Cell Down (Ctrl+D)`, `Duplicate Cell Right (Ctrl+R)`, `Insert Row Above/Below`, `Delete Row`, `Filter by Cell Value`, `Pin Column`, `Configure Summary Type`).
|
|
22
|
+
- **Native Excel TSV Clipboard (`Ctrl+C` / `Ctrl+V`):** Copy and paste multi-row/multi-column ranges directly between Microsoft Excel, Google Sheets, and SheetGL.
|
|
23
|
+
- 🔄 **Enterprise Event Triggers & Async Cascading Backend Lookups:**
|
|
24
|
+
- Full lifecycle hooks: `onEditingStart`, `onCellValueChanging`, `onCellValueChanged`, `onRowInserting`, `onRowInserted`, `onRowUpdating`, `onRowUpdated`, `onRowRemoving`, `onRowRemoved`, `onSaving`, `onSaved`.
|
|
25
|
+
- **Column-Level `setCellValue` Cascading Engine:** When a column value changes (e.g. `city`, `category`, `status`, `balance`), automatically fetch dependent fields from your backend API and update related columns on the row with a live `⟳` row sync indicator!
|
|
26
|
+
- 🔒 **3-Tier Permissions (`write` / `readonly` / `read`):**
|
|
27
|
+
- Grid-level `permissions`, column-level `permission` (`'write' | 'readonly' | 'read'`), and row/cell conditional `canEdit(row, col)` + `validator(val, row)` rules.
|
|
28
|
+
- 💾 **Batch CRUD & Dirty State Engine:**
|
|
29
|
+
- Visual green top-right cell triangles for modified cells and green gutter indicators for newly added/duplicated rows.
|
|
30
|
+
- Atomic **Batch Save**, **Discard Changes**, and 100-step **Undo / Redo (`Ctrl+Z` / `Ctrl+Y`)**.
|
|
31
|
+
- 🧮 **Dynamic Summary Rows & Dual-Mode Excel Header Filters:**
|
|
32
|
+
- Switch any column's footer & group summary between `SUM`, `AVG`, `MIN`, `MAX`, `COUNT`, or `NONE` at runtime, plus live Excel status bar stats (`Count`, `SUM`, `AVG`, `MIN`, `MAX`) when multiple cells are selected.
|
|
33
|
+
- Excel Header Filter Popover with **Distinct Value Checkbox List** (preserving checked state across searches and reopenings) and **Condition Rules** (`contains`, `=`, `<>`, `>`, `<`, `between`).
|
|
34
|
+
- 🌗 **Interactive Landing Page & Full Documentation Portal (Dark & Light Mode):**
|
|
35
|
+
- Switch seamlessly between **Excel Studio**, **Product Landing Page**, and **Interactive Documentation Portal** in both Dark and Light modes (`TR` & `EN`).
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## ⚖️ Comparison: SheetGL vs. Traditional Grids
|
|
40
|
+
|
|
41
|
+
| Feature | SheetGL v2.0.2 | Traditional Enterprise Grids | AG-Grid Enterprise | Standard React Table |
|
|
42
|
+
| :--- | :---: | :---: | :---: | :---: |
|
|
43
|
+
| **Licensing** | **Free (MIT)** | Commercial ($1,200+/yr) | Commercial ($1,200+/yr) | Free (MIT) |
|
|
44
|
+
| **Rendering Engine** | **HTML5 Canvas 2D** | DOM Virtualization | DOM Virtualization | 100% DOM Nodes |
|
|
45
|
+
| **DOM Overhead** | **1 Canvas Element** | 500+ DOM Nodes | 400+ DOM Nodes | 1,000+ DOM Nodes |
|
|
46
|
+
| **Scroll Performance (100k rows)** | **Ultra-Smooth** | Moderate | Fast | Lag / Crash |
|
|
47
|
+
| **Memory Footprint** | **~15 MB** | ~60 MB | ~55 MB | 150+ MB |
|
|
48
|
+
| **Fill Handle & Quick Duplicate** | **Built-in** | ❌ Manual | Plugin | ❌ Not supported |
|
|
49
|
+
| **Async Cascading Lookups** | **Built-in** | Supported | ❌ Complex | ❌ Not supported |
|
|
50
|
+
| **Dual-Mode Excel Filters** | **Built-in** | Built-in | Built-in | ❌ Requires custom code |
|
|
51
|
+
| **Batch CRUD with Dirty Flags** | **Built-in** | Supported | Supported | ❌ Not supported |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 📦 Installation & NPX CLI Setup
|
|
56
|
+
|
|
57
|
+
### 1. Install via Package Manager (`npm` / `pnpm` / `yarn`)
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Using npm
|
|
61
|
+
npm install sheetgl
|
|
62
|
+
|
|
63
|
+
# Using pnpm
|
|
64
|
+
pnpm add sheetgl
|
|
65
|
+
|
|
66
|
+
# Using yarn
|
|
67
|
+
yarn add sheetgl
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Instant Setup via `npx sheetgl` CLI
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Generate a ready-to-use <SheetGLGrid /> component in your existing React project
|
|
74
|
+
npx sheetgl init
|
|
75
|
+
|
|
76
|
+
# Or scaffold a complete standalone Vite + React + TypeScript + SheetGL starter app
|
|
77
|
+
npx sheetgl create my-excel-app
|
|
78
|
+
|
|
79
|
+
# Run diagnostics on package build & environment
|
|
80
|
+
npx sheetgl doctor
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 🚀 Quick Start
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
import React, { useMemo, useState } from 'react';
|
|
89
|
+
import { SheetGL, ColumnDef } from 'sheetgl';
|
|
90
|
+
|
|
91
|
+
export function SimpleGrid() {
|
|
92
|
+
const [data] = useState([
|
|
93
|
+
{ id: 1, name: 'Acme Corporation', sector: 'Enterprise SaaS', balance: 54200.5, status: 'active', rating: 5 },
|
|
94
|
+
{ id: 2, name: 'Quantum AI Systems', sector: 'Robotics', balance: 129000.0, status: 'in-review', rating: 4 },
|
|
95
|
+
{ id: 3, name: 'Apex Global Logistics', sector: 'Logistics', balance: 34100.25, status: 'pending', rating: 3 },
|
|
96
|
+
]);
|
|
97
|
+
|
|
98
|
+
const columns: ColumnDef[] = useMemo(() => [
|
|
99
|
+
{ id: 'id', title: 'ID', type: 'number', width: 60, pinned: 'left' },
|
|
100
|
+
{ id: 'name', title: 'Company Name', type: 'text', width: 220, sortable: true, filterable: true },
|
|
101
|
+
{ id: 'sector', title: 'Industry Sector', type: 'text', width: 160, groupable: true },
|
|
102
|
+
{ id: 'balance', title: 'Balance ($)', type: 'currency', width: 140, currencySymbol: '$', summaryType: 'sum' },
|
|
103
|
+
{ id: 'rating', title: 'Trust Score', type: 'rating', width: 120 },
|
|
104
|
+
], []);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div style={{ width: '100vw', height: '100vh' }}>
|
|
108
|
+
<SheetGL
|
|
109
|
+
dataSource={data}
|
|
110
|
+
columns={columns}
|
|
111
|
+
theme="apple-dark"
|
|
112
|
+
locale="en"
|
|
113
|
+
onCellValueChanged={(e) => {
|
|
114
|
+
console.log(`Cell ${e.column.id} changed:`, e.oldValue, '->', e.newValue);
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 📚 Comprehensive Documentation
|
|
125
|
+
|
|
126
|
+
Explore detailed architectural guides and API references in the [`docs/`](docs/) directory:
|
|
127
|
+
|
|
128
|
+
- [**Documentation Index**](docs/INDEX.md)
|
|
129
|
+
- [**Architecture & Technical Design**](docs/ARCHITECTURE.md): Canvas 2D render loop, prefix-sum binary search, zero-DOM vs micro-DOM lifecycle, and dual-bridge theming.
|
|
130
|
+
- [**API Reference**](docs/API_REFERENCE.md): Full TypeScript interfaces for `<SheetGL />`, `ColumnDef`, `IDataStore`, `IColumnTypePlugin`, and `IGridLocale`.
|
|
131
|
+
- [**Custom Column Plugins Guide**](docs/CUSTOM_COLUMN_GUIDE.md): Building Zero-DOM canvas painters and Micro-DOM cell editors.
|
|
132
|
+
- [**Remote Operations & Enterprise REST DTO Guide**](docs/REMOTE_OPERATIONS_GUIDE.md): Connecting `RemoteDataStore` to server-side APIs with Node.js, ASP.NET Core, and FastAPI backend examples.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## ⌨️ Google Sheets & Excel Keyboard Shortcuts
|
|
137
|
+
|
|
138
|
+
- `Arrow Keys`: Move active cell selection.
|
|
139
|
+
- `Tab` / `Shift + Tab`: Move to next/previous cell horizontally.
|
|
140
|
+
- `Enter` / `F2`: Start editing active cell.
|
|
141
|
+
- `Escape`: Cancel editing or clear selection.
|
|
142
|
+
- `Ctrl + D`: Duplicate cell value or row downwards.
|
|
143
|
+
- `Ctrl + R`: Duplicate cell value to the right.
|
|
144
|
+
- `Shift + Click`: Multi-column natural sorting.
|
|
145
|
+
- `Ctrl + C` / `Cmd + C`: Copy selected range as TSV (pasteable into Excel & Sheets).
|
|
146
|
+
- `Ctrl + V` / `Cmd + V`: Paste TSV matrix into active cell selection.
|
|
147
|
+
- `Ctrl + Z` / `Ctrl + Y`: Undo and Redo operations (100 steps).
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 🛠️ Development & Building
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Install dependencies
|
|
155
|
+
npm install
|
|
156
|
+
|
|
157
|
+
# Start development server with live HMR
|
|
158
|
+
npm run dev
|
|
159
|
+
|
|
160
|
+
# Run strict TypeScript check and production build
|
|
161
|
+
npm run build
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 📄 License
|
|
167
|
+
|
|
168
|
+
This project is licensed under the **MIT License** — free for commercial and open-source use without license fees or telemetry.
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
const pkgRoot = path.resolve(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
const CYAN = '\x1b[36m';
|
|
13
|
+
const GREEN = '\x1b[32m';
|
|
14
|
+
const YELLOW = '\x1b[33m';
|
|
15
|
+
const BOLD = '\x1b[1m';
|
|
16
|
+
const DIM = '\x1b[2m';
|
|
17
|
+
const RESET = '\x1b[0m';
|
|
18
|
+
|
|
19
|
+
function readPkgVersion() {
|
|
20
|
+
try {
|
|
21
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, 'package.json'), 'utf8'));
|
|
22
|
+
return pkg.version || '2.0.2';
|
|
23
|
+
} catch {
|
|
24
|
+
return '2.0.2';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function printBanner() {
|
|
29
|
+
const version = readPkgVersion();
|
|
30
|
+
console.log(`
|
|
31
|
+
${CYAN}${BOLD} ╔══════════════════════════════════════════════════════════════╗
|
|
32
|
+
║ ⚡ SheetGL v${version} — Enterprise Canvas Excel DataGrid ║
|
|
33
|
+
╚══════════════════════════════════════════════════════════════╝${RESET}
|
|
34
|
+
`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function printHelp() {
|
|
38
|
+
printBanner();
|
|
39
|
+
console.log(`${BOLD}Usage:${RESET}
|
|
40
|
+
npx sheetgl <command> [options]
|
|
41
|
+
|
|
42
|
+
${BOLD}Commands:${RESET}
|
|
43
|
+
${GREEN}init${RESET} [target-file] Generate a ready-to-use <SheetGLGrid /> component in your React project
|
|
44
|
+
(Default: src/components/SheetGLGrid.tsx)
|
|
45
|
+
${GREEN}create${RESET} <project-name> Scaffold a new Vite + React + TypeScript + SheetGL starter app
|
|
46
|
+
${GREEN}demo${RESET} Launch the interactive SheetGL Studio & Docs server
|
|
47
|
+
${GREEN}doctor${RESET} Verify Node.js, package build artifacts, and environment readiness
|
|
48
|
+
${GREEN}help${RESET} Show this help message
|
|
49
|
+
|
|
50
|
+
${BOLD}Examples:${RESET}
|
|
51
|
+
${DIM}# 1. Install SheetGL into an existing React project:${RESET}
|
|
52
|
+
npm install sheetgl
|
|
53
|
+
|
|
54
|
+
${DIM}# 2. Generate a full-featured SheetGLGrid.tsx component:${RESET}
|
|
55
|
+
npx sheetgl init
|
|
56
|
+
|
|
57
|
+
${DIM}# 3. Create a brand-new starter project:${RESET}
|
|
58
|
+
npx sheetgl create my-excel-app
|
|
59
|
+
`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const STARTER_COMPONENT_TEMPLATE = `import React, { useMemo, useState } from 'react';
|
|
63
|
+
import { SheetGL, ColumnDef } from 'sheetgl';
|
|
64
|
+
|
|
65
|
+
const STATUS_OPTIONS = [
|
|
66
|
+
{ value: 'active', label: 'Active', bg: '#DCFCE7', fg: '#166534', darkBg: 'rgba(48, 209, 88, 0.16)', darkFg: '#30D158' },
|
|
67
|
+
{ value: 'pending', label: 'Pending', bg: '#FEF3C7', fg: '#92400E', darkBg: 'rgba(255, 159, 10, 0.16)', darkFg: '#FF9F0A' },
|
|
68
|
+
{ value: 'review', label: 'In Review', bg: '#E0F2FE', fg: '#075985', darkBg: 'rgba(10, 132, 255, 0.16)', darkFg: '#64D2FF' },
|
|
69
|
+
{ value: 'rejected', label: 'Cancelled', bg: '#FEE2E2', fg: '#991B1B', darkBg: 'rgba(255, 69, 58, 0.16)', darkFg: '#FF453A' },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const CITY_OPTIONS = [
|
|
73
|
+
{ value: 'New York', label: 'New York (US)' },
|
|
74
|
+
{ value: 'London', label: 'London (UK)' },
|
|
75
|
+
{ value: 'Berlin', label: 'Berlin (DE)' },
|
|
76
|
+
{ value: 'Tokyo', label: 'Tokyo (JP)' },
|
|
77
|
+
{ value: 'Istanbul', label: 'Istanbul (TR)' },
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
const TAG_OPTIONS = [
|
|
81
|
+
{ value: 'SOC2', label: 'SOC2', bg: '#E0E7FF', fg: '#3730A3' },
|
|
82
|
+
{ value: 'GDPR', label: 'GDPR', bg: '#DBEAFE', fg: '#1E40AF' },
|
|
83
|
+
{ value: 'ISO27001', label: 'ISO-27001', bg: '#DCFCE7', fg: '#166534' },
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
export function SheetGLGrid() {
|
|
87
|
+
const [data] = useState(() =>
|
|
88
|
+
Array.from({ length: 1000 }, (_, idx) => {
|
|
89
|
+
const i = idx + 1;
|
|
90
|
+
return {
|
|
91
|
+
id: i,
|
|
92
|
+
code: \`ACC-\${10000 + i}\`,
|
|
93
|
+
company: ['Acme Global Holding', 'Vertex BioPharma Labs', 'Nexus Cloud Technologies', 'Quantum Dynamics'][i % 4],
|
|
94
|
+
city: CITY_OPTIONS[i % CITY_OPTIONS.length].value,
|
|
95
|
+
status: STATUS_OPTIONS[i % STATUS_OPTIONS.length].value,
|
|
96
|
+
tags: i % 2 === 0 ? ['SOC2', 'GDPR'] : ['ISO27001'],
|
|
97
|
+
balance: Math.round((25000 + (i * 137) % 80000) * 100) / 100,
|
|
98
|
+
taxRate: 20,
|
|
99
|
+
netBalance: Math.round((25000 + (i * 137) % 80000) * 0.8 * 100) / 100,
|
|
100
|
+
progress: (i * 9) % 101,
|
|
101
|
+
rating: (i % 5) + 1,
|
|
102
|
+
isApproved: i % 3 === 0,
|
|
103
|
+
date: '2025-05-15',
|
|
104
|
+
lastAuditAt: '2025-05-15 14:30',
|
|
105
|
+
cutoffTime: '17:00',
|
|
106
|
+
sparkline: [25, 42, 38, 65, 58, 78, 92],
|
|
107
|
+
};
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const columns = useMemo<ColumnDef[]>(
|
|
112
|
+
() => [
|
|
113
|
+
{ id: 'id', title: 'ID', type: 'number', decimalDigits: 0, width: 65, pinned: 'left', readonly: true },
|
|
114
|
+
{ id: 'code', title: 'Account Code', type: 'text', width: 125, pinned: 'left' },
|
|
115
|
+
{ id: 'company', title: 'Company', type: 'text', width: 220, pinned: 'left' },
|
|
116
|
+
{
|
|
117
|
+
id: 'city',
|
|
118
|
+
title: 'City (Dropdown) ⚡',
|
|
119
|
+
type: 'dropdown',
|
|
120
|
+
width: 160,
|
|
121
|
+
options: CITY_OPTIONS,
|
|
122
|
+
setCellValue: async (newData, newCity, currentRow) => {
|
|
123
|
+
const taxMap: Record<string, number> = { 'New York': 21, London: 19, Berlin: 25, Tokyo: 23, Istanbul: 20 };
|
|
124
|
+
const tax = taxMap[newCity] ?? 20;
|
|
125
|
+
newData.taxRate = tax;
|
|
126
|
+
newData.netBalance = Math.round((Number(currentRow.balance) || 0) * (1 - tax / 100) * 100) / 100;
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{ id: 'status', title: 'Status (Select)', type: 'select', width: 135, options: STATUS_OPTIONS },
|
|
130
|
+
{ id: 'tags', title: 'Compliance (Multi)', type: 'multiselect', width: 195, options: TAG_OPTIONS },
|
|
131
|
+
{ id: 'balance', title: 'Gross Balance ($)', type: 'currency', width: 150, currencySymbol: '$', summaryType: 'sum' },
|
|
132
|
+
{ id: 'taxRate', title: 'Tax (%)', type: 'progress', width: 110, summaryType: 'avg' },
|
|
133
|
+
{ id: 'netBalance', title: 'Net Balance ($)', type: 'currency', width: 150, currencySymbol: '$', readonly: true, summaryType: 'sum' },
|
|
134
|
+
{ id: 'isApproved', title: 'Approved', type: 'boolean', width: 90 },
|
|
135
|
+
{ id: 'rating', title: 'Rating', type: 'rating', width: 120, summaryType: 'avg' },
|
|
136
|
+
{ id: 'date', title: 'Date', type: 'date', width: 135 },
|
|
137
|
+
{ id: 'lastAuditAt', title: 'Audit (DateTime)', type: 'datetime', width: 170 },
|
|
138
|
+
{ id: 'cutoffTime', title: 'Cut-off (Time)', type: 'time', width: 125 },
|
|
139
|
+
{ id: 'sparkline', title: '7D Trend', type: 'sparkline', width: 135 },
|
|
140
|
+
],
|
|
141
|
+
[]
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<div style={{ width: '100%', height: '100vh' }}>
|
|
146
|
+
<SheetGL
|
|
147
|
+
dataSource={data}
|
|
148
|
+
columns={columns}
|
|
149
|
+
theme="apple-dark"
|
|
150
|
+
locale="tr"
|
|
151
|
+
batchEditMode={true}
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export default SheetGLGrid;
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
function handleInit(rawArgs) {
|
|
161
|
+
printBanner();
|
|
162
|
+
let dirOpt = null;
|
|
163
|
+
let nameOpt = null;
|
|
164
|
+
let rowsOpt = 1000;
|
|
165
|
+
let positionalPath = null;
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
168
|
+
const arg = rawArgs[i];
|
|
169
|
+
if (arg === '--dir' || arg === '-d') {
|
|
170
|
+
dirOpt = rawArgs[++i];
|
|
171
|
+
} else if (arg === '--name' || arg === '-n') {
|
|
172
|
+
nameOpt = rawArgs[++i];
|
|
173
|
+
} else if (arg === '--rows' || arg === '-r') {
|
|
174
|
+
const parsed = parseInt(rawArgs[++i], 10);
|
|
175
|
+
if (!Number.isNaN(parsed) && parsed > 0) rowsOpt = parsed;
|
|
176
|
+
} else if (!arg.startsWith('-') && !positionalPath) {
|
|
177
|
+
positionalPath = arg;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const componentName = (nameOpt || 'SheetGLGrid').replace(/\.(tsx|ts|jsx|js)$/i, '');
|
|
182
|
+
const defaultRelPath = path.join(dirOpt || 'src/components', `${componentName}.tsx`);
|
|
183
|
+
const outPath = path.resolve(process.cwd(), positionalPath || defaultRelPath);
|
|
184
|
+
const outDir = path.dirname(outPath);
|
|
185
|
+
|
|
186
|
+
if (!fs.existsSync(outDir)) {
|
|
187
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const customizedTemplate = STARTER_COMPONENT_TEMPLATE
|
|
191
|
+
.replace(/SheetGLGrid/g, componentName)
|
|
192
|
+
.replace('length: 1000', `length: ${rowsOpt}`);
|
|
193
|
+
|
|
194
|
+
fs.writeFileSync(outPath, customizedTemplate, 'utf8');
|
|
195
|
+
console.log(`${GREEN}✔ Created SheetGL starter component at:${RESET} ${BOLD}${outPath}${RESET}`);
|
|
196
|
+
console.log(`
|
|
197
|
+
${BOLD}Next steps:${RESET}
|
|
198
|
+
1. Ensure ${CYAN}sheetgl${RESET} is installed in your project:
|
|
199
|
+
${YELLOW}npm install sheetgl${RESET}
|
|
200
|
+
2. Import and render ${CYAN}<${componentName} />${RESET} in your ${BOLD}App.tsx${RESET}:
|
|
201
|
+
${DIM}import { ${componentName} } from './components/${componentName}';${RESET}
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function handleCreate(projectName) {
|
|
206
|
+
printBanner();
|
|
207
|
+
if (!projectName) {
|
|
208
|
+
console.error(`${YELLOW}⚠ Please specify a project directory name:${RESET}\n npx sheetgl create my-sheetgl-app`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
213
|
+
if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {
|
|
214
|
+
console.error(`${YELLOW}⚠ Target directory "${projectName}" already exists and is not empty.${RESET}`);
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fs.mkdirSync(path.join(targetDir, 'src', 'components'), { recursive: true });
|
|
219
|
+
|
|
220
|
+
const appPkg = {
|
|
221
|
+
name: projectName.toLowerCase().replace(/[^a-z0-9-_]/g, '-'),
|
|
222
|
+
private: true,
|
|
223
|
+
version: '0.1.0',
|
|
224
|
+
type: 'module',
|
|
225
|
+
scripts: {
|
|
226
|
+
dev: 'vite',
|
|
227
|
+
build: 'tsc && vite build',
|
|
228
|
+
preview: 'vite preview',
|
|
229
|
+
},
|
|
230
|
+
dependencies: {
|
|
231
|
+
react: '^19.0.0',
|
|
232
|
+
'react-dom': '^19.0.0',
|
|
233
|
+
sheetgl: `^${readPkgVersion()}`,
|
|
234
|
+
},
|
|
235
|
+
devDependencies: {
|
|
236
|
+
'@types/react': '^19.0.0',
|
|
237
|
+
'@types/react-dom': '^19.0.0',
|
|
238
|
+
'@vitejs/plugin-react': '^4.3.0',
|
|
239
|
+
typescript: '^5.6.0',
|
|
240
|
+
vite: '^6.0.0',
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
fs.writeFileSync(path.join(targetDir, 'package.json'), JSON.stringify(appPkg, null, 2), 'utf8');
|
|
245
|
+
fs.writeFileSync(
|
|
246
|
+
path.join(targetDir, 'index.html'),
|
|
247
|
+
`<!doctype html>
|
|
248
|
+
<html lang="en">
|
|
249
|
+
<head>
|
|
250
|
+
<meta charset="UTF-8" />
|
|
251
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
252
|
+
<title>${projectName} — SheetGL</title>
|
|
253
|
+
</head>
|
|
254
|
+
<body style="margin:0;padding:0;overflow:hidden;">
|
|
255
|
+
<div id="root"></div>
|
|
256
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
257
|
+
</body>
|
|
258
|
+
</html>
|
|
259
|
+
`,
|
|
260
|
+
'utf8'
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
fs.writeFileSync(
|
|
264
|
+
path.join(targetDir, 'vite.config.ts'),
|
|
265
|
+
`import { defineConfig } from 'vite';
|
|
266
|
+
import react from '@vitejs/plugin-react';
|
|
267
|
+
|
|
268
|
+
export default defineConfig({
|
|
269
|
+
plugins: [react()],
|
|
270
|
+
});
|
|
271
|
+
`,
|
|
272
|
+
'utf8'
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
fs.writeFileSync(
|
|
276
|
+
path.join(targetDir, 'tsconfig.json'),
|
|
277
|
+
JSON.stringify(
|
|
278
|
+
{
|
|
279
|
+
compilerOptions: {
|
|
280
|
+
target: 'ES2022',
|
|
281
|
+
lib: ['ES2022', 'DOM', 'DOM.Iterable'],
|
|
282
|
+
module: 'ESNext',
|
|
283
|
+
moduleResolution: 'bundler',
|
|
284
|
+
jsx: 'react-jsx',
|
|
285
|
+
strict: true,
|
|
286
|
+
skipLibCheck: true,
|
|
287
|
+
noEmit: true,
|
|
288
|
+
},
|
|
289
|
+
include: ['src'],
|
|
290
|
+
},
|
|
291
|
+
null,
|
|
292
|
+
2
|
|
293
|
+
),
|
|
294
|
+
'utf8'
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
fs.writeFileSync(path.join(targetDir, 'src', 'components', 'SheetGLGrid.tsx'), STARTER_COMPONENT_TEMPLATE, 'utf8');
|
|
298
|
+
fs.writeFileSync(
|
|
299
|
+
path.join(targetDir, 'src', 'App.tsx'),
|
|
300
|
+
`import React from 'react';
|
|
301
|
+
import { SheetGLGrid } from './components/SheetGLGrid';
|
|
302
|
+
|
|
303
|
+
export default function App() {
|
|
304
|
+
return <SheetGLGrid />;
|
|
305
|
+
}
|
|
306
|
+
`,
|
|
307
|
+
'utf8'
|
|
308
|
+
);
|
|
309
|
+
fs.writeFileSync(
|
|
310
|
+
path.join(targetDir, 'src', 'main.tsx'),
|
|
311
|
+
`import React from 'react';
|
|
312
|
+
import ReactDOM from 'react-dom/client';
|
|
313
|
+
import App from './App';
|
|
314
|
+
|
|
315
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
316
|
+
<React.StrictMode>
|
|
317
|
+
<App />
|
|
318
|
+
</React.StrictMode>
|
|
319
|
+
);
|
|
320
|
+
`,
|
|
321
|
+
'utf8'
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
console.log(`${GREEN}✔ Scaffolded new SheetGL project in:${RESET} ${BOLD}${targetDir}${RESET}\n`);
|
|
325
|
+
console.log(`${BOLD}Run the following commands to start:${RESET}
|
|
326
|
+
${CYAN}cd ${projectName}${RESET}
|
|
327
|
+
${CYAN}npm install${RESET}
|
|
328
|
+
${CYAN}npm run dev${RESET}
|
|
329
|
+
`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function handleDoctor() {
|
|
333
|
+
printBanner();
|
|
334
|
+
const esmBundle = path.join(pkgRoot, 'dist', 'lib', 'sheetgl.js');
|
|
335
|
+
const cjsBundle = path.join(pkgRoot, 'dist', 'lib', 'sheetgl.cjs');
|
|
336
|
+
const dtsBundle = path.join(pkgRoot, 'dist', 'lib', 'types', 'index.d.ts');
|
|
337
|
+
const demoIndex = path.join(pkgRoot, 'dist', 'index.html');
|
|
338
|
+
|
|
339
|
+
console.log(`${BOLD}Environment & Package Diagnostics:${RESET}`);
|
|
340
|
+
console.log(` • Node.js Runtime : ${GREEN}${process.version}${RESET}`);
|
|
341
|
+
console.log(` • Platform / Arch : ${process.platform} (${process.arch})`);
|
|
342
|
+
console.log(` • ESM Library : ${fs.existsSync(esmBundle) ? `${GREEN}✔ Ready (dist/lib/sheetgl.js)${RESET}` : `${YELLOW}⚠ Missing (run npm run build:lib)${RESET}`}`);
|
|
343
|
+
console.log(` • CJS Library : ${fs.existsSync(cjsBundle) ? `${GREEN}✔ Ready (dist/lib/sheetgl.cjs)${RESET}` : `${YELLOW}⚠ Missing (run npm run build:lib)${RESET}`}`);
|
|
344
|
+
console.log(` • TypeScript .d.ts: ${fs.existsSync(dtsBundle) ? `${GREEN}✔ Ready (dist/lib/types/index.d.ts)${RESET}` : `${YELLOW}⚠ Missing (run npm run build:lib)${RESET}`}`);
|
|
345
|
+
console.log(` • Demo SPA Bundle : ${fs.existsSync(demoIndex) ? `${GREEN}✔ Ready (dist/index.html)${RESET}` : `${YELLOW}⚠ Missing (run npm run build:demo)${RESET}`}`);
|
|
346
|
+
console.log('');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function handleDemo() {
|
|
350
|
+
printBanner();
|
|
351
|
+
console.log(`${CYAN}Starting SheetGL Studio development server...${RESET}\n`);
|
|
352
|
+
spawnSync('npx', ['vite'], { cwd: pkgRoot, stdio: 'inherit', shell: true });
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const args = process.argv.slice(2);
|
|
356
|
+
const cmd = (args[0] || 'help').toLowerCase();
|
|
357
|
+
|
|
358
|
+
if (cmd === 'init' || cmd === 'setup') {
|
|
359
|
+
handleInit(args.slice(1));
|
|
360
|
+
} else if (cmd === 'create') {
|
|
361
|
+
handleCreate(args[1]);
|
|
362
|
+
} else if (cmd === 'doctor' || cmd === 'info' || cmd === 'check') {
|
|
363
|
+
handleDoctor();
|
|
364
|
+
} else if (cmd === 'demo' || cmd === 'studio' || cmd === 'start') {
|
|
365
|
+
handleDemo();
|
|
366
|
+
} else if (cmd === '-v' || cmd === '--version' || cmd === 'version') {
|
|
367
|
+
console.log(readPkgVersion());
|
|
368
|
+
} else {
|
|
369
|
+
printHelp();
|
|
370
|
+
}
|