@baasix/lexical 0.0.10 → 0.0.11

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/index.js CHANGED
@@ -57,11 +57,11 @@ import "./chunk-PZ5AY32C.js";
57
57
 
58
58
  // src/LexicalEditor.tsx
59
59
  import {
60
- useCallback as useCallback30,
60
+ useCallback as useCallback31,
61
61
  useEffect as useEffect48,
62
62
  useMemo as useMemo24,
63
- useRef as useRef18,
64
- useState as useState43
63
+ useRef as useRef20,
64
+ useState as useState44
65
65
  } from "react";
66
66
  import { LexicalComposer as LexicalComposer2 } from "@lexical/react/LexicalComposer";
67
67
  import { OnChangePlugin as OnChangePlugin2 } from "@lexical/react/LexicalOnChangePlugin";
@@ -87,7 +87,7 @@ import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin
87
87
  import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
88
88
  import { useLexicalEditable as useLexicalEditable10 } from "@lexical/react/useLexicalEditable";
89
89
  import { CAN_USE_DOM } from "@lexical/utils";
90
- import { useEffect as useEffect47, useState as useState42 } from "react";
90
+ import { useEffect as useEffect47, useState as useState43 } from "react";
91
91
 
92
92
  // src/plugins/ActionsPlugin/index.tsx
93
93
  import { $createCodeNode, $isCodeNode } from "@lexical/code";
@@ -6234,7 +6234,7 @@ import {
6234
6234
  $isRangeSelection as $isRangeSelection7,
6235
6235
  FORMAT_ELEMENT_COMMAND
6236
6236
  } from "lexical";
6237
- import { useCallback as useCallback22, useMemo as useMemo18, useState as useState30 } from "react";
6237
+ import { useCallback as useCallback23, useMemo as useMemo18, useState as useState31 } from "react";
6238
6238
  import * as ReactDOM2 from "react-dom";
6239
6239
 
6240
6240
  // src/plugins/DateTimePlugin/index.tsx
