@ishibashi0112/spreadsheet-grid 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/ActiveCellOverlay.d.ts +14 -0
- package/dist/CellEditorLayer.d.ts +18 -0
- package/dist/SelectionOverlay.d.ts +14 -0
- package/dist/SpreadsheetGrid.d.ts +3 -0
- package/dist/hooks/useColumnAutosizeRunner.d.ts +16 -0
- package/dist/hooks/useColumnChooserController.d.ts +18 -0
- package/dist/hooks/useColumnHeaderDragController.d.ts +24 -0
- package/dist/hooks/useColumnMenuController.d.ts +23 -0
- package/dist/hooks/useColumnSelectOptionsCollector.d.ts +18 -0
- package/dist/hooks/useFilterPopoverController.d.ts +30 -0
- package/dist/hooks/useGridBarContext.d.ts +17 -0
- package/dist/hooks/useGridClipboardController.d.ts +22 -0
- package/dist/hooks/useGridEditController.d.ts +23 -0
- package/dist/hooks/useGridKeyboardInteractions.d.ts +21 -0
- package/dist/hooks/useGridPointerInteractions.d.ts +46 -0
- package/dist/hooks/useGridViewportSync.d.ts +21 -0
- package/dist/hooks/useServerSideRowModel.d.ts +16 -0
- package/dist/hooks/useSortManagementController.d.ts +18 -0
- package/dist/index.cjs +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5024 -0
- package/dist/logic/columnAutosize.d.ts +18 -0
- package/dist/logic/cx.d.ts +1 -0
- package/dist/logic/domGuards.d.ts +7 -0
- package/dist/logic/filtering.d.ts +12 -0
- package/dist/logic/geometry.d.ts +72 -0
- package/dist/logic/rowHeightStore.d.ts +13 -0
- package/dist/logic/selectOptions.d.ts +9 -0
- package/dist/logic/serverSideBlocks.d.ts +2 -0
- package/dist/logic/serverSideCache.d.ts +13 -0
- package/dist/logic/serverSideQuery.d.ts +7 -0
- package/dist/logic/sorting.d.ts +11 -0
- package/dist/logic/verticalGeometry.d.ts +50 -0
- package/dist/model/gridActions.d.ts +87 -0
- package/dist/model/gridReducer.d.ts +4 -0
- package/dist/model/gridSelectors.d.ts +40 -0
- package/dist/model/gridTypes.d.ts +267 -0
- package/dist/style.css +2 -0
- package/dist/utils/clipboard.d.ts +25 -0
- package/dist/utils/excelColumnName.d.ts +1 -0
- package/dist/utils/permissions.d.ts +4 -0
- package/dist/utils/scheduler.d.ts +1 -0
- package/dist/view/ColumnChooserPanel.d.ts +23 -0
- package/dist/view/ColumnFilterPopover.d.ts +40 -0
- package/dist/view/ColumnMenuPopover.d.ts +25 -0
- package/dist/view/DefaultGridBottomBar.d.ts +6 -0
- package/dist/view/DefaultGridTopBar.d.ts +6 -0
- package/dist/view/GridBodyLayer.d.ts +43 -0
- package/dist/view/GridHeaderRow.d.ts +41 -0
- package/dist/view/SortManagementPanel.d.ts +24 -0
- package/dist/view/gridBarHelpers.d.ts +12 -0
- package/package.json +89 -0
package/dist/style.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@layer ssg-base{.ssg-root{--ssg-accent:#3461c9;--ssg-accent-strong:#1d4ed8;--ssg-line:#f1f5f9;--ssg-line-strong:#e5e7eb;--ssg-divider:#d7dce3;--ssg-header-bg:#f8fafc;--ssg-row-hover-bg:#f1f5f9;--ssg-glyph:#94a3b8;--ssg-glyph-hover:#475569;--ssg-icon-hover-bg:#d6dee8;--ssg-icon-active-bg:#e3e9f5;--ssg-icon-active-bg-hover:#d4ddf0;--ssg-icon-active-border:#c7d3ea;--ssg-cell-bg:#fff;--ssg-cell-text:#0f172a;--ssg-readonly-bg:#f8fafc;--ssg-readonly-text:#64748b;--ssg-readonly-hover-bg:#eef2f7;--ssg-header-text:#334155;--ssg-header-hover-bg:#e2e8f0;--ssg-select-bg:#e3e9f5;--ssg-select-bg-hover:#ccd7ee;--ssg-selection-fill:#3461c914;--ssg-radius:8px;--ssg-icon-btn-size:22px;border:1px solid var(--ssg-divider);border-radius:var(--ssg-radius);background-color:var(--ssg-cell-bg);overflow:hidden;box-shadow:0 4px 14px #0f172a0a}.ssg-icon-btn{width:var(--ssg-icon-btn-size);height:var(--ssg-icon-btn-size);color:var(--ssg-glyph);cursor:pointer;background-color:#0000;border:1px solid #0000;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;font-size:11px;line-height:1;transition:background-color .1s,color .1s;display:inline-flex}.ssg-icon-btn:hover{background-color:var(--ssg-icon-hover-bg);color:var(--ssg-glyph-hover)}.ssg-icon-btn--active{border-color:var(--ssg-icon-active-border);background-color:var(--ssg-icon-active-bg);color:var(--ssg-accent)}.ssg-icon-btn--active:hover{background-color:var(--ssg-icon-active-bg-hover);color:var(--ssg-accent)}.ssg-body-cell{box-sizing:border-box;border-right:1px solid var(--ssg-line);border-bottom:1px solid var(--ssg-line-strong);background-color:var(--ssg-cell-bg);color:var(--ssg-cell-text);white-space:nowrap;cursor:default;-webkit-user-select:none;user-select:none;outline:none;align-items:center;padding:0 10px;display:flex;position:absolute;top:0;overflow:hidden}.ssg-body-cell--autoheight{white-space:normal;word-break:break-word;align-items:flex-start;overflow:visible}.ssg-body-cell--row-hovered{background-color:var(--ssg-row-hover-bg)}.ssg-body-cell--readonly{background-color:var(--ssg-readonly-bg);color:var(--ssg-readonly-text)}.ssg-body-cell--readonly.ssg-body-cell--row-hovered{background-color:var(--ssg-readonly-hover-bg)}.ssg-header-row{z-index:6;background-color:var(--ssg-header-bg);position:sticky;top:0}.ssg-header-cell{box-sizing:border-box;border-right:1px solid var(--ssg-line);border-bottom:1px solid var(--ssg-divider);background-color:var(--ssg-header-bg);color:var(--ssg-header-text);align-items:center;gap:8px;padding:0 10px;font-size:13px;font-weight:600;display:flex;position:absolute;top:0}.ssg-header-cell--hovered{background-color:var(--ssg-header-hover-bg)}.ssg-header-cell--selected{background-color:var(--ssg-select-bg)}.ssg-header-cell--selected.ssg-header-cell--hovered{background-color:var(--ssg-select-bg-hover)}.ssg-row-header-cell{z-index:5;justify-content:center;font-weight:500;left:0}.ssg-corner-cell{z-index:7;border-right:1px solid var(--ssg-line-strong);justify-content:center;padding:0;line-height:1;left:0}.ssg-active-cell-overlay{box-sizing:border-box;border:2px solid var(--ssg-accent);pointer-events:none;z-index:4}.ssg-selection-overlay{box-sizing:border-box;border:2px solid var(--ssg-accent);background-color:var(--ssg-selection-fill);pointer-events:none;z-index:2}.ssg-cell-editor{pointer-events:none;z-index:5}.ssg-cell-editor-input{box-sizing:border-box;border:2px solid var(--ssg-accent);width:100%;height:100%;color:var(--ssg-cell-text);background-color:var(--ssg-cell-bg);pointer-events:auto;outline:none;margin:0;padding:0 10px;font-size:16px}.ssg-bar--top{border-bottom:1px solid var(--ssg-divider)}.ssg-bar--bottom{border-top:1px solid var(--ssg-divider)}.ssg-bar-container{background-color:var(--ssg-header-bg);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;padding:10px 12px;display:flex}.ssg-bar-group{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.ssg-bar-leading{min-width:0;color:var(--ssg-header-text);flex:auto;font-size:13px}.ssg-bar-title{color:var(--ssg-header-text);font-size:13px;font-weight:700}.ssg-bar-chip{background-color:var(--ssg-cell-bg);border:1px solid var(--ssg-header-hover-bg);color:var(--ssg-header-text);white-space:nowrap;border-radius:9999px;align-items:center;padding:4px 8px;font-size:12px;display:inline-flex}.ssg-bar-chip--emphasis{background-color:var(--ssg-header-hover-bg);border-color:#0000;font-weight:600}.ssg-bar-input{box-sizing:border-box;background-color:var(--ssg-cell-bg);width:100%;min-width:0;color:var(--ssg-cell-text);caret-color:var(--ssg-cell-text);-webkit-text-fill-color:var(--ssg-cell-text);border:1px solid #cbd5e1;border-radius:8px;outline:none;padding:10px 12px;font-size:14px;line-height:1.4}.ssg-bar-input-group{align-items:center;gap:8px;width:100%;max-width:420px;display:flex}.ssg-bar-clear-btn{background-color:var(--ssg-cell-bg);color:#475569;cursor:pointer;white-space:nowrap;border:1px solid #cbd5e1;border-radius:8px;flex:none;padding:10px 12px;font-size:12px;line-height:1}.ssg-popover{box-sizing:border-box;z-index:1000;background-color:#fff;border:1px solid #cbd5e1;border-radius:12px;flex-direction:column;padding:12px;display:flex;position:fixed;box-shadow:0 12px 28px #0f172a29}.ssg-popover-header{border-bottom:1px solid #e2e8f0;justify-content:space-between;align-items:center;gap:8px;margin-bottom:8px;padding-bottom:8px;display:flex}.ssg-popover-title{color:#1e293b;-webkit-user-select:none;user-select:none;font-size:13px;font-weight:700}.ssg-popover-close{color:#64748b;cursor:pointer;background-color:#0000;border:none;border-radius:6px;justify-content:center;align-items:center;width:24px;height:24px;font-size:16px;line-height:1;display:flex}.ssg-popover-close:hover{background-color:#f1f5f9}.ssg-popover-footer{border-top:1px solid #e2e8f0;gap:8px;margin-top:8px;padding-top:8px;display:flex}.ssg-sort-panel{max-height:420px}.ssg-sort-list{flex-direction:column;flex:1;gap:6px;min-height:0;margin:0 -4px;padding:0 4px;display:flex;overflow-y:auto}.ssg-sort-empty{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:10px 4px;font-size:12px}.ssg-sort-level{opacity:1;border-top:2px solid #0000;align-items:center;gap:6px;display:flex}.ssg-sort-level--drop-before{border-top-color:#2563eb}.ssg-sort-level--dragging{opacity:.4}.ssg-sort-handle{cursor:grab;touch-action:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:16px;height:26px;display:flex}.ssg-sort-handle--dragging{cursor:grabbing}.ssg-sort-handle--disabled{cursor:default}.ssg-sort-handle:not(.ssg-sort-handle--disabled):hover{background-color:#f1f5f9}.ssg-sort-badge{color:#2563eb;-webkit-user-select:none;user-select:none;background-color:#eff6ff;border-radius:9px;flex:none;justify-content:center;align-items:center;width:18px;height:18px;font-size:11px;font-weight:700;display:flex}.ssg-sort-select{box-sizing:border-box;color:#334155;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:6px;flex:1;min-width:0;padding:5px 6px;font-size:13px}.ssg-sort-select:disabled{cursor:default}.ssg-sort-dir-group{flex:none;display:flex}.ssg-sort-dir-btn{box-sizing:border-box;color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;flex:none;padding:4px 9px;font-size:12px;line-height:1.4}.ssg-sort-dir-group>.ssg-sort-dir-btn:first-child{border-right:none;border-top-left-radius:6px;border-bottom-left-radius:6px}.ssg-sort-dir-group>.ssg-sort-dir-btn:last-child{border-top-right-radius:6px;border-bottom-right-radius:6px}.ssg-sort-dir-btn--active{color:#fff;background-color:#2563eb;border-color:#2563eb}.ssg-sort-dir-btn:disabled{color:#cbd5e1;cursor:default}.ssg-sort-delete{color:#64748b;cursor:pointer;background-color:#0000;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;font-size:15px;line-height:1;display:flex}.ssg-sort-delete:disabled{color:#cbd5e1;cursor:default}.ssg-sort-delete:not(:disabled):hover{color:#dc2626;background-color:#fef2f2}.ssg-sort-drop-end{border-top:2px solid #2563eb;height:0}.ssg-sort-footer-btn{box-sizing:border-box;color:#334155;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background-color:#0000;border:1px solid #e2e8f0;border-radius:8px;font-size:13px}.ssg-sort-footer-btn--add{flex:1;padding:7px 8px}.ssg-sort-footer-btn--clear{flex:none;padding:7px 12px}.ssg-sort-footer-btn:disabled{color:#cbd5e1;cursor:default}.ssg-sort-footer-btn:not(:disabled):hover{background-color:#f1f5f9}.ssg-sort-note{color:#94a3b8;-webkit-user-select:none;user-select:none;margin-top:8px;font-size:11px}.ssg-chooser-panel{max-height:420px}.ssg-chooser-search-row{align-items:center;gap:8px;margin-bottom:8px;display:flex}.ssg-chooser-master-btn{cursor:pointer;background:0 0;border:none;align-items:center;padding:0;display:flex}.ssg-chooser-master-btn:disabled{cursor:default}.ssg-chooser-search-field{flex:1;min-width:0;position:relative}.ssg-chooser-search-icon{color:#94a3b8;pointer-events:none;font-size:13px;line-height:1;position:absolute;top:50%;left:9px;transform:translateY(-50%)}.ssg-chooser-search-input{box-sizing:border-box;color:#334155;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;padding:7px 10px 7px 26px;font-size:13px}.ssg-chooser-list{flex:1;min-height:0;margin:0 -4px;padding:0 4px;overflow-y:auto}.ssg-chooser-empty{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:10px 4px;font-size:12px}.ssg-chooser-section-heading{color:#94a3b8;letter-spacing:.4px;-webkit-user-select:none;user-select:none;padding:8px 4px 4px;font-size:11px;font-weight:700}.ssg-chooser-row{opacity:1;border-top:2px solid #0000;align-items:center;gap:4px;display:flex}.ssg-chooser-row--drop-before{border-top-color:#2563eb}.ssg-chooser-row--dragging{opacity:.4}.ssg-chooser-handle{cursor:grab;touch-action:none;border-radius:6px;flex:none;justify-content:center;align-items:center;width:18px;height:28px;display:flex}.ssg-chooser-handle--dragging{cursor:grabbing}.ssg-chooser-handle--disabled{cursor:default}.ssg-chooser-handle:not(.ssg-chooser-handle--disabled):hover{background-color:#f1f5f9}.ssg-chooser-toggle{box-sizing:border-box;cursor:pointer;text-align:left;background-color:#0000;border:none;border-radius:8px;flex:1;align-items:center;gap:10px;min-width:0;padding:7px 8px;display:flex}.ssg-chooser-toggle:disabled{cursor:default}.ssg-chooser-toggle:not(:disabled):hover{background-color:#f1f5f9}.ssg-chooser-label{color:#334155;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:13px;overflow:hidden}.ssg-chooser-label--muted{color:#94a3b8}.ssg-chooser-drop-end{border-top:2px solid #2563eb;height:0}.ssg-chooser-footer{border-top:1px solid #e2e8f0;margin-top:8px;padding-top:8px}.ssg-chooser-reset-btn{box-sizing:border-box;color:#334155;cursor:pointer;text-align:center;-webkit-user-select:none;user-select:none;background-color:#0000;border:1px solid #e2e8f0;border-radius:8px;width:100%;padding:7px 8px;font-size:13px;display:block}.ssg-chooser-reset-btn:disabled{color:#cbd5e1;cursor:default}.ssg-chooser-reset-btn:not(:disabled):hover{background-color:#f1f5f9}.ssg-chooser-note{color:#94a3b8;-webkit-user-select:none;user-select:none;margin-top:8px;font-size:11px}.ssg-checkbox{background-color:#fff;border:1.5px solid #94a3b8;border-radius:5px;flex:none;justify-content:center;align-items:center;width:18px;height:18px;transition:background-color 80ms,border-color 80ms;display:flex}.ssg-checkbox--filled{background-color:#2563eb;border-color:#2563eb}.ssg-checkbox--disabled{background-color:#f1f5f9;border-color:#cbd5e1}.ssg-checkbox-dash{background-color:#fff;border-radius:1px;width:9px;height:2px}.ssg-filter-popover{box-sizing:border-box;z-index:1000;background-color:#fff;border:1px solid #cbd5e1;border-radius:10px;padding:12px;position:fixed;box-shadow:0 10px 24px #0f172a1f}.ssg-filter-title{color:#334155;margin-bottom:8px;font-size:12px;font-weight:700}.ssg-filter-hint{color:#64748b;margin-bottom:8px;font-size:11px}.ssg-filter-meta{color:#64748b;margin-bottom:10px;font-size:11px}.ssg-filter-meta--ellipsis{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ssg-filter-collecting{text-align:center;color:#64748b;padding:24px;font-size:12px}.ssg-filter-input{box-sizing:border-box;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;margin-bottom:8px;padding:8px 10px}.ssg-filter-select{box-sizing:border-box;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;outline:none;width:100%;margin-bottom:8px;padding:8px 10px}.ssg-filter-selectall{cursor:pointer;color:#334155;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e2e8f0;align-items:center;gap:8px;height:28px;padding:0 8px;font-size:12px;display:flex}.ssg-filter-selectall-label{font-weight:600}.ssg-filter-list{border:1px solid #e2e8f0;border-top:none;border-radius:0 0 8px 8px;height:208px;margin-bottom:8px;overflow-y:auto}.ssg-filter-empty{color:#94a3b8;text-align:center;padding:12px;font-size:12px}.ssg-filter-virt{width:100%;position:relative}.ssg-filter-option{box-sizing:border-box;cursor:pointer;color:#334155;-webkit-user-select:none;user-select:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;display:flex;position:absolute;top:0;left:0;right:0}.ssg-filter-option-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ssg-filter-footer{justify-content:flex-end;gap:8px;display:flex}.ssg-filter-btn-secondary{color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:6px 10px;font-size:12px}.ssg-filter-btn-primary{color:#fff;cursor:pointer;background-color:#2563eb;border:1px solid #2563eb;border-radius:8px;padding:6px 10px;font-size:12px}.ssg-menu-panel{box-sizing:border-box;background-color:#fff;border:1px solid #cbd5e1;border-radius:10px;padding:8px;box-shadow:0 10px 24px #0f172a1f}.ssg-menu-title{color:#334155;text-overflow:ellipsis;white-space:nowrap;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e2e8f0;margin-bottom:4px;padding:2px 8px 6px;font-size:12px;font-weight:700;overflow:hidden}.ssg-menu-item{box-sizing:border-box;color:#334155;text-align:left;cursor:pointer;background-color:#0000;border:none;border-radius:8px;align-items:center;gap:8px;width:100%;padding:7px 8px;font-size:13px;display:flex}.ssg-menu-item:disabled,.ssg-menu-item--disabled{color:#94a3b8;cursor:default}.ssg-menu-item--active,.ssg-menu-item:not(:disabled):not(.ssg-menu-item--disabled):hover{background-color:#f1f5f9}.ssg-menu-submenu-anchor{position:relative}.ssg-menu-icon{text-align:center;flex:none;width:14px}.ssg-menu-sort-icon{text-align:center;color:#94a3b8;flex:none;width:14px;font-weight:400}.ssg-menu-sort-icon--active{color:#2563eb;font-weight:700}.ssg-menu-check{text-align:center;color:#2563eb;flex:none;width:14px;font-weight:700}.ssg-menu-check--hidden{visibility:hidden}.ssg-menu-label{flex:1;min-width:0}.ssg-menu-label--sorted{color:#1d4ed8}.ssg-menu-caret{color:#94a3b8;flex:none;font-size:12px;line-height:1}.ssg-menu-separator{border-top:1px solid #e2e8f0;margin:4px 0}.ssg-menu-note{color:#94a3b8;-webkit-user-select:none;user-select:none;padding:4px 8px 2px;font-size:11px}.ssg-menu-footer{border-top:1px solid #e2e8f0;justify-content:flex-end;margin-top:4px;padding-top:6px;display:flex}.ssg-menu-close-btn{color:#475569;cursor:pointer;background-color:#fff;border:1px solid #cbd5e1;border-radius:8px;padding:5px 10px;font-size:12px}.ssg-body-row{contain:layout style paint;width:100%;position:absolute;top:0;left:0}.ssg-header-grip{color:#cbd5e1;cursor:grab;touch-action:none;-webkit-user-select:none;user-select:none;flex:none;justify-content:center;align-items:center;width:14px;height:22px;display:inline-flex}.ssg-header-label-row{flex:1;align-items:center;gap:4px;min-width:0;display:flex}.ssg-header-label{min-width:0;color:var(--ssg-header-text);text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.ssg-header-label--filtered{color:var(--ssg-accent-strong)}.ssg-header-sort{color:var(--ssg-accent);flex:none;align-items:center;gap:1px;font-size:12px;font-weight:700;line-height:1;display:inline-flex}.ssg-header-sort-priority{font-size:9px;font-weight:700;line-height:1}.ssg-header-resize{cursor:col-resize;z-index:3;width:6px;height:100%;position:absolute;top:0;right:-3px}.ssg-skeleton-rowheader{color:#94a3b8}.ssg-skeleton-bar{background-color:#e2e8f0;border-radius:4px;height:10px}.ssg-shell{background-color:var(--ssg-cell-bg);position:relative;overflow:hidden}.ssg-scroll-container{max-height:480px;position:relative;overflow:auto}.ssg-inner-row{display:flex}.ssg-center-pane{z-index:1;flex-shrink:0;position:relative}.ssg-empty-state{color:#94a3b8;-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;height:160px;font-size:13px;display:flex;position:sticky;left:0}.ssg-autosize-overlay{pointer-events:none;z-index:5;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.ssg-autosize-pill{color:#f8fafc;-webkit-user-select:none;user-select:none;background-color:#0f172ad1;border-radius:8px;padding:8px 14px;font-size:13px;font-weight:600;box-shadow:0 6px 20px #0f172a40}}
|
|
2
|
+
/*$vite$:1*/
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { GridColumn } from '../model/gridTypes';
|
|
2
|
+
export type ClipboardMatrix = string[][];
|
|
3
|
+
export declare const parseClipboardText: (text: string) => ClipboardMatrix;
|
|
4
|
+
export declare const serializeSelectionToTsv: <T>(getRow: (viewIndex: number) => T, viewRowCount: number, columns: GridColumn<T>[], selection: {
|
|
5
|
+
type: "cell";
|
|
6
|
+
range: {
|
|
7
|
+
start: {
|
|
8
|
+
row: number;
|
|
9
|
+
col: number;
|
|
10
|
+
};
|
|
11
|
+
end: {
|
|
12
|
+
row: number;
|
|
13
|
+
col: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
} | {
|
|
17
|
+
type: "row";
|
|
18
|
+
startRow: number;
|
|
19
|
+
endRow: number;
|
|
20
|
+
} | {
|
|
21
|
+
type: "col";
|
|
22
|
+
startCol: number;
|
|
23
|
+
endCol: number;
|
|
24
|
+
} | null) => string;
|
|
25
|
+
export declare const applyClipboardMatrixToRows: <T extends object>(rows: T[], resolveSourceIndex: (viewIndex: number) => number | undefined, columns: GridColumn<T>[], matrix: ClipboardMatrix, startRowIndex: number, startColIndex: number, canWriteCell: (originalRowIndex: number, colIndex: number, row: T, column: GridColumn<T>) => boolean) => T[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const toExcelColumnName: (columnIndex: number) => string;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GridColumn, SpreadsheetGridProps } from '../model/gridTypes';
|
|
2
|
+
export declare const isCellEditable: <T>(props: Pick<SpreadsheetGridProps<T>, "readOnly" | "canEditCell">, rowIndex: number, colIndex: number, row: T, column: GridColumn<T>) => boolean;
|
|
3
|
+
export declare const getCellValue: <T>(row: T, column: GridColumn<T>) => unknown;
|
|
4
|
+
export declare const setCellValue: <T>(row: T, column: GridColumn<T>, value: unknown) => T;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const yieldToMain: () => Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { ColumnChooserLayout } from '../hooks/useColumnChooserController';
|
|
3
|
+
import type { ColumnPane } from '../logic/geometry';
|
|
4
|
+
export type ColumnChooserItem = {
|
|
5
|
+
key: string;
|
|
6
|
+
title: string;
|
|
7
|
+
visible: boolean;
|
|
8
|
+
pane: ColumnPane;
|
|
9
|
+
};
|
|
10
|
+
type ColumnChooserPanelProps = {
|
|
11
|
+
isOpen: boolean;
|
|
12
|
+
items: ColumnChooserItem[];
|
|
13
|
+
canToggle: boolean;
|
|
14
|
+
layout: ColumnChooserLayout | null;
|
|
15
|
+
panelRef: RefObject<HTMLDivElement | null>;
|
|
16
|
+
onToggleColumnVisibility: (columnKey: string, nextVisible: boolean) => void;
|
|
17
|
+
onShowAllColumns: () => void;
|
|
18
|
+
onResetColumns: () => void;
|
|
19
|
+
onReorderColumns: (orderedKeys: string[]) => void;
|
|
20
|
+
onRequestClose: () => void;
|
|
21
|
+
};
|
|
22
|
+
export declare function ColumnChooserPanel({ isOpen, items, canToggle, layout, panelRef, onToggleColumnVisibility, onShowAllColumns, onResetColumns, onReorderColumns, onRequestClose, }: ColumnChooserPanelProps): import("react").ReactPortal | null;
|
|
23
|
+
export default ColumnChooserPanel;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
export type ColumnFilterPopoverLayout = {
|
|
3
|
+
top: number;
|
|
4
|
+
left: number;
|
|
5
|
+
width: number;
|
|
6
|
+
};
|
|
7
|
+
export type ColumnFilterPopoverOption = {
|
|
8
|
+
label: string;
|
|
9
|
+
value: string;
|
|
10
|
+
};
|
|
11
|
+
export type ColumnFilterSetSelection = {
|
|
12
|
+
mode: 'include' | 'exclude';
|
|
13
|
+
values: ReadonlySet<string>;
|
|
14
|
+
};
|
|
15
|
+
export declare const isSetValueSelected: (selection: ColumnFilterSetSelection | null, value: string) => boolean;
|
|
16
|
+
type ColumnFilterPopoverProps = {
|
|
17
|
+
isOpen: boolean;
|
|
18
|
+
title: string;
|
|
19
|
+
filterType: 'text' | 'number' | 'date' | 'select' | 'set' | 'custom';
|
|
20
|
+
draftValue: string;
|
|
21
|
+
currentValueText: string;
|
|
22
|
+
layout: ColumnFilterPopoverLayout | null;
|
|
23
|
+
selectOptions: ColumnFilterPopoverOption[];
|
|
24
|
+
optionsStatus: 'idle' | 'collecting' | 'ready';
|
|
25
|
+
optionsProgress: number;
|
|
26
|
+
setSelection: ColumnFilterSetSelection | null;
|
|
27
|
+
popoverRef: RefObject<HTMLDivElement | null>;
|
|
28
|
+
textInputRef: RefObject<HTMLInputElement | null>;
|
|
29
|
+
selectRef: RefObject<HTMLSelectElement | null>;
|
|
30
|
+
onRequestClose: () => void;
|
|
31
|
+
onDraftChange: (value: string) => void;
|
|
32
|
+
onApply: () => void;
|
|
33
|
+
onClear: () => void;
|
|
34
|
+
onSetValueToggle: (value: string) => void;
|
|
35
|
+
onSetSelectAllChange: (scope: 'all' | string[], nextSelected: boolean) => void;
|
|
36
|
+
onSetClear: () => void;
|
|
37
|
+
isServerSide?: boolean;
|
|
38
|
+
};
|
|
39
|
+
export declare function ColumnFilterPopover({ isOpen, title, filterType, draftValue, currentValueText, layout, selectOptions, optionsStatus, optionsProgress, setSelection, popoverRef, textInputRef, selectRef, onRequestClose, onDraftChange, onApply, onClear, onSetValueToggle, onSetSelectAllChange, onSetClear, isServerSide, }: ColumnFilterPopoverProps): import("react").ReactPortal | null;
|
|
40
|
+
export default ColumnFilterPopover;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { GridColumnPinned, GridSortDirection } from '../model/gridTypes';
|
|
3
|
+
import type { ColumnMenuLayout } from '../hooks/useColumnMenuController';
|
|
4
|
+
type ColumnMenuPopoverProps = {
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
title: string;
|
|
7
|
+
columnKey: string;
|
|
8
|
+
canSort: boolean;
|
|
9
|
+
sortDirection: GridSortDirection;
|
|
10
|
+
onSortChange: (direction: Exclude<GridSortDirection, null>) => void;
|
|
11
|
+
onOpenSortManager: () => void;
|
|
12
|
+
pinned: GridColumnPinned | undefined;
|
|
13
|
+
canChangePinned: boolean;
|
|
14
|
+
layout: ColumnMenuLayout | null;
|
|
15
|
+
popoverRef: RefObject<HTMLDivElement | null>;
|
|
16
|
+
onPinnedChange: (columnKey: string, pinned: GridColumnPinned | undefined) => void;
|
|
17
|
+
onAutosizeColumn: (columnKey: string) => void;
|
|
18
|
+
onAutosizeAllColumns: () => void;
|
|
19
|
+
onOpenColumnChooser: () => void;
|
|
20
|
+
canResetColumns: boolean;
|
|
21
|
+
onResetColumns: () => void;
|
|
22
|
+
onRequestClose: () => void;
|
|
23
|
+
};
|
|
24
|
+
export declare function ColumnMenuPopover({ isOpen, title, columnKey, canSort, sortDirection, onSortChange, onOpenSortManager, pinned, canChangePinned, layout, popoverRef, onPinnedChange, onAutosizeColumn, onAutosizeAllColumns, onOpenColumnChooser, canResetColumns, onResetColumns, onRequestClose, }: ColumnMenuPopoverProps): import("react").ReactPortal | null;
|
|
25
|
+
export default ColumnMenuPopover;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SpreadsheetGridSlotContext } from '../model/gridTypes';
|
|
2
|
+
type DefaultGridBottomBarProps<T> = {
|
|
3
|
+
context: SpreadsheetGridSlotContext<T>;
|
|
4
|
+
};
|
|
5
|
+
export declare function DefaultGridBottomBar<T>({ context, }: DefaultGridBottomBarProps<T>): import("react").JSX.Element;
|
|
6
|
+
export default DefaultGridBottomBar;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SpreadsheetGridSlotContext } from '../model/gridTypes';
|
|
2
|
+
type DefaultGridTopBarProps<T> = {
|
|
3
|
+
context: SpreadsheetGridSlotContext<T>;
|
|
4
|
+
};
|
|
5
|
+
export declare function DefaultGridTopBar<T>({ context, }: DefaultGridTopBarProps<T>): import("react").JSX.Element;
|
|
6
|
+
export default DefaultGridTopBar;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CSSProperties, PointerEvent, ReactNode } from 'react';
|
|
2
|
+
import type { SelectionSnapshot } from '../model/gridSelectors';
|
|
3
|
+
import type { CellCoord, CellRenderState, GridColumn, RowModel, SpreadsheetGridProps } from '../model/gridTypes';
|
|
4
|
+
import type { PaneColumnEntry } from '../logic/geometry';
|
|
5
|
+
import type { GridPaneKind } from './GridHeaderRow';
|
|
6
|
+
type VirtualRowLike = {
|
|
7
|
+
index: number;
|
|
8
|
+
start: number;
|
|
9
|
+
size?: number;
|
|
10
|
+
};
|
|
11
|
+
type GridBodyLayerProps<T> = {
|
|
12
|
+
pane: GridPaneKind;
|
|
13
|
+
ownsRowHeader: boolean;
|
|
14
|
+
leadingWidth: number;
|
|
15
|
+
rowModel: RowModel<T>;
|
|
16
|
+
virtualRows: VirtualRowLike[];
|
|
17
|
+
virtualRowIndexes: Set<number>;
|
|
18
|
+
renderEntries: PaneColumnEntry<T>[];
|
|
19
|
+
rowHeight: number;
|
|
20
|
+
autoHeight?: boolean;
|
|
21
|
+
isServerSide?: boolean;
|
|
22
|
+
rowHeaderCellStyle: CSSProperties;
|
|
23
|
+
hoveredRowIndex: number | null;
|
|
24
|
+
isWholeGridSelected: boolean;
|
|
25
|
+
activeCell: CellCoord | null;
|
|
26
|
+
editingCell: CellCoord | null;
|
|
27
|
+
selectionSnapshot: SelectionSnapshot;
|
|
28
|
+
readOnly: boolean;
|
|
29
|
+
canEditCell: SpreadsheetGridProps<T>['canEditCell'];
|
|
30
|
+
onRowHeaderPointerDown: (rowIndex: number, event: PointerEvent<HTMLDivElement>) => void;
|
|
31
|
+
onRowHeaderPointerEnter: (rowIndex: number, event: PointerEvent<HTMLDivElement>) => void;
|
|
32
|
+
onRowHeaderPointerLeave: (rowIndex: number) => void;
|
|
33
|
+
onCellPointerDown: (cell: CellCoord, event: PointerEvent<HTMLDivElement>) => void;
|
|
34
|
+
onCellPointerEnter: (cell: CellCoord, event: PointerEvent<HTMLDivElement>) => void;
|
|
35
|
+
onCellDoubleClick: (cell: CellCoord) => void;
|
|
36
|
+
renderCellContent: (row: T, rowIndex: number, column: GridColumn<T>, colIndex: number, cellState: CellRenderState) => ReactNode;
|
|
37
|
+
getRowClassName?: (row: T, rowIndex: number) => string | undefined;
|
|
38
|
+
bodyCellClassName?: string;
|
|
39
|
+
bodyRowClassName?: string;
|
|
40
|
+
rowHeaderCellClassName?: string;
|
|
41
|
+
};
|
|
42
|
+
export declare function GridBodyLayer<T>({ pane, ownsRowHeader, leadingWidth, rowModel, virtualRows, virtualRowIndexes, renderEntries, rowHeight, autoHeight, isServerSide, rowHeaderCellStyle, hoveredRowIndex, isWholeGridSelected, activeCell, editingCell, selectionSnapshot, readOnly, canEditCell, onRowHeaderPointerDown, onRowHeaderPointerEnter, onRowHeaderPointerLeave, onCellPointerDown, onCellPointerEnter, onCellDoubleClick, renderCellContent, getRowClassName, bodyCellClassName, bodyRowClassName, rowHeaderCellClassName, }: GridBodyLayerProps<T>): import("react").JSX.Element;
|
|
43
|
+
export default GridBodyLayer;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type CSSProperties, type MouseEvent, type PointerEvent } from 'react';
|
|
2
|
+
import type { SelectionSnapshot } from '../model/gridSelectors';
|
|
3
|
+
import type { ColumnFilterValue, GridColumn, GridSortState } from '../model/gridTypes';
|
|
4
|
+
import type { PaneColumnEntry } from '../logic/geometry';
|
|
5
|
+
export type GridPaneKind = 'left' | 'center' | 'right';
|
|
6
|
+
type GridHeaderRowProps<T> = {
|
|
7
|
+
pane: GridPaneKind;
|
|
8
|
+
ownsRowHeader: boolean;
|
|
9
|
+
leadingWidth: number;
|
|
10
|
+
headerHeight: number;
|
|
11
|
+
rowHeaderCellStyle: CSSProperties;
|
|
12
|
+
headerRowClassName?: string;
|
|
13
|
+
headerCellClassName?: string;
|
|
14
|
+
rowHeaderCellClassName?: string;
|
|
15
|
+
isCornerHovered: boolean;
|
|
16
|
+
isWholeGridSelected: boolean;
|
|
17
|
+
filteredRowsLength: number;
|
|
18
|
+
visibleColumnsLength: number;
|
|
19
|
+
renderEntries: PaneColumnEntry<T>[];
|
|
20
|
+
hoveredColumnIndex: number | null;
|
|
21
|
+
selectionSnapshot: SelectionSnapshot;
|
|
22
|
+
columnFilterValues: Record<string, ColumnFilterValue>;
|
|
23
|
+
sortState: GridSortState;
|
|
24
|
+
iconButtonClassName?: string;
|
|
25
|
+
onCornerPointerDown: (event: PointerEvent<HTMLDivElement>) => void;
|
|
26
|
+
onCornerPointerEnter: () => void;
|
|
27
|
+
onCornerPointerLeave: () => void;
|
|
28
|
+
onColumnHeaderPointerDown: (colIndex: number, event: PointerEvent<HTMLDivElement>) => void;
|
|
29
|
+
onColumnHeaderPointerEnter: (colIndex: number, event: PointerEvent<HTMLDivElement>) => void;
|
|
30
|
+
onColumnHeaderPointerLeave: (colIndex: number) => void;
|
|
31
|
+
onColumnFilterButtonPointerDown: (column: GridColumn<T>, event: PointerEvent<HTMLButtonElement>) => void;
|
|
32
|
+
onColumnResizePointerDown: (column: GridColumn<T>, event: PointerEvent<HTMLDivElement>) => void;
|
|
33
|
+
enableColumnMenu: boolean;
|
|
34
|
+
openedMenuColumnKey: string | null;
|
|
35
|
+
onColumnMenuButtonPointerDown: (column: GridColumn<T>, event: PointerEvent<HTMLButtonElement>) => void;
|
|
36
|
+
onColumnHeaderContextMenu: (column: GridColumn<T>, event: MouseEvent<HTMLDivElement>) => void;
|
|
37
|
+
onColumnDragHandlePointerDown?: (column: GridColumn<T>, event: PointerEvent<HTMLSpanElement>) => void;
|
|
38
|
+
};
|
|
39
|
+
declare function GridHeaderRowInner<T>({ pane, ownsRowHeader, leadingWidth, headerHeight, rowHeaderCellStyle, headerRowClassName, headerCellClassName, rowHeaderCellClassName, isCornerHovered, isWholeGridSelected, filteredRowsLength, visibleColumnsLength, renderEntries, hoveredColumnIndex, selectionSnapshot, columnFilterValues, sortState, iconButtonClassName, onCornerPointerDown, onCornerPointerEnter, onCornerPointerLeave, onColumnHeaderPointerDown, onColumnHeaderPointerEnter, onColumnHeaderPointerLeave, onColumnFilterButtonPointerDown, onColumnResizePointerDown, enableColumnMenu, openedMenuColumnKey, onColumnMenuButtonPointerDown, onColumnHeaderContextMenu, onColumnDragHandlePointerDown, }: GridHeaderRowProps<T>): import("react").JSX.Element;
|
|
40
|
+
export declare const GridHeaderRow: typeof GridHeaderRowInner;
|
|
41
|
+
export default GridHeaderRow;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RefObject } from 'react';
|
|
2
|
+
import type { GridSortEntry } from '../model/gridTypes';
|
|
3
|
+
import type { SortManagementLayout } from '../hooks/useSortManagementController';
|
|
4
|
+
export type SortManagementColumn = {
|
|
5
|
+
key: string;
|
|
6
|
+
title: string;
|
|
7
|
+
};
|
|
8
|
+
type SortManagementPanelProps = {
|
|
9
|
+
isOpen: boolean;
|
|
10
|
+
entries: GridSortEntry[];
|
|
11
|
+
columns: SortManagementColumn[];
|
|
12
|
+
canSort: boolean;
|
|
13
|
+
layout: SortManagementLayout | null;
|
|
14
|
+
panelRef: RefObject<HTMLDivElement | null>;
|
|
15
|
+
onAddLevel: (columnKey: string, direction: 'asc' | 'desc') => void;
|
|
16
|
+
onChangeDirection: (index: number, direction: 'asc' | 'desc') => void;
|
|
17
|
+
onChangeColumn: (index: number, columnKey: string) => void;
|
|
18
|
+
onRemoveLevel: (index: number) => void;
|
|
19
|
+
onClearAll: () => void;
|
|
20
|
+
onMove: (from: number, to: number) => void;
|
|
21
|
+
onRequestClose: () => void;
|
|
22
|
+
};
|
|
23
|
+
export declare function SortManagementPanel({ isOpen, entries, columns, canSort, layout, panelRef, onAddLevel, onChangeDirection, onChangeColumn, onRemoveLevel, onClearAll, onMove, onRequestClose, }: SortManagementPanelProps): import("react").ReactPortal | null;
|
|
24
|
+
export default SortManagementPanel;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { CellCoord, GridSelection, SpreadsheetGridSlotContext, SpreadsheetGridDerivedSummary, SpreadsheetGridSelectionStats } from '../model/gridTypes';
|
|
3
|
+
export declare const resolveGridSlot: <T>(slotRenderer: ((context: SpreadsheetGridSlotContext<T>) => ReactNode) | undefined, context: SpreadsheetGridSlotContext<T>, fallback: ReactNode) => ReactNode;
|
|
4
|
+
export declare const formatGridCellLabel: (cell: CellCoord | null) => string;
|
|
5
|
+
export declare const formatGridSelectionLabel: (selection: GridSelection) => string;
|
|
6
|
+
export declare const formatGridRowSummary: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "rows">, filteredRowCount: number) => string;
|
|
7
|
+
export declare const formatGridColumnSummary: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "columns" | "visibleColumns">) => string;
|
|
8
|
+
export declare const getGridSelectionStats: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "selection" | "visibleColumns">, filteredRowCount: number) => SpreadsheetGridSelectionStats;
|
|
9
|
+
export declare const formatGridSelectionStatsLabel: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "selection" | "visibleColumns">, filteredRowCount: number) => string;
|
|
10
|
+
export declare const formatGridFilterSummary: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "globalFilterText" | "columnFilterValues">) => string;
|
|
11
|
+
export declare const formatGridSortSummary: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "columns" | "sortState">) => string;
|
|
12
|
+
export declare const buildGridDerivedSummary: <T>(context: Pick<SpreadsheetGridSlotContext<T>, "rows" | "columns" | "visibleColumns" | "globalFilterText" | "columnFilterValues" | "sortState" | "activeCell" | "selection">, filteredRowCount: number) => SpreadsheetGridDerivedSummary;
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ishibashi0112/spreadsheet-grid",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React 19 製のカスタム仮想化データグリッド。100 万行対応の仮想化・3 ペイン固定列・ソート/フィルター・クライアント/サーバーサイド行モデル対応。",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"react19",
|
|
8
|
+
"grid",
|
|
9
|
+
"datagrid",
|
|
10
|
+
"table",
|
|
11
|
+
"spreadsheet",
|
|
12
|
+
"virtualized",
|
|
13
|
+
"virtual-scroll",
|
|
14
|
+
"typescript",
|
|
15
|
+
"ssrm"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Yuki Sakakibara",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/ishibashi0112/datasheet-grid.git"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/ishibashi0112/datasheet-grid#readme",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/ishibashi0112/datasheet-grid/issues"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"sideEffects": [
|
|
29
|
+
"**/*.css"
|
|
30
|
+
],
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"main": "./dist/index.cjs",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js",
|
|
41
|
+
"require": "./dist/index.cjs"
|
|
42
|
+
},
|
|
43
|
+
"./style.css": "./dist/style.css"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": "^19.0.0",
|
|
53
|
+
"react-dom": "^19.0.0"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@tanstack/react-virtual": "^3.14.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@eslint/js": "^10.0.1",
|
|
60
|
+
"@testing-library/dom": "^10.4.1",
|
|
61
|
+
"@testing-library/react": "^16.3.2",
|
|
62
|
+
"@types/node": "^24.12.3",
|
|
63
|
+
"@types/react": "^19.2.14",
|
|
64
|
+
"@types/react-dom": "^19.2.3",
|
|
65
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
66
|
+
"eslint": "^10.3.0",
|
|
67
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
68
|
+
"eslint-plugin-react-refresh": "^0.5.2",
|
|
69
|
+
"globals": "^17.6.0",
|
|
70
|
+
"jsdom": "^29.1.1",
|
|
71
|
+
"react": "^19.2.6",
|
|
72
|
+
"react-dom": "^19.2.6",
|
|
73
|
+
"typescript": "~6.0.2",
|
|
74
|
+
"typescript-eslint": "^8.59.2",
|
|
75
|
+
"vite": "^8.0.12",
|
|
76
|
+
"vitest": "^4.1.9"
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"dev": "vite",
|
|
80
|
+
"build": "tsc -b && vite build",
|
|
81
|
+
"build:lib": "vite build --config vite.lib.config.ts && tsc -p tsconfig.lib.json",
|
|
82
|
+
"build:types": "tsc -p tsconfig.lib.json",
|
|
83
|
+
"lint": "eslint .",
|
|
84
|
+
"preview": "vite preview",
|
|
85
|
+
"test": "vitest run",
|
|
86
|
+
"test:watch": "vitest",
|
|
87
|
+
"typecheck:test": "tsc --noEmit -p tsconfig.vitest.json"
|
|
88
|
+
}
|
|
89
|
+
}
|