@nualang/nualang-ui-components 0.1.1190 → 0.1.1191

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Chat/Chat.js CHANGED
@@ -49,6 +49,7 @@ function Chat({
49
49
  moveScriptItem,
50
50
  handleRemoveMessage,
51
51
  learnLang,
52
+ voice,
52
53
  forLang,
53
54
  isPrimaryColor = false,
54
55
  handleKeyPress,
@@ -122,6 +123,7 @@ function Chat({
122
123
  speak: speak,
123
124
  stopSpeaking: stopSpeaking,
124
125
  learnLang: learnLang,
126
+ voice: voice,
125
127
  forLang: forLang,
126
128
  voiceSpeed: voiceSpeed,
127
129
  handleEditMessage: handleEditMessage,
@@ -60,6 +60,7 @@ function Messages({
60
60
  answerCounts,
61
61
  noAnswerCounts,
62
62
  moveScriptItem,
63
+ voice,
63
64
  ...otherProps
64
65
  }) {
65
66
  const {
@@ -175,6 +176,7 @@ function Messages({
175
176
  disableTranslation: disableTranslation,
176
177
  messageIndex: i,
177
178
  voiceSpeed: voiceSpeed,
179
+ voice: voice,
178
180
  messageCount: messages.length,
179
181
  isSpeaking: isSpeaking,
180
182
  isSpeakingTextContainer: isSpeakingTextContainer,
@@ -217,6 +219,7 @@ function Messages({
217
219
  disableTranslation: disableTranslation,
218
220
  messageIndex: i,
219
221
  voiceSpeed: voiceSpeed,
222
+ voice: voice,
220
223
  messageCount: messages.length,
221
224
  isSpeaking: isSpeaking,
222
225
  isSpeakingTextContainer: isSpeakingTextContainer,
@@ -219,9 +219,9 @@ function InviteDialog({
219
219
  component: "b",
220
220
  fontWeight: "bold",
221
221
  color: "primary"
222
- }, "Practice more with ", /*#__PURE__*/_react.default.createElement(NualangLogo, {
222
+ }, "Go to ", /*#__PURE__*/_react.default.createElement(NualangLogo, {
223
223
  src: _nualangLogoPrimary.default
224
- })), " ", "via the ", /*#__PURE__*/_react.default.createElement("b", null, "Learning Site"), ".")) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, teachClassroomsState.length > 0 && /*#__PURE__*/_react.default.createElement(_material.Tabs, {
224
+ }), " classroom"), " ", "via the ", /*#__PURE__*/_react.default.createElement("b", null, "Learning Site"), ".")) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, teachClassroomsState.length > 0 && /*#__PURE__*/_react.default.createElement(_material.Tabs, {
225
225
  value: tabValue,
226
226
  onChange: handleChangeTab,
227
227
  sx: {
@@ -87,6 +87,22 @@ const useStyles = (0, _mui.makeStyles)()(theme => ({
87
87
  paddingRight: `env(safe-area-inset-right)`
88
88
  }
89
89
  }));
90
+ function parsePhraseWithAlternatives(phraseString) {
91
+ const parts = phraseString.split("|").map(p => p.trim());
92
+ return {
93
+ primary: parts[0],
94
+ alternatives: parts.slice(1).filter(p => p && p.length > 0)
95
+ };
96
+ }
97
+
98
+ /**
99
+ * Processes CSV data with the following format:
100
+ * - phrase: Primary phrase with optional alternatives separated by '|'
101
+ * Example: "Hello|Hi|Hey"
102
+ * - translations: Multiple translations separated by '|'
103
+ * - image: Optional image URL
104
+ */
105
+
90
106
  function UploadPhrases({
91
107
  t = text => text,
92
108
  open,
@@ -136,9 +152,14 @@ function UploadPhrases({
136
152
  if (data.phrase && data.translations) {
137
153
  setisError(false);
138
154
  setErrorMessage("");
155
+ const {
156
+ primary,
157
+ alternatives
158
+ } = parsePhraseWithAlternatives(data.phrase);
139
159
  const formattedTranslations = data.translations.split("|").map(t => t.trim());
140
160
  return {
141
- phrase: data.phrase.trim(),
161
+ phrase: primary,
162
+ alternativeVersions: alternatives,
142
163
  translations: formattedTranslations,
143
164
  image: data.image ? data.image.trim() : "",
144
165
  voices: [],
@@ -182,6 +182,9 @@ function Bot({
182
182
  const tabVariant = isSmallScreen ? "fullWidth" : null;
183
183
  const [tabValue, setTabValue] = (0, _react.useState)(0);
184
184
  const [simplified, setSimplified] = (0, _react.useState)(initialValues.editorMode === "advanced" ? false : true);
185
+ const {
186
+ voice
187
+ } = bot;
185
188
  const joyrideSteps = [{
186
189
  content: /*#__PURE__*/_react.default.createElement("h2", null, t("bot_editor_welcome")),
187
190
  placement: "center",
@@ -549,7 +552,8 @@ function Bot({
549
552
  speak: speak,
550
553
  stopSpeaking: stopSpeaking,
551
554
  isSpeaking: isSpeaking,
552
- isSpeakingTextContainer: isSpeakingTextContainer
555
+ isSpeakingTextContainer: isSpeakingTextContainer,
556
+ voice: voice
553
557
  });
554
558
  const tabs = [{
555
559
  label: t("editor")
@@ -243,15 +243,15 @@ function PhrasesEditor(props) {
243
243
  return rowEmpty;
244
244
  };
245
245
  const formatRowsToPhrases = rows => {
246
- const filtered = rows.filter(r => !isRowEmpty(r));
247
- return filtered.map((r, index) => {
248
- const newRow = {
246
+ return rows.filter(r => !isRowEmpty(r)).map(r => {
247
+ const newAlternatives = r.phrase.includes("|") ? r.phrase.split("|").slice(1).map(a => a.trim()).filter(Boolean) : [];
248
+ const updatedAlternativeVersions = [...(r.alternativeVersions || []), ...newAlternatives.filter(alt => !r.alternativeVersions?.map(v => v.toLowerCase()).includes(alt.toLowerCase()))];
249
+ return {
249
250
  ...r,
250
- idx: index,
251
- translations: r.translations.split("|").map(t => t.trim())
251
+ phrase: r.phrase.split("|")[0].trim() || '',
252
+ alternativeVersions: updatedAlternativeVersions,
253
+ translations: (r.translations || '').split("|").map(t => t.trim()).filter(Boolean)
252
254
  };
253
- delete newRow.id;
254
- return newRow;
255
255
  });
256
256
  };
257
257
 
@@ -311,8 +311,10 @@ function PhrasesEditor(props) {
311
311
  value: (row, {
312
312
  focus
313
313
  }) => {
314
+ const phraseDisplay = [row.phrase || '', ...(row.alternativeVersions || [])].filter(Boolean).join(" | ");
314
315
  return /*#__PURE__*/_react.default.createElement(_reactSpreadsheetGrid.Input, {
315
- value: row.phrase,
316
+ value: phraseDisplay,
317
+ placeholder: t("enter_phrase_with_alternatives"),
316
318
  focus: focus,
317
319
  onChange: onFieldChange(row.id, "phrase")
318
320
  });
@@ -393,27 +395,29 @@ function PhrasesEditor(props) {
393
395
  };
394
396
  const handleScriptDownload = () => {
395
397
  try {
398
+ const formattedRows = rows.map(row => ({
399
+ ...row,
400
+ phrase: [row.phrase || '', ...(row.alternativeVersions || [])].filter(Boolean).join(" | ")
401
+ }));
396
402
  const parser = new _plainjs.Parser({
397
403
  fields: ["phrase", "translations", "image"],
398
404
  defaultValue: ""
399
405
  });
400
- const csv = parser.parse(rows);
406
+ const csv = parser.parse(formattedRows);
401
407
  const element = document.createElement("a");
402
- const file = new Blob([csv.replace(",,", "").trim()], {
408
+ const file = new Blob([csv], {
403
409
  type: "text/plain"
404
410
  });
405
411
  element.href = URL.createObjectURL(file);
406
- const date = new Date();
407
- const dayOfDownload = date.getDate();
408
- const monthOfDownload = date.getMonth() + 1;
409
- const yearOfDownload = date.getFullYear();
410
- const formattedDate = `${dayOfDownload}-${monthOfDownload}-${yearOfDownload}`;
411
- element.download = `${topicName}-${formattedDate}.csv`;
412
- document.body.appendChild(element); // Required for this to work in Firefox
412
+ element.download = `${topicName}-${new Date().toLocaleDateString()}.csv`;
413
+ document.body.appendChild(element);
413
414
  element.click();
415
+ // Cleanup
416
+ document.body.removeChild(element);
417
+ URL.revokeObjectURL(element.href);
414
418
  } catch (err) {
415
419
  console.error(err);
416
- alert("There was a problem downloading");
420
+ alert(t("download_error"));
417
421
  }
418
422
  };
419
423
  const handleModeSelection = (event, mode) => {
@@ -848,14 +848,16 @@ function Listener({
848
848
  handleSubmit: () => handleContinue(false),
849
849
  handleSkip: () => handleContinue(true),
850
850
  isSubmitAnswerAllowed: true,
851
- isSubmitAnswerDisabled: !isWordBankAttemptChanged || !listeningWords || listeningWords.length === 0
851
+ isSubmitAnswerDisabled: !isWordBankAttemptChanged || !listeningWords || listeningWords.length === 0,
852
+ useWordBank: useWordBank
852
853
  }) : /*#__PURE__*/_react.default.createElement(_ExerciseBottomBar.default, {
853
854
  t: t,
854
855
  listeningWords: listeningWords,
855
856
  handleSubmit: () => handleContinue(false),
856
857
  handleSkip: () => handleContinue(true),
857
858
  isSubmitAnswerAllowed: true,
858
- isSubmitAnswerDisabled: !listeningText && (!listeningWords || listeningWords.length === 0)
859
+ isSubmitAnswerDisabled: !listeningText && (!listeningWords || listeningWords.length === 0),
860
+ useWordBank: useWordBank
859
861
  }), /*#__PURE__*/_react.default.createElement(_CompletedExcercise.default, {
860
862
  open: isCompletionModalOpen,
861
863
  restartExcercise: handleRestartExercise,
@@ -826,14 +826,16 @@ function Translator({
826
826
  handleSubmit: () => handleContinue(false),
827
827
  handleSkip: () => handleContinue(true),
828
828
  isSubmitAnswerAllowed: true,
829
- isSubmitAnswerDisabled: !isWordBankAttemptChanged || !translationWords || translationWords.length === 0
829
+ isSubmitAnswerDisabled: !isWordBankAttemptChanged || !translationWords || translationWords.length === 0,
830
+ useWordBank: useWordBank
830
831
  }) : /*#__PURE__*/_react.default.createElement(_ExerciseBottomBar.default, {
831
832
  t: t,
832
833
  translationWords: translationWords,
833
834
  handleSubmit: () => handleContinue(false),
834
835
  handleSkip: () => handleContinue(true),
835
836
  isSubmitAnswerAllowed: true,
836
- isSubmitAnswerDisabled: !translationText && (!translationWords || translationWords.length === 0)
837
+ isSubmitAnswerDisabled: !translationText && (!translationWords || translationWords.length === 0),
838
+ useWordBank: useWordBank
837
839
  }), /*#__PURE__*/_react.default.createElement(_AnswerResult.default, _extends({
838
840
  t: t,
839
841
  open: isCorrectResultOpen,
@@ -36,8 +36,9 @@ function ChipInput(props) {
36
36
  return /*#__PURE__*/_react.default.createElement(_CustomChipInput.default, _extends({
37
37
  label: label
38
38
  }, props, {
39
- onAdd: chip => handleAddChip(chip),
40
- onDelete: chip => deleteChip(chip)
39
+ onAdd: handleAddChip,
40
+ onDelete: deleteChip,
41
+ delimiter: delimiter
41
42
  }));
42
43
  }
43
44
  var _default = exports.default = ChipInput;
@@ -269,13 +269,17 @@ function FeedbackForm({
269
269
  }, /*#__PURE__*/_react.default.createElement(_material.Box, {
270
270
  key: attendee?.memberId,
271
271
  display: "flex",
272
- alignItems: "center"
272
+ alignItems: "center",
273
+ sx: {
274
+ marginBottom: 1,
275
+ marginTop: 1
276
+ }
273
277
  }, index !== 0 && /*#__PURE__*/_react.default.createElement(_material.Avatar, {
274
278
  alt: attendee,
275
279
  src: attendee.userImage,
276
280
  sx: {
277
- width: 24,
278
- height: 24,
281
+ width: 40,
282
+ height: 40,
279
283
  marginRight: "8px"
280
284
  }
281
285
  }), attendee.username, index === 0 &&
@@ -6,7 +6,13 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = FeedbackInfo;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _material = require("@mui/material");
9
+ var _theme = require("../../../../.storybook/theme");
9
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ const getModeConditionalBackground = (dark, light) => theme => ({
12
+ backgroundColor: theme.palette.mode === "dark" ? dark // Using MUI's palette
13
+ : light,
14
+ padding: 2
15
+ });
10
16
  function FeedbackInfo({
11
17
  values = {
12
18
  feedback1: [{
@@ -79,10 +85,7 @@ function FeedbackInfo({
79
85
  }, gradingOption)))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
80
86
  container: true,
81
87
  alignItems: "flex-start",
82
- sx: {
83
- backgroundColor: "#f0f0f0",
84
- padding: 2
85
- }
88
+ sx: getModeConditionalBackground("#424242", "#f0f0f0")
86
89
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
87
90
  item: true,
88
91
  xs: 4
@@ -98,10 +101,7 @@ function FeedbackInfo({
98
101
  }, feedback1.length > 0 ? feedback1[0]?.feedbackLevelName : "-"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
99
102
  container: true,
100
103
  alignItems: "flex-start",
101
- sx: {
102
- backgroundColor: "#e0e0e0",
103
- padding: 2
104
- }
104
+ sx: getModeConditionalBackground("#303030", "#e0e0e0")
105
105
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
106
106
  item: true,
107
107
  xs: 4
@@ -117,10 +117,7 @@ function FeedbackInfo({
117
117
  }, feedback2.length > 0 ? feedback2[0]?.feedbackLevelName : "-"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
118
118
  container: true,
119
119
  alignItems: "flex-start",
120
- sx: {
121
- backgroundColor: "#f0f0f0",
122
- padding: 2
123
- }
120
+ sx: getModeConditionalBackground("#424242", "#f0f0f0")
124
121
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
125
122
  item: true,
126
123
  xs: 4
@@ -136,10 +133,7 @@ function FeedbackInfo({
136
133
  }, feedback3.length > 0 ? feedback3[0]?.feedbackLevelName : "-"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
137
134
  container: true,
138
135
  alignItems: "flex-start",
139
- sx: {
140
- backgroundColor: "#e0e0e0",
141
- padding: 2
142
- }
136
+ sx: getModeConditionalBackground("#303030", "#e0e0e0")
143
137
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
144
138
  item: true,
145
139
  xs: 4
@@ -155,10 +149,7 @@ function FeedbackInfo({
155
149
  }, feedback4.length > 0 ? feedback4[0]?.feedbackLevelName : "-"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
156
150
  container: true,
157
151
  alignItems: "flex-start",
158
- sx: {
159
- backgroundColor: "#f0f0f0",
160
- padding: 2
161
- }
152
+ sx: getModeConditionalBackground("#424242", "#f0f0f0")
162
153
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
163
154
  item: true,
164
155
  xs: 4
@@ -174,10 +165,7 @@ function FeedbackInfo({
174
165
  }, feedback5.length > 0 ? feedback5[0]?.feedbackLevelName : "-"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
175
166
  container: true,
176
167
  alignItems: "flex-start",
177
- sx: {
178
- backgroundColor: "#e0e0e0",
179
- padding: 2
180
- }
168
+ sx: getModeConditionalBackground("#303030", "#e0e0e0")
181
169
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
182
170
  item: true,
183
171
  xs: 4
@@ -193,10 +181,7 @@ function FeedbackInfo({
193
181
  }, feedback6.length > 0 ? feedback6[0]?.feedbackLevelName : "-"))), /*#__PURE__*/_react.default.createElement(_material.Grid, {
194
182
  container: true,
195
183
  alignItems: "flex-start",
196
- sx: {
197
- backgroundColor: "#f0f0f0",
198
- padding: 2
199
- }
184
+ sx: getModeConditionalBackground("#424242", "#f0f0f0")
200
185
  }, /*#__PURE__*/_react.default.createElement(_material.Grid, {
201
186
  item: true,
202
187
  xs: 4
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.Adornment = Adornment;
7
7
  exports.default = void 0;
8
8
  var _react = _interopRequireWildcard(require("react"));
9
+ var _styles = require("@mui/material/styles");
9
10
  var _IconButton = _interopRequireDefault(require("@mui/material/IconButton"));
10
11
  var _Input = _interopRequireDefault(require("@mui/material/Input"));
11
12
  var _OutlinedInput = _interopRequireDefault(require("@mui/material/OutlinedInput"));
@@ -19,8 +20,7 @@ var _Menu = _interopRequireDefault(require("@mui/material/Menu"));
19
20
  var _MenuItem = _interopRequireDefault(require("@mui/material/MenuItem"));
20
21
  var _FormHelperText = _interopRequireDefault(require("@mui/material/FormHelperText"));
21
22
  var _reactFeather = require("react-feather");
22
- var _react2 = _interopRequireDefault(require("@emoji-mart/react"));
23
- var _apple = _interopRequireDefault(require("@emoji-mart/data/sets/14/apple.json"));
23
+ var _emojiPickerReact = _interopRequireDefault(require("emoji-picker-react"));
24
24
  var _Dialog = _interopRequireDefault(require("@mui/material/Dialog"));
25
25
  var _index = require("../../utils/index");
26
26
  var _colors = require("@mui/material/colors");
@@ -50,6 +50,7 @@ function Adornment(props) {
50
50
  setIsDisabled,
51
51
  setIsButtonClicked
52
52
  } = props;
53
+ const theme = (0, _styles.useTheme)();
53
54
  const isEnglish = learnLang === "english";
54
55
  const isSmallScreen = (0, _useMediaQuery.default)("(max-width:420px)");
55
56
  const {
@@ -85,18 +86,17 @@ function Adornment(props) {
85
86
  }
86
87
  });
87
88
  };
88
- const addEmoji = emoji => {
89
- handleEmojiClose();
90
- const newText = [value.slice(0, selectionStart), `${emoji.native}`, value.slice(selectionStart)].join("");
89
+ const handleEmojiClose = () => {
90
+ setShowEmojiPicker(false);
91
+ };
92
+ const onEmojiClick = event => {
93
+ const newText = [value.slice(0, selectionStart), `${event.emoji}`, value.slice(selectionStart)].join("");
91
94
  onChange({
92
95
  target: {
93
96
  name: name,
94
97
  value: newText
95
98
  }
96
99
  });
97
- };
98
- const handleEmojiClose = () => {
99
- setIsDisabled(true);
100
100
  setShowEmojiPicker(false);
101
101
  };
102
102
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_InputAdornment.default, {
@@ -104,11 +104,12 @@ function Adornment(props) {
104
104
  }, emoji && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Dialog.default, {
105
105
  open: showEmojiPicker,
106
106
  onClose: handleEmojiClose
107
- }, /*#__PURE__*/_react.default.createElement(_react2.default, {
108
- set: "apple",
109
- onEmojiSelect: addEmoji,
110
- data: _apple.default,
111
- perLine: isSmallScreen ? 6 : 9
107
+ }, /*#__PURE__*/_react.default.createElement(_emojiPickerReact.default, {
108
+ pickerStyle: {
109
+ width: "100%"
110
+ },
111
+ theme: theme.palette.mode === "dark" ? "dark" : "light",
112
+ onEmojiClick: onEmojiClick
112
113
  })), /*#__PURE__*/_react.default.createElement(_Tooltip.default, {
113
114
  title: isDisabled ? t("Please select a textfield") : t("insert_emoji")
114
115
  }, /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_IconButton.default, {
@@ -552,7 +552,8 @@ function LiveListener({
552
552
  listeningText: listeningText,
553
553
  listeningWords: listeningWords,
554
554
  setCurrentAnswer: setCurrentAnswer,
555
- exercise: exercise
555
+ exercise: exercise,
556
+ useWordBank: useWordBank
556
557
  })));
557
558
  }
558
559
  LiveListener.propTypes = {};
@@ -666,7 +666,8 @@ function LiveTranslator({
666
666
  translationText: translationText,
667
667
  translationWords: translationWords,
668
668
  setCurrentAnswer: setCurrentAnswer,
669
- exercise: exercise
669
+ exercise: exercise,
670
+ useWordBank: useWordBank
670
671
  })));
671
672
  }
672
673
  LiveTranslator.propTypes = {};