@@ -7646,7 +7646,7 @@ function PageBreakPlugin() {
7646
7646
  import { useLexicalComposerContext as useLexicalComposerContext21 } from "@lexical/react/LexicalComposerContext";
7647
7647
  import { $insertNodeToNearestRoot as $insertNodeToNearestRoot7 } from "@lexical/utils";
7648
7648
  import { COMMAND_PRIORITY_EDITOR as COMMAND_PRIORITY_EDITOR13, createCommand as createCommand13 } from "lexical";
7649
- import { useCallback as useCallback12, useEffect as useEffect23, useMemo as useMemo8, useState as useState18 } from "react";
7649
+ import { useCallback as useCallback12, useEffect as useEffect23, useMemo as useMemo8, useRef as useRef9, useState as useState18 } from "react";
7650
7650
 
7651
7651
  // src/nodes/NotesNode.tsx
7652
7652
  import { $getNodeByKey as $getNodeByKey4 } from "lexical";
@@ -7942,34 +7942,68 @@ function convertNotes(input) {
7942
7942
  const doc = parser.parseFromString(input, "text/html");
7943
7943
  html += Array.from(doc.body.childNodes).map(processNode).join("");
7944
7944
  } else {
7945
- const paragraphs = input.split(/\n\s*\n/);
7946
7945
  const style = CARD_STYLES.notes;
7947
- paragraphs.forEach((p) => {
7948
- p = p.trim();
7949
- if (!p) return;
7950
- if (p.match(/^[-•*]/) || p.match(/^\d+\./)) {
7951
- const items = p.split(/\n/).map((l) => l.trim()).filter((l) => l);
7952
- const isOrdered = p.match(/^\d+\./);
7953
- const tag = isOrdered ? "ol" : "ul";
7954
- html += ` <${tag} style="margin-left: 20px; padding-left: 20px; margin-bottom: 15px;">
7946
+ const lines = input.split("\n");
7947
+ let inList = null;
7948
+ const closeList = () => {
7949
+ if (inList) {
7950
+ html += ` </${inList}>
7955
7951
  `;
7956
- items.forEach((item) => {
7957
- const cleanItem = item.replace(/^([-•*]|\d+\.)\s*/, "");
7958
- if (cleanItem) {
7959
- html += ` <li style="margin-bottom: 5px;">${cleanItem}</li>
7952
+ inList = null;
7953
+ }
7954
+ };
7955
+ const isBullet = (line) => /^[\s]*[-•*]\s/.test(line);
7956
+ const isOrdered = (line) => /^[\s]*\d+[.)]\s/.test(line);
7957
+ const isHeading = (line) => {
7958
+ const t = line.trim();
7959
+ if (t.length > 120 || t.length < 2) return false;
7960
+ if (t.endsWith(".") || t.endsWith(",")) return false;
7961
+ if (isBullet(t) || isOrdered(t)) return false;
7962
+ if (t.endsWith(":")) return true;
7963
+ if (t.length < 80 && !/[.!?,;]$/.test(t)) return true;
7964
+ return false;
7965
+ };
7966
+ for (let i = 0; i < lines.length; i++) {
7967
+ const line = lines[i];
7968
+ const trimmed = line.trim();
7969
+ if (!trimmed) {
7970
+ closeList();
7971
+ continue;
7972
+ }
7973
+ if (isBullet(trimmed)) {
7974
+ if (inList !== "ul") {
7975
+ closeList();
7976
+ inList = "ul";
7977
+ html += ` <ul style="margin-left: 20px; padding-left: 20px; margin-bottom: 15px;">
7960
7978
  `;
7961
- }
7962
- });
7963
- html += ` </${tag}>
7979
+ }
7980
+ const cleanItem = trimmed.replace(/^[-•*]\s*/, "");
7981
+ html += ` <li style="margin-bottom: 5px;">${cleanItem}</li>
7964
7982
  `;
7965
- } else if (p.length < 100 && !p.endsWith(".")) {
7966
- html += ` <h3 style="color: ${style.headingColor}; border-bottom: 2px solid ${style.headingBorder}; padding-bottom: 5px; margin-top: 25px; margin-bottom: 15px;">${p}</h3>
7983
+ continue;
7984
+ }
7985
+ if (isOrdered(trimmed)) {
7986
+ if (inList !== "ol") {
7987
+ closeList();
7988
+ inList = "ol";
7989
+ html += ` <ol style="margin-left: 20px; padding-left: 20px; margin-bottom: 15px;">
7967
7990
  `;
7968
- } else {
7969
- html += ` <p style="margin-bottom: 15px;">${p}</p>
7991
+ }
7992
+ const cleanItem = trimmed.replace(/^\d+[.)]\s*/, "");
7993
+ html += ` <li style="margin-bottom: 5px;">${cleanItem}</li>
7970
7994
  `;
7995
+ continue;
7971
7996
  }
7972
- });
7997
+ closeList();
7998
+ if (isHeading(trimmed)) {
7999
+ html += ` <h3 style="color: ${style.headingColor}; border-bottom: 2px solid ${style.headingBorder}; padding-bottom: 5px; margin-top: 25px; margin-bottom: 15px;">${trimmed}</h3>
8000
+ `;
8001
+ continue;
8002
+ }
8003
+ html += ` <p style="margin-bottom: 15px;">${trimmed}</p>
8004
+ `;
8005
+ }
8006
+ closeList();
7973
8007
  }
7974
8008
  html += "</div>";
7975
8009
  return compactHtml(html);
@@ -8133,7 +8167,7 @@ function convertTextCards(input) {
8133
8167
  const c = styles[key];
8134
8168
  html += ` <div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px; border-radius: 12px; min-height: 120px;">
8135
8169
  <h3 style="margin-top: 0; color: inherit; font-size: 14px;">${c.emoji} ${c.number}. ${c.title}</h3>
8136
- <p style="margin: 0; font-size: 13px;">${content}</p>
8170
+ <p style="margin: 0; font-size: 13px;">${nl2br(content)}</p>
8137
8171
  </div>
8138
8172
  `;
8139
8173
  });
@@ -8239,8 +8273,8 @@ var QUESTIONS_CARD_GRID_SECTIONS = [
8239
8273
  "tips"
8240
8274
  ];
8241
8275
  var QUESTIONS_SECTION_PATTERNS = {
8242
- question: /^Q\d+\./i,
8243
- answer: /^Answer:\s*$/i,
8276
+ question: /^(\d+\.\s*)?Q(uestion|\d+)\s*[\s.:]/i,
8277
+ answer: /^(Model\s+)?Answer:\s*/i,
8244
8278
  rubric: /^(\d+\.\s*)?MARKING\s+RUBRIC/i,
8245
8279
  mnemonics: /^(\d+\.\s*)?MNEMONIC/i,
8246
8280
  examiner: /^(\d+\.\s*)?EXAMINER/i,
@@ -8251,103 +8285,244 @@ var QUESTIONS_SECTION_PATTERNS = {
8251
8285
  variations: /^(\d+\.\s*)?EXAM\s+VARIATION/i,
8252
8286
  tips: /^(\d+\.\s*)?(HIGH-YIELD|EXAM\s+TIP)/i
8253
8287
  };
8288
+ function formatMcqQuestion(text) {
8289
+ const optionMatch = text.match(/\s+[a-eA-E][)]\s/);
8290
+ if (!optionMatch || optionMatch.index === void 0) return text;
8291
+ const questionPart = text.substring(0, optionMatch.index).trim();
8292
+ const optionsPart = text.substring(optionMatch.index).trim();
8293
+ const options = optionsPart.split(/(?=\s*[a-eA-E][)]\s)/).map((o) => o.trim()).filter(Boolean);
8294
+ if (options.length < 2) return text;
8295
+ let optionsHtml = '<div style="margin-top: 10px; display: flex; flex-direction: column; gap: 6px;">';
8296
+ options.forEach((opt) => {
8297
+ const letter = opt.charAt(0).toUpperCase();
8298
+ const optText = opt.replace(/^[a-eA-E][)]\s*/, "").trim();
8299
+ optionsHtml += `<div style="display: flex; align-items: baseline; gap: 8px;">
8300
+ <span style="background: rgba(0,0,0,0.08); border-radius: 4px; padding: 2px 8px; font-weight: 600; font-size: 13px; min-width: 24px; text-align: center;">${letter}</span>
8301
+ <span style="font-size: 14px;">${optText}</span>
8302
+ </div>`;
8303
+ });
8304
+ optionsHtml += "</div>";
8305
+ return `${questionPart}${optionsHtml}`;
8306
+ }
8307
+ function formatMcqAnswer(text) {
8308
+ const match = text.match(/^([a-eA-E])[)]\s*/);
8309
+ if (!match) return text;
8310
+ const letter = match[1].toUpperCase();
8311
+ const explanation = text.substring(match[0].length).trim();
8312
+ return `<span style="background: rgba(76, 175, 80, 0.15); border: 1px solid rgba(76, 175, 80, 0.4); border-radius: 4px; padding: 2px 8px; font-weight: 700; font-size: 14px; margin-right: 8px;">${letter}</span> ${explanation}`;
8313
+ }
8314
+ function nl2br(text) {
8315
+ return text.replace(/\n/g, "<br>");
8316
+ }
8254
8317
  function convertQuestionsCards(input) {
8255
8318
  if (!input.trim()) return "";
8256
- const sections = parseQuestionsInput(input);
8319
+ const parsed = parseQuestionsInput(input);
8257
8320
  const styles = CARD_STYLES.questionsCards;
8258
8321
  let html = "";
8259
- if (sections.question) {
8260
- const c = styles.question;
8261
- html += `<div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px 20px; border-radius: 12px; margin-bottom: 20px;">
8262
- <h3 style="margin: 0; color: inherit;">${c.emoji} Question</h3>
8263
- <p style="margin-top: 8px; color: inherit;">${sections.question}</p>
8322
+ parsed.qaPairs.forEach((qa, idx) => {
8323
+ if (qa.question) {
8324
+ const c = styles.question;
8325
+ const qLabel = parsed.qaPairs.length > 1 ? `Question ${idx + 1}` : "Question";
8326
+ const formattedQ = formatMcqQuestion(nl2br(qa.question));
8327
+ html += `<div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px 20px; border-radius: 12px; margin-bottom: 20px;">
8328
+ <h3 style="margin: 0; color: inherit;">${c.emoji} ${qLabel}</h3>
8329
+ <div style="margin-top: 8px; color: inherit;">${formattedQ}</div>
8264
8330
  </div>
8265
8331
  `;
8266
- }
8267
- if (sections.answer) {
8268
- const c = styles.answer;
8269
- html += `<div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px 20px; border-radius: 12px; margin-bottom: 20px;">
8332
+ }
8333
+ if (qa.answer) {
8334
+ const c = styles.answer;
8335
+ const formattedA = formatMcqAnswer(nl2br(qa.answer));
8336
+ html += `<div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px 20px; border-radius: 12px; margin-bottom: 20px;">
8270
8337
  <h3 style="margin-top: 0; color: inherit;">${c.emoji} ${c.title}</h3>
8271
- <p>${sections.answer}</p>
8338
+ <p>${formattedA}</p>
8272
8339
  </div>
8273
8340
  `;
8274
- }
8275
- const hasGridCards = QUESTIONS_CARD_GRID_SECTIONS.some((k) => sections[k]);
8276
- if (hasGridCards) {
8277
- html += `<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-top: 20px;">
8341
+ }
8342
+ const qaSections = qa.sections || {};
8343
+ const hasGridCards = QUESTIONS_CARD_GRID_SECTIONS.some((k) => qaSections[k]);
8344
+ if (hasGridCards) {
8345
+ html += `<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-top: 8px; margin-bottom: 24px;">
8278
8346
  `;
8279
- QUESTIONS_CARD_GRID_SECTIONS.forEach((key) => {
8280
- const content = sections[key];
8281
- if (!content) return;
8282
- const c = styles[key];
8283
- html += ` <div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px; border-radius: 12px; min-height: 120px;">
8347
+ QUESTIONS_CARD_GRID_SECTIONS.forEach((key) => {
8348
+ const content = qaSections[key];
8349
+ if (!content) return;
8350
+ const c = styles[key];
8351
+ html += ` <div style="background: ${c.light}; border: 2px solid ${c.border}; border-left: 4px solid ${c.border}; padding: 16px; border-radius: 12px; min-height: 120px;">
8284
8352
  <h3 style="margin-top: 0; color: inherit; font-size: 14px;">${c.emoji} ${c.number}. ${c.title}</h3>
8285
- <p style="margin: 0; font-size: 13px;">${content}</p>
8353
+ <p style="margin: 0; font-size: 13px;">${nl2br(content)}</p>
8286
8354
  </div>
8287
8355
  `;
8288
- });
8289
- html += "</div>\n";
8290
- }
8356
+ });
8357
+ html += "</div>\n";
8358
+ }
8359
+ });
8291
8360
  return compactHtml(html);
8292
8361
  }
8362
+ var INLINE_ANSWER_PATTERNS = [
8363
+ /\s+Correct\s+Answer:\s*/i,
8364
+ /\s+Model\s+Answer:\s*/i
8365
+ ];
8366
+ var MCQ_LINE_PATTERN = /^\d+[.)]\s+/;
8293
8367
  function parseQuestionsInput(input) {
8294
8368
  const lines = input.split("\n").filter((l) => l.trim());
8295
- const sections = {};
8369
+ const result = { qaPairs: [] };
8296
8370
  let currentSection = null;
8297
8371
  let contentBuffer = [];
8298
- const flush = () => {
8372
+ let currentQA = { question: "", answer: "", sections: {} };
8373
+ let inQASection = null;
8374
+ const flushQA = () => {
8375
+ if (inQASection === "question") {
8376
+ currentQA.question = contentBuffer.join("\n").trim();
8377
+ } else if (inQASection === "answer") {
8378
+ currentQA.answer = contentBuffer.join("\n").trim();
8379
+ }
8380
+ contentBuffer = [];
8381
+ };
8382
+ const flushSection = () => {
8299
8383
  if (currentSection && contentBuffer.length > 0) {
8300
- sections[currentSection] = contentBuffer.join(" ").trim();
8384
+ currentQA.sections[currentSection] = contentBuffer.join("\n").trim();
8301
8385
  }
8302
8386
  contentBuffer = [];
8303
8387
  };
8388
+ const pushCurrentQA = () => {
8389
+ if (currentQA.question || currentQA.answer || Object.keys(currentQA.sections).length > 0) {
8390
+ result.qaPairs.push({ ...currentQA, sections: { ...currentQA.sections } });
8391
+ currentQA = { question: "", answer: "", sections: {} };
8392
+ }
8393
+ };
8394
+ const trySplitInline = (line) => {
8395
+ for (const pattern of INLINE_ANSWER_PATTERNS) {
8396
+ const match = line.match(pattern);
8397
+ if (match && match.index !== void 0) {
8398
+ return {
8399
+ question: line.substring(0, match.index).trim(),
8400
+ answer: line.substring(match.index + match[0].length).trim()
8401
+ };
8402
+ }
8403
+ }
8404
+ return null;
8405
+ };
8304
8406
  for (const line of lines) {
8305
8407
  const trimmed = line.trim();
8408
+ if (QUESTIONS_SECTION_PATTERNS.question.test(trimmed)) {
8409
+ if (inQASection) flushQA();
8410
+ if (currentSection) {
8411
+ flushSection();
8412
+ currentSection = null;
8413
+ }
8414
+ pushCurrentQA();
8415
+ const qText = trimmed.replace(/^(\d+\.\s*)?Q(uestion|\d+)\s*[\s.:]+/i, "").trim();
8416
+ const inlineSplit = trySplitInline(qText);
8417
+ if (inlineSplit) {
8418
+ currentQA = { question: inlineSplit.question, answer: inlineSplit.answer, sections: {} };
8419
+ inQASection = null;
8420
+ } else {
8421
+ inQASection = "question";
8422
+ if (qText) contentBuffer.push(qText);
8423
+ }
8424
+ continue;
8425
+ }
8426
+ if (QUESTIONS_SECTION_PATTERNS.answer.test(trimmed)) {
8427
+ if (inQASection) flushQA();
8428
+ if (currentSection) {
8429
+ flushSection();
8430
+ currentSection = null;
8431
+ }
8432
+ inQASection = "answer";
8433
+ const aText = trimmed.replace(/^(Model\s+)?Answer:\s*/i, "").trim();
8434
+ if (aText) contentBuffer.push(aText);
8435
+ continue;
8436
+ }
8437
+ if (MCQ_LINE_PATTERN.test(trimmed) && !QUESTIONS_SECTION_PATTERNS.question.test(trimmed)) {
8438
+ const inlineSplit = trySplitInline(trimmed);
8439
+ if (inlineSplit) {
8440
+ if (inQASection) flushQA();
8441
+ if (currentSection) {
8442
+ flushSection();
8443
+ currentSection = null;
8444
+ }
8445
+ pushCurrentQA();
8446
+ const qText = inlineSplit.question.replace(/^\d+[.)]\s*/, "").trim();
8447
+ currentQA = { question: qText, answer: inlineSplit.answer, sections: {} };
8448
+ inQASection = null;
8449
+ continue;
8450
+ }
8451
+ }
8306
8452
  let foundSection = false;
8307
8453
  for (const [key, pattern] of Object.entries(QUESTIONS_SECTION_PATTERNS)) {
8454
+ if (key === "question" || key === "answer") continue;
8308
8455
  if (pattern.test(trimmed)) {
8309
- flush();
8456
+ if (inQASection) {
8457
+ flushQA();
8458
+ inQASection = null;
8459
+ }
8460
+ if (currentSection) flushSection();
8310
8461
  currentSection = key;
8311
8462
  foundSection = true;
8312
- if (key === "question") {
8313
- const qText = trimmed.replace(/^Q\d+\.\s*/, "").trim();
8314
- if (qText) contentBuffer.push(qText);
8315
- }
8316
8463
  break;
8317
8464
  }
8318
8465
  }
8319
8466
  if (foundSection) continue;
8320
- if (currentSection) {
8321
- contentBuffer.push(trimmed);
8322
- }
8467
+ contentBuffer.push(trimmed);
8323
8468
  }
8324
- flush();
8325
- return sections;
8469
+ if (inQASection) flushQA();
8470
+ if (currentSection) flushSection();
8471
+ pushCurrentQA();
8472
+ return result;
8326
8473
  }
8327
8474
  function parseQuestionsCardsHtml(html) {
8328
8475
  const parser = new DOMParser();
8329
8476
  const doc = parser.parseFromString(html, "text/html");
8330
8477
  const result = {
8331
- question: "",
8332
- answer: "",
8333
- sections: []
8478
+ qaPairs: []
8334
8479
  };
8335
8480
  const styles = CARD_STYLES.questionsCards;
8336
8481
  const gridEntries = QUESTIONS_CARD_GRID_SECTIONS.map((k) => ({ key: k, title: styles[k].title }));
8482
+ let currentQA = null;
8337
8483
  const children = Array.from(doc.body.children);
8338
8484
  for (const el of children) {
8339
8485
  const h3 = el.querySelector("h3");
8340
8486
  if (!h3) continue;
8341
8487
  const h3Text = (h3.textContent || "").trim();
8342
8488
  if (h3Text.includes("Question")) {
8489
+ if (currentQA) result.qaPairs.push(currentQA);
8490
+ currentQA = { question: "", answer: "", sections: [] };
8343
8491
  const clone = el.cloneNode(true);
8344
8492
  clone.querySelector("h3")?.remove();
8345
- result.question = (clone.textContent || "").trim();
8493
+ const optionsContainer = clone.querySelector('div[style*="flex-direction"]');
8494
+ if (optionsContainer) {
8495
+ const optionDivs = optionsContainer.querySelectorAll("div");
8496
+ const options = [];
8497
+ optionDivs.forEach((optDiv) => {
8498
+ const spans = optDiv.querySelectorAll("span");
8499
+ if (spans.length >= 2) {
8500
+ const letter = (spans[0].textContent || "").trim().toLowerCase();
8501
+ const text = (spans[1].textContent || "").trim();
8502
+ options.push(`${letter}) ${text}`);
8503
+ }
8504
+ });
8505
+ optionsContainer.remove();
8506
+ const qText = (clone.textContent || "").trim();
8507
+ currentQA.question = qText + (options.length > 0 ? " " + options.join(" ") : "");
8508
+ } else {
8509
+ currentQA.question = (clone.textContent || "").trim();
8510
+ }
8346
8511
  } else if (h3Text.includes("Answer")) {
8512
+ if (!currentQA) currentQA = { question: "", answer: "", sections: [] };
8347
8513
  const clone = el.cloneNode(true);
8348
8514
  clone.querySelector("h3")?.remove();
8349
- result.answer = (clone.textContent || "").trim();
8515
+ const badge = clone.querySelector('span[style*="rgba(76"]');
8516
+ if (badge) {
8517
+ const letter = (badge.textContent || "").trim().toLowerCase();
8518
+ badge.remove();
8519
+ const explanation = (clone.textContent || "").trim();
8520
+ currentQA.answer = `${letter}) ${explanation}`;
8521
+ } else {
8522
+ currentQA.answer = (clone.textContent || "").trim();
8523
+ }
8350
8524
  } else if (el.children.length > 1) {
8525
+ if (!currentQA) currentQA = { question: "", answer: "", sections: [] };
8351
8526
  for (const card of Array.from(el.children)) {
8352
8527
  const cardH3 = card.querySelector("h3");
8353
8528
  if (!cardH3) continue;
@@ -8356,10 +8531,14 @@ function parseQuestionsCardsHtml(html) {
8356
8531
  const key = match ? match.key : "rubric";
8357
8532
  const clone = card.cloneNode(true);
8358
8533
  clone.querySelector("h3")?.remove();
8359
- result.sections.push({ key, content: (clone.textContent || "").trim() });
8534
+ currentQA.sections.push({ key, content: (clone.textContent || "").trim() });
8360
8535
  }
8361
8536
  }
8362
8537
  }
8538
+ if (currentQA) result.qaPairs.push(currentQA);
8539
+ if (result.qaPairs.length === 0) {
8540
+ result.qaPairs.push({ question: "", answer: "", sections: [] });
8541
+ }
8363
8542
  return result;
8364
8543
  }
8365
8544
 
@@ -8569,27 +8748,95 @@ function NotesPlugin() {
8569
8748
  }, [editor]);
8570
8749
  return null;
8571
8750
  }
8751
+ function convertRichHtmlToNotes(htmlStr, baasixClient, folder) {
8752
+ return new Promise(async (resolve) => {
8753
+ const parser = new DOMParser();
8754
+ const doc = parser.parseFromString(htmlStr, "text/html");
8755
+ if (baasixClient) {
8756
+ const imgs = doc.querySelectorAll("img");
8757
+ for (let i = 0; i < imgs.length; i++) {
8758
+ const img2 = imgs[i];
8759
+ const src = img2.getAttribute("src") || "";
8760
+ if (src.startsWith("data:")) {
8761
+ try {
8762
+ const resp = await fetch(src);
8763
+ const blob = await resp.blob();
8764
+ const ext = blob.type.split("/")[1] || "png";
8765
+ const file = new File([blob], `note-image-${i}.${ext}`, { type: blob.type });
8766
+ const uploadedUrl = await uploadImageToBaasix(baasixClient, file, folder);
8767
+ img2.setAttribute("src", uploadedUrl);
8768
+ } catch {
8769
+ }
8770
+ }
8771
+ }
8772
+ }
8773
+ let html = `<div style="font-family: sans-serif; line-height: 1.6; color: inherit;">`;
8774
+ const children = Array.from(doc.body.childNodes);
8775
+ for (const child of children) {
8776
+ html += processNode(child);
8777
+ }
8778
+ html += "</div>";
8779
+ resolve(html.replace(/>\s+</g, "><"));
8780
+ });
8781
+ }
8572
8782
  function InsertNotesDialog({
8573
8783
  activeEditor,
8574
8784
  onClose
8575
8785
  }) {
8576
8786
  const [input, setInput] = useState18("");
8577
- const preview = useMemo8(() => {
8787
+ const [richHtml, setRichHtml] = useState18("");
8788
+ const [isUploading, setIsUploading] = useState18(false);
8789
+ const pasteAreaRef = useRef9(null);
8790
+ let editorConfig = null;
8791
+ try {
8792
+ editorConfig = useEditorConfig();
8793
+ } catch {
8794
+ }
8795
+ const handleRichPaste = useCallback12(async (e) => {
8796
+ e.preventDefault();
8797
+ const clipboardData = e.clipboardData;
8798
+ const htmlData = clipboardData.getData("text/html");
8799
+ const textData = clipboardData.getData("text/plain");
8800
+ if (htmlData) {
8801
+ setIsUploading(true);
8802
+ try {
8803
+ const processed = await convertRichHtmlToNotes(
8804
+ htmlData,
8805
+ editorConfig?.baasixClient,
8806
+ editorConfig?.folder
8807
+ );
8808
+ setRichHtml(processed);
8809
+ setInput("");
8810
+ } finally {
8811
+ setIsUploading(false);
8812
+ }
8813
+ } else if (textData) {
8814
+ setInput((prev) => prev ? prev + "\n" + textData : textData);
8815
+ }
8816
+ if (pasteAreaRef.current) {
8817
+ pasteAreaRef.current.innerHTML = '<span style="color: #9ca3af; pointer-events: none; user-select: none;">Paste from Word/Docs here (preserves formatting)</span>';
8818
+ }
8819
+ }, [editorConfig]);
8820
+ const finalHtml = useMemo8(() => {
8821
+ if (richHtml) return richHtml;
8578
8822
  if (!input.trim()) return "";
8579
8823
  return convertNotes(input);
8580
- }, [input]);
8824
+ }, [input, richHtml]);
8581
8825
  const handleInsert = useCallback12(() => {
8582
- if (!preview) return;
8583
- activeEditor.dispatchCommand(INSERT_NOTES_COMMAND, preview);
8826
+ if (!finalHtml) return;
8827
+ activeEditor.dispatchCommand(INSERT_NOTES_COMMAND, finalHtml);
8584
8828
  onClose();
8585
- }, [activeEditor, preview, onClose]);
8829
+ }, [activeEditor, finalHtml, onClose]);
8586
8830
  return /* @__PURE__ */ jsxs14("div", { style: { minWidth: 500 }, children: [
8587
8831
  /* @__PURE__ */ jsx24(
8588
8832
  "textarea",
8589
8833
  {
8590
8834
  value: input,
8591
- onChange: (e) => setInput(e.target.value),
8592
- placeholder: "Paste notes here...\nExample:\nSuperficial Fascia\nThe superficial fascia is a layer of loose...\n\nFunctions\n- Passageway for vessels\n- Insulation",
8835
+ onChange: (e) => {
8836
+ setInput(e.target.value);
8837
+ setRichHtml("");
8838
+ },
8839
+ placeholder: "Paste or type notes here (plain text)...\nExample:\nSuperficial Fascia\nThe superficial fascia is a layer of loose...\n\nFunctions\n- Passageway for vessels\n- Insulation",
8593
8840
  style: {
8594
8841
  width: "100%",
8595
8842
  minHeight: 120,
@@ -8603,9 +8850,33 @@ function InsertNotesDialog({
8603
8850
  }
8604
8851
  }
8605
8852
  ),
8606
- preview && /* @__PURE__ */ jsxs14("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 200, overflow: "auto" }, children: [
8853
+ /* @__PURE__ */ jsx24(
8854
+ "div",
8855
+ {
8856
+ ref: pasteAreaRef,
8857
+ contentEditable: true,
8858
+ onPaste: handleRichPaste,
8859
+ onMouseDown: (e) => e.stopPropagation(),
8860
+ style: {
8861
+ width: "100%",
8862
+ minHeight: 40,
8863
+ padding: 8,
8864
+ border: "2px dashed #93c5fd",
8865
+ borderRadius: 4,
8866
+ fontSize: 12,
8867
+ color: "#6b7280",
8868
+ marginBottom: 8,
8869
+ outline: "none",
8870
+ background: "#f0f7ff"
8871
+ },
8872
+ suppressContentEditableWarning: true,
8873
+ children: /* @__PURE__ */ jsx24("span", { style: { color: "#9ca3af", pointerEvents: "none", userSelect: "none" }, children: isUploading ? "Processing content..." : "Paste from Word/Docs here (preserves formatting)" })
8874
+ }
8875
+ ),
8876
+ richHtml && /* @__PURE__ */ jsx24("div", { style: { marginBottom: 8, fontSize: 11, color: "#16a34a" }, children: "Rich content captured (formatting preserved)" }),
8877
+ finalHtml && /* @__PURE__ */ jsxs14("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 200, overflow: "auto" }, children: [
8607
8878
  /* @__PURE__ */ jsx24("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
8608
- /* @__PURE__ */ jsx24("div", { dangerouslySetInnerHTML: { __html: preview } })
8879
+ /* @__PURE__ */ jsx24("div", { dangerouslySetInnerHTML: { __html: finalHtml } })
8609
8880
  ] }),
8610
8881
  /* @__PURE__ */ jsxs14("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
8611
8882
  /* @__PURE__ */ jsx24(
@@ -8622,9 +8893,9 @@ function InsertNotesDialog({
8622
8893
  {
8623
8894
  type: "button",
8624
8895
  onClick: handleInsert,
8625
- disabled: !preview,
8626
- style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
8627
- children: "Insert"
8896
+ disabled: !finalHtml || isUploading,
8897
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: finalHtml && !isUploading ? 1 : 0.5 },
8898
+ children: isUploading ? "Processing..." : "Insert"
8628
8899
  }
8629
8900
  )
8630
8901
  ] })
@@ -9310,7 +9581,7 @@ function InsertTerminologyDialog({
9310
9581
  import { useLexicalComposerContext as useLexicalComposerContext28 } from "@lexical/react/LexicalComposerContext";
9311
9582
  import { $insertNodeToNearestRoot as $insertNodeToNearestRoot10 } from "@lexical/utils";
9312
9583
  import { COMMAND_PRIORITY_EDITOR as COMMAND_PRIORITY_EDITOR17, createCommand as createCommand17 } from "lexical";
9313
- import { useCallback as useCallback18, useEffect as useEffect27, useMemo as useMemo14, useState as useState25 } from "react";
9584
+ import { useCallback as useCallback19, useEffect as useEffect27, useMemo as useMemo14, useState as useState26 } from "react";
9314
9585
 
9315
9586
  // src/nodes/TextCardsNode.tsx
9316
9587
  import { $getNodeByKey as $getNodeByKey7 } from "lexical";
@@ -9605,6 +9876,134 @@ function $isTextCardsNode(node) {
9605
9876
  return node instanceof TextCardsNode;
9606
9877
  }
9607
9878
 
9879
+ // src/utils/useRichPaste.ts
9880
+ import { useCallback as useCallback18, useRef as useRef10, useState as useState25 } from "react";
9881
+ function useRichPaste(onText, baasixClient, folder) {
9882
+ const [images, setImages] = useState25([]);
9883
+ const [isUploading, setIsUploading] = useState25(false);
9884
+ const pasteAreaRef = useRef10(null);
9885
+ const extractImages = useCallback18(
9886
+ async (htmlStr) => {
9887
+ const parser = new DOMParser();
9888
+ const doc = parser.parseFromString(htmlStr, "text/html");
9889
+ const imgs = doc.querySelectorAll("img");
9890
+ const newImages = [];
9891
+ for (let i = 0; i < imgs.length; i++) {
9892
+ const img2 = imgs[i];
9893
+ const src = img2.getAttribute("src") || "";
9894
+ const placeholder = `__IMG_${Date.now()}_${i}__`;
9895
+ if (src.startsWith("data:") && baasixClient) {
9896
+ try {
9897
+ const resp = await fetch(src);
9898
+ const blob = await resp.blob();
9899
+ const ext = blob.type.split("/")[1] || "png";
9900
+ const file = new File([blob], `pasted-image-${i}.${ext}`, { type: blob.type });
9901
+ const uploadedUrl = await uploadImageToBaasix(baasixClient, file, folder);
9902
+ newImages.push({ placeholder, src: uploadedUrl });
9903
+ } catch {
9904
+ newImages.push({ placeholder, src });
9905
+ }
9906
+ } else if (src) {
9907
+ newImages.push({ placeholder, src });
9908
+ }
9909
+ }
9910
+ return newImages;
9911
+ },
9912
+ [baasixClient, folder]
9913
+ );
9914
+ const insertPlaceholders = useCallback18(
9915
+ (plainText, htmlStr, imgPlaceholders) => {
9916
+ if (imgPlaceholders.length === 0) return plainText;
9917
+ const parser = new DOMParser();
9918
+ const doc = parser.parseFromString(htmlStr, "text/html");
9919
+ const segments = [];
9920
+ let imgIdx = 0;
9921
+ const blockTags = /* @__PURE__ */ new Set(["P", "DIV", "LI", "TR", "H1", "H2", "H3", "H4", "H5", "H6", "BLOCKQUOTE", "PRE", "TABLE"]);
9922
+ const walkNode = (node) => {
9923
+ if (node.nodeType === Node.TEXT_NODE) {
9924
+ const t = (node.textContent || "").trim();
9925
+ if (t) segments.push({ type: "text", text: t });
9926
+ return;
9927
+ }
9928
+ if (node.nodeType !== Node.ELEMENT_NODE) return;
9929
+ const el = node;
9930
+ if (el.tagName === "IMG") {
9931
+ segments.push({ type: "img", idx: imgIdx++ });
9932
+ return;
9933
+ }
9934
+ for (const child of Array.from(el.childNodes)) walkNode(child);
9935
+ };
9936
+ walkNode(doc.body);
9937
+ const textCountBeforeImg = [];
9938
+ let textCount = 0;
9939
+ for (const seg of segments) {
9940
+ if (seg.type === "text") {
9941
+ textCount++;
9942
+ } else {
9943
+ textCountBeforeImg.push(textCount);
9944
+ }
9945
+ }
9946
+ const lines = plainText.split("\n");
9947
+ const nonEmptyLineIndices = [];
9948
+ for (let i = 0; i < lines.length; i++) {
9949
+ if (lines[i].trim()) nonEmptyLineIndices.push(i);
9950
+ }
9951
+ for (let i = textCountBeforeImg.length - 1; i >= 0; i--) {
9952
+ const placeholder = imgPlaceholders[i]?.placeholder;
9953
+ if (!placeholder) continue;
9954
+ const tc = textCountBeforeImg[i];
9955
+ const lineIdx = tc > 0 && tc <= nonEmptyLineIndices.length ? nonEmptyLineIndices[tc - 1] : nonEmptyLineIndices.length > 0 ? nonEmptyLineIndices[nonEmptyLineIndices.length - 1] : lines.length - 1;
9956
+ lines.splice(lineIdx + 1, 0, placeholder);
9957
+ for (let j = 0; j < nonEmptyLineIndices.length; j++) {
9958
+ if (nonEmptyLineIndices[j] > lineIdx) nonEmptyLineIndices[j]++;
9959
+ }
9960
+ }
9961
+ return lines.join("\n");
9962
+ },
9963
+ []
9964
+ );
9965
+ const handlePaste = useCallback18(
9966
+ async (e) => {
9967
+ e.preventDefault();
9968
+ const clipboardData = e.clipboardData;
9969
+ const htmlData = clipboardData.getData("text/html");
9970
+ const textData = clipboardData.getData("text/plain");
9971
+ if (htmlData && htmlData.includes("<img")) {
9972
+ setIsUploading(true);
9973
+ try {
9974
+ const processedImages = await extractImages(htmlData);
9975
+ let text = textData || "";
9976
+ text = insertPlaceholders(text, htmlData, processedImages);
9977
+ onText(text);
9978
+ setImages((prev) => [...prev, ...processedImages]);
9979
+ } finally {
9980
+ setIsUploading(false);
9981
+ }
9982
+ } else {
9983
+ onText(textData || "");
9984
+ }
9985
+ if (pasteAreaRef.current) {
9986
+ pasteAreaRef.current.textContent = "";
9987
+ }
9988
+ },
9989
+ [extractImages, insertPlaceholders, onText]
9990
+ );
9991
+ const replaceImagePlaceholders = useCallback18(
9992
+ (html) => {
9993
+ let result = html;
9994
+ images.forEach(({ placeholder, src }) => {
9995
+ result = result.replace(
9996
+ new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
9997
+ `<img src="${src}" style="max-width: 100%; border-radius: 8px; margin: 8px 0;" />`
9998
+ );
9999
+ });
10000
+ return result;
10001
+ },
10002
+ [images]
10003
+ );
10004
+ return { images, isUploading, pasteAreaRef, handlePaste, replaceImagePlaceholders };
10005
+ }
10006
+
9608
10007
  // src/plugins/TextCardsPlugin/index.tsx
9609
10008
  import { jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
9610
10009
  var INSERT_TEXT_CARDS_COMMAND = createCommand17(
@@ -9632,16 +10031,27 @@ function InsertTextCardsDialog({
9632
10031
  activeEditor,
9633
10032
  onClose
9634
10033
  }) {
9635
- const [input, setInput] = useState25("");
9636
- const preview = useMemo14(() => {
10034
+ const [input, setInput] = useState26("");
10035
+ let editorConfig = null;
10036
+ try {
10037
+ editorConfig = useEditorConfig();
10038
+ } catch {
10039
+ }
10040
+ const richPaste = useRichPaste(
10041
+ (text) => setInput((prev) => prev ? prev + "\n" + text : text),
10042
+ editorConfig?.baasixClient,
10043
+ editorConfig?.folder
10044
+ );
10045
+ const finalHtml = useMemo14(() => {
9637
10046
  if (!input.trim()) return "";
9638
- return convertTextCards(input);
9639
- }, [input]);
9640
- const handleInsert = useCallback18(() => {
9641
- if (!preview) return;
9642
- activeEditor.dispatchCommand(INSERT_TEXT_CARDS_COMMAND, preview);
10047
+ const html = convertTextCards(input);
10048
+ return richPaste.replaceImagePlaceholders(html);
10049
+ }, [input, richPaste]);
10050
+ const handleInsert = useCallback19(() => {
10051
+ if (!finalHtml) return;
10052
+ activeEditor.dispatchCommand(INSERT_TEXT_CARDS_COMMAND, finalHtml);
9643
10053
  onClose();
9644
- }, [activeEditor, preview, onClose]);
10054
+ }, [activeEditor, finalHtml, onClose]);
9645
10055
  return /* @__PURE__ */ jsxs21("div", { style: { minWidth: 500 }, children: [
9646
10056
  /* @__PURE__ */ jsx31(
9647
10057
  "textarea",
@@ -9668,7 +10078,7 @@ Critical Insight
9668
10078
  Pathology bridges clinical suspicion with molecular certainty...`,
9669
10079
  style: {
9670
10080
  width: "100%",
9671
- minHeight: 180,
10081
+ minHeight: 150,
9672
10082
  fontFamily: "monospace",
9673
10083
  fontSize: 13,
9674
10084
  padding: 8,
@@ -9679,9 +10089,38 @@ Pathology bridges clinical suspicion with molecular certainty...`,
9679
10089
  }
9680
10090
  }
9681
10091
  ),
9682
- preview && /* @__PURE__ */ jsxs21("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
10092
+ /* @__PURE__ */ jsx31(
10093
+ "div",
10094
+ {
10095
+ ref: richPaste.pasteAreaRef,
10096
+ contentEditable: true,
10097
+ onPaste: richPaste.handlePaste,
10098
+ onMouseDown: (e) => e.stopPropagation(),
10099
+ style: {
10100
+ width: "100%",
10101
+ minHeight: 40,
10102
+ padding: 8,
10103
+ border: "2px dashed #93c5fd",
10104
+ borderRadius: 4,
10105
+ fontSize: 12,
10106
+ color: "#6b7280",
10107
+ marginBottom: 8,
10108
+ outline: "none",
10109
+ background: "#f0f7ff"
10110
+ },
10111
+ suppressContentEditableWarning: true,
10112
+ children: /* @__PURE__ */ jsx31("span", { style: { color: "#9ca3af", pointerEvents: "none", userSelect: "none" }, children: richPaste.isUploading ? "Uploading images..." : "Paste from Word/Docs here for image support" })
10113
+ }
10114
+ ),
10115
+ richPaste.images.length > 0 && /* @__PURE__ */ jsxs21("div", { style: { marginBottom: 8, fontSize: 11, color: "#16a34a" }, children: [
10116
+ richPaste.images.length,
10117
+ " image",
10118
+ richPaste.images.length > 1 ? "s" : "",
10119
+ " captured"
10120
+ ] }),
10121
+ finalHtml && /* @__PURE__ */ jsxs21("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
9683
10122
  /* @__PURE__ */ jsx31("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
9684
- /* @__PURE__ */ jsx31("div", { dangerouslySetInnerHTML: { __html: preview } })
10123
+ /* @__PURE__ */ jsx31("div", { dangerouslySetInnerHTML: { __html: finalHtml } })
9685
10124
  ] }),
9686
10125
  /* @__PURE__ */ jsxs21("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
9687
10126
  /* @__PURE__ */ jsx31(
@@ -9698,9 +10137,9 @@ Pathology bridges clinical suspicion with molecular certainty...`,
9698
10137
  {
9699
10138
  type: "button",
9700
10139
  onClick: handleInsert,
9701
- disabled: !preview,
9702
- style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
9703
- children: "Insert"
10140
+ disabled: !finalHtml || richPaste.isUploading,
10141
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: finalHtml && !richPaste.isUploading ? 1 : 0.5 },
10142
+ children: richPaste.isUploading ? "Uploading..." : "Insert"
9704
10143
  }
9705
10144
  )
9706
10145
  ] })
@@ -9711,7 +10150,7 @@ Pathology bridges clinical suspicion with molecular certainty...`,
9711
10150
  import { useLexicalComposerContext as useLexicalComposerContext30 } from "@lexical/react/LexicalComposerContext";
9712
10151
  import { $insertNodeToNearestRoot as $insertNodeToNearestRoot11 } from "@lexical/utils";
9713
10152
  import { COMMAND_PRIORITY_EDITOR as COMMAND_PRIORITY_EDITOR18, createCommand as createCommand18 } from "lexical";
9714
- import { useCallback as useCallback20, useEffect as useEffect28, useMemo as useMemo16, useState as useState27 } from "react";
10153
+ import { useCallback as useCallback21, useEffect as useEffect28, useMemo as useMemo16, useState as useState28 } from "react";
9715
10154
 
9716
10155
  // src/nodes/QuestionsCardsNode.tsx
9717
10156
  import { $getNodeByKey as $getNodeByKey8 } from "lexical";
@@ -9721,7 +10160,7 @@ import {
9721
10160
  } from "@lexical/react/LexicalDecoratorBlockNode";
9722
10161
  import { useLexicalComposerContext as useLexicalComposerContext29 } from "@lexical/react/LexicalComposerContext";
9723
10162
  import { useLexicalEditable as useLexicalEditable5 } from "@lexical/react/useLexicalEditable";
9724
- import { useCallback as useCallback19, useMemo as useMemo15, useState as useState26 } from "react";
10163
+ import { useCallback as useCallback20, useMemo as useMemo15, useState as useState27 } from "react";
9725
10164
  import { jsx as jsx32, jsxs as jsxs22 } from "react/jsx-runtime";
9726
10165
  var GRID_SECTION_KEYS = [
9727
10166
  "rubric",
@@ -9742,44 +10181,45 @@ function QuestionsCardsComponent({
9742
10181
  }) {
9743
10182
  const [editor] = useLexicalComposerContext29();
9744
10183
  const isEditable = useLexicalEditable5();
9745
- const [isEditing, setIsEditing] = useState26(false);
9746
- const [question, setQuestion] = useState26("");
9747
- const [answer, setAnswer] = useState26("");
9748
- const [sections, setSections] = useState26([]);
9749
- const openEditor = useCallback19(() => {
10184
+ const [isEditing, setIsEditing] = useState27(false);
10185
+ const [qaPairs, setQaPairs] = useState27([]);
10186
+ const makeEmptyQA = () => ({
10187
+ question: "",
10188
+ answer: "",
10189
+ sections: GRID_SECTION_KEYS.map((k) => ({ key: k, content: "" }))
10190
+ });
10191
+ const openEditor = useCallback20(() => {
9750
10192
  const parsed = parseQuestionsCardsHtml(html);
9751
- setQuestion(parsed.question);
9752
- setAnswer(parsed.answer);
9753
- const existing = parsed.sections;
9754
- const all = GRID_SECTION_KEYS.map((k) => {
9755
- const found = existing.find((s) => s.key === k);
9756
- return found || { key: k, content: "" };
10193
+ const pairs = parsed.qaPairs.map((qa) => {
10194
+ const existing = qa.sections || [];
10195
+ const all = GRID_SECTION_KEYS.map((k) => {
10196
+ const found = existing.find((s) => s.key === k);
10197
+ return found || { key: k, content: "" };
10198
+ });
10199
+ return { question: qa.question, answer: qa.answer, sections: all };
9757
10200
  });
9758
- setSections(all);
10201
+ setQaPairs(pairs.length > 0 ? pairs : [makeEmptyQA()]);
9759
10202
  setIsEditing(true);
9760
10203
  }, [html]);
9761
10204
  const preview = useMemo15(() => {
9762
10205
  if (!isEditing) return "";
9763
- const styles2 = CARD_STYLES.questionsCards;
10206
+ const cStyles = CARD_STYLES.questionsCards;
9764
10207
  const lines = [];
9765
- if (question) {
9766
- lines.push(`Q1. ${question}`);
9767
- }
9768
- if (answer) {
9769
- lines.push("Answer:");
9770
- lines.push(answer);
9771
- }
9772
- sections.forEach((s) => {
9773
- const sStyle = styles2[s.key];
9774
- if (sStyle && "title" in sStyle && s.content) {
9775
- lines.push(sStyle.title);
9776
- lines.push(s.content);
9777
- }
10208
+ qaPairs.forEach((qa, idx) => {
10209
+ if (qa.question) lines.push(`${idx + 1}. Question: ${qa.question}`);
10210
+ if (qa.answer) lines.push(`Answer: ${qa.answer}`);
10211
+ qa.sections.forEach((s) => {
10212
+ const sStyle = cStyles[s.key];
10213
+ if (sStyle && "title" in sStyle && s.content) {
10214
+ lines.push(sStyle.title);
10215
+ lines.push(s.content);
10216
+ }
10217
+ });
9778
10218
  });
9779
10219
  const text = lines.join("\n");
9780
10220
  return text.trim() ? convertQuestionsCards(text) : "";
9781
- }, [isEditing, question, answer, sections]);
9782
- const saveChanges = useCallback19(() => {
10221
+ }, [isEditing, qaPairs]);
10222
+ const saveChanges = useCallback20(() => {
9783
10223
  if (!preview) return;
9784
10224
  editor.update(() => {
9785
10225
  const node = $getNodeByKey8(nodeKey);
@@ -9789,13 +10229,23 @@ function QuestionsCardsComponent({
9789
10229
  });
9790
10230
  setIsEditing(false);
9791
10231
  }, [editor, nodeKey, preview]);
9792
- const cancelEdit = useCallback19(() => {
10232
+ const cancelEdit = useCallback20(() => {
9793
10233
  setIsEditing(false);
9794
10234
  }, []);
9795
- const updateSection = useCallback19((idx, value) => {
9796
- setSections(
9797
- (prev) => prev.map((s, i) => i === idx ? { ...s, content: value } : s)
9798
- );
10235
+ const updateQA = useCallback20((idx, field, value) => {
10236
+ setQaPairs((prev) => prev.map((qa, i) => i === idx ? { ...qa, [field]: value } : qa));
10237
+ }, []);
10238
+ const addQAPair = useCallback20(() => {
10239
+ setQaPairs((prev) => [...prev, makeEmptyQA()]);
10240
+ }, []);
10241
+ const removeQAPair = useCallback20((idx) => {
10242
+ setQaPairs((prev) => prev.filter((_, i) => i !== idx));
10243
+ }, []);
10244
+ const updateSection = useCallback20((qIdx, sIdx, value) => {
10245
+ setQaPairs((prev) => prev.map((qa, i) => {
10246
+ if (i !== qIdx) return qa;
10247
+ return { ...qa, sections: qa.sections.map((s, j) => j === sIdx ? { ...s, content: value } : s) };
10248
+ }));
9799
10249
  }, []);
9800
10250
  const styles = CARD_STYLES.questionsCards;
9801
10251
  return /* @__PURE__ */ jsx32(BlockWithAlignableContents8, { className, format, nodeKey, children: /* @__PURE__ */ jsxs22("div", { style: { position: "relative" }, children: [
@@ -9849,52 +10299,78 @@ function QuestionsCardsComponent({
9849
10299
  )
9850
10300
  ] })
9851
10301
  ] }),
9852
- /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 6 }, children: [
9853
- /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#1976d2", fontWeight: 600, display: "block", marginBottom: 2 }, children: "Question" }),
9854
- /* @__PURE__ */ jsx32(
9855
- "textarea",
9856
- {
9857
- placeholder: "Enter question text...",
9858
- value: question,
9859
- onChange: (e) => setQuestion(e.target.value),
9860
- onMouseDown: (e) => e.stopPropagation(),
9861
- style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
9862
- }
9863
- )
9864
- ] }),
9865
- /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 6 }, children: [
9866
- /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#666", fontWeight: 600, display: "block", marginBottom: 2 }, children: "Answer" }),
9867
- /* @__PURE__ */ jsx32(
9868
- "textarea",
9869
- {
9870
- placeholder: "Enter answer text...",
9871
- value: answer,
9872
- onChange: (e) => setAnswer(e.target.value),
9873
- onMouseDown: (e) => e.stopPropagation(),
9874
- style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 60, resize: "vertical" }
9875
- }
9876
- )
9877
- ] }),
9878
- /* @__PURE__ */ jsxs22("div", { style: { border: "1px solid #e5e7eb", borderRadius: 6, padding: 8, background: "#fff" }, children: [
9879
- /* @__PURE__ */ jsx32("span", { style: { fontSize: 11, color: "#666", fontWeight: 600, display: "block", marginBottom: 4 }, children: "Card Sections" }),
9880
- sections.map((section, idx) => {
9881
- const sStyle = styles[section.key];
9882
- const label = sStyle && "title" in sStyle ? sStyle.title : section.key;
9883
- return /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
9884
- /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#666", display: "block", marginBottom: 2 }, children: label }),
9885
- /* @__PURE__ */ jsx32(
9886
- "textarea",
9887
- {
9888
- placeholder: `${label} content...`,
9889
- value: section.content,
9890
- onChange: (e) => updateSection(idx, e.target.value),
9891
- onMouseDown: (e) => e.stopPropagation(),
9892
- style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
9893
- }
9894
- )
9895
- ] }, idx);
9896
- })
9897
- ] }),
10302
+ qaPairs.map((qa, qIdx) => /* @__PURE__ */ jsxs22("div", { style: { border: "1px solid #e5e7eb", borderRadius: 6, padding: 8, marginBottom: 8, background: "#fff" }, children: [
10303
+ /* @__PURE__ */ jsxs22("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 4 }, children: [
10304
+ /* @__PURE__ */ jsxs22("span", { style: { fontSize: 12, fontWeight: 600, color: "#1976d2" }, children: [
10305
+ "Q",
10306
+ qIdx + 1
10307
+ ] }),
10308
+ qaPairs.length > 1 && /* @__PURE__ */ jsx32(
10309
+ "button",
10310
+ {
10311
+ type: "button",
10312
+ onClick: () => removeQAPair(qIdx),
10313
+ style: { padding: "2px 6px", fontSize: 14, border: "1px solid #ddd", borderRadius: 4, background: "#fff", cursor: "pointer", color: "#e11d48" },
10314
+ children: "\xD7"
10315
+ }
10316
+ )
10317
+ ] }),
10318
+ /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
10319
+ /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#1976d2", fontWeight: 600, display: "block", marginBottom: 2 }, children: "Question" }),
10320
+ /* @__PURE__ */ jsx32(
10321
+ "textarea",
10322
+ {
10323
+ placeholder: "Enter question text...",
10324
+ value: qa.question,
10325
+ onChange: (e) => updateQA(qIdx, "question", e.target.value),
10326
+ onMouseDown: (e) => e.stopPropagation(),
10327
+ style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
10328
+ }
10329
+ )
10330
+ ] }),
10331
+ /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
10332
+ /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#666", fontWeight: 600, display: "block", marginBottom: 2 }, children: "Answer" }),
10333
+ /* @__PURE__ */ jsx32(
10334
+ "textarea",
10335
+ {
10336
+ placeholder: "Enter answer text...",
10337
+ value: qa.answer,
10338
+ onChange: (e) => updateQA(qIdx, "answer", e.target.value),
10339
+ onMouseDown: (e) => e.stopPropagation(),
10340
+ style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 60, resize: "vertical" }
10341
+ }
10342
+ )
10343
+ ] }),
10344
+ /* @__PURE__ */ jsxs22("details", { style: { marginTop: 4 }, children: [
10345
+ /* @__PURE__ */ jsx32("summary", { style: { fontSize: 11, color: "#666", fontWeight: 600, cursor: "pointer" }, children: "Card Sections" }),
10346
+ /* @__PURE__ */ jsx32("div", { style: { marginTop: 4 }, children: qa.sections.map((section, sIdx) => {
10347
+ const sStyle = styles[section.key];
10348
+ const label = sStyle && "title" in sStyle ? sStyle.title : section.key;
10349
+ return /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
10350
+ /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#666", display: "block", marginBottom: 2 }, children: label }),
10351
+ /* @__PURE__ */ jsx32(
10352
+ "textarea",
10353
+ {
10354
+ placeholder: `${label} content...`,
10355
+ value: section.content,
10356
+ onChange: (e) => updateSection(qIdx, sIdx, e.target.value),
10357
+ onMouseDown: (e) => e.stopPropagation(),
10358
+ style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
10359
+ }
10360
+ )
10361
+ ] }, sIdx);
10362
+ }) })
10363
+ ] })
10364
+ ] }, qIdx)),
10365
+ /* @__PURE__ */ jsx32(
10366
+ "button",
10367
+ {
10368
+ type: "button",
10369
+ onClick: addQAPair,
10370
+ style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, background: "#fff", cursor: "pointer", marginBottom: 8 },
10371
+ children: "+ Add Question"
10372
+ }
10373
+ ),
9898
10374
  preview && /* @__PURE__ */ jsxs22("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" }, children: [
9899
10375
  /* @__PURE__ */ jsx32("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
9900
10376
  /* @__PURE__ */ jsx32("div", { dangerouslySetInnerHTML: { __html: preview } })
@@ -10003,16 +10479,27 @@ function InsertQuestionsCardsDialog({
10003
10479
  activeEditor,
10004
10480
  onClose
10005
10481
  }) {
10006
- const [input, setInput] = useState27("");
10007
- const preview = useMemo16(() => {
10482
+ const [input, setInput] = useState28("");
10483
+ let editorConfig = null;
10484
+ try {
10485
+ editorConfig = useEditorConfig();
10486
+ } catch {
10487
+ }
10488
+ const richPaste = useRichPaste(
10489
+ (text) => setInput((prev) => prev ? prev + "\n" + text : text),
10490
+ editorConfig?.baasixClient,
10491
+ editorConfig?.folder
10492
+ );
10493
+ const finalHtml = useMemo16(() => {
10008
10494
  if (!input.trim()) return "";
10009
- return convertQuestionsCards(input);
10010
- }, [input]);
10011
- const handleInsert = useCallback20(() => {
10012
- if (!preview) return;
10013
- activeEditor.dispatchCommand(INSERT_QUESTIONS_CARDS_COMMAND, preview);
10495
+ const html = convertQuestionsCards(input);
10496
+ return richPaste.replaceImagePlaceholders(html);
10497
+ }, [input, richPaste]);
10498
+ const handleInsert = useCallback21(() => {
10499
+ if (!finalHtml) return;
10500
+ activeEditor.dispatchCommand(INSERT_QUESTIONS_CARDS_COMMAND, finalHtml);
10014
10501
  onClose();
10015
- }, [activeEditor, preview, onClose]);
10502
+ }, [activeEditor, finalHtml, onClose]);
10016
10503
  return /* @__PURE__ */ jsxs23("div", { style: { minWidth: 500 }, children: [
10017
10504
  /* @__PURE__ */ jsx33(
10018
10505
  "textarea",
@@ -10021,28 +10508,18 @@ function InsertQuestionsCardsDialog({
10021
10508
  onChange: (e) => setInput(e.target.value),
10022
10509
  placeholder: `Paste question content here...
10023
10510
  Example:
10024
- Q1. Describe the pathogenesis of tuberculosis.
10511
+ Q1 : Describe the pathogenesis of tuberculosis.
10025
10512
 
10026
- Answer:
10027
- Tuberculosis is caused by Mycobacterium tuberculosis...
10513
+ Answer: Tuberculosis is caused by Mycobacterium tuberculosis...
10028
10514
 
10029
- MARKING RUBRIC
10515
+ 1. MARKING RUBRIC
10030
10516
  Definition: 2 marks, Pathogenesis: 5 marks...
10031
10517
 
10032
- MNEMONICS
10033
- Remember TB pathogenesis with "IGRA"...
10034
-
10035
- EXAMINER'S PERSPECTIVE
10036
- Examiners look for systematic approach...
10037
-
10038
- CLINICAL CORRELATION
10039
- TB commonly presents with...
10040
-
10041
- HIGH-YIELD EXAM TIP
10042
- Always mention Ghon complex...`,
10518
+ 2. MNEMONICS
10519
+ Remember TB pathogenesis with "IGRA"...`,
10043
10520
  style: {
10044
10521
  width: "100%",
10045
- minHeight: 180,
10522
+ minHeight: 150,
10046
10523
  fontFamily: "monospace",
10047
10524
  fontSize: 13,
10048
10525
  padding: 8,
@@ -10053,9 +10530,38 @@ Always mention Ghon complex...`,
10053
10530
  }
10054
10531
  }
10055
10532
  ),
10056
- preview && /* @__PURE__ */ jsxs23("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
10533
+ /* @__PURE__ */ jsx33(
10534
+ "div",
10535
+ {
10536
+ ref: richPaste.pasteAreaRef,
10537
+ contentEditable: true,
10538
+ onPaste: richPaste.handlePaste,
10539
+ onMouseDown: (e) => e.stopPropagation(),
10540
+ style: {
10541
+ width: "100%",
10542
+ minHeight: 40,
10543
+ padding: 8,
10544
+ border: "2px dashed #93c5fd",
10545
+ borderRadius: 4,
10546
+ fontSize: 12,
10547
+ color: "#6b7280",
10548
+ marginBottom: 8,
10549
+ outline: "none",
10550
+ background: "#f0f7ff"
10551
+ },
10552
+ suppressContentEditableWarning: true,
10553
+ children: /* @__PURE__ */ jsx33("span", { style: { color: "#9ca3af", pointerEvents: "none", userSelect: "none" }, children: richPaste.isUploading ? "Uploading images..." : "Paste from Word/Docs here for image support" })
10554
+ }
10555
+ ),
10556
+ richPaste.images.length > 0 && /* @__PURE__ */ jsxs23("div", { style: { marginBottom: 8, fontSize: 11, color: "#16a34a" }, children: [
10557
+ richPaste.images.length,
10558
+ " image",
10559
+ richPaste.images.length > 1 ? "s" : "",
10560
+ " captured"
10561
+ ] }),
10562
+ finalHtml && /* @__PURE__ */ jsxs23("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
10057
10563
  /* @__PURE__ */ jsx33("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
10058
- /* @__PURE__ */ jsx33("div", { dangerouslySetInnerHTML: { __html: preview } })
10564
+ /* @__PURE__ */ jsx33("div", { dangerouslySetInnerHTML: { __html: finalHtml } })
10059
10565
  ] }),
10060
10566
  /* @__PURE__ */ jsxs23("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
10061
10567
  /* @__PURE__ */ jsx33(
@@ -10072,9 +10578,9 @@ Always mention Ghon complex...`,
10072
10578
  {
10073
10579
  type: "button",
10074
10580
  onClick: handleInsert,
10075
- disabled: !preview,
10076
- style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
10077
- children: "Insert"
10581
+ disabled: !finalHtml || richPaste.isUploading,
10582
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: finalHtml && !richPaste.isUploading ? 1 : 0.5 },
10583
+ children: richPaste.isUploading ? "Uploading..." : "Insert"
10078
10584
  }
10079
10585
  )
10080
10586
  ] })
