@baasix/lexical 0.0.10 → 0.0.12

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
 
@@ -8397,7 +8576,7 @@ function NotesComponent({
8397
8576
  setIsEditing(false);
8398
8577
  }, []);
8399
8578
  return /* @__PURE__ */ jsx23(BlockWithAlignableContents4, { className, format, nodeKey, children: /* @__PURE__ */ jsxs13("div", { style: { position: "relative" }, children: [
8400
- isEditable && !isEditing && /* @__PURE__ */ jsx23(
8579
+ isEditable && /* @__PURE__ */ jsx23(
8401
8580
  "button",
8402
8581
  {
8403
8582
  type: "button",
@@ -8422,37 +8601,13 @@ function NotesComponent({
8422
8601
  children: "Edit Notes"
8423
8602
  }
8424
8603
  ),
8425
- isEditing ? /* @__PURE__ */ jsxs13("div", { style: { border: "1px solid #ccc", borderRadius: 4, padding: 8, background: "#f9f9f9" }, children: [
8426
- /* @__PURE__ */ jsxs13("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
8427
- /* @__PURE__ */ jsx23("span", { style: { fontSize: 13, fontWeight: 600, color: CARD_STYLES.notes.headingColor }, children: "Edit Notes" }),
8428
- /* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 4 }, children: [
8429
- /* @__PURE__ */ jsx23(
8430
- "button",
8431
- {
8432
- type: "button",
8433
- onClick: cancelEdit,
8434
- style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
8435
- children: "Cancel"
8436
- }
8437
- ),
8438
- /* @__PURE__ */ jsx23(
8439
- "button",
8440
- {
8441
- type: "button",
8442
- onClick: saveChanges,
8443
- disabled: !preview,
8444
- style: { padding: "2px 10px", fontSize: 12, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
8445
- children: "Save"
8446
- }
8447
- )
8448
- ] })
8449
- ] }),
8604
+ /* @__PURE__ */ jsx23("div", { dangerouslySetInnerHTML: { __html: html } }),
8605
+ isEditing && /* @__PURE__ */ jsx23(Modal, { onClose: cancelEdit, title: "Edit Notes", children: /* @__PURE__ */ jsxs13("div", { style: { minWidth: 500 }, children: [
8450
8606
  /* @__PURE__ */ jsx23(
8451
8607
  "textarea",
8452
8608
  {
8453
8609
  value: editText,
8454
8610
  onChange: (e) => setEditText(e.target.value),
8455
- onMouseDown: (e) => e.stopPropagation(),
8456
8611
  style: {
8457
8612
  width: "100%",
8458
8613
  minHeight: 150,
@@ -8465,11 +8620,15 @@ function NotesComponent({
8465
8620
  }
8466
8621
  }
8467
8622
  ),
8468
- preview && /* @__PURE__ */ jsxs13("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" }, children: [
8623
+ preview && /* @__PURE__ */ jsxs13("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff", maxHeight: 200, overflow: "auto" }, children: [
8469
8624
  /* @__PURE__ */ jsx23("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
8470
8625
  /* @__PURE__ */ jsx23("div", { dangerouslySetInnerHTML: { __html: preview } })
8626
+ ] }),
8627
+ /* @__PURE__ */ jsxs13("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }, children: [
8628
+ /* @__PURE__ */ jsx23("button", { type: "button", onClick: cancelEdit, style: { padding: "6px 16px", fontSize: 13, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" }, children: "Cancel" }),
8629
+ /* @__PURE__ */ jsx23("button", { type: "button", onClick: saveChanges, disabled: !preview, style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 }, children: "Save" })
8471
8630
  ] })
8472
- ] }) : /* @__PURE__ */ jsx23("div", { dangerouslySetInnerHTML: { __html: html } })
8631
+ ] }) })
8473
8632
  ] }) });
8474
8633
  }
8475
8634
  var DATA_ATTR = "data-lexical-notes";
@@ -8569,27 +8728,95 @@ function NotesPlugin() {
8569
8728
  }, [editor]);
8570
8729
  return null;
8571
8730
  }
