@lv-x-software-house/x_view 1.2.2-dev.14 → 1.2.2-dev.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +104 -21
  2. package/dist/index.mjs +106 -23
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3216,8 +3216,8 @@ function CustomPropertyDisplay({
3216
3216
  const availableOptions = [
3217
3217
  { value: "links", label: "Links", unique: true },
3218
3218
  { value: "images", label: "Images", unique: true },
3219
- { value: "documents", label: "Documents", unique: true },
3220
3219
  { value: "date", label: "Data", unique: true },
3220
+ { value: "documents", label: "Documents", unique: true },
3221
3221
  { value: "text", label: "Texto", unique: false },
3222
3222
  { value: "number", label: "N\xFAmero", unique: false },
3223
3223
  { value: "list", label: "Lista", unique: false }
@@ -4080,6 +4080,24 @@ function DescriptionEditModal({
4080
4080
  },
4081
4081
  /* @__PURE__ */ import_react6.default.createElement(import_fi4.FiList, { size: 12 }),
4082
4082
  " Lista"
4083
+ ), /* @__PURE__ */ import_react6.default.createElement(
4084
+ "button",
4085
+ {
4086
+ onClick: () => insertAtCursor("1. "),
4087
+ className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
4088
+ title: "Lista Numerada"
4089
+ },
4090
+ /* @__PURE__ */ import_react6.default.createElement("span", { className: "text-[10px] font-bold" }, "1."),
4091
+ " Numerada"
4092
+ ), /* @__PURE__ */ import_react6.default.createElement(
4093
+ "button",
4094
+ {
4095
+ onClick: () => insertAtCursor("- [ ] "),
4096
+ className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
4097
+ title: "Checklist (Checkbox)"
4098
+ },
4099
+ /* @__PURE__ */ import_react6.default.createElement(import_fi4.FiCheckSquare, { size: 12 }),
4100
+ " Checklist"
4083
4101
  ), /* @__PURE__ */ import_react6.default.createElement(
4084
4102
  "button",
4085
4103
  {
@@ -4386,7 +4404,7 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
4386
4404
  );
4387
4405
  });
4388
4406
  };
4389
- var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
4407
+ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
4390
4408
  const trimmedLine = line.replace(/\r$/, "");
4391
4409
  const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
4392
4410
  if (line.startsWith("# ")) {
@@ -4397,9 +4415,33 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
4397
4415
  const content = line.replace("## ", "");
4398
4416
  return /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
4399
4417
  }
4418
+ const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
4419
+ if (checkboxMatch) {
4420
+ const [_, space, state, content] = checkboxMatch;
4421
+ const isChecked = state.toLowerCase() === "x";
4422
+ const currentIdx = globalCheckboxCounterRef.current;
4423
+ globalCheckboxCounterRef.current += 1;
4424
+ return /* @__PURE__ */ import_react7.default.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1" }, /* @__PURE__ */ import_react7.default.createElement(
4425
+ "input",
4426
+ {
4427
+ type: "checkbox",
4428
+ checked: isChecked,
4429
+ onChange: (e) => {
4430
+ e.stopPropagation();
4431
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4432
+ },
4433
+ className: "mt-1 cursor-pointer accent-indigo-500 w-3.5 h-3.5 border-white/20 rounded-sm focus:ring-indigo-500 focus:ring-offset-slate-900"
4434
+ }
4435
+ ), /* @__PURE__ */ import_react7.default.createElement("span", { className: `transition-all duration-200 ${isChecked ? "line-through text-slate-500" : "text-slate-200"}` }, processContent(content)));
4436
+ }
4437
+ const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
4438
+ if (numberMatch) {
4439
+ const [_, space, numberStr, content] = numberMatch;
4440
+ return /* @__PURE__ */ import_react7.default.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-indigo-400 font-mono font-bold text-xs mt-[3px] shrink-0" }, numberStr), /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-slate-200" }, processContent(content)));
4441
+ }
4400
4442
  if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
4401
4443
  const content = trimmedLine.trim().substring(2);
