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

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 +116 -21
  2. package/dist/index.mjs +118 -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,46 @@ 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 group/checkbox" }, /* @__PURE__ */ import_react7.default.createElement(
4425
+ "div",
4426
+ {
4427
+ onClick: (e) => {
4428
+ e.stopPropagation();
4429
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4430
+ },
4431
+ className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
4432
+ ${isChecked ? "bg-indigo-500 border-indigo-500 shadow-[0_0_8px_rgba(99,102,241,0.4)]" : "border-slate-500 bg-slate-900/50 hover:border-slate-400 group-hover/checkbox:border-slate-400"}
4433
+ `
4434
+ },
4435
+ isChecked && /* @__PURE__ */ import_react7.default.createElement(import_fi5.FiCheck, { size: 12, className: "text-white" })
4436
+ ), /* @__PURE__ */ import_react7.default.createElement(
4437
+ "span",
4438
+ {
4439
+ className: `transition-all duration-200 cursor-pointer pt-[1px]
4440
+ ${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
4441
+ `,
4442
+ onClick: (e) => {
4443
+ e.stopPropagation();
4444
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4445
+ }
4446
+ },
4447
+ processContent(content)
4448
+ ));
4449
+ }
4450
+ const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
4451
+ if (numberMatch) {
4452
+ const [_, space, numberStr, content] = numberMatch;
4453
+ 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)));
4454
+ }
4400
4455
  if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
4401
4456
  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));
4457
+ 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
4458
  }
4404
4459
  return /* @__PURE__ */ import_react7.default.createElement("span", { className: "break-words" }, processContent(line));
4405
4460
  };
@@ -4411,14 +4466,31 @@ function DescriptionDisplay({
4411
4466
  onOpenReference,
4412
4467
  onMentionClick,
4413
4468
  onImageClick,
4414
- // <--- NOVA PROP RECEBIDA
4415
4469
  onSectionChange,
4416
4470
  onBranchNav,
4417
4471
  onHighlightNode,
4418
4472
  initialSectionId,
4419
- currentBranchDirection = null
4473
+ currentBranchDirection = null,
4474
+ onSaveDescription
4420
4475
  }) {
4421
- const sections = (0, import_react7.useMemo)(() => parseDescriptionSections(description, savedSections), [description, savedSections]);
4476
+ const [localDescription, setLocalDescription] = (0, import_react7.useState)(description || "");
4477
+ (0, import_react7.useEffect)(() => {
4478
+ setLocalDescription(description || "");
4479
+ }, [description]);
4480
+ const sections = (0, import_react7.useMemo)(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
4481
+ const globalCheckboxCounterRef = (0, import_react7.useRef)(0);
4482
+ const handleToggleCheckbox = (targetIndex) => {
4483
+ let currentIndex = 0;
4484
+ const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
4485
+ if (currentIndex === targetIndex) {
4486
+ currentIndex++;
4487
+ return state === " " ? `${space}- [x]` : `${space}- [ ]`;
4488
+ }
4489
+ currentIndex++;
4490
+ return match;
4491
+ });
4492
+ setLocalDescription(newDesc);
4493
+ };
4422
4494
  const flatNavigation = (0, import_react7.useMemo)(() => {
4423
4495
  const navItems = [];
4424
4496
  sections.forEach((section, sIdx) => {
@@ -4559,26 +4631,27 @@ function DescriptionDisplay({
4559
4631
  }
4560
4632
  const lines = part.replace(/\n$/, "").split("\n");
4561
4633
  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
4634
  const isEmptyLine = line.trim() === "";
4564
4635
  if (isEmptyLine) {
4565
4636
  return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ import_react7.default.createElement("br", null));
4566
4637
  }
4567
4638
  return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ import_react7.default.createElement(
4568
- "span",
4639
+ "div",
4569
4640
  {
4570
4641
  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);
4642
+ onClick: (e) => {
4643
+ if (e.target.type !== "checkbox") {
4644
+ const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4645
+ if (idx !== -1) setCurrentStepIndex(idx);
4646
+ }
4574
4647
  },
4575
4648
  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"}
4649
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
4650
+ ${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4578
4651
  `
4579
4652
  },
4580
- formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
4581
- ), !isLastLine && /* @__PURE__ */ import_react7.default.createElement("br", null));
4653
+ formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
4654
+ ));
4582
4655
  }));
4583
4656
  });
4584
4657
  };
