@vuu-ui/vuu-data-editing 5.0.0-alpha.2 → 5.0.0-alpha.4
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 +40 -3
- package/package.json +7 -6
- package/src/DirectEditSession.js +8 -1
- package/src/EditButtons.js +6 -5
- package/src/EditModeProvider.js +14 -5
- package/src/EditSession.js +78 -8
- package/src/edit-control/EditControlCheckbox.js +25 -0
- package/src/edit-control/EditControlDropdown.js +34 -0
- package/src/edit-control/EditControlLookupDropdown.js +31 -0
- package/src/edit-control/get-data-item-edit-control.js +139 -0
- package/src/edit-control/index.js +4 -0
- package/src/edit-errors.js +7 -0
- package/src/edit-field/EditField.js +117 -24
- package/src/edit-field/useEditField.js +66 -52
- package/src/edit-form/CreateRowForm.js +37 -0
- package/src/edit-form/EditForm.css.js +32 -0
- package/src/edit-form/EditForm.js +85 -0
- package/src/edit-form/EditFormButtons.js +48 -0
- package/src/edit-form/EditFormContext.js +4 -0
- package/src/edit-form/index.js +4 -0
- package/src/form-fields.js +40 -0
- package/src/index.js +9 -0
- package/src/lookup-values/useLookupOptions.js +106 -0
- package/src/useConfirmDiscard.js +34 -0
- package/src/useCustomEditField.js +76 -0
- package/src/useEditForm.js +306 -0
- package/src/useEditSessionState.js +72 -0
- package/src/useEditable.js +26 -9
- package/src/useEditableColumns.js +105 -0
- package/src/useEditableTable.js +32 -9
- package/types/DirectEditSession.d.ts +6 -1
- package/types/EditButtons.d.ts +20 -3
- package/types/EditModeProvider.d.ts +10 -2
- package/types/EditSession.d.ts +18 -1
- package/types/edit-control/EditControlCheckbox.d.ts +8 -0
- package/types/edit-control/EditControlDropdown.d.ts +14 -0
- package/types/edit-control/EditControlLookupDropdown.d.ts +13 -0
- package/types/edit-control/get-data-item-edit-control.d.ts +40 -0
- package/types/edit-control/index.d.ts +4 -0
- package/types/edit-errors.d.ts +9 -0
- package/types/edit-field/EditField.d.ts +37 -3
- package/types/edit-field/useEditField.d.ts +2 -1
- package/types/edit-form/CreateRowForm.d.ts +29 -0
- package/types/edit-form/EditForm.d.ts +36 -0
- package/types/edit-form/EditFormButtons.d.ts +18 -0
- package/types/edit-form/EditFormContext.d.ts +59 -0
- package/types/edit-form/index.d.ts +4 -0
- package/types/form-fields.d.ts +32 -0
- package/types/index.d.ts +12 -2
- package/types/lookup-values/useLookupOptions.d.ts +35 -0
- package/types/useConfirmDiscard.d.ts +23 -0
- package/types/useCustomEditField.d.ts +51 -0
- package/types/useEditForm.d.ts +127 -0
- package/types/useEditSessionState.d.ts +27 -0
- package/types/useEditable.d.ts +30 -3
- package/types/useEditableColumns.d.ts +79 -0
- package/types/useEditableTable.d.ts +18 -3
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { CreateRowForm, type CreateRowFormField, type CreateRowFormProps, } from "./CreateRowForm";
|
|
2
|
+
export { EditForm, type EditFormProps } from "./EditForm";
|
|
3
|
+
export { EditFormButtons, type EditFormButtonsProps, } from "./EditFormButtons";
|
|
4
|
+
export { useEditFormContext } from "./EditFormContext";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DataValueDescriptor, TableSchema } from "@vuu-ui/vuu-data-types";
|
|
2
|
+
export interface FormFieldsOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Table columns, e.g. `config.columns`. Their `label`, `editor`, `type`
|
|
5
|
+
* and `editable` carry over to the fields, and they come first, in this
|
|
6
|
+
* order.
|
|
7
|
+
*/
|
|
8
|
+
columns?: readonly DataValueDescriptor[];
|
|
9
|
+
/**
|
|
10
|
+
* Choose the fields, in order, rather than generating one per schema
|
|
11
|
+
* column. Each is still overlaid on its schema column (and table column).
|
|
12
|
+
*/
|
|
13
|
+
fields?: readonly DataValueDescriptor[];
|
|
14
|
+
/**
|
|
15
|
+
* `insert` for a create form: fields that can't be set on a new row are
|
|
16
|
+
* left out. @default "update"
|
|
17
|
+
*/
|
|
18
|
+
operation?: "insert" | "update";
|
|
19
|
+
/** The server schema, usually `dataSource.tableSchema`. */
|
|
20
|
+
schema?: TableSchema;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The fields of a generated form: one per schema column, except the
|
|
24
|
+
* server-maintained `vuuCreatedTimestamp`, `vuuUpdatedTimestamp` and
|
|
25
|
+
* `vuuMsg`. Columns also in `columns` come first, in that order, then the
|
|
26
|
+
* rest in schema order. Each field is the schema column overlaid with the
|
|
27
|
+
* matching table column, so a column's `label`, `editor` and `type` carry
|
|
28
|
+
* over, and its `editable` can narrow, never widen, the server's.
|
|
29
|
+
*
|
|
30
|
+
* Without a schema, the fields are generated from `columns`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const getFormFields: ({ columns, fields, operation, schema, }: FormFieldsOptions) => DataValueDescriptor[];
|
package/types/index.d.ts
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
export { DataEditingProvider, useEditSession, useTableEditSession, } from "./DataEditingProvider";
|
|
2
|
-
export { DirectEditSession, type DirectEditSessionConstructorProps, } from "./DirectEditSession";
|
|
2
|
+
export { DirectEditSession, type DirectEditSessionConstructorProps, type DirectEditValidator, } from "./DirectEditSession";
|
|
3
3
|
export type { TableEditSession, TableEditSessionEvents, } from "./TableEditSession";
|
|
4
4
|
export { useCellEdited } from "./useCellEdited";
|
|
5
5
|
export { useEditState } from "./useEditState";
|
|
6
|
+
export { useEditSessionState, type EditSessionStateSnapshot, } from "./useEditSessionState";
|
|
7
|
+
export type { EditErrorHandler, EditOperation } from "./edit-errors";
|
|
6
8
|
export { getVuuEditMessage, isInlineEditingSession, isEditRowReadOnly, withDataRowEditErrors, } from "./edit-utils";
|
|
7
9
|
export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
8
10
|
export { EditField, type DropdownEditFieldProps, type EditFieldProps, type EditFieldType, type TextFieldType, } from "./edit-field/EditField";
|
|
9
11
|
export { useEditField, type EditFieldHookProps, } from "./edit-field/useEditField";
|
|
10
12
|
export { EditModeProvider, useEditMode, type EditModeContextProps, } from "./EditModeProvider";
|
|
11
|
-
export { EditError, EditSession, SupersededEditError, type AddRowResultData, type DeleteSelectedRowsResultData, type EditActionType, type EditCommitOptions, type EditLifecycle, type EditSessionConstructorProps, type EditSessionValue, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
|
|
13
|
+
export { EditError, EditSession, SupersededEditError, type AddRowResultData, type DeleteSelectedRowsResultData, type EditActionType, type EditCommitOptions, type EditLifecycle, type EditSessionApi, type EditSessionConstructorProps, type EditSessionValue, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
|
|
12
14
|
export { StaleUpdateError } from "@vuu-ui/vuu-utils";
|
|
13
15
|
export { lookupOptionsFromRows, useLookupValues, type LookupOption, type LookupValuedHookProps, type OptionMap, } from "./lookup-values/useLookupValues";
|
|
14
16
|
export { useEditable, type EditableHookProps } from "./useEditable";
|
|
15
17
|
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator, } from "./editActionRowClassNameGenerator";
|
|
16
18
|
export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps, } from "./UndoCellRenderer";
|
|
17
19
|
export { useEditableTable, type EditableTableHookProps, type EditMode, } from "./useEditableTable";
|
|
20
|
+
export { DEFAULT_READ_ONLY_COLUMNS, getEditableColumns, UNDO_COLUMN, useEditableColumns, narrowEditable, type EditableColumnsHookProps, } from "./useEditableColumns";
|
|
21
|
+
export { getDataRowValues, useEditForm, type EditFormFieldErrors, type EditFormHookProps, type EditFormHookResult, type EditFormMode, type EditFormValidator, type EditFormValues, } from "./useEditForm";
|
|
22
|
+
export { useLookupOptions, type LookupOptionsHookProps, type LookupOptionsHookResult, type LookupRow, } from "./lookup-values/useLookupOptions";
|
|
23
|
+
export { useCustomEditField, type CustomEditFieldHookProps, } from "./useCustomEditField";
|
|
24
|
+
export { useConfirmDiscard, type ConfirmDiscardHookProps, } from "./useConfirmDiscard";
|
|
25
|
+
export * from "./edit-form";
|
|
26
|
+
export * from "./edit-control";
|
|
27
|
+
export { type FormFieldsOptions, getFormFields } from "./form-fields";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { VuuRowDataItemType, VuuTable } from "@vuu-ui/vuu-protocol-types";
|
|
2
|
+
import { type LookupOption, type OptionMap } from "./useLookupValues";
|
|
3
|
+
export type LookupRow = Readonly<Record<string, VuuRowDataItemType>>;
|
|
4
|
+
export interface LookupOptionsHookProps<T = LookupOption> {
|
|
5
|
+
/** @default true */
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
/** The lookup table. */
|
|
8
|
+
table?: VuuTable;
|
|
9
|
+
/**
|
|
10
|
+
* Maps rows to `LookupOption` (`{ value, label, metadata }`). Either
|
|
11
|
+
* `optionMap` or `columns` plus `mapRow` is required.
|
|
12
|
+
*/
|
|
13
|
+
optionMap?: OptionMap;
|
|
14
|
+
/** Columns to subscribe to. Defaults to the columns named in `optionMap`. */
|
|
15
|
+
columns?: readonly string[];
|
|
16
|
+
/** Maps a row (column name to value) to an option. Overrides `optionMap`. */
|
|
17
|
+
mapRow?: (row: LookupRow) => T;
|
|
18
|
+
/** A Vuu filter expression, e.g. `ccy = "EUR"`. */
|
|
19
|
+
filter?: string;
|
|
20
|
+
/** @default 100 */
|
|
21
|
+
maxRows?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface LookupOptionsHookResult<T> {
|
|
24
|
+
options: T[];
|
|
25
|
+
loading: boolean;
|
|
26
|
+
error?: Error;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Subscribes to a (typically small) lookup table and maps its rows to
|
|
30
|
+
* options, e.g. for a dropdown. Unlike `useLookupValues`, this supports any
|
|
31
|
+
* row mapping, a filter and a row limit, and reports `loading` and `error`.
|
|
32
|
+
*
|
|
33
|
+
* Pass stable (memoized) values for `optionMap`, `columns` and `mapRow`.
|
|
34
|
+
*/
|
|
35
|
+
export declare const useLookupOptions: <T = LookupOption>({ columns: columnsProp, enabled, filter, mapRow, maxRows, optionMap, table, }: LookupOptionsHookProps<T>) => LookupOptionsHookResult<T>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ConfirmDiscardHookProps {
|
|
2
|
+
/** @default "Discard changes?" */
|
|
3
|
+
title?: string;
|
|
4
|
+
/** @default "You have unsaved changes. Discard them?" */
|
|
5
|
+
message?: string;
|
|
6
|
+
/** @default "Discard" */
|
|
7
|
+
confirmButtonLabel?: string;
|
|
8
|
+
/** @default "Keep editing" */
|
|
9
|
+
cancelButtonLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns a function that asks the user to confirm discarding unsaved
|
|
13
|
+
* changes. Resolves true if the user confirms. Pass it to
|
|
14
|
+
* `EditButtons.confirmCancel`, or call it before changing selection or
|
|
15
|
+
* closing a form.
|
|
16
|
+
*
|
|
17
|
+
* Requires a `ModalProvider` in scope.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const confirmDiscard = useConfirmDiscard();
|
|
21
|
+
* <EditButtons confirmCancel={confirmDiscard} ... />
|
|
22
|
+
*/
|
|
23
|
+
export declare const useConfirmDiscard: ({ cancelButtonLabel, confirmButtonLabel, message, title, }?: ConfirmDiscardHookProps) => () => Promise<boolean>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
|
|
2
|
+
import type { EditSession, EditSessionValue } from "./EditSession";
|
|
3
|
+
export interface CustomEditFieldHookProps<T extends EditSessionValue> {
|
|
4
|
+
/** Key of the row being edited. */
|
|
5
|
+
rowKey: string;
|
|
6
|
+
/** The column the value is saved to. */
|
|
7
|
+
name: string;
|
|
8
|
+
/**
|
|
9
|
+
* The saved value. The field resets to this value when it changes, and
|
|
10
|
+
* when the edit session ends.
|
|
11
|
+
*/
|
|
12
|
+
originalValue: T | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Compares an edited value with `originalValue`. When equal, the edit is
|
|
15
|
+
* reverted rather than committed, so the session is no longer dirty.
|
|
16
|
+
* @default Object.is
|
|
17
|
+
*/
|
|
18
|
+
equals?: (a: T, b: T) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Converts the value to the scalar sent to the server. Required when `T`
|
|
21
|
+
* is an object.
|
|
22
|
+
*/
|
|
23
|
+
serialize?: (value: T) => VuuRowDataItemType;
|
|
24
|
+
/** Defaults to the session from the enclosing DataEditingProvider. */
|
|
25
|
+
editSession?: EditSession;
|
|
26
|
+
/** Called when a commit fails. */
|
|
27
|
+
onError?: (error: Error) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Adapts a non-standard editor (a picker, a list editor, any custom control)
|
|
31
|
+
* to an EditSession. Tracks the current and original values, reverts the
|
|
32
|
+
* edit when the user restores the original value, and commits to the session
|
|
33
|
+
* table with `serialize(value)`.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const { value, setValue, isDirty } = useCustomEditField({
|
|
37
|
+
* rowKey: dataRow.key,
|
|
38
|
+
* name: "permissions",
|
|
39
|
+
* originalValue: permissions,
|
|
40
|
+
* equals: (a, b) => a.equals(b),
|
|
41
|
+
* serialize: (p) => JSON.stringify(p.toJSON()),
|
|
42
|
+
* });
|
|
43
|
+
*/
|
|
44
|
+
export declare const useCustomEditField: <T extends EditSessionValue>({ editSession: editSessionProp, equals, name, onError, originalValue, rowKey, serialize, }: CustomEditFieldHookProps<T>) => {
|
|
45
|
+
committing: boolean;
|
|
46
|
+
error: Error | undefined;
|
|
47
|
+
isDirty: boolean;
|
|
48
|
+
reset: () => void;
|
|
49
|
+
setValue: (nextValue: T) => Promise<void>;
|
|
50
|
+
value: T | undefined;
|
|
51
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { DataSource, DeleteRowMode } from "@vuu-ui/vuu-data-types";
|
|
2
|
+
import type { VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
|
|
3
|
+
import type { DataRow } from "@vuu-ui/vuu-table-types";
|
|
4
|
+
import { EditSession, type EditSessionApi, type EditSessionValue, type RowDefaultDataItemValues } from "./EditSession";
|
|
5
|
+
import { DirectEditSession } from "./DirectEditSession";
|
|
6
|
+
import { type EditErrorHandler } from "./edit-errors";
|
|
7
|
+
export type EditFormMode = "edit" | "create";
|
|
8
|
+
/**
|
|
9
|
+
* Edit mode only.
|
|
10
|
+
* - `session`: edits are staged in a session table and applied on Save.
|
|
11
|
+
* - `direct`: each field is validated and sent to `dataSource` as it is
|
|
12
|
+
* committed. There is nothing to save; `submit` just ends editing.
|
|
13
|
+
*/
|
|
14
|
+
export type EditFormEditModel = "session" | "direct";
|
|
15
|
+
export type EditFormValues = Readonly<Record<string, EditSessionValue | undefined>>;
|
|
16
|
+
/** Field name to error message. Return an empty object (or nothing) when valid. */
|
|
17
|
+
export type EditFormFieldErrors = Readonly<Record<string, string>>;
|
|
18
|
+
/**
|
|
19
|
+
* Cross-field validation run before the form is saved. Return error messages
|
|
20
|
+
* keyed by field name.
|
|
21
|
+
*/
|
|
22
|
+
export type EditFormValidator = (values: EditFormValues) => EditFormFieldErrors | undefined;
|
|
23
|
+
export interface EditFormHookProps {
|
|
24
|
+
/** Source table data source. */
|
|
25
|
+
dataSource: DataSource;
|
|
26
|
+
/**
|
|
27
|
+
* The row being edited (edit mode). Its values, merged with any edits, are
|
|
28
|
+
* passed to `validate`.
|
|
29
|
+
*/
|
|
30
|
+
dataRow?: DataRow;
|
|
31
|
+
/**
|
|
32
|
+
* `"edit"` edits the selected row(s) of `dataSource`. `"create"` adds a
|
|
33
|
+
* new row via an empty session table.
|
|
34
|
+
* @default "edit"
|
|
35
|
+
*/
|
|
36
|
+
mode?: EditFormMode;
|
|
37
|
+
/** Create mode: the form's fields, in tab order. */
|
|
38
|
+
columns?: readonly string[];
|
|
39
|
+
/**
|
|
40
|
+
* Fields that must have a value. In create mode, defaults to `columns`. In
|
|
41
|
+
* direct edit mode, an empty value for one of these is not sent.
|
|
42
|
+
*/
|
|
43
|
+
requiredColumns?: readonly string[];
|
|
44
|
+
/** @default "session" */
|
|
45
|
+
editModel?: EditFormEditModel;
|
|
46
|
+
/**
|
|
47
|
+
* Create mode only: add the new row to this session, owned by someone else
|
|
48
|
+
* (e.g. a table's edit session), rather than to a session of the form's
|
|
49
|
+
* own. Create then adds the row to the session without saving it; the
|
|
50
|
+
* owner saves or cancels the session.
|
|
51
|
+
*/
|
|
52
|
+
editSession?: EditSession;
|
|
53
|
+
/**
|
|
54
|
+
* Edit mode only: whether the edit session is active. When omitted, edit
|
|
55
|
+
* mode is read from the nearest EditModeProvider. Create mode is always
|
|
56
|
+
* active while the form is mounted.
|
|
57
|
+
*/
|
|
58
|
+
isEditMode?: boolean;
|
|
59
|
+
/** @default "soft" */
|
|
60
|
+
deleteMode?: DeleteRowMode;
|
|
61
|
+
/** @default "createSessionDataSource" */
|
|
62
|
+
editSessionApi?: EditSessionApi;
|
|
63
|
+
/** Default column values merged into the new row. Pass a stable reference. */
|
|
64
|
+
rowDefaults?: RowDefaultDataItemValues;
|
|
65
|
+
validate?: EditFormValidator;
|
|
66
|
+
/** Called once changes have been saved. */
|
|
67
|
+
onSaved?: () => void;
|
|
68
|
+
/** Called once the form has been cancelled. */
|
|
69
|
+
onCancelled?: () => void;
|
|
70
|
+
/** Called when begin, save or cancel fails. Defaults to console.error. */
|
|
71
|
+
onError?: EditErrorHandler;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Plain column values of a row. Table DataRows are Proxies with no own
|
|
75
|
+
* keys, so they cannot be spread; they serialize via `toJSON`.
|
|
76
|
+
*/
|
|
77
|
+
export declare const getDataRowValues: (dataRow: DataRow) => Record<string, VuuRowDataItemType>;
|
|
78
|
+
/**
|
|
79
|
+
* Owns an EditSession for a form that edits one entity, or creates one.
|
|
80
|
+
*
|
|
81
|
+
* - edit mode copies the selected row into a session table (`"Selected"`).
|
|
82
|
+
* - create mode begins an empty session table (`"Empty"`) and stages field
|
|
83
|
+
* values as a new-row draft. Render fields with
|
|
84
|
+
* `dataRow={{ key: EditSession.newRowKey }}` and `deferNewRow`.
|
|
85
|
+
*
|
|
86
|
+
* Call `submit()` to validate and save, `cancel()` to discard. Wrap the form
|
|
87
|
+
* in a `DataEditingProvider` with the returned `fieldEditSession`.
|
|
88
|
+
*
|
|
89
|
+
* With `editModel: "direct"` each field is validated and sent as it is
|
|
90
|
+
* committed. With a shared `editSession` (create mode), Create adds the row
|
|
91
|
+
* to that session, which its owner saves.
|
|
92
|
+
*/
|
|
93
|
+
export declare const useEditForm: ({ columns, dataRow, dataSource, deleteMode, editModel, editSession: sharedEditSession, editSessionApi, isEditMode: isEditModeProp, mode, onCancelled, onError, onSaved, requiredColumns, rowDefaults, validate, }: EditFormHookProps) => {
|
|
94
|
+
canCancel: boolean;
|
|
95
|
+
editState: import("./EditSession").EditState;
|
|
96
|
+
inEditMode: boolean;
|
|
97
|
+
isActive: boolean;
|
|
98
|
+
isEnding: boolean;
|
|
99
|
+
isStarting: boolean;
|
|
100
|
+
lifecycle: import("./EditSession").EditLifecycle;
|
|
101
|
+
newRowState: import("./EditSession").NewRowState;
|
|
102
|
+
canSave: boolean;
|
|
103
|
+
cancel: () => Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* The row being edited, a new-row placeholder in create mode. With
|
|
106
|
+
* direct editing, includes the values sent so far.
|
|
107
|
+
*/
|
|
108
|
+
dataRow: DataRow | undefined;
|
|
109
|
+
editModel: "direct" | "session";
|
|
110
|
+
editSession: EditSession;
|
|
111
|
+
/** Create mode: rows are added to a session owned by someone else. */
|
|
112
|
+
isSharedSession: boolean;
|
|
113
|
+
/** The session fields commit their edits to. */
|
|
114
|
+
fieldEditSession: DirectEditSession | EditSession;
|
|
115
|
+
error: Error | undefined;
|
|
116
|
+
fieldErrors: Readonly<Record<string, string>>;
|
|
117
|
+
getValues: () => EditFormValues;
|
|
118
|
+
isDirty: boolean;
|
|
119
|
+
isEditMode: boolean;
|
|
120
|
+
mode: EditFormMode;
|
|
121
|
+
/** Create mode: the row was added, saving the session failed. */
|
|
122
|
+
rowAdded: boolean;
|
|
123
|
+
saving: boolean;
|
|
124
|
+
setValue: (name: string, value: VuuRowDataItemType | undefined) => void;
|
|
125
|
+
submit: (force?: boolean) => Promise<boolean>;
|
|
126
|
+
};
|
|
127
|
+
export type EditFormHookResult = ReturnType<typeof useEditForm>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EditLifecycle, EditSession, EditState, NewRowState } from "./EditSession";
|
|
2
|
+
export interface EditSessionStateSnapshot {
|
|
3
|
+
/** True when the session can be cancelled (active, or a failed save). */
|
|
4
|
+
canCancel: boolean;
|
|
5
|
+
/** True when there are valid, unsaved changes (or a stale save to force). */
|
|
6
|
+
canSave: boolean;
|
|
7
|
+
editState: EditState;
|
|
8
|
+
/** The error from the most recent failed begin or end, if any. */
|
|
9
|
+
error?: Error;
|
|
10
|
+
/** True while a session is active, including while it is ending. */
|
|
11
|
+
inEditMode: boolean;
|
|
12
|
+
isActive: boolean;
|
|
13
|
+
isDirty: boolean;
|
|
14
|
+
isEnding: boolean;
|
|
15
|
+
isStarting: boolean;
|
|
16
|
+
lifecycle: EditLifecycle;
|
|
17
|
+
newRowState: NewRowState;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Subscribes to an EditSession and returns a single, render-safe snapshot of
|
|
21
|
+
* its state: editState, lifecycle, new-row draft and the derived flags most
|
|
22
|
+
* UIs need (canSave, canCancel, isDirty etc).
|
|
23
|
+
*
|
|
24
|
+
* Prefer this to adding `editState`/`lifecycle`/`newRow` listeners by hand.
|
|
25
|
+
* Returns an idle, clean snapshot when no session is provided.
|
|
26
|
+
*/
|
|
27
|
+
export declare const useEditSessionState: (editSession: EditSession | undefined) => EditSessionStateSnapshot;
|
package/types/useEditable.d.ts
CHANGED
|
@@ -1,13 +1,40 @@
|
|
|
1
|
-
import type { CopyOption, DataSource } from "@vuu-ui/vuu-data-types";
|
|
2
|
-
import { EditSession } from "./EditSession";
|
|
1
|
+
import type { CopyOption, DataSource, DeleteRowMode } from "@vuu-ui/vuu-data-types";
|
|
2
|
+
import { EditSession, type EditSessionApi, type RowDefaultDataItemValues } from "./EditSession";
|
|
3
|
+
import { type EditErrorHandler } from "./edit-errors";
|
|
3
4
|
export interface EditableHookProps {
|
|
5
|
+
/** @default "Selected" */
|
|
4
6
|
copyOption?: CopyOption;
|
|
5
7
|
dataSource: DataSource;
|
|
8
|
+
/** @default "soft" */
|
|
9
|
+
deleteMode?: DeleteRowMode;
|
|
10
|
+
/** @default "createSessionDataSource" */
|
|
11
|
+
editSessionApi?: EditSessionApi;
|
|
12
|
+
/**
|
|
13
|
+
* Controls the edit session. When omitted, edit mode is read from the
|
|
14
|
+
* nearest EditModeProvider.
|
|
15
|
+
*/
|
|
16
|
+
isEditMode?: boolean;
|
|
6
17
|
onCancel: () => void;
|
|
18
|
+
/** Called when begin, save or cancel fails. Defaults to console.error. */
|
|
19
|
+
onError?: EditErrorHandler;
|
|
7
20
|
onSave: () => void;
|
|
21
|
+
/** Default column values applied to every addRow call. Pass a stable reference. */
|
|
22
|
+
rowDefaults?: RowDefaultDataItemValues;
|
|
8
23
|
}
|
|
9
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Owns an EditSession for a form (or any non-table editor). The session is
|
|
26
|
+
* begun when edit mode is entered and ended (without saving) when it is left.
|
|
27
|
+
* Wrap the editor in a DataEditingProvider with the returned editSession.
|
|
28
|
+
*
|
|
29
|
+
* For a higher level API, with create mode and validation, see `useEditForm`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const useEditable: ({ copyOption, dataSource, deleteMode, editSessionApi, isEditMode: isEditModeProp, onCancel, onError, onSave, rowDefaults, }: EditableHookProps) => {
|
|
32
|
+
canCancel: boolean;
|
|
33
|
+
canSave: boolean;
|
|
10
34
|
editSession: EditSession;
|
|
35
|
+
editState: import("./EditSession").EditState;
|
|
36
|
+
isEditMode: boolean;
|
|
37
|
+
lifecycle: import("./EditSession").EditLifecycle;
|
|
11
38
|
onCancel: () => Promise<void>;
|
|
12
39
|
onSave: (force?: boolean) => Promise<void>;
|
|
13
40
|
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { DataEditable, TableSchema } from "@vuu-ui/vuu-data-types";
|
|
2
|
+
import type { ColumnDescriptor } from "@vuu-ui/vuu-table-types";
|
|
3
|
+
/** Columns maintained by the Vuu server, never editable by default. */
|
|
4
|
+
export declare const DEFAULT_READ_ONLY_COLUMNS: readonly ["vuuCreatedTimestamp", "vuuUpdatedTimestamp", "vuuMsg"];
|
|
5
|
+
/** The client-side column that hosts the `UndoCellRenderer`. */
|
|
6
|
+
export declare const UNDO_COLUMN: ColumnDescriptor;
|
|
7
|
+
export interface EditableColumnsHookProps {
|
|
8
|
+
/**
|
|
9
|
+
* Column descriptors used in view mode and as the base for edit mode. A
|
|
10
|
+
* column's `editable` narrows what the server schema allows, its `editor`
|
|
11
|
+
* is used as the cell editor in edit mode.
|
|
12
|
+
*/
|
|
13
|
+
columns: readonly ColumnDescriptor[];
|
|
14
|
+
/**
|
|
15
|
+
* Whether the table is currently showing the edit session. Typically
|
|
16
|
+
* `isEditSessionReady` from `useEditableTable`. When false, editing is
|
|
17
|
+
* switched off for every column.
|
|
18
|
+
*/
|
|
19
|
+
isEditing: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* The schema of the table being edited. A column the schema marks as not
|
|
22
|
+
* editable can never be edited, whatever the column descriptor says.
|
|
23
|
+
* Columns with no `editable` flag in the schema are editable.
|
|
24
|
+
*/
|
|
25
|
+
schema?: TableSchema;
|
|
26
|
+
/**
|
|
27
|
+
* Append the client-side undo column while editing. Pass a partial
|
|
28
|
+
* descriptor to override defaults such as width.
|
|
29
|
+
*/
|
|
30
|
+
undoColumn?: boolean | Partial<ColumnDescriptor>;
|
|
31
|
+
/**
|
|
32
|
+
* Append the session table's `vuuAction` column while editing, either
|
|
33
|
+
* hidden (it still drives row styling) or visible.
|
|
34
|
+
*/
|
|
35
|
+
actionColumn?: "hidden" | "visible" | false;
|
|
36
|
+
/**
|
|
37
|
+
* When true, edit-mode columns are built from `editSchema` rather than
|
|
38
|
+
* `columns`. Pass `columnsDiverge` and `editSchema` from `useEditableTable`.
|
|
39
|
+
* Descriptors in `columns` with a matching name are used as a base so that
|
|
40
|
+
* labels, widths and formatting are preserved.
|
|
41
|
+
*/
|
|
42
|
+
columnsDiverge?: boolean;
|
|
43
|
+
editSchema?: TableSchema;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Combines the schema and column `editable` values. The column can only
|
|
47
|
+
* narrow what the schema allows.
|
|
48
|
+
*/
|
|
49
|
+
export declare const narrowEditable: (schemaEditable?: DataEditable, columnEditable?: DataEditable) => DataEditable;
|
|
50
|
+
/**
|
|
51
|
+
* Builds edit-mode column descriptors. Exposed for use outside React, e.g. in
|
|
52
|
+
* tests or when composing a TableConfig by hand. Most code should use
|
|
53
|
+
* `useEditableColumns`.
|
|
54
|
+
*/
|
|
55
|
+
export declare const getEditableColumns: ({ actionColumn, columns, columnsDiverge, editSchema, isEditing, schema, undoColumn, }: EditableColumnsHookProps) => readonly ColumnDescriptor[];
|
|
56
|
+
/**
|
|
57
|
+
* Maps view-mode column descriptors to edit-mode descriptors and adds the
|
|
58
|
+
* action and undo columns. Editability comes from the schema, narrowed by
|
|
59
|
+
* each column's `editable`; a column's `editor` becomes its cell editor.
|
|
60
|
+
*
|
|
61
|
+
* When `isEditing` is false, editing is switched off for every column.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const columns = useEditableColumns({
|
|
65
|
+
* columns: [
|
|
66
|
+
* { name: "ric", editable: { insert: true, update: false } },
|
|
67
|
+
* {
|
|
68
|
+
* name: "currency",
|
|
69
|
+
* editor: { name: "dropdown-cell", values: ["EUR", "GBP", "USD"] },
|
|
70
|
+
* },
|
|
71
|
+
* { name: "lastUpdate", editable: false },
|
|
72
|
+
* ],
|
|
73
|
+
* isEditing: isEditSessionReady,
|
|
74
|
+
* schema: dataSource.tableSchema,
|
|
75
|
+
* undoColumn: true,
|
|
76
|
+
* actionColumn: "hidden",
|
|
77
|
+
* });
|
|
78
|
+
*/
|
|
79
|
+
export declare const useEditableColumns: ({ actionColumn, columns, columnsDiverge, editSchema, isEditing, schema, undoColumn, }: EditableColumnsHookProps) => readonly ColumnDescriptor[];
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { CopyOption, DataSource, DeleteRowMode } from "@vuu-ui/vuu-data-types";
|
|
2
2
|
import type { VuuTable } from "@vuu-ui/vuu-protocol-types";
|
|
3
3
|
import type { DataRow } from "@vuu-ui/vuu-table-types";
|
|
4
|
-
import { EditSession, type EditActionType, type EditLifecycle, type EditSessionApi, type RowDefaultDataItemValues } from "./EditSession";
|
|
4
|
+
import { EditSession, type EditActionType, type EditLifecycle, type EditSessionApi, type EditState, type RowDefaultDataItemValues } from "./EditSession";
|
|
5
|
+
import { type EditErrorHandler } from "./edit-errors";
|
|
5
6
|
export type EditMode = "edit" | "view";
|
|
6
7
|
export interface EditableTableHookProps {
|
|
7
8
|
/**
|
|
@@ -11,11 +12,23 @@ export interface EditableTableHookProps {
|
|
|
11
12
|
columns?: string[];
|
|
12
13
|
dataSource?: DataSource;
|
|
13
14
|
addRowsCount?: number;
|
|
15
|
+
/** @default "soft" */
|
|
14
16
|
deleteMode?: DeleteRowMode;
|
|
17
|
+
/** @default "createSessionDataSource" */
|
|
15
18
|
editSessionApi?: EditSessionApi;
|
|
19
|
+
/** Rows copied into the session table when editing begins. @default "All" */
|
|
16
20
|
copyOption?: CopyOption;
|
|
17
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Begins (true) or ends (false) the edit session. When omitted, edit mode
|
|
23
|
+
* is read from the nearest EditModeProvider.
|
|
24
|
+
*/
|
|
25
|
+
isEditMode?: boolean;
|
|
18
26
|
onCancel: () => void;
|
|
27
|
+
/**
|
|
28
|
+
* Called when begin, save, cancel or delete fails. Defaults to
|
|
29
|
+
* console.error. Use this to surface errors, e.g. as a notification.
|
|
30
|
+
*/
|
|
31
|
+
onError?: EditErrorHandler;
|
|
19
32
|
onSave: () => void;
|
|
20
33
|
/** Default column values applied to every addRow call. Pass a stable reference — a new object triggers EditSession recreation. */
|
|
21
34
|
rowDefaults?: RowDefaultDataItemValues;
|
|
@@ -25,13 +38,15 @@ export interface EditableTableHookProps {
|
|
|
25
38
|
*/
|
|
26
39
|
table?: VuuTable;
|
|
27
40
|
}
|
|
28
|
-
export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, deleteMode, editSessionApi, copyOption, isEditMode, onCancel, onSave, rowDefaults, table, }: EditableTableHookProps) => {
|
|
41
|
+
export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, deleteMode, editSessionApi, copyOption, isEditMode: isEditModeProp, onCancel, onError, onSave, rowDefaults, table, }: EditableTableHookProps) => {
|
|
29
42
|
canCancel: boolean;
|
|
30
43
|
canSave: boolean;
|
|
31
44
|
columnsDiverge: boolean;
|
|
32
45
|
dataSource: DataSource;
|
|
33
46
|
editSchema: import("@vuu-ui/vuu-data-types").TableSchema | undefined;
|
|
34
47
|
editSession: EditSession;
|
|
48
|
+
editState: EditState;
|
|
49
|
+
isEditMode: boolean;
|
|
35
50
|
lifecycle: EditLifecycle;
|
|
36
51
|
hasSelection: boolean;
|
|
37
52
|
isEditSessionReady: boolean;
|