4402
- return /* @__PURE__ */ import_react7.default.createElement("span", { className: "pl-2 text-slate-200 break-words" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-indigo-400 font-bold mr-1.5" }, "\u2022"), processContent(content));
4444
+ return /* @__PURE__ */ import_react7.default.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1 text-slate-200" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "text-indigo-400 font-bold shrink-0 mt-[2px] text-xs" }, "\u2022"), /* @__PURE__ */ import_react7.default.createElement("span", null, processContent(content)));
4403
4445
  }
4404
4446
  return /* @__PURE__ */ import_react7.default.createElement("span", { className: "break-words" }, processContent(line));
4405
4447
  };
@@ -4411,14 +4453,32 @@ function DescriptionDisplay({
4411
4453
  onOpenReference,
4412
4454
  onMentionClick,
4413
4455
  onImageClick,
4414
- // <--- NOVA PROP RECEBIDA
4415
4456
  onSectionChange,
4416
4457
  onBranchNav,
4417
4458
  onHighlightNode,
4418
4459
  initialSectionId,
4419
- currentBranchDirection = null
4460
+ currentBranchDirection = null,
4461
+ onSaveDescription
4462
+ // NOVO: Prop para salvar checklist
4420
4463
  }) {
4421
- const sections = (0, import_react7.useMemo)(() => parseDescriptionSections(description, savedSections), [description, savedSections]);
4464
+ const [localDescription, setLocalDescription] = (0, import_react7.useState)(description || "");
4465
+ (0, import_react7.useEffect)(() => {
4466
+ setLocalDescription(description || "");
4467
+ }, [description]);
4468
+ const sections = (0, import_react7.useMemo)(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
4469
+ const globalCheckboxCounterRef = (0, import_react7.useRef)(0);
4470
+ const handleToggleCheckbox = (targetIndex) => {
4471
+ let currentIndex = 0;
4472
+ const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
4473
+ if (currentIndex === targetIndex) {
4474
+ currentIndex++;
4475
+ return state === " " ? `${space}- [x]` : `${space}- [ ]`;
4476
+ }
4477
+ currentIndex++;
4478
+ return match;
4479
+ });
4480
+ setLocalDescription(newDesc);
4481
+ };
4422
4482
  const flatNavigation = (0, import_react7.useMemo)(() => {
4423
4483
  const navItems = [];
4424
4484
  sections.forEach((section, sIdx) => {
@@ -4559,26 +4619,27 @@ function DescriptionDisplay({
4559
4619
  }
4560
4620
  const lines = part.replace(/\n$/, "").split("\n");
4561
4621
  return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
4562
- const isLastLine = lineIndex === lines.length - 1;
4563
4622
  const isEmptyLine = line.trim() === "";
4564
4623
  if (isEmptyLine) {
4565
4624
  return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ import_react7.default.createElement("br", null));
4566
4625
  }
4567
4626
  return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ import_react7.default.createElement(
4568
- "span",
4627
+ "div",
4569
4628
  {
4570
4629
  ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
4571
- onClick: () => {
4572
- const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4573
- if (idx !== -1) setCurrentStepIndex(idx);
4630
+ onClick: (e) => {
4631
+ if (e.target.type !== "checkbox") {
4632
+ const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4633
+ if (idx !== -1) setCurrentStepIndex(idx);
4634
+ }
4574
4635
  },
4575
4636
  className: `
4576
- transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
4577
- ${isActiveSection ? "bg-indigo-500/20 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4637
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
4638
+ ${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4578
4639
  `
4579
4640
  },
4580
- formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
4581
- ), !isLastLine && /* @__PURE__ */ import_react7.default.createElement("br", null));
4641
+ formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
4642
+ ));
4582
4643
  }));
4583
4644
  });
4584
4645
  };
