@vuu-ui/vuu-data-editing 3.0.0-beta.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/LICENSE +201 -0
- package/README.md +5 -0
- package/cjs/DataEditingProvider.js +28 -0
- package/cjs/DataEditingProvider.js.map +1 -0
- package/cjs/EditButtons.js +59 -0
- package/cjs/EditButtons.js.map +1 -0
- package/cjs/EditModeProvider.js +18 -0
- package/cjs/EditModeProvider.js.map +1 -0
- package/cjs/EditSession.js +565 -0
- package/cjs/EditSession.js.map +1 -0
- package/cjs/UndoCellRenderer.js +48 -0
- package/cjs/UndoCellRenderer.js.map +1 -0
- package/cjs/edit-utils.js +53 -0
- package/cjs/edit-utils.js.map +1 -0
- package/cjs/editActionRowClassNameGenerator.js +25 -0
- package/cjs/editActionRowClassNameGenerator.js.map +1 -0
- package/cjs/index.js +43 -0
- package/cjs/index.js.map +1 -0
- package/cjs/useCellEdited.js +29 -0
- package/cjs/useCellEdited.js.map +1 -0
- package/cjs/useEditableTable.js +146 -0
- package/cjs/useEditableTable.js.map +1 -0
- package/esm/DataEditingProvider.js +25 -0
- package/esm/DataEditingProvider.js.map +1 -0
- package/esm/EditButtons.js +57 -0
- package/esm/EditButtons.js.map +1 -0
- package/esm/EditModeProvider.js +15 -0
- package/esm/EditModeProvider.js.map +1 -0
- package/esm/EditSession.js +561 -0
- package/esm/EditSession.js.map +1 -0
- package/esm/UndoCellRenderer.js +43 -0
- package/esm/UndoCellRenderer.js.map +1 -0
- package/esm/edit-utils.js +45 -0
- package/esm/edit-utils.js.map +1 -0
- package/esm/editActionRowClassNameGenerator.js +22 -0
- package/esm/editActionRowClassNameGenerator.js.map +1 -0
- package/esm/index.js +11 -0
- package/esm/index.js.map +1 -0
- package/esm/useCellEdited.js +27 -0
- package/esm/useCellEdited.js.map +1 -0
- package/esm/useEditableTable.js +144 -0
- package/esm/useEditableTable.js.map +1 -0
- package/package.json +39 -0
- package/types/DataEditingProvider.d.ts +8 -0
- package/types/EditButtons.d.ts +14 -0
- package/types/EditModeProvider.d.ts +13 -0
- package/types/EditSession.d.ts +73 -0
- package/types/UndoCellRenderer.d.ts +12 -0
- package/types/edit-utils.d.ts +5 -0
- package/types/editActionRowClassNameGenerator.d.ts +3 -0
- package/types/index.d.ts +10 -0
- package/types/useCellEdited.d.ts +2 -0
- package/types/useEditableTable.d.ts +40 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { Tooltip, Button } from '@salt-ds/core';
|
|
3
|
+
import { Icon } from '@vuu-ui/vuu-ui-controls';
|
|
4
|
+
import { registerComponent } from '@vuu-ui/vuu-utils';
|
|
5
|
+
import { useEditSession } from './DataEditingProvider.js';
|
|
6
|
+
|
|
7
|
+
const UNDO_CELL_RENDERER = "vuu.undo-cell";
|
|
8
|
+
const getUndoButtonContent = (componentProps) => ({
|
|
9
|
+
icon: componentProps?.icon,
|
|
10
|
+
text: componentProps?.text === void 0 ? "UNDO" : componentProps.text || void 0
|
|
11
|
+
});
|
|
12
|
+
const getUndoTooltipContent = (action) => action === "deleteRow" ? "Undo delete row" : action === "addRow" ? "Undo insert row" : action === "editCell" ? "Undo row edits" : void 0;
|
|
13
|
+
const UndoCellRenderer = ({
|
|
14
|
+
column,
|
|
15
|
+
dataRow
|
|
16
|
+
}) => {
|
|
17
|
+
const editSession = useEditSession();
|
|
18
|
+
const renderer = column.type?.renderer;
|
|
19
|
+
const { icon, text } = getUndoButtonContent(
|
|
20
|
+
renderer?.componentProps
|
|
21
|
+
);
|
|
22
|
+
const tooltipContent = getUndoTooltipContent(
|
|
23
|
+
dataRow.vuu_action
|
|
24
|
+
);
|
|
25
|
+
if (tooltipContent === void 0) return null;
|
|
26
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: tooltipContent, children: /* @__PURE__ */ jsxs(
|
|
27
|
+
Button,
|
|
28
|
+
{
|
|
29
|
+
appearance: "transparent",
|
|
30
|
+
"aria-label": tooltipContent,
|
|
31
|
+
onClick: () => editSession?.undoRowChange(dataRow.key),
|
|
32
|
+
style: { height: "100%", width: "100%" },
|
|
33
|
+
children: [
|
|
34
|
+
icon ? /* @__PURE__ */ jsx(Icon, { name: icon }) : null,
|
|
35
|
+
text
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
) });
|
|
39
|
+
};
|
|
40
|
+
registerComponent(UNDO_CELL_RENDERER, UndoCellRenderer, "cell-renderer");
|
|
41
|
+
|
|
42
|
+
export { UNDO_CELL_RENDERER, UndoCellRenderer, getUndoButtonContent, getUndoTooltipContent };
|
|
43
|
+
//# sourceMappingURL=UndoCellRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UndoCellRenderer.js","sources":["../../../packages/vuu-data-editing/src/UndoCellRenderer.tsx"],"sourcesContent":["import { Button, Tooltip } from \"@salt-ds/core\";\nimport type {\n ColumnTypeRendering,\n DataValueTypeDescriptor,\n TableCellRendererProps,\n} from \"@vuu-ui/vuu-table-types\";\nimport { Icon } from \"@vuu-ui/vuu-ui-controls\";\nimport { registerComponent } from \"@vuu-ui/vuu-utils\";\nimport { useEditSession } from \"./DataEditingProvider\";\n\nexport const UNDO_CELL_RENDERER = \"vuu.undo-cell\";\n\nexport interface UndoCellRendererComponentProps {\n icon?: string;\n text?: string | false;\n}\n\nexport const getUndoButtonContent = (\n componentProps?: UndoCellRendererComponentProps,\n) => ({\n icon: componentProps?.icon,\n text:\n componentProps?.text === undefined\n ? \"UNDO\"\n : componentProps.text || undefined,\n});\n\nexport const getUndoTooltipContent = (\n action: unknown,\n) =>\n action === \"deleteRow\"\n ? \"Undo delete row\"\n : action === \"addRow\"\n ? \"Undo insert row\"\n : action === \"editCell\"\n ? \"Undo row edits\"\n : undefined;\n\nexport const UndoCellRenderer = ({\n column,\n dataRow,\n}: TableCellRendererProps) => {\n const editSession = useEditSession();\n const renderer = (column.type as DataValueTypeDescriptor)\n ?.renderer as ColumnTypeRendering;\n const { icon, text } = getUndoButtonContent(\n renderer?.componentProps as UndoCellRendererComponentProps | undefined,\n );\n const tooltipContent = getUndoTooltipContent(\n dataRow.vuu_action,\n );\n\n if (tooltipContent === undefined) return null;\n\n return (\n <Tooltip content={tooltipContent}>\n <Button\n appearance=\"transparent\"\n aria-label={tooltipContent}\n onClick={() => editSession?.undoRowChange(dataRow.key)}\n style={{ height: \"100%\", width: \"100%\" }}\n >\n {icon ? <Icon name={icon} /> : null}\n {text}\n </Button>\n </Tooltip>\n );\n};\n\nregisterComponent(UNDO_CELL_RENDERER, UndoCellRenderer, \"cell-renderer\");\n"],"names":[],"mappings":";;;;;;AAUO,MAAM,kBAAqB,GAAA;AAOrB,MAAA,oBAAA,GAAuB,CAClC,cACI,MAAA;AAAA,EACJ,MAAM,cAAgB,EAAA,IAAA;AAAA,EACtB,MACE,cAAgB,EAAA,IAAA,KAAS,KACrB,CAAA,GAAA,MAAA,GACA,eAAe,IAAQ,IAAA,KAAA;AAC/B,CAAA;AAEa,MAAA,qBAAA,GAAwB,CACnC,MAAA,KAEA,MAAW,KAAA,WAAA,GACP,iBACA,GAAA,MAAA,KAAW,QACT,GAAA,iBAAA,GACA,MAAW,KAAA,UAAA,GACT,gBACA,GAAA,KAAA;AAEH,MAAM,mBAAmB,CAAC;AAAA,EAC/B,MAAA;AAAA,EACA;AACF,CAA8B,KAAA;AAC5B,EAAA,MAAM,cAAc,cAAe,EAAA;AACnC,EAAM,MAAA,QAAA,GAAY,OAAO,IACrB,EAAA,QAAA;AACJ,EAAM,MAAA,EAAE,IAAM,EAAA,IAAA,EAAS,GAAA,oBAAA;AAAA,IACrB,QAAU,EAAA;AAAA,GACZ;AACA,EAAA,MAAM,cAAiB,GAAA,qBAAA;AAAA,IACrB,OAAQ,CAAA;AAAA,GACV;AAEA,EAAI,IAAA,cAAA,KAAmB,QAAkB,OAAA,IAAA;AAEzC,EACE,uBAAA,GAAA,CAAC,OAAQ,EAAA,EAAA,OAAA,EAAS,cAChB,EAAA,QAAA,kBAAA,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,UAAW,EAAA,aAAA;AAAA,MACX,YAAY,EAAA,cAAA;AAAA,MACZ,OAAS,EAAA,MAAM,WAAa,EAAA,aAAA,CAAc,QAAQ,GAAG,CAAA;AAAA,MACrD,KAAO,EAAA,EAAE,MAAQ,EAAA,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,MAEtC,QAAA,EAAA;AAAA,QAAA,IAAA,mBAAQ,GAAA,CAAA,IAAA,EAAA,EAAK,IAAM,EAAA,IAAA,EAAM,CAAK,GAAA,IAAA;AAAA,QAC9B;AAAA;AAAA;AAAA,GAEL,EAAA,CAAA;AAEJ;AAEA,iBAAkB,CAAA,kBAAA,EAAoB,kBAAkB,eAAe,CAAA;;;;"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { formatDate } from '@vuu-ui/vuu-utils';
|
|
3
|
+
export { isInlineEditingSession } from '@vuu-ui/vuu-utils2';
|
|
4
|
+
|
|
5
|
+
const timeFormatter = formatDate({ time: "hh:mm:ss" });
|
|
6
|
+
const dataRowEditErrors = /* @__PURE__ */ Symbol("vuuDataRowEditErrors");
|
|
7
|
+
const isEditRowReadOnly = (dataRow) => dataRow.vuu_action === "deleteRow";
|
|
8
|
+
const withDataRowEditErrors = (dataRow, errors) => {
|
|
9
|
+
Object.defineProperty(dataRow, dataRowEditErrors, {
|
|
10
|
+
configurable: true,
|
|
11
|
+
value: errors
|
|
12
|
+
});
|
|
13
|
+
return dataRow;
|
|
14
|
+
};
|
|
15
|
+
const getVuuEditMessage = (dataRow, column, originalValue) => {
|
|
16
|
+
const editError = dataRow[dataRowEditErrors]?.[column.name];
|
|
17
|
+
if (editError) {
|
|
18
|
+
return editError;
|
|
19
|
+
}
|
|
20
|
+
const vuuMsg = dataRow.vuuMsg;
|
|
21
|
+
if (typeof vuuMsg === "string" && vuuMsg !== "") {
|
|
22
|
+
const columnMessages = vuuMsg.split(",");
|
|
23
|
+
const msgForCol = columnMessages.find(
|
|
24
|
+
(msg) => msg.startsWith(`${column.name}:`)
|
|
25
|
+
);
|
|
26
|
+
if (msgForCol) {
|
|
27
|
+
const [, value, updatedValue, ts] = msgForCol.split(":");
|
|
28
|
+
const updateTime = timeFormatter(new Date(parseInt(ts)));
|
|
29
|
+
return /* @__PURE__ */ jsxs("span", { children: [
|
|
30
|
+
"Update rejected. Original value ",
|
|
31
|
+
/* @__PURE__ */ jsx("b", { children: originalValue }),
|
|
32
|
+
" could not be updated to ",
|
|
33
|
+
/* @__PURE__ */ jsx("b", { children: value }),
|
|
34
|
+
". It was updated to ",
|
|
35
|
+
/* @__PURE__ */ jsx("b", { children: updatedValue }),
|
|
36
|
+
" at ",
|
|
37
|
+
updateTime,
|
|
38
|
+
"."
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { getVuuEditMessage, isEditRowReadOnly, withDataRowEditErrors };
|
|
45
|
+
//# sourceMappingURL=edit-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-utils.js","sources":["../../../packages/vuu-data-editing/src/edit-utils.tsx"],"sourcesContent":["import type { DataRow, RuntimeColumnDescriptor } from \"@vuu-ui/vuu-table-types\";\nimport { formatDate } from \"@vuu-ui/vuu-utils\";\n\nexport { isInlineEditingSession } from \"@vuu-ui/vuu-utils2\";\n\nconst timeFormatter = formatDate({ time: \"hh:mm:ss\" });\nconst dataRowEditErrors = Symbol(\"vuuDataRowEditErrors\");\n\nexport const isEditRowReadOnly = (dataRow: DataRow) =>\n dataRow.vuu_action === \"deleteRow\";\n\ntype DataRowWithEditErrors = DataRow & {\n [dataRowEditErrors]?: Record<string, string>;\n};\n\nexport const withDataRowEditErrors = <T extends DataRow>(\n dataRow: T,\n errors: Record<string, string>,\n): T => {\n Object.defineProperty(dataRow, dataRowEditErrors, {\n configurable: true,\n value: errors,\n });\n return dataRow;\n};\n\nexport const getVuuEditMessage = (\n dataRow: DataRow,\n column: RuntimeColumnDescriptor,\n originalValue: string,\n) => {\n const editError = (dataRow as DataRowWithEditErrors)[dataRowEditErrors]?.[\n column.name\n ];\n if (editError) {\n return editError;\n }\n\n const vuuMsg = dataRow.vuuMsg as string;\n if (typeof vuuMsg === \"string\" && vuuMsg !== \"\") {\n const columnMessages = vuuMsg.split(\",\");\n const msgForCol = columnMessages.find((msg) =>\n msg.startsWith(`${column.name}:`),\n );\n if (msgForCol) {\n const [, value, updatedValue, ts] = msgForCol.split(\":\");\n const updateTime = timeFormatter(new Date(parseInt(ts as string)));\n return (\n <span>\n {\"Update rejected. Original value \"}\n <b>{originalValue}</b>\n {\" could not be updated to \"}\n <b>{value}</b>\n {\". It was updated to \"}\n <b>{updatedValue}</b>\n {\" at \"}\n {updateTime}\n {\".\"}\n </span>\n );\n }\n }\n};\n"],"names":[],"mappings":";;;;AAKA,MAAM,aAAgB,GAAA,UAAA,CAAW,EAAE,IAAA,EAAM,YAAY,CAAA;AACrD,MAAM,iBAAA,0BAA2B,sBAAsB,CAAA;AAEhD,MAAM,iBAAoB,GAAA,CAAC,OAChC,KAAA,OAAA,CAAQ,UAAe,KAAA;AAMZ,MAAA,qBAAA,GAAwB,CACnC,OAAA,EACA,MACM,KAAA;AACN,EAAO,MAAA,CAAA,cAAA,CAAe,SAAS,iBAAmB,EAAA;AAAA,IAChD,YAAc,EAAA,IAAA;AAAA,IACd,KAAO,EAAA;AAAA,GACR,CAAA;AACD,EAAO,OAAA,OAAA;AACT;AAEO,MAAM,iBAAoB,GAAA,CAC/B,OACA,EAAA,MAAA,EACA,aACG,KAAA;AACH,EAAA,MAAM,SAAa,GAAA,OAAA,CAAkC,iBAAiB,CAAA,GACpE,OAAO,IACT,CAAA;AACA,EAAA,IAAI,SAAW,EAAA;AACb,IAAO,OAAA,SAAA;AAAA;AAGT,EAAA,MAAM,SAAS,OAAQ,CAAA,MAAA;AACvB,EAAA,IAAI,OAAO,MAAA,KAAW,QAAY,IAAA,MAAA,KAAW,EAAI,EAAA;AAC/C,IAAM,MAAA,cAAA,GAAiB,MAAO,CAAA,KAAA,CAAM,GAAG,CAAA;AACvC,IAAA,MAAM,YAAY,cAAe,CAAA,IAAA;AAAA,MAAK,CAAC,GACrC,KAAA,GAAA,CAAI,WAAW,CAAG,EAAA,MAAA,CAAO,IAAI,CAAG,CAAA,CAAA;AAAA,KAClC;AACA,IAAA,IAAI,SAAW,EAAA;AACb,MAAM,MAAA,GAAG,KAAO,EAAA,YAAA,EAAc,EAAE,CAAI,GAAA,SAAA,CAAU,MAAM,GAAG,CAAA;AACvD,MAAA,MAAM,aAAa,aAAc,CAAA,IAAI,KAAK,QAAS,CAAA,EAAY,CAAC,CAAC,CAAA;AACjE,MAAA,4BACG,MACE,EAAA,EAAA,QAAA,EAAA;AAAA,QAAA,kCAAA;AAAA,wBACD,GAAA,CAAC,OAAG,QAAc,EAAA,aAAA,EAAA,CAAA;AAAA,QACjB,2BAAA;AAAA,wBACD,GAAA,CAAC,OAAG,QAAM,EAAA,KAAA,EAAA,CAAA;AAAA,QACT,sBAAA;AAAA,wBACD,GAAA,CAAC,OAAG,QAAa,EAAA,YAAA,EAAA,CAAA;AAAA,QAChB,MAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACH,EAAA,CAAA;AAAA;AAEJ;AAEJ;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { registerComponent } from '@vuu-ui/vuu-utils';
|
|
2
|
+
|
|
3
|
+
const EDIT_ACTION_ROW_CLASS_NAME_GENERATOR = "vuu-edit-actions";
|
|
4
|
+
const editActionRowClassNameGenerator = (dataRow) => {
|
|
5
|
+
switch (dataRow.vuu_action) {
|
|
6
|
+
case "addRow":
|
|
7
|
+
return "vuuTableRow-inserted";
|
|
8
|
+
case "deleteRow":
|
|
9
|
+
return "vuuTableRow-deleted";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
registerComponent(
|
|
13
|
+
EDIT_ACTION_ROW_CLASS_NAME_GENERATOR,
|
|
14
|
+
{
|
|
15
|
+
fn: editActionRowClassNameGenerator,
|
|
16
|
+
id: EDIT_ACTION_ROW_CLASS_NAME_GENERATOR
|
|
17
|
+
},
|
|
18
|
+
"row-class-generator"
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator };
|
|
22
|
+
//# sourceMappingURL=editActionRowClassNameGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editActionRowClassNameGenerator.js","sources":["../../../packages/vuu-data-editing/src/editActionRowClassNameGenerator.ts"],"sourcesContent":["import type { DataRow } from \"@vuu-ui/vuu-table-types\";\nimport { registerComponent } from \"@vuu-ui/vuu-utils\";\n\nexport const EDIT_ACTION_ROW_CLASS_NAME_GENERATOR = \"vuu-edit-actions\";\n\nexport const editActionRowClassNameGenerator = (dataRow: DataRow) => {\n switch (dataRow.vuu_action) {\n case \"addRow\":\n return \"vuuTableRow-inserted\";\n case \"deleteRow\":\n return \"vuuTableRow-deleted\";\n }\n};\n\nregisterComponent(\n EDIT_ACTION_ROW_CLASS_NAME_GENERATOR,\n {\n fn: editActionRowClassNameGenerator,\n id: EDIT_ACTION_ROW_CLASS_NAME_GENERATOR,\n },\n \"row-class-generator\",\n);\n"],"names":[],"mappings":";;AAGO,MAAM,oCAAuC,GAAA;AAEvC,MAAA,+BAAA,GAAkC,CAAC,OAAqB,KAAA;AACnE,EAAA,QAAQ,QAAQ,UAAY;AAAA,IAC1B,KAAK,QAAA;AACH,MAAO,OAAA,sBAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAO,OAAA,qBAAA;AAAA;AAEb;AAEA,iBAAA;AAAA,EACE,oCAAA;AAAA,EACA;AAAA,IACE,EAAI,EAAA,+BAAA;AAAA,IACJ,EAAI,EAAA;AAAA,GACN;AAAA,EACA;AACF,CAAA;;;;"}
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { DataEditingProvider, useEditSession } from './DataEditingProvider.js';
|
|
2
|
+
export { useCellEdited } from './useCellEdited.js';
|
|
3
|
+
export { getVuuEditMessage, isEditRowReadOnly, withDataRowEditErrors } from './edit-utils.js';
|
|
4
|
+
export { EditButtons } from './EditButtons.js';
|
|
5
|
+
export { EditModeProvider, useEditMode } from './EditModeProvider.js';
|
|
6
|
+
export { EditError, EditSession, SupersededEditError } from './EditSession.js';
|
|
7
|
+
export { StaleUpdateError, isInlineEditingSession } from '@vuu-ui/vuu-utils2';
|
|
8
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator } from './editActionRowClassNameGenerator.js';
|
|
9
|
+
export { UNDO_CELL_RENDERER, UndoCellRenderer, getUndoButtonContent, getUndoTooltipContent } from './UndoCellRenderer.js';
|
|
10
|
+
export { useEditableTable } from './useEditableTable.js';
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
2
|
+
|
|
3
|
+
const useCellEdited = (editSession, key, columnName) => {
|
|
4
|
+
const subscribe = useCallback(
|
|
5
|
+
(onStoreChange) => {
|
|
6
|
+
if (!editSession) {
|
|
7
|
+
return () => void 0;
|
|
8
|
+
}
|
|
9
|
+
const handleCellEditChanged = (changedKey, changedColumnName) => {
|
|
10
|
+
if (changedKey === key && changedColumnName === columnName) {
|
|
11
|
+
onStoreChange();
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
editSession.on("cellEditChanged", handleCellEditChanged);
|
|
15
|
+
return () => editSession.removeListener("cellEditChanged", handleCellEditChanged);
|
|
16
|
+
},
|
|
17
|
+
[columnName, editSession, key]
|
|
18
|
+
);
|
|
19
|
+
const getSnapshot = useCallback(
|
|
20
|
+
() => editSession?.isCellEdited(key, columnName) ?? false,
|
|
21
|
+
[columnName, editSession, key]
|
|
22
|
+
);
|
|
23
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { useCellEdited };
|
|
27
|
+
//# sourceMappingURL=useCellEdited.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCellEdited.js","sources":["../../../packages/vuu-data-editing/src/useCellEdited.ts"],"sourcesContent":["import { useCallback, useSyncExternalStore } from \"react\";\nimport type { EditSession } from \"./EditSession\";\n\nexport const useCellEdited = (\n editSession: EditSession | undefined,\n key: string,\n columnName: string,\n) => {\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (!editSession) {\n return () => undefined;\n }\n const handleCellEditChanged = (\n changedKey: string,\n changedColumnName: string,\n ) => {\n if (changedKey === key && changedColumnName === columnName) {\n onStoreChange();\n }\n };\n editSession.on(\"cellEditChanged\", handleCellEditChanged);\n return () =>\n editSession.removeListener(\"cellEditChanged\", handleCellEditChanged);\n },\n [columnName, editSession, key],\n );\n const getSnapshot = useCallback(\n () => editSession?.isCellEdited(key, columnName) ?? false,\n [columnName, editSession, key],\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n};\n"],"names":[],"mappings":";;AAGO,MAAM,aAAgB,GAAA,CAC3B,WACA,EAAA,GAAA,EACA,UACG,KAAA;AACH,EAAA,MAAM,SAAY,GAAA,WAAA;AAAA,IAChB,CAAC,aAA8B,KAAA;AAC7B,MAAA,IAAI,CAAC,WAAa,EAAA;AAChB,QAAA,OAAO,MAAM,KAAA,CAAA;AAAA;AAEf,MAAM,MAAA,qBAAA,GAAwB,CAC5B,UAAA,EACA,iBACG,KAAA;AACH,QAAI,IAAA,UAAA,KAAe,GAAO,IAAA,iBAAA,KAAsB,UAAY,EAAA;AAC1D,UAAc,aAAA,EAAA;AAAA;AAChB,OACF;AACA,MAAY,WAAA,CAAA,EAAA,CAAG,mBAAmB,qBAAqB,CAAA;AACvD,MAAA,OAAO,MACL,WAAA,CAAY,cAAe,CAAA,iBAAA,EAAmB,qBAAqB,CAAA;AAAA,KACvE;AAAA,IACA,CAAC,UAAY,EAAA,WAAA,EAAa,GAAG;AAAA,GAC/B;AACA,EAAA,MAAM,WAAc,GAAA,WAAA;AAAA,IAClB,MAAM,WAAA,EAAa,YAAa,CAAA,GAAA,EAAK,UAAU,CAAK,IAAA,KAAA;AAAA,IACpD,CAAC,UAAY,EAAA,WAAA,EAAa,GAAG;AAAA,GAC/B;AAEA,EAAO,OAAA,oBAAA,CAAqB,SAAW,EAAA,WAAA,EAAa,WAAW,CAAA;AACjE;;;;"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { useLayoutEffectSkipFirst } from '@vuu-ui/vuu-utils';
|
|
2
|
+
import { useData } from '@vuu-ui/vuu-utils2';
|
|
3
|
+
import { useState, useMemo, useRef, useCallback, useEffect } from 'react';
|
|
4
|
+
import { EditSession } from './EditSession.js';
|
|
5
|
+
import { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR } from './editActionRowClassNameGenerator.js';
|
|
6
|
+
|
|
7
|
+
const EDIT_ACTION_ROW_CLASS_NAME_GENERATORS = [
|
|
8
|
+
EDIT_ACTION_ROW_CLASS_NAME_GENERATOR
|
|
9
|
+
];
|
|
10
|
+
const useEditableTable = ({
|
|
11
|
+
columns,
|
|
12
|
+
dataSource: dataSourceProp,
|
|
13
|
+
deleteMode = "soft",
|
|
14
|
+
editSessionApi = "createSessionDataSource",
|
|
15
|
+
copyOption = "All",
|
|
16
|
+
isEditMode,
|
|
17
|
+
onCancel,
|
|
18
|
+
onSave,
|
|
19
|
+
table
|
|
20
|
+
}) => {
|
|
21
|
+
const { VuuDataSource } = useData();
|
|
22
|
+
const [selectionCount, setSelectionCount] = useState(0);
|
|
23
|
+
useLayoutEffectSkipFirst(() => {
|
|
24
|
+
console.warn("[useEditableTable] columns and or table changed");
|
|
25
|
+
}, [columns, table]);
|
|
26
|
+
const sourceDataSource = useMemo(() => {
|
|
27
|
+
if (dataSourceProp) {
|
|
28
|
+
return dataSourceProp;
|
|
29
|
+
} else if (table) {
|
|
30
|
+
return new VuuDataSource({ columns, table });
|
|
31
|
+
} else {
|
|
32
|
+
throw Error(
|
|
33
|
+
"useEditableTable unable to provide DataSource, neither dataSource nor table available as props"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}, [VuuDataSource, columns, dataSourceProp, table]);
|
|
37
|
+
const editSession = useMemo(
|
|
38
|
+
() => new EditSession(sourceDataSource, deleteMode, editSessionApi),
|
|
39
|
+
[deleteMode, editSessionApi, sourceDataSource]
|
|
40
|
+
);
|
|
41
|
+
const [lifecycle, setLifecycle] = useState(
|
|
42
|
+
editSession.lifecycle
|
|
43
|
+
);
|
|
44
|
+
const [editState, setEditState] = useState(editSession.editState);
|
|
45
|
+
const [subscribedSessionDataSource, setSubscribedSessionDataSource] = useState();
|
|
46
|
+
const onCancelRef = useRef(onCancel);
|
|
47
|
+
onCancelRef.current = onCancel;
|
|
48
|
+
const sessionDataSource = "sessionDataSource" in lifecycle ? lifecycle.sessionDataSource : void 0;
|
|
49
|
+
const dataSource = sessionDataSource ?? sourceDataSource;
|
|
50
|
+
const handleCancel = useCallback(async () => {
|
|
51
|
+
try {
|
|
52
|
+
await editSession.end();
|
|
53
|
+
setSelectionCount(0);
|
|
54
|
+
onCancel();
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("[useEditableTable] cancel edit session failed", error);
|
|
57
|
+
}
|
|
58
|
+
}, [editSession, onCancel]);
|
|
59
|
+
const handleSave = useCallback(
|
|
60
|
+
async (force = false) => {
|
|
61
|
+
try {
|
|
62
|
+
await editSession.end(true, force);
|
|
63
|
+
setSelectionCount(0);
|
|
64
|
+
onSave();
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("[useEditableTable] save edit session failed", error);
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
[editSession, onSave]
|
|
70
|
+
);
|
|
71
|
+
const handleDelete = useCallback(async () => {
|
|
72
|
+
await editSession.deleteSelectedRows();
|
|
73
|
+
}, [editSession]);
|
|
74
|
+
const handleUndoRowChange = useCallback(
|
|
75
|
+
(key) => void editSession.undoRowChange(key),
|
|
76
|
+
[editSession]
|
|
77
|
+
);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
dataSource.on("row-selection", setSelectionCount);
|
|
80
|
+
return () => dataSource.removeListener("row-selection", setSelectionCount);
|
|
81
|
+
}, [dataSource]);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (!sessionDataSource) {
|
|
84
|
+
setSubscribedSessionDataSource(void 0);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const handleSubscribed = () => setSubscribedSessionDataSource(sessionDataSource);
|
|
88
|
+
setSubscribedSessionDataSource(void 0);
|
|
89
|
+
sessionDataSource.on("subscribed", handleSubscribed);
|
|
90
|
+
if (sessionDataSource.status === "subscribed" && sessionDataSource.tableSchema) {
|
|
91
|
+
handleSubscribed();
|
|
92
|
+
}
|
|
93
|
+
return () => sessionDataSource.removeListener("subscribed", handleSubscribed);
|
|
94
|
+
}, [sessionDataSource]);
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
const handleEditState = (nextEditState) => {
|
|
97
|
+
setEditState(nextEditState);
|
|
98
|
+
};
|
|
99
|
+
const handleLifecycle = (nextLifecycle) => {
|
|
100
|
+
setLifecycle(nextLifecycle);
|
|
101
|
+
};
|
|
102
|
+
setEditState(editSession.editState);
|
|
103
|
+
setLifecycle(editSession.lifecycle);
|
|
104
|
+
editSession.on("editState", handleEditState);
|
|
105
|
+
editSession.on("lifecycle", handleLifecycle);
|
|
106
|
+
return () => {
|
|
107
|
+
editSession.removeListener("editState", handleEditState);
|
|
108
|
+
editSession.removeListener("lifecycle", handleLifecycle);
|
|
109
|
+
};
|
|
110
|
+
}, [editSession]);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
const transition = isEditMode ? editSession.begin(copyOption) : editSession.end();
|
|
113
|
+
void transition.catch((error) => {
|
|
114
|
+
if (isEditMode) {
|
|
115
|
+
console.error("[useEditableTable] begin edit session failed", error);
|
|
116
|
+
onCancelRef.current();
|
|
117
|
+
} else {
|
|
118
|
+
console.error("[useEditableTable] end edit session failed", error);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}, [copyOption, editSession, isEditMode]);
|
|
122
|
+
const canCancel = lifecycle.status === "active" || lifecycle.status === "error" && lifecycle.operation === "end";
|
|
123
|
+
const canSave = canCancel && (editState === "dirty" || editState === "stale") && editSession.invalidCount === 0;
|
|
124
|
+
const isEditSessionReady = isEditMode && sessionDataSource !== void 0 && sessionDataSource === editSession.sessionDataSource && subscribedSessionDataSource === sessionDataSource && sessionDataSource.status === "subscribed" && sessionDataSource.tableSchema !== void 0;
|
|
125
|
+
return {
|
|
126
|
+
canCancel,
|
|
127
|
+
canSave,
|
|
128
|
+
dataSource,
|
|
129
|
+
editSession,
|
|
130
|
+
lifecycle,
|
|
131
|
+
hasSelection: selectionCount > 0,
|
|
132
|
+
isEditSessionReady,
|
|
133
|
+
onCancel: handleCancel,
|
|
134
|
+
onDelete: handleDelete,
|
|
135
|
+
onSave: handleSave,
|
|
136
|
+
onUndoRowChange: handleUndoRowChange,
|
|
137
|
+
rowClassNameGenerators: isEditMode ? EDIT_ACTION_ROW_CLASS_NAME_GENERATORS : void 0,
|
|
138
|
+
sessionDataSource,
|
|
139
|
+
sourceDataSource
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export { useEditableTable };
|
|
144
|
+
//# sourceMappingURL=useEditableTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEditableTable.js","sources":["../../../packages/vuu-data-editing/src/useEditableTable.ts"],"sourcesContent":["import type {\n CopyOption,\n DataSource,\n DeleteRowMode,\n EditApi,\n} from \"@vuu-ui/vuu-data-types\";\nimport type { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport { useLayoutEffectSkipFirst } from \"@vuu-ui/vuu-utils\";\nimport { useData } from \"@vuu-ui/vuu-utils2\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n EditSession,\n type EditLifecycle,\n type EditSessionApi,\n type EditState,\n} from \"./EditSession\";\nimport { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR } from \"./editActionRowClassNameGenerator\";\n\nconst EDIT_ACTION_ROW_CLASS_NAME_GENERATORS = [\n EDIT_ACTION_ROW_CLASS_NAME_GENERATOR,\n];\n\nexport type EditMode = \"edit\" | \"view\";\n\nexport interface EditableTableHookProps {\n /**\n * columns to be included in subscription. If not provided,\n * default will be '*'. Ignored if dataSource prop present.\n */\n columns?: string[];\n dataSource?: DataSource;\n addRowsCount?: number;\n deleteMode?: DeleteRowMode;\n editSessionApi?: EditSessionApi;\n copyOption?: CopyOption;\n isEditMode: boolean;\n onCancel: () => void;\n onSave: () => void;\n /**\n * If dataSource not provided, new DataSource\n * will be created using table and columns\n */\n table?: VuuTable;\n}\n\nexport const useEditableTable = ({\n columns,\n dataSource: dataSourceProp,\n deleteMode = \"soft\",\n editSessionApi = \"createSessionDataSource\",\n copyOption = \"All\",\n isEditMode,\n onCancel,\n onSave,\n table,\n}: EditableTableHookProps) => {\n const { VuuDataSource } = useData();\n const [selectionCount, setSelectionCount] = useState(0);\n useLayoutEffectSkipFirst(() => {\n console.warn(\"[useEditableTable] columns and or table changed\");\n }, [columns, table]);\n\n const sourceDataSource = useMemo(() => {\n if (dataSourceProp) {\n return dataSourceProp;\n } else if (table) {\n return new VuuDataSource({ columns, table });\n } else {\n throw Error(\n \"useEditableTable unable to provide DataSource, neither dataSource nor table available as props\",\n );\n }\n }, [VuuDataSource, columns, dataSourceProp, table]);\n\n // The editSession will be made available to all the edit controls in scope\n // by wrapping the edit component with a DataEditingProvider.\n const editSession = useMemo(\n () => new EditSession(sourceDataSource as EditApi, deleteMode, editSessionApi),\n [deleteMode, editSessionApi, sourceDataSource],\n );\n const [lifecycle, setLifecycle] = useState<EditLifecycle>(\n editSession.lifecycle,\n );\n const [editState, setEditState] = useState<EditState>(editSession.editState);\n const [subscribedSessionDataSource, setSubscribedSessionDataSource] =\n useState<DataSource>();\n const onCancelRef = useRef(onCancel);\n onCancelRef.current = onCancel;\n\n const sessionDataSource =\n \"sessionDataSource\" in lifecycle ? lifecycle.sessionDataSource : undefined;\n const dataSource = sessionDataSource ?? sourceDataSource;\n\n const handleCancel = useCallback(async () => {\n try {\n await editSession.end();\n setSelectionCount(0);\n onCancel();\n } catch (error) {\n console.error(\"[useEditableTable] cancel edit session failed\", error);\n }\n }, [editSession, onCancel]);\n\n const handleSave = useCallback(\n async (force = false) => {\n try {\n await editSession.end(true, force);\n setSelectionCount(0);\n onSave();\n } catch (error) {\n console.error(\"[useEditableTable] save edit session failed\", error);\n }\n },\n [editSession, onSave],\n );\n\n const handleDelete = useCallback(async () => {\n await editSession.deleteSelectedRows();\n }, [editSession]);\n\n const handleUndoRowChange = useCallback(\n (key: string) => void editSession.undoRowChange(key),\n [editSession],\n );\n\n useEffect(() => {\n dataSource.on(\"row-selection\", setSelectionCount);\n return () => dataSource.removeListener(\"row-selection\", setSelectionCount);\n }, [dataSource]);\n\n useEffect(() => {\n if (!sessionDataSource) {\n setSubscribedSessionDataSource(undefined);\n return;\n }\n\n const handleSubscribed = () =>\n setSubscribedSessionDataSource(sessionDataSource);\n\n setSubscribedSessionDataSource(undefined);\n sessionDataSource.on(\"subscribed\", handleSubscribed);\n if (\n sessionDataSource.status === \"subscribed\" &&\n sessionDataSource.tableSchema\n ) {\n handleSubscribed();\n }\n\n return () =>\n sessionDataSource.removeListener(\"subscribed\", handleSubscribed);\n }, [sessionDataSource]);\n\n useEffect(() => {\n const handleEditState = (nextEditState: EditState) => {\n setEditState(nextEditState);\n };\n const handleLifecycle = (nextLifecycle: EditLifecycle) => {\n setLifecycle(nextLifecycle);\n };\n\n setEditState(editSession.editState);\n setLifecycle(editSession.lifecycle);\n editSession.on(\"editState\", handleEditState);\n editSession.on(\"lifecycle\", handleLifecycle);\n return () => {\n editSession.removeListener(\"editState\", handleEditState);\n editSession.removeListener(\"lifecycle\", handleLifecycle);\n };\n }, [editSession]);\n\n useEffect(() => {\n const transition = isEditMode\n ? editSession.begin(copyOption)\n : editSession.end();\n\n void transition.catch((error) => {\n if (isEditMode) {\n console.error(\"[useEditableTable] begin edit session failed\", error);\n onCancelRef.current();\n } else {\n console.error(\"[useEditableTable] end edit session failed\", error);\n }\n });\n }, [copyOption, editSession, isEditMode]);\n\n const canCancel =\n lifecycle.status === \"active\" ||\n (lifecycle.status === \"error\" && lifecycle.operation === \"end\");\n\n const canSave =\n canCancel &&\n (editState === \"dirty\" || editState === \"stale\") &&\n editSession.invalidCount === 0;\n const isEditSessionReady =\n isEditMode &&\n sessionDataSource !== undefined &&\n sessionDataSource === editSession.sessionDataSource &&\n subscribedSessionDataSource === sessionDataSource &&\n sessionDataSource.status === \"subscribed\" &&\n sessionDataSource.tableSchema !== undefined;\n\n return {\n canCancel,\n canSave,\n dataSource,\n editSession,\n lifecycle,\n hasSelection: selectionCount > 0,\n isEditSessionReady,\n onCancel: handleCancel,\n onDelete: handleDelete,\n onSave: handleSave,\n onUndoRowChange: handleUndoRowChange,\n rowClassNameGenerators: isEditMode\n ? EDIT_ACTION_ROW_CLASS_NAME_GENERATORS\n : undefined,\n sessionDataSource,\n sourceDataSource,\n };\n};\n"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "3.0.0-beta.1",
|
|
3
|
+
"description": "Shared data editing APIs and React components for VUU UI",
|
|
4
|
+
"author": "heswell",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@salt-ds/core": "1.54.1",
|
|
9
|
+
"@vuu-ui/vuu-ui-controls": "3.0.0-beta.1",
|
|
10
|
+
"@vuu-ui/vuu-utils": "3.0.0-beta.1",
|
|
11
|
+
"@vuu-ui/vuu-utils2": "3.0.0-beta.1"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@vuu-ui/vuu-data-types": "3.0.0-beta.1",
|
|
15
|
+
"@vuu-ui/vuu-protocol-types": "3.0.0-beta.1",
|
|
16
|
+
"@vuu-ui/vuu-table-types": "3.0.0-beta.1"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": "^19.2.3"
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"files": [
|
|
23
|
+
"README.md",
|
|
24
|
+
"esm",
|
|
25
|
+
"cjs",
|
|
26
|
+
"/types"
|
|
27
|
+
],
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"require": "./cjs/index.js",
|
|
31
|
+
"import": "./esm/index.js",
|
|
32
|
+
"types": "./types/index.d.ts"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"main": "cjs/index.js",
|
|
36
|
+
"module": "esm/index.js",
|
|
37
|
+
"name": "@vuu-ui/vuu-data-editing",
|
|
38
|
+
"types": "types/index.d.ts"
|
|
39
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { EditSession } from "./EditSession";
|
|
3
|
+
export declare const DataEditingProvider: ({ children, editSession, }: {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
editSession: EditSession;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function useEditSession(throwIfUnavailable?: false): EditSession | undefined;
|
|
8
|
+
export declare function useEditSession(throwIfUnavailable: true): EditSession;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EditSession } from "./EditSession";
|
|
2
|
+
export interface EditButtonProps {
|
|
3
|
+
canCancel: boolean;
|
|
4
|
+
canSave: boolean;
|
|
5
|
+
editSession?: EditSession;
|
|
6
|
+
hasSelection?: boolean;
|
|
7
|
+
onCancel?: () => void;
|
|
8
|
+
onDelete?: () => void;
|
|
9
|
+
onSave: (force?: boolean) => void;
|
|
10
|
+
saveLabel?: string;
|
|
11
|
+
confirmSave?: () => boolean | Promise<boolean>;
|
|
12
|
+
confirmCancel?: () => boolean | Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export declare const EditButtons: ({ canCancel, canSave, confirmCancel, confirmSave, editSession, hasSelection, onCancel, onDelete, onSave, saveLabel, }: EditButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export interface EditModeContextProps {
|
|
3
|
+
isEditMode: boolean;
|
|
4
|
+
setEditMode: (inEditMode: boolean) => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Implemented as a standalone Provider so that EditMode cna be implemented
|
|
8
|
+
* at higher level than individual edit controls.
|
|
9
|
+
*/
|
|
10
|
+
export declare const EditModeProvider: ({ children }: {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare const useEditMode: () => EditModeContextProps;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { CopyOption, DataSource, DeleteRowMode, EditApi } 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
|
+
export type EditState = "clean" | "dirty" | "invalid" | "stale";
|
|
5
|
+
export type EditSessionApi = "createSessionDataSource" | "beginEditSession";
|
|
6
|
+
export type NewRowState = {
|
|
7
|
+
columns: readonly string[];
|
|
8
|
+
draftRevision: number;
|
|
9
|
+
errors: Readonly<Record<string, string>>;
|
|
10
|
+
submitting: boolean;
|
|
11
|
+
values: Readonly<Record<string, VuuRowDataItemType>>;
|
|
12
|
+
};
|
|
13
|
+
export type EditLifecycle = {
|
|
14
|
+
status: "idle";
|
|
15
|
+
} | {
|
|
16
|
+
status: "starting";
|
|
17
|
+
} | {
|
|
18
|
+
status: "active";
|
|
19
|
+
sessionDataSource: DataSource;
|
|
20
|
+
} | {
|
|
21
|
+
status: "ending";
|
|
22
|
+
sessionDataSource: DataSource;
|
|
23
|
+
} | {
|
|
24
|
+
status: "error";
|
|
25
|
+
operation: "begin" | "end";
|
|
26
|
+
error: Error;
|
|
27
|
+
sessionDataSource?: DataSource;
|
|
28
|
+
};
|
|
29
|
+
export declare class EditError extends Error {
|
|
30
|
+
}
|
|
31
|
+
export declare class SupersededEditError extends Error {
|
|
32
|
+
}
|
|
33
|
+
type EditSessionEvents = {
|
|
34
|
+
cellEditChanged: (key: string, columnName: string) => void;
|
|
35
|
+
editState: (editState: EditState) => void;
|
|
36
|
+
lifecycle: (lifecycle: EditLifecycle) => void;
|
|
37
|
+
newRow: (newRowState: NewRowState) => void;
|
|
38
|
+
};
|
|
39
|
+
export declare class EditSession extends EventEmitter<EditSessionEvents> {
|
|
40
|
+
#private;
|
|
41
|
+
static readonly newRowKey = "__vuu_new_row__";
|
|
42
|
+
constructor(dataSource: EditApi, deleteMode?: DeleteRowMode, editSessionApi?: EditSessionApi);
|
|
43
|
+
get editCount(): number;
|
|
44
|
+
set editCount(val: number);
|
|
45
|
+
get invalidCount(): number;
|
|
46
|
+
set invalidCount(val: number);
|
|
47
|
+
get deleteCount(): number;
|
|
48
|
+
set deleteCount(val: number);
|
|
49
|
+
get addCount(): number;
|
|
50
|
+
set addCount(val: number);
|
|
51
|
+
get editState(): EditState;
|
|
52
|
+
get newRowState(): NewRowState;
|
|
53
|
+
isNewRow(key: string): key is "__vuu_new_row__";
|
|
54
|
+
isNewRowFinalColumn(columnName: string): boolean;
|
|
55
|
+
isNewRowComplete(): boolean;
|
|
56
|
+
configureNewRow(columns: readonly string[]): void;
|
|
57
|
+
setNewRowValue(column: string, value: VuuRowDataItemType): void;
|
|
58
|
+
addNewRow(): Promise<RpcResult>;
|
|
59
|
+
deleteSelectedRows(): Promise<void>;
|
|
60
|
+
addRow(rowData?: Record<string, VuuRowDataItemType>): Promise<RpcResult>;
|
|
61
|
+
restoreRows(keys: string[]): void;
|
|
62
|
+
hasRowChanges(key: string): boolean;
|
|
63
|
+
isCellEdited(key: string, columnName: string): boolean;
|
|
64
|
+
undoRowChange(key: string): Promise<void>;
|
|
65
|
+
begin(copyOption?: CopyOption): Promise<DataSource>;
|
|
66
|
+
get dataSource(): EditApi<import("@vuu-ui/vuu-data-types").DataSourceRow<VuuRowDataItemType>> | undefined;
|
|
67
|
+
get sessionDataSource(): DataSource | undefined;
|
|
68
|
+
end(saveChanges?: boolean, force?: boolean): Promise<void>;
|
|
69
|
+
get lifecycle(): EditLifecycle;
|
|
70
|
+
get inEditMode(): boolean;
|
|
71
|
+
commit(key: string, columnName: string, originalValue: VuuRowDataItemType, typedValue: string | number | boolean, isValid: boolean): Promise<RpcResult>;
|
|
72
|
+
}
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TableCellRendererProps } from "@vuu-ui/vuu-table-types";
|
|
2
|
+
export declare const UNDO_CELL_RENDERER = "vuu.undo-cell";
|
|
3
|
+
export interface UndoCellRendererComponentProps {
|
|
4
|
+
icon?: string;
|
|
5
|
+
text?: string | false;
|
|
6
|
+
}
|
|
7
|
+
export declare const getUndoButtonContent: (componentProps?: UndoCellRendererComponentProps) => {
|
|
8
|
+
icon: string | undefined;
|
|
9
|
+
text: string | undefined;
|
|
10
|
+
};
|
|
11
|
+
export declare const getUndoTooltipContent: (action: unknown) => "Undo delete row" | "Undo insert row" | "Undo row edits" | undefined;
|
|
12
|
+
export declare const UndoCellRenderer: ({ column, dataRow, }: TableCellRendererProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DataRow, RuntimeColumnDescriptor } from "@vuu-ui/vuu-table-types";
|
|
2
|
+
export { isInlineEditingSession } from "@vuu-ui/vuu-utils2";
|
|
3
|
+
export declare const isEditRowReadOnly: (dataRow: DataRow) => boolean;
|
|
4
|
+
export declare const withDataRowEditErrors: <T extends DataRow>(dataRow: T, errors: Record<string, string>) => T;
|
|
5
|
+
export declare const getVuuEditMessage: (dataRow: DataRow, column: RuntimeColumnDescriptor, originalValue: string) => string | import("react/jsx-runtime").JSX.Element | undefined;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { DataEditingProvider, useEditSession } from "./DataEditingProvider";
|
|
2
|
+
export { useCellEdited } from "./useCellEdited";
|
|
3
|
+
export { getVuuEditMessage, isInlineEditingSession, isEditRowReadOnly, withDataRowEditErrors, } from "./edit-utils";
|
|
4
|
+
export { EditButtons, type EditButtonProps } from "./EditButtons";
|
|
5
|
+
export { EditModeProvider, useEditMode, type EditModeContextProps, } from "./EditModeProvider";
|
|
6
|
+
export { EditError, EditSession, SupersededEditError, type EditLifecycle, type NewRowState, type EditState, } from "./EditSession";
|
|
7
|
+
export { StaleUpdateError } from "@vuu-ui/vuu-utils2";
|
|
8
|
+
export { EDIT_ACTION_ROW_CLASS_NAME_GENERATOR, editActionRowClassNameGenerator, } from "./editActionRowClassNameGenerator";
|
|
9
|
+
export { getUndoButtonContent, getUndoTooltipContent, UNDO_CELL_RENDERER, UndoCellRenderer, type UndoCellRendererComponentProps, } from "./UndoCellRenderer";
|
|
10
|
+
export { useEditableTable, type EditableTableHookProps, type EditMode, } from "./useEditableTable";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CopyOption, DataSource, DeleteRowMode } from "@vuu-ui/vuu-data-types";
|
|
2
|
+
import type { VuuTable } from "@vuu-ui/vuu-protocol-types";
|
|
3
|
+
import { EditSession, type EditLifecycle, type EditSessionApi } from "./EditSession";
|
|
4
|
+
export type EditMode = "edit" | "view";
|
|
5
|
+
export interface EditableTableHookProps {
|
|
6
|
+
/**
|
|
7
|
+
* columns to be included in subscription. If not provided,
|
|
8
|
+
* default will be '*'. Ignored if dataSource prop present.
|
|
9
|
+
*/
|
|
10
|
+
columns?: string[];
|
|
11
|
+
dataSource?: DataSource;
|
|
12
|
+
addRowsCount?: number;
|
|
13
|
+
deleteMode?: DeleteRowMode;
|
|
14
|
+
editSessionApi?: EditSessionApi;
|
|
15
|
+
copyOption?: CopyOption;
|
|
16
|
+
isEditMode: boolean;
|
|
17
|
+
onCancel: () => void;
|
|
18
|
+
onSave: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* If dataSource not provided, new DataSource
|
|
21
|
+
* will be created using table and columns
|
|
22
|
+
*/
|
|
23
|
+
table?: VuuTable;
|
|
24
|
+
}
|
|
25
|
+
export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, deleteMode, editSessionApi, copyOption, isEditMode, onCancel, onSave, table, }: EditableTableHookProps) => {
|
|
26
|
+
canCancel: boolean;
|
|
27
|
+
canSave: boolean;
|
|
28
|
+
dataSource: DataSource;
|
|
29
|
+
editSession: EditSession;
|
|
30
|
+
lifecycle: EditLifecycle;
|
|
31
|
+
hasSelection: boolean;
|
|
32
|
+
isEditSessionReady: boolean;
|
|
33
|
+
onCancel: () => Promise<void>;
|
|
34
|
+
onDelete: () => Promise<void>;
|
|
35
|
+
onSave: (force?: boolean) => Promise<void>;
|
|
36
|
+
onUndoRowChange: (key: string) => undefined;
|
|
37
|
+
rowClassNameGenerators: string[] | undefined;
|
|
38
|
+
sessionDataSource: import("@vuu-ui/vuu-data-types").DataSourceBase<import("@vuu-ui/vuu-data-types").DataSourceRowWithBigint> | undefined;
|
|
39
|
+
sourceDataSource: DataSource;
|
|
40
|
+
};
|