questionlayoutrefactoring 0.1.2 → 0.1.13

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.
Files changed (67) hide show
  1. package/README.md +2 -0
  2. package/dist/components/Atoms/AssistantImageModal/ImageModal.js +2 -1
  3. package/dist/components/Atoms/AssistantImageModal/ImageModal.js.map +1 -1
  4. package/dist/components/Atoms/GlobalButton/GlobalButton.d.ts +1 -1
  5. package/dist/components/Atoms/GlobalButton/GlobalButton.js +25 -7
  6. package/dist/components/Atoms/GlobalButton/GlobalButton.js.map +1 -1
  7. package/dist/components/Molecules/ActivityBanner/ActivityBanner.js +1 -1
  8. package/dist/components/Molecules/ActivityBanner/ActivityBanner.js.map +1 -1
  9. package/dist/components/Molecules/DashPlayer/DashPlayer.stories.js +1 -1
  10. package/dist/components/Molecules/DashPlayer/DashPlayer.stories.js.map +1 -1
  11. package/dist/components/Molecules/DescriptiveAnswer/DescriptiveAnswerV1.js +1 -1
  12. package/dist/components/Molecules/DescriptiveAnswer/DescriptiveAnswerV1.js.map +1 -1
  13. package/dist/components/Molecules/FactualCard/FactualCard.d.ts +3 -1
  14. package/dist/components/Molecules/FactualCard/FactualCard.js +15 -9
  15. package/dist/components/Molecules/FactualCard/FactualCard.js.map +1 -1
  16. package/dist/components/Molecules/RecapNode/ContentView.js +2 -2
  17. package/dist/components/Molecules/RecapNode/ContentView.js.map +1 -1
  18. package/dist/components/Molecules/RecapNode/VideoView.d.ts +4 -2
  19. package/dist/components/Molecules/RecapNode/VideoView.js +14 -4
  20. package/dist/components/Molecules/RecapNode/VideoView.js.map +1 -1
  21. package/dist/components/Molecules/Revision/Revision.js +2 -2
  22. package/dist/components/Molecules/Revision/Revision.js.map +1 -1
  23. package/dist/components/Molecules/SmartLearn/SmartLearn.stories.js +10 -10
  24. package/dist/components/Molecules/SmartLearn/SmartLearn.stories.js.map +1 -1
  25. package/dist/components/Molecules/Tutor/User/User.js +1 -1
  26. package/dist/components/Molecules/Tutor/User/User.js.map +1 -1
  27. package/dist/components/Molecules/VideoView/VideoModal.js +2 -2
  28. package/dist/components/Molecules/VideoView/VideoModal.js.map +1 -1
  29. package/dist/components/Molecules/comprehension/ComprehensionLayout.js +10 -6
  30. package/dist/components/Molecules/comprehension/ComprehensionLayout.js.map +1 -1
  31. package/dist/components/Molecules/comprehension/SubQuestionLayout.js +1 -1
  32. package/dist/components/Molecules/comprehension/SubQuestionLayout.js.map +1 -1
  33. package/dist/components/Molecules/optionLayouts/Scq.js +3 -5
  34. package/dist/components/Molecules/optionLayouts/Scq.js.map +1 -1
  35. package/dist/components/Molecules/questionLayouts/AnswerView.js +0 -1
  36. package/dist/components/Molecules/questionLayouts/AnswerView.js.map +1 -1
  37. package/dist/components/Molecules/questionLayouts/QuestionView.js +0 -1
  38. package/dist/components/Molecules/questionLayouts/QuestionView.js.map +1 -1
  39. package/dist/components/Organisms/FlashCardNode/FlashCardNode.js +2 -2
  40. package/dist/components/Organisms/FlashCardNode/FlashCardNode.js.map +1 -1
  41. package/dist/components/Organisms/FlashCardNode/FlashcardContainer.d.ts +1 -2
  42. package/dist/components/Organisms/FlashCardNode/FlashcardContainer.js +2 -2
  43. package/dist/components/Organisms/FlashCardNode/FlashcardContainer.js.map +1 -1
  44. package/dist/components/Organisms/FlashCardNode/MobileAccordionView.d.ts +1 -2
  45. package/dist/components/Organisms/FlashCardNode/MobileAccordionView.js +5 -7
  46. package/dist/components/Organisms/FlashCardNode/MobileAccordionView.js.map +1 -1
  47. package/dist/components/Organisms/RecapGraph/Reactgraphflow.js +21 -44
  48. package/dist/components/Organisms/RecapGraph/Reactgraphflow.js.map +1 -1
  49. package/dist/components/Organisms/RecapGraph/useRecapGraphLogic.js +0 -8
  50. package/dist/components/Organisms/RecapGraph/useRecapGraphLogic.js.map +1 -1
  51. package/dist/components/Organisms/ReviewComponent/ReviewPresenter.d.ts +2 -1
  52. package/dist/components/Organisms/ReviewComponent/ReviewPresenter.js +3 -2
  53. package/dist/components/Organisms/ReviewComponent/ReviewPresenter.js.map +1 -1
  54. package/dist/components/Organisms/StudentEditor/StudentEditor.stories.d.ts +1 -0
  55. package/dist/components/Organisms/StudentEditor/StudentEditor.stories.js +92 -4
  56. package/dist/components/Organisms/StudentEditor/StudentEditor.stories.js.map +1 -1
  57. package/dist/components/Organisms/StudentEditor/components/MathModal.js +21 -2
  58. package/dist/components/Organisms/StudentEditor/components/MathModal.js.map +1 -1
  59. package/dist/components/Organisms/StudentEditor/components/TextEditor.js +176 -343
  60. package/dist/components/Organisms/StudentEditor/components/TextEditor.js.map +1 -1
  61. package/dist/components/Organisms/TableComponent/TableComponent.js +22 -2
  62. package/dist/components/Organisms/TableComponent/TableComponent.js.map +1 -1
  63. package/dist/index.d.ts +3 -0
  64. package/dist/index.js +8 -1
  65. package/dist/index.js.map +1 -1
  66. package/dist/utils/common-utils.js.map +1 -1
  67. package/package.json +7 -2