@@ -4606,7 +4667,9 @@ function DescriptionDisplay({
4606
4667
  ${isActiveSection ? "opacity-100" : "opacity-90"}
4607
4668
  ` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
4608
4669
  };
4609
- return /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-2 pr-9" }, sections.map((section, index) => {
4670
+ globalCheckboxCounterRef.current = 0;
4671
+ const hasUnsavedChanges = localDescription !== (description || "");
4672
+ return /* @__PURE__ */ import_react7.default.createElement("div", { className: "relative w-full h-full min-h-[100px]" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-16 pr-9" }, sections.map((section, index) => {
4610
4673
  const currentNavItem = flatNavigation[currentStepIndex];
4611
4674
  const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
4612
4675
  const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
@@ -4622,7 +4685,18 @@ function DescriptionDisplay({
4622
4685
  if (index === 0) leadingSpace = "";
4623
4686
  const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
4624
4687
  return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: index }, /* @__PURE__ */ import_react7.default.createElement("span", null, leadingSpace), isRef ? renderReferenceSection(bodyText, index, isSectionContextActive, setRef) : renderMixedContent(bodyText, index, isSectionContextActive, activeMentionIndex, setRef), /* @__PURE__ */ import_react7.default.createElement("span", null, trailingSpace));
4625
- }));
4688
+ })), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ import_react7.default.createElement("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-[100] animate-in slide-in-from-bottom-4 fade-in duration-300" }, /* @__PURE__ */ import_react7.default.createElement(
4689
+ "button",
4690
+ {
4691
+ onClick: (e) => {
4692
+ e.stopPropagation();
4693
+ onSaveDescription(localDescription);
4694
+ },
4695
+ className: "flex items-center gap-2 px-5 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white rounded-full shadow-[0_8px_20px_rgba(5,150,105,0.4)] font-semibold text-sm transition-all hover:scale-105 active:scale-95 border border-emerald-400/30"
4696
+ },
4697
+ /* @__PURE__ */ import_react7.default.createElement(import_fi5.FiSave, { size: 16 }),
4698
+ " Salvar Checklist"
4699
+ )));
4626
4700
  }
4627
4701
 
4628
4702
  // src/components/DescriptionReadModePanel.jsx
@@ -4712,7 +4786,8 @@ function DescriptionReadModePanel({
4712
4786
  userRole,
4713
4787
  abstractionTree = null,
4714
4788
  onRenderAbstractionTree = null,
4715
- initialShowAbstraction = false
4789
+ initialShowAbstraction = false,
4790
+ onSaveDescription
4716
4791
  }) {
4717
4792
  const [showProperties, setShowProperties] = (0, import_react8.useState)(false);
4718
4793
  const [showAbstraction, setShowAbstraction] = (0, import_react8.useState)(false);
@@ -4930,7 +5005,8 @@ function DescriptionReadModePanel({
4930
5005
  onHighlightNode,
4931
5006
  initialSectionId,
4932
5007
  currentBranchDirection,
4933
- onImageClick
5008
+ onImageClick,
5009
+ onSaveDescription
4934
5010
  }
4935
5011
  )),
4936
5012
  leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ import_react8.default.createElement(
@@ -7712,6 +7788,11 @@ function NodeDetailsPanel({
7712
7788
  textureImageUrl: url
7713
7789
  });
7714
7790
  };
7791
+ const handleSaveDescriptionInline = (newDescription) => {
7792
+ setDescription(newDescription);
7793
+ onDataUpdate({ ...node, description: newDescription });
7794
+ triggerAutoSave({ description: newDescription });
7795
+ };
7715
7796
  const handleSave = async (keepOpen = false, overrides = {}) => {
7716
7797
  const currentName = overrides.name !== void 0 ? overrides.name : name;
7717
7798
  const currentTypes = overrides.types !== void 0 ? overrides.types : types;
@@ -7806,7 +7887,8 @@ function NodeDetailsPanel({
7806
7887
  availableAncestries,
7807
7888
  onOpenReference,
7808
7889
  onMentionClick,
7809
- onImageClick: handleImageClickFromText
7890
+ onImageClick: handleImageClickFromText,
7891
+ onSaveDescription: handleSaveDescriptionInline
7810
7892
  }
7811
7893
  ) : /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ import_react16.default.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ import_react16.default.createElement("div", null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ import_react16.default.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ import_react16.default.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ import_react16.default.createElement(
7812
7894
  "button",
@@ -7874,7 +7956,8 @@ function NodeDetailsPanel({
7874
7956
  availableAncestries,
7875
7957
  onOpenReference,
7876
7958
  onMentionClick,
7877
- onImageClick: handleImageClickFromText
7959
+ onImageClick: handleImageClickFromText,
7960
+ onSaveDescription: handleSaveDescriptionInline
7878
7961
  }
7879
7962
  ), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ import_react16.default.createElement(
7880
7963
  "button",
package/dist/index.mjs CHANGED
@@ -3172,8 +3172,8 @@ function CustomPropertyDisplay({
3172
3172
  const availableOptions = [
3173
3173
  { value: "links", label: "Links", unique: true },
3174
3174
  { value: "images", label: "Images", unique: true },
3175
- { value: "documents", label: "Documents", unique: true },
3176
3175
  { value: "date", label: "Data", unique: true },
3176
+ { value: "documents", label: "Documents", unique: true },
3177
3177
  { value: "text", label: "Texto", unique: false },
3178
3178
  { value: "number", label: "N\xFAmero", unique: false },
3179
3179
  { value: "list", label: "Lista", unique: false }
@@ -3396,7 +3396,7 @@ import { FiPlus, FiEdit2 as FiEdit22, FiBookOpen } from "react-icons/fi";
3396
3396
 
3397
3397
  // src/components/DescriptionEditModal.jsx
3398
3398
  import React5, { useState as useState6, useEffect as useEffect5, useRef as useRef5, useMemo as useMemo4 } from "react";
3399
- import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage } from "react-icons/fi";
3399
+ import { FiType, FiList, FiCode, FiLink as FiLink2, FiAtSign, FiSearch as FiSearch2, FiHexagon as FiHexagon2, FiGlobe, FiImage, FiCheckSquare } from "react-icons/fi";
3400
3400
 
3401
3401
  // src/components/SectionImportModal.jsx
3402
3402
  import React4, { useState as useState5, useMemo as useMemo3, useRef as useRef4, useEffect as useEffect4 } from "react";
@@ -4036,6 +4036,24 @@ function DescriptionEditModal({
4036
4036
  },
4037
4037
  /* @__PURE__ */ React5.createElement(FiList, { size: 12 }),
4038
4038
  " Lista"
4039
+ ), /* @__PURE__ */ React5.createElement(
4040
+ "button",
4041
+ {
4042
+ onClick: () => insertAtCursor("1. "),
4043
+ className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
4044
+ title: "Lista Numerada"
4045
+ },
4046
+ /* @__PURE__ */ React5.createElement("span", { className: "text-[10px] font-bold" }, "1."),
4047
+ " Numerada"
4048
+ ), /* @__PURE__ */ React5.createElement(
4049
+ "button",
4050
+ {
4051
+ onClick: () => insertAtCursor("- [ ] "),
4052
+ className: "flex items-center gap-1 px-3 py-1.5 rounded bg-slate-800 hover:bg-slate-700 border border-white/10 text-xs font-medium transition-colors whitespace-nowrap",
4053
+ title: "Checklist (Checkbox)"
4054
+ },
4055
+ /* @__PURE__ */ React5.createElement(FiCheckSquare, { size: 12 }),
4056
+ " Checklist"
4039
4057
  ), /* @__PURE__ */ React5.createElement(
4040
4058
  "button",
4041
4059
  {
@@ -4199,7 +4217,7 @@ function DescriptionEditModal({
4199
4217
 
4200
4218
  // src/components/DescriptionDisplay.jsx
4201
4219
  import React6, { useMemo as useMemo5, useState as useState7, useEffect as useEffect6, useRef as useRef6 } from "react";
4202
- import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2 } from "react-icons/fi";
4220
+ import { FiCopy as FiCopy2, FiCheck as FiCheck3, FiChevronDown as FiChevronDown3, FiChevronRight as FiChevronRight2, FiTerminal as FiTerminal2, FiCornerDownRight, FiExternalLink as FiExternalLink2, FiImage as FiImage2, FiSave } from "react-icons/fi";
4203
4221
  var CodeBlock2 = ({ content, isActive, onClick }) => {
4204
4222
  const [isExpanded, setIsExpanded] = useState7(false);
4205
4223
  const [copied, setCopied] = useState7(false);
@@ -4342,7 +4360,7 @@ var renderTextWithMentions = (text, availableNodes, onMentionClick, activeMentio
4342
4360
  );
4343
4361
  });
4344
4362
  };
4345
- var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick) => {
4363
+ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick, onToggleCheckbox, globalCheckboxCounterRef) => {
4346
4364
  const trimmedLine = line.replace(/\r$/, "");
4347
4365
  const processContent = (content) => renderTextWithMentions(content, availableNodes, onMentionClick, activeMentionIndex, mentionCounterRef, setRef, onImageClick);
4348
4366
  if (line.startsWith("# ")) {
@@ -4353,9 +4371,33 @@ var formatLineContent2 = (line, availableNodes, onMentionClick, activeMentionInd
4353
4371
  const content = line.replace("## ", "");
4354
4372
  return /* @__PURE__ */ React6.createElement("span", { className: "text-sm sm:text-base font-semibold text-indigo-200 leading-tight break-words" }, processContent(content));
4355
4373
  }
4374
+ const checkboxMatch = trimmedLine.match(/^(\s*)- \[([ xX])\]\s+(.*)/);
4375
+ if (checkboxMatch) {
4376
+ const [_, space, state, content] = checkboxMatch;
4377
+ const isChecked = state.toLowerCase() === "x";
4378
+ const currentIdx = globalCheckboxCounterRef.current;
4379
+ globalCheckboxCounterRef.current += 1;
4380
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2.5 my-1 break-words ml-1" }, /* @__PURE__ */ React6.createElement(
4381
+ "input",
4382
+ {
4383
+ type: "checkbox",
4384
+ checked: isChecked,
4385
+ onChange: (e) => {
4386
+ e.stopPropagation();
4387
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4388
+ },
4389
+ className: "mt-1 cursor-pointer accent-indigo-500 w-3.5 h-3.5 border-white/20 rounded-sm focus:ring-indigo-500 focus:ring-offset-slate-900"
4390
+ }
4391
+ ), /* @__PURE__ */ React6.createElement("span", { className: `transition-all duration-200 ${isChecked ? "line-through text-slate-500" : "text-slate-200"}` }, processContent(content)));
4392
+ }
4393
+ const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
4394
+ if (numberMatch) {
4395
+ const [_, space, numberStr, content] = numberMatch;
4396
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-mono font-bold text-xs mt-[3px] shrink-0" }, numberStr), /* @__PURE__ */ React6.createElement("span", { className: "text-slate-200" }, processContent(content)));
4397
+ }
4356
4398
  if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
4357
4399
  const content = trimmedLine.trim().substring(2);
4358
- return /* @__PURE__ */ React6.createElement("span", { className: "pl-2 text-slate-200 break-words" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-bold mr-1.5" }, "\u2022"), processContent(content));
4400
+ return /* @__PURE__ */ React6.createElement("span", { className: "flex items-start gap-2 my-0.5 break-words ml-1 text-slate-200" }, /* @__PURE__ */ React6.createElement("span", { className: "text-indigo-400 font-bold shrink-0 mt-[2px] text-xs" }, "\u2022"), /* @__PURE__ */ React6.createElement("span", null, processContent(content)));
4359
4401
  }
4360
4402
  return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
4361
4403
  };
@@ -4367,14 +4409,32 @@ function DescriptionDisplay({
4367
4409
  onOpenReference,
4368
4410
  onMentionClick,
4369
4411
  onImageClick,
4370
- // <--- NOVA PROP RECEBIDA
4371
4412
  onSectionChange,
4372
4413
  onBranchNav,
4373
4414
  onHighlightNode,
4374
4415
  initialSectionId,
4375
- currentBranchDirection = null
4416
+ currentBranchDirection = null,
4417
+ onSaveDescription
4418
+ // NOVO: Prop para salvar checklist
4376
4419
  }) {
4377
- const sections = useMemo5(() => parseDescriptionSections(description, savedSections), [description, savedSections]);
4420
+ const [localDescription, setLocalDescription] = useState7(description || "");
4421
+ useEffect6(() => {
4422
+ setLocalDescription(description || "");
4423
+ }, [description]);
4424
+ const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
4425
+ const globalCheckboxCounterRef = useRef6(0);
4426
+ const handleToggleCheckbox = (targetIndex) => {
4427
+ let currentIndex = 0;
4428
+ const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
4429
+ if (currentIndex === targetIndex) {
4430
+ currentIndex++;
4431
+ return state === " " ? `${space}- [x]` : `${space}- [ ]`;
4432
+ }
4433
+ currentIndex++;
4434
+ return match;
4435
+ });
4436
+ setLocalDescription(newDesc);
4437
+ };
4378
4438
  const flatNavigation = useMemo5(() => {
4379
4439
  const navItems = [];
4380
4440
  sections.forEach((section, sIdx) => {
@@ -4515,26 +4575,27 @@ function DescriptionDisplay({
4515
4575
  }
4516
4576
  const lines = part.replace(/\n$/, "").split("\n");
4517
4577
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
4518
- const isLastLine = lineIndex === lines.length - 1;
4519
4578
  const isEmptyLine = line.trim() === "";
4520
4579
  if (isEmptyLine) {
4521
4580
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
4522
4581
  }
4523
4582
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
4524
- "span",
4583
+ "div",
4525
4584
  {
4526
4585
  ref: isActiveSection && activeMentionIndex === -1 && partIndex === 0 && lineIndex === 0 ? setRef : null,
4527
- onClick: () => {
4528
- const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4529
- if (idx !== -1) setCurrentStepIndex(idx);
4586
+ onClick: (e) => {
4587
+ if (e.target.type !== "checkbox") {
4588
+ const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4589
+ if (idx !== -1) setCurrentStepIndex(idx);
4590
+ }
4530
4591
  },
4531
4592
  className: `
4532
- transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone
4533
- ${isActiveSection ? "bg-indigo-500/20 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4593
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
4594
+ ${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4534
4595
  `
4535
4596
  },
4536
- formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
4537
- ), !isLastLine && /* @__PURE__ */ React6.createElement("br", null));
4597
+ formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
4598
+ ));
4538
4599
  }));
4539
4600
  });
4540
4601
  };
@@ -4562,7 +4623,9 @@ function DescriptionDisplay({
4562
4623
  ${isActiveSection ? "opacity-100" : "opacity-90"}
4563
4624
  ` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
4564
4625
  };
4565
- return /* @__PURE__ */ React6.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-2 pr-9" }, sections.map((section, index) => {
4626
+ globalCheckboxCounterRef.current = 0;
4627
+ const hasUnsavedChanges = localDescription !== (description || "");
4628
+ return /* @__PURE__ */ React6.createElement("div", { className: "relative w-full h-full min-h-[100px]" }, /* @__PURE__ */ React6.createElement("div", { className: "w-full text-sm leading-relaxed text-slate-300 break-words whitespace-pre-wrap px-3 pt-1 pb-16 pr-9" }, sections.map((section, index) => {
4566
4629
  const currentNavItem = flatNavigation[currentStepIndex];
4567
4630
  const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
4568
4631
  const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
@@ -4578,7 +4641,18 @@ function DescriptionDisplay({
4578
4641
  if (index === 0) leadingSpace = "";
4579
4642
  const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
4580
4643
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: index }, /* @__PURE__ */ React6.createElement("span", null, leadingSpace), isRef ? renderReferenceSection(bodyText, index, isSectionContextActive, setRef) : renderMixedContent(bodyText, index, isSectionContextActive, activeMentionIndex, setRef), /* @__PURE__ */ React6.createElement("span", null, trailingSpace));
4581
- }));
4644
+ })), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ React6.createElement("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-[100] animate-in slide-in-from-bottom-4 fade-in duration-300" }, /* @__PURE__ */ React6.createElement(
4645
+ "button",
4646
+ {
4647
+ onClick: (e) => {
4648
+ e.stopPropagation();
4649
+ onSaveDescription(localDescription);
4650
+ },
4651
+ className: "flex items-center gap-2 px-5 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white rounded-full shadow-[0_8px_20px_rgba(5,150,105,0.4)] font-semibold text-sm transition-all hover:scale-105 active:scale-95 border border-emerald-400/30"
4652
+ },
4653
+ /* @__PURE__ */ React6.createElement(FiSave, { size: 16 }),
4654
+ " Salvar Checklist"
4655
+ )));
4582
4656
  }
