@nualang/nualang-ui-components 0.1.1364 → 0.1.1365

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.
@@ -7,7 +7,6 @@ import SpreadsheetEditor from "./SpreadsheetEditor/SpreadsheetEditor";
7
7
  import CreatePhraseDialog from "../../Dialogs/CreatePhrase/CreatePhrase";
8
8
  import UploadPhrasesDialog from "../../Dialogs/UploadPhrases/UploadPhrases";
9
9
  import DeleteIcon from "@mui/icons-material/Delete";
10
- import { Input } from "react-spreadsheet-grid";
11
10
  import useSpreadsheetState from "../../hooks/useSpreadsheetState";
12
11
  import DefaultButton from "../../Misc/DefaultColourButton/DefaultColourButton";
13
12
  import { Parser } from "@json2csv/plainjs";
@@ -134,14 +133,15 @@ const CreatorComponent = ({
134
133
  t,
135
134
  mode,
136
135
  errors,
136
+ hasNonEmptyRows,
137
137
  rows,
138
- columns,
139
- selectedRow,
140
- onCellClick,
141
- onColumnResize,
142
- onFieldChange,
143
- isRowEmpty,
138
+ processRowUpdate,
139
+ selectionModel,
140
+ onRowSelectionModelChange,
144
141
  saveChanges,
142
+ addRow,
143
+ isDirty,
144
+ hasTrailingEmptyRow,
145
145
  phrases,
146
146
  learnLang,
147
147
  forLang,
@@ -202,14 +202,15 @@ const CreatorComponent = ({
202
202
  }), mode === Modes.SPREADSHEET && /*#__PURE__*/_jsx(SpreadsheetEditor, {
203
203
  t: t,
204
204
  errors: errors,
205
+ hasNonEmptyRows: hasNonEmptyRows,
205
206
  rows: rows,
206
- columns: columns,
207
- selectedRow: selectedRow,
208
- onCellClick: onCellClick,
209
- onColumnResize: onColumnResize,
210
- onFieldChange: onFieldChange,
211
- isRowEmpty: isRowEmpty,
212
- saveChanges: saveChanges
207
+ processRowUpdate: processRowUpdate,
208
+ selectionModel: selectionModel,
209
+ onRowSelectionModelChange: onRowSelectionModelChange,
210
+ saveChanges: saveChanges,
211
+ addRow: addRow,
212
+ isDirty: isDirty,
213
+ hasTrailingEmptyRow: hasTrailingEmptyRow
213
214
  })]
214
215
  });
215
216
  function EmptyPhraseList({
@@ -291,6 +292,10 @@ function PhrasesEditor(props) {
291
292
  scriptDownloadRef
292
293
  } = props;
293
294
  const [errors, setErrors] = useState([]);
295
+ const [selectionModel, setSelectionModel] = useState({
296
+ type: "include",
297
+ ids: new Set()
298
+ });
294
299
  const [spreadsheetPhrases, setSpreadsheetPhrases] = useState(Object.keys(phrases).length > 0 ? phrases : [rowTemplate]);
295
300
  const isRowEmpty = row => {
296
301
  let rowEmpty = true;
@@ -356,96 +361,20 @@ function PhrasesEditor(props) {
356
361
  });
357
362
  return validationErrors;
358
363
  }, [validateRow]);