@@ -10089,7 +10595,7 @@ import {
10089
10595
  TableNode as TableNode2,
10090
10596
  TableRowNode as TableRowNode2
10091
10597
  } from "@lexical/table";
10092
- import { createContext as createContext4, useContext as useContext4, useEffect as useEffect29, useMemo as useMemo17, useState as useState28 } from "react";
10598
+ import { createContext as createContext4, useContext as useContext4, useEffect as useEffect29, useMemo as useMemo17, useState as useState29 } from "react";
10093
10599
  import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
10094
10600
  var CellContext = createContext4({
10095
10601
  cellEditorConfig: null,
@@ -10101,9 +10607,9 @@ function InsertTableDialog({
10101
10607
  activeEditor,
10102
10608
  onClose
10103
10609
  }) {
10104
- const [rows, setRows] = useState28("5");
10105
- const [columns, setColumns] = useState28("5");
10106
- const [isDisabled, setIsDisabled] = useState28(true);
10610
+ const [rows, setRows] = useState29("5");
10611
+ const [columns, setColumns] = useState29("5");
10612
+ const [isDisabled, setIsDisabled] = useState29(true);
10107
10613
  useEffect29(() => {
10108
10614
  const row = Number(rows);
10109
10615
  const column = Number(columns);
@@ -10155,7 +10661,7 @@ import {
10155
10661
  } from "@lexical/react/LexicalDecoratorBlockNode";
10156
10662
  import { useLexicalComposerContext as useLexicalComposerContext32 } from "@lexical/react/LexicalComposerContext";
10157
10663
  import { useLexicalEditable as useLexicalEditable6 } from "@lexical/react/useLexicalEditable";
10158
- import { useCallback as useCallback21, useRef as useRef9, useState as useState29 } from "react";
10664
+ import { useCallback as useCallback22, useRef as useRef11, useState as useState30 } from "react";
10159
10665
  import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
10160
10666
  function HtmlBlockComponent({
10161
10667
  className,
@@ -10165,15 +10671,15 @@ function HtmlBlockComponent({
10165
10671
  }) {
10166
10672
  const [editor] = useLexicalComposerContext32();
10167
10673
  const isEditable = useLexicalEditable6();
10168
- const [isEditing, setIsEditing] = useState29(false);
10169
- const [editValue, setEditValue] = useState29("");
10170
- const textareaRef = useRef9(null);
10171
- const openEditor = useCallback21(() => {
10674
+ const [isEditing, setIsEditing] = useState30(false);
10675
+ const [editValue, setEditValue] = useState30("");
10676
+ const textareaRef = useRef11(null);
10677
+ const openEditor = useCallback22(() => {
10172
10678
  setEditValue(html);
10173
10679
  setIsEditing(true);
10174
10680
  setTimeout(() => textareaRef.current?.focus(), 50);
10175
10681
  }, [html]);
10176
- const saveHtml = useCallback21(() => {
10682
+ const saveHtml = useCallback22(() => {
10177
10683
  editor.update(() => {
10178
10684
  const node = $getNodeByKey9(nodeKey);
10179
10685
  if ($isHtmlBlockNode(node)) {
@@ -10182,7 +10688,7 @@ function HtmlBlockComponent({
10182
10688
  });
10183
10689
  setIsEditing(false);
10184
10690
  }, [editor, nodeKey, editValue]);
10185
- const cancelEdit = useCallback21(() => {
10691
+ const cancelEdit = useCallback22(() => {
10186
10692
  setIsEditing(false);
10187
10693
  }, []);
10188
10694
  return /* @__PURE__ */ jsx35(
@@ -10661,7 +11167,7 @@ function getBaseOptions(editor, showModal) {
10661
11167
  function ComponentPickerMenuPlugin() {
10662
11168
  const [editor] = useLexicalComposerContext33();
10663
11169
  const [modal, showModal] = useModal();
10664
- const [queryString, setQueryString] = useState30(null);
11170
+ const [queryString, setQueryString] = useState31(null);
10665
11171
  const checkForTriggerMatch = useBasicTypeaheadTriggerMatch("/", {
10666
11172
  allowWhitespace: true,
10667
11173
  minLength: 0
@@ -10679,7 +11185,7 @@ function ComponentPickerMenuPlugin() {
10679
11185
  )
10680
11186
  ];
10681
11187
  }, [editor, queryString, showModal]);
10682
- const onSelectOption = useCallback22(
11188
+ const onSelectOption = useCallback23(
10683
11189
  (selectedOption, nodeToRemove, closeMenu, matchingString) => {
10684
11190
  editor.update(() => {
10685
11191
  nodeToRemove?.remove();
@@ -10912,7 +11418,7 @@ import {
10912
11418
  $isParagraphNode as $isParagraphNode4,
10913
11419
  $isTextNode as $isTextNode4
10914
11420
  } from "lexical";
10915
- import { useCallback as useCallback23, useEffect as useEffect31, useMemo as useMemo20, useRef as useRef10, useState as useState31 } from "react";
11421
+ import { useCallback as useCallback24, useEffect as useEffect31, useMemo as useMemo20, useRef as useRef12, useState as useState32 } from "react";
10916
11422
  import * as ReactDOM3 from "react-dom";
10917
11423
  import { Fragment as Fragment12, jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
10918
11424
  var DRAGGABLE_BLOCK_MENU_CLASSNAME = "draggable-block-menu";
@@ -10924,18 +11430,18 @@ function DraggableBlockPlugin({
10924
11430
  }) {
10925
11431
  const [editor] = useLexicalComposerContext36();
10926
11432
  const [modal, showModal] = useModal();
10927
- const menuRef = useRef10(null);
10928
- const pickerRef = useRef10(null);
10929
- const searchInputRef = useRef10(null);
10930
- const targetLineRef = useRef10(null);
10931
- const [draggableElement, setDraggableElement] = useState31(
11433
+ const menuRef = useRef12(null);
11434
+ const pickerRef = useRef12(null);
11435
+ const searchInputRef = useRef12(null);
11436
+ const targetLineRef = useRef12(null);
11437
+ const [draggableElement, setDraggableElement] = useState32(
10932
11438
  null
10933
11439
  );
10934
- const [pickerState, setPickerState] = useState31(null);
10935
- const [isPickerOpen, setIsPickerOpen] = useState31(false);
10936
- const [queryString, setQueryString] = useState31("");
10937
- const [highlightedIndex, setHighlightedIndex] = useState31(0);
10938
- const [pickerPosition, setPickerPosition] = useState31(null);
11440
+ const [pickerState, setPickerState] = useState32(null);
11441
+ const [isPickerOpen, setIsPickerOpen] = useState32(false);
11442
+ const [queryString, setQueryString] = useState32("");
11443
+ const [highlightedIndex, setHighlightedIndex] = useState32(0);
11444
+ const [pickerPosition, setPickerPosition] = useState32(null);
10939
11445
  const options = useMemo20(() => {
10940
11446
  const baseOptions = getBaseOptions(editor, showModal);
10941
11447
  if (!queryString) {
@@ -10979,7 +11485,7 @@ function DraggableBlockPlugin({
10979
11485
  document.removeEventListener("mousedown", handleClickOutside);
10980
11486
  };
10981
11487
  }, [isPickerOpen]);
10982
- const selectOption = useCallback23(
11488
+ const selectOption = useCallback24(
10983
11489
  (option) => {
10984
11490
  if (!pickerState) {
10985
11491
  setIsPickerOpen(false);
@@ -11156,7 +11662,7 @@ import {
11156
11662
  $getSelection as $getSelection11,
11157
11663
  $isRangeSelection as $isRangeSelection9
11158
11664
  } from "lexical";
11159
- import { useCallback as useCallback24, useEffect as useEffect32, useMemo as useMemo21, useState as useState32 } from "react";
11665
+ import { useCallback as useCallback25, useEffect as useEffect32, useMemo as useMemo21, useState as useState33 } from "react";
11160
11666
  import * as ReactDOM4 from "react-dom";
11161
11667
  import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
11162
11668
  var EmojiOption = class extends MenuOption2 {
@@ -11204,8 +11710,8 @@ function EmojiMenuItem({
11204
11710
  var MAX_EMOJI_SUGGESTION_COUNT = 10;
11205
11711
  function EmojiPickerPlugin() {
11206
11712
  const [editor] = useLexicalComposerContext37();
11207
- const [queryString, setQueryString] = useState32(null);
11208
- const [emojis, setEmojis] = useState32([]);
11713
+ const [queryString, setQueryString] = useState33(null);
11714
+ const [emojis, setEmojis] = useState33([]);
11209
11715
  useEffect32(() => {
11210
11716
  import("./emoji-list-MUV74SND.js").then((file) => setEmojis(file.default));
11211
11717
  }, []);
@@ -11229,7 +11735,7 @@ function EmojiPickerPlugin() {
11229
11735
  ) : false : emojiOptions;
11230
11736
  }).slice(0, MAX_EMOJI_SUGGESTION_COUNT);
11231
11737
  }, [emojiOptions, queryString]);
11232
- const onSelectOption = useCallback24(
11738
+ const onSelectOption = useCallback25(
11233
11739
  (selectedOption, nodeToRemove, closeMenu) => {
11234
11740
  editor.update(() => {
11235
11741
  const selection = $getSelection11();
@@ -11302,7 +11808,7 @@ import {
11302
11808
  KEY_ESCAPE_COMMAND as KEY_ESCAPE_COMMAND2,
11303
11809
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND2
11304
11810
  } from "lexical";
11305
- import { useCallback as useCallback25, useEffect as useEffect33, useRef as useRef11, useState as useState33 } from "react";
11811
+ import { useCallback as useCallback26, useEffect as useEffect33, useRef as useRef13, useState as useState34 } from "react";
11306
11812
  import { createPortal as createPortal8 } from "react-dom";
11307
11813
 
11308
11814
  // src/utils/getSelectedNode.ts
@@ -11363,14 +11869,14 @@ function FloatingLinkEditor({
11363
11869
  isLinkEditMode,
11364
11870
  setIsLinkEditMode
11365
11871
  }) {
11366
- const editorRef = useRef11(null);
11367
- const inputRef = useRef11(null);
11368
- const [linkUrl, setLinkUrl] = useState33("");
11369
- const [editedLinkUrl, setEditedLinkUrl] = useState33("https://");
11370
- const [lastSelection, setLastSelection] = useState33(
11872
+ const editorRef = useRef13(null);
11873
+ const inputRef = useRef13(null);
11874
+ const [linkUrl, setLinkUrl] = useState34("");
11875
+ const [editedLinkUrl, setEditedLinkUrl] = useState34("https://");
11876
+ const [lastSelection, setLastSelection] = useState34(
11371
11877
  null
11372
11878
  );
11373
- const $updateLinkEditor = useCallback25(() => {
11879
+ const $updateLinkEditor = useCallback26(() => {
11374
11880
  const selection = $getSelection12();
11375
11881
  if ($isRangeSelection10(selection)) {
11376
11882
  const node = getSelectedNode(selection);
@@ -11622,8 +12128,8 @@ function FloatingLinkEditor({
11622
12128
  ] }) });
11623
12129
  }
11624
12130
  function useFloatingLinkEditorToolbar(editor, anchorElem, isLinkEditMode, setIsLinkEditMode) {
11625
- const [activeEditor, setActiveEditor] = useState33(editor);
11626
- const [isLink, setIsLink] = useState33(false);
12131
+ const [activeEditor, setActiveEditor] = useState34(editor);
12132
+ const [isLink, setIsLink] = useState34(false);
11627
12133
  useEffect33(() => {
11628
12134
  function $updateToolbar() {
11629
12135
  const selection = $getSelection12();
@@ -11740,7 +12246,7 @@ import {
11740
12246
  getDOMSelection as getDOMSelection3,
11741
12247
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND3
11742
12248
  } from "lexical";
11743
- import { useCallback as useCallback26, useEffect as useEffect34, useRef as useRef12, useState as useState34 } from "react";
12249
+ import { useCallback as useCallback27, useEffect as useEffect34, useRef as useRef14, useState as useState35 } from "react";
11744
12250
  import { createPortal as createPortal9 } from "react-dom";
11745
12251
 
11746
12252
  // src/utils/getDOMRangeRect.ts
@@ -11819,8 +12325,8 @@ function TextFormatFloatingToolbar({
11819
12325
  isSuperscript: isSuperscript2,
11820
12326
  setIsLinkEditMode
11821
12327
  }) {
11822
- const popupCharStylesEditorRef = useRef12(null);
11823
- const insertLink = useCallback26(() => {
12328
+ const popupCharStylesEditorRef = useRef14(null);
12329
+ const insertLink = useCallback27(() => {
11824
12330
  if (!isLink) {
11825
12331
  setIsLinkEditMode(true);
11826
12332
  editor.dispatchCommand(TOGGLE_LINK_COMMAND4, "https://");
@@ -11861,7 +12367,7 @@ function TextFormatFloatingToolbar({
11861
12367
  };
11862
12368
  }
11863
12369
  }, [popupCharStylesEditorRef]);
11864
- const $updateTextFormatFloatingToolbar = useCallback26(() => {
12370
+ const $updateTextFormatFloatingToolbar = useCallback27(() => {
11865
12371
  const selection = $getSelection13();
11866
12372
  const popupCharStylesEditorElem = popupCharStylesEditorRef.current;
11867
12373
  const nativeSelection = getDOMSelection3(editor._window);
@@ -12075,19 +12581,19 @@ function TextFormatFloatingToolbar({
12075
12581
  ] });
12076
12582
  }
12077
12583
  function useFloatingTextFormatToolbar(editor, anchorElem, setIsLinkEditMode) {
12078
- const [isText, setIsText] = useState34(false);
12079
- const [isLink, setIsLink] = useState34(false);
12080
- const [isBold, setIsBold] = useState34(false);
12081
- const [isItalic, setIsItalic] = useState34(false);
12082
- const [isUnderline, setIsUnderline] = useState34(false);
12083
- const [isUppercase2, setIsUppercase] = useState34(false);
12084
- const [isLowercase2, setIsLowercase] = useState34(false);
12085
- const [isCapitalize2, setIsCapitalize] = useState34(false);
12086
- const [isStrikethrough, setIsStrikethrough] = useState34(false);
12087
- const [isSubscript2, setIsSubscript] = useState34(false);
12088
- const [isSuperscript2, setIsSuperscript] = useState34(false);
12089
- const [isCode, setIsCode] = useState34(false);
12090
- const updatePopup = useCallback26(() => {
12584
+ const [isText, setIsText] = useState35(false);
12585
+ const [isLink, setIsLink] = useState35(false);
12586
+ const [isBold, setIsBold] = useState35(false);
12587
+ const [isItalic, setIsItalic] = useState35(false);
12588
+ const [isUnderline, setIsUnderline] = useState35(false);
12589
+ const [isUppercase2, setIsUppercase] = useState35(false);
12590
+ const [isLowercase2, setIsLowercase] = useState35(false);
12591
+ const [isCapitalize2, setIsCapitalize] = useState35(false);
12592
+ const [isStrikethrough, setIsStrikethrough] = useState35(false);
12593
+ const [isSubscript2, setIsSubscript] = useState35(false);
12594
+ const [isSuperscript2, setIsSuperscript] = useState35(false);
12595
+ const [isCode, setIsCode] = useState35(false);
12596
+ const updatePopup = useCallback27(() => {
12091
12597
  editor.getEditorState().read(() => {
12092
12598
  if (editor.isComposing()) {
12093
12599
  return;
@@ -12963,12 +13469,12 @@ import {
12963
13469
  isDOMNode as isDOMNode2,
12964
13470
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND4
12965
13471
  } from "lexical";
12966
- import { useCallback as useCallback27, useEffect as useEffect39, useRef as useRef14, useState as useState36 } from "react";
13472
+ import { useCallback as useCallback28, useEffect as useEffect39, useRef as useRef16, useState as useState37 } from "react";
12967
13473
  import { createPortal as createPortal10 } from "react-dom";
12968
13474
 
12969
13475
  // src/ui/ColorPicker.tsx
12970
13476
  import { calculateZoomLevel as calculateZoomLevel2 } from "@lexical/utils";
12971
- import { useMemo as useMemo22, useRef as useRef13, useState as useState35 } from "react";
13477
+ import { useMemo as useMemo22, useRef as useRef15, useState as useState36 } from "react";
12972
13478
  import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
12973
13479
  var skipAddingToHistoryStack = false;
12974
13480
  var basicColors = [
@@ -12994,11 +13500,11 @@ function ColorPicker({
12994
13500
  color,
12995
13501
  onChange
12996
13502
  }) {
12997
- const [selfColor, setSelfColor] = useState35(transformColor("hex", color));
12998
- const [inputColor, setInputColor] = useState35(
13503
+ const [selfColor, setSelfColor] = useState36(transformColor("hex", color));
13504
+ const [inputColor, setInputColor] = useState36(
12999
13505
  transformColor("hex", color).hex
13000
13506
  );
13001
- const innerDivRef = useRef13(null);
13507
+ const innerDivRef = useRef15(null);
13002
13508
  const saturationPosition = useMemo22(
13003
13509
  () => ({
13004
13510
  x: selfColor.hsv.s / 100 * WIDTH,
@@ -13108,8 +13614,8 @@ function ColorPicker({
13108
13614
  );
13109
13615
  }
13110
13616
  function MoveWrapper({ className, style, onChange, children }) {
13111
- const divRef = useRef13(null);
13112
- const draggedRef = useRef13(false);
13617
+ const divRef = useRef15(null);
13618
+ const draggedRef = useRef15(false);
13113
13619
  const move = (e) => {
13114
13620
  if (divRef.current) {
13115
13621
  const { current: div } = divRef;
@@ -13282,15 +13788,15 @@ function TableActionMenu({
13282
13788
  showColorPickerModal
13283
13789
  }) {
13284
13790
  const [editor] = useLexicalComposerContext43();
13285
- const dropDownRef = useRef14(null);
13286
- const [tableCellNode, updateTableCellNode] = useState36(_tableCellNode);
13287
- const [selectionCounts, updateSelectionCounts] = useState36({
13791
+ const dropDownRef = useRef16(null);
13792
+ const [tableCellNode, updateTableCellNode] = useState37(_tableCellNode);
13793
+ const [selectionCounts, updateSelectionCounts] = useState37({
13288
13794
  columns: 1,
13289
13795
  rows: 1
13290
13796
  });
13291
- const [canMergeCells, setCanMergeCells] = useState36(false);
13292
- const [canUnmergeCell, setCanUnmergeCell] = useState36(false);
13293
- const [backgroundColor, setBackgroundColor] = useState36(
13797
+ const [canMergeCells, setCanMergeCells] = useState37(false);
13798
+ const [canUnmergeCell, setCanUnmergeCell] = useState37(false);
13799
+ const [backgroundColor, setBackgroundColor] = useState37(
13294
13800
  () => currentCellBackgroundColor(editor) || ""
13295
13801
  );
13296
13802
  useEffect39(() => {
@@ -13354,7 +13860,7 @@ function TableActionMenu({
13354
13860
  window.addEventListener("click", handleClickOutside);
13355
13861
  return () => window.removeEventListener("click", handleClickOutside);
13356
13862
  }, [setIsMenuOpen, contextRef]);
13357
- const clearTableSelection = useCallback27(() => {
13863
+ const clearTableSelection = useCallback28(() => {
13358
13864
  editor.update(() => {
13359
13865
  if (tableCellNode.isAttached()) {
13360
13866
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13397,7 +13903,7 @@ function TableActionMenu({
13397
13903
  $unmergeCell();
13398
13904
  });
13399
13905
  };
13400
- const insertTableRowAtSelection = useCallback27(
13906
+ const insertTableRowAtSelection = useCallback28(
13401
13907
  (shouldInsertAfter) => {
13402
13908
  editor.update(() => {
13403
13909
  for (let i = 0; i < selectionCounts.rows; i++) {
@@ -13408,7 +13914,7 @@ function TableActionMenu({
13408
13914
  },
13409
13915
  [editor, onClose, selectionCounts.rows]
13410
13916
  );
13411
- const insertTableColumnAtSelection = useCallback27(
13917
+ const insertTableColumnAtSelection = useCallback28(
13412
13918
  (shouldInsertAfter) => {
13413
13919
  editor.update(() => {
13414
13920
  for (let i = 0; i < selectionCounts.columns; i++) {
@@ -13419,13 +13925,13 @@ function TableActionMenu({
13419
13925
  },
13420
13926
  [editor, onClose, selectionCounts.columns]
13421
13927
  );
13422
- const deleteTableRowAtSelection = useCallback27(() => {
13928
+ const deleteTableRowAtSelection = useCallback28(() => {
13423
13929
  editor.update(() => {
13424
13930
  $deleteTableRowAtSelection();
13425
13931
  onClose();
13426
13932
  });
13427
13933
  }, [editor, onClose]);
13428
- const deleteTableAtSelection = useCallback27(() => {
13934
+ const deleteTableAtSelection = useCallback28(() => {
13429
13935
  editor.update(() => {
13430
13936
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
13431
13937
  tableNode.remove();
@@ -13433,13 +13939,13 @@ function TableActionMenu({
13433
13939
  onClose();
13434
13940
  });
13435
13941
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13436
- const deleteTableColumnAtSelection = useCallback27(() => {
13942
+ const deleteTableColumnAtSelection = useCallback28(() => {
13437
13943
  editor.update(() => {
13438
13944
  $deleteTableColumnAtSelection();
13439
13945
  onClose();
13440
13946
  });
13441
13947
  }, [editor, onClose]);
13442
- const toggleTableRowIsHeader = useCallback27(() => {
13948
+ const toggleTableRowIsHeader = useCallback28(() => {
13443
13949
  editor.update(() => {
13444
13950
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
13445
13951
  const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode);
@@ -13460,7 +13966,7 @@ function TableActionMenu({
13460
13966
  onClose();
13461
13967
  });
13462
13968
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13463
- const toggleTableColumnIsHeader = useCallback27(() => {
13969
+ const toggleTableColumnIsHeader = useCallback28(() => {
13464
13970
  editor.update(() => {
13465
13971
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
13466
13972
  const tableColumnIndex = $getTableColumnIndexFromTableCellNode(tableCellNode);
@@ -13481,7 +13987,7 @@ function TableActionMenu({
13481
13987
  onClose();
13482
13988
  });
13483
13989
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13484
- const toggleRowStriping = useCallback27(() => {
13990
+ const toggleRowStriping = useCallback28(() => {
13485
13991
  editor.update(() => {
13486
13992
  if (tableCellNode.isAttached()) {
13487
13993
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13493,7 +13999,7 @@ function TableActionMenu({
13493
13999
  onClose();
13494
14000
  });
13495
14001
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13496
- const toggleFirstRowFreeze = useCallback27(() => {
14002
+ const toggleFirstRowFreeze = useCallback28(() => {
13497
14003
  editor.update(() => {
13498
14004
  if (tableCellNode.isAttached()) {
13499
14005
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13505,7 +14011,7 @@ function TableActionMenu({
13505
14011
  onClose();
13506
14012
  });
13507
14013
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13508
- const toggleFirstColumnFreeze = useCallback27(() => {
14014
+ const toggleFirstColumnFreeze = useCallback28(() => {
13509
14015
  editor.update(() => {
13510
14016
  if (tableCellNode.isAttached()) {
13511
14017
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13519,7 +14025,7 @@ function TableActionMenu({
13519
14025
  onClose();
13520
14026
  });
13521
14027
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13522
- const handleCellBackgroundColor = useCallback27(
14028
+ const handleCellBackgroundColor = useCallback28(
13523
14029
  (value) => {
13524
14030
  editor.update(() => {
13525
14031
  const selection = $getSelection17();
@@ -13832,14 +14338,14 @@ function TableCellActionMenuContainer({
13832
14338
  cellMerge
13833
14339
  }) {
13834
14340
  const [editor] = useLexicalComposerContext43();
13835
- const menuButtonRef = useRef14(null);
13836
- const menuRootRef = useRef14(null);
13837
- const [isMenuOpen, setIsMenuOpen] = useState36(false);
13838
- const [tableCellNode, setTableMenuCellNode] = useState36(
14341
+ const menuButtonRef = useRef16(null);
14342
+ const menuRootRef = useRef16(null);
14343
+ const [isMenuOpen, setIsMenuOpen] = useState37(false);
14344
+ const [tableCellNode, setTableMenuCellNode] = useState37(
13839
14345
  null
13840
14346
  );
13841
14347
  const [colorPickerModal, showColorPickerModal] = useModal();
13842
- const checkTableCellOverflow = useCallback27(
14348
+ const checkTableCellOverflow = useCallback28(
13843
14349
  (tableCellParentNodeDOM) => {
13844
14350
  const scrollableContainer = tableCellParentNodeDOM.closest(
13845
14351
  ".PlaygroundEditorTheme__tableScrollableWrapper"
@@ -13857,7 +14363,7 @@ function TableCellActionMenuContainer({
13857
14363
  },
13858
14364
  []
13859
14365
  );
13860
- const $moveMenu = useCallback27(() => {
14366
+ const $moveMenu = useCallback28(() => {
13861
14367
  const menu = menuButtonRef.current;
13862
14368
  const selection = $getSelection17();
13863
14369
  const nativeSelection = getDOMSelection4(editor._window);
@@ -13984,7 +14490,7 @@ function TableCellActionMenuContainer({
13984
14490
  () => clearTimeout(timeoutId)
13985
14491
  );
13986
14492
  });
13987
- const prevTableCellDOM = useRef14(tableCellNode);
14493
+ const prevTableCellDOM = useRef16(tableCellNode);
13988
14494
  useEffect39(() => {
13989
14495
  if (prevTableCellDOM.current !== tableCellNode) {
13990
14496
  setIsMenuOpen(false);
@@ -14056,11 +14562,11 @@ import {
14056
14562
  SKIP_SCROLL_INTO_VIEW_TAG
14057
14563
  } from "lexical";
14058
14564
  import {
14059
- useCallback as useCallback28,
14565
+ useCallback as useCallback29,
14060
14566
  useEffect as useEffect40,
14061
14567
  useMemo as useMemo23,
14062
- useRef as useRef15,
14063
- useState as useState37
14568
+ useRef as useRef17,
14569
+ useState as useState38
14064
14570
  } from "react";
14065
14571
  import { createPortal as createPortal11 } from "react-dom";
14066
14572
  import { Fragment as Fragment16, jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
@@ -14068,16 +14574,16 @@ var MIN_ROW_HEIGHT = 33;
14068
14574
  var MIN_COLUMN_WIDTH = 92;
14069
14575
  var ACTIVE_RESIZER_COLOR = "#76b6ff";
14070
14576
  function TableCellResizer({ editor }) {
14071
- const targetRef = useRef15(null);
14072
- const resizerRef = useRef15(null);
14073
- const tableRectRef = useRef15(null);
14074
- const [hasTable, setHasTable] = useState37(false);
14075
- const pointerStartPosRef = useRef15(null);
14076
- const [pointerCurrentPos, updatePointerCurrentPos] = useState37(null);
14077
- const [activeCell, updateActiveCell] = useState37(null);
14078
- const [draggingDirection, updateDraggingDirection] = useState37(null);
14079
- const [hoveredDirection, updateHoveredDirection] = useState37(null);
14080
- const resetState = useCallback28(() => {
14577
+ const targetRef = useRef17(null);
14578
+ const resizerRef = useRef17(null);
14579
+ const tableRectRef = useRef17(null);
14580
+ const [hasTable, setHasTable] = useState38(false);
14581
+ const pointerStartPosRef = useRef17(null);
14582
+ const [pointerCurrentPos, updatePointerCurrentPos] = useState38(null);
14583
+ const [activeCell, updateActiveCell] = useState38(null);
14584
+ const [draggingDirection, updateDraggingDirection] = useState38(null);
14585
+ const [hoveredDirection, updateHoveredDirection] = useState38(null);
14586
+ const resetState = useCallback29(() => {
14081
14587
  updateActiveCell(null);
14082
14588
  targetRef.current = null;
14083
14589
  updateDraggingDirection(null);
@@ -14188,7 +14694,7 @@ function TableCellResizer({ editor }) {
14188
14694
  }
14189
14695
  return false;
14190
14696
  };
14191
- const updateRowHeight = useCallback28(
14697
+ const updateRowHeight = useCallback29(
14192
14698
  (heightChange) => {
14193
14699
  if (!activeCell) {
14194
14700
  throw new Error("TableCellResizer: Expected active cell.");
@@ -14241,7 +14747,7 @@ function TableCellResizer({ editor }) {
14241
14747
  }
14242
14748
  }
14243
14749
  };
14244
- const updateColumnWidth = useCallback28(
14750
+ const updateColumnWidth = useCallback29(
14245
14751
  (widthChange) => {
14246
14752
  if (!activeCell) {
14247
14753
  throw new Error("TableCellResizer: Expected active cell.");
@@ -14280,7 +14786,7 @@ function TableCellResizer({ editor }) {
14280
14786
  },
14281
14787
  [activeCell, editor]
14282
14788
  );
14283
- const pointerUpHandler = useCallback28(
14789
+ const pointerUpHandler = useCallback29(
14284
14790
  (direction) => {
14285
14791
  const handler = (event) => {
14286
14792
  event.preventDefault();
@@ -14309,7 +14815,7 @@ function TableCellResizer({ editor }) {
14309
14815
  },
14310
14816
  [activeCell, resetState, updateColumnWidth, updateRowHeight]
14311
14817
  );
14312
- const toggleResize = useCallback28(
14818
+ const toggleResize = useCallback29(
14313
14819
  (direction) => (event) => {
14314
14820
  event.preventDefault();
14315
14821
  event.stopPropagation();
@@ -14326,7 +14832,7 @@ function TableCellResizer({ editor }) {
14326
14832
  },
14327
14833
  [activeCell, pointerUpHandler]
14328
14834
  );
14329
- const getResizers = useCallback28(() => {
14835
+ const getResizers = useCallback29(() => {
14330
14836
  if (activeCell) {
14331
14837
  const { height, width, top, left } = activeCell.elem.getBoundingClientRect();
14332
14838
  const zoom = calculateZoomLevel3(activeCell.elem);
@@ -14384,7 +14890,7 @@ function TableCellResizer({ editor }) {
14384
14890
  top: null
14385
14891
  };
14386
14892
  }, [activeCell, draggingDirection, hoveredDirection, pointerCurrentPos]);
14387
- const handlePointerEnter = useCallback28(
14893
+ const handlePointerEnter = useCallback29(
14388
14894
  (direction) => () => {
14389
14895
  if (!draggingDirection) {
14390
14896
  updateHoveredDirection(direction);
@@ -14392,7 +14898,7 @@ function TableCellResizer({ editor }) {
14392
14898
  },
14393
14899
  [draggingDirection]
14394
14900
  );
14395
- const handlePointerLeave = useCallback28(() => {
14901
+ const handlePointerLeave = useCallback29(() => {
14396
14902
  if (!draggingDirection) {
14397
14903
  updateHoveredDirection(null);
14398
14904
  }
@@ -14458,7 +14964,7 @@ import {
14458
14964
  $getSiblingCaret as $getSiblingCaret2,
14459
14965
  isHTMLElement as isHTMLElement5
14460
14966
  } from "lexical";
14461
- import { useEffect as useEffect41, useRef as useRef16, useState as useState38 } from "react";
14967
+ import { useEffect as useEffect41, useRef as useRef18, useState as useState39 } from "react";
14462
14968
  import { createPortal as createPortal12 } from "react-dom";
14463
14969
 
14464
14970
  // src/utils/getThemeSelector.ts
@@ -14562,31 +15068,31 @@ function TableHoverActionsV2({
14562
15068
  }) {
14563
15069
  const [editor, { getTheme }] = useLexicalComposerContext45();
14564
15070
  const isEditable = useLexicalEditable9();
14565
- const [isVisible, setIsVisible] = useState38(false);
14566
- const [isLeftVisible, setIsLeftVisible] = useState38(false);
14567
- const virtualRef = useRef16({
15071
+ const [isVisible, setIsVisible] = useState39(false);
15072
+ const [isLeftVisible, setIsLeftVisible] = useState39(false);
15073
+ const virtualRef = useRef18({
14568
15074
  getBoundingClientRect: () => new DOMRect()
14569
15075
  });
14570
- const leftVirtualRef = useRef16({
15076
+ const leftVirtualRef = useRef18({
14571
15077
  getBoundingClientRect: () => new DOMRect()
14572
15078
  });
14573
- const floatingElemRef = useRef16(null);
14574
- const leftFloatingElemRef = useRef16(null);
14575
- const dragHandleRef = useRef16(null);
14576
- const hoveredLeftCellRef = useRef16(null);
14577
- const hoveredTopCellRef = useRef16(null);
14578
- const handleMouseLeaveRef = useRef16(
15079
+ const floatingElemRef = useRef18(null);
15080
+ const leftFloatingElemRef = useRef18(null);
15081
+ const dragHandleRef = useRef18(null);
15082
+ const hoveredLeftCellRef = useRef18(null);
15083
+ const hoveredTopCellRef = useRef18(null);
15084
+ const handleMouseLeaveRef = useRef18(
14579
15085
  null
14580
15086
  );
14581
- const dropIndicatorCleanupRef = useRef16([]);
14582
- const [hoveredTable, setHoveredTable] = useState38(
15087
+ const dropIndicatorCleanupRef = useRef18([]);
15088
+ const [hoveredTable, setHoveredTable] = useState39(
14583
15089
  null
14584
15090
  );
14585
- const [hoveredColumnIndex, setHoveredColumnIndex] = useState38(
15091
+ const [hoveredColumnIndex, setHoveredColumnIndex] = useState39(
14586
15092
  null
14587
15093
  );
14588
- const [canReorder, setCanReorder] = useState38(false);
14589
- const [dropIndicatorState, setDropIndicatorState] = useState38(null);
15094
+ const [canReorder, setCanReorder] = useState39(false);
15095
+ const [dropIndicatorState, setDropIndicatorState] = useState39(null);
14590
15096
  const { refs, floatingStyles, update } = useFloating({
14591
15097
  middleware: [
14592
15098
  offset({ mainAxis: -TOP_BUTTON_OVERHANG }),
@@ -15011,7 +15517,7 @@ function TableHoverActionsV2Plugin({
15011
15517
  // src/plugins/TableOfContentsPlugin/index.tsx
15012
15518
  import { useLexicalComposerContext as useLexicalComposerContext46 } from "@lexical/react/LexicalComposerContext";
15013
15519
  import { TableOfContentsPlugin as LexicalTableOfContentsPlugin } from "@lexical/react/LexicalTableOfContentsPlugin";
15014
- import { useEffect as useEffect42, useRef as useRef17, useState as useState39 } from "react";
15520
+ import { useEffect as useEffect42, useRef as useRef19, useState as useState40 } from "react";
15015
15521
  import { jsx as jsx47, jsxs as jsxs35 } from "react/jsx-runtime";
15016
15522
  var MARGIN_ABOVE_EDITOR = 624;
15017
15523
  var HEADING_WIDTH = 9;
@@ -15037,8 +15543,8 @@ function isHeadingBelowTheTopOfThePage(element) {
15037
15543
  function TableOfContentsList({
15038
15544
  tableOfContents
15039
15545
  }) {
15040
- const [selectedKey, setSelectedKey] = useState39("");
15041
- const selectedIndex = useRef17(0);
15546
+ const [selectedKey, setSelectedKey] = useState40("");
15547
+ const selectedIndex = useRef19(0);
15042
15548
  const [editor] = useLexicalComposerContext46();
15043
15549
  function scrollToNode(key, currIndex) {
15044
15550
  editor.getEditorState().read(() => {
@@ -15303,7 +15809,7 @@ import {
15303
15809
  SKIP_SELECTION_FOCUS_TAG as SKIP_SELECTION_FOCUS_TAG2,
15304
15810
  UNDO_COMMAND as UNDO_COMMAND2
15305
15811
  } from "lexical";
15306
- import { useCallback as useCallback29, useEffect as useEffect45, useState as useState41 } from "react";
15812
+ import { useCallback as useCallback30, useEffect as useEffect45, useState as useState42 } from "react";
15307
15813
 
15308
15814
  // src/ui/DropdownColorPicker.tsx
15309
15815
  import { jsx as jsx48 } from "react/jsx-runtime";
@@ -15737,7 +16243,7 @@ function FontDropDown({
15737
16243
  style,
15738
16244
  disabled = false
15739
16245
  }) {
15740
- const handleClick = useCallback29(
16246
+ const handleClick = useCallback30(
15741
16247
  (option) => {
15742
16248
  editor.update(() => {
15743
16249
  $addUpdateTag3(SKIP_SELECTION_FOCUS_TAG2);
@@ -15943,11 +16449,11 @@ function ToolbarPlugin({
15943
16449
  setActiveEditor,
15944
16450
  setIsLinkEditMode
15945
16451
  }) {
15946
- const [selectedElementKey, setSelectedElementKey] = useState41(
16452
+ const [selectedElementKey, setSelectedElementKey] = useState42(
15947
16453
  null
15948
16454
  );
15949
16455
  const [modal, showModal] = useModal();
15950
- const [isEditable, setIsEditable] = useState41(() => editor.isEditable());
16456
+ const [isEditable, setIsEditable] = useState42(() => editor.isEditable());
15951
16457
  const { toolbarState, updateToolbarState } = useToolbarState();
15952
16458
  const dispatchToolbarCommand = (command, payload = void 0, skipRefocus = false) => {
15953
16459
  activeEditor.update(() => {
@@ -15958,7 +16464,7 @@ function ToolbarPlugin({
15958
16464
  });
15959
16465
  };
15960
16466
  const dispatchFormatTextCommand = (payload, skipRefocus = false) => dispatchToolbarCommand(FORMAT_TEXT_COMMAND3, payload, skipRefocus);
15961
- const $handleHeadingNode = useCallback29(
16467
+ const $handleHeadingNode = useCallback30(
15962
16468
  (selectedElement) => {
15963
16469
  const type = $isHeadingNode2(selectedElement) ? selectedElement.getTag() : selectedElement.getType();
15964
16470
  if (type in blockTypeToBlockName) {
@@ -15973,7 +16479,7 @@ function ToolbarPlugin({
15973
16479
  const {
15974
16480
  settings: { isCodeHighlighted, isCodeShiki }
15975
16481
  } = useSettings();
15976
- const $handleCodeNode = useCallback29(
16482
+ const $handleCodeNode = useCallback30(
15977
16483
  (element) => {
15978
16484
  if ($isCodeNode6(element)) {
15979
16485
  const language = element.getLanguage();
@@ -15989,7 +16495,7 @@ function ToolbarPlugin({
15989
16495
  },
15990
16496
  [updateToolbarState, isCodeHighlighted, isCodeShiki]
15991
16497
  );
15992
- const $updateToolbar = useCallback29(() => {
16498
+ const $updateToolbar = useCallback30(() => {
15993
16499
  const selection = $getSelection18();
15994
16500
  if ($isRangeSelection16(selection)) {
15995
16501
  if (activeEditor !== editor && $isEditorIsNestedEditor(activeEditor)) {
@@ -16162,7 +16668,7 @@ function ToolbarPlugin({
16162
16668
  )
16163
16669
  );
16164
16670
  }, [$updateToolbar, activeEditor, editor, updateToolbarState]);
16165
- const applyStyleText = useCallback29(
16671
+ const applyStyleText = useCallback30(
16166
16672
  (styles, skipHistoryStack, skipRefocus = false) => {
16167
16673
  activeEditor.update(
16168
16674
  () => {
@@ -16179,13 +16685,13 @@ function ToolbarPlugin({
16179
16685
  },
16180
16686
  [activeEditor]
16181
16687
  );
16182
- const onFontColorSelect = useCallback29(
16688
+ const onFontColorSelect = useCallback30(
16183
16689
  (value, skipHistoryStack, skipRefocus) => {
16184
16690
  applyStyleText({ color: value }, skipHistoryStack, skipRefocus);
16185
16691
  },
16186
16692
  [applyStyleText]
16187
16693
  );
16188
- const onBgColorSelect = useCallback29(
16694
+ const onBgColorSelect = useCallback30(
16189
16695
  (value, skipHistoryStack, skipRefocus) => {
16190
16696
  applyStyleText(
16191
16697
  { "background-color": value },
@@ -16195,7 +16701,7 @@ function ToolbarPlugin({
16195
16701
  },
16196
16702
  [applyStyleText]
16197
16703
  );
16198
- const insertLink = useCallback29(() => {
16704
+ const insertLink = useCallback30(() => {
16199
16705
  if (!toolbarState.isLink) {
16200
16706
  setIsLinkEditMode(true);
16201
16707
  activeEditor.dispatchCommand(
@@ -16207,7 +16713,7 @@ function ToolbarPlugin({
16207
16713
  activeEditor.dispatchCommand(TOGGLE_LINK_COMMAND6, null);
16208
16714
  }
16209
16715
  }, [activeEditor, setIsLinkEditMode, toolbarState.isLink]);
16210
- const onCodeLanguageSelect = useCallback29(
16716
+ const onCodeLanguageSelect = useCallback30(
16211
16717
  (value) => {
16212
16718
  activeEditor.update(() => {
16213
16719
  $addUpdateTag3(SKIP_SELECTION_FOCUS_TAG2);
@@ -16221,7 +16727,7 @@ function ToolbarPlugin({
16221
16727
  },
16222
16728
  [activeEditor, selectedElementKey]
16223
16729
  );
16224
- const onCodeThemeSelect = useCallback29(
16730
+ const onCodeThemeSelect = useCallback30(
16225
16731
  (value) => {
16226
16732
  activeEditor.update(() => {
16227
16733
  if (selectedElementKey !== null) {
@@ -16955,11 +17461,11 @@ function Editor({ placeholder: placeholderProp, maxLength }) {
16955
17461
  } = useSettings();
16956
17462
  const isEditable = useLexicalEditable10();
16957
17463
  const placeholder = placeholderProp ?? (isRichText ? "Enter some rich text..." : "Enter some plain text...");
16958
- const [floatingAnchorElem, setFloatingAnchorElem] = useState42(null);
16959
- const [isSmallWidthViewport, setIsSmallWidthViewport] = useState42(false);
17464
+ const [floatingAnchorElem, setFloatingAnchorElem] = useState43(null);
17465
+ const [isSmallWidthViewport, setIsSmallWidthViewport] = useState43(false);
16960
17466
  const [editor] = useLexicalComposerContext49();
16961
- const [activeEditor, setActiveEditor] = useState42(editor);
16962
- const [isLinkEditMode, setIsLinkEditMode] = useState42(false);
17467
+ const [activeEditor, setActiveEditor] = useState43(editor);
17468
+ const [isLinkEditMode, setIsLinkEditMode] = useState43(false);
16963
17469
  const onRef = (_floatingAnchorElem) => {
16964
17470
  if (_floatingAnchorElem !== null) {
16965
17471
  setFloatingAnchorElem(_floatingAnchorElem);
@@ -17289,9 +17795,9 @@ function HtmlPlugin({
17289
17795
  debounceMs = 300
17290
17796
  }) {
17291
17797
  const [editor] = useLexicalComposerContext50();
17292
- const lastSyncedValue = useRef18(null);
17293
- const hasUserEdited = useRef18(false);
17294
- const debounceTimer = useRef18(null);
17798
+ const lastSyncedValue = useRef20(null);
17799
+ const hasUserEdited = useRef20(false);
17800
+ const debounceTimer = useRef20(null);
17295
17801
  useEffect48(() => {
17296
17802
  return editor.registerCommand(
17297
17803
  FOCUS_COMMAND2,
@@ -17341,7 +17847,7 @@ function HtmlPlugin({
17341
17847
  { tag: "historic" }
17342
17848
  );
17343
17849
  }, [editor, value]);
17344
- const handleChange = useCallback30(
17850
+ const handleChange = useCallback31(
17345
17851
  (_editorState, _editor, tags) => {
17346
17852
  if (!tags.has("historic")) {
17347
17853
  hasUserEdited.current = true;
@@ -17392,7 +17898,7 @@ function LexicalEditor20({
17392
17898
  readOnly,
17393
17899
  maxLength
17394
17900
  }) {
17395
- const [isFullscreen, setIsFullscreen] = useState43(false);
17901
+ const [isFullscreen, setIsFullscreen] = useState44(false);
17396
17902
  const initialConfig = {
17397
17903
  namespace: "LexicalEditor",
17398
17904
  nodes: [...PlaygroundNodes_default],
@@ -17421,7 +17927,7 @@ function LexicalEditor20({
17421
17927
  document.addEventListener("keydown", handleEsc);
17422
17928
  return () => document.removeEventListener("keydown", handleEsc);
17423
17929
  }, [isFullscreen]);
17424
- const toggleFullscreen = useCallback30(
17930
+ const toggleFullscreen = useCallback31(
17425
17931
  () => setIsFullscreen((f) => !f),
17426
17932
  []
17427
17933
  );