@@ -4606,7 +4679,9 @@ function DescriptionDisplay({
4606
4679
  ${isActiveSection ? "opacity-100" : "opacity-90"}
4607
4680
  ` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
4608
4681
  };
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) => {
4682
+ globalCheckboxCounterRef.current = 0;
4683
+ const hasUnsavedChanges = localDescription !== (description || "");
4684
+ 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
4685
  const currentNavItem = flatNavigation[currentStepIndex];
4611
4686
  const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
4612
4687
  const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
@@ -4622,7 +4697,18 @@ function DescriptionDisplay({
4622
4697
  if (index === 0) leadingSpace = "";
4623
4698
  const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
4624
4699
  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
- }));
4700
+ })), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ import_react7.default.createElement("div", { className: "absolute bottom-2 left-2 z-[100] animate-in slide-in-from-bottom-2 fade-in duration-300" }, /* @__PURE__ */ import_react7.default.createElement(
4701
+ "button",
4702
+ {
4703
+ onClick: (e) => {
4704
+ e.stopPropagation();
4705
+ onSaveDescription(localDescription);
4706
+ },
4707
+ className: "flex items-center gap-1.5 px-3 py-1.5 bg-emerald-600/90 hover:bg-emerald-500 text-white rounded-md shadow-[0_4px_12px_rgba(5,150,105,0.3)] text-xs font-medium transition-all hover:scale-105 active:scale-95 border border-emerald-400/20 backdrop-blur-sm"
4708
+ },
4709
+ /* @__PURE__ */ import_react7.default.createElement(import_fi5.FiSave, { size: 12 }),
4710
+ " Salvar Checklist"
4711
+ )));
4626
4712
  }
4627
4713
 
4628
4714
  // src/components/DescriptionReadModePanel.jsx
@@ -4712,7 +4798,8 @@ function DescriptionReadModePanel({
4712
4798
  userRole,
4713
4799
  abstractionTree = null,
4714
4800
  onRenderAbstractionTree = null,
4715
- initialShowAbstraction = false
4801
+ initialShowAbstraction = false,
4802
+ onSaveDescription
4716
4803
  }) {
4717
4804
  const [showProperties, setShowProperties] = (0, import_react8.useState)(false);
4718
4805
  const [showAbstraction, setShowAbstraction] = (0, import_react8.useState)(false);
@@ -4930,7 +5017,8 @@ function DescriptionReadModePanel({
4930
5017
  onHighlightNode,
4931
5018
  initialSectionId,
4932
5019
  currentBranchDirection,
4933
- onImageClick
5020
+ onImageClick,
5021
+ onSaveDescription
4934
5022
  }
4935
5023
  )),
4936
5024
  leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ import_react8.default.createElement(
@@ -7712,6 +7800,11 @@ function NodeDetailsPanel({
7712
7800
  textureImageUrl: url
7713
7801
  });
7714
7802
  };
7803
+ const handleSaveDescriptionInline = (newDescription) => {
7804
+ setDescription(newDescription);
7805
+ onDataUpdate({ ...node, description: newDescription });
7806
+ triggerAutoSave({ description: newDescription });
7807
+ };
7715
7808
  const handleSave = async (keepOpen = false, overrides = {}) => {
7716
7809
  const currentName = overrides.name !== void 0 ? overrides.name : name;
7717
7810
  const currentTypes = overrides.types !== void 0 ? overrides.types : types;
@@ -7806,7 +7899,8 @@ function NodeDetailsPanel({
7806
7899
  availableAncestries,
7807
7900
  onOpenReference,
7808
7901
  onMentionClick,
7809
- onImageClick: handleImageClickFromText
7902
+ onImageClick: handleImageClickFromText,
7903
+ onSaveDescription: handleSaveDescriptionInline
7810
7904
  }
7811
7905
  ) : /* @__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
7906
  "button",
@@ -7874,7 +7968,8 @@ function NodeDetailsPanel({
7874
7968
  availableAncestries,
7875
7969
  onOpenReference,
7876
7970
  onMentionClick,
7877
- onImageClick: handleImageClickFromText
7971
+ onImageClick: handleImageClickFromText,
7972
+ onSaveDescription: handleSaveDescriptionInline
7878
7973
  }
7879
7974
  ), /* @__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
7975
  "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,46 @@ 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 group/checkbox" }, /* @__PURE__ */ React6.createElement(
4381
+ "div",
4382
+ {
4383
+ onClick: (e) => {
4384
+ e.stopPropagation();
4385
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4386
+ },
4387
+ className: `mt-1 cursor-pointer w-4 h-4 rounded border flex-shrink-0 flex items-center justify-center transition-all duration-200
4388
+ ${isChecked ? "bg-indigo-500 border-indigo-500 shadow-[0_0_8px_rgba(99,102,241,0.4)]" : "border-slate-500 bg-slate-900/50 hover:border-slate-400 group-hover/checkbox:border-slate-400"}
4389
+ `
4390
+ },
4391
+ isChecked && /* @__PURE__ */ React6.createElement(FiCheck3, { size: 12, className: "text-white" })
4392
+ ), /* @__PURE__ */ React6.createElement(
4393
+ "span",
4394
+ {
4395
+ className: `transition-all duration-200 cursor-pointer pt-[1px]
4396
+ ${isChecked ? "line-through text-slate-500" : "text-slate-200 group-hover/checkbox:text-white"}
4397
+ `,
4398
+ onClick: (e) => {
4399
+ e.stopPropagation();
4400
+ if (onToggleCheckbox) onToggleCheckbox(currentIdx);
4401
+ }
4402
+ },
4403
+ processContent(content)
4404
+ ));
4405
+ }
4406
+ const numberMatch = trimmedLine.match(/^(\s*)(\d+\.)\s+(.*)/);
4407
+ if (numberMatch) {
4408
+ const [_, space, numberStr, content] = numberMatch;
4409
+ 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)));
4410
+ }
4356
4411
  if (trimmedLine.trim().startsWith("- ") || trimmedLine.trim().startsWith("* ")) {
4357
4412
  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));
4413
+ 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
4414
  }
4360
4415
  return /* @__PURE__ */ React6.createElement("span", { className: "break-words" }, processContent(line));
4361
4416
  };
@@ -4367,14 +4422,31 @@ function DescriptionDisplay({
4367
4422
  onOpenReference,
4368
4423
  onMentionClick,
4369
4424
  onImageClick,
4370
- // <--- NOVA PROP RECEBIDA
4371
4425
  onSectionChange,
4372
4426
  onBranchNav,
4373
4427
  onHighlightNode,
4374
4428
  initialSectionId,
4375
- currentBranchDirection = null
4429
+ currentBranchDirection = null,
4430
+ onSaveDescription
4376
4431
  }) {
4377
- const sections = useMemo5(() => parseDescriptionSections(description, savedSections), [description, savedSections]);
4432
+ const [localDescription, setLocalDescription] = useState7(description || "");
4433
+ useEffect6(() => {
4434
+ setLocalDescription(description || "");
4435
+ }, [description]);
4436
+ const sections = useMemo5(() => parseDescriptionSections(localDescription, savedSections), [localDescription, savedSections]);
4437
+ const globalCheckboxCounterRef = useRef6(0);
4438
+ const handleToggleCheckbox = (targetIndex) => {
4439
+ let currentIndex = 0;
4440
+ const newDesc = localDescription.replace(/^(\s*)- \[([ xX])\]/gm, (match, space, state) => {
4441
+ if (currentIndex === targetIndex) {
4442
+ currentIndex++;
4443
+ return state === " " ? `${space}- [x]` : `${space}- [ ]`;
4444
+ }
4445
+ currentIndex++;
4446
+ return match;
4447
+ });
4448
+ setLocalDescription(newDesc);
4449
+ };
4378
4450
  const flatNavigation = useMemo5(() => {
4379
4451
  const navItems = [];
4380
4452
  sections.forEach((section, sIdx) => {
@@ -4515,26 +4587,27 @@ function DescriptionDisplay({
4515
4587
  }
4516
4588
  const lines = part.replace(/\n$/, "").split("\n");
4517
4589
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `text-${parentIndex}-${partIndex}` }, lines.map((line, lineIndex) => {
4518
- const isLastLine = lineIndex === lines.length - 1;
4519
4590
  const isEmptyLine = line.trim() === "";
4520
4591
  if (isEmptyLine) {
4521
4592
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement("br", null));
4522
4593
  }
4523
4594
  return /* @__PURE__ */ React6.createElement(React6.Fragment, { key: `${parentIndex}-${partIndex}-${lineIndex}` }, /* @__PURE__ */ React6.createElement(
4524
- "span",
4595
+ "div",
4525
4596
  {
4526
4597
  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);
4598
+ onClick: (e) => {
4599
+ if (e.target.type !== "checkbox") {
4600
+ const idx = flatNavigation.findIndex((item) => item.type === "section" && item.sectionIndex === parentIndex);
4601
+ if (idx !== -1) setCurrentStepIndex(idx);
4602
+ }
4530
4603
  },
4531
4604
  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"}
4605
+ transition-colors duration-200 cursor-pointer rounded-md px-1 py-0.5 -mx-1 box-decoration-clone inline-block w-full
4606
+ ${isActiveSection ? "bg-indigo-500/10 text-white ring-1 ring-indigo-500/30" : "hover:bg-white/5 hover:text-slate-200"}
4534
4607
  `
4535
4608
  },
4536
- formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick)
4537
- ), !isLastLine && /* @__PURE__ */ React6.createElement("br", null));
4609
+ formatLineContent2(line, availableNodes, onMentionClick, isActiveSection ? activeMentionIndex : -1, mentionCounterRef, setRef, onImageClick, handleToggleCheckbox, globalCheckboxCounterRef)
4610
+ ));
4538
4611
  }));