359
-
360
- // Column definition for spreadsheet grid
361
- const initColumns = () => [{
362
- id: "id",
363
- title: () => /*#__PURE__*/_jsx(Typography, {
364
- children: t("row")
365
- }),
366
- value: row => {
367
- return /*#__PURE__*/_jsx(Typography, {
368
- children: row.id + 1
369
- });
370
- },
371
- width: 10
372
- }, {
373
- id: "phrase",
374
- title: () => /*#__PURE__*/_jsx(Typography, {
375
- children: t("phrase")
376
- }),
377
- value: (row, {
378
- focus
379
- }) => {
380
- const phraseDisplay = [row.phrase || "", ...(row.alternativeVersions || [])].filter(Boolean).join(" | ");
381
- return /*#__PURE__*/_jsx(Input, {
382
- value: phraseDisplay,
383
- placeholder: t("enter_phrase_with_alternatives"),
384
- focus: focus,
385
- onChange: onFieldChange(row.id, "phrase")
386
- });
387
- },
388
- width: 30
389
- }, {
390
- id: "translations",
391
- title: () => /*#__PURE__*/_jsx(Typography, {
392
- children: t("translations")
393
- }),
394
- value: (row, {
395
- focus
396
- }) => {
397
- return /*#__PURE__*/_jsx(Input, {
398
- value: row.translations,
399
- focus: focus,
400
- onChange: onFieldChange(row.id, "translations")
401
- });
402
- },
403
- width: 25
404
- }, {
405
- id: "definitions",
406
- title: () => /*#__PURE__*/_jsx(Typography, {
407
- children: t("definitions")
408
- }),
409
- value: (row, {
410
- focus
411
- }) => {
412
- return /*#__PURE__*/_jsx(Input, {
413
- value: row.definitions,
414
- focus: focus,
415
- onChange: onFieldChange(row.id, "definitions")
416
- });
417
- },
418
- width: 25
419
- }, {
420
- id: "image",
421
- title: () => /*#__PURE__*/_jsx(Typography, {
422
- children: t("image")
423
- }),
424
- value: (row, {
425
- focus
426
- }) => {
427
- return /*#__PURE__*/_jsx(Input, {
428
- value: row.image,
429
- focus: focus,
430
- onChange: onFieldChange(row.id, "image")
431
- });
432
- },
433
- width: 30
434
- }];
435
364
  const {
436
365
  rows,
437
- columns,
366
+ addRow,
367
+ isDirty,
368
+ hasTrailingEmptyRow,
438
369
  selectedRow,
439
- onCellClick,
440
- onColumnResize,
441
370
  deleteSelectedRow,
442
- onFieldChange
371
+ processRowUpdate
443
372
  } = useSpreadsheetState({
444
373
  rowTemplate,
445
374
  data: spreadsheetPhrases,
446
- initColumns,
447
375
  isRowEmpty
448
376
  });
377
+ const hasNonEmptyRows = rows.some(r => !isRowEmpty(r));
449
378
 
450
379
  // Validates rows whenever spreadsheet gets edited