@@ -39,6 +39,7 @@ const slate_conversions_1 = require("../utils/slate-conversions");
39
39
  const common_utils_1 = require("../../../../utils/common-utils");
40
40
  const EditorStyles_1 = require("./EditorStyles");
41
41
  const LearningPathUtils_1 = require("../../../../utils/LearningPathUtils");
42
+ const EditorComponent_1 = require("./EditorComponent");
42
43
  const InvalidSession_1 = __importDefault(require("../../../Molecules/InvalidSession/InvalidSession"));
43
44
  // Theme customization without placeholder styling
44
45
  const theme = (0, react_2.extendTheme)({
@@ -61,7 +62,7 @@ const theme = (0, react_2.extendTheme)({
61
62
  },
62
63
  });
63
64
  const TextEditor = (props) => {
64
- const { data, handleChange, onSubmit, icons, isDisabled = false, disablePaste = false, addImageRender = undefined, height = undefined, handleOpenMath, handleCloseMath, showBottomBar = true, isMobile, tutorMode = true, taskType, handleClick: propHandleClick, isDescAnsQues = false, isRevision = false, } = props;
65
+ const { data, handleChange, onSubmit, icons, isDisabled = false, disablePaste = false, addImageRender = undefined, height = undefined, handleOpenMath, handleCloseMath, showBottomBar = true, isMobile, tutorMode = true, taskType, isRevision = false, isDescAnsQues = false, handleClick: propHandleClick, showerrorpopup, } = props;
65
66
  // Initialize the Slate editor with our custom plugins
66
67
  const editor = (0, react_1.useMemo)(() => (0, slate_plugins_1.withMath)((0, slate_history_1.withHistory)((0, slate_react_1.withReact)((0, slate_1.createEditor)()))), []);
67
68
  const [value, setValue] = (0, react_1.useState)((0, slate_conversions_1.textToSlate)(data));
@@ -69,11 +70,19 @@ const TextEditor = (props) => {
69
70
  const [currentLatex, setCurrentLatex] = (0, react_1.useState)("");
70
71
  const [editingPath, setEditingPath] = (0, react_1.useState)(null);
71
72
  const [isFocused, setIsFocused] = (0, react_1.useState)(false);
72
- const [isHovered, setIsHovered] = (0, react_1.useState)(false);
73
+ const [tabFocusedElement, setTabFocusedElement] = (0, react_1.useState)(null);
74
+ const formulaIconRef = (0, react_1.useRef)(null);
75
+ const submitButtonRef = (0, react_1.useRef)(null);
76
+ const addImageNavRef = (0, react_1.useRef)({ focusFirst: null });
73
77
  const editorRef = (0, react_1.useRef)(null);
78
+ const isDisabledRevision = isDisabled && isRevision;
79
+ const isInitialMount = (0, react_1.useRef)(true);
74
80
  (0, react_1.useEffect)(() => {
75
- setValue((0, slate_conversions_1.textToSlate)(data));
76
- if ((0, common_utils_1.isEmptyOrNull)(data)) {
81
+ if (isInitialMount.current) {
82
+ setValue((0, slate_conversions_1.textToSlate)(data));
83
+ isInitialMount.current = false;
84
+ }
85
+ else if ((0, common_utils_1.isEmptyOrNull)(data) && !(0, common_utils_1.isEmptyOrNull)((0, slate_conversions_1.slateToText)(value))) {
77
86
  handleClear();
78
87
  }
79
88
  }, [data]);
@@ -81,17 +90,18 @@ const TextEditor = (props) => {
81
90
  handleOpenMath && openMathEditor();
82
91
  }, [handleOpenMath]);
83
92
  // Focus the editor when it first mounts
84
- // useEffect(() => {
85
- // if (!isDisabled) {
86
- // setTimeout(() => {
87
- // try {
88
- // ReactEditor.focus(editor);
89
- // } catch (error) {
90
- // console.error("Error focusing editor on mount:", error);
91
- // }
92
- // }, 100);
93
- // }
94
- // }, [editor, isDisabled]);
93
+ (0, react_1.useEffect)(() => {
94
+ if (!isDisabled) {
95
+ setTimeout(() => {
96
+ try {
97
+ slate_react_1.ReactEditor.focus(editor);
98
+ }
99
+ catch (error) {
100
+ console.error("Error focusing editor on mount:", error);
101
+ }
102
+ }, 100);
103
+ }
104
+ }, [editor, isDisabled]);
95
105
  // Function to open the math editor modal for new entries
96
106
  const openMathEditor = (0, react_1.useCallback)(() => {
97
107
  const { selection } = editor;
@@ -235,7 +245,7 @@ const TextEditor = (props) => {
235
245
  case "math":
236
246
  return ((0, jsx_runtime_1.jsx)(MathElement_1.default, { "data-testid": "math-element", ...props, onEdit: () => editMath(element) }));
237
247
  default:
238
- return ((0, jsx_runtime_1.jsx)(react_2.chakra.p, { "data-testid": "text-element", ...attributes, children: children }));
248
+ return ((0, jsx_runtime_1.jsx)(react_2.Text, { "data-testid": "text-element", ...attributes, children: children }));
239
249
  }
240
250
  }, [editMath]);
241
251
  // Handle click on editable area
@@ -249,368 +259,191 @@ const TextEditor = (props) => {
249
259
  }
250
260
  }
251
261
  }, [editor]);