4539
4612
  });
4540
4613
  };
@@ -4562,7 +4635,9 @@ function DescriptionDisplay({
4562
4635
  ${isActiveSection ? "opacity-100" : "opacity-90"}
4563
4636
  ` }, renderMixedContent(resolved.content, index, isActiveSection, -1, setRef)));
4564
4637
  };
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) => {
4638
+ globalCheckboxCounterRef.current = 0;
4639
+ const hasUnsavedChanges = localDescription !== (description || "");
4640
+ 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
4641
  const currentNavItem = flatNavigation[currentStepIndex];
4567
4642
  const isSectionContextActive = currentNavItem && currentNavItem.sectionIndex === index;
4568
4643
  const activeMentionIndex = isSectionContextActive && currentNavItem.type === "mention" ? currentNavItem.mentionIndex : -1;
@@ -4578,7 +4653,18 @@ function DescriptionDisplay({
4578
4653
  if (index === 0) leadingSpace = "";
4579
4654
  const isRef = bodyText.trim().match(/^\[\[REF:(node|ancestry):([a-zA-Z0-9\-_]+):([a-zA-Z0-9\-_]+)\]\]$/);
4580
4655
  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
- }));
4656
+ })), hasUnsavedChanges && onSaveDescription && /* @__PURE__ */ React6.createElement("div", { className: "absolute bottom-2 left-2 z-[100] animate-in slide-in-from-bottom-2 fade-in duration-300" }, /* @__PURE__ */ React6.createElement(
4657
+ "button",
4658
+ {
4659
+ onClick: (e) => {
4660
+ e.stopPropagation();
4661
+ onSaveDescription(localDescription);
4662
+ },
4663
+ className: "flex items-center gap-1.5 px-3 py-1.5 bg-emerald-600/90 hover:bg-emerald-500 text-white rounded-md shadow-[0_4px_12px_rgba(5,150,105,0.3)] text-xs font-medium transition-all hover:scale-105 active:scale-95 border border-emerald-400/20 backdrop-blur-sm"
4664
+ },
4665
+ /* @__PURE__ */ React6.createElement(FiSave, { size: 12 }),
4666
+ " Salvar Checklist"
4667
+ )));
4582
4668
  }
4583
4669
 
4584
4670
  // src/components/DescriptionReadModePanel.jsx
@@ -4682,7 +4768,8 @@ function DescriptionReadModePanel({
4682
4768
  userRole,
4683
4769
  abstractionTree = null,
4684
4770
  onRenderAbstractionTree = null,
4685
- initialShowAbstraction = false
4771
+ initialShowAbstraction = false,
4772
+ onSaveDescription
4686
4773
  }) {
4687
4774
  const [showProperties, setShowProperties] = useState8(false);
4688
4775
  const [showAbstraction, setShowAbstraction] = useState8(false);
@@ -4900,7 +4987,8 @@ function DescriptionReadModePanel({
4900
4987
  onHighlightNode,
4901
4988
  initialSectionId,
4902
4989
  currentBranchDirection,
4903
- onImageClick
4990
+ onImageClick,
4991
+ onSaveDescription
4904
4992
  }
4905
4993
  )),
4906
4994
  leftAction && !showAbstraction && !showProperties && /* @__PURE__ */ React7.createElement(
@@ -7698,6 +7786,11 @@ function NodeDetailsPanel({
7698
7786
  textureImageUrl: url
7699
7787
  });
7700
7788
  };
7789
+ const handleSaveDescriptionInline = (newDescription) => {
7790
+ setDescription(newDescription);
7791
+ onDataUpdate({ ...node, description: newDescription });
7792
+ triggerAutoSave({ description: newDescription });
7793
+ };
7701
7794
  const handleSave = async (keepOpen = false, overrides = {}) => {
7702
7795
  const currentName = overrides.name !== void 0 ? overrides.name : name;
7703
7796
  const currentTypes = overrides.types !== void 0 ? overrides.types : types;
@@ -7792,7 +7885,8 @@ function NodeDetailsPanel({
7792
7885
  availableAncestries,
7793
7886
  onOpenReference,
7794
7887
  onMentionClick,
7795
- onImageClick: handleImageClickFromText
7888
+ onImageClick: handleImageClickFromText,
7889
+ onSaveDescription: handleSaveDescriptionInline
7796
7890
  }
7797
7891
  ) : /* @__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
7892
  "button",
@@ -7860,7 +7954,8 @@ function NodeDetailsPanel({
7860
7954
  availableAncestries,
7861
7955
  onOpenReference,
7862
7956
  onMentionClick,
7863
- onImageClick: handleImageClickFromText
7957
+ onImageClick: handleImageClickFromText,
7958
+ onSaveDescription: handleSaveDescriptionInline
7864
7959
  }
7865
7960
  ), /* @__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
7961
  "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.18",
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",