@jielga/tmdatagrid 2.5.0 → 2.6.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/dist/index.d.ts +69 -8
- package/dist/index.js +337 -284
- package/dist/index.js.map +1 -1
- package/docs/components.md +3 -1
- package/docs/editors.md +96 -6
- package/docs/testing.md +1 -0
- package/package.json +1 -1
- package/skills/appearance/SKILL.md +1 -1
- package/skills/cell-selection/SKILL.md +1 -1
- package/skills/columns/SKILL.md +1 -1
- package/skills/data/SKILL.md +1 -1
- package/skills/editing/SKILL.md +15 -17
- package/skills/editing/references/editing-api.md +2 -1
- package/skills/editing/references/editors-and-validation.md +79 -4
- package/skills/filtering/SKILL.md +1 -1
- package/skills/getting-started/SKILL.md +1 -1
- package/skills/grouping/SKILL.md +1 -1
- package/skills/migrating-to-2/SKILL.md +1 -1
- package/skills/options/SKILL.md +1 -1
- package/skills/rows/SKILL.md +1 -1
- package/skills/server-side/SKILL.md +1 -1
- package/skills/testing/SKILL.md +1 -1
- package/skills/testing-components/SKILL.md +1 -1
- package/skills/testing-editing/SKILL.md +4 -2
- package/src/components/editors/TMDataGridBooleanEditor.tsx +26 -4
- package/src/components/editors/TMDataGridDateEditor.tsx +33 -5
- package/src/components/editors/TMDataGridMultiSelectEditor.tsx +39 -6
- package/src/components/editors/TMDataGridNumberEditor.tsx +33 -6
- package/src/components/editors/TMDataGridSelectEditor.tsx +39 -6
- package/src/components/editors/TMDataGridStringEditor.tsx +33 -6
- package/src/components/editors/editorShared.ts +27 -1
- package/src/index.ts +24 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MultiSelect } from "@mantine/core";
|
|
1
|
+
import { MultiSelect, type MultiSelectProps } from "@mantine/core";
|
|
2
2
|
import type { TMDataGridEditorArgs } from "../../core/editEngine";
|
|
3
3
|
import {
|
|
4
4
|
optionsToComboboxData,
|
|
@@ -6,7 +6,35 @@ import {
|
|
|
6
6
|
} from "../../core/columnOptions";
|
|
7
7
|
import { getColumnLabel } from "../../core/columnUtils";
|
|
8
8
|
import { useTMDataGridContext } from "../../TMDataGridContext";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
useFieldInvalid,
|
|
11
|
+
useFieldValue,
|
|
12
|
+
type EditorDataAttributes,
|
|
13
|
+
} from "./editorShared";
|
|
14
|
+
|
|
15
|
+
export type TMDataGridMultiSelectEditorProps = TMDataGridEditorArgs & {
|
|
16
|
+
/**
|
|
17
|
+
* Props for the Mantine `MultiSelect`. The grid keeps `data`, the value,
|
|
18
|
+
* `onChange`, `error`, `size`, the accessible name and
|
|
19
|
+
* `comboboxProps.withinPortal`; `onBlur` runs after the grid's own.
|
|
20
|
+
*/
|
|
21
|
+
inputProps?: Omit<
|
|
22
|
+
MultiSelectProps,
|
|
23
|
+
| "data"
|
|
24
|
+
| "value"
|
|
25
|
+
| "defaultValue"
|
|
26
|
+
| "onChange"
|
|
27
|
+
| "error"
|
|
28
|
+
| "size"
|
|
29
|
+
| "aria-label"
|
|
30
|
+
| "comboboxProps"
|
|
31
|
+
> & {
|
|
32
|
+
comboboxProps?: Omit<
|
|
33
|
+
NonNullable<MultiSelectProps["comboboxProps"]>,
|
|
34
|
+
"withinPortal"
|
|
35
|
+
>;
|
|
36
|
+
} & EditorDataAttributes;
|
|
37
|
+
};
|
|
10
38
|
|
|
11
39
|
/**
|
|
12
40
|
* The built-in editor for `meta.type: "multiSelect"` - cells holding string
|
|
@@ -19,16 +47,18 @@ export function TMDataGridMultiSelectEditor({
|
|
|
19
47
|
row,
|
|
20
48
|
table,
|
|
21
49
|
size,
|
|
22
|
-
|
|
50
|
+
inputProps,
|
|
51
|
+
}: TMDataGridMultiSelectEditorProps) {
|
|
23
52
|
const { labels } = useTMDataGridContext();
|
|
24
53
|
const value = useFieldValue(field);
|
|
25
54
|
const invalid = useFieldInvalid(field);
|
|
26
55
|
return (
|
|
27
56
|
<MultiSelect
|
|
28
|
-
size={size}
|
|
29
57
|
w="100%"
|
|
30
58
|
searchable
|
|
31
|
-
|
|
59
|
+
{...inputProps}
|
|
60
|
+
size={size}
|
|
61
|
+
comboboxProps={{ ...inputProps?.comboboxProps, withinPortal: false }}
|
|
32
62
|
aria-label={labels.editCell(getColumnLabel(column))}
|
|
33
63
|
data-dg-part="editor-input"
|
|
34
64
|
data={optionsToComboboxData(
|
|
@@ -36,7 +66,10 @@ export function TMDataGridMultiSelectEditor({
|
|
|
36
66
|
)}
|
|
37
67
|
value={Array.isArray(value) ? value.map(String) : []}
|
|
38
68
|
onChange={(next) => field.handleChange(next)}
|
|
39
|
-
onBlur={
|
|
69
|
+
onBlur={(event) => {
|
|
70
|
+
field.handleBlur();
|
|
71
|
+
inputProps?.onBlur?.(event);
|
|
72
|
+
}}
|
|
40
73
|
error={invalid}
|
|
41
74
|
/>
|
|
42
75
|
);
|
|
@@ -1,17 +1,37 @@
|
|
|
1
|
-
import { NumberInput } from "@mantine/core";
|
|
1
|
+
import { NumberInput, type NumberInputProps } from "@mantine/core";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import type { TMDataGridEditorArgs } from "../../core/editEngine";
|
|
4
4
|
import { getColumnLabel } from "../../core/columnUtils";
|
|
5
5
|
import { useTMDataGridContext } from "../../TMDataGridContext";
|
|
6
6
|
import {
|
|
7
|
+
mergeRefs,
|
|
7
8
|
selectAllOnFocus,
|
|
8
9
|
useCaretKeeper,
|
|
9
10
|
useFieldInvalid,
|
|
10
11
|
useFieldValue,
|
|
12
|
+
type EditorDataAttributes,
|
|
11
13
|
} from "./editorShared";
|
|
12
14
|
|
|
15
|
+
export type TMDataGridNumberEditorProps = TMDataGridEditorArgs & {
|
|
16
|
+
/**
|
|
17
|
+
* Props for the Mantine `NumberInput`. The grid keeps the value, `onChange`,
|
|
18
|
+
* `error`, `size` and the accessible name; `onFocus` and `onBlur` run after
|
|
19
|
+
* the grid's own, and `ref` receives the input beside the grid's ref.
|
|
20
|
+
*/
|
|
21
|
+
inputProps?: Omit<
|
|
22
|
+
NumberInputProps,
|
|
23
|
+
"value" | "defaultValue" | "onChange" | "error" | "size" | "aria-label"
|
|
24
|
+
> &
|
|
25
|
+
EditorDataAttributes;
|
|
26
|
+
};
|
|
27
|
+
|
|
13
28
|
/** The built-in editor for `meta.type: "number"`. */
|
|
14
|
-
export function TMDataGridNumberEditor({
|
|
29
|
+
export function TMDataGridNumberEditor({
|
|
30
|
+
field,
|
|
31
|
+
column,
|
|
32
|
+
size,
|
|
33
|
+
inputProps,
|
|
34
|
+
}: TMDataGridNumberEditorProps) {
|
|
15
35
|
const { labels } = useTMDataGridContext();
|
|
16
36
|
const value = useFieldValue(field);
|
|
17
37
|
const invalid = useFieldInvalid(field);
|
|
@@ -31,11 +51,15 @@ export function TMDataGridNumberEditor({ field, column, size }: TMDataGridEditor
|
|
|
31
51
|
: value === null;
|
|
32
52
|
return (
|
|
33
53
|
<NumberInput
|
|
34
|
-
ref={inputRef}
|
|
35
|
-
size={size}
|
|
36
54
|
w="100%"
|
|
37
|
-
onFocus={selectAllOnFocus}
|
|
38
55
|
hideControls
|
|
56
|
+
{...inputProps}
|
|
57
|
+
ref={mergeRefs(inputRef, inputProps?.ref)}
|
|
58
|
+
size={size}
|
|
59
|
+
onFocus={(event) => {
|
|
60
|
+
selectAllOnFocus(event);
|
|
61
|
+
inputProps?.onFocus?.(event);
|
|
62
|
+
}}
|
|
39
63
|
aria-label={labels.editCell(getColumnLabel(column))}
|
|
40
64
|
data-dg-part="editor-input"
|
|
41
65
|
value={
|
|
@@ -63,7 +87,10 @@ export function TMDataGridNumberEditor({ field, column, size }: TMDataGridEditor
|
|
|
63
87
|
next !== "" && Number.isFinite(parsed) ? parsed : null,
|
|
64
88
|
);
|
|
65
89
|
}}
|
|
66
|
-
onBlur={
|
|
90
|
+
onBlur={(event) => {
|
|
91
|
+
field.handleBlur();
|
|
92
|
+
inputProps?.onBlur?.(event);
|
|
93
|
+
}}
|
|
67
94
|
error={invalid}
|
|
68
95
|
/>
|
|
69
96
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Select } from "@mantine/core";
|
|
1
|
+
import { Select, type SelectProps } from "@mantine/core";
|
|
2
2
|
import type { TMDataGridEditorArgs } from "../../core/editEngine";
|
|
3
3
|
import {
|
|
4
4
|
optionsToComboboxData,
|
|
@@ -6,7 +6,35 @@ import {
|
|
|
6
6
|
} from "../../core/columnOptions";
|
|
7
7
|
import { getColumnLabel } from "../../core/columnUtils";
|
|
8
8
|
import { useTMDataGridContext } from "../../TMDataGridContext";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
useFieldInvalid,
|
|
11
|
+
useFieldValue,
|
|
12
|
+
type EditorDataAttributes,
|
|
13
|
+
} from "./editorShared";
|
|
14
|
+
|
|
15
|
+
export type TMDataGridSelectEditorProps = TMDataGridEditorArgs & {
|
|
16
|
+
/**
|
|
17
|
+
* Props for the Mantine `Select`. The grid keeps `data`, the value,
|
|
18
|
+
* `onChange`, `error`, `size`, the accessible name and
|
|
19
|
+
* `comboboxProps.withinPortal`; `onBlur` runs after the grid's own.
|
|
20
|
+
*/
|
|
21
|
+
inputProps?: Omit<
|
|
22
|
+
SelectProps,
|
|
23
|
+
| "data"
|
|
24
|
+
| "value"
|
|
25
|
+
| "defaultValue"
|
|
26
|
+
| "onChange"
|
|
27
|
+
| "error"
|
|
28
|
+
| "size"
|
|
29
|
+
| "aria-label"
|
|
30
|
+
| "comboboxProps"
|
|
31
|
+
> & {
|
|
32
|
+
comboboxProps?: Omit<
|
|
33
|
+
NonNullable<SelectProps["comboboxProps"]>,
|
|
34
|
+
"withinPortal"
|
|
35
|
+
>;
|
|
36
|
+
} & EditorDataAttributes;
|
|
37
|
+
};
|
|
10
38
|
|
|
11
39
|
/**
|
|
12
40
|
* The built-in editor for `meta.type: "select"`. Options come from the same
|
|
@@ -20,18 +48,20 @@ export function TMDataGridSelectEditor({
|
|
|
20
48
|
table,
|
|
21
49
|
size,
|
|
22
50
|
commit,
|
|
23
|
-
|
|
51
|
+
inputProps,
|
|
52
|
+
}: TMDataGridSelectEditorProps) {
|
|
24
53
|
const { labels, features } = useTMDataGridContext();
|
|
25
54
|
const value = useFieldValue(field);
|
|
26
55
|
const invalid = useFieldInvalid(field);
|
|
27
56
|
return (
|
|
28
57
|
<Select
|
|
29
|
-
size={size}
|
|
30
58
|
w="100%"
|
|
31
59
|
searchable
|
|
60
|
+
{...inputProps}
|
|
61
|
+
size={size}
|
|
32
62
|
// Inside the cell, so picking an option is not a click-away - the same
|
|
33
63
|
// reason the filter panel keeps its dropdowns unportalled.
|
|
34
|
-
comboboxProps={{ withinPortal: false }}
|
|
64
|
+
comboboxProps={{ ...inputProps?.comboboxProps, withinPortal: false }}
|
|
35
65
|
aria-label={labels.editCell(getColumnLabel(column))}
|
|
36
66
|
data-dg-part="editor-input"
|
|
37
67
|
data={optionsToComboboxData(
|
|
@@ -44,7 +74,10 @@ export function TMDataGridSelectEditor({
|
|
|
44
74
|
// The confirming modes leave the draft for their explicit commit.
|
|
45
75
|
if (next !== null && features.editMode === "cell") void commit();
|
|
46
76
|
}}
|
|
47
|
-
onBlur={
|
|
77
|
+
onBlur={(event) => {
|
|
78
|
+
field.handleBlur();
|
|
79
|
+
inputProps?.onBlur?.(event);
|
|
80
|
+
}}
|
|
48
81
|
error={invalid}
|
|
49
82
|
/>
|
|
50
83
|
);
|
|
@@ -1,26 +1,50 @@
|
|
|
1
|
-
import { TextInput } from "@mantine/core";
|
|
1
|
+
import { TextInput, type TextInputProps } from "@mantine/core";
|
|
2
2
|
import type { TMDataGridEditorArgs } from "../../core/editEngine";
|
|
3
3
|
import { getColumnLabel } from "../../core/columnUtils";
|
|
4
4
|
import { useTMDataGridContext } from "../../TMDataGridContext";
|
|
5
5
|
import {
|
|
6
|
+
mergeRefs,
|
|
6
7
|
selectAllOnFocus,
|
|
7
8
|
useCaretKeeper,
|
|
8
9
|
useFieldInvalid,
|
|
9
10
|
useFieldValue,
|
|
11
|
+
type EditorDataAttributes,
|
|
10
12
|
} from "./editorShared";
|
|
11
13
|
|
|
14
|
+
export type TMDataGridStringEditorProps = TMDataGridEditorArgs & {
|
|
15
|
+
/**
|
|
16
|
+
* Props for the Mantine `TextInput`. The grid keeps the value, `onChange`,
|
|
17
|
+
* `error`, `size` and the accessible name; `onFocus` and `onBlur` run after
|
|
18
|
+
* the grid's own, and `ref` receives the input beside the grid's ref.
|
|
19
|
+
*/
|
|
20
|
+
inputProps?: Omit<
|
|
21
|
+
TextInputProps,
|
|
22
|
+
"value" | "defaultValue" | "onChange" | "error" | "size" | "aria-label"
|
|
23
|
+
> &
|
|
24
|
+
EditorDataAttributes;
|
|
25
|
+
};
|
|
26
|
+
|
|
12
27
|
/** The built-in editor for `meta.type: "string"` (and the default). */
|
|
13
|
-
export function TMDataGridStringEditor({
|
|
28
|
+
export function TMDataGridStringEditor({
|
|
29
|
+
field,
|
|
30
|
+
column,
|
|
31
|
+
size,
|
|
32
|
+
inputProps,
|
|
33
|
+
}: TMDataGridStringEditorProps) {
|
|
14
34
|
const { labels } = useTMDataGridContext();
|
|
15
35
|
const value = useFieldValue(field);
|
|
16
36
|
const invalid = useFieldInvalid(field);
|
|
17
37
|
const { inputRef, remember } = useCaretKeeper();
|
|
18
38
|
return (
|
|
19
39
|
<TextInput
|
|
20
|
-
ref={inputRef}
|
|
21
|
-
size={size}
|
|
22
40
|
w="100%"
|
|
23
|
-
|
|
41
|
+
{...inputProps}
|
|
42
|
+
ref={mergeRefs(inputRef, inputProps?.ref)}
|
|
43
|
+
size={size}
|
|
44
|
+
onFocus={(event) => {
|
|
45
|
+
selectAllOnFocus(event);
|
|
46
|
+
inputProps?.onFocus?.(event);
|
|
47
|
+
}}
|
|
24
48
|
aria-label={labels.editCell(getColumnLabel(column))}
|
|
25
49
|
data-dg-part="editor-input"
|
|
26
50
|
value={typeof value === "string" ? value : ""}
|
|
@@ -28,7 +52,10 @@ export function TMDataGridStringEditor({ field, column, size }: TMDataGridEditor
|
|
|
28
52
|
remember(event.currentTarget);
|
|
29
53
|
field.handleChange(event.currentTarget.value);
|
|
30
54
|
}}
|
|
31
|
-
onBlur={
|
|
55
|
+
onBlur={(event) => {
|
|
56
|
+
field.handleBlur();
|
|
57
|
+
inputProps?.onBlur?.(event);
|
|
58
|
+
}}
|
|
32
59
|
error={invalid}
|
|
33
60
|
/>
|
|
34
61
|
);
|
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
import { useStore } from "@tanstack/react-form";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useLayoutEffect,
|
|
4
|
+
useRef,
|
|
5
|
+
type Ref,
|
|
6
|
+
type RefCallback,
|
|
7
|
+
type RefObject,
|
|
8
|
+
} from "react";
|
|
3
9
|
import { isInputElement } from "../../core/dom";
|
|
4
10
|
import { firstErrorText, type TMDataGridEditField } from "../../core/editEngine";
|
|
5
11
|
|
|
12
|
+
/**
|
|
13
|
+
* `data-*` attributes for a built-in editor's `inputProps`. JSX accepts them
|
|
14
|
+
* on any element, but a props object literal only takes declared keys.
|
|
15
|
+
*/
|
|
16
|
+
export type EditorDataAttributes = {
|
|
17
|
+
[attribute: `data-${string}`]: string | number | boolean | undefined;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** One ref callback feeding the grid's own ref and the consumer's. */
|
|
21
|
+
export function mergeRefs<T>(
|
|
22
|
+
...refs: Array<Ref<T> | undefined>
|
|
23
|
+
): RefCallback<T> {
|
|
24
|
+
return (node) => {
|
|
25
|
+
for (const ref of refs) {
|
|
26
|
+
if (typeof ref === "function") ref(node);
|
|
27
|
+
else if (ref !== null && ref !== undefined) ref.current = node;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
6
32
|
/** The field's live value - one subscription, on the field's own store. */
|
|
7
33
|
export function useFieldValue(field: TMDataGridEditField): unknown {
|
|
8
34
|
return useStore(field.store, (state) => state.value as unknown);
|
package/src/index.ts
CHANGED
|
@@ -143,12 +143,30 @@ export { DgRangeSliderFilter } from "./components/filters/DgRangeSliderFilter";
|
|
|
143
143
|
export { DgDateRangeFilter } from "./components/filters/DgDateRangeFilter";
|
|
144
144
|
export { DgAutocompleteFilter } from "./components/filters/DgAutocompleteFilter";
|
|
145
145
|
export { DgTriStateFilter } from "./components/filters/DgTriStateFilter";
|
|
146
|
-
export {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
export {
|
|
151
|
-
|
|
146
|
+
export {
|
|
147
|
+
TMDataGridStringEditor,
|
|
148
|
+
type TMDataGridStringEditorProps,
|
|
149
|
+
} from "./components/editors/TMDataGridStringEditor";
|
|
150
|
+
export {
|
|
151
|
+
TMDataGridNumberEditor,
|
|
152
|
+
type TMDataGridNumberEditorProps,
|
|
153
|
+
} from "./components/editors/TMDataGridNumberEditor";
|
|
154
|
+
export {
|
|
155
|
+
TMDataGridBooleanEditor,
|
|
156
|
+
type TMDataGridBooleanEditorProps,
|
|
157
|
+
} from "./components/editors/TMDataGridBooleanEditor";
|
|
158
|
+
export {
|
|
159
|
+
TMDataGridDateEditor,
|
|
160
|
+
type TMDataGridDateEditorProps,
|
|
161
|
+
} from "./components/editors/TMDataGridDateEditor";
|
|
162
|
+
export {
|
|
163
|
+
TMDataGridSelectEditor,
|
|
164
|
+
type TMDataGridSelectEditorProps,
|
|
165
|
+
} from "./components/editors/TMDataGridSelectEditor";
|
|
166
|
+
export {
|
|
167
|
+
TMDataGridMultiSelectEditor,
|
|
168
|
+
type TMDataGridMultiSelectEditorProps,
|
|
169
|
+
} from "./components/editors/TMDataGridMultiSelectEditor";
|
|
152
170
|
export {
|
|
153
171
|
mergeLabels,
|
|
154
172
|
TMDATAGRID_LABELS_EN,
|