8731
+ function convertRichHtmlToNotes(htmlStr, baasixClient, folder) {
8732
+ return new Promise(async (resolve) => {
8733
+ const parser = new DOMParser();
8734
+ const doc = parser.parseFromString(htmlStr, "text/html");
8735
+ if (baasixClient) {
8736
+ const imgs = doc.querySelectorAll("img");
8737
+ for (let i = 0; i < imgs.length; i++) {
8738
+ const img2 = imgs[i];
8739
+ const src = img2.getAttribute("src") || "";
8740
+ if (src.startsWith("data:")) {
8741
+ try {
8742
+ const resp = await fetch(src);
8743
+ const blob = await resp.blob();
8744
+ const ext = blob.type.split("/")[1] || "png";
8745
+ const file = new File([blob], `note-image-${i}.${ext}`, { type: blob.type });
8746
+ const uploadedUrl = await uploadImageToBaasix(baasixClient, file, folder);
8747
+ img2.setAttribute("src", uploadedUrl);
8748
+ } catch {
8749
+ }
8750
+ }
8751
+ }
8752
+ }
8753
+ let html = `<div style="font-family: sans-serif; line-height: 1.6; color: inherit;">`;
8754
+ const children = Array.from(doc.body.childNodes);
8755
+ for (const child of children) {
8756
+ html += processNode(child);
8757
+ }
8758
+ html += "</div>";
8759
+ resolve(html.replace(/>\s+</g, "><"));
8760
+ });
8761
+ }
8572
8762
  function InsertNotesDialog({
8573
8763
  activeEditor,
8574
8764
  onClose
8575
8765
  }) {
8576
8766
  const [input, setInput] = useState18("");
8577
- const preview = useMemo8(() => {
8767
+ const [richHtml, setRichHtml] = useState18("");
8768
+ const [isUploading, setIsUploading] = useState18(false);
8769
+ const pasteAreaRef = useRef9(null);
8770
+ let editorConfig = null;
8771
+ try {
8772
+ editorConfig = useEditorConfig();
8773
+ } catch {
8774
+ }
8775
+ const handleRichPaste = useCallback12(async (e) => {
8776
+ e.preventDefault();
8777
+ const clipboardData = e.clipboardData;
8778
+ const htmlData = clipboardData.getData("text/html");
8779
+ const textData = clipboardData.getData("text/plain");
8780
+ if (htmlData) {
8781
+ setIsUploading(true);
8782
+ try {
8783
+ const processed = await convertRichHtmlToNotes(
8784
+ htmlData,
8785
+ editorConfig?.baasixClient,
8786
+ editorConfig?.folder
8787
+ );
8788
+ setRichHtml(processed);
8789
+ setInput("");
8790
+ } finally {
8791
+ setIsUploading(false);
8792
+ }
8793
+ } else if (textData) {
8794
+ setInput((prev) => prev ? prev + "\n" + textData : textData);
8795
+ }
8796
+ if (pasteAreaRef.current) {
8797
+ pasteAreaRef.current.innerHTML = '<span style="color: #9ca3af; pointer-events: none; user-select: none;">Paste from Word/Docs here (preserves formatting)</span>';
8798
+ }
8799
+ }, [editorConfig]);
8800
+ const finalHtml = useMemo8(() => {
8801
+ if (richHtml) return richHtml;
8578
8802
  if (!input.trim()) return "";
8579
8803
  return convertNotes(input);
8580
- }, [input]);
8804
+ }, [input, richHtml]);
8581
8805
  const handleInsert = useCallback12(() => {
8582
- if (!preview) return;
8583
- activeEditor.dispatchCommand(INSERT_NOTES_COMMAND, preview);
8806
+ if (!finalHtml) return;
8807
+ activeEditor.dispatchCommand(INSERT_NOTES_COMMAND, finalHtml);
8584
8808
  onClose();
8585
- }, [activeEditor, preview, onClose]);
8809
+ }, [activeEditor, finalHtml, onClose]);
8586
8810
  return /* @__PURE__ */ jsxs14("div", { style: { minWidth: 500 }, children: [
8587
8811
  /* @__PURE__ */ jsx24(
8588
8812
  "textarea",
8589
8813
  {
8590
8814
  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",
8815
+ onChange: (e) => {
8816
+ setInput(e.target.value);
8817
+ setRichHtml("");
8818
+ },
8819
+ 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
8820
  style: {
8594
8821
  width: "100%",
8595
8822
  minHeight: 120,
@@ -8603,9 +8830,33 @@ function InsertNotesDialog({
8603
8830
  }
8604
8831
  }
8605
8832
  ),
8606
- preview && /* @__PURE__ */ jsxs14("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 200, overflow: "auto" }, children: [
8833
+ /* @__PURE__ */ jsx24(
8834
+ "div",
8835
+ {
8836
+ ref: pasteAreaRef,
8837
+ contentEditable: true,
8838
+ onPaste: handleRichPaste,
8839
+ onMouseDown: (e) => e.stopPropagation(),
8840
+ style: {
8841
+ width: "100%",
8842
+ minHeight: 40,
8843
+ padding: 8,
8844
+ border: "2px dashed #93c5fd",
8845
+ borderRadius: 4,
8846
+ fontSize: 12,
8847
+ color: "#6b7280",
8848
+ marginBottom: 8,
8849
+ outline: "none",
8850
+ background: "#f0f7ff"
8851
+ },
8852
+ suppressContentEditableWarning: true,
8853
+ children: /* @__PURE__ */ jsx24("span", { style: { color: "#9ca3af", pointerEvents: "none", userSelect: "none" }, children: isUploading ? "Processing content..." : "Paste from Word/Docs here (preserves formatting)" })
8854
+ }
8855
+ ),
8856
+ richHtml && /* @__PURE__ */ jsx24("div", { style: { marginBottom: 8, fontSize: 11, color: "#16a34a" }, children: "Rich content captured (formatting preserved)" }),
8857
+ finalHtml && /* @__PURE__ */ jsxs14("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 200, overflow: "auto" }, children: [
8607
8858
  /* @__PURE__ */ jsx24("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
8608
- /* @__PURE__ */ jsx24("div", { dangerouslySetInnerHTML: { __html: preview } })
8859
+ /* @__PURE__ */ jsx24("div", { dangerouslySetInnerHTML: { __html: finalHtml } })
8609
8860
  ] }),
8610
8861
  /* @__PURE__ */ jsxs14("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
8611
8862
  /* @__PURE__ */ jsx24(
@@ -8622,9 +8873,9 @@ function InsertNotesDialog({
8622
8873
  {
8623
8874
  type: "button",
8624
8875
  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"
8876
+ disabled: !finalHtml || isUploading,
8877
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: finalHtml && !isUploading ? 1 : 0.5 },
8878
+ children: isUploading ? "Processing..." : "Insert"
8628
8879
  }
8629
8880
  )
8630
8881
  ] })
@@ -8743,7 +8994,7 @@ function RevisionComponent({
8743
8994
  setItems((prev) => prev.filter((_, i) => i !== index));
8744
8995
  }, []);
8745
8996
  return /* @__PURE__ */ jsx26(BlockWithAlignableContents5, { className, format, nodeKey, children: /* @__PURE__ */ jsxs16("div", { style: { position: "relative" }, children: [
8746
- isEditable && !isEditing && /* @__PURE__ */ jsx26(
8997
+ isEditable && /* @__PURE__ */ jsx26(
8747
8998
  "button",
8748
8999
  {
8749
9000
  type: "button",
@@ -8768,31 +9019,8 @@ function RevisionComponent({
8768
9019
  children: "Edit Revision"
8769
9020
  }
8770
9021
  ),
8771
- isEditing ? /* @__PURE__ */ jsxs16("div", { style: { border: "1px solid #ccc", borderRadius: 4, padding: 8, background: "#f9f9f9" }, children: [
8772
- /* @__PURE__ */ jsxs16("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
8773
- /* @__PURE__ */ jsx26("span", { style: { fontSize: 13, fontWeight: 600, color: "#c2703a" }, children: "Edit Revision Points" }),
8774
- /* @__PURE__ */ jsxs16("div", { style: { display: "flex", gap: 4 }, children: [
8775
- /* @__PURE__ */ jsx26(
8776
- "button",
8777
- {
8778
- type: "button",
8779
- onClick: cancelEdit,
8780
- style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
8781
- children: "Cancel"
8782
- }
8783
- ),
8784
- /* @__PURE__ */ jsx26(
8785
- "button",
8786
- {
8787
- type: "button",
8788
- onClick: saveChanges,
8789
- disabled: !preview,
8790
- style: { padding: "2px 10px", fontSize: 12, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
8791
- children: "Save"
8792
- }
8793
- )
8794
- ] })
8795
- ] }),
9022
+ /* @__PURE__ */ jsx26("div", { dangerouslySetInnerHTML: { __html: html } }),
9023
+ isEditing && /* @__PURE__ */ jsx26(Modal, { onClose: cancelEdit, title: "Edit Revision Points", children: /* @__PURE__ */ jsxs16("div", { style: { minWidth: 500 }, children: [
8796
9024
  items.map((item, index) => /* @__PURE__ */ jsxs16("div", { style: { display: "flex", gap: 4, marginBottom: 4, alignItems: "center" }, children: [
8797
9025
  /* @__PURE__ */ jsx26(
8798
9026
  "input",
@@ -8801,7 +9029,6 @@ function RevisionComponent({
8801
9029
  placeholder: "Revision point",
8802
9030
  value: item,
8803
9031
  onChange: (e) => updateItem(index, e.target.value),
8804
- onMouseDown: (e) => e.stopPropagation(),
8805
9032
  style: { flex: 1, padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4 }
8806
9033
  }
8807
9034
  ),
@@ -8824,11 +9051,15 @@ function RevisionComponent({
8824
9051
  children: "+ Add Point"
8825
9052
  }
8826
9053
  ),
8827
- preview && /* @__PURE__ */ jsxs16("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" }, children: [
9054
+ preview && /* @__PURE__ */ jsxs16("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff", maxHeight: 200, overflow: "auto" }, children: [
8828
9055
  /* @__PURE__ */ jsx26("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
8829
9056
  /* @__PURE__ */ jsx26("div", { dangerouslySetInnerHTML: { __html: preview } })
9057
+ ] }),
9058
+ /* @__PURE__ */ jsxs16("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }, children: [
9059
+ /* @__PURE__ */ jsx26("button", { type: "button", onClick: cancelEdit, style: { padding: "6px 16px", fontSize: 13, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" }, children: "Cancel" }),
9060
+ /* @__PURE__ */ jsx26("button", { type: "button", onClick: saveChanges, disabled: !preview, style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 }, children: "Save" })
8830
9061
  ] })
8831
- ] }) : /* @__PURE__ */ jsx26("div", { dangerouslySetInnerHTML: { __html: html } })
9062
+ ] }) })
8832
9063
  ] }) });
8833
9064
  }
8834
9065
  var DATA_ATTR2 = "data-lexical-revision";
@@ -9047,57 +9278,36 @@ function TerminologyComponent({
9047
9278
  const removeItem = useCallback15((index) => {
9048
9279
  setItems((prev) => prev.filter((_, i) => i !== index));
9049
9280
  }, []);
9050
- return /* @__PURE__ */ jsx28(BlockWithAlignableContents6, { className, format, nodeKey, children: /* @__PURE__ */ jsxs18("div", { style: { position: "relative" }, children: [
9051
- isEditable && !isEditing && /* @__PURE__ */ jsx28(
9052
- "button",
9053
- {
9054
- type: "button",
9055
- onClick: openEditor,
9056
- onMouseDown: (e) => e.preventDefault(),
9057
- style: {
9058
- position: "absolute",
9059
- top: 4,
9060
- right: 4,
9061
- zIndex: 10,
9062
- background: CARD_STYLES.terminology.keyColor,
9063
- color: "#fff",
9064
- border: "none",
9065
- borderRadius: 4,
9066
- padding: "2px 8px",
9067
- fontSize: 12,
9068
- cursor: "pointer",
9069
- opacity: 0,
9070
- transition: "opacity 0.15s"
9071
- },
9072
- className: "html-block-edit-btn",
9073
- children: "Edit Terminology"
9074
- }
9075
- ),
9076
- isEditing ? /* @__PURE__ */ jsxs18("div", { style: { border: "1px solid #ccc", borderRadius: 4, padding: 8, background: "#f9f9f9" }, children: [
9077
- /* @__PURE__ */ jsxs18("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
9078
- /* @__PURE__ */ jsx28("span", { style: { fontSize: 13, fontWeight: 600, color: CARD_STYLES.terminology.keyColor }, children: "Edit Terminology" }),
9079
- /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: 4 }, children: [
9080
- /* @__PURE__ */ jsx28(
9081
- "button",
9082
- {
9083
- type: "button",
9084
- onClick: cancelEdit,
9085
- style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
9086
- children: "Cancel"
9087
- }
9088
- ),
9089
- /* @__PURE__ */ jsx28(
9090
- "button",
9091
- {
9092
- type: "button",
9093
- onClick: saveChanges,
9094
- disabled: !preview,
9095
- style: { padding: "2px 10px", fontSize: 12, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
9096
- children: "Save"
9097
- }
9098
- )
9099
- ] })
9100
- ] }),
9281
+ return /* @__PURE__ */ jsxs18(BlockWithAlignableContents6, { className, format, nodeKey, children: [
9282
+ /* @__PURE__ */ jsxs18("div", { style: { position: "relative" }, children: [
9283
+ isEditable && /* @__PURE__ */ jsx28(
9284
+ "button",
9285
+ {
9286
+ type: "button",
9287
+ onClick: openEditor,
9288
+ onMouseDown: (e) => e.preventDefault(),
9289
+ style: {
9290
+ position: "absolute",
9291
+ top: 4,
9292
+ right: 4,
9293
+ zIndex: 10,
9294
+ background: CARD_STYLES.terminology.keyColor,
9295
+ color: "#fff",
9296
+ border: "none",
9297
+ borderRadius: 4,
9298
+ padding: "2px 8px",
9299
+ fontSize: 12,
9300
+ cursor: "pointer",
9301
+ opacity: 0,
9302
+ transition: "opacity 0.15s"
9303
+ },
9304
+ className: "html-block-edit-btn",
9305
+ children: "Edit Terminology"
9306
+ }
9307
+ ),
9308
+ /* @__PURE__ */ jsx28("div", { dangerouslySetInnerHTML: { __html: html } })
9309
+ ] }),
9310
+ isEditing && /* @__PURE__ */ jsx28(Modal, { onClose: cancelEdit, title: "Edit Terminology", children: /* @__PURE__ */ jsxs18("div", { style: { minWidth: 500 }, children: [
9101
9311
  items.map((item, index) => /* @__PURE__ */ jsxs18("div", { style: { display: "flex", gap: 4, marginBottom: 4, alignItems: "center" }, children: [
9102
9312
  /* @__PURE__ */ jsx28(
9103
9313
  "input",
@@ -9106,7 +9316,6 @@ function TerminologyComponent({
9106
9316
  placeholder: "Term",
9107
9317
  value: item.term,
9108
9318
  onChange: (e) => updateItem(index, "term", e.target.value),
9109
- onMouseDown: (e) => e.stopPropagation(),
9110
9319
  style: { width: "30%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4 }
9111
9320
  }
9112
9321
  ),
@@ -9117,7 +9326,6 @@ function TerminologyComponent({
9117
9326
  placeholder: "Definition",
9118
9327
  value: item.definition,
9119
9328
  onChange: (e) => updateItem(index, "definition", e.target.value),
9120
- onMouseDown: (e) => e.stopPropagation(),
9121
9329
  style: { flex: 1, padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4 }
9122
9330
  }
9123
9331
  ),
@@ -9136,16 +9344,37 @@ function TerminologyComponent({
9136
9344
  {
9137
9345
  type: "button",
9138
9346
  onClick: addItem,
9139
- style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, background: "#fff", cursor: "pointer", marginTop: 4 },
9347
+ style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, background: "#fff", cursor: "pointer", marginTop: 4, marginBottom: 8 },
9140
9348
  children: "+ Add Term"
9141
9349
  }
9142
9350
  ),
9143
- preview && /* @__PURE__ */ jsxs18("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" }, children: [
9351
+ preview && /* @__PURE__ */ jsxs18("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff", maxHeight: 200, overflow: "auto" }, children: [
9144
9352
  /* @__PURE__ */ jsx28("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
9145
9353
  /* @__PURE__ */ jsx28("div", { dangerouslySetInnerHTML: { __html: preview } })
9354
+ ] }),
9355
+ /* @__PURE__ */ jsxs18("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
9356
+ /* @__PURE__ */ jsx28(
9357
+ "button",
9358
+ {
9359
+ type: "button",
9360
+ onClick: cancelEdit,
9361
+ style: { padding: "6px 16px", fontSize: 13, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
9362
+ children: "Cancel"
9363
+ }
9364
+ ),
9365
+ /* @__PURE__ */ jsx28(
9366
+ "button",
9367
+ {
9368
+ type: "button",
9369
+ onClick: saveChanges,
9370
+ disabled: !preview,
9371
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
9372
+ children: "Save"
9373
+ }
9374
+ )
9146
9375
  ] })
9147
- ] }) : /* @__PURE__ */ jsx28("div", { dangerouslySetInnerHTML: { __html: html } })
9148
- ] }) });
9376
+ ] }) })
9377
+ ] });
9149
9378
  }
9150
9379
  var DATA_ATTR3 = "data-lexical-terminology";
9151
9380
  var TerminologyNode = class _TerminologyNode extends DecoratorBlockNode6 {
@@ -9310,7 +9539,7 @@ function InsertTerminologyDialog({
9310
9539
  import { useLexicalComposerContext as useLexicalComposerContext28 } from "@lexical/react/LexicalComposerContext";
9311
9540
  import { $insertNodeToNearestRoot as $insertNodeToNearestRoot10 } from "@lexical/utils";
9312
9541
  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";
9542
+ import { useCallback as useCallback19, useEffect as useEffect27, useMemo as useMemo14, useState as useState26 } from "react";
9314
9543
 
9315
9544
  // src/nodes/TextCardsNode.tsx
9316
9545
  import { $getNodeByKey as $getNodeByKey7 } from "lexical";
@@ -9419,7 +9648,7 @@ function TextCardsComponent({
9419
9648
  }, []);
9420
9649
  const styles = CARD_STYLES.textCards;
9421
9650
  return /* @__PURE__ */ jsx30(BlockWithAlignableContents7, { className, format, nodeKey, children: /* @__PURE__ */ jsxs20("div", { style: { position: "relative" }, children: [
9422
- isEditable && !isEditing && /* @__PURE__ */ jsx30(
9651
+ isEditable && /* @__PURE__ */ jsx30(
9423
9652
  "button",
9424
9653
  {
9425
9654
  type: "button",
@@ -9444,31 +9673,8 @@ function TextCardsComponent({
9444
9673
  children: "Edit Text Cards"
9445
9674
  }
9446
9675
  ),
9447
- isEditing ? /* @__PURE__ */ jsxs20("div", { style: { border: "1px solid #ccc", borderRadius: 4, padding: 8, background: "#f9f9f9" }, children: [
9448
- /* @__PURE__ */ jsxs20("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
9449
- /* @__PURE__ */ jsx30("span", { style: { fontSize: 13, fontWeight: 600, color: "rgba(76, 175, 80, 0.8)" }, children: "Edit Text Cards" }),
9450
- /* @__PURE__ */ jsxs20("div", { style: { display: "flex", gap: 4 }, children: [
9451
- /* @__PURE__ */ jsx30(
9452
- "button",
9453
- {
9454
- type: "button",
9455
- onClick: cancelEdit,
9456
- style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
9457
- children: "Cancel"
9458
- }
9459
- ),
9460
- /* @__PURE__ */ jsx30(
9461
- "button",
9462
- {
9463
- type: "button",
9464
- onClick: saveChanges,
9465
- disabled: !preview,
9466
- style: { padding: "2px 10px", fontSize: 12, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
9467
- children: "Save"
9468
- }
9469
- )
9470
- ] })
9471
- ] }),
9676
+ /* @__PURE__ */ jsx30("div", { dangerouslySetInnerHTML: { __html: html } }),
9677
+ isEditing && /* @__PURE__ */ jsx30(Modal, { onClose: cancelEdit, title: "Edit Text Cards", children: /* @__PURE__ */ jsxs20("div", { style: { minWidth: 500 }, children: [
9472
9678
  concepts.map((concept, cIdx) => /* @__PURE__ */ jsxs20("div", { style: { border: "1px solid #e5e7eb", borderRadius: 6, padding: 8, marginBottom: 8, background: "#fff" }, children: [
9473
9679
  /* @__PURE__ */ jsxs20("div", { style: { display: "flex", gap: 4, marginBottom: 6, alignItems: "center" }, children: [
9474
9680
  /* @__PURE__ */ jsxs20("span", { style: { fontSize: 12, fontWeight: 600, color: "#4caf50", minWidth: 80 }, children: [
@@ -9483,7 +9689,6 @@ function TextCardsComponent({
9483
9689
  placeholder: "Concept title",
9484
9690
  value: concept.conceptTitle,
9485
9691
  onChange: (e) => updateConceptTitle(cIdx, e.target.value),
9486
- onMouseDown: (e) => e.stopPropagation(),
9487
9692
  style: { flex: 1, padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4 }
9488
9693
  }
9489
9694
  ),
@@ -9508,7 +9713,6 @@ function TextCardsComponent({
9508
9713
  placeholder: `${label} content...`,
9509
9714
  value: section.content,
9510
9715
  onChange: (e) => updateSection(cIdx, sIdx, e.target.value),
9511
- onMouseDown: (e) => e.stopPropagation(),
9512
9716
  style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
9513
9717
  }
9514
9718
  )
@@ -9524,11 +9728,15 @@ function TextCardsComponent({
9524
9728
  children: "+ Add Concept"
9525
9729
  }
9526
9730
  ),
9527
- preview && /* @__PURE__ */ jsxs20("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" }, children: [
9731
+ preview && /* @__PURE__ */ jsxs20("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff", maxHeight: 200, overflow: "auto" }, children: [
9528
9732
  /* @__PURE__ */ jsx30("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
9529
9733
  /* @__PURE__ */ jsx30("div", { dangerouslySetInnerHTML: { __html: preview } })
9734
+ ] }),
9735
+ /* @__PURE__ */ jsxs20("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }, children: [
9736
+ /* @__PURE__ */ jsx30("button", { type: "button", onClick: cancelEdit, style: { padding: "6px 16px", fontSize: 13, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" }, children: "Cancel" }),
9737
+ /* @__PURE__ */ jsx30("button", { type: "button", onClick: saveChanges, disabled: !preview, style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 }, children: "Save" })
9530
9738
  ] })
9531
- ] }) : /* @__PURE__ */ jsx30("div", { dangerouslySetInnerHTML: { __html: html } })
9739
+ ] }) })
9532
9740
  ] }) });
9533
9741
  }
9534
9742
  var DATA_ATTR4 = "data-lexical-text-cards";
@@ -9605,6 +9813,134 @@ function $isTextCardsNode(node) {
9605
9813
  return node instanceof TextCardsNode;
9606
9814
  }
9607
9815
 
9816
+ // src/utils/useRichPaste.ts
9817
+ import { useCallback as useCallback18, useRef as useRef10, useState as useState25 } from "react";
9818
+ function useRichPaste(onText, baasixClient, folder) {
9819
+ const [images, setImages] = useState25([]);
9820
+ const [isUploading, setIsUploading] = useState25(false);
9821
+ const pasteAreaRef = useRef10(null);
9822
+ const extractImages = useCallback18(
9823
+ async (htmlStr) => {
9824
+ const parser = new DOMParser();
9825
+ const doc = parser.parseFromString(htmlStr, "text/html");
9826
+ const imgs = doc.querySelectorAll("img");
9827
+ const newImages = [];
9828
+ for (let i = 0; i < imgs.length; i++) {
9829
+ const img2 = imgs[i];
9830
+ const src = img2.getAttribute("src") || "";
9831
+ const placeholder = `__IMG_${Date.now()}_${i}__`;
9832
+ if (src.startsWith("data:") && baasixClient) {
9833
+ try {
9834
+ const resp = await fetch(src);
9835
+ const blob = await resp.blob();
9836
+ const ext = blob.type.split("/")[1] || "png";
9837
+ const file = new File([blob], `pasted-image-${i}.${ext}`, { type: blob.type });
9838
+ const uploadedUrl = await uploadImageToBaasix(baasixClient, file, folder);
9839
+ newImages.push({ placeholder, src: uploadedUrl });
9840
+ } catch {
9841
+ newImages.push({ placeholder, src });
9842
+ }
9843
+ } else if (src) {
9844
+ newImages.push({ placeholder, src });
9845
+ }
9846
+ }
9847
+ return newImages;
9848
+ },
9849
+ [baasixClient, folder]
9850
+ );
9851
+ const insertPlaceholders = useCallback18(
9852
+ (plainText, htmlStr, imgPlaceholders) => {
9853
+ if (imgPlaceholders.length === 0) return plainText;
9854
+ const parser = new DOMParser();
9855
+ const doc = parser.parseFromString(htmlStr, "text/html");
9856
+ const segments = [];
9857
+ let imgIdx = 0;
9858
+ const blockTags = /* @__PURE__ */ new Set(["P", "DIV", "LI", "TR", "H1", "H2", "H3", "H4", "H5", "H6", "BLOCKQUOTE", "PRE", "TABLE"]);
9859
+ const walkNode = (node) => {
9860
+ if (node.nodeType === Node.TEXT_NODE) {
9861
+ const t = (node.textContent || "").trim();
9862
+ if (t) segments.push({ type: "text", text: t });
9863
+ return;
9864
+ }
9865
+ if (node.nodeType !== Node.ELEMENT_NODE) return;
9866
+ const el = node;
9867
+ if (el.tagName === "IMG") {
9868
+ segments.push({ type: "img", idx: imgIdx++ });
9869
+ return;
9870
+ }
9871
+ for (const child of Array.from(el.childNodes)) walkNode(child);
9872
+ };
9873
+ walkNode(doc.body);
9874
+ const textCountBeforeImg = [];
9875
+ let textCount = 0;
9876
+ for (const seg of segments) {
9877
+ if (seg.type === "text") {
9878
+ textCount++;
9879
+ } else {
9880
+ textCountBeforeImg.push(textCount);
9881
+ }
9882
+ }
9883
+ const lines = plainText.split("\n");
9884
+ const nonEmptyLineIndices = [];
9885
+ for (let i = 0; i < lines.length; i++) {
9886
+ if (lines[i].trim()) nonEmptyLineIndices.push(i);
9887
+ }
9888
+ for (let i = textCountBeforeImg.length - 1; i >= 0; i--) {
9889
+ const placeholder = imgPlaceholders[i]?.placeholder;
9890
+ if (!placeholder) continue;
9891
+ const tc = textCountBeforeImg[i];
9892
+ const lineIdx = tc > 0 && tc <= nonEmptyLineIndices.length ? nonEmptyLineIndices[tc - 1] : nonEmptyLineIndices.length > 0 ? nonEmptyLineIndices[nonEmptyLineIndices.length - 1] : lines.length - 1;
9893
+ lines.splice(lineIdx + 1, 0, placeholder);
9894
+ for (let j = 0; j < nonEmptyLineIndices.length; j++) {
9895
+ if (nonEmptyLineIndices[j] > lineIdx) nonEmptyLineIndices[j]++;
9896
+ }
9897
+ }
9898
+ return lines.join("\n");
9899
+ },
9900
+ []
9901
+ );
9902
+ const handlePaste = useCallback18(
9903
+ async (e) => {
9904
+ e.preventDefault();
9905
+ const clipboardData = e.clipboardData;
9906
+ const htmlData = clipboardData.getData("text/html");
9907
+ const textData = clipboardData.getData("text/plain");
9908
+ if (htmlData && htmlData.includes("<img")) {
9909
+ setIsUploading(true);
9910
+ try {
9911
+ const processedImages = await extractImages(htmlData);
9912
+ let text = textData || "";
9913
+ text = insertPlaceholders(text, htmlData, processedImages);
9914
+ onText(text);
9915
+ setImages((prev) => [...prev, ...processedImages]);
9916
+ } finally {
9917
+ setIsUploading(false);
9918
+ }
9919
+ } else {
9920
+ onText(textData || "");
9921
+ }
9922
+ if (pasteAreaRef.current) {
9923
+ pasteAreaRef.current.textContent = "";
9924
+ }
9925
+ },
9926
+ [extractImages, insertPlaceholders, onText]
9927
+ );
9928
+ const replaceImagePlaceholders = useCallback18(
9929
+ (html) => {
9930
+ let result = html;
9931
+ images.forEach(({ placeholder, src }) => {
9932
+ result = result.replace(
9933
+ new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
9934
+ `<img src="${src}" style="max-width: 100%; border-radius: 8px; margin: 8px 0;" />`
9935
+ );
9936
+ });
9937
+ return result;
9938
+ },
9939
+ [images]
9940
+ );
9941
+ return { images, isUploading, pasteAreaRef, handlePaste, replaceImagePlaceholders };
9942
+ }
9943
+
9608
9944
  // src/plugins/TextCardsPlugin/index.tsx
9609
9945
  import { jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
9610
9946
  var INSERT_TEXT_CARDS_COMMAND = createCommand17(
@@ -9632,16 +9968,27 @@ function InsertTextCardsDialog({
9632
9968
  activeEditor,
9633
9969
  onClose
9634
9970
  }) {
9635
- const [input, setInput] = useState25("");
9636
- const preview = useMemo14(() => {
9971
+ const [input, setInput] = useState26("");
9972
+ let editorConfig = null;
9973
+ try {
9974
+ editorConfig = useEditorConfig();
9975
+ } catch {
9976
+ }
9977
+ const richPaste = useRichPaste(
9978
+ (text) => setInput((prev) => prev ? prev + "\n" + text : text),
9979
+ editorConfig?.baasixClient,
9980
+ editorConfig?.folder
9981
+ );
9982
+ const finalHtml = useMemo14(() => {
9637
9983
  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);
9984
+ const html = convertTextCards(input);
9985
+ return richPaste.replaceImagePlaceholders(html);
9986
+ }, [input, richPaste]);
9987
+ const handleInsert = useCallback19(() => {
9988
+ if (!finalHtml) return;
9989
+ activeEditor.dispatchCommand(INSERT_TEXT_CARDS_COMMAND, finalHtml);
9643
9990
  onClose();
9644
- }, [activeEditor, preview, onClose]);
9991
+ }, [activeEditor, finalHtml, onClose]);
9645
9992
  return /* @__PURE__ */ jsxs21("div", { style: { minWidth: 500 }, children: [
9646
9993
  /* @__PURE__ */ jsx31(
9647
9994
  "textarea",
@@ -9668,7 +10015,7 @@ Critical Insight
9668
10015
  Pathology bridges clinical suspicion with molecular certainty...`,
9669
10016
  style: {
9670
10017
  width: "100%",
9671
- minHeight: 180,
10018
+ minHeight: 150,
9672
10019
  fontFamily: "monospace",
9673
10020
  fontSize: 13,
9674
10021
  padding: 8,
@@ -9679,9 +10026,38 @@ Pathology bridges clinical suspicion with molecular certainty...`,
9679
10026
  }
9680
10027
  }
9681
10028
  ),
9682
- preview && /* @__PURE__ */ jsxs21("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
10029
+ /* @__PURE__ */ jsx31(
10030
+ "div",
10031
+ {
10032
+ ref: richPaste.pasteAreaRef,
10033
+ contentEditable: true,
10034
+ onPaste: richPaste.handlePaste,
10035
+ onMouseDown: (e) => e.stopPropagation(),
10036
+ style: {
10037
+ width: "100%",
10038
+ minHeight: 40,
10039
+ padding: 8,
10040
+ border: "2px dashed #93c5fd",
10041
+ borderRadius: 4,
10042
+ fontSize: 12,
10043
+ color: "#6b7280",
10044
+ marginBottom: 8,
10045
+ outline: "none",
10046
+ background: "#f0f7ff"
10047
+ },
10048
+ suppressContentEditableWarning: true,
10049
+ children: /* @__PURE__ */ jsx31("span", { style: { color: "#9ca3af", pointerEvents: "none", userSelect: "none" }, children: richPaste.isUploading ? "Uploading images..." : "Paste from Word/Docs here for image support" })
10050
+ }
10051
+ ),
10052
+ richPaste.images.length > 0 && /* @__PURE__ */ jsxs21("div", { style: { marginBottom: 8, fontSize: 11, color: "#16a34a" }, children: [
10053
+ richPaste.images.length,
10054
+ " image",
10055
+ richPaste.images.length > 1 ? "s" : "",
10056
+ " captured"
10057
+ ] }),
10058
+ finalHtml && /* @__PURE__ */ jsxs21("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
9683
10059
  /* @__PURE__ */ jsx31("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
9684
- /* @__PURE__ */ jsx31("div", { dangerouslySetInnerHTML: { __html: preview } })
10060
+ /* @__PURE__ */ jsx31("div", { dangerouslySetInnerHTML: { __html: finalHtml } })
9685
10061
  ] }),
9686
10062
  /* @__PURE__ */ jsxs21("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
9687
10063
  /* @__PURE__ */ jsx31(
@@ -9698,9 +10074,9 @@ Pathology bridges clinical suspicion with molecular certainty...`,
9698
10074
  {
9699
10075
  type: "button",
9700
10076
  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"
10077
+ disabled: !finalHtml || richPaste.isUploading,
10078
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: finalHtml && !richPaste.isUploading ? 1 : 0.5 },
10079
+ children: richPaste.isUploading ? "Uploading..." : "Insert"
9704
10080
  }
9705
10081
  )
9706
10082
  ] })
@@ -9711,7 +10087,7 @@ Pathology bridges clinical suspicion with molecular certainty...`,
9711
10087
  import { useLexicalComposerContext as useLexicalComposerContext30 } from "@lexical/react/LexicalComposerContext";
9712
10088
  import { $insertNodeToNearestRoot as $insertNodeToNearestRoot11 } from "@lexical/utils";
9713
10089
  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";
10090
+ import { useCallback as useCallback21, useEffect as useEffect28, useMemo as useMemo16, useState as useState28 } from "react";
9715
10091
 
9716
10092
  // src/nodes/QuestionsCardsNode.tsx
9717
10093
  import { $getNodeByKey as $getNodeByKey8 } from "lexical";
@@ -9721,7 +10097,7 @@ import {
9721
10097
  } from "@lexical/react/LexicalDecoratorBlockNode";
9722
10098
  import { useLexicalComposerContext as useLexicalComposerContext29 } from "@lexical/react/LexicalComposerContext";
9723
10099
  import { useLexicalEditable as useLexicalEditable5 } from "@lexical/react/useLexicalEditable";
9724
- import { useCallback as useCallback19, useMemo as useMemo15, useState as useState26 } from "react";
10100
+ import { useCallback as useCallback20, useMemo as useMemo15, useState as useState27 } from "react";
9725
10101
  import { jsx as jsx32, jsxs as jsxs22 } from "react/jsx-runtime";
9726
10102
  var GRID_SECTION_KEYS = [
9727
10103
  "rubric",
@@ -9742,44 +10118,45 @@ function QuestionsCardsComponent({
9742
10118
  }) {
9743
10119
  const [editor] = useLexicalComposerContext29();
9744
10120
  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(() => {
10121
+ const [isEditing, setIsEditing] = useState27(false);
10122
+ const [qaPairs, setQaPairs] = useState27([]);
10123
+ const makeEmptyQA = () => ({
10124
+ question: "",
10125
+ answer: "",
10126
+ sections: GRID_SECTION_KEYS.map((k) => ({ key: k, content: "" }))
10127
+ });
10128
+ const openEditor = useCallback20(() => {
9750
10129
  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: "" };
10130
+ const pairs = parsed.qaPairs.map((qa) => {
10131
+ const existing = qa.sections || [];
10132
+ const all = GRID_SECTION_KEYS.map((k) => {
10133
+ const found = existing.find((s) => s.key === k);
10134
+ return found || { key: k, content: "" };
10135
+ });
10136
+ return { question: qa.question, answer: qa.answer, sections: all };
9757
10137
  });
9758
- setSections(all);
10138
+ setQaPairs(pairs.length > 0 ? pairs : [makeEmptyQA()]);
9759
10139
  setIsEditing(true);
9760
10140
  }, [html]);
9761
10141
  const preview = useMemo15(() => {
9762
10142
  if (!isEditing) return "";
9763
- const styles2 = CARD_STYLES.questionsCards;
10143
+ const cStyles = CARD_STYLES.questionsCards;
9764
10144
  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
- }
10145
+ qaPairs.forEach((qa, idx) => {
10146
+ if (qa.question) lines.push(`${idx + 1}. Question: ${qa.question}`);
10147
+ if (qa.answer) lines.push(`Answer: ${qa.answer}`);
10148
+ qa.sections.forEach((s) => {
10149
+ const sStyle = cStyles[s.key];
10150
+ if (sStyle && "title" in sStyle && s.content) {
10151
+ lines.push(sStyle.title);
10152
+ lines.push(s.content);
10153
+ }
10154
+ });
9778
10155
  });
9779
10156
  const text = lines.join("\n");
9780
10157
  return text.trim() ? convertQuestionsCards(text) : "";
9781
- }, [isEditing, question, answer, sections]);
9782
- const saveChanges = useCallback19(() => {
10158
+ }, [isEditing, qaPairs]);
10159
+ const saveChanges = useCallback20(() => {
9783
10160
  if (!preview) return;
9784
10161
  editor.update(() => {
9785
10162
  const node = $getNodeByKey8(nodeKey);
@@ -9789,17 +10166,27 @@ function QuestionsCardsComponent({
9789
10166
  });
9790
10167
  setIsEditing(false);
9791
10168
  }, [editor, nodeKey, preview]);
9792
- const cancelEdit = useCallback19(() => {
10169
+ const cancelEdit = useCallback20(() => {
9793
10170
  setIsEditing(false);
9794
10171
  }, []);
9795
- const updateSection = useCallback19((idx, value) => {
9796
- setSections(
9797
- (prev) => prev.map((s, i) => i === idx ? { ...s, content: value } : s)
9798
- );
10172
+ const updateQA = useCallback20((idx, field, value) => {
10173
+ setQaPairs((prev) => prev.map((qa, i) => i === idx ? { ...qa, [field]: value } : qa));
10174
+ }, []);
10175
+ const addQAPair = useCallback20(() => {
10176
+ setQaPairs((prev) => [...prev, makeEmptyQA()]);
10177
+ }, []);
10178
+ const removeQAPair = useCallback20((idx) => {
10179
+ setQaPairs((prev) => prev.filter((_, i) => i !== idx));
10180
+ }, []);
10181
+ const updateSection = useCallback20((qIdx, sIdx, value) => {
10182
+ setQaPairs((prev) => prev.map((qa, i) => {
10183
+ if (i !== qIdx) return qa;
10184
+ return { ...qa, sections: qa.sections.map((s, j) => j === sIdx ? { ...s, content: value } : s) };
10185
+ }));
9799
10186
  }, []);
9800
10187
  const styles = CARD_STYLES.questionsCards;
9801
10188
  return /* @__PURE__ */ jsx32(BlockWithAlignableContents8, { className, format, nodeKey, children: /* @__PURE__ */ jsxs22("div", { style: { position: "relative" }, children: [
9802
- isEditable && !isEditing && /* @__PURE__ */ jsx32(
10189
+ isEditable && /* @__PURE__ */ jsx32(
9803
10190
  "button",
9804
10191
  {
9805
10192
  type: "button",
@@ -9824,82 +10211,86 @@ function QuestionsCardsComponent({
9824
10211
  children: "Edit Questions Card"
9825
10212
  }
9826
10213
  ),
9827
- isEditing ? /* @__PURE__ */ jsxs22("div", { style: { border: "1px solid #ccc", borderRadius: 4, padding: 8, background: "#f9f9f9" }, children: [
9828
- /* @__PURE__ */ jsxs22("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
9829
- /* @__PURE__ */ jsx32("span", { style: { fontSize: 13, fontWeight: 600, color: "rgba(25, 118, 210, 0.8)" }, children: "Edit Questions Card" }),
9830
- /* @__PURE__ */ jsxs22("div", { style: { display: "flex", gap: 4 }, children: [
9831
- /* @__PURE__ */ jsx32(
10214
+ /* @__PURE__ */ jsx32("div", { dangerouslySetInnerHTML: { __html: html } }),
10215
+ isEditing && /* @__PURE__ */ jsx32(Modal, { onClose: cancelEdit, title: "Edit Questions Card", children: /* @__PURE__ */ jsxs22("div", { style: { minWidth: 500 }, children: [
10216
+ qaPairs.map((qa, qIdx) => /* @__PURE__ */ jsxs22("div", { style: { border: "1px solid #e5e7eb", borderRadius: 6, padding: 8, marginBottom: 8, background: "#fff" }, children: [
10217
+ /* @__PURE__ */ jsxs22("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 4 }, children: [
10218
+ /* @__PURE__ */ jsxs22("span", { style: { fontSize: 12, fontWeight: 600, color: "#1976d2" }, children: [
10219
+ "Q",
10220
+ qIdx + 1
10221
+ ] }),
10222
+ qaPairs.length > 1 && /* @__PURE__ */ jsx32(
9832
10223
  "button",
9833
10224
  {
9834
10225
  type: "button",
9835
- onClick: cancelEdit,
9836
- style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
9837
- children: "Cancel"
10226
+ onClick: () => removeQAPair(qIdx),
10227
+ style: { padding: "2px 6px", fontSize: 14, border: "1px solid #ddd", borderRadius: 4, background: "#fff", cursor: "pointer", color: "#e11d48" },
10228
+ children: "\xD7"
9838
10229
  }
9839
- ),
10230
+ )
10231
+ ] }),
10232
+ /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
10233
+ /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#1976d2", fontWeight: 600, display: "block", marginBottom: 2 }, children: "Question" }),
9840
10234
  /* @__PURE__ */ jsx32(
9841
- "button",
10235
+ "textarea",
9842
10236
  {
9843
- type: "button",
9844
- onClick: saveChanges,
9845
- disabled: !preview,
9846
- style: { padding: "2px 10px", fontSize: 12, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 },
9847
- children: "Save"
10237
+ placeholder: "Enter question text...",
10238
+ value: qa.question,
10239
+ onChange: (e) => updateQA(qIdx, "question", e.target.value),
10240
+ style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
10241
+ }
10242
+ )
10243
+ ] }),
10244
+ /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
10245
+ /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#666", fontWeight: 600, display: "block", marginBottom: 2 }, children: "Answer" }),
10246
+ /* @__PURE__ */ jsx32(
10247
+ "textarea",
10248
+ {
10249
+ placeholder: "Enter answer text...",
10250
+ value: qa.answer,
10251
+ onChange: (e) => updateQA(qIdx, "answer", e.target.value),
10252
+ style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 60, resize: "vertical" }
9848
10253
  }
9849
10254
  )
10255
+ ] }),
10256
+ /* @__PURE__ */ jsxs22("details", { style: { marginTop: 4 }, children: [
10257
+ /* @__PURE__ */ jsx32("summary", { style: { fontSize: 11, color: "#666", fontWeight: 600, cursor: "pointer" }, children: "Card Sections" }),
10258
+ /* @__PURE__ */ jsx32("div", { style: { marginTop: 4 }, children: qa.sections.map((section, sIdx) => {
10259
+ const sStyle = styles[section.key];
10260
+ const label = sStyle && "title" in sStyle ? sStyle.title : section.key;
10261
+ return /* @__PURE__ */ jsxs22("div", { style: { marginBottom: 4 }, children: [
10262
+ /* @__PURE__ */ jsx32("label", { style: { fontSize: 11, color: "#666", display: "block", marginBottom: 2 }, children: label }),
10263
+ /* @__PURE__ */ jsx32(
10264
+ "textarea",
10265
+ {
10266
+ placeholder: `${label} content...`,
10267
+ value: section.content,
10268
+ onChange: (e) => updateSection(qIdx, sIdx, e.target.value),
10269
+ style: { width: "100%", padding: "4px 6px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, minHeight: 40, resize: "vertical" }
10270
+ }
10271
+ )
10272
+ ] }, sIdx);
10273
+ }) })
9850
10274
  ] })
9851
- ] }),
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
- ] }),
9898
- preview && /* @__PURE__ */ jsxs22("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" }, children: [
10275
+ ] }, qIdx)),
10276
+ /* @__PURE__ */ jsx32(
10277
+ "button",
10278
+ {
10279
+ type: "button",
10280
+ onClick: addQAPair,
10281
+ style: { padding: "2px 10px", fontSize: 12, border: "1px solid #ddd", borderRadius: 4, background: "#fff", cursor: "pointer", marginBottom: 8 },
10282
+ children: "+ Add Question"
10283
+ }
10284
+ ),
10285
+ preview && /* @__PURE__ */ jsxs22("div", { style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff", maxHeight: 200, overflow: "auto" }, children: [
9899
10286
  /* @__PURE__ */ jsx32("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
9900
10287
  /* @__PURE__ */ jsx32("div", { dangerouslySetInnerHTML: { __html: preview } })
10288
+ ] }),
10289
+ /* @__PURE__ */ jsxs22("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 12 }, children: [
10290
+ /* @__PURE__ */ jsx32("button", { type: "button", onClick: cancelEdit, style: { padding: "6px 16px", fontSize: 13, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" }, children: "Cancel" }),
10291
+ /* @__PURE__ */ jsx32("button", { type: "button", onClick: saveChanges, disabled: !preview, style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: preview ? 1 : 0.5 }, children: "Save" })
9901
10292
  ] })
9902
- ] }) : /* @__PURE__ */ jsx32("div", { dangerouslySetInnerHTML: { __html: html } })
10293
+ ] }) })
9903
10294
  ] }) });
9904
10295
  }
9905
10296
  var DATA_ATTR5 = "data-lexical-questions-cards";
@@ -10003,16 +10394,27 @@ function InsertQuestionsCardsDialog({
10003
10394
  activeEditor,
10004
10395
  onClose
10005
10396
  }) {
10006
- const [input, setInput] = useState27("");
10007
- const preview = useMemo16(() => {
10397
+ const [input, setInput] = useState28("");
10398
+ let editorConfig = null;
10399
+ try {
10400
+ editorConfig = useEditorConfig();
10401
+ } catch {
10402
+ }
10403
+ const richPaste = useRichPaste(
10404
+ (text) => setInput((prev) => prev ? prev + "\n" + text : text),
10405
+ editorConfig?.baasixClient,
10406
+ editorConfig?.folder
10407
+ );
10408
+ const finalHtml = useMemo16(() => {
10008
10409
  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);
10410
+ const html = convertQuestionsCards(input);
10411
+ return richPaste.replaceImagePlaceholders(html);
10412
+ }, [input, richPaste]);
10413
+ const handleInsert = useCallback21(() => {
10414
+ if (!finalHtml) return;
10415
+ activeEditor.dispatchCommand(INSERT_QUESTIONS_CARDS_COMMAND, finalHtml);
10014
10416
  onClose();
10015
- }, [activeEditor, preview, onClose]);
10417
+ }, [activeEditor, finalHtml, onClose]);
10016
10418
  return /* @__PURE__ */ jsxs23("div", { style: { minWidth: 500 }, children: [
10017
10419
  /* @__PURE__ */ jsx33(
10018
10420
  "textarea",
@@ -10021,28 +10423,18 @@ function InsertQuestionsCardsDialog({
10021
10423
  onChange: (e) => setInput(e.target.value),
10022
10424
  placeholder: `Paste question content here...
10023
10425
  Example:
10024
- Q1. Describe the pathogenesis of tuberculosis.
10426
+ Q1 : Describe the pathogenesis of tuberculosis.
10025
10427
 
10026
- Answer:
10027
- Tuberculosis is caused by Mycobacterium tuberculosis...
10428
+ Answer: Tuberculosis is caused by Mycobacterium tuberculosis...
10028
10429
 
10029
- MARKING RUBRIC
10430
+ 1. MARKING RUBRIC
10030
10431
  Definition: 2 marks, Pathogenesis: 5 marks...
10031
10432
 
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...`,
10433
+ 2. MNEMONICS
10434
+ Remember TB pathogenesis with "IGRA"...`,
10043
10435
  style: {
10044
10436
  width: "100%",
10045
- minHeight: 180,
10437
+ minHeight: 150,
10046
10438
  fontFamily: "monospace",
10047
10439
  fontSize: 13,
10048
10440
  padding: 8,
@@ -10053,9 +10445,38 @@ Always mention Ghon complex...`,
10053
10445
  }
10054
10446
  }
10055
10447
  ),
10056
- preview && /* @__PURE__ */ jsxs23("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
10448
+ /* @__PURE__ */ jsx33(
10449
+ "div",
10450
+ {
10451
+ ref: richPaste.pasteAreaRef,
10452
+ contentEditable: true,
10453
+ onPaste: richPaste.handlePaste,
10454
+ onMouseDown: (e) => e.stopPropagation(),
10455
+ style: {
10456
+ width: "100%",
10457
+ minHeight: 40,
10458
+ padding: 8,
10459
+ border: "2px dashed #93c5fd",
10460
+ borderRadius: 4,
10461
+ fontSize: 12,
10462
+ color: "#6b7280",
10463
+ marginBottom: 8,
10464
+ outline: "none",
10465
+ background: "#f0f7ff"
10466
+ },
10467
+ suppressContentEditableWarning: true,
10468
+ children: /* @__PURE__ */ jsx33("span", { style: { color: "#9ca3af", pointerEvents: "none", userSelect: "none" }, children: richPaste.isUploading ? "Uploading images..." : "Paste from Word/Docs here for image support" })
10469
+ }
10470
+ ),
10471
+ richPaste.images.length > 0 && /* @__PURE__ */ jsxs23("div", { style: { marginBottom: 8, fontSize: 11, color: "#16a34a" }, children: [
10472
+ richPaste.images.length,
10473
+ " image",
10474
+ richPaste.images.length > 1 ? "s" : "",
10475
+ " captured"
10476
+ ] }),
10477
+ finalHtml && /* @__PURE__ */ jsxs23("div", { style: { marginBottom: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fafafa", maxHeight: 250, overflow: "auto" }, children: [
10057
10478
  /* @__PURE__ */ jsx33("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
10058
- /* @__PURE__ */ jsx33("div", { dangerouslySetInnerHTML: { __html: preview } })
10479
+ /* @__PURE__ */ jsx33("div", { dangerouslySetInnerHTML: { __html: finalHtml } })
10059
10480
  ] }),
10060
10481
  /* @__PURE__ */ jsxs23("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
10061
10482
  /* @__PURE__ */ jsx33(
@@ -10072,9 +10493,9 @@ Always mention Ghon complex...`,
10072
10493
  {
10073
10494
  type: "button",
10074
10495
  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"
10496
+ disabled: !finalHtml || richPaste.isUploading,
10497
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer", opacity: finalHtml && !richPaste.isUploading ? 1 : 0.5 },
10498
+ children: richPaste.isUploading ? "Uploading..." : "Insert"
10078
10499
  }
10079
10500
  )
10080
10501
  ] })
@@ -10089,7 +10510,7 @@ import {
10089
10510
  TableNode as TableNode2,
10090
10511
  TableRowNode as TableRowNode2
10091
10512
  } from "@lexical/table";
10092
- import { createContext as createContext4, useContext as useContext4, useEffect as useEffect29, useMemo as useMemo17, useState as useState28 } from "react";
10513
+ import { createContext as createContext4, useContext as useContext4, useEffect as useEffect29, useMemo as useMemo17, useState as useState29 } from "react";
10093
10514
  import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
10094
10515
  var CellContext = createContext4({
10095
10516
  cellEditorConfig: null,
@@ -10101,9 +10522,9 @@ function InsertTableDialog({
10101
10522
  activeEditor,
10102
10523
  onClose
10103
10524
  }) {
10104
- const [rows, setRows] = useState28("5");
10105
- const [columns, setColumns] = useState28("5");
10106
- const [isDisabled, setIsDisabled] = useState28(true);
10525
+ const [rows, setRows] = useState29("5");
10526
+ const [columns, setColumns] = useState29("5");
10527
+ const [isDisabled, setIsDisabled] = useState29(true);
10107
10528
  useEffect29(() => {
10108
10529
  const row = Number(rows);
10109
10530
  const column = Number(columns);
@@ -10155,7 +10576,7 @@ import {
10155
10576
  } from "@lexical/react/LexicalDecoratorBlockNode";
10156
10577
  import { useLexicalComposerContext as useLexicalComposerContext32 } from "@lexical/react/LexicalComposerContext";
10157
10578
  import { useLexicalEditable as useLexicalEditable6 } from "@lexical/react/useLexicalEditable";
10158
- import { useCallback as useCallback21, useRef as useRef9, useState as useState29 } from "react";
10579
+ import { useCallback as useCallback22, useRef as useRef11, useState as useState30 } from "react";
10159
10580
  import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
10160
10581
  function HtmlBlockComponent({
10161
10582
  className,
@@ -10165,15 +10586,15 @@ function HtmlBlockComponent({
10165
10586
  }) {
10166
10587
  const [editor] = useLexicalComposerContext32();
10167
10588
  const isEditable = useLexicalEditable6();
10168
- const [isEditing, setIsEditing] = useState29(false);
10169
- const [editValue, setEditValue] = useState29("");
10170
- const textareaRef = useRef9(null);
10171
- const openEditor = useCallback21(() => {
10589
+ const [isEditing, setIsEditing] = useState30(false);
10590
+ const [editValue, setEditValue] = useState30("");
10591
+ const textareaRef = useRef11(null);
10592
+ const openEditor = useCallback22(() => {
10172
10593
  setEditValue(html);
10173
10594
  setIsEditing(true);
10174
10595
  setTimeout(() => textareaRef.current?.focus(), 50);
10175
10596
  }, [html]);
10176
- const saveHtml = useCallback21(() => {
10597
+ const saveHtml = useCallback22(() => {
10177
10598
  editor.update(() => {
10178
10599
  const node = $getNodeByKey9(nodeKey);
10179
10600
  if ($isHtmlBlockNode(node)) {
@@ -10182,7 +10603,7 @@ function HtmlBlockComponent({
10182
10603
  });
10183
10604
  setIsEditing(false);
10184
10605
  }, [editor, nodeKey, editValue]);
10185
- const cancelEdit = useCallback21(() => {
10606
+ const cancelEdit = useCallback22(() => {
10186
10607
  setIsEditing(false);
10187
10608
  }, []);
10188
10609
  return /* @__PURE__ */ jsx35(
@@ -10192,7 +10613,7 @@ function HtmlBlockComponent({
10192
10613
  format,
10193
10614
  nodeKey,
10194
10615
  children: /* @__PURE__ */ jsxs25("div", { style: { position: "relative" }, children: [
10195
- isEditable && !isEditing && /* @__PURE__ */ jsx35(
10616
+ isEditable && /* @__PURE__ */ jsx35(
10196
10617
  "button",
10197
10618
  {
10198
10619
  type: "button",
@@ -10217,52 +10638,14 @@ function HtmlBlockComponent({
10217
10638
  children: "Edit HTML"
10218
10639
  }
10219
10640
  ),
10220
- isEditing ? /* @__PURE__ */ jsxs25("div", { style: { border: "1px solid #ccc", borderRadius: 4, padding: 8, background: "#f9f9f9" }, children: [
10221
- /* @__PURE__ */ jsxs25("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 6 }, children: [
10222
- /* @__PURE__ */ jsx35("span", { style: { fontSize: 12, fontWeight: 600, color: "#333" }, children: "Edit HTML Source" }),
10223
- /* @__PURE__ */ jsxs25("div", { style: { display: "flex", gap: 4 }, children: [
10224
- /* @__PURE__ */ jsx35(
10225
- "button",
10226
- {
10227
- type: "button",
10228
- onClick: cancelEdit,
10229
- style: {
10230
- padding: "2px 10px",
10231
- fontSize: 12,
10232
- border: "1px solid #ccc",
10233
- borderRadius: 4,
10234
- background: "#fff",
10235
- cursor: "pointer"
10236
- },
10237
- children: "Cancel"
10238
- }
10239
- ),
10240
- /* @__PURE__ */ jsx35(
10241
- "button",
10242
- {
10243
- type: "button",
10244
- onClick: saveHtml,
10245
- style: {
10246
- padding: "2px 10px",
10247
- fontSize: 12,
10248
- border: "none",
10249
- borderRadius: 4,
10250
- background: "#2563eb",
10251
- color: "#fff",
10252
- cursor: "pointer"
10253
- },
10254
- children: "Save"
10255
- }
10256
- )
10257
- ] })
10258
- ] }),
10641
+ /* @__PURE__ */ jsx35("div", { dangerouslySetInnerHTML: { __html: html } }),
10642
+ isEditing && /* @__PURE__ */ jsx35(Modal, { onClose: cancelEdit, title: "Edit HTML Source", children: /* @__PURE__ */ jsxs25("div", { style: { minWidth: 500 }, children: [
10259
10643
  /* @__PURE__ */ jsx35(
10260
10644
  "textarea",
10261
10645
  {
10262
10646
  ref: textareaRef,
10263
10647
  value: editValue,
10264
10648
  onChange: (e) => setEditValue(e.target.value),
10265
- onMouseDown: (e) => e.stopPropagation(),
10266
10649
  style: {
10267
10650
  width: "100%",
10268
10651
  minHeight: 150,
@@ -10271,21 +10654,36 @@ function HtmlBlockComponent({
10271
10654
  padding: 8,
10272
10655
  border: "1px solid #ddd",
10273
10656
  borderRadius: 4,
10274
- resize: "vertical"
10657
+ resize: "vertical",
10658
+ marginBottom: 8
10275
10659
  }
10276
10660
  }
10277
10661
  ),
10278
- /* @__PURE__ */ jsxs25(
10279
- "div",
10280
- {
10281
- style: { marginTop: 8, padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff" },
10282
- children: [
10283
- /* @__PURE__ */ jsx35("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
10284
- /* @__PURE__ */ jsx35("div", { dangerouslySetInnerHTML: { __html: editValue } })
10285
- ]
10286
- }
10287
- )
10288
- ] }) : /* @__PURE__ */ jsx35("div", { dangerouslySetInnerHTML: { __html: html } })
10662
+ /* @__PURE__ */ jsxs25("div", { style: { padding: 8, border: "1px solid #e5e7eb", borderRadius: 4, background: "#fff", maxHeight: 200, overflow: "auto", marginBottom: 8 }, children: [
10663
+ /* @__PURE__ */ jsx35("span", { style: { fontSize: 11, color: "#888", display: "block", marginBottom: 4 }, children: "Preview:" }),
10664
+ /* @__PURE__ */ jsx35("div", { dangerouslySetInnerHTML: { __html: editValue } })
10665
+ ] }),
10666
+ /* @__PURE__ */ jsxs25("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: [
10667
+ /* @__PURE__ */ jsx35(
10668
+ "button",
10669
+ {
10670
+ type: "button",
10671
+ onClick: cancelEdit,
10672
+ style: { padding: "6px 16px", fontSize: 13, border: "1px solid #ccc", borderRadius: 4, background: "#fff", cursor: "pointer" },
10673
+ children: "Cancel"
10674
+ }
10675
+ ),
10676
+ /* @__PURE__ */ jsx35(
10677
+ "button",
10678
+ {
10679
+ type: "button",
10680
+ onClick: saveHtml,
10681
+ style: { padding: "6px 16px", fontSize: 13, border: "none", borderRadius: 4, background: "#2563eb", color: "#fff", cursor: "pointer" },
10682
+ children: "Save"
10683
+ }
10684
+ )
10685
+ ] })
10686
+ ] }) })
10289
10687
  ] })
10290
10688
  }
10291
10689
  );
@@ -10661,7 +11059,7 @@ function getBaseOptions(editor, showModal) {
10661
11059
  function ComponentPickerMenuPlugin() {
10662
11060
  const [editor] = useLexicalComposerContext33();
10663
11061
  const [modal, showModal] = useModal();
10664
- const [queryString, setQueryString] = useState30(null);
11062
+ const [queryString, setQueryString] = useState31(null);
10665
11063
  const checkForTriggerMatch = useBasicTypeaheadTriggerMatch("/", {
10666
11064
  allowWhitespace: true,
10667
11065
  minLength: 0
@@ -10679,7 +11077,7 @@ function ComponentPickerMenuPlugin() {
10679
11077
  )
10680
11078
  ];
10681
11079
  }, [editor, queryString, showModal]);
10682
- const onSelectOption = useCallback22(
11080
+ const onSelectOption = useCallback23(
10683
11081
  (selectedOption, nodeToRemove, closeMenu, matchingString) => {
10684
11082
  editor.update(() => {
10685
11083
  nodeToRemove?.remove();
@@ -10912,7 +11310,7 @@ import {
10912
11310
  $isParagraphNode as $isParagraphNode4,
10913
11311
  $isTextNode as $isTextNode4
10914
11312
  } from "lexical";
10915
- import { useCallback as useCallback23, useEffect as useEffect31, useMemo as useMemo20, useRef as useRef10, useState as useState31 } from "react";
11313
+ import { useCallback as useCallback24, useEffect as useEffect31, useMemo as useMemo20, useRef as useRef12, useState as useState32 } from "react";
10916
11314
  import * as ReactDOM3 from "react-dom";
10917
11315
  import { Fragment as Fragment12, jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
10918
11316
  var DRAGGABLE_BLOCK_MENU_CLASSNAME = "draggable-block-menu";
@@ -10924,18 +11322,18 @@ function DraggableBlockPlugin({
10924
11322
  }) {
10925
11323
  const [editor] = useLexicalComposerContext36();
10926
11324
  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(
11325
+ const menuRef = useRef12(null);
11326
+ const pickerRef = useRef12(null);
11327
+ const searchInputRef = useRef12(null);
11328
+ const targetLineRef = useRef12(null);
11329
+ const [draggableElement, setDraggableElement] = useState32(
10932
11330
  null
10933
11331
  );
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);
11332
+ const [pickerState, setPickerState] = useState32(null);
11333
+ const [isPickerOpen, setIsPickerOpen] = useState32(false);
11334
+ const [queryString, setQueryString] = useState32("");
11335
+ const [highlightedIndex, setHighlightedIndex] = useState32(0);
11336
+ const [pickerPosition, setPickerPosition] = useState32(null);
10939
11337
  const options = useMemo20(() => {
10940
11338
  const baseOptions = getBaseOptions(editor, showModal);
10941
11339
  if (!queryString) {
@@ -10979,7 +11377,7 @@ function DraggableBlockPlugin({
10979
11377
  document.removeEventListener("mousedown", handleClickOutside);
10980
11378
  };
10981
11379
  }, [isPickerOpen]);
10982
- const selectOption = useCallback23(
11380
+ const selectOption = useCallback24(
10983
11381
  (option) => {
10984
11382
  if (!pickerState) {
10985
11383
  setIsPickerOpen(false);
@@ -11156,7 +11554,7 @@ import {
11156
11554
  $getSelection as $getSelection11,
11157
11555
  $isRangeSelection as $isRangeSelection9
11158
11556
  } from "lexical";
11159
- import { useCallback as useCallback24, useEffect as useEffect32, useMemo as useMemo21, useState as useState32 } from "react";
11557
+ import { useCallback as useCallback25, useEffect as useEffect32, useMemo as useMemo21, useState as useState33 } from "react";
11160
11558
  import * as ReactDOM4 from "react-dom";
11161
11559
  import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
11162
11560
  var EmojiOption = class extends MenuOption2 {
@@ -11204,8 +11602,8 @@ function EmojiMenuItem({
11204
11602
  var MAX_EMOJI_SUGGESTION_COUNT = 10;
11205
11603
  function EmojiPickerPlugin() {
11206
11604
  const [editor] = useLexicalComposerContext37();
11207
- const [queryString, setQueryString] = useState32(null);
11208
- const [emojis, setEmojis] = useState32([]);
11605
+ const [queryString, setQueryString] = useState33(null);
11606
+ const [emojis, setEmojis] = useState33([]);
11209
11607
  useEffect32(() => {
11210
11608
  import("./emoji-list-MUV74SND.js").then((file) => setEmojis(file.default));
11211
11609
  }, []);
@@ -11229,7 +11627,7 @@ function EmojiPickerPlugin() {
11229
11627
  ) : false : emojiOptions;
11230
11628
  }).slice(0, MAX_EMOJI_SUGGESTION_COUNT);
11231
11629
  }, [emojiOptions, queryString]);
11232
- const onSelectOption = useCallback24(
11630
+ const onSelectOption = useCallback25(
11233
11631
  (selectedOption, nodeToRemove, closeMenu) => {
11234
11632
  editor.update(() => {
11235
11633
  const selection = $getSelection11();
@@ -11302,7 +11700,7 @@ import {
11302
11700
  KEY_ESCAPE_COMMAND as KEY_ESCAPE_COMMAND2,
11303
11701
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND2
11304
11702
  } from "lexical";
11305
- import { useCallback as useCallback25, useEffect as useEffect33, useRef as useRef11, useState as useState33 } from "react";
11703
+ import { useCallback as useCallback26, useEffect as useEffect33, useRef as useRef13, useState as useState34 } from "react";
11306
11704
  import { createPortal as createPortal8 } from "react-dom";
11307
11705
 
11308
11706
  // src/utils/getSelectedNode.ts
@@ -11363,14 +11761,14 @@ function FloatingLinkEditor({
11363
11761
  isLinkEditMode,
11364
11762
  setIsLinkEditMode
11365
11763
  }) {
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(
11764
+ const editorRef = useRef13(null);
11765
+ const inputRef = useRef13(null);
11766
+ const [linkUrl, setLinkUrl] = useState34("");
11767
+ const [editedLinkUrl, setEditedLinkUrl] = useState34("https://");
11768
+ const [lastSelection, setLastSelection] = useState34(
11371
11769
  null
11372
11770
  );
11373
- const $updateLinkEditor = useCallback25(() => {
11771
+ const $updateLinkEditor = useCallback26(() => {
11374
11772
  const selection = $getSelection12();
11375
11773
  if ($isRangeSelection10(selection)) {
11376
11774
  const node = getSelectedNode(selection);
@@ -11622,8 +12020,8 @@ function FloatingLinkEditor({
11622
12020
  ] }) });
11623
12021
  }
11624
12022
  function useFloatingLinkEditorToolbar(editor, anchorElem, isLinkEditMode, setIsLinkEditMode) {
11625
- const [activeEditor, setActiveEditor] = useState33(editor);
11626
- const [isLink, setIsLink] = useState33(false);
12023
+ const [activeEditor, setActiveEditor] = useState34(editor);
12024
+ const [isLink, setIsLink] = useState34(false);
11627
12025
  useEffect33(() => {
11628
12026
  function $updateToolbar() {
11629
12027
  const selection = $getSelection12();
@@ -11740,7 +12138,7 @@ import {
11740
12138
  getDOMSelection as getDOMSelection3,
11741
12139
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND3
11742
12140
  } from "lexical";
11743
- import { useCallback as useCallback26, useEffect as useEffect34, useRef as useRef12, useState as useState34 } from "react";
12141
+ import { useCallback as useCallback27, useEffect as useEffect34, useRef as useRef14, useState as useState35 } from "react";
11744
12142
  import { createPortal as createPortal9 } from "react-dom";
11745
12143
 
11746
12144
  // src/utils/getDOMRangeRect.ts
@@ -11819,8 +12217,8 @@ function TextFormatFloatingToolbar({
11819
12217
  isSuperscript: isSuperscript2,
11820
12218
  setIsLinkEditMode
11821
12219
  }) {
11822
- const popupCharStylesEditorRef = useRef12(null);
11823
- const insertLink = useCallback26(() => {
12220
+ const popupCharStylesEditorRef = useRef14(null);
12221
+ const insertLink = useCallback27(() => {
11824
12222
  if (!isLink) {
11825
12223
  setIsLinkEditMode(true);
11826
12224
  editor.dispatchCommand(TOGGLE_LINK_COMMAND4, "https://");
@@ -11861,7 +12259,7 @@ function TextFormatFloatingToolbar({
11861
12259
  };
11862
12260
  }
11863
12261
  }, [popupCharStylesEditorRef]);
11864
- const $updateTextFormatFloatingToolbar = useCallback26(() => {
12262
+ const $updateTextFormatFloatingToolbar = useCallback27(() => {
11865
12263
  const selection = $getSelection13();
11866
12264
  const popupCharStylesEditorElem = popupCharStylesEditorRef.current;
11867
12265
  const nativeSelection = getDOMSelection3(editor._window);
@@ -12075,19 +12473,19 @@ function TextFormatFloatingToolbar({
12075
12473
  ] });
12076
12474
  }
12077
12475
  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(() => {
12476
+ const [isText, setIsText] = useState35(false);
12477
+ const [isLink, setIsLink] = useState35(false);
12478
+ const [isBold, setIsBold] = useState35(false);
12479
+ const [isItalic, setIsItalic] = useState35(false);
12480
+ const [isUnderline, setIsUnderline] = useState35(false);
12481
+ const [isUppercase2, setIsUppercase] = useState35(false);
12482
+ const [isLowercase2, setIsLowercase] = useState35(false);
12483
+ const [isCapitalize2, setIsCapitalize] = useState35(false);
12484
+ const [isStrikethrough, setIsStrikethrough] = useState35(false);
12485
+ const [isSubscript2, setIsSubscript] = useState35(false);
12486
+ const [isSuperscript2, setIsSuperscript] = useState35(false);
12487
+ const [isCode, setIsCode] = useState35(false);
12488
+ const updatePopup = useCallback27(() => {
12091
12489
  editor.getEditorState().read(() => {
12092
12490
  if (editor.isComposing()) {
12093
12491
  return;
@@ -12963,12 +13361,12 @@ import {
12963
13361
  isDOMNode as isDOMNode2,
12964
13362
  SELECTION_CHANGE_COMMAND as SELECTION_CHANGE_COMMAND4
12965
13363
  } from "lexical";
12966
- import { useCallback as useCallback27, useEffect as useEffect39, useRef as useRef14, useState as useState36 } from "react";
13364
+ import { useCallback as useCallback28, useEffect as useEffect39, useRef as useRef16, useState as useState37 } from "react";
12967
13365
  import { createPortal as createPortal10 } from "react-dom";
12968
13366
 
12969
13367
  // src/ui/ColorPicker.tsx
12970
13368
  import { calculateZoomLevel as calculateZoomLevel2 } from "@lexical/utils";
12971
- import { useMemo as useMemo22, useRef as useRef13, useState as useState35 } from "react";
13369
+ import { useMemo as useMemo22, useRef as useRef15, useState as useState36 } from "react";
12972
13370
  import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
12973
13371
  var skipAddingToHistoryStack = false;
12974
13372
  var basicColors = [
@@ -12994,11 +13392,11 @@ function ColorPicker({
12994
13392
  color,
12995
13393
  onChange
12996
13394
  }) {
12997
- const [selfColor, setSelfColor] = useState35(transformColor("hex", color));
12998
- const [inputColor, setInputColor] = useState35(
13395
+ const [selfColor, setSelfColor] = useState36(transformColor("hex", color));
13396
+ const [inputColor, setInputColor] = useState36(
12999
13397
  transformColor("hex", color).hex
13000
13398
  );
13001
- const innerDivRef = useRef13(null);
13399
+ const innerDivRef = useRef15(null);
13002
13400
  const saturationPosition = useMemo22(
13003
13401
  () => ({
13004
13402
  x: selfColor.hsv.s / 100 * WIDTH,
@@ -13108,8 +13506,8 @@ function ColorPicker({
13108
13506
  );
13109
13507
  }
13110
13508
  function MoveWrapper({ className, style, onChange, children }) {
13111
- const divRef = useRef13(null);
13112
- const draggedRef = useRef13(false);
13509
+ const divRef = useRef15(null);
13510
+ const draggedRef = useRef15(false);
13113
13511
  const move = (e) => {
13114
13512
  if (divRef.current) {
13115
13513
  const { current: div } = divRef;
@@ -13282,15 +13680,15 @@ function TableActionMenu({
13282
13680
  showColorPickerModal
13283
13681
  }) {
13284
13682
  const [editor] = useLexicalComposerContext43();
13285
- const dropDownRef = useRef14(null);
13286
- const [tableCellNode, updateTableCellNode] = useState36(_tableCellNode);
13287
- const [selectionCounts, updateSelectionCounts] = useState36({
13683
+ const dropDownRef = useRef16(null);
13684
+ const [tableCellNode, updateTableCellNode] = useState37(_tableCellNode);
13685
+ const [selectionCounts, updateSelectionCounts] = useState37({
13288
13686
  columns: 1,
13289
13687
  rows: 1
13290
13688
  });
13291
- const [canMergeCells, setCanMergeCells] = useState36(false);
13292
- const [canUnmergeCell, setCanUnmergeCell] = useState36(false);
13293
- const [backgroundColor, setBackgroundColor] = useState36(
13689
+ const [canMergeCells, setCanMergeCells] = useState37(false);
13690
+ const [canUnmergeCell, setCanUnmergeCell] = useState37(false);
13691
+ const [backgroundColor, setBackgroundColor] = useState37(
13294
13692
  () => currentCellBackgroundColor(editor) || ""
13295
13693
  );
13296
13694
  useEffect39(() => {
@@ -13354,7 +13752,7 @@ function TableActionMenu({
13354
13752
  window.addEventListener("click", handleClickOutside);
13355
13753
  return () => window.removeEventListener("click", handleClickOutside);
13356
13754
  }, [setIsMenuOpen, contextRef]);
13357
- const clearTableSelection = useCallback27(() => {
13755
+ const clearTableSelection = useCallback28(() => {
13358
13756
  editor.update(() => {
13359
13757
  if (tableCellNode.isAttached()) {
13360
13758
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13397,7 +13795,7 @@ function TableActionMenu({
13397
13795
  $unmergeCell();
13398
13796
  });
13399
13797
  };
13400
- const insertTableRowAtSelection = useCallback27(
13798
+ const insertTableRowAtSelection = useCallback28(
13401
13799
  (shouldInsertAfter) => {
13402
13800
  editor.update(() => {
13403
13801
  for (let i = 0; i < selectionCounts.rows; i++) {
@@ -13408,7 +13806,7 @@ function TableActionMenu({
13408
13806
  },
13409
13807
  [editor, onClose, selectionCounts.rows]
13410
13808
  );
13411
- const insertTableColumnAtSelection = useCallback27(
13809
+ const insertTableColumnAtSelection = useCallback28(
13412
13810
  (shouldInsertAfter) => {
13413
13811
  editor.update(() => {
13414
13812
  for (let i = 0; i < selectionCounts.columns; i++) {
@@ -13419,13 +13817,13 @@ function TableActionMenu({
13419
13817
  },
13420
13818
  [editor, onClose, selectionCounts.columns]
13421
13819
  );
13422
- const deleteTableRowAtSelection = useCallback27(() => {
13820
+ const deleteTableRowAtSelection = useCallback28(() => {
13423
13821
  editor.update(() => {
13424
13822
  $deleteTableRowAtSelection();
13425
13823
  onClose();
13426
13824
  });
13427
13825
  }, [editor, onClose]);
13428
- const deleteTableAtSelection = useCallback27(() => {
13826
+ const deleteTableAtSelection = useCallback28(() => {
13429
13827
  editor.update(() => {
13430
13828
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
13431
13829
  tableNode.remove();
@@ -13433,13 +13831,13 @@ function TableActionMenu({
13433
13831
  onClose();
13434
13832
  });
13435
13833
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13436
- const deleteTableColumnAtSelection = useCallback27(() => {
13834
+ const deleteTableColumnAtSelection = useCallback28(() => {
13437
13835
  editor.update(() => {
13438
13836
  $deleteTableColumnAtSelection();
13439
13837
  onClose();
13440
13838
  });
13441
13839
  }, [editor, onClose]);
13442
- const toggleTableRowIsHeader = useCallback27(() => {
13840
+ const toggleTableRowIsHeader = useCallback28(() => {
13443
13841
  editor.update(() => {
13444
13842
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
13445
13843
  const tableRowIndex = $getTableRowIndexFromTableCellNode(tableCellNode);
@@ -13460,7 +13858,7 @@ function TableActionMenu({
13460
13858
  onClose();
13461
13859
  });
13462
13860
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13463
- const toggleTableColumnIsHeader = useCallback27(() => {
13861
+ const toggleTableColumnIsHeader = useCallback28(() => {
13464
13862
  editor.update(() => {
13465
13863
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
13466
13864
  const tableColumnIndex = $getTableColumnIndexFromTableCellNode(tableCellNode);
@@ -13481,7 +13879,7 @@ function TableActionMenu({
13481
13879
  onClose();
13482
13880
  });
13483
13881
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13484
- const toggleRowStriping = useCallback27(() => {
13882
+ const toggleRowStriping = useCallback28(() => {
13485
13883
  editor.update(() => {
13486
13884
  if (tableCellNode.isAttached()) {
13487
13885
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13493,7 +13891,7 @@ function TableActionMenu({
13493
13891
  onClose();
13494
13892
  });
13495
13893
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13496
- const toggleFirstRowFreeze = useCallback27(() => {
13894
+ const toggleFirstRowFreeze = useCallback28(() => {
13497
13895
  editor.update(() => {
13498
13896
  if (tableCellNode.isAttached()) {
13499
13897
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13505,7 +13903,7 @@ function TableActionMenu({
13505
13903
  onClose();
13506
13904
  });
13507
13905
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13508
- const toggleFirstColumnFreeze = useCallback27(() => {
13906
+ const toggleFirstColumnFreeze = useCallback28(() => {
13509
13907
  editor.update(() => {
13510
13908
  if (tableCellNode.isAttached()) {
13511
13909
  const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode);
@@ -13519,7 +13917,7 @@ function TableActionMenu({
13519
13917
  onClose();
13520
13918
  });
13521
13919
  }, [editor, tableCellNode, clearTableSelection, onClose]);
13522
- const handleCellBackgroundColor = useCallback27(
13920
+ const handleCellBackgroundColor = useCallback28(
13523
13921
  (value) => {
13524
13922
  editor.update(() => {
13525
13923
  const selection = $getSelection17();
@@ -13832,14 +14230,14 @@ function TableCellActionMenuContainer({
13832
14230
  cellMerge
13833
14231
  }) {
13834
14232
  const [editor] = useLexicalComposerContext43();
13835
- const menuButtonRef = useRef14(null);
13836
- const menuRootRef = useRef14(null);
13837
- const [isMenuOpen, setIsMenuOpen] = useState36(false);
13838
- const [tableCellNode, setTableMenuCellNode] = useState36(
14233
+ const menuButtonRef = useRef16(null);
14234
+ const menuRootRef = useRef16(null);
14235
+ const [isMenuOpen, setIsMenuOpen] = useState37(false);
14236
+ const [tableCellNode, setTableMenuCellNode] = useState37(
13839
14237
  null
13840
14238
  );
13841
14239
  const [colorPickerModal, showColorPickerModal] = useModal();
13842
- const checkTableCellOverflow = useCallback27(
14240
+ const checkTableCellOverflow = useCallback28(
13843
14241
  (tableCellParentNodeDOM) => {
13844
14242
  const scrollableContainer = tableCellParentNodeDOM.closest(
13845
14243
  ".PlaygroundEditorTheme__tableScrollableWrapper"
@@ -13857,7 +14255,7 @@ function TableCellActionMenuContainer({
13857
14255
  },
13858
14256
  []
13859
14257
  );
13860
- const $moveMenu = useCallback27(() => {
14258
+ const $moveMenu = useCallback28(() => {
13861
14259
  const menu = menuButtonRef.current;
13862
14260
  const selection = $getSelection17();
13863
14261
  const nativeSelection = getDOMSelection4(editor._window);
@@ -13984,7 +14382,7 @@ function TableCellActionMenuContainer({
13984
14382
  () => clearTimeout(timeoutId)
13985
14383
  );
13986
14384
  });
13987
- const prevTableCellDOM = useRef14(tableCellNode);
14385
+ const prevTableCellDOM = useRef16(tableCellNode);
13988
14386
  useEffect39(() => {
13989
14387
  if (prevTableCellDOM.current !== tableCellNode) {
13990
14388
  setIsMenuOpen(false);
@@ -14056,11 +14454,11 @@ import {
14056
14454
  SKIP_SCROLL_INTO_VIEW_TAG
14057
14455
  } from "lexical";
14058
14456
  import {
14059
- useCallback as useCallback28,
14457
+ useCallback as useCallback29,
14060
14458
  useEffect as useEffect40,
14061
14459
  useMemo as useMemo23,
14062
- useRef as useRef15,
14063
- useState as useState37
14460
+ useRef as useRef17,
14461
+ useState as useState38
14064
14462
  } from "react";
14065
14463
  import { createPortal as createPortal11 } from "react-dom";
14066
14464
  import { Fragment as Fragment16, jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
@@ -14068,16 +14466,16 @@ var MIN_ROW_HEIGHT = 33;
14068
14466
  var MIN_COLUMN_WIDTH = 92;
14069
14467
  var ACTIVE_RESIZER_COLOR = "#76b6ff";
14070
14468
  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(() => {
14469
+ const targetRef = useRef17(null);
14470
+ const resizerRef = useRef17(null);
14471
+ const tableRectRef = useRef17(null);
14472
+ const [hasTable, setHasTable] = useState38(false);
14473
+ const pointerStartPosRef = useRef17(null);
14474
+ const [pointerCurrentPos, updatePointerCurrentPos] = useState38(null);
14475
+ const [activeCell, updateActiveCell] = useState38(null);
14476
+ const [draggingDirection, updateDraggingDirection] = useState38(null);
14477
+ const [hoveredDirection, updateHoveredDirection] = useState38(null);
14478
+ const resetState = useCallback29(() => {
14081
14479
  updateActiveCell(null);
14082
14480
  targetRef.current = null;
14083
14481
  updateDraggingDirection(null);
@@ -14188,7 +14586,7 @@ function TableCellResizer({ editor }) {
14188
14586
  }
14189
14587
  return false;
14190
14588
  };
14191
- const updateRowHeight = useCallback28(
14589
+ const updateRowHeight = useCallback29(
14192
14590
  (heightChange) => {
14193
14591
  if (!activeCell) {
14194
14592
  throw new Error("TableCellResizer: Expected active cell.");
@@ -14241,7 +14639,7 @@ function TableCellResizer({ editor }) {
14241
14639
  }
14242
14640
  }
14243
14641
  };
14244
- const updateColumnWidth = useCallback28(
14642
+ const updateColumnWidth = useCallback29(
14245
14643
  (widthChange) => {
14246
14644
  if (!activeCell) {
14247
14645
  throw new Error("TableCellResizer: Expected active cell.");
@@ -14280,7 +14678,7 @@ function TableCellResizer({ editor }) {
14280
14678
  },
14281
14679
  [activeCell, editor]
14282
14680
  );
14283
- const pointerUpHandler = useCallback28(
14681
+ const pointerUpHandler = useCallback29(
14284
14682
  (direction) => {
14285
14683
  const handler = (event) => {
14286
14684
  event.preventDefault();
@@ -14309,7 +14707,7 @@ function TableCellResizer({ editor }) {
14309
14707
  },
14310
14708
  [activeCell, resetState, updateColumnWidth, updateRowHeight]
14311
14709
  );
14312
- const toggleResize = useCallback28(
14710
+ const toggleResize = useCallback29(
14313
14711
  (direction) => (event) => {
14314
14712
  event.preventDefault();
14315
14713
  event.stopPropagation();
@@ -14326,7 +14724,7 @@ function TableCellResizer({ editor }) {
14326
14724
  },
14327
14725
  [activeCell, pointerUpHandler]
14328
14726
  );
14329
- const getResizers = useCallback28(() => {
14727
+ const getResizers = useCallback29(() => {
14330
14728
  if (activeCell) {
14331
14729
  const { height, width, top, left } = activeCell.elem.getBoundingClientRect();
14332
14730
  const zoom = calculateZoomLevel3(activeCell.elem);
@@ -14384,7 +14782,7 @@ function TableCellResizer({ editor }) {
14384
14782
  top: null
14385
14783
  };
14386
14784
  }, [activeCell, draggingDirection, hoveredDirection, pointerCurrentPos]);
14387
- const handlePointerEnter = useCallback28(
14785
+ const handlePointerEnter = useCallback29(
14388
14786
  (direction) => () => {
14389
14787
  if (!draggingDirection) {
14390
14788
  updateHoveredDirection(direction);
@@ -14392,7 +14790,7 @@ function TableCellResizer({ editor }) {
14392
14790
  },
14393
14791
  [draggingDirection]
14394
14792
  );
14395
- const handlePointerLeave = useCallback28(() => {
14793
+ const handlePointerLeave = useCallback29(() => {
14396
14794
  if (!draggingDirection) {
14397
14795
  updateHoveredDirection(null);
14398
14796
  }
@@ -14458,7 +14856,7 @@ import {
14458
14856
  $getSiblingCaret as $getSiblingCaret2,
14459
14857
  isHTMLElement as isHTMLElement5
14460
14858
  } from "lexical";
14461
- import { useEffect as useEffect41, useRef as useRef16, useState as useState38 } from "react";
14859
+ import { useEffect as useEffect41, useRef as useRef18, useState as useState39 } from "react";
14462
14860
  import { createPortal as createPortal12 } from "react-dom";
14463
14861
 
14464
14862
  // src/utils/getThemeSelector.ts
@@ -14562,31 +14960,31 @@ function TableHoverActionsV2({
14562
14960
  }) {
14563
14961
  const [editor, { getTheme }] = useLexicalComposerContext45();
14564
14962
  const isEditable = useLexicalEditable9();
14565
- const [isVisible, setIsVisible] = useState38(false);
14566
- const [isLeftVisible, setIsLeftVisible] = useState38(false);
14567
- const virtualRef = useRef16({
14963
+ const [isVisible, setIsVisible] = useState39(false);
14964
+ const [isLeftVisible, setIsLeftVisible] = useState39(false);
14965
+ const virtualRef = useRef18({
14568
14966
  getBoundingClientRect: () => new DOMRect()
14569
14967
  });
14570
- const leftVirtualRef = useRef16({
14968
+ const leftVirtualRef = useRef18({
14571
14969
  getBoundingClientRect: () => new DOMRect()
14572
14970
  });
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(
14971
+ const floatingElemRef = useRef18(null);
14972
+ const leftFloatingElemRef = useRef18(null);
14973
+ const dragHandleRef = useRef18(null);
14974
+ const hoveredLeftCellRef = useRef18(null);
14975
+ const hoveredTopCellRef = useRef18(null);
14976
+ const handleMouseLeaveRef = useRef18(
14579
14977
  null
14580
14978
  );
14581
- const dropIndicatorCleanupRef = useRef16([]);
14582
- const [hoveredTable, setHoveredTable] = useState38(
14979
+ const dropIndicatorCleanupRef = useRef18([]);
14980
+ const [hoveredTable, setHoveredTable] = useState39(
14583
14981
  null
14584
14982
  );
14585
- const [hoveredColumnIndex, setHoveredColumnIndex] = useState38(
14983
+ const [hoveredColumnIndex, setHoveredColumnIndex] = useState39(
14586
14984
  null
14587
14985
  );
14588
- const [canReorder, setCanReorder] = useState38(false);
14589
- const [dropIndicatorState, setDropIndicatorState] = useState38(null);
14986
+ const [canReorder, setCanReorder] = useState39(false);
14987
+ const [dropIndicatorState, setDropIndicatorState] = useState39(null);
14590
14988
  const { refs, floatingStyles, update } = useFloating({
14591
14989
  middleware: [
14592
14990
  offset({ mainAxis: -TOP_BUTTON_OVERHANG }),
@@ -15011,7 +15409,7 @@ function TableHoverActionsV2Plugin({
15011
15409
  // src/plugins/TableOfContentsPlugin/index.tsx
15012
15410
  import { useLexicalComposerContext as useLexicalComposerContext46 } from "@lexical/react/LexicalComposerContext";
15013
15411
  import { TableOfContentsPlugin as LexicalTableOfContentsPlugin } from "@lexical/react/LexicalTableOfContentsPlugin";
15014
- import { useEffect as useEffect42, useRef as useRef17, useState as useState39 } from "react";
15412
+ import { useEffect as useEffect42, useRef as useRef19, useState as useState40 } from "react";
15015
15413
  import { jsx as jsx47, jsxs as jsxs35 } from "react/jsx-runtime";
15016
15414
  var MARGIN_ABOVE_EDITOR = 624;
15017
15415
  var HEADING_WIDTH = 9;
@@ -15037,8 +15435,8 @@ function isHeadingBelowTheTopOfThePage(element) {
15037
15435
  function TableOfContentsList({
15038
15436
  tableOfContents
15039
15437
  }) {
15040
- const [selectedKey, setSelectedKey] = useState39("");
15041
- const selectedIndex = useRef17(0);
15438
+ const [selectedKey, setSelectedKey] = useState40("");
15439
+ const selectedIndex = useRef19(0);
15042
15440
  const [editor] = useLexicalComposerContext46();
15043
15441
  function scrollToNode(key, currIndex) {
15044
15442
  editor.getEditorState().read(() => {
@@ -15303,7 +15701,7 @@ import {
15303
15701
  SKIP_SELECTION_FOCUS_TAG as SKIP_SELECTION_FOCUS_TAG2,
15304
15702
  UNDO_COMMAND as UNDO_COMMAND2
15305
15703
  } from "lexical";
15306
- import { useCallback as useCallback29, useEffect as useEffect45, useState as useState41 } from "react";
15704
+ import { useCallback as useCallback30, useEffect as useEffect45, useState as useState42 } from "react";
15307
15705
 
15308
15706
  // src/ui/DropdownColorPicker.tsx
15309
15707
  import { jsx as jsx48 } from "react/jsx-runtime";
@@ -15737,7 +16135,7 @@ function FontDropDown({
15737
16135
  style,
15738
16136
  disabled = false
15739
16137
  }) {
15740
- const handleClick = useCallback29(
16138
+ const handleClick = useCallback30(
15741
16139
  (option) => {
15742
16140
  editor.update(() => {
15743
16141
  $addUpdateTag3(SKIP_SELECTION_FOCUS_TAG2);
@@ -15943,11 +16341,11 @@ function ToolbarPlugin({
15943
16341
  setActiveEditor,
15944
16342
  setIsLinkEditMode
15945
16343
  }) {
15946
- const [selectedElementKey, setSelectedElementKey] = useState41(
16344
+ const [selectedElementKey, setSelectedElementKey] = useState42(
15947
16345
  null
15948
16346
  );
15949
16347
  const [modal, showModal] = useModal();
15950
- const [isEditable, setIsEditable] = useState41(() => editor.isEditable());
16348
+ const [isEditable, setIsEditable] = useState42(() => editor.isEditable());
15951
16349
  const { toolbarState, updateToolbarState } = useToolbarState();
15952
16350
  const dispatchToolbarCommand = (command, payload = void 0, skipRefocus = false) => {
15953
16351
  activeEditor.update(() => {
@@ -15958,7 +16356,7 @@ function ToolbarPlugin({
15958
16356
  });
15959
16357
  };
15960
16358
  const dispatchFormatTextCommand = (payload, skipRefocus = false) => dispatchToolbarCommand(FORMAT_TEXT_COMMAND3, payload, skipRefocus);
15961
- const $handleHeadingNode = useCallback29(
16359
+ const $handleHeadingNode = useCallback30(
15962
16360
  (selectedElement) => {
15963
16361
  const type = $isHeadingNode2(selectedElement) ? selectedElement.getTag() : selectedElement.getType();
15964
16362
  if (type in blockTypeToBlockName) {
@@ -15973,7 +16371,7 @@ function ToolbarPlugin({
15973
16371
  const {
15974
16372
  settings: { isCodeHighlighted, isCodeShiki }
15975
16373
  } = useSettings();
15976
- const $handleCodeNode = useCallback29(
16374
+ const $handleCodeNode = useCallback30(
15977
16375
  (element) => {
15978
16376
  if ($isCodeNode6(element)) {
15979
16377
  const language = element.getLanguage();
@@ -15989,7 +16387,7 @@ function ToolbarPlugin({
15989
16387
  },
15990
16388
  [updateToolbarState, isCodeHighlighted, isCodeShiki]
15991
16389
  );
15992
- const $updateToolbar = useCallback29(() => {
16390
+ const $updateToolbar = useCallback30(() => {
15993
16391
  const selection = $getSelection18();
15994
16392
  if ($isRangeSelection16(selection)) {
15995
16393
  if (activeEditor !== editor && $isEditorIsNestedEditor(activeEditor)) {
@@ -16162,7 +16560,7 @@ function ToolbarPlugin({
16162
16560
  )
16163
16561
  );
16164
16562
  }, [$updateToolbar, activeEditor, editor, updateToolbarState]);
16165
- const applyStyleText = useCallback29(
16563
+ const applyStyleText = useCallback30(
16166
16564
  (styles, skipHistoryStack, skipRefocus = false) => {
16167
16565
  activeEditor.update(
16168
16566
  () => {
@@ -16179,13 +16577,13 @@ function ToolbarPlugin({
16179
16577
  },
16180
16578
  [activeEditor]
16181
16579
  );
16182
- const onFontColorSelect = useCallback29(
16580
+ const onFontColorSelect = useCallback30(
16183
16581
  (value, skipHistoryStack, skipRefocus) => {
16184
16582
  applyStyleText({ color: value }, skipHistoryStack, skipRefocus);
16185
16583
  },
16186
16584
  [applyStyleText]
16187
16585
  );
16188
- const onBgColorSelect = useCallback29(
16586
+ const onBgColorSelect = useCallback30(
16189
16587
  (value, skipHistoryStack, skipRefocus) => {
16190
16588
  applyStyleText(
16191
16589
  { "background-color": value },
@@ -16195,7 +16593,7 @@ function ToolbarPlugin({
16195
16593
  },
16196
16594
  [applyStyleText]
16197
16595
  );
16198
- const insertLink = useCallback29(() => {
16596
+ const insertLink = useCallback30(() => {
16199
16597
  if (!toolbarState.isLink) {
16200
16598
  setIsLinkEditMode(true);
16201
16599
  activeEditor.dispatchCommand(
@@ -16207,7 +16605,7 @@ function ToolbarPlugin({
16207
16605
  activeEditor.dispatchCommand(TOGGLE_LINK_COMMAND6, null);
16208
16606
  }
16209
16607
  }, [activeEditor, setIsLinkEditMode, toolbarState.isLink]);
16210
- const onCodeLanguageSelect = useCallback29(
16608
+ const onCodeLanguageSelect = useCallback30(
16211
16609
  (value) => {
16212
16610
  activeEditor.update(() => {
16213
16611
  $addUpdateTag3(SKIP_SELECTION_FOCUS_TAG2);
@@ -16221,7 +16619,7 @@ function ToolbarPlugin({
16221
16619
  },
16222
16620
  [activeEditor, selectedElementKey]
16223
16621
  );
16224
- const onCodeThemeSelect = useCallback29(
16622
+ const onCodeThemeSelect = useCallback30(
16225
16623
  (value) => {
16226
16624
  activeEditor.update(() => {
16227
16625
  if (selectedElementKey !== null) {
@@ -16955,11 +17353,11 @@ function Editor({ placeholder: placeholderProp, maxLength }) {
16955
17353
  } = useSettings();
16956
17354
  const isEditable = useLexicalEditable10();
16957
17355
  const placeholder = placeholderProp ?? (isRichText ? "Enter some rich text..." : "Enter some plain text...");
16958
- const [floatingAnchorElem, setFloatingAnchorElem] = useState42(null);
16959
- const [isSmallWidthViewport, setIsSmallWidthViewport] = useState42(false);
17356
+ const [floatingAnchorElem, setFloatingAnchorElem] = useState43(null);
17357
+ const [isSmallWidthViewport, setIsSmallWidthViewport] = useState43(false);
16960
17358
  const [editor] = useLexicalComposerContext49();
16961
- const [activeEditor, setActiveEditor] = useState42(editor);
16962
- const [isLinkEditMode, setIsLinkEditMode] = useState42(false);
17359
+ const [activeEditor, setActiveEditor] = useState43(editor);
17360
+ const [isLinkEditMode, setIsLinkEditMode] = useState43(false);
16963
17361
  const onRef = (_floatingAnchorElem) => {
16964
17362
  if (_floatingAnchorElem !== null) {
16965
17363
  setFloatingAnchorElem(_floatingAnchorElem);
@@ -17289,9 +17687,9 @@ function HtmlPlugin({
17289
17687
  debounceMs = 300
17290
17688
  }) {
17291
17689
  const [editor] = useLexicalComposerContext50();
17292
- const lastSyncedValue = useRef18(null);
17293
- const hasUserEdited = useRef18(false);
17294
- const debounceTimer = useRef18(null);
17690
+ const lastSyncedValue = useRef20(null);
17691
+ const hasUserEdited = useRef20(false);
17692
+ const debounceTimer = useRef20(null);
17295
17693
  useEffect48(() => {
17296
17694
  return editor.registerCommand(
17297
17695
  FOCUS_COMMAND2,
@@ -17341,7 +17739,7 @@ function HtmlPlugin({
17341
17739
  { tag: "historic" }
17342
17740
  );
17343
17741
  }, [editor, value]);
17344
- const handleChange = useCallback30(
17742
+ const handleChange = useCallback31(
17345
17743
  (_editorState, _editor, tags) => {
17346
17744
  if (!tags.has("historic")) {
17347
17745
  hasUserEdited.current = true;
@@ -17392,7 +17790,7 @@ function LexicalEditor20({
17392
17790
  readOnly,
17393
17791
  maxLength
17394
17792
  }) {
17395
- const [isFullscreen, setIsFullscreen] = useState43(false);
17793
+ const [isFullscreen, setIsFullscreen] = useState44(false);
17396
17794
  const initialConfig = {
17397
17795
  namespace: "LexicalEditor",
17398
17796
  nodes: [...PlaygroundNodes_default],
@@ -17421,7 +17819,7 @@ function LexicalEditor20({
17421
17819
  document.addEventListener("keydown", handleEsc);
17422
17820
  return () => document.removeEventListener("keydown", handleEsc);
17423
17821
  }, [isFullscreen]);
17424
- const toggleFullscreen = useCallback30(
17822
+ const toggleFullscreen = useCallback31(
17425
17823
  () => setIsFullscreen((f) => !f),
17426
17824
  []
17427
17825
  );