xontable 0.1.3 → 0.2.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.
- package/README.md +22 -50
- package/dist/XOnTable.d.ts.map +1 -1
- package/dist/XOnTable.js +17 -5
- package/dist/components/XOnTableHeader.d.ts.map +1 -1
- package/dist/components/XOnTableHeader.js +4 -2
- package/dist/components/XOnTableStatusBar.d.ts +17 -0
- package/dist/components/XOnTableStatusBar.d.ts.map +1 -0
- package/dist/components/XOnTableStatusBar.js +12 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/hooks/useTableModel.d.ts +5 -0
- package/dist/hooks/useTableModel.d.ts.map +1 -1
- package/dist/hooks/useTableModel.js +12 -1
- package/dist/styles/xontable.base.css +18 -4
- package/dist/styles/xontable.filter.css +15 -0
- package/dist/styles/xontable.theme.css +31 -19
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -46,6 +46,8 @@ import "xontable/styles";
|
|
|
46
46
|
- `onChange(nextRows, meta)`: Updated rows with change meta
|
|
47
47
|
- `readOnly`: Disable editing
|
|
48
48
|
- `theme`: `"light" | "dark"`
|
|
49
|
+
- `showStatusBar`: Show validation summary bar
|
|
50
|
+
- `darkThemeColors`: Override dark theme colors
|
|
49
51
|
|
|
50
52
|
## Column Definition
|
|
51
53
|
|
|
@@ -65,27 +67,12 @@ type ColumnDef<Row> = {
|
|
|
65
67
|
};
|
|
66
68
|
```
|
|
67
69
|
|
|
68
|
-
## Data Model
|
|
69
|
-
|
|
70
|
-
Rows are objects:
|
|
71
|
-
|
|
72
|
-
```ts
|
|
73
|
-
type Row = { id: string; [key: string]: any };
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
`onChange` receives a **new rows array** whenever edits/paste/fill happen.
|
|
77
|
-
|
|
78
70
|
## Editing
|
|
79
71
|
- Single click selects
|
|
80
72
|
- Enter or double-click to edit
|
|
81
73
|
- Typing starts edit with typed character
|
|
82
74
|
- Enter commits, Esc cancels, Tab commits and moves
|
|
83
75
|
|
|
84
|
-
## Keyboard Navigation
|
|
85
|
-
- Arrow keys move selection
|
|
86
|
-
- Tab / Shift+Tab moves horizontally
|
|
87
|
-
- Shift + arrows extends selection
|
|
88
|
-
|
|
89
76
|
## Copy / Paste
|
|
90
77
|
- TSV compatible with Excel/Google Sheets
|
|
91
78
|
- Use Ctrl/Cmd+C to copy selection
|
|
@@ -103,11 +90,13 @@ Per-column validation:
|
|
|
103
90
|
{ key: "qty", label: "Qty", type: "number", validator: (v) => v ? null : "Required" }
|
|
104
91
|
```
|
|
105
92
|
|
|
106
|
-
|
|
93
|
+
## Status Bar
|
|
107
94
|
|
|
108
|
-
|
|
95
|
+
```tsx
|
|
96
|
+
<XOnTable showStatusBar />
|
|
97
|
+
```
|
|
109
98
|
|
|
110
|
-
|
|
99
|
+
## Select Dropdowns
|
|
111
100
|
|
|
112
101
|
```ts
|
|
113
102
|
{ key: "city", label: "City", type: "select", options: [
|
|
@@ -115,59 +104,42 @@ Static options:
|
|
|
115
104
|
] }
|
|
116
105
|
```
|
|
117
106
|
|
|
118
|
-
Async options:
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
{ key: "group", label: "Group", type: "select", getOptions: async () => groupOptions }
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
Cascading select with `dependsOn`:
|
|
125
|
-
|
|
126
|
-
```ts
|
|
127
|
-
{ key: "subgroup", label: "Subgroup", type: "select", dependsOn: "group", getOptions: async (row) => options[row.group] }
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
Invalid values will show validation color.
|
|
131
|
-
|
|
132
107
|
## Checkbox Cells
|
|
133
108
|
|
|
134
109
|
```ts
|
|
135
110
|
{ key: "active", label: "Active", type: "checkbox" }
|
|
136
111
|
```
|
|
137
112
|
|
|
138
|
-
Values are `true` / `false`.
|
|
139
|
-
|
|
140
113
|
## Column Groups
|
|
141
114
|
|
|
142
115
|
```ts
|
|
143
|
-
|
|
144
|
-
{ key: "
|
|
116
|
+
const columns: ColumnDef<Row>[] = [
|
|
117
|
+
{ key: "name", label: "Name", group: "User" },
|
|
118
|
+
{ key: "active", label: "Active", type: "checkbox", group: "User" },
|
|
119
|
+
{ key: "group", label: "Group", type: "select", group: "Account Details" },
|
|
120
|
+
{ key: "subgroup", label: "Subgroup", type: "select", group: "Account Details" },
|
|
121
|
+
{ key: "city", label: "City", type: "select", group: "Login info" },
|
|
122
|
+
];
|
|
145
123
|
```
|
|
146
124
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
## Filters
|
|
150
|
-
Each column header shows a filter icon.
|
|
151
|
-
- Search inside the filter menu
|
|
152
|
-
- Toggle values on/off
|
|
153
|
-
|
|
154
|
-
## Readonly Mode
|
|
125
|
+
## Theme
|
|
155
126
|
|
|
156
127
|
```tsx
|
|
157
|
-
<XOnTable
|
|
128
|
+
<XOnTable theme="dark" />
|
|
158
129
|
```
|
|
159
130
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
## Theme
|
|
131
|
+
### Dark Theme Colors (Props)
|
|
163
132
|
|
|
164
133
|
```tsx
|
|
165
|
-
<XOnTable
|
|
134
|
+
<XOnTable
|
|
135
|
+
theme="dark"
|
|
136
|
+
darkThemeColors={{ bg: "#111318", headBg: "#1c1f26", accent: "#7aa2ff" }}
|
|
137
|
+
/>
|
|
166
138
|
```
|
|
167
139
|
|
|
168
140
|
## Requirements
|
|
169
141
|
- React 19+
|
|
170
|
-
- Peer deps: `react`, `react-dom
|
|
142
|
+
- Peer deps: `react`, `react-dom`
|
|
171
143
|
|
|
172
144
|
## Troubleshooting
|
|
173
145
|
|
package/dist/XOnTable.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XOnTable.d.ts","sourceRoot":"","sources":["../src/XOnTable.tsx"],"names":[],"mappings":"AACA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,wBAAgB,QAAQ,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"XOnTable.d.ts","sourceRoot":"","sources":["../src/XOnTable.tsx"],"names":[],"mappings":"AACA,OAAO,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7C,wBAAgB,QAAQ,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,GAAG,CAAC,2CA8IlF"}
|
package/dist/XOnTable.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import "./styles/xontable.css";
|
|
4
|
-
import { SelectMenu, XOnTableGrid } from "./components";
|
|
4
|
+
import { SelectMenu, XOnTableGrid, XOnTableStatusBar } from "./components";
|
|
5
5
|
import { useAutoRows, useClipboardCatcher, useColumnFilters, useColumnGroups, useColumnResize, useEditorOverlay, useFillHandle, useGridKeydown, useOutsideClick, useRangeSelection, useSelectOptions, useTableModel } from "./hooks";
|
|
6
6
|
const clamp = (n, min, max) => Math.max(min, Math.min(max, n));
|
|
7
7
|
export function XOnTable(props) {
|
|
8
|
-
const { columns, rows, rowIdKey = "id", onChange, readOnly = false, theme = "light" } = props;
|
|
8
|
+
const { columns, rows, rowIdKey = "id", onChange, readOnly = false, theme = "light", showStatusBar = false, darkThemeColors } = props;
|
|
9
9
|
const activeCellRef = React.useRef(null);
|
|
10
10
|
const [editingRowId, setEditingRowId] = React.useState(null);
|
|
11
11
|
const { normalizedRows, handleChange, createRow } = useAutoRows(columns, rows, rowIdKey, onChange, editingRowId);
|
|
@@ -15,7 +15,7 @@ export function XOnTable(props) {
|
|
|
15
15
|
const selection = useRangeSelection();
|
|
16
16
|
const [copiedBounds, setCopiedBounds] = React.useState(null);
|
|
17
17
|
React.useEffect(() => { resetWidths(); }, [columns, resetWidths]);
|
|
18
|
-
const { data, active, setActive, getValue, updateCells, moveActive, rowCount, colCount, hasError, getError, setCellErrorView, undo, redo } = useTableModel({
|
|
18
|
+
const { data, active, setActive, getValue, updateCells, moveActive, rowCount, colCount, hasError, getError, setCellErrorView, errorList, undo, redo } = useTableModel({
|
|
19
19
|
columns: visibleColumns.map((v) => v.col),
|
|
20
20
|
rows: normalizedRows,
|
|
21
21
|
rowFilter: filters.rowFilter,
|
|
@@ -171,12 +171,24 @@ export function XOnTable(props) {
|
|
|
171
171
|
onGridKeyDown(e);
|
|
172
172
|
}, [active.c, active.r, onGridKeyDown, selection]);
|
|
173
173
|
useOutsideClick({ isOpen: filters.filterOpenKey != null, onClose: filters.closeFilter });
|
|
174
|
-
|
|
174
|
+
const darkVars = theme === "dark" && darkThemeColors ? {
|
|
175
|
+
"--xontable-dark-bg": darkThemeColors.bg, "--xontable-dark-border": darkThemeColors.border, "--xontable-dark-text": darkThemeColors.text,
|
|
176
|
+
"--xontable-dark-cell-bg": darkThemeColors.cellBg, "--xontable-dark-head-bg": darkThemeColors.headBg, "--xontable-dark-rownum-bg": darkThemeColors.rownumBg,
|
|
177
|
+
"--xontable-dark-group-bg": darkThemeColors.groupBg, "--xontable-dark-zebra-bg": darkThemeColors.zebraBg, "--xontable-dark-active-head-bg": darkThemeColors.activeHeadBg,
|
|
178
|
+
"--xontable-dark-range": darkThemeColors.range, "--xontable-dark-copy": darkThemeColors.copy, "--xontable-dark-accent": darkThemeColors.accent,
|
|
179
|
+
"--xontable-dark-select": darkThemeColors.select, "--xontable-dark-invalid-bg": darkThemeColors.invalidBg, "--xontable-dark-invalid-border": darkThemeColors.invalidBorder,
|
|
180
|
+
"--xontable-dark-editor-bg": darkThemeColors.editorBg, "--xontable-dark-editor-text": darkThemeColors.editorText,
|
|
181
|
+
"--xontable-dark-readonly-bg": darkThemeColors.readonlyBg, "--xontable-dark-readonly-border": darkThemeColors.readonlyBorder,
|
|
182
|
+
"--xontable-dark-readonly-head-bg": darkThemeColors.readonlyHeadBg, "--xontable-dark-readonly-rownum-bg": darkThemeColors.readonlyRownumBg,
|
|
183
|
+
"--xontable-dark-readonly-zebra-bg": darkThemeColors.readonlyZebraBg,
|
|
184
|
+
} : undefined;
|
|
185
|
+
const onSelectError = React.useCallback((r, c) => { setActive({ r, c }); selection.startSelection({ r, c }); focusClipboard(); }, [focusClipboard, selection, setActive]);
|
|
186
|
+
return (_jsxs("div", { className: `xontable-wrap theme-${theme}${readOnly ? " is-readonly" : ""}`, style: darkVars, children: [_jsx("textarea", { ref: clipRef, className: "xontable-clip", name: "xontable-clip", "aria-hidden": "true", tabIndex: -1, onCopy: onCopy, onPaste: onPaste, onKeyDown: onGridKeyDownWithCopy, readOnly: true }), _jsx("div", { className: `xontable-surface${filters.filterOpenKey ? " is-filter-open" : ""}`, tabIndex: 0, onFocus: (e) => {
|
|
175
187
|
const target = e.target;
|
|
176
188
|
if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA"))
|
|
177
189
|
return;
|
|
178
190
|
focusClipboard();
|
|
179
191
|
}, onKeyDown: onGridKeyDownWithCopy, children: _jsx(XOnTableGrid, { columns: visibleColumns, groups: groupHeaders.some((g) => g.label) ? groupHeaders : undefined, rowNumberWidth: 44, data: data, rowIdKey: rowIdKey, active: active, activeCol: active.c, isEditing: isEditing, readOnly: readOnly, selectionBounds: selection.getBounds(), copiedBounds: copiedBounds, getColWidth: getColWidth, getValue: getValue, hasError: hasError, getError: getError, isPreview: isPreview, activeCellRef: activeCellRef, onCellMouseDown: (r, c, ev) => { ev.preventDefault(); setActive({ r, c }); selection.startSelection({ r, c }); setCopiedBounds(null); focusClipboard(); if (filters.filterOpenKey)
|
|
180
192
|
filters.closeFilter(); }, onCellMouseEnter: (r, c) => { if (selection.isSelecting)
|
|
181
|
-
selection.updateSelection({ r, c }); }, onCellDoubleClick: (r, c) => { setActive({ r, c }); startEditCell(); }, onCheckboxToggle: toggleCheckbox, onSelectOpen: openSelectAt, onFillStart: (r, c, ev) => { ev.preventDefault(); ev.stopPropagation(); startDrag(r, c); }, onResizeStart: (c, ev) => { ev.preventDefault(); ev.stopPropagation(); startResize(c, ev.clientX); }, onResizeDoubleClick: (c, ev) => { ev.preventDefault(); ev.stopPropagation(); autoFitCol(c); }, onGroupToggle: toggleGroup, filterOpenKey: filters.filterOpenKey, filterSearch: filters.filterSearch, getFilterOptions: filters.getFilterOptions, isFilterChecked: filters.isFilterChecked, isFilterAllChecked: filters.isAllChecked, onFilterOpen: filters.openFilter, onFilterSearch: filters.setFilterSearch, onFilterToggle: filters.toggleFilterValue, onFilterToggleAll: filters.toggleAll }) }), isEditing && editorRect && (_jsx("input", { ref: editorRef, className: "xontable-editor", name: "xontable-editor", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: onEditorKeyDown, onBlur: () => { commitEdit(); validateSelect(active.r, active.c, draft, activeRow); }, style: { position: "fixed", left: editorRect.left, top: editorRect.top, width: editorRect.width, height: editorRect.height } })), _jsx(SelectMenu, { isOpen: Boolean(isEditing && activeCol?.type === "select"), rect: editorRect, options: activeRow && activeCol ? getOptions(activeRow, activeCol) : [], loading: Boolean(activeRow && activeCol && isLoading(activeRow, activeCol)), filter: draft, onSelect: (v) => { setDraft(v); commitEdit(v); validateSelect(active.r, active.c, v, activeRow); } })] }));
|
|
193
|
+
selection.updateSelection({ r, c }); }, onCellDoubleClick: (r, c) => { setActive({ r, c }); startEditCell(); }, onCheckboxToggle: toggleCheckbox, onSelectOpen: openSelectAt, onFillStart: (r, c, ev) => { ev.preventDefault(); ev.stopPropagation(); startDrag(r, c); }, onResizeStart: (c, ev) => { ev.preventDefault(); ev.stopPropagation(); startResize(c, ev.clientX); }, onResizeDoubleClick: (c, ev) => { ev.preventDefault(); ev.stopPropagation(); autoFitCol(c); }, onGroupToggle: toggleGroup, filterOpenKey: filters.filterOpenKey, filterSearch: filters.filterSearch, getFilterOptions: filters.getFilterOptions, isFilterChecked: filters.isFilterChecked, isFilterAllChecked: filters.isAllChecked, onFilterOpen: filters.openFilter, onFilterSearch: filters.setFilterSearch, onFilterToggle: filters.toggleFilterValue, onFilterToggleAll: filters.toggleAll }) }), showStatusBar && _jsx(XOnTableStatusBar, { errors: errorList, columns: visibleColumns, onSelect: onSelectError }), isEditing && editorRect && (_jsx("input", { ref: editorRef, className: "xontable-editor", name: "xontable-editor", value: draft, onChange: (e) => setDraft(e.target.value), onKeyDown: onEditorKeyDown, onBlur: () => { commitEdit(); validateSelect(active.r, active.c, draft, activeRow); }, style: { position: "fixed", left: editorRect.left, top: editorRect.top, width: editorRect.width, height: editorRect.height } })), _jsx(SelectMenu, { isOpen: Boolean(isEditing && activeCol?.type === "select"), rect: editorRect, options: activeRow && activeCol ? getOptions(activeRow, activeCol) : [], loading: Boolean(activeRow && activeCol && isLoading(activeRow, activeCol)), filter: draft, onSelect: (v) => { setDraft(v); commitEdit(v); validateSelect(active.r, active.c, v, activeRow); } })] }));
|
|
182
194
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XOnTableHeader.d.ts","sourceRoot":"","sources":["../../src/components/XOnTableHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"XOnTableHeader.d.ts","sourceRoot":"","sources":["../../src/components/XOnTableHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC;AAE3G,KAAK,WAAW,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IAClD,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC5D,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACnC,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IACzD,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IAC5C,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACzD,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAgB,cAAc,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,2CAgEtF"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Filter, Minus, Plus } from "lucide-react";
|
|
3
2
|
import { ColumnFilterMenu } from "./ColumnFilterMenu";
|
|
4
3
|
export function XOnTableHeader(props) {
|
|
5
4
|
const { columns, groups, rowNumberWidth, activeCol, getColWidth, onResizeStart, onResizeDoubleClick, onGroupToggle, filterOpenKey, filterSearch, getFilterOptions, isFilterChecked, isFilterAllChecked, onFilterOpen, onFilterSearch, onFilterToggle, onFilterToggleAll } = props;
|
|
6
|
-
|
|
5
|
+
const FilterIcon = () => (_jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M3 5h18M6 11h12M10 17h4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
|
|
6
|
+
const PlusIcon = () => (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M12 5v14M5 12h14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
|
|
7
|
+
const MinusIcon = () => (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M5 12h14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
|
|
8
|
+
return (_jsxs(_Fragment, { children: [groups && groups.length > 0 && (_jsxs("div", { className: "xontable-row xontable-group-row", children: [_jsx("div", { className: "xontable-cell xontable-rownum-cell xontable-group-cell", style: { width: rowNumberWidth } }), groups.map((g) => (_jsxs("div", { className: "xontable-cell xontable-group-cell", style: { width: g.width }, children: [_jsx("span", { className: "xontable-group-label", children: g.label }), g.collapsible && (_jsx("button", { type: "button", className: "xontable-group-toggle", onClick: () => onGroupToggle(g.key), title: g.collapsed ? "Expand" : "Collapse", children: g.collapsed ? _jsx(PlusIcon, {}) : _jsx(MinusIcon, {}) }))] }, g.key)))] })), _jsxs("div", { className: "xontable-row xontable-head", children: [_jsx("div", { className: "xontable-cell xontable-rownum-cell xontable-head-cell", style: { width: rowNumberWidth } }), columns.map(({ col, idx }, c) => (_jsxs("div", { className: ["xontable-cell", "xontable-head-cell", c === activeCol ? "is-active-col-head" : ""].join(" "), style: { width: getColWidth(c) }, children: [_jsx("span", { className: "xontable-head-label", children: col.label }), idx != null && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "xontable-filter-btn", onClick: () => onFilterOpen(col.key), title: "Filter", children: _jsx(FilterIcon, {}) }), _jsx("div", { className: "xontable-col-resizer", onMouseDown: (ev) => onResizeStart(c, ev), onDoubleClick: (ev) => onResizeDoubleClick(c, ev), title: "Drag to resize" }), _jsx(ColumnFilterMenu, { isOpen: filterOpenKey === col.key, search: filterSearch, options: getFilterOptions(col.key), allChecked: isFilterAllChecked(col.key), isChecked: (v) => isFilterChecked(col.key, v), onSearchChange: onFilterSearch, onToggle: (v) => onFilterToggle(col.key, v), onToggleAll: () => onFilterToggleAll(col.key) })] }))] }, col.key + String(idx ?? c))))] })] }));
|
|
7
9
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ColumnDef } from "../types";
|
|
2
|
+
type ErrorItem = {
|
|
3
|
+
r: number;
|
|
4
|
+
c: number;
|
|
5
|
+
message: string;
|
|
6
|
+
};
|
|
7
|
+
type StatusBarProps<Row extends Record<string, any>> = {
|
|
8
|
+
errors: ErrorItem[];
|
|
9
|
+
columns: Array<{
|
|
10
|
+
col: ColumnDef<Row>;
|
|
11
|
+
idx: number | null;
|
|
12
|
+
}>;
|
|
13
|
+
onSelect: (r: number, c: number) => void;
|
|
14
|
+
};
|
|
15
|
+
export declare function XOnTableStatusBar<Row extends Record<string, any>>(props: StatusBarProps<Row>): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=XOnTableStatusBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XOnTableStatusBar.d.ts","sourceRoot":"","sources":["../../src/components/XOnTableStatusBar.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,KAAK,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,KAAK,cAAc,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACrD,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC5D,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,2CAsB5F"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function XOnTableStatusBar(props) {
|
|
3
|
+
const { errors, columns, onSelect } = props;
|
|
4
|
+
const total = errors.length;
|
|
5
|
+
const visible = errors.slice(0, 3);
|
|
6
|
+
const countLabel = total ? "Errors" : "No errors";
|
|
7
|
+
return (_jsxs("div", { className: "xontable-status", children: [_jsxs("span", { className: ["xontable-status-count", total ? "is-error" : ""].join(" "), children: [_jsx("span", { className: "xontable-status-num", children: total }), _jsx("span", { className: "xontable-status-label", children: countLabel })] }), visible.map((e, idx) => {
|
|
8
|
+
const col = columns[e.c]?.col;
|
|
9
|
+
const label = col?.label ?? `Col ${e.c + 1}`;
|
|
10
|
+
return (_jsx("button", { type: "button", className: ["xontable-status-item", "is-error", `is-chip-${idx % 3}`].join(" "), onClick: () => onSelect(e.r, e.c), title: e.message, children: `Row ${e.r + 1}, ${label}: ${e.message}` }, `${e.r}:${e.c}`));
|
|
11
|
+
})] }));
|
|
12
|
+
}
|
|
@@ -2,4 +2,5 @@ export { ColumnFilterMenu } from "./ColumnFilterMenu";
|
|
|
2
2
|
export { SelectMenu } from "./SelectMenu";
|
|
3
3
|
export { XOnTableGrid } from "./XOnTableGrid";
|
|
4
4
|
export { XOnTableHeader } from "./XOnTableHeader";
|
|
5
|
+
export { XOnTableStatusBar } from "./XOnTableStatusBar";
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/components/index.js
CHANGED
|
@@ -24,6 +24,11 @@ export declare function useTableModel<Row extends Record<string, any>>(options:
|
|
|
24
24
|
hasError: (r: number, c: number) => boolean;
|
|
25
25
|
getError: (r: number, c: number) => string | null;
|
|
26
26
|
setCellErrorView: (r: number, c: number, msg: string | null) => void;
|
|
27
|
+
errorList: {
|
|
28
|
+
r: number;
|
|
29
|
+
c: number;
|
|
30
|
+
message: string;
|
|
31
|
+
}[];
|
|
27
32
|
undo: () => void;
|
|
28
33
|
redo: () => void;
|
|
29
34
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTableModel.d.ts","sourceRoot":"","sources":["../../src/hooks/useTableModel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGjE,KAAK,UAAU,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC;AAEvD,KAAK,iBAAiB,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACxD,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1B,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC;CACvB,CAAC;AAIF,wBAAgB,aAAa,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC;;;;;kBAsB3D,MAAM,KAAK,MAAM;2BAgBR,UAAU,EAAE,QAAQ,YAAY;qBAoBtC,MAAM,MAAM,MAAM;;;kBAmBjB,MAAM,KAAK,MAAM;kBAIjB,MAAM,KAAK,MAAM;0BApDb,MAAM,KAAK,MAAM,OAAO,MAAM,GAAG,IAAI
|
|
1
|
+
{"version":3,"file":"useTableModel.d.ts","sourceRoot":"","sources":["../../src/hooks/useTableModel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAGjE,KAAK,UAAU,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC;AAEvD,KAAK,iBAAiB,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI;IACxD,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1B,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC;CACvB,CAAC;AAIF,wBAAgB,aAAa,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC;;;;;kBAsB3D,MAAM,KAAK,MAAM;2BAgBR,UAAU,EAAE,QAAQ,YAAY;qBAoBtC,MAAM,MAAM,MAAM;;;kBAmBjB,MAAM,KAAK,MAAM;kBAIjB,MAAM,KAAK,MAAM;0BApDb,MAAM,KAAK,MAAM,OAAO,MAAM,GAAG,IAAI;;;;;;;;EAmF/E"}
|
|
@@ -32,7 +32,7 @@ export function useTableModel(options) {
|
|
|
32
32
|
const v = row && col ? row[col.key] : "";
|
|
33
33
|
return v == null ? "" : String(v);
|
|
34
34
|
}, [columns, view.map]);
|
|
35
|
-
const { validateCell, setCellError, hasError, getError } = useValidation(columns, getRow, getValue);
|
|
35
|
+
const { validateCell, setCellError, hasError, getError, errors } = useValidation(columns, getRow, getValue);
|
|
36
36
|
const setCellErrorView = useCallback((r, c, msg) => {
|
|
37
37
|
const real = view.map[r];
|
|
38
38
|
if (real == null)
|
|
@@ -116,6 +116,16 @@ export function useTableModel(options) {
|
|
|
116
116
|
const real = view.map[r];
|
|
117
117
|
return real == null ? null : getError(real, c);
|
|
118
118
|
}, [getError, view.map]);
|
|
119
|
+
const errorList = useMemo(() => {
|
|
120
|
+
const map = new Map();
|
|
121
|
+
view.map.forEach((real, idx) => { if (real != null)
|
|
122
|
+
map.set(real, idx); });
|
|
123
|
+
return Object.entries(errors).flatMap(([key, message]) => {
|
|
124
|
+
const [r, c] = key.split(":").map(Number);
|
|
125
|
+
const vr = map.get(r);
|
|
126
|
+
return vr == null || Number.isNaN(c) ? [] : [{ r: vr, c, message }];
|
|
127
|
+
});
|
|
128
|
+
}, [errors, view.map]);
|
|
119
129
|
return {
|
|
120
130
|
data: view.list,
|
|
121
131
|
rawData: dataRef.current,
|
|
@@ -129,6 +139,7 @@ export function useTableModel(options) {
|
|
|
129
139
|
hasError: hasErrorView,
|
|
130
140
|
getError: getErrorView,
|
|
131
141
|
setCellErrorView,
|
|
142
|
+
errorList,
|
|
132
143
|
undo,
|
|
133
144
|
redo,
|
|
134
145
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.xontable-wrap { display: block; width: 100%; height: 100%; border: 1px solid #e3e5ea; border-radius: 8px; overflow: hidden; background: #fff; --xontable-range: #1a73e8; --xontable-copy: #1a1a1a; }
|
|
2
|
-
.xontable-surface { outline: none; width: 100%; height: 100%; overflow: auto; scrollbar-width: thin; scrollbar-color: #b9c1cd transparent; }
|
|
2
|
+
.xontable-surface { outline: none; width: 100%; height: 100%; min-height: 220px; overflow: auto; scrollbar-width: thin; scrollbar-color: #b9c1cd transparent; }
|
|
3
|
+
.xontable-surface.is-filter-open { overflow-x: auto; overflow-y: visible; }
|
|
3
4
|
.xontable-surface::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
4
5
|
.xontable-surface::-webkit-scrollbar-thumb { background: #b9c1cd; border-radius: 999px; }
|
|
5
6
|
.xontable-surface::-webkit-scrollbar-track { background: transparent; }
|
|
@@ -44,8 +45,8 @@
|
|
|
44
45
|
}
|
|
45
46
|
.xontable-head-cell.is-active-col-head,
|
|
46
47
|
.xontable-rownum-cell.is-active-rownum { background: #cfe3ff; }
|
|
47
|
-
.xontable-cell.is-invalid { background: #
|
|
48
|
-
.xontable-cell.is-invalid:hover { background: #
|
|
48
|
+
.xontable-cell.is-invalid { background: #fff1f1; border: 1px solid #f3b1b1; box-shadow: inset 0 0 0 0 #f3b1b1; }
|
|
49
|
+
.xontable-cell.is-invalid:hover { background: #ffe7e7; }
|
|
49
50
|
.xontable-cell.is-fill-preview { background: #e8f0fe; }
|
|
50
51
|
.xontable-fill-handle { position: absolute; width: 14px; height: 14px; right: -7px; bottom: -7px; background: #0b65d4; border: 1px solid #fff; border-radius: 4px; cursor: crosshair; }
|
|
51
52
|
.xontable-editor { box-sizing: border-box; border: 2px solid #1a73e8; padding: 2px 6px 2px 8px; font: inherit; background: #fff; outline: none; line-height: 1.2; }
|
|
@@ -53,6 +54,19 @@
|
|
|
53
54
|
.xontable-select-menu { background: #fff; border: 1px solid #e1e4ea; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12); border-radius: 4px; padding: 4px 0; z-index: 30; max-height: 220px; overflow: auto; }
|
|
54
55
|
.xontable-select-item { width: 100%; text-align: left; padding: 6px 10px; border: 0; background: transparent; cursor: pointer; font-size: 12px; }
|
|
55
56
|
.xontable-select-item:hover, .xontable-select-item.is-active { background: #e9f1ff; }
|
|
57
|
+
.xontable-status { display: flex; align-items: center; gap: 8px; padding: 6px 8px; font-size: 12px; border-top: 1px solid #e6e8ee; background: #f9fafb; color: #374151; }
|
|
58
|
+
.xontable-status-count { display: inline-flex; align-items: center; gap: 6px; font-weight: 700; background: #eef2ff; color: #3730a3; padding: 2px 8px; border-radius: 999px; }
|
|
59
|
+
.xontable-status-count.is-error { background: #fff1f2; color: #b91c1c; }
|
|
60
|
+
.xontable-status-num { width: 18px; height: 18px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; background: #3730a3; color: #fff; font-size: 11px; }
|
|
61
|
+
.xontable-status-count.is-error .xontable-status-num { background: #dc2626; }
|
|
62
|
+
.xontable-status-label { letter-spacing: 0.2px; }
|
|
63
|
+
.xontable-status-item { border: 1px solid #e6e8ee; background: #fff; color: #1f2937; cursor: pointer; padding: 2px 6px; border-radius: 999px; text-align: left; white-space: nowrap; }
|
|
64
|
+
.xontable-status-item.is-error { background: #ffe7e7; border-color: #dc2626; color: #a10d0d; }
|
|
65
|
+
.xontable-status-item:hover { background: #eef2ff; border-color: #c7d2fe; }
|
|
66
|
+
.xontable-status-item.is-error:hover { background: #ffdada; border-color: #f2a0a0; }
|
|
67
|
+
.xontable-status-item.is-chip-0 { background: #eef2ff; border-color: #c7d2fe; color: #3730a3; }
|
|
68
|
+
.xontable-status-item.is-chip-1 { background: #ecfdf5; border-color: #a7f3d0; color: #065f46; }
|
|
69
|
+
.xontable-status-item.is-chip-2 { background: #fff7ed; border-color: #fed7aa; color: #9a3412; }
|
|
56
70
|
|
|
57
71
|
.xontable-wrap.is-readonly { background: #fff; border-color: #e4e7ec; }
|
|
58
72
|
.xontable-wrap.is-readonly .xontable { color: #222; }
|
|
@@ -68,4 +82,4 @@
|
|
|
68
82
|
.xontable-wrap.is-readonly .xontable-fill-handle { display: none; }
|
|
69
83
|
.xontable-wrap.is-readonly .xontable-select-trigger { display: none; }
|
|
70
84
|
.xontable-wrap.is-readonly .xontable-checkbox { accent-color: #49b86e; }
|
|
71
|
-
.xontable-wrap.is-readonly .xontable-cell.is-invalid { background: #
|
|
85
|
+
.xontable-wrap.is-readonly .xontable-cell.is-invalid { background: #fff1f1; border-color: #f4c2c2; box-shadow: inset 0 0 0 0 #f4c2c2; }
|
|
@@ -63,3 +63,18 @@
|
|
|
63
63
|
gap: 6px;
|
|
64
64
|
font-size: 12px;
|
|
65
65
|
}
|
|
66
|
+
|
|
67
|
+
.xontable-wrap.theme-dark .xontable-filter-menu {
|
|
68
|
+
background: var(--xontable-dark-head-bg, #2b2d31);
|
|
69
|
+
border-color: var(--xontable-dark-border, #3a3a3a);
|
|
70
|
+
color: var(--xontable-dark-text, #e6e6e6);
|
|
71
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
|
|
72
|
+
}
|
|
73
|
+
.xontable-wrap.theme-dark .xontable-filter-search {
|
|
74
|
+
background: var(--xontable-dark-cell-bg, #1e1f22);
|
|
75
|
+
border-color: var(--xontable-dark-border, #3a3a3a);
|
|
76
|
+
color: var(--xontable-dark-text, #e6e6e6);
|
|
77
|
+
}
|
|
78
|
+
.xontable-wrap.theme-dark .xontable-filter-item span {
|
|
79
|
+
color: var(--xontable-dark-text, #e6e6e6);
|
|
80
|
+
}
|
|
@@ -1,42 +1,54 @@
|
|
|
1
|
-
.xontable-wrap.theme-dark { border-color: #3a3a3a; background: #1e1f22; --xontable-range: #8ab4f8; --xontable-copy: #e6e6e6; }
|
|
2
|
-
.xontable-wrap.theme-dark .xontable { color: #e6e6e6; background: transparent; }
|
|
1
|
+
.xontable-wrap.theme-dark { border-color: var(--xontable-dark-border, #3a3a3a); background: var(--xontable-dark-bg, #1e1f22); --xontable-range: var(--xontable-dark-range, #8ab4f8); --xontable-copy: var(--xontable-dark-copy, #e6e6e6); }
|
|
2
|
+
.xontable-wrap.theme-dark .xontable { color: var(--xontable-dark-text, #e6e6e6); background: transparent; }
|
|
3
3
|
|
|
4
4
|
.xontable-wrap.theme-dark .xontable-cell {
|
|
5
|
-
border-color: #3a3a3a;
|
|
6
|
-
background: #1e1f22;
|
|
5
|
+
border-color: var(--xontable-dark-border, #3a3a3a);
|
|
6
|
+
background: var(--xontable-dark-cell-bg, #1e1f22);
|
|
7
7
|
}
|
|
8
8
|
.xontable-wrap.theme-dark .xontable-surface { scrollbar-color: #4b5563 transparent; }
|
|
9
9
|
.xontable-wrap.theme-dark .xontable-surface::-webkit-scrollbar-thumb { background: #4b5563; }
|
|
10
|
-
.xontable-wrap.theme-dark .xontable-select-trigger::after { border-top-color: #b6bcc5; }
|
|
11
|
-
.xontable-wrap.theme-dark .xontable-checkbox { accent-color: #8ab4f8; }
|
|
10
|
+
.xontable-wrap.theme-dark .xontable-select-trigger::after { border-top-color: var(--xontable-dark-select, #b6bcc5); }
|
|
11
|
+
.xontable-wrap.theme-dark .xontable-checkbox { accent-color: var(--xontable-dark-accent, #8ab4f8); }
|
|
12
12
|
|
|
13
13
|
.xontable-wrap.theme-dark .xontable-cell.is-range { background: #1f3526; }
|
|
14
|
-
.xontable-wrap.theme-dark .xontable-cell.is-invalid { background: #
|
|
14
|
+
.xontable-wrap.theme-dark .xontable-cell.is-invalid { background: var(--xontable-dark-invalid-bg, #3a1f1f); border-color: var(--xontable-dark-invalid-border, #efb1b1); box-shadow: inset 0 0 0 0 var(--xontable-dark-invalid-border, #efb1b1); }
|
|
15
15
|
.xontable-wrap.theme-dark .xontable-cell.is-copied { outline: 1px dotted #7ad27a; outline-offset: -1px; }
|
|
16
|
-
.xontable-wrap.theme-dark .xontable-editor { background: #1e1f22; color: #e6e6e6; border-color: #8ab4f8; }
|
|
16
|
+
.xontable-wrap.theme-dark .xontable-editor { background: var(--xontable-dark-editor-bg, #1e1f22); color: var(--xontable-dark-editor-text, #e6e6e6); border-color: var(--xontable-dark-accent, #8ab4f8); }
|
|
17
17
|
|
|
18
18
|
.xontable-wrap.theme-dark .xontable-row.is-zebra .xontable-cell {
|
|
19
|
-
background: #232428;
|
|
19
|
+
background: var(--xontable-dark-zebra-bg, #232428);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
.xontable-wrap.theme-dark .xontable-head-cell,
|
|
23
23
|
.xontable-wrap.theme-dark .xontable-rownum-cell,
|
|
24
24
|
.xontable-wrap.theme-dark .xontable-group-cell {
|
|
25
|
-
background: #2b2d31;
|
|
26
|
-
color: #e6e6e6;
|
|
25
|
+
background: var(--xontable-dark-head-bg, #2b2d31);
|
|
26
|
+
color: var(--xontable-dark-text, #e6e6e6);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.xontable-wrap.theme-dark .xontable-head-cell.is-active-col-head,
|
|
30
30
|
.xontable-wrap.theme-dark .xontable-rownum-cell.is-active-rownum {
|
|
31
|
-
background: #344769;
|
|
31
|
+
background: var(--xontable-dark-active-head-bg, #344769);
|
|
32
32
|
}
|
|
33
|
+
.xontable-wrap.theme-dark .xontable-status { background: var(--xontable-dark-head-bg, #2b2d31); border-top-color: var(--xontable-dark-border, #3a3a3a); color: var(--xontable-dark-text, #e6e6e6); }
|
|
34
|
+
.xontable-wrap.theme-dark .xontable-status-count { background: #2a3552; color: #c7d2fe; }
|
|
35
|
+
.xontable-wrap.theme-dark .xontable-status-count.is-error { background: #3a1f1f; color: #fca5a5; }
|
|
36
|
+
.xontable-wrap.theme-dark .xontable-status-num { background: #374151; color: #fff; }
|
|
37
|
+
.xontable-wrap.theme-dark .xontable-status-count.is-error .xontable-status-num { background: #dc2626; }
|
|
38
|
+
.xontable-wrap.theme-dark .xontable-status-item { color: var(--xontable-dark-text, #e6e6e6); background: #1e222b; border-color: var(--xontable-dark-border, #3a3a3a); }
|
|
39
|
+
.xontable-wrap.theme-dark .xontable-status-item:hover { background: #2a3552; border-color: #3b4a6b; }
|
|
40
|
+
.xontable-wrap.theme-dark .xontable-status-item.is-error { background: #3a1f1f; border-color: #dc2626; color: #fca5a5; }
|
|
41
|
+
.xontable-wrap.theme-dark .xontable-status-item.is-chip-0 { background: #23304a; border-color: #3b4a6b; color: #c7d2fe; }
|
|
42
|
+
.xontable-wrap.theme-dark .xontable-status-item.is-chip-1 { background: #1d2f28; border-color: #2f5f4a; color: #6ee7b7; }
|
|
43
|
+
.xontable-wrap.theme-dark .xontable-status-item.is-chip-2 { background: #2b251d; border-color: #6b4a2f; color: #fdba74; }
|
|
33
44
|
|
|
34
|
-
.xontable-wrap.theme-dark.is-readonly { border-color: #2c2f36; background: #1b1c1f; }
|
|
35
|
-
.xontable-wrap.theme-dark.is-readonly .xontable { color: #e6e6e6; }
|
|
36
|
-
.xontable-wrap.theme-dark.is-readonly .xontable-cell { border-bottom-color: #2f333b; background: #1b1c1f; }
|
|
45
|
+
.xontable-wrap.theme-dark.is-readonly { border-color: var(--xontable-dark-readonly-border, #2c2f36); background: var(--xontable-dark-readonly-bg, #1b1c1f); }
|
|
46
|
+
.xontable-wrap.theme-dark.is-readonly .xontable { color: var(--xontable-dark-text, #e6e6e6); }
|
|
47
|
+
.xontable-wrap.theme-dark.is-readonly .xontable-cell { border-bottom-color: #2f333b; background: var(--xontable-dark-readonly-bg, #1b1c1f); }
|
|
37
48
|
.xontable-wrap.theme-dark.is-readonly .xontable-head-cell,
|
|
38
49
|
.xontable-wrap.theme-dark.is-readonly .xontable-rownum-cell,
|
|
39
|
-
.xontable-wrap.theme-dark.is-readonly .xontable-group-cell { background: #23252b; color: #e6e6e6; }
|
|
40
|
-
.xontable-wrap.theme-dark.is-readonly .xontable-
|
|
41
|
-
.xontable-wrap.theme-dark.is-readonly .xontable-row.is-zebra .xontable-
|
|
42
|
-
.xontable-wrap.theme-dark.is-readonly .xontable-
|
|
50
|
+
.xontable-wrap.theme-dark.is-readonly .xontable-group-cell { background: var(--xontable-dark-readonly-head-bg, #23252b); color: var(--xontable-dark-text, #e6e6e6); }
|
|
51
|
+
.xontable-wrap.theme-dark.is-readonly .xontable-rownum-cell { background: var(--xontable-dark-readonly-rownum-bg, #23252b); }
|
|
52
|
+
.xontable-wrap.theme-dark.is-readonly .xontable-row.is-zebra .xontable-cell { background: var(--xontable-dark-readonly-zebra-bg, #202329); }
|
|
53
|
+
.xontable-wrap.theme-dark.is-readonly .xontable-row.is-zebra .xontable-rownum-cell { background: var(--xontable-dark-readonly-zebra-bg, #1e2025); }
|
|
54
|
+
.xontable-wrap.theme-dark.is-readonly .xontable-cell.is-active { outline-color: var(--xontable-dark-accent, #8ab4f8); }
|
package/dist/types.d.ts
CHANGED
|
@@ -32,6 +32,31 @@ export type XOnTableProps<Row extends Record<string, any> = any> = {
|
|
|
32
32
|
rowIdKey?: keyof Row;
|
|
33
33
|
readOnly?: boolean;
|
|
34
34
|
theme?: "light" | "dark";
|
|
35
|
+
showStatusBar?: boolean;
|
|
36
|
+
darkThemeColors?: Partial<{
|
|
37
|
+
bg: string;
|
|
38
|
+
border: string;
|
|
39
|
+
text: string;
|
|
40
|
+
cellBg: string;
|
|
41
|
+
headBg: string;
|
|
42
|
+
rownumBg: string;
|
|
43
|
+
groupBg: string;
|
|
44
|
+
zebraBg: string;
|
|
45
|
+
activeHeadBg: string;
|
|
46
|
+
range: string;
|
|
47
|
+
copy: string;
|
|
48
|
+
accent: string;
|
|
49
|
+
select: string;
|
|
50
|
+
invalidBg: string;
|
|
51
|
+
invalidBorder: string;
|
|
52
|
+
editorBg: string;
|
|
53
|
+
editorText: string;
|
|
54
|
+
readonlyBg: string;
|
|
55
|
+
readonlyBorder: string;
|
|
56
|
+
readonlyHeadBg: string;
|
|
57
|
+
readonlyRownumBg: string;
|
|
58
|
+
readonlyZebraBg: string;
|
|
59
|
+
}>;
|
|
35
60
|
onChange?: (rows: Row[], meta: XOnTableMeta) => void;
|
|
36
61
|
};
|
|
37
62
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5E,MAAM,MAAM,SAAS,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClD,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI;IACjE,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1B,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACtD,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5E,MAAM,MAAM,SAAS,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,IAAI,CAAC;CACxD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClD,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI;IACjE,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IAC1B,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;QACxB,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACtD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xontable",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,8 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^19.0.0",
|
|
29
|
-
"react-dom": "^19.0.0"
|
|
30
|
-
"lucide-react": "^0.468.0"
|
|
29
|
+
"react-dom": "^19.0.0"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"typescript": "^5.9.3"
|