@vuu-ui/vuu-data-editing 4.0.0-alpha.17 → 4.0.0-alpha.19

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "4.0.0-alpha.17",
2
+ "version": "4.0.0-alpha.19",
3
3
  "description": "Shared data editing APIs and React components for VUU UI",
4
4
  "main": "./src/index.js",
5
5
  "author": "heswell",
@@ -12,13 +12,13 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@salt-ds/core": "1.67.0",
15
- "@vuu-ui/vuu-ui-controls": "4.0.0-alpha.17",
16
- "@vuu-ui/vuu-utils": "4.0.0-alpha.17"
15
+ "@vuu-ui/vuu-ui-controls": "4.0.0-alpha.19",
16
+ "@vuu-ui/vuu-utils": "4.0.0-alpha.19"
17
17
  },
18
18
  "devDependencies": {
19
- "@vuu-ui/vuu-data-types": "4.0.0-alpha.17",
20
- "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.17",
21
- "@vuu-ui/vuu-table-types": "4.0.0-alpha.17"
19
+ "@vuu-ui/vuu-data-types": "4.0.0-alpha.19",
20
+ "@vuu-ui/vuu-protocol-types": "4.0.0-alpha.19",
21
+ "@vuu-ui/vuu-table-types": "4.0.0-alpha.19"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "react": "^19.2.3"
@@ -1,5 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { createContext, useContext } from "react";
3
+ import { EditSession } from "./EditSession.js";
3
4
  const DataEditingContext = /*#__PURE__*/ createContext(void 0);
4
5
  const DataEditingProvider = ({ children, editSession })=>/*#__PURE__*/ jsx(DataEditingContext.Provider, {
5
6
  value: editSession,
@@ -7,7 +8,8 @@ const DataEditingProvider = ({ children, editSession })=>/*#__PURE__*/ jsx(DataE
7
8
  });
8
9
  function useEditSession(throwIfUnavailable = false) {
9
10
  const editSession = useContext(DataEditingContext);
10
- if (void 0 !== editSession) return editSession;
11
- if (throwIfUnavailable) throw Error("[useEditSession] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider");
11
+ if (editSession instanceof EditSession) return editSession;
12
+ if (throwIfUnavailable) throw Error(void 0 === editSession ? "[useEditSession] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider" : "[useEditSession] DataEditingProvider does not provide an EditSession");
12
13
  }
13
- export { DataEditingProvider, useEditSession };
14
+ const useTableEditSession = ()=>useContext(DataEditingContext);
15
+ export { DataEditingProvider, useEditSession, useTableEditSession };
@@ -0,0 +1,35 @@
1
+ import { EventEmitter } from "@vuu-ui/vuu-utils";
2
+ class DirectEditSession extends EventEmitter {
3
+ #dataSource;
4
+ constructor({ dataSource }){
5
+ super();
6
+ this.#dataSource = dataSource;
7
+ }
8
+ get dataSource() {
9
+ return this.#dataSource;
10
+ }
11
+ get inEditMode() {
12
+ return false;
13
+ }
14
+ isCellEdited(_key, _columnName) {
15
+ return false;
16
+ }
17
+ async cancel(_key, _columnName, _restoredValue) {
18
+ return {
19
+ data: void 0,
20
+ type: "SUCCESS_RESULT"
21
+ };
22
+ }
23
+ async commit(key, columnName, _originalValue, typedValue, isValid) {
24
+ if (!isValid) return {
25
+ errorMessage: "Invalid value",
26
+ type: "ERROR_RESULT"
27
+ };
28
+ const editCell = this.#dataSource.editCell;
29
+ if (void 0 === editCell) throw Error("[DirectEditSession] datasource does not support editCell");
30
+ const response = await editCell.call(this.#dataSource, key, columnName, typedValue);
31
+ if (void 0 === response) throw Error("[DirectEditSession] datasource returned no response from editCell");
32
+ return response;
33
+ }
34
+ }
35
+ export { DirectEditSession };
@@ -478,6 +478,15 @@ class EditSession extends EventEmitter {
478
478
  #isLatestCellCommit(key, columnName, revision) {
479
479
  return this.#cellCommitRevisions.get(key)?.get(columnName) === revision;
480
480
  }
481
+ async cancel(key, columnName, restoredValue) {
482
+ const cellEdits = this.#rowEdits.get(key)?.cellEdits;
483
+ const cellEdit = cellEdits?.get(columnName);
484
+ if (this.inEditMode && cellEdits && cellEdit && !cellEdit.isValid) this.#storeCellEdit(key, cellEdits, columnName, cellEdit.originalValue, restoredValue, true);
485
+ return {
486
+ data: void 0,
487
+ type: "SUCCESS_RESULT"
488
+ };
489
+ }
481
490
  async commit(key, columnName, originalValue, typedValue, isValid, { dataSourceValue, syncToDataSource = true } = {}) {
482
491
  if ("active" !== this.#lifecycle.status && !("error" === this.#lifecycle.status && "end" === this.#lifecycle.operation)) throw new Error("No edit session in progress");
483
492
  const revision = this.#setCellCommitRevision(key, columnName);
File without changes
@@ -56,7 +56,7 @@ const EditField = ({ dataRow, deferNewRow = false, label, name, readOnly = false
56
56
  name,
57
57
  serverDataType: "string"
58
58
  };
59
- const { editing, inputProps, onDropdownSelectionChange, onKeyDown, previousValue = "", value, warningMessage, ...editProps } = useEditField({
59
+ const { inputProps, onChange, onDropdownSelectionChange, onKeyDown, value } = useEditField({
60
60
  column,
61
61
  textType: "checkbox" !== type && "dropdown" !== type ? type : void 0,
62
62
  onEdit,
@@ -90,8 +90,11 @@ const EditField = ({ dataRow, deferNewRow = false, label, name, readOnly = false
90
90
  children: listOption.label
91
91
  }, listOption.value))
92
92
  }) : /*#__PURE__*/ jsx(Input, {
93
- ...editProps,
94
93
  bordered: true,
94
+ inputProps: {
95
+ ...inputProps,
96
+ onChange
97
+ },
95
98
  onKeyDown: onKeyDown,
96
99
  readOnly: readOnly,
97
100
  value: value
@@ -147,12 +147,7 @@ const useEditField = ({ column, value, onEdit, textType, type = "string" })=>{
147
147
  ]);
148
148
  const handleBlur = useCallback(async ()=>{
149
149
  if (editState.editing) {
150
- if (isDirtyRef.current) {
151
- const commitSuccessful = await commit();
152
- console.log({
153
- commitSuccessful
154
- });
155
- }
150
+ if (isDirtyRef.current) await commit();
156
151
  setEditState((editState)=>({
157
152
  ...editState,
158
153
  editing: false
package/src/edit-utils.js CHANGED
@@ -4,7 +4,7 @@ const timeFormatter = formatDate({
4
4
  time: "hh:mm:ss"
5
5
  });
6
6
  const dataRowEditErrors = Symbol("vuuDataRowEditErrors");
7
- const isEditRowReadOnly = (dataRow)=>"deleteRow" === dataRow.vuuAction;
7
+ const isEditRowReadOnly = (dataRow)=>dataRow.hasColumn("vuuAction") && "deleteRow" === dataRow.vuuAction;
8
8
  const withDataRowEditErrors = (dataRow, errors)=>{
9
9
  Object.defineProperty(dataRow, dataRowEditErrors, {
10
10
  configurable: true,
package/src/index.js CHANGED
@@ -1,15 +1,16 @@
1
- export { StaleUpdateError } from "@vuu-ui/vuu-utils";
2
- export { DataEditingProvider, useEditSession } from "./DataEditingProvider.js";
3
- export { EditField } from "./edit-field/EditField.js";
4
- export { useEditField } from "./edit-field/useEditField.js";
5
- export { lookupOptionsFromRows, useLookupValues } from "./lookup-values/useLookupValues.js";
1
+ export { DataEditingProvider, useEditSession, useTableEditSession } from "./DataEditingProvider.js";
2
+ export { DirectEditSession } from "./DirectEditSession.js";
3
+ export { useCellEdited } from "./useCellEdited.js";
4
+ export { useEditState } from "./useEditState.js";
6
5
  export { getVuuEditMessage, isEditRowReadOnly, isInlineEditingSession, withDataRowEditErrors } from "./edit-utils.js";
7
- export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator.js";
8
6
  export { EditButtons } from "./EditButtons.js";
7
+ export { EditField } from "./edit-field/EditField.js";
8
+ export { useEditField } from "./edit-field/useEditField.js";
9
9
  export { EditModeProvider, useEditMode } from "./EditModeProvider.js";
10
10
  export { EditError, EditSession, SupersededEditError } from "./EditSession.js";
11
- export { UNDO_CELL_RENDERER, UndoCellRenderer, getUndoButtonContent, getUndoTooltipContent } from "./UndoCellRenderer.js";
12
- export { useCellEdited } from "./useCellEdited.js";
11
+ export { StaleUpdateError } from "@vuu-ui/vuu-utils";
12
+ export { lookupOptionsFromRows, useLookupValues } from "./lookup-values/useLookupValues.js";
13
13
  export { useEditable } from "./useEditable.js";
14
+ export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator.js";
15
+ export { UNDO_CELL_RENDERER, UndoCellRenderer, getUndoButtonContent, getUndoTooltipContent } from "./UndoCellRenderer.js";
14
16
  export { useEditableTable } from "./useEditableTable.js";
15
- export { useEditState } from "./useEditState.js";
@@ -1,4 +1,5 @@
1
- import { EditSession, useEditMode } from "./index.js";
1
+ import { EditSession } from "./EditSession.js";
2
+ import { useEditMode } from "./EditModeProvider.js";
2
3
  import { useCallback, useEffect, useMemo } from "react";
3
4
  const useEditable = ({ copyOption = "Selected", dataSource, onCancel, onSave })=>{
4
5
  const { isEditMode } = useEditMode();
@@ -12,7 +13,7 @@ const useEditable = ({ copyOption = "Selected", dataSource, onCancel, onSave })=
12
13
  await editSession.end();
13
14
  onCancel();
14
15
  } catch (error) {
15
- console.error("[useEditableTable] cancel edit session failed", error);
16
+ console.error("[useEditable] cancel edit session failed", error);
16
17
  }
17
18
  }, [
18
19
  editSession,
@@ -23,7 +24,7 @@ const useEditable = ({ copyOption = "Selected", dataSource, onCancel, onSave })=
23
24
  await editSession.end(true, force);
24
25
  onSave();
25
26
  } catch (error) {
26
- console.error("[useEditableTable] save edit session failed", error);
27
+ console.error("[useEditable] save edit session failed", error);
27
28
  }
28
29
  }, [
29
30
  editSession,
@@ -33,9 +34,9 @@ const useEditable = ({ copyOption = "Selected", dataSource, onCancel, onSave })=
33
34
  const transition = isEditMode ? editSession.begin(copyOption) : editSession.end();
34
35
  transition.catch((error)=>{
35
36
  if (isEditMode) {
36
- console.error("[useEditableTable] begin edit session failed", error);
37
+ console.error("[useEditable] begin edit session failed", error);
37
38
  handleCancel();
38
- } else console.error("[useEditableTable] end edit session failed", error);
39
+ } else console.error("[useEditable] end edit session failed", error);
39
40
  });
40
41
  }, [
41
42
  copyOption,
@@ -1,8 +1,20 @@
1
1
  import { type ReactNode } from "react";
2
- import type { EditSession } from "./EditSession";
2
+ import { EditSession } from "./EditSession";
3
+ import type { TableEditSession } from "./TableEditSession";
3
4
  export declare const DataEditingProvider: ({ children, editSession, }: {
4
5
  children: ReactNode;
5
- editSession: EditSession;
6
+ editSession: TableEditSession;
6
7
  }) => import("react").JSX.Element;
8
+ /**
9
+ * Returns the EditSession provided by an enclosing DataEditingProvider. If the
10
+ * provider holds some other TableEditSession (e.g. DirectEditSession), there is
11
+ * no EditSession in scope and undefined is returned.
12
+ */
7
13
  export declare function useEditSession(throwIfUnavailable?: false): EditSession | undefined;
8
14
  export declare function useEditSession(throwIfUnavailable: true): EditSession;
15
+ /**
16
+ * Returns whichever TableEditSession is provided by an enclosing
17
+ * DataEditingProvider. Intended for use by Table cells, which commit and
18
+ * cancel edits regardless of the type of session.
19
+ */
20
+ export declare const useTableEditSession: () => TableEditSession | undefined;
@@ -0,0 +1,22 @@
1
+ import type { DataSource } from "@vuu-ui/vuu-data-types";
2
+ import type { RpcResult, VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
3
+ import { EventEmitter } from "@vuu-ui/vuu-utils";
4
+ import type { TableEditSession, TableEditSessionEvents } from "./TableEditSession";
5
+ export type DirectEditSessionConstructorProps = {
6
+ dataSource: DataSource;
7
+ };
8
+ /**
9
+ * A lightweight edit session for services that allow cells to be edited
10
+ * directly on the source table. There is no begin/end lifecycle, no session
11
+ * table and no local tracking of edits - each committed edit is sent
12
+ * immediately via the dataSource editCell RPC.
13
+ */
14
+ export declare class DirectEditSession extends EventEmitter<TableEditSessionEvents> implements TableEditSession {
15
+ #private;
16
+ constructor({ dataSource }: DirectEditSessionConstructorProps);
17
+ get dataSource(): DataSource;
18
+ get inEditMode(): boolean;
19
+ isCellEdited(_key: string, _columnName: string): boolean;
20
+ cancel(_key: string, _columnName: string, _restoredValue: VuuRowDataItemType): Promise<RpcResult>;
21
+ commit(key: string, columnName: string, _originalValue: VuuRowDataItemType, typedValue: string | number | boolean, isValid: boolean): Promise<RpcResult>;
22
+ }
@@ -1,6 +1,7 @@
1
1
  import type { CopyOption, DataSource, DeleteRowMode, SessionType } from "@vuu-ui/vuu-data-types";
2
2
  import type { RpcResult, VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
3
3
  import { EventEmitter } from "@vuu-ui/vuu-utils";
4
+ import type { TableEditSession } from "./TableEditSession";
4
5
  export type EditState = "clean" | "dirty" | "invalid" | "stale";
5
6
  export type EditActionType = "deleteRow" | "addRow" | "editCell";
6
7
  export type EditSessionValue = VuuRowDataItemType | object;
@@ -54,7 +55,7 @@ type EditSessionEvents = {
54
55
  lifecycle: (lifecycle: EditLifecycle) => void;
55
56
  newRow: (newRowState: NewRowState) => void;
56
57
  };
57
- export declare class EditSession extends EventEmitter<EditSessionEvents> {
58
+ export declare class EditSession extends EventEmitter<EditSessionEvents> implements TableEditSession {
58
59
  #private;
59
60
  static readonly newRowKey = "__vuu_new_row__";
60
61
  constructor({ dataSource, deleteMode, editSessionApi, rowDefaults, }: EditSessionConstructorProps);
@@ -89,6 +90,7 @@ export declare class EditSession extends EventEmitter<EditSessionEvents> {
89
90
  end(saveChanges?: boolean, force?: boolean): Promise<void>;
90
91
  get lifecycle(): EditLifecycle;
91
92
  get inEditMode(): boolean;
93
+ cancel(key: string, columnName: string, restoredValue: VuuRowDataItemType): Promise<RpcResult>;
92
94
  commit(key: string, columnName: string, originalValue: EditSessionValue, typedValue: EditSessionValue, isValid: boolean, { dataSourceValue, syncToDataSource }?: EditCommitOptions): Promise<RpcResult>;
93
95
  }
94
96
  export {};
@@ -0,0 +1,28 @@
1
+ import type { RpcResult, VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
2
+ export type TableEditSessionEvents = {
3
+ cellEditChanged: (key: string, columnName: string) => void;
4
+ };
5
+ /**
6
+ * The subset of edit session behaviour consumed by Table and its cells.
7
+ * Implemented by EditSession (edits staged in a session table, committed or
8
+ * discarded at end of session) and DirectEditSession (edits applied directly
9
+ * to the source table).
10
+ */
11
+ export interface TableEditSession {
12
+ /**
13
+ * True while a staged edit session is in progress. Always false for
14
+ * DirectEditSession.
15
+ */
16
+ readonly inEditMode: boolean;
17
+ commit(key: string, columnName: string, originalValue: VuuRowDataItemType, typedValue: string | number | boolean, isValid: boolean): Promise<RpcResult>;
18
+ /**
19
+ * Invoked when user abandons an in-progress cell edit, restoring the value
20
+ * the cell held before editing began. Values that have only been typed, not
21
+ * committed, have never been sent to the server, so nothing is sent here.
22
+ * Any invalid edit previously recorded for the cell is discarded.
23
+ */
24
+ cancel(key: string, columnName: string, restoredValue: VuuRowDataItemType): Promise<RpcResult>;
25
+ isCellEdited(key: string, columnName: string): boolean;
26
+ on<E extends keyof TableEditSessionEvents>(event: E, listener: TableEditSessionEvents[E]): void;
27
+ removeListener<E extends keyof TableEditSessionEvents>(event: E, listener: TableEditSessionEvents[E]): void;
28
+ }
@@ -21,6 +21,6 @@ export declare const useEditField: <T extends string | number | boolean = string
21
21
  previousValue: string | undefined;
22
22
  value: string;
23
23
  warningMessage: string | undefined;
24
- onChange: ChangeEventHandler;
24
+ onChange: ChangeEventHandler<HTMLInputElement>;
25
25
  onDropdownSelectionChange: (_evt: SyntheticEvent, [selectedOption]: LookupOption[]) => void;
26
26
  };
package/types/index.d.ts CHANGED
@@ -1,15 +1,17 @@
1
- export { StaleUpdateError } from "@vuu-ui/vuu-utils";
2
- export { DataEditingProvider, useEditSession } from "./DataEditingProvider";
3
- export { EditField } from './edit-field/EditField';
4
- export { useEditField } from './edit-field/useEditField';
5
- export { lookupOptionsFromRows, useLookupValues, type LookupOption, type LookupValuedHookProps, type OptionMap, } from "./lookup-values/useLookupValues";
6
- export { getVuuEditMessage, isEditRowReadOnly, isInlineEditingSession, withDataRowEditErrors } from "./edit-utils";
7
- export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from "./editActionRowClassNameGenerator";
8
- export { EditButtons, type EditButtonProps } from "./EditButtons";
9
- export { EditModeProvider, useEditMode, type EditModeContextProps } from "./EditModeProvider";
10
- export { EditError, EditSession, SupersededEditError, type EditActionType, type EditLifecycle, type EditSessionConstructorProps, type EditState, type NewRowState, type RowDefaultDataItemValues } from "./EditSession";
11
- export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps } from "./UndoCellRenderer";
1
+ export { DataEditingProvider, useEditSession, useTableEditSession, } from "./DataEditingProvider";
2
+ export { DirectEditSession, type DirectEditSessionConstructorProps, } from "./DirectEditSession";
3
+ export type { TableEditSession, TableEditSessionEvents, } from "./TableEditSession";
12
4
  export { useCellEdited } from "./useCellEdited";
13
- export { useEditable } from './useEditable';
14
- export { useEditableTable, type EditableTableHookProps, type EditMode } from "./useEditableTable";
15
5
  export { useEditState } from "./useEditState";
6
+ export { getVuuEditMessage, isInlineEditingSession, isEditRowReadOnly, withDataRowEditErrors, } from "./edit-utils";
7
+ export { EditButtons, type EditButtonProps } from "./EditButtons";
8
+ export { EditField, type DropdownEditFieldProps, type EditFieldProps, type EditFieldType, type TextFieldType, } from "./edit-field/EditField";
9
+ export { useEditField, type EditFieldHookProps, } from "./edit-field/useEditField";
10
+ export { EditModeProvider, useEditMode, type EditModeContextProps, } from "./EditModeProvider";
11
+ export { EditError, EditSession, SupersededEditError, type EditActionType, type EditCommitOptions, type EditLifecycle, type EditSessionConstructorProps, type EditSessionValue, type NewRowState, type EditState, type RowDefaultDataItemValues, } from "./EditSession";
12
+ export { StaleUpdateError } from "@vuu-ui/vuu-utils";
13
+ export { lookupOptionsFromRows, useLookupValues, type LookupOption, type LookupValuedHookProps, type OptionMap, } from "./lookup-values/useLookupValues";
14
+ export { useEditable, type EditableHookProps } from "./useEditable";
15
+ export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator, } from "./editActionRowClassNameGenerator";
16
+ export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps, } from "./UndoCellRenderer";
17
+ export { useEditableTable, type EditableTableHookProps, type EditMode, } from "./useEditableTable";
@@ -1,2 +1,2 @@
1
- import type { EditSession } from "./EditSession";
2
- export declare const useCellEdited: (editSession: EditSession | undefined, key: string, columnName: string) => boolean;
1
+ import type { TableEditSession } from "./TableEditSession";
2
+ export declare const useCellEdited: (editSession: TableEditSession | undefined, key: string, columnName: string) => boolean;
@@ -1,12 +1,12 @@
1
1
  import type { CopyOption, DataSource } from "@vuu-ui/vuu-data-types";
2
- import { EditSession } from ".";
2
+ import { EditSession } from "./EditSession";
3
3
  export interface EditableHookProps {
4
4
  copyOption?: CopyOption;
5
5
  dataSource: DataSource;
6
6
  onCancel: () => void;
7
7
  onSave: () => void;
8
8
  }
9
- export declare const useEditable: ({ copyOption, dataSource, onCancel, onSave }: EditableHookProps) => {
9
+ export declare const useEditable: ({ copyOption, dataSource, onCancel, onSave, }: EditableHookProps) => {
10
10
  editSession: EditSession;
11
11
  onCancel: () => Promise<void>;
12
12
  onSave: (force?: boolean) => Promise<void>;