4583
4657
 
4584
4658
  // src/components/DescriptionReadModePanel.jsx
@@ -4682,7 +4756,8 @@ function DescriptionReadModePanel({
4682
4756
  userRole,
4683
4757
  abstractionTree = null,
4684
4758
  onRenderAbstractionTree = null,
4685
- initialShowAbstraction = false
4759
+ initialShowAbstraction = false,
4760
+ onSaveDescription
4686
4761
  }) {
4687
4762
  const [showProperties, setShowProperties] = useState8(false);
4688
4763
  const [showAbstraction, setShowAbstraction] = useState8(false);
@@ -4900,7 +4975,8 @@ function DescriptionReadModePanel({
4900
4975
  onHighlightNode,
4901
4976
  initialSectionId,
4902
4977
  currentBranchDirection,
4903
- onImageClick
4978
+ onImageClick,
4979
+ onSaveDescription
4904
4980
  }
4905
4981
  )),
4906
4982
  leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
@@ -7698,6 +7774,11 @@ function NodeDetailsPanel({
7698
7774
  textureImageUrl: url
7699
7775
  });
7700
7776
  };
7777
+ const handleSaveDescriptionInline = (newDescription) => {
7778
+ setDescription(newDescription);
7779
+ onDataUpdate({ ...node, description: newDescription });
7780
+ triggerAutoSave({ description: newDescription });
7781
+ };
7701
7782
  const handleSave = async (keepOpen = false, overrides = {}) => {
7702
7783
  const currentName = overrides.name !== void 0 ? overrides.name : name;
7703
7784
  const currentTypes = overrides.types !== void 0 ? overrides.types : types;
@@ -7792,7 +7873,8 @@ function NodeDetailsPanel({
7792
7873
  availableAncestries,
7793
7874
  onOpenReference,
7794
7875
  onMentionClick,
7795
- onImageClick: handleImageClickFromText
7876
+ onImageClick: handleImageClickFromText,
7877
+ onSaveDescription: handleSaveDescriptionInline
7796
7878
  }
7797
7879
  ) : /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "h-[2px] bg-gradient-to-r from-indigo-400/0 via-indigo-400/70 to-indigo-400/0" }), /* @__PURE__ */ React15.createElement("div", { className: "px-6 pt-5 pb-3 flex items-start justify-between gap-4" }, /* @__PURE__ */ React15.createElement("div", null, /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React15.createElement("span", { className: "inline-flex h-2.5 w-2.5 rounded-full bg-indigo-400/80 shadow-[0_0_18px_2px_rgba(99,102,241,0.55)]" }), /* @__PURE__ */ React15.createElement("p", { className: "text-xs/relaxed text-slate-300" }, "Detalhes do Node"), /* @__PURE__ */ React15.createElement(
7798
7880
  "button",
@@ -7860,7 +7942,8 @@ function NodeDetailsPanel({
7860
7942
  availableAncestries,
7861
7943
  onOpenReference,
7862
7944
  onMentionClick,
7863
- onImageClick: handleImageClickFromText
7945
+ onImageClick: handleImageClickFromText,
7946
+ onSaveDescription: handleSaveDescriptionInline
7864
7947
  }
7865
7948
  ), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-0 right-0 flex bg-slate-900/50 rounded-bl-lg backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity overflow-hidden border-b border-l border-white/5" }, /* @__PURE__ */ React15.createElement(
7866
7949
  "button",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.2-dev.14",
3
+ "version": "1.2.2-dev.15",
4
4
  "description": "Pacote privado contendo os componentes e lógica de renderização 3D do X View.",
5
5
  "author": "iv.x - Engenharia de Software - ivxsoftwarehouse@gmail.com",
6
6
  "license": "UNLICENSED",