451
380
  useEffect(() => {
@@ -559,11 +488,6 @@ function PhrasesEditor(props) {
559
488
  mode: mode,
560
489
  errors: errors,
561
490
  rows: rows,
562
- columns: columns,
563
- selectedRow: selectedRow,
564
- onCellClick: onCellClick,
565
- onColumnResize: onColumnResize,
566
- onFieldChange: onFieldChange,
567
491
  isRowEmpty: isRowEmpty,
568
492
  saveChanges: saveChanges,
569
493
  phrases: phrases,
@@ -592,7 +516,12 @@ function PhrasesEditor(props) {
592
516
  otherPhraseLists: otherPhraseLists,
593
517
  otherPhraseListsLoading: otherPhraseListsLoading,
594
518
  handleTransferPhrase: handleTransferPhrase,
595
- handleCreatePhraseListFromSelection: handleCreatePhraseListFromSelection
519
+ handleCreatePhraseListFromSelection: handleCreatePhraseListFromSelection,
520
+ addRow: addRow,
521
+ isDirty: isDirty,
522
+ hasTrailingEmptyRow: hasTrailingEmptyRow,
523
+ hasNonEmptyRows: hasNonEmptyRows,
524
+ processRowUpdate: processRowUpdate
596
525
  }) : /*#__PURE__*/_jsx(EmptyPhraseList, {
597
526
  t: t,
598
527
  siteLanguage: siteLanguage,
@@ -1,58 +1,93 @@
1
+ import { useMemo } from "react";
1
2
  import PropTypes from "prop-types";
2
3
  import { Box, Button, Typography } from "@mui/material";
3
4
  import { makeStyles } from "tss-react/mui";
4
- import { Grid as SpreadsheetGrid } from "react-spreadsheet-grid";
5
+ import { DataGrid } from "@mui/x-data-grid";
6
+ import AddIcon from "@mui/icons-material/Add";
5
7
  import ParseScriptErrors from "../../../Lists/ParseScriptErrors/ParseScriptErrors";
6
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
9
  const useStyles = makeStyles()(theme => ({
8
- parseErrorsBox: {
9
- marginTop: theme.spacing(),
10
+ dataGridBox: {
10
11
  padding: theme.spacing(2)
11
12
  },
12
- spreadsheetBox: {
13
- marginBottom: theme.spacing(),
14
- padding: theme.spacing(2)
13
+ dataGrid: {
14
+ "& .MuiDataGrid-columnHeader": {
15
+ backgroundColor: theme.palette.primary.main,
16
+ color: theme.palette.primary.contrastText
17
+ },
18
+ "& .MuiDataGrid-columnHeaderCheckbox .MuiSvgIcon-root": {
19
+ color: theme.palette.primary.contrastText
20
+ }
15
21
  },
16
- buttonsBox: {
17
- display: "flex",
18
- justifyContent: "space-between",
19
- alignItems: "center",
22
+ parseErrorsBox: {
20
23
  padding: theme.spacing(2),
21
- paddingBottom: 0
22
- },
23
- uploadButton: {
24
- marginRight: theme.spacing()
24
+ paddingTop: 0
25
25
  },
26
26
  saveChangesBox: {
27
27
  paddingLeft: theme.spacing(2),
28
28
  paddingBottom: theme.spacing()
29
29
  }
30
30
  }));
31
- function SpreadsheetEditor(props) {
31
+ function SpreadsheetEditor({
32
+ t = text => text,
33
+ rows,
34
+ processRowUpdate,
35
+ selectionModel,
36
+ onRowSelectionModelChange,
37
+ errors,
38
+ hasNonEmptyRows,
39
+ saveChanges,
40
+ addRow,
41
+ isDirty,
42
+ hasTrailingEmptyRow
43
+ }) {
32
44
  const {
33
45
  classes
34
46
  } = useStyles();
35
- const {
36
- t = text => text,
37
- rows,
38
- columns,
39
- onCellClick,
40
- onColumnResize,
41
- onFieldChange,
42
- errors,
43
- saveChanges
44
- } = props;
47
+ const columns = useMemo(() => [{
48
+ field: "phrase",
49
+ headerName: t("phrase"),
50
+ editable: true,
51
+ flex: 3,
52
+ minWidth: 150
53
+ }, {
54
+ field: "translations",
55
+ headerName: t("translations"),
56
+ editable: true,
57
+ flex: 2.5,
58
+ minWidth: 120
59
+ }, {
60
+ field: "definitions",
61
+ headerName: t("definitions"),
62
+ editable: true,
63
+ flex: 2.5,
64
+ minWidth: 120
65
+ }, {
66
+ field: "image",
67
+ headerName: t("image"),
68
+ editable: true,
69
+ flex: 3,
70
+ minWidth: 120
71
+ }], [t]);
45
72
  return /*#__PURE__*/_jsxs(Box, {
46
73
  children: [/*#__PURE__*/_jsx(Box, {
47
- className: classes.spreadsheetBox,
48
- children: /*#__PURE__*/_jsx(SpreadsheetGrid, {
49
- columns: columns,
74
+ className: classes.dataGridBox,
75
+ children: /*#__PURE__*/_jsx(DataGrid, {
76
+ className: classes.dataGrid,
50
77
  rows: rows,
51
- isColumnsResizable: true,
52
- onFieldChange: onFieldChange,
53
- onCellClick: onCellClick,
54
- onColumnResize: onColumnResize,
55
- getRowKey: row => row.id
78
+ columns: columns,
79
+ processRowUpdate: processRowUpdate,
80
+ onProcessRowUpdateError: error => console.error(error),
81
+ rowSelectionModel: selectionModel,
82
+ onRowSelectionModelChange: onRowSelectionModelChange,
83
+ autoHeight: true,
84
+ hideFooter: true,
85
+ disableColumnMenu: true,
86
+ disableColumnSorting: true,
87
+ disableRowSelectionOnClick: true,
88
+ checkboxSelection: true,
89
+ showCellVerticalBorder: true,
90
+ showColumnVerticalBorder: true
56
91
  })
57
92
  }), errors.length > 0 && /*#__PURE__*/_jsxs(Box, {
58
93
  className: classes.parseErrorsBox,
@@ -68,28 +103,40 @@ function SpreadsheetEditor(props) {
68
103
  t: t,
69
104
  errors: errors
70
105
  })]
71
- }), /*#__PURE__*/_jsx(Box, {
106
+ }), /*#__PURE__*/_jsxs(Box, {
72
107
  className: classes.saveChangesBox,
73
- children: /*#__PURE__*/_jsx(Button, {
108
+ sx: {
109
+ display: "flex",
110
+ gap: 1
111
+ },
112
+ children: [/*#__PURE__*/_jsx(Button, {
113
+ variant: "outlined",
114
+ onClick: addRow,
115
+ startIcon: /*#__PURE__*/_jsx(AddIcon, {}),
116
+ disabled: hasTrailingEmptyRow,
117
+ children: t("add_row")
118
+ }), /*#__PURE__*/_jsx(Button, {
74
119
  variant: "contained",
75
120
  color: "primary",
76
121
  onClick: saveChanges,
77
- disabled: errors.length > 0,
122
+ disabled: errors.length > 0 || !hasNonEmptyRows || !isDirty,
78
123
  "data-cy": "save-spreadsheet-changes",
79
124
  children: t("save_changes")
80
- })
125
+ })]
81
126
  })]
82
127
  });
83
128
  }
84
129
  SpreadsheetEditor.propTypes = {
85
- t: PropTypes.func.isRequired,
130
+ t: PropTypes.func,
86
131
  rows: PropTypes.array,
132
+ processRowUpdate: PropTypes.func,
133
+ selectionModel: PropTypes.object,
134
+ onRowSelectionModelChange: PropTypes.func,
87
135
  errors: PropTypes.array,
88
- columns: PropTypes.array,
89
- selectedRow: PropTypes.number,
90
- onCellClick: PropTypes.func,
91
- onColumnResize: PropTypes.func,
92
- onFieldChange: PropTypes.func,
93
- saveChanges: PropTypes.func
136
+ hasNonEmptyRows: PropTypes.bool,
137
+ saveChanges: PropTypes.func,
138
+ addRow: PropTypes.func,
139
+ isDirty: PropTypes.bool,
140
+ hasTrailingEmptyRow: PropTypes.bool
94
141
  };
95
142
  export default SpreadsheetEditor;
@@ -141,9 +141,16 @@ export default function MultiStepFormDialog({
141
141
  const [activeStep, setActiveStep] = useState(0);
142
142
  const [skipped, setSkipped] = useState(new Set());
143
143
  const steps = getSteps(t);
144
+
145
+ // Only re-sync from parent when dialog opens (not on every re-render)
146
+ // For edit: this picks up the selected discussion data
147
+ // For create: this resets to clean defaults
144
148
  useEffect(() => {
145
- setValues(initialValues);
146
- }, [initialValues]);
149
+ if (open) {
150
+ setValues(initialValues);
151
+ setActiveStep(0);
152
+ }
153
+ }, [open]);
147
154
  const handleGroupAssignmentChange = updatedValues => {
148
155
  setValues(updatedValues);
149
156
  };
@@ -1,6 +1,7 @@
1
1
  import { useState, useEffect, useRef, useMemo } from "react";
2
2
  import { Link as RouterLink, useNavigate, useLocation } from "react-router";
3
3
  import { Joyride, STATUS } from "react-joyride";
4
+ import dayjs from "dayjs";
4
5
  import { Typography, Button, Box, Menu, MenuItem, IconButton, Tooltip } from "@mui/material";
5
6
  import { useTheme } from "@mui/material/styles";
6
7
  import { makeStyles } from "tss-react/mui";
@@ -1614,7 +1615,9 @@ function Classroom({
1614
1615
  },
1615
1616
  values: {
1616
1617
  members: classroomMembers,
1617
- recordTimeLimit: 1
1618
+ recordTimeLimit: 1,
1619
+ meetingDate: dayjs().add(1, "day").format("MM/DD/YYYY"),
1620
+ meetingTime: dayjs().add(1, "day").format("h:mm A")
1618
1621
  },
1619
1622
  isDialog: true,
1620
1623
  loading: loading,
@@ -1,83 +1,87 @@
1
1
  import { useEffect, useState } from "react";
2
-
3
- /**
4
- * Custom hook to manage the state and handlers of spreadsheet in react-spreadsheet-grid component
5
- * @param data
6
- * @param rowTemplate
7
- * @param initColumns
8
- * @param isRowEmpty
9
- * @returns {{onCellClick: (function(*): void), setRows: (value: (((prevState: *[]) => *[]) | *[])) => void, columns: unknown, onColumnResize: onColumnResize, selectedRow: unknown, rows: *[], onFieldChange: (function(*, *): function(*): void), isRowEmpty, setSelectedRow: (value: unknown) => void, deleteSelectedRow: deleteSelectedRow}}
10
- */
11
2
  export default function useSpreadsheetState({
12
3
  data = [],
13
4
  rowTemplate,
14
- initColumns,
15
5
  isRowEmpty
16
6
  }) {
7
+ // Converts a raw phrase row (arrays for translations/definitions, separate
8
+ // alternativeVersions) into the flat string format used by the spreadsheet.
17
9
  const formatRows = rows => {
18
10
  return rows.map((r, index) => {
19
- const translationsArray = Array.isArray(r.translations) ? r.translations : r.translations.split("|").map(t => t.trim());
11
+ const translationsArray = Array.isArray(r.translations) ? r.translations : (r.translations || "").split("|").map(t => t.trim());
12
+ const definitionsArray = Array.isArray(r.definitions) ? r.definitions : (r.definitions || "").split("|").map(d => d.trim());
13
+
14
+ // Combine phrase + alternativeVersions into one pipe-separated string for
15
+ // display and editing. formatRowsToPhrases splits them back on save.
16
+ const phraseDisplay = [r.phrase || "", ...(r.alternativeVersions || [])].filter(Boolean).join(" | ");
20
17
  return {
21
18
  ...r,
22
19
  id: index,
23
- translations: translationsArray.join(" | ")
20
+ phrase: phraseDisplay,
21
+ translations: translationsArray.join(" | "),
22
+ definitions: definitionsArray.join(" | ")
24
23
  };
25
24
  });
26
25
  };
27
26
  const [rows, setRows] = useState([]);
28
- const [columns, setColumns] = useState(initColumns());
29
- const [selectedRow, setSelectedRow] = useState(undefined);
30
- const onColumnResize = widthValues => {
31
- const newColumns = [].concat(columns);
32
- Object.keys(widthValues).forEach(columnId => {
33
- const foundIndex = newColumns.findIndex(col => col.id === columnId);
34
- newColumns[foundIndex].width = widthValues[columnId];
35
- });
36
- setColumns(newColumns);
37
- };
38
-
39
- // stringified to detect changes in nested objects
27
+ const [isDirty, setIsDirty] = useState(false);
40
28
  const dataStringified = JSON.stringify(data);
41
29
  useEffect(() => {
42
- const parsed = JSON.parse(dataStringified);
43
- setRows(formatRows(parsed));
44
- }, [dataStringified]);
45
- const onFieldChange = (rowId, field) => value => {
46
- setRows(prevState => {
47
- const newRows = [...prevState];
48
- // Find the row that is being changed
49
- const row = newRows.find(({
50
- id
51
- }) => id === rowId);
30
+ const formatted = formatRows(JSON.parse(dataStringified));
31
+ setRows(formatted);
32
+ setIsDirty(false);
33
+ }, [dataStringified]); // eslint-disable-line react-hooks/exhaustive-deps
52
34
 
53
- // Change a value of a field
54
- row[field] = value;
55
- if (!isRowEmpty(newRows[newRows.length - 1])) {
56
- newRows.push({
57
- id: newRows.length,
58
- ...rowTemplate
35
+ // Called by DataGrid after a cell edit is committed. Returns the updated row
36
+ // so DataGrid can update its own display, and appends an empty trailing row
37
+ // whenever the previous last row now has content.
38
+ const processRowUpdate = newRow => {
39
+ setRows(prevRows => {
40
+ const updated = prevRows.map(r => r.id === newRow.id ? newRow : r);
41
+ if (!isRowEmpty(updated[updated.length - 1])) {
42
+ updated.push({
43
+ ...rowTemplate,
44
+ id: updated.length,
45
+ translations: "",
46
+ definitions: ""
59
47
  });
60
48
  }
61
- return newRows;
49
+ return updated;
62
50
  });
51
+ setIsDirty(true);
52
+ return newRow;
53
+ };
54
+
55
+ // Removes rows whose ids are in selectedIds, re-indexes the remainder,
56
+ // and returns the new rows so callers can save immediately.
57
+ const deleteRows = selectedIds => {
58
+ const filtered = rows.filter(r => !selectedIds.has(r.id));
59
+ const newRows = formatRows(filtered);
60
+ setRows(newRows);
61
+ setIsDirty(true);
62
+ return newRows;
63
63
  };
64
- const onCellClick = row => setSelectedRow(row.id);
65
- const deleteSelectedRow = () => {
66
- setRows(prevState => {
67
- const newRows = prevState.filter(r => r.id !== selectedRow);
68
- return formatRows(newRows);
64
+
65
+ // Explicitly appends a new empty row regardless of current state.
66
+ const addRow = () => {
67
+ setRows(prevRows => {
68
+ const newRows = [...prevRows, {
69
+ ...rowTemplate,
70
+ id: prevRows.length,
71
+ translations: "",
72
+ definitions: ""
73
+ }];
74
+ return newRows;
69
75
  });
76
+ setIsDirty(true);
70
77
  };
78
+ const hasTrailingEmptyRow = rows.length > 0 && isRowEmpty(rows[rows.length - 1]);
71
79
  return {
72
80
  rows,
73
- columns,
74
- setRows,
75
- selectedRow,
76
- setSelectedRow,
77
- deleteSelectedRow,
78
- onColumnResize,
79
- onFieldChange,
80
- onCellClick,
81
- isRowEmpty
81
+ processRowUpdate,
82
+ deleteRows,
83
+ addRow,
84
+ isDirty,
85
+ hasTrailingEmptyRow
82
86
  };
83
87
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nualang/nualang-ui-components",
3
- "version": "0.1.1364",
3
+ "version": "0.1.1365",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -20,6 +20,7 @@
20
20
  "@emotion/styled": "^11.13",
21
21
  "@hookform/resolvers": "^5.2.2",
22
22
  "@json2csv/plainjs": "^7.0.1",
23
+ "@mui/x-data-grid": "^9.0.1",
23
24
  "@nualang/avatars": "2.0.3",
24
25
  "@nualang/rivescript": "^2.2.2-alpha1",
25
26
  "axios": "^1.14.0",
@@ -76,7 +77,6 @@
76
77
  "react-qrcode-logo": "^4.0.0",
77
78
  "react-refresh": "^0.18.0",
78
79
  "react-simplemde-editor": "5.2.0",
79
- "react-spreadsheet-grid": "^2.3.1",
80
80
  "react-swipeable-views": "^0.14.0",
81
81
  "rehype-raw": "^7.0.0",
82
82
  "socket.io-client": "^4.7.1",
@@ -1,88 +0,0 @@
1
- import { useState } from "react";
2
- import { Typography } from "@mui/material";
3
- import { Grid, Input } from "react-spreadsheet-grid";
4
- import { jsx as _jsx } from "react/jsx-runtime";
5
- const initRows = [{
6
- id: 0,
7
- phrase: "hello",
8
- translations: "hola"
9
- }, {
10
- id: 1,
11
- phrase: "dog",
12
- translations: "madra"
13
- }];
14
- export default function SpreadsheetGrid({
15
- t = text => text
16
- }) {
17
- // const [rows, setRows] = useState([]);
18
- const [rows, setRows] = useState(initRows);
19
-
20
- // A callback called every time a value changed.
21
- // Every time it save a new value to the state.
22
- const onFieldChange = (rowId, field) => value => {
23
- // Find the row that is being changed
24
- // const row = rows.find({ id } => id === rowId);
25
- const row = rows.find(({
26
- id
27
- }) => id === rowId);
28
-
29
- // Change a value of a field
30
- row[field] = value;
31
- setRows([].concat(rows));
32
- };
33
- const initColumns = () => [{
34
- id: "phrase",
35
- title: () => /*#__PURE__*/_jsx(Typography, {
36
- children: t("phrase")
37
- }),
38
- value: (row, {
39
- focus
40
- }) => {
41
- return /*#__PURE__*/_jsx(Input, {
42
- value: row.phrase,
43
- focus: focus,
44
- onChange: onFieldChange(row.id, "phrase")
45
- });
46
- },
47
- width: 50
48
- }, {
49
- id: "translations",
50
- title: () => /*#__PURE__*/_jsx(Typography, {
51
- children: t("translations")
52
- }),
53
- value: (row, {
54
- focus
55
- }) => {
56
- return /*#__PURE__*/_jsx(Input, {
57
- value: row.translations,
58
- focus: focus,
59
- onChange: onFieldChange(row.id, "translations")
60
- });
61
- },
62
- width: 50
63
- }];
64
- const [columns, setColumns] = useState(initColumns());
65
-
66
- // Change columns width values in the state to not lose them.
67
- const onColumnResize = widthValues => {
68
- const newColumns = [].concat(columns);
69
- Object.keys(widthValues).forEach(columnId => {
70
- const foundIndex = newColumns.findIndex(col => col.id === columnId);
71
- newColumns[foundIndex].width = widthValues[columnId];
72
- });
73
- setColumns(newColumns);
74
- };
75
- return /*#__PURE__*/_jsx(Grid, {
76
- columns: columns,
77
- rows: rows,
78
- isColumnsResizable: true,
79
- onColumnResize: onColumnResize,
80
- getRowKey: row => row.id
81
- });
82
- }
83
- SpreadsheetGrid.propTypes = {
84
- // t: PropTypes.func.isRequired,
85
- // initColumns: PropTypes.func.isRequired;
86
- // onFieldChange: PropTypes.func.isRequired;
87
- // onColumnResize: PropTypes.func.isRequired
88
- };