252
- // Enhanced clipboard handlers using Navigator Clipboard API
253
- const handlePaste = async (event) => {
262
+ const handlePaste = (0, react_1.useCallback)((event) => {
254
263
  if (disablePaste) {
255
264
  event.preventDefault();
256
265
  }
257
- };
258
- const handleCopy = async (event) => {
259
- event.preventDefault();
260
- // Clear clipboard to prevent copying
261
- try {
262
- if (navigator.clipboard && navigator.clipboard.writeText) {
263
- await navigator.clipboard.writeText("");
264
- }
265
- }
266
- catch (error) {
267
- console.error("Could not clear clipboard:", error);
268
- }
269
- };
270
- const handleCut = async (event) => {
266
+ }, [disablePaste]);
267
+ const handleDragStart = (0, react_1.useCallback)((event) => {
271
268
  event.preventDefault();
272
- // Clear clipboard to prevent cutting
273
- try {
274
- if (navigator.clipboard && navigator.clipboard.writeText) {
275
- await navigator.clipboard.writeText("");
276
- }
277
- }
278
- catch (error) {
279
- console.error("Could not clear clipboard:", error);
280
- }
281
- };
282
- // Enhanced drag and drop handlers
283
- const handleDragStart = (event) => {
284
- event.preventDefault();
285
- };
286
- const handleDrop = (event) => {
287
- event.preventDefault();
288
- };
289
- const handleDragOver = (event) => {
269
+ }, []);
270
+ const handleDrop = (0, react_1.useCallback)((event) => {
290
271
  event.preventDefault();
291
- };
292
- const handleDragEnter = (event) => {
272
+ }, []);
273
+ const handleDragOver = (0, react_1.useCallback)((event) => {
293
274
  event.preventDefault();
294
- };
295
- const handleDragLeave = (event) => {
275
+ }, []);
276
+ const handleDragEnter = (0, react_1.useCallback)((event) => {
296
277
  event.preventDefault();
297
- };
298
- const handleFocus = (0, react_1.useCallback)(() => {
299
- setIsFocused(true);
300
278
  }, []);
301
- const handleBlur = (0, react_1.useCallback)(() => {
302
- setIsFocused(false);
279
+ const handleDragLeave = (0, react_1.useCallback)((event) => {
280
+ event.preventDefault();
303
281
  }, []);
304
- const isDisabledRevision = isDisabled && isRevision;
305
- // Handle clicks outside to clear focus
306
- const handleContainerBlur = (0, react_1.useCallback)((event) => {
307
- // Check if the click is outside the editor container
308
- if (editorRef.current && !editorRef.current.contains(event.relatedTarget)) {
309
- setIsFocused(false);
282
+ const handleTabNavigation = (0, react_1.useCallback)((event) => {
283
+ if (event.key !== "Tab" || event.shiftKey)
284
+ return; // Only handle forward Tab
285
+ // Define tab order elements based on what's available
286
+ const tabElements = [];
287
+ if (icons?.formula && !isDisabled) {
288
+ tabElements.push({ name: "formula", ref: formulaIconRef });
310
289
  }
311
- }, []);
312
- // Handle hover events for the entire editor area (disabled on mobile)
313
- const handleEditorMouseEnter = (0, react_1.useCallback)(() => {
314
- if (!isMobile) {
315
- setIsHovered(true);
290
+ // Add placeholder for addImageRender - it will handle its own internal navigation
291
+ // but we need to know it exists for proper tab order coordination
292
+ if (addImageRender && !isDisabled) {
293
+ tabElements.push({ name: "addImageRender", ref: null });
294
+ }
295
+ if (icons?.submit && !isDisabled && !(0, common_utils_1.isEmptyOrNull)(data?.trim())) {
296
+ tabElements.push({ name: "submit", ref: submitButtonRef });
297
+ }
298
+ if (tabElements.length === 0)
299
+ return; // No focusable elements, let browser handle
300
+ const currentIndex = tabElements.findIndex((el) => el.name === tabFocusedElement);
301
+ let nextIndex;
302
+ if (currentIndex === -1) {
303
+ // Not currently focused on any element, start from first
304
+ event.preventDefault();
305
+ nextIndex = 0;
306
+ }
307
+ else if (currentIndex === tabElements.length - 1) {
308
+ // At last element, tab out (clear focus and let browser handle)
309
+ setTabFocusedElement(null);
310
+ return; // Don't preventDefault, let browser handle tab out
316
311
  }
317
- }, [isMobile]);
318
- const handleEditorMouseLeave = (0, react_1.useCallback)(() => {
319
- if (!isMobile) {
320
- setIsHovered(false);
321
- setIsFocused(false);
312
+ else {
313
+ // Go to next element
314
+ event.preventDefault();
315
+ nextIndex = currentIndex + 1;
322
316
  }
323
- }, [isMobile]);
324
- // Show TopSection when either focused or hovered (but NEVER on mobile)
325
- const shouldShowTopSection = (0, react_1.useMemo)(() => !isMobile &&
326
- tutorMode &&
327
- (isFocused || isHovered) &&
328
- !isRevision &&
329
- showBottomBar, [isMobile, tutorMode, isFocused, isHovered, showBottomBar]);
330
- const memoizedIcons = (0, react_1.useMemo)(() => icons, [icons?.formula, icons?.submit, icons?.shift, icons?.info]);
331
- const shiftIconStyle = (0, react_1.useMemo)(() => ({
332
- h: "16px",
333
- w: "16px",
334
- cursor: "not-allowed",
335
- }), []);
336
- const topSectionBgColor = (0, react_1.useMemo)(() => tutorMode || (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment)
337
- ? "white"
338
- : "#F8F3D8", [tutorMode, taskType]);
339
- // Use effect to handle clicks outside the editor
340
- // useEffect(() => {
341
- // const handleClickOutside = (event) => {
342
- // if (editorRef.current && !editorRef.current.contains(event.target)) {
343
- // setIsFocused(false);
344
- // }
345
- // };
346
- // document.addEventListener('mousedown', handleClickOutside);
347
- // return () => {
348
- // document.removeEventListener('mousedown', handleClickOutside);
349
- // };
350
- // }, []);
317
+ const nextElement = tabElements[nextIndex];
318
+ // Handle addImageRender specially - it manages its own internal focus
319
+ if (nextElement.name === "addImageRender") {
320
+ setTabFocusedElement("addImageRender");
321
+ // Coming from formula, focus first image element
322
+ if (addImageNavRef.current.focusFirst) {
323
+ addImageNavRef.current.focusFirst();
324
+ }
325
+ return;
326
+ }
327
+ // For formula and submit elements, use their refs
328
+ setTabFocusedElement(nextElement.name);
329
+ nextElement.ref.current?.focus();
330
+ }, [tabFocusedElement, icons, isDisabled, data, addImageRender]);
331
+ // Helper function to check if current focus is within addImageRender elements
332
+ const isCurrentlyInAddImageRender = (0, react_1.useCallback)(() => {
333
+ if (!addImageRender)
334
+ return false;
335
+ const focusedElement = document.activeElement;
336
+ if (!focusedElement || !editorRef.current)
337
+ return false;
338
+ // Check if focused element is within the editor but not formula or submit icons
339
+ const isInEditor = editorRef.current.contains(focusedElement);
340
+ const isFormulaIcon = focusedElement === formulaIconRef.current;
341
+ const isSubmitIcon = focusedElement === submitButtonRef.current;
342
+ const isEditorItself = focusedElement === editorRef.current;
343
+ return isInEditor && !isFormulaIcon && !isSubmitIcon && !isEditorItself;
344
+ }, [addImageRender]);
351
345
  // Alternative onKeyDown handler approach for the Editable component
352
- const handleKeyDown = (0, react_1.useCallback)(async (event) => {
346
+ const handleKeyDown = (0, react_1.useCallback)((event) => {
353
347
  if (isDisabled || !onSubmit)
354
348
  return;
355
- // Block common clipboard keyboard shortcuts
356
349
  if (disablePaste &&
357
350
  (event.ctrlKey || event.metaKey) &&
358
351
  (event.key === "v" || event.key === "c" || event.key === "x")) {
359
352
  event.preventDefault();
360
- // Clear clipboard when shortcuts are attempted
361
- try {
362
- if (navigator.clipboard && navigator.clipboard.writeText) {
363
- await navigator.clipboard.writeText("");
364
- }
365
- }
366
- catch (error) {
367
- console.log("Could not clear clipboard:", error);
368
- }
369
- console.log("Clipboard keyboard shortcut disabled");
353
+ }
354
+ if (event.key === "Tab" && !isCurrentlyInAddImageRender()) {
355
+ handleTabNavigation(event);
370
356
  return;
371
357
  }
372
358
  if (event.key === "Enter") {
373
- if (isMobile) {
374
- return; // Let the default behavior happen (new line)
375
- }
376
- if (event.shiftKey) {
377
- return; // Let the default behavior happen (new line)
378
- }
379
- // Regular Enter should submit
380
- event.preventDefault();
381
- const currentText = (0, slate_conversions_1.slateToText)(value);
382
- if (!(0, common_utils_1.isEmptyOrNull)(currentText?.trim()) && showBottomBar == true) {
383
- handleSubmit();
384
- handleChange && handleChange("");
385
- }
359
+ // if (isMobile) {
360
+ return; // Let the default behavior happen (new line)
361
+ // }
362
+ // if (event.shiftKey) {
363
+ // return; // Let the default behavior happen (new line)
364
+ // }
365
+ // // Regular Enter should submit
366
+ // event.preventDefault();
367
+ // const currentText = slateToText(value);
368
+ // if (!isEmptyOrNull(currentText?.trim()) && showBottomBar == true) {
369
+ // handleSubmit();
370
+ // handleChange && handleChange("");
371
+ // }
386
372
  }
387
- }, [value, handleSubmit, handleChange, isDisabled]);
388
- const isDataEmpty = (0, react_1.useMemo)(() => (0, common_utils_1.isEmptyOrNull)(data), [data]);
389
- // Mobile bottom icons section
390
- const MobileBottomIcons = (0, react_1.useMemo)(() => {
391
- if (!isMobile || !tutorMode)
392
- return null;
393
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_2.Box, { sx: {
394
- height: "1px",
395
- backgroundColor: "#E0DBDB",
396
- width: "100%",
397
- mt: 3,
398
- mb: 3,
399
- } }), (0, jsx_runtime_1.jsxs)(react_2.HStack, { justifyContent: "flex-end", alignItems: "center", width: "100%", spacing: 2, children: [(0, jsx_runtime_1.jsx)(react_2.HStack, { spacing: 3, children: (tutorMode ||
400
- (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment)) && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [memoizedIcons?.formula && ((0, jsx_runtime_1.jsx)(react_2.Image, { sx: {
401
- h: "28px",
402
- w: "28px",
403
- cursor: isDisabled ? "not-allowed" : "pointer",
404
- }, src: memoizedIcons?.formula, alt: "Add formula", onClick: () => {
405
- !isDisabled && openMathEditor();
406
- } })), addImageRender && addImageRender()] })) }), memoizedIcons?.submit && ((0, jsx_runtime_1.jsx)(react_2.Image, { "data-testid": "submit-icon", sx: {
407
- h: "48px",
408
- w: "48px",
409
- cursor: isDataEmpty ? "not-allowed" : "pointer",
410
- opacity: isDataEmpty ? 0.6 : 1,
411
- }, src: memoizedIcons?.submit, alt: "submit", onClick: () => {
412
- if (!(0, common_utils_1.isEmptyOrNull)(data?.trim())) {
413
- handleSubmit();
414
- handleChange && handleChange("");
415
- }
416
- } }))] })] }));
417
373
  }, [
374
+ value,
375
+ handleSubmit,
376
+ handleChange,
377
+ isDisabled,
378
+ handleTabNavigation,
379
+ isCurrentlyInAddImageRender,
380
+ ]);
381
+ const editorBoxProps = (0, react_1.useMemo)(() => ({
382
+ editorRef,
383
+ handleClick,
384
+ height,
385
+ handleKeyDown,
386
+ handlePaste,
387
+ handleDrop,
388
+ handleDragOver,
389
+ handleDragEnter,
390
+ handleDragLeave,
391
+ handleDragStart,
392
+ isDisabled,
393
+ showBottomBar,
394
+ isRevision,
395
+ renderElement,
418
396
  isMobile,
397
+ isDescAnsQues,
398
+ }), [
399
+ editorRef,
400
+ handleClick,
401
+ height,
402
+ handleKeyDown,
403
+ handlePaste,
404
+ handleDrop,
405
+ handleDragOver,
406
+ handleDragEnter,
407
+ handleDragLeave,
408
+ handleDragStart,
409
+ isDisabled,
410
+ showBottomBar,
411
+ isRevision,
412
+ renderElement,
413
+ isMobile,
414
+ isDescAnsQues,
415
+ ]);
416
+ const iconProps = {
419
417
  tutorMode,
420
418
  taskType,
421
- memoizedIcons,
419
+ icons,
422
420
  isDisabled,
423
- isDataEmpty,
424
- addImageRender,
425
421
  openMathEditor,
426
- handleChange,
422
+ addImageRender,
427
423
  data,
428
- ]);
429
- const TopSection = (0, react_1.useMemo)(() => {
430
- // Don't show top section on mobile at all
431
- if (isMobile)
432
- return null;
433
- return ((0, jsx_runtime_1.jsx)(react_2.Box, { position: "absolute", top: "0", left: "0", right: "0", zIndex: 10, overflow: "hidden", sx: {
434
- height: shouldShowTopSection ? "auto" : "0px",
435
- opacity: shouldShowTopSection ? 1 : 0,
436
- // Add smooth transitions with delay
437
- transition: shouldShowTopSection
438
- ? "opacity 0.2s ease-in-out 0.1s, height 0.3s ease-in-out"
439
- : "opacity 0.15s ease-in-out, height 0.25s ease-in-out 0.1s",
440
- }, children: (0, jsx_runtime_1.jsxs)(react_2.Box, { sx: {
441
- transform: shouldShowTopSection
442
- ? "translateY(0)"
443
- : "translateY(-100%)",
444
- // Smooth slide transition with delay
445
- transition: shouldShowTopSection
446
- ? "transform 0.3s ease-out 0.15s"
447
- : "transform 0.2s ease-in",
448
- backgroundColor: tutorMode || (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment)
424
+ handleSubmit,
425
+ handleChange,
426
+ formulaIconRef,
427
+ submitButtonRef,
428
+ addImageNavRef,
429
+ tabFocusedElement,
430
+ setTabFocusedElement,
431
+ handleTabNavigation,
432
+ };
433
+ const StackWrapper = isMobile ? react_2.VStack : react_2.HStack;
434
+ const IconsComponent = EditorComponent_1.Icons;
435
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [showerrorpopup && (0, jsx_runtime_1.jsx)(InvalidSession_1.default, { handleClick: propHandleClick }), (0, jsx_runtime_1.jsx)(react_2.ChakraProvider, { theme: theme, children: (0, jsx_runtime_1.jsxs)(react_2.Box, { "data-testid": "studenteditor", w: "100%", borderRadius: "16px", p: isMobile ? "8px" : "16px", border: showBottomBar ? "1px solid #BFBEDC" : "none", pointerEvents: isDisabled ? "none" : "auto", opacity: tutorMode === false ? 1 : isDisabled ? 0.5 : 1, bg: tutorMode || (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment)
449
436
  ? "white"
450
- : "#F8F3D8",
451
- borderRadius: "12px 12px 0 0",
452
- px: 4,
453
- pt: 3,
454
- }, children: [(0, jsx_runtime_1.jsxs)(react_2.HStack, { justifyContent: "space-between", position: "relative", userSelect: "none", pb: 2, children: [(0, jsx_runtime_1.jsx)(react_2.Box, { ml: 2, display: "flex", children: !isDisabled && ((0, jsx_runtime_1.jsx)(react_2.Text, { as: "div", sx: EditorStyles_1.styles.multiLineText, children: "Press Enter to send, Shift+Enter for new line" })) }), (0, jsx_runtime_1.jsxs)(react_2.HStack, { spacing: "0px", display: ["none", "flex"], mr: 2, children: [(0, jsx_runtime_1.jsx)(react_2.Text, { as: "div", sx: EditorStyles_1.styles.multiLineBox, children: (0, jsx_runtime_1.jsx)(react_2.Image, { sx: {
455
- h: "16px",
456
- w: "16px",
457
- cursor: "not-allowed",
458
- }, src: icons?.shift, alt: "info" }) }), (0, jsx_runtime_1.jsx)(react_2.Text, { as: "div", ml: 2, mr: 2, children: "+" }), (0, jsx_runtime_1.jsx)(react_2.Text, { as: "div", sx: EditorStyles_1.styles.multiLineBox, children: "Enter" })] })] }), (0, jsx_runtime_1.jsx)(react_2.Box, { sx: {
459
- height: "1px",
460
- backgroundColor: "#E0DBDB",
461
- width: "100%",
462
- opacity: shouldShowTopSection ? 1 : 0,
463
- // Smooth line transition
464
- transition: "opacity 0.2s ease-in-out",
465
- } })] }) }));
466
- }, [
467
- isMobile,
468
- shouldShowTopSection,
469
- isDisabled,
470
- icons?.shift,
471
- EditorStyles_1.styles.multiLineText,
472
- EditorStyles_1.styles.multiLineBox,
473
- ]);
474
- const LearningCreditsWarning = () => ((0, jsx_runtime_1.jsxs)(react_2.HStack, { sx: { opacity: "1", zIndex: 2, width: "100%" }, spacing: 3, justifyContent: "space-between", children: [(0, jsx_runtime_1.jsxs)(react_2.HStack, { spacing: 3, children: [icons?.info && ((0, jsx_runtime_1.jsx)(react_2.Image, { sx: {
475
- h: "28px",
476
- w: "28px",
477
- cursor: "not-allowed",
478
- color: "#D0392E",
479
- transform: "rotate(180deg)",
480
- }, src: icons?.info, alt: "info" })), (0, jsx_runtime_1.jsxs)(react_2.Text, { as: "div", sx: {
481
- ...EditorStyles_1.styles.multiLineText,
482
- ...EditorStyles_1.styles.multiLineRed,
483
- }, children: ["Since you do not have enough", " ", (0, jsx_runtime_1.jsx)(react_2.Text, { as: "span", sx: { ...EditorStyles_1.styles.multiLineBold }, children: "Learning Credits Vin wont be able to help you." })] })] }), icons?.submit && ((0, jsx_runtime_1.jsx)(react_2.Image, { "data-testid": "submit-icon", sx: {
484
- h: "48px",
485
- w: "48px",
486
- zIndex: 2,
487
- cursor: (0, common_utils_1.isEmptyOrNull)(data) ? "not-allowed" : "pointer",
488
- opacity: (0, common_utils_1.isEmptyOrNull)(data) ? 0.6 : 1,
489
- }, src: icons?.submit, alt: "submit", onClick: () => {
490
- if (!(0, common_utils_1.isEmptyOrNull)(data?.trim())) {
491
- handleSubmit();
492
- handleChange && handleChange("");
493
- }
494
- } }))] }));
495
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [props?.showerrorpopup && ((0, jsx_runtime_1.jsx)(InvalidSession_1.default, { handleClick: propHandleClick })), (0, jsx_runtime_1.jsx)(react_2.ChakraProvider, { theme: theme, children: (0, jsx_runtime_1.jsxs)(react_2.Box, { "data-testid": "studenteditor", w: "100%", borderRadius: "8px", p: "24px", border: showBottomBar ? "1px solid var(--Text-100, #BFBEDC)" : "none", pointerEvents: isDisabled ? "none" : "auto", opacity: tutorMode === false ? 1 : isDisabled ? 0.5 : 1, bg: isDisabledRevision
496
- ? "transparent"
497
- : tutorMode || (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment)
498
- ? "white"
499
- : "#F8F3D8", onMouseEnter: handleEditorMouseEnter, onMouseLeave: handleEditorMouseLeave, position: "relative", children: [TopSection, tutorMode && ((0, jsx_runtime_1.jsx)(slate_react_1.Slate, { editor: editor, initialValue: value, onChange: (newValue) => {
437
+ : "#F8F3D8", children: [(tutorMode || (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment)) && ((0, jsx_runtime_1.jsx)(slate_react_1.Slate, { editor: editor, initialValue: value, onChange: (newValue) => {
500
438
  setValue(newValue);
501
439
  handleChange && handleChange((0, slate_conversions_1.slateToText)(newValue));
502
- }, children: isMobile ? ((0, jsx_runtime_1.jsxs)(react_2.VStack, { spacing: 0, alignItems: "stretch", width: "100%", children: [(0, jsx_runtime_1.jsx)(react_2.Box, { ref: editorRef, onClick: handleClick, sx: {
503
- position: "relative",
504
- minH: "0px",
505
- maxH: height ?? "200px",
506
- overflow: "auto",
507
- cursor: "text",
440
+ }, children: (0, jsx_runtime_1.jsxs)(StackWrapper, { spacing: 0, alignItems: isMobile ? "stretch" : "flex-end", width: "100%", children: [(0, jsx_runtime_1.jsx)(EditorComponent_1.EditorBox, { ...editorBoxProps }), isMobile && ((0, jsx_runtime_1.jsx)(react_2.Box, { sx: {
441
+ height: "1px",
442
+ backgroundColor: "#E0DBDB",
508
443
  width: "100%",
509
- }, children: (0, jsx_runtime_1.jsx)(react_2.chakra.div, { sx: {
510
- "[data-slate-placeholder]": {
511
- display: isDisabled || isFocused
512
- ? "none !important"
513
- : "inline-block !important",
514
- color: "black !important",
515
- pointerEvents: "none !important",
516
- fontWeight: "400 !important",
517
- fontSize: "16px !important",
518
- top: "0px !important",
519
- left: "4px !important",
520
- position: "absolute !important",
521
- // width: "calc(100% - 8px) !important",
522
- lineHeight: "1.5 !important",
523
- whiteSpace: "pre-wrap !important",
524
- },
525
- }, children: (0, jsx_runtime_1.jsx)(slate_react_1.Editable, { "data-testid": "input-editor", renderElement: renderElement, placeholder: showBottomBar
526
- ? isRevision
527
- ? "Write your answer first — that's where real learning happens."
528
- : "Ask Vin any question, use voice, or upload your work!"
529
- : "", readOnly: isDisabled, onKeyDown: handleKeyDown, onPaste: handlePaste, onCopy: handleCopy, onCut: handleCut, onFocus: handleFocus, onBlur: handleBlur, onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragStart: handleDragStart, draggable: false, style: {
530
- position: "relative",
531
- // outline: "none",
532
- minHeight: "50px",
533
- zIndex: 1,
534
- cursor: isDisabled ? "not-allowed" : "text",
535
- userSelect: isDisabled ? "none" : "auto",
536
- pointerEvents: isDisabled ? "none" : "auto",
537
- paddingLeft: "4px",
538
- overflow: "auto",
539
- "&::-webkit-scrollbar": {
540
- width: "0px",
541
- height: "0px",
542
- },
543
- scrollbarWidth: "none",
544
- } }) }) }), isMobile && MobileBottomIcons] })) : (
545
- /* Desktop Layout (original) */
546
- (0, jsx_runtime_1.jsxs)(react_2.HStack, { spacing: 0, alignItems: "flex-end", children: [(0, jsx_runtime_1.jsx)(react_2.Box, { ref: editorRef, onClick: handleClick, flex: 1, sx: {
547
- position: "relative",
548
- minH: "0px",
549
- maxH: height ?? "200px",
550
- overflow: "auto",
551
- cursor: "text",
552
444
  mt: 2,
553
- pt: shouldShowTopSection ? "60px" : "0px",
554
- // Add smooth padding transition
555
- transition: "padding-top 0.3s ease-in-out",
556
- }, children: (0, jsx_runtime_1.jsx)(react_2.chakra.div, { sx: {
557
- "[data-slate-placeholder]": {
558
- display: isDisabled || isFocused
559
- ? "none !important"
560
- : "inline-block !important",
561
- color: "black !important",
562
- pointerEvents: "none !important",
563
- fontWeight: "400 !important",
564
- fontSize: "16px !important",
565
- position: "absolute !important",
566
- // Position at top of container
567
- top: "0px !important",
568
- left: "4px !important",
569
- // Add smooth placeholder transitions
570
- // transition: "all 0.2s ease-in-out !important",
571
- },
572
- }, children: (0, jsx_runtime_1.jsx)(slate_react_1.Editable, { "data-testid": "input-editor", renderElement: renderElement, placeholder: showBottomBar
573
- ? isRevision
574
- ? "Write your answer first — that's where real learning happens."
575
- : "Ask Vin any question, use voice, or upload your work!"
576
- : "", readOnly: isDisabled, onKeyDown: handleKeyDown, onPaste: handlePaste, onCopy: handleCopy, onCut: handleCut, onFocus: handleFocus, onBlur: handleBlur, onDrop: handleDrop, onDragOver: handleDragOver, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragStart: handleDragStart, draggable: false, style: {
577
- position: "relative",
578
- outline: "none",
579
- minHeight: "50px",
580
- zIndex: 1,
581
- cursor: isDisabled ? "not-allowed" : "text",
582
- pointerEvents: isDisabled ? "none" : "auto",
583
- paddingLeft: "4px",
584
- width: "100%",
585
- display: "block",
586
- overflow: "auto",
587
- "&::-webkit-scrollbar": {
588
- width: "0px",
589
- height: "0px",
590
- },
591
- scrollbarWidth: "none",
592
- } }) }) }), (0, jsx_runtime_1.jsxs)(react_2.HStack, { justifyContent: "flex-end", position: "relative", ml: 2, userSelect: "none", spacing: 5, children: [(tutorMode ||
593
- (!tutorMode && taskType === LearningPathUtils_1.taskTypes.assessment) ||
594
- isDisabledRevision) && ((0, jsx_runtime_1.jsxs)(react_2.HStack, { sx: { opacity: "1", zIndex: 2 }, spacing: 5, children: [icons?.formula && ((0, jsx_runtime_1.jsx)(react_2.Image, { sx: {
595
- h: "28px",
596
- w: "28px",
597
- cursor: isDisabled ? "not-allowed" : "pointer",
598
- }, src: icons?.formula, alt: "Add formula", onClick: () => {
599
- !isDisabled && openMathEditor();
600
- } })), addImageRender && addImageRender()] })), icons?.submit && ((0, jsx_runtime_1.jsx)(react_2.Image, { "data-testid": "submit-icon", sx: {
601
- h: "48px",
602
- w: "48px",
603
- zIndex: 2,
604
- cursor: (0, common_utils_1.isEmptyOrNull)(data)
605
- ? "not-allowed"
606
- : "pointer",
607
- opacity: (0, common_utils_1.isEmptyOrNull)(data) ? 0.6 : 1,
608
- }, src: icons?.submit, alt: "submit", onClick: () => {
609
- if (!(0, common_utils_1.isEmptyOrNull)(data?.trim())) {
610
- handleSubmit();
611
- handleChange && handleChange("");
612
- }
613
- } }))] })] })) })), !tutorMode && taskType !== LearningPathUtils_1.taskTypes.assessment && !isRevision && ((0, jsx_runtime_1.jsx)(LearningCreditsWarning, {})), (0, jsx_runtime_1.jsx)(MathModal_1.default, { isOpen: isModalOpen, onClose: handleModalClose, onSave: handleSaveMath, initialLatex: currentLatex, subject: props.subject })] }) })] }));
445
+ mb: 2,
446
+ } })), (0, jsx_runtime_1.jsx)(IconsComponent, { ...iconProps, isDisabledRevision: !isMobile ? isDisabledRevision : "" })] }) })), !tutorMode && taskType !== LearningPathUtils_1.taskTypes.assessment && !isRevision && ((0, jsx_runtime_1.jsx)(EditorComponent_1.LearningCreditsWarning, { icons: icons, data: data, handleSubmit: handleSubmit, handleChange: handleChange })), (0, jsx_runtime_1.jsx)(MathModal_1.default, { isOpen: isModalOpen, onClose: handleModalClose, onSave: handleSaveMath, initialLatex: currentLatex, subject: props.subject })] }) })] }));
614
447
  };
615
448
  exports.default = TextEditor;
616
449
  //# sourceMappingURL=TextEditor.js.map