@lv-x-software-house/x_view 1.2.6-dev.12 → 1.2.6-dev.14

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 +193 -35
  2. package/dist/index.mjs +196 -36
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13079,6 +13079,7 @@ function RichGroupEditor({
13079
13079
  }) {
13080
13080
  const editorRef = (0, import_react28.useRef)(null);
13081
13081
  const isMountedRef = (0, import_react28.useRef)(false);
13082
+ const dismissedTriggerRef = (0, import_react28.useRef)(null);
13082
13083
  const [mentionState, setMentionState] = (0, import_react28.useState)(null);
13083
13084
  const [isEmpty, setIsEmpty] = (0, import_react28.useState)(true);
13084
13085
  (0, import_react28.useEffect)(() => {
@@ -13094,10 +13095,17 @@ function RichGroupEditor({
13094
13095
  const selection = window.getSelection();
13095
13096
  if (!selection || selection.rangeCount === 0) return null;
13096
13097
  const range = selection.getRangeAt(0);
13097
- if (range.startContainer.nodeType !== Node.TEXT_NODE) return null;
13098
- const textBefore = range.startContainer.textContent.substring(0, range.startOffset);
13098
+ const node = range.startContainer;
13099
+ if (node.nodeType !== Node.TEXT_NODE) return null;
13100
+ const textBefore = node.textContent.substring(0, range.startOffset);
13099
13101
  const atIndex = textBefore.lastIndexOf("@");
13100
- if (atIndex === -1) return null;
13102
+ if (atIndex === -1) {
13103
+ dismissedTriggerRef.current = null;
13104
+ return null;
13105
+ }
13106
+ if (dismissedTriggerRef.current && dismissedTriggerRef.current.node === node && dismissedTriggerRef.current.atIndex === atIndex) {
13107
+ return null;
13108
+ }
13101
13109
  const query = textBefore.substring(atIndex + 1);
13102
13110
  if (query.includes(" ") || query.includes(".") || query.includes(",") || query.length > 40) {
13103
13111
  return null;
@@ -13232,6 +13240,21 @@ function RichGroupEditor({
13232
13240
  const handleBlur = (0, import_react28.useCallback)(() => {
13233
13241
  setTimeout(() => setMentionState(null), 200);
13234
13242
  }, []);
13243
+ const handleMentionDismiss = (0, import_react28.useCallback)(() => {
13244
+ const selection = window.getSelection();
13245
+ if (selection && selection.rangeCount > 0) {
13246
+ const range = selection.getRangeAt(0);
13247
+ const node = range.startContainer;
13248
+ if (node.nodeType === Node.TEXT_NODE) {
13249
+ const textBefore = node.textContent.substring(0, range.startOffset);
13250
+ const atIndex = textBefore.lastIndexOf("@");
13251
+ if (atIndex !== -1) {
13252
+ dismissedTriggerRef.current = { node, atIndex };
13253
+ }
13254
+ }
13255
+ }
13256
+ setMentionState(null);
13257
+ }, []);
13235
13258
  return /* @__PURE__ */ import_react28.default.createElement("div", { className: "relative" }, isEmpty && !readOnly && /* @__PURE__ */ import_react28.default.createElement("div", { className: "absolute top-0 left-0 text-sm text-slate-600 pointer-events-none select-none" }, placeholder || "Escreva sobre este grupo\u2026 ou digite @ para mencionar"), /* @__PURE__ */ import_react28.default.createElement(
13236
13259
  "div",
13237
13260
  {
@@ -13253,14 +13276,14 @@ function RichGroupEditor({
13253
13276
  items: searchItems || [],
13254
13277
  position: mentionState.position,
13255
13278
  onSelect: insertMention,
13256
- onClose: () => setMentionState(null)
13279
+ onClose: handleMentionDismiss
13257
13280
  }
13258
13281
  ));
13259
13282
  }
13260
13283
 
13261
13284
  // src/components/AncestryBoard.jsx
13262
- var GroupItem = ({
13263
- group,
13285
+ var BoardItem = ({
13286
+ item,
13264
13287
  index,
13265
13288
  onUpdate,
13266
13289
  onDelete,
@@ -13269,16 +13292,55 @@ var GroupItem = ({
13269
13292
  onOutdent,
13270
13293
  searchItems,
13271
13294
  onMentionClick,
13295
+ onEnterFolder,
13272
13296
  canEdit
13273
13297
  }) => {
13298
+ var _a;
13299
+ const isFolder = item.type === "folder";
13274
13300
  const canIndent = index > 0;
13275
13301
  const handleContentChange = (content) => {
13276
- onUpdate(group.id, { ...group, content });
13302
+ onUpdate(item.id, { ...item, content });
13303
+ };
13304
+ const handleNameChange = (e) => {
13305
+ onUpdate(item.id, { ...item, name: e.target.value });
13277
13306
  };
13307
+ if (isFolder) {
13308
+ return /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col gap-2 mb-3 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement(
13309
+ "div",
13310
+ {
13311
+ onClick: () => onEnterFolder(item.id),
13312
+ className: "flex items-center gap-3 py-3 px-4 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 rounded-xl cursor-pointer transition-all duration-200 group/folder"
13313
+ },
13314
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-10 h-10 rounded-lg bg-indigo-500/10 flex items-center justify-center text-indigo-400 group-hover/folder:scale-110 transition-transform" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiFolder, { size: 20 })),
13315
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex-1 min-w-0" }, canEdit ? /* @__PURE__ */ import_react29.default.createElement(
13316
+ "input",
13317
+ {
13318
+ type: "text",
13319
+ value: item.name,
13320
+ onChange: handleNameChange,
13321
+ onClick: (e) => e.stopPropagation(),
13322
+ className: "bg-transparent border-none outline-none text-sm font-medium text-slate-200 w-full focus:text-white",
13323
+ placeholder: "Nome da pasta..."
13324
+ }
13325
+ ) : /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-sm font-medium text-slate-200" }, item.name), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-2 mt-0.5" }, /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider font-semibold" }, ((_a = item.children) == null ? void 0 : _a.length) || 0, " itens"))),
13326
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-2 opacity-0 group-hover/folder:opacity-100 transition-opacity" }, canEdit && /* @__PURE__ */ import_react29.default.createElement(
13327
+ "button",
13328
+ {
13329
+ onClick: (e) => {
13330
+ e.stopPropagation();
13331
+ onDelete(item.id);
13332
+ },
13333
+ className: "p-1.5 text-slate-500 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13334
+ title: "Remover Pasta"
13335
+ },
13336
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiTrash2, { size: 14 })
13337
+ ), /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiChevronRight, { className: "text-slate-500 group-hover/folder:translate-x-1 transition-transform" }))
13338
+ ));
13339
+ }
13278
13340
  return /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col gap-2 py-2 px-3 transition-all duration-200 hover:bg-white/5 border-l-2 border-transparent hover:border-white/20" }, /* @__PURE__ */ import_react29.default.createElement(
13279
13341
  RichGroupEditor,
13280
13342
  {
13281
- content: group.content,
13343
+ content: item.content,
13282
13344
  onChange: handleContentChange,
13283
13345
  onMentionClick,
13284
13346
  searchItems,
@@ -13288,15 +13350,25 @@ var GroupItem = ({
13288
13350
  ), canEdit && /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react29.default.createElement(
13289
13351
  "button",
13290
13352
  {
13291
- onClick: () => onAddSubgroup(group.id),
13292
- className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13353
+ onClick: () => onAddSubgroup(item.id, "group"),
13354
+ className: "flex items-center gap-1 px-1.5 py-1 text-[10px] uppercase font-bold tracking-wider text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13293
13355
  title: "Criar Subgrupo"
13294
13356
  },
13295
- /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 14 })
13357
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 12 }),
13358
+ /* @__PURE__ */ import_react29.default.createElement("span", null, "Subgrupo")
13359
+ ), /* @__PURE__ */ import_react29.default.createElement(
13360
+ "button",
13361
+ {
13362
+ onClick: () => onAddSubgroup(item.id, "folder"),
13363
+ className: "flex items-center gap-1 px-1.5 py-1 text-[10px] uppercase font-bold tracking-wider text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13364
+ title: "Criar Subpasta"
13365
+ },
13366
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiFolder, { size: 12 }),
13367
+ /* @__PURE__ */ import_react29.default.createElement("span", null, "Pasta")
13296
13368
  )), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ import_react29.default.createElement(
13297
13369
  "button",
13298
13370
  {
13299
- onClick: () => onIndent(group.id),
13371
+ onClick: () => onIndent(item.id),
13300
13372
  disabled: !canIndent,
13301
13373
  className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
13302
13374
  title: "Aninhar no grupo acima"
@@ -13305,7 +13377,7 @@ var GroupItem = ({
13305
13377
  ), /* @__PURE__ */ import_react29.default.createElement(
13306
13378
  "button",
13307
13379
  {
13308
- onClick: () => onOutdent(group.id),
13380
+ onClick: () => onOutdent(item.id),
13309
13381
  className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13310
13382
  title: "Desaninhar"
13311
13383
  },
@@ -13313,17 +13385,17 @@ var GroupItem = ({
13313
13385
  ), /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ import_react29.default.createElement(
13314
13386
  "button",
13315
13387
  {
13316
- onClick: () => onDelete(group.id),
13388
+ onClick: () => onDelete(item.id),
13317
13389
  className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13318
13390
  title: "Remover Grupo"
13319
13391
  },
13320
13392
  /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiTrash2, { size: 14 })
13321
- )))), group.children && group.children.length > 0 && /* @__PURE__ */ import_react29.default.createElement("div", { className: "ml-2" }, group.children.map((child, idx) => /* @__PURE__ */ import_react29.default.createElement(
13322
- GroupItem,
13393
+ )))), item.children && item.children.length > 0 && /* @__PURE__ */ import_react29.default.createElement("div", { className: "ml-2" }, item.children.map((child, idx) => /* @__PURE__ */ import_react29.default.createElement(
13394
+ BoardItem,
13323
13395
  {
13324
13396
  key: child.id,
13325
13397
  index: idx,
13326
- group: child,
13398
+ item: child,
13327
13399
  onUpdate,
13328
13400
  onDelete,
13329
13401
  onAddSubgroup,
@@ -13331,6 +13403,7 @@ var GroupItem = ({
13331
13403
  onOutdent,
13332
13404
  searchItems,
13333
13405
  onMentionClick,
13406
+ onEnterFolder,
13334
13407
  canEdit
13335
13408
  }
13336
13409
  ))));
@@ -13348,13 +13421,15 @@ function AncestryBoard({
13348
13421
  const [groups, setGroups] = (0, import_react29.useState)([]);
13349
13422
  const [isLoaded, setIsLoaded] = (0, import_react29.useState)(false);
13350
13423
  const [saveStatus, setSaveStatus] = (0, import_react29.useState)("idle");
13424
+ const [navigationStack, setNavigationStack] = (0, import_react29.useState)([]);
13351
13425
  const canEdit = (0, import_react29.useMemo)(() => userRole !== "viewer", [userRole]);
13352
13426
  (0, import_react29.useEffect)(() => {
13353
13427
  if (initialGroups && !isLoaded) {
13354
13428
  const migrate = (list) => list.map((g) => ({
13355
13429
  id: g.id || (0, import_uuid11.v4)(),
13430
+ type: g.type || "group",
13431
+ name: g.name || "",
13356
13432
  content: Array.isArray(g.content) ? g.content : [],
13357
- // descarta dados legados
13358
13433
  children: migrate(g.children || [])
13359
13434
  }));
13360
13435
  setGroups(migrate(initialGroups));
@@ -13389,6 +13464,8 @@ function AncestryBoard({
13389
13464
  }, [availableAncestries, availableNodes]);
13390
13465
  const sanitizeGroups = (list) => list.map((g) => ({
13391
13466
  id: g.id,
13467
+ type: g.type || "group",
13468
+ name: g.name || "",
13392
13469
  content: g.content || [],
13393
13470
  children: sanitizeGroups(g.children || [])
13394
13471
  }));
@@ -13419,23 +13496,72 @@ function AncestryBoard({
13419
13496
  window.addEventListener("keydown", handler);
13420
13497
  return () => window.removeEventListener("keydown", handler);
13421
13498
  }, [isOpen, onClose]);
13422
- const handleAddRootGroup = () => {
13423
- setGroups((prev) => [{ id: (0, import_uuid11.v4)(), content: [], children: [] }, ...prev]);
13499
+ const currentPath = (0, import_react29.useMemo)(() => {
13500
+ const path = [];
13501
+ let currentLevel = groups;
13502
+ for (const folderId of navigationStack) {
13503
+ const folder = currentLevel.find((f) => f.id === folderId);
13504
+ if (folder) {
13505
+ path.push(folder);
13506
+ currentLevel = folder.children;
13507
+ }
13508
+ }
13509
+ return path;
13510
+ }, [groups, navigationStack]);
13511
+ const currentGroups = (0, import_react29.useMemo)(() => {
13512
+ const lastFolder = currentPath[currentPath.length - 1];
13513
+ return lastFolder ? lastFolder.children : groups;
13514
+ }, [groups, currentPath]);
13515
+ const navigateUp = () => {
13516
+ setNavigationStack((prev) => prev.slice(0, -1));
13517
+ };
13518
+ const navigateTo = (folderId) => {
13519
+ setNavigationStack((prev) => [...prev, folderId]);
13424
13520
  };
13425
- const handleAddSubgroup = (parentId) => {
13426
- const newGroup = { id: (0, import_uuid11.v4)(), content: [], children: [] };
13521
+ const navigateToBreadcrumb = (index) => {
13522
+ setNavigationStack((prev) => prev.slice(0, index + 1));
13523
+ };
13524
+ const navigateHome = () => {
13525
+ setNavigationStack([]);
13526
+ };
13527
+ const handleAddItem = (type = "group") => {
13528
+ const newItem = {
13529
+ id: (0, import_uuid11.v4)(),
13530
+ type,
13531
+ name: type === "folder" ? "Nova Pasta" : "",
13532
+ content: [],
13533
+ children: []
13534
+ };
13535
+ if (navigationStack.length === 0) {
13536
+ setGroups((prev) => [newItem, ...prev]);
13537
+ } else {
13538
+ const parentId = navigationStack[navigationStack.length - 1];
13539
+ const add = (list) => list.map(
13540
+ (g) => g.id === parentId ? { ...g, children: [newItem, ...g.children] } : { ...g, children: add(g.children) }
13541
+ );
13542
+ setGroups((prev) => add(prev));
13543
+ }
13544
+ };
13545
+ const handleAddSubgroup = (parentId, type = "group") => {
13546
+ const newItem = {
13547
+ id: (0, import_uuid11.v4)(),
13548
+ type,
13549
+ name: type === "folder" ? "Nova Pasta" : "",
13550
+ content: [],
13551
+ children: []
13552
+ };
13427
13553
  const add = (list) => list.map(
13428
- (g) => g.id === parentId ? { ...g, children: [newGroup, ...g.children] } : { ...g, children: add(g.children) }
13554
+ (g) => g.id === parentId ? { ...g, children: [newItem, ...g.children] } : { ...g, children: add(g.children) }
13429
13555
  );
13430
13556
  setGroups((prev) => add(prev));
13431
13557
  };
13432
- const handleUpdateGroup = (id, newData) => {
13558
+ const handleUpdateItem = (id, newData) => {
13433
13559
  const update = (list) => list.map(
13434
13560
  (g) => g.id === id ? newData : { ...g, children: update(g.children) }
13435
13561
  );
13436
13562
  setGroups((prev) => update(prev));
13437
13563
  };
13438
- const handleDeleteGroup = (id) => {
13564
+ const handleDeleteItem = (id) => {
13439
13565
  const del = (list) => list.filter((g) => g.id !== id).map((g) => ({ ...g, children: del(g.children) }));
13440
13566
  setGroups((prev) => del(prev));
13441
13567
  };
@@ -13493,15 +13619,23 @@ function AncestryBoard({
13493
13619
  className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
13494
13620
  onClick: (e) => e.stopPropagation()
13495
13621
  },
13496
- /* @__PURE__ */ import_react29.default.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react29.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLoader, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ import_react29.default.createElement(
13622
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ import_react29.default.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLayers, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ import_react29.default.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLoader, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ import_react29.default.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, /* @__PURE__ */ import_react29.default.createElement(
13497
13623
  "button",
13498
13624
  {
13499
- onClick: handleAddRootGroup,
13625
+ onClick: () => handleAddItem("folder"),
13626
+ className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
13627
+ },
13628
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 14, className: "text-amber-400" }),
13629
+ /* @__PURE__ */ import_react29.default.createElement("span", { className: "hidden sm:inline" }, "Nova Pasta")
13630
+ ), /* @__PURE__ */ import_react29.default.createElement(
13631
+ "button",
13632
+ {
13633
+ onClick: () => handleAddItem("group"),
13500
13634
  className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
13501
13635
  },
13502
13636
  /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiPlus, { size: 14, className: "text-indigo-400" }),
13503
13637
  /* @__PURE__ */ import_react29.default.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
13504
- ), /* @__PURE__ */ import_react29.default.createElement(
13638
+ )), /* @__PURE__ */ import_react29.default.createElement(
13505
13639
  "button",
13506
13640
  {
13507
13641
  onClick: onClose,
@@ -13509,23 +13643,47 @@ function AncestryBoard({
13509
13643
  },
13510
13644
  /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiX, { size: 16 })
13511
13645
  ))),
13512
- /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar bg-slate-950/30 p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react29.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ import_react29.default.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ import_react29.default.createElement(
13513
- GroupItem,
13646
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "h-10 px-6 bg-slate-900/40 border-b border-white/5 flex items-center gap-2 text-[10px] uppercase font-bold tracking-widest text-slate-500 overflow-x-auto no-scrollbar whitespace-nowrap" }, /* @__PURE__ */ import_react29.default.createElement(
13647
+ "button",
13648
+ {
13649
+ onClick: navigateHome,
13650
+ className: `hover:text-white transition-colors flex items-center gap-1 ${navigationStack.length === 0 ? "text-indigo-400" : ""}`
13651
+ },
13652
+ "Home"
13653
+ ), currentPath.map((folder, idx) => /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, { key: folder.id }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiChevronRight, { size: 10, className: "shrink-0" }), /* @__PURE__ */ import_react29.default.createElement(
13654
+ "button",
13655
+ {
13656
+ onClick: () => navigateToBreadcrumb(idx),
13657
+ className: `hover:text-white transition-colors ${idx === currentPath.length - 1 ? "text-indigo-400" : ""}`
13658
+ },
13659
+ folder.name || "Sem Nome"
13660
+ ))), navigationStack.length > 0 && /* @__PURE__ */ import_react29.default.createElement("div", { className: "ml-auto" }, /* @__PURE__ */ import_react29.default.createElement(
13661
+ "button",
13662
+ {
13663
+ onClick: navigateUp,
13664
+ className: "flex items-center gap-1 px-2 py-1 rounded bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white transition-all"
13665
+ },
13666
+ /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiArrowLeft, { size: 10 }),
13667
+ /* @__PURE__ */ import_react29.default.createElement("span", null, "Voltar")
13668
+ ))),
13669
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar bg-slate-950/30 p-6 space-y-4" }, currentGroups.length === 0 ? /* @__PURE__ */ import_react29.default.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl bg-slate-900/20" }, /* @__PURE__ */ import_react29.default.createElement(import_fi23.FiLayers, { size: 24, className: "opacity-20" }), /* @__PURE__ */ import_react29.default.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, "Esta pasta est\xE1 vazia.", /* @__PURE__ */ import_react29.default.createElement("br", null), "Use os bot\xF5es acima para criar conte\xFAdo.") : /* @__PURE__ */ import_react29.default.createElement(import_react29.default.Fragment, null, "Nenhum conte\xFAdo dispon\xEDvel nesta pasta."))) : currentGroups.map((item, index) => /* @__PURE__ */ import_react29.default.createElement(
13670
+ BoardItem,
13514
13671
  {
13515
- key: group.id,
13672
+ key: item.id,
13516
13673
  index,
13517
- group,
13518
- onUpdate: handleUpdateGroup,
13519
- onDelete: handleDeleteGroup,
13674
+ item,
13675
+ onUpdate: handleUpdateItem,
13676
+ onDelete: handleDeleteItem,
13520
13677
  onAddSubgroup: handleAddSubgroup,
13521
13678
  onIndent: handleIndent,
13522
13679
  onOutdent: handleOutdent,
13523
13680
  searchItems: allSearchableItems,
13524
13681
  onMentionClick: handleMentionClick,
13682
+ onEnterFolder: navigateTo,
13525
13683
  canEdit
13526
13684
  }
13527
13685
  ))),
13528
- /* @__PURE__ */ import_react29.default.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-end flex-shrink-0" }, /* @__PURE__ */ import_react29.default.createElement("span", null, groups.length, " grupos raiz"))
13686
+ /* @__PURE__ */ import_react29.default.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-end flex-shrink-0" }, /* @__PURE__ */ import_react29.default.createElement("span", null, currentGroups.length, " itens nesta visualiza\xE7\xE3o"))
13529
13687
  )
13530
13688
  );
13531
13689
  }
package/dist/index.mjs CHANGED
@@ -12965,7 +12965,9 @@ import {
12965
12965
  FiX as FiX8,
12966
12966
  FiBox as FiBox2,
12967
12967
  FiCheckSquare as FiCheckSquare4,
12968
- FiGitBranch as FiGitBranch4
12968
+ FiGitBranch as FiGitBranch4,
12969
+ FiFolder as FiFolder3,
12970
+ FiChevronRight as FiChevronRight7
12969
12971
  } from "react-icons/fi";
12970
12972
  import { v4 as uuidv411 } from "uuid";
12971
12973
 
@@ -13125,6 +13127,7 @@ function RichGroupEditor({
13125
13127
  }) {
13126
13128
  const editorRef = useRef19(null);
13127
13129
  const isMountedRef = useRef19(false);
13130
+ const dismissedTriggerRef = useRef19(null);
13128
13131
  const [mentionState, setMentionState] = useState26(null);
13129
13132
  const [isEmpty, setIsEmpty] = useState26(true);
13130
13133
  useEffect22(() => {
@@ -13140,10 +13143,17 @@ function RichGroupEditor({
13140
13143
  const selection = window.getSelection();
13141
13144
  if (!selection || selection.rangeCount === 0) return null;
13142
13145
  const range = selection.getRangeAt(0);
13143
- if (range.startContainer.nodeType !== Node.TEXT_NODE) return null;
13144
- const textBefore = range.startContainer.textContent.substring(0, range.startOffset);
13146
+ const node = range.startContainer;
13147
+ if (node.nodeType !== Node.TEXT_NODE) return null;
13148
+ const textBefore = node.textContent.substring(0, range.startOffset);
13145
13149
  const atIndex = textBefore.lastIndexOf("@");
13146
- if (atIndex === -1) return null;
13150
+ if (atIndex === -1) {
13151
+ dismissedTriggerRef.current = null;
13152
+ return null;
13153
+ }
13154
+ if (dismissedTriggerRef.current && dismissedTriggerRef.current.node === node && dismissedTriggerRef.current.atIndex === atIndex) {
13155
+ return null;
13156
+ }
13147
13157
  const query = textBefore.substring(atIndex + 1);
13148
13158
  if (query.includes(" ") || query.includes(".") || query.includes(",") || query.length > 40) {
13149
13159
  return null;
@@ -13278,6 +13288,21 @@ function RichGroupEditor({
13278
13288
  const handleBlur = useCallback4(() => {
13279
13289
  setTimeout(() => setMentionState(null), 200);
13280
13290
  }, []);
13291
+ const handleMentionDismiss = useCallback4(() => {
13292
+ const selection = window.getSelection();
13293
+ if (selection && selection.rangeCount > 0) {
13294
+ const range = selection.getRangeAt(0);
13295
+ const node = range.startContainer;
13296
+ if (node.nodeType === Node.TEXT_NODE) {
13297
+ const textBefore = node.textContent.substring(0, range.startOffset);
13298
+ const atIndex = textBefore.lastIndexOf("@");
13299
+ if (atIndex !== -1) {
13300
+ dismissedTriggerRef.current = { node, atIndex };
13301
+ }
13302
+ }
13303
+ }
13304
+ setMentionState(null);
13305
+ }, []);
13281
13306
  return /* @__PURE__ */ React27.createElement("div", { className: "relative" }, isEmpty && !readOnly && /* @__PURE__ */ React27.createElement("div", { className: "absolute top-0 left-0 text-sm text-slate-600 pointer-events-none select-none" }, placeholder || "Escreva sobre este grupo\u2026 ou digite @ para mencionar"), /* @__PURE__ */ React27.createElement(
13282
13307
  "div",
13283
13308
  {
@@ -13299,14 +13324,14 @@ function RichGroupEditor({
13299
13324
  items: searchItems || [],
13300
13325
  position: mentionState.position,
13301
13326
  onSelect: insertMention,
13302
- onClose: () => setMentionState(null)
13327
+ onClose: handleMentionDismiss
13303
13328
  }
13304
13329
  ));
13305
13330
  }
13306
13331
 
13307
13332
  // src/components/AncestryBoard.jsx
13308
- var GroupItem = ({
13309
- group,
13333
+ var BoardItem = ({
13334
+ item,
13310
13335
  index,
13311
13336
  onUpdate,
13312
13337
  onDelete,
@@ -13315,16 +13340,55 @@ var GroupItem = ({
13315
13340
  onOutdent,
13316
13341
  searchItems,
13317
13342
  onMentionClick,
13343
+ onEnterFolder,
13318
13344
  canEdit
13319
13345
  }) => {
13346
+ var _a;
13347
+ const isFolder = item.type === "folder";
13320
13348
  const canIndent = index > 0;
13321
13349
  const handleContentChange = (content) => {
13322
- onUpdate(group.id, { ...group, content });
13350
+ onUpdate(item.id, { ...item, content });
13351
+ };
13352
+ const handleNameChange = (e) => {
13353
+ onUpdate(item.id, { ...item, name: e.target.value });
13323
13354
  };
13355
+ if (isFolder) {
13356
+ return /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col gap-2 mb-3 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement(
13357
+ "div",
13358
+ {
13359
+ onClick: () => onEnterFolder(item.id),
13360
+ className: "flex items-center gap-3 py-3 px-4 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 rounded-xl cursor-pointer transition-all duration-200 group/folder"
13361
+ },
13362
+ /* @__PURE__ */ React28.createElement("div", { className: "w-10 h-10 rounded-lg bg-indigo-500/10 flex items-center justify-center text-indigo-400 group-hover/folder:scale-110 transition-transform" }, /* @__PURE__ */ React28.createElement(FiFolder3, { size: 20 })),
13363
+ /* @__PURE__ */ React28.createElement("div", { className: "flex-1 min-w-0" }, canEdit ? /* @__PURE__ */ React28.createElement(
13364
+ "input",
13365
+ {
13366
+ type: "text",
13367
+ value: item.name,
13368
+ onChange: handleNameChange,
13369
+ onClick: (e) => e.stopPropagation(),
13370
+ className: "bg-transparent border-none outline-none text-sm font-medium text-slate-200 w-full focus:text-white",
13371
+ placeholder: "Nome da pasta..."
13372
+ }
13373
+ ) : /* @__PURE__ */ React28.createElement("span", { className: "text-sm font-medium text-slate-200" }, item.name), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-2 mt-0.5" }, /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] text-slate-500 uppercase tracking-wider font-semibold" }, ((_a = item.children) == null ? void 0 : _a.length) || 0, " itens"))),
13374
+ /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-2 opacity-0 group-hover/folder:opacity-100 transition-opacity" }, canEdit && /* @__PURE__ */ React28.createElement(
13375
+ "button",
13376
+ {
13377
+ onClick: (e) => {
13378
+ e.stopPropagation();
13379
+ onDelete(item.id);
13380
+ },
13381
+ className: "p-1.5 text-slate-500 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13382
+ title: "Remover Pasta"
13383
+ },
13384
+ /* @__PURE__ */ React28.createElement(FiTrash23, { size: 14 })
13385
+ ), /* @__PURE__ */ React28.createElement(FiChevronRight7, { className: "text-slate-500 group-hover/folder:translate-x-1 transition-transform" }))
13386
+ ));
13387
+ }
13324
13388
  return /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col gap-2 mb-3 pl-3 border-l border-white/10 relative group/item animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement("div", { className: "absolute -left-[1px] top-4 w-2 h-px bg-white/20" }), /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col gap-2 py-2 px-3 transition-all duration-200 hover:bg-white/5 border-l-2 border-transparent hover:border-white/20" }, /* @__PURE__ */ React28.createElement(
13325
13389
  RichGroupEditor,
13326
13390
  {
13327
- content: group.content,
13391
+ content: item.content,
13328
13392
  onChange: handleContentChange,
13329
13393
  onMentionClick,
13330
13394
  searchItems,
@@ -13334,15 +13398,25 @@ var GroupItem = ({
13334
13398
  ), canEdit && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center justify-between pt-2 mt-1 border-t border-white/5 opacity-40 group-hover/item:opacity-100 transition-opacity" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React28.createElement(
13335
13399
  "button",
13336
13400
  {
13337
- onClick: () => onAddSubgroup(group.id),
13338
- className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13401
+ onClick: () => onAddSubgroup(item.id, "group"),
13402
+ className: "flex items-center gap-1 px-1.5 py-1 text-[10px] uppercase font-bold tracking-wider text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13339
13403
  title: "Criar Subgrupo"
13340
13404
  },
13341
- /* @__PURE__ */ React28.createElement(FiPlus10, { size: 14 })
13405
+ /* @__PURE__ */ React28.createElement(FiPlus10, { size: 12 }),
13406
+ /* @__PURE__ */ React28.createElement("span", null, "Subgrupo")
13407
+ ), /* @__PURE__ */ React28.createElement(
13408
+ "button",
13409
+ {
13410
+ onClick: () => onAddSubgroup(item.id, "folder"),
13411
+ className: "flex items-center gap-1 px-1.5 py-1 text-[10px] uppercase font-bold tracking-wider text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13412
+ title: "Criar Subpasta"
13413
+ },
13414
+ /* @__PURE__ */ React28.createElement(FiFolder3, { size: 12 }),
13415
+ /* @__PURE__ */ React28.createElement("span", null, "Pasta")
13342
13416
  )), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1" }, /* @__PURE__ */ React28.createElement(
13343
13417
  "button",
13344
13418
  {
13345
- onClick: () => onIndent(group.id),
13419
+ onClick: () => onIndent(item.id),
13346
13420
  disabled: !canIndent,
13347
13421
  className: `p-1.5 rounded transition-colors ${!canIndent ? "text-slate-800 cursor-not-allowed" : "text-slate-500 hover:text-white hover:bg-white/10"}`,
13348
13422
  title: "Aninhar no grupo acima"
@@ -13351,7 +13425,7 @@ var GroupItem = ({
13351
13425
  ), /* @__PURE__ */ React28.createElement(
13352
13426
  "button",
13353
13427
  {
13354
- onClick: () => onOutdent(group.id),
13428
+ onClick: () => onOutdent(item.id),
13355
13429
  className: "p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-colors",
13356
13430
  title: "Desaninhar"
13357
13431
  },
@@ -13359,17 +13433,17 @@ var GroupItem = ({
13359
13433
  ), /* @__PURE__ */ React28.createElement("div", { className: "w-px h-3 bg-white/10 mx-1" }), /* @__PURE__ */ React28.createElement(
13360
13434
  "button",
13361
13435
  {
13362
- onClick: () => onDelete(group.id),
13436
+ onClick: () => onDelete(item.id),
13363
13437
  className: "p-1.5 text-slate-600 hover:text-red-400 hover:bg-red-500/10 rounded transition-colors",
13364
13438
  title: "Remover Grupo"
13365
13439
  },
13366
13440
  /* @__PURE__ */ React28.createElement(FiTrash23, { size: 14 })
13367
- )))), group.children && group.children.length > 0 && /* @__PURE__ */ React28.createElement("div", { className: "ml-2" }, group.children.map((child, idx) => /* @__PURE__ */ React28.createElement(
13368
- GroupItem,
13441
+ )))), item.children && item.children.length > 0 && /* @__PURE__ */ React28.createElement("div", { className: "ml-2" }, item.children.map((child, idx) => /* @__PURE__ */ React28.createElement(
13442
+ BoardItem,
13369
13443
  {
13370
13444
  key: child.id,
13371
13445
  index: idx,
13372
- group: child,
13446
+ item: child,
13373
13447
  onUpdate,
13374
13448
  onDelete,
13375
13449
  onAddSubgroup,
@@ -13377,6 +13451,7 @@ var GroupItem = ({
13377
13451
  onOutdent,
13378
13452
  searchItems,
13379
13453
  onMentionClick,
13454
+ onEnterFolder,
13380
13455
  canEdit
13381
13456
  }
13382
13457
  ))));
@@ -13394,13 +13469,15 @@ function AncestryBoard({
13394
13469
  const [groups, setGroups] = useState27([]);
13395
13470
  const [isLoaded, setIsLoaded] = useState27(false);
13396
13471
  const [saveStatus, setSaveStatus] = useState27("idle");
13472
+ const [navigationStack, setNavigationStack] = useState27([]);
13397
13473
  const canEdit = useMemo12(() => userRole !== "viewer", [userRole]);
13398
13474
  useEffect23(() => {
13399
13475
  if (initialGroups && !isLoaded) {
13400
13476
  const migrate = (list) => list.map((g) => ({
13401
13477
  id: g.id || uuidv411(),
13478
+ type: g.type || "group",
13479
+ name: g.name || "",
13402
13480
  content: Array.isArray(g.content) ? g.content : [],
13403
- // descarta dados legados
13404
13481
  children: migrate(g.children || [])
13405
13482
  }));
13406
13483
  setGroups(migrate(initialGroups));
@@ -13435,6 +13512,8 @@ function AncestryBoard({
13435
13512
  }, [availableAncestries, availableNodes]);
13436
13513
  const sanitizeGroups = (list) => list.map((g) => ({
13437
13514
  id: g.id,
13515
+ type: g.type || "group",
13516
+ name: g.name || "",
13438
13517
  content: g.content || [],
13439
13518
  children: sanitizeGroups(g.children || [])
13440
13519
  }));
@@ -13465,23 +13544,72 @@ function AncestryBoard({
13465
13544
  window.addEventListener("keydown", handler);
13466
13545
  return () => window.removeEventListener("keydown", handler);
13467
13546
  }, [isOpen, onClose]);
13468
- const handleAddRootGroup = () => {
13469
- setGroups((prev) => [{ id: uuidv411(), content: [], children: [] }, ...prev]);
13547
+ const currentPath = useMemo12(() => {
13548
+ const path = [];
13549
+ let currentLevel = groups;
13550
+ for (const folderId of navigationStack) {
13551
+ const folder = currentLevel.find((f) => f.id === folderId);
13552
+ if (folder) {
13553
+ path.push(folder);
13554
+ currentLevel = folder.children;
13555
+ }
13556
+ }
13557
+ return path;
13558
+ }, [groups, navigationStack]);
13559
+ const currentGroups = useMemo12(() => {
13560
+ const lastFolder = currentPath[currentPath.length - 1];
13561
+ return lastFolder ? lastFolder.children : groups;
13562
+ }, [groups, currentPath]);
13563
+ const navigateUp = () => {
13564
+ setNavigationStack((prev) => prev.slice(0, -1));
13565
+ };
13566
+ const navigateTo = (folderId) => {
13567
+ setNavigationStack((prev) => [...prev, folderId]);
13470
13568
  };
13471
- const handleAddSubgroup = (parentId) => {
13472
- const newGroup = { id: uuidv411(), content: [], children: [] };
13569
+ const navigateToBreadcrumb = (index) => {
13570
+ setNavigationStack((prev) => prev.slice(0, index + 1));
13571
+ };
13572
+ const navigateHome = () => {
13573
+ setNavigationStack([]);
13574
+ };
13575
+ const handleAddItem = (type = "group") => {
13576
+ const newItem = {
13577
+ id: uuidv411(),
13578
+ type,
13579
+ name: type === "folder" ? "Nova Pasta" : "",
13580
+ content: [],
13581
+ children: []
13582
+ };
13583
+ if (navigationStack.length === 0) {
13584
+ setGroups((prev) => [newItem, ...prev]);
13585
+ } else {
13586
+ const parentId = navigationStack[navigationStack.length - 1];
13587
+ const add = (list) => list.map(
13588
+ (g) => g.id === parentId ? { ...g, children: [newItem, ...g.children] } : { ...g, children: add(g.children) }
13589
+ );
13590
+ setGroups((prev) => add(prev));
13591
+ }
13592
+ };
13593
+ const handleAddSubgroup = (parentId, type = "group") => {
13594
+ const newItem = {
13595
+ id: uuidv411(),
13596
+ type,
13597
+ name: type === "folder" ? "Nova Pasta" : "",
13598
+ content: [],
13599
+ children: []
13600
+ };
13473
13601
  const add = (list) => list.map(
13474
- (g) => g.id === parentId ? { ...g, children: [newGroup, ...g.children] } : { ...g, children: add(g.children) }
13602
+ (g) => g.id === parentId ? { ...g, children: [newItem, ...g.children] } : { ...g, children: add(g.children) }
13475
13603
  );
13476
13604
  setGroups((prev) => add(prev));
13477
13605
  };
13478
- const handleUpdateGroup = (id, newData) => {
13606
+ const handleUpdateItem = (id, newData) => {
13479
13607
  const update = (list) => list.map(
13480
13608
  (g) => g.id === id ? newData : { ...g, children: update(g.children) }
13481
13609
  );
13482
13610
  setGroups((prev) => update(prev));
13483
13611
  };
13484
- const handleDeleteGroup = (id) => {
13612
+ const handleDeleteItem = (id) => {
13485
13613
  const del = (list) => list.filter((g) => g.id !== id).map((g) => ({ ...g, children: del(g.children) }));
13486
13614
  setGroups((prev) => del(prev));
13487
13615
  };
@@ -13539,15 +13667,23 @@ function AncestryBoard({
13539
13667
  className: "bg-slate-950 border border-white/10 rounded-xl w-[98vw] h-[97vh] flex flex-col shadow-2xl overflow-hidden animate-in fade-in zoom-in-95 duration-200",
13540
13668
  onClick: (e) => e.stopPropagation()
13541
13669
  },
13542
- /* @__PURE__ */ React28.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React28.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React28.createElement(FiLayers7, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(FiLoader5, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ React28.createElement(
13670
+ /* @__PURE__ */ React28.createElement("div", { className: "h-14 px-4 border-b border-white/10 bg-slate-900/90 flex items-center justify-between shrink-0" }, /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-4" }, /* @__PURE__ */ React28.createElement("h3", { className: "text-base font-semibold text-white flex items-center gap-2 whitespace-nowrap" }, /* @__PURE__ */ React28.createElement(FiLayers7, { className: "text-indigo-400" }), "Ancestry Board"), saveStatus !== "idle" && /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-2 animate-in fade-in slide-in-from-left-2 duration-300" }, /* @__PURE__ */ React28.createElement("div", { className: "w-px h-4 bg-white/10 mx-1" }), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-1.5 px-2 py-0.5 rounded-full bg-slate-900/50 border border-white/5" }, saveStatus === "saving" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(FiLoader5, { className: "animate-spin text-indigo-400", size: 12 }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-indigo-300" }, "Salvando")), saveStatus === "saved" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(FiCheckCircle, { className: "text-emerald-400", size: 12 }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-slate-400" }, "Salvo")), saveStatus === "error" && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement("span", { className: "w-2 h-2 rounded-full bg-red-500" }), /* @__PURE__ */ React28.createElement("span", { className: "text-[10px] uppercase tracking-wide font-medium text-red-400" }, "Erro"))))), /* @__PURE__ */ React28.createElement("div", { className: "flex items-center gap-3" }, canEdit && /* @__PURE__ */ React28.createElement(React28.Fragment, null, /* @__PURE__ */ React28.createElement(
13543
13671
  "button",
13544
13672
  {
13545
- onClick: handleAddRootGroup,
13673
+ onClick: () => handleAddItem("folder"),
13674
+ className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
13675
+ },
13676
+ /* @__PURE__ */ React28.createElement(FiPlus10, { size: 14, className: "text-amber-400" }),
13677
+ /* @__PURE__ */ React28.createElement("span", { className: "hidden sm:inline" }, "Nova Pasta")
13678
+ ), /* @__PURE__ */ React28.createElement(
13679
+ "button",
13680
+ {
13681
+ onClick: () => handleAddItem("group"),
13546
13682
  className: "flex items-center gap-2 px-3 py-1.5 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/20 backdrop-blur-sm text-slate-200 hover:text-white rounded-md transition-all duration-200 text-xs font-medium shadow-sm"
13547
13683
  },
13548
13684
  /* @__PURE__ */ React28.createElement(FiPlus10, { size: 14, className: "text-indigo-400" }),
13549
13685
  /* @__PURE__ */ React28.createElement("span", { className: "hidden sm:inline" }, "Novo Grupo")
13550
- ), /* @__PURE__ */ React28.createElement(
13686
+ )), /* @__PURE__ */ React28.createElement(
13551
13687
  "button",
13552
13688
  {
13553
13689
  onClick: onClose,
@@ -13555,23 +13691,47 @@ function AncestryBoard({
13555
13691
  },
13556
13692
  /* @__PURE__ */ React28.createElement(FiX8, { size: 16 })
13557
13693
  ))),
13558
- /* @__PURE__ */ React28.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar bg-slate-950/30 p-6 space-y-4" }, groups.length === 0 ? /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl m-4 bg-slate-900/20" }, /* @__PURE__ */ React28.createElement(FiLayers7, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React28.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React28.createElement(React28.Fragment, null, "Nenhum grupo criado.", /* @__PURE__ */ React28.createElement("br", null), 'Use o bot\xE3o "Novo Grupo" acima.') : /* @__PURE__ */ React28.createElement(React28.Fragment, null, "Nenhum grupo dispon\xEDvel para visualiza\xE7\xE3o."))) : groups.map((group, index) => /* @__PURE__ */ React28.createElement(
13559
- GroupItem,
13694
+ /* @__PURE__ */ React28.createElement("div", { className: "h-10 px-6 bg-slate-900/40 border-b border-white/5 flex items-center gap-2 text-[10px] uppercase font-bold tracking-widest text-slate-500 overflow-x-auto no-scrollbar whitespace-nowrap" }, /* @__PURE__ */ React28.createElement(
13695
+ "button",
13696
+ {
13697
+ onClick: navigateHome,
13698
+ className: `hover:text-white transition-colors flex items-center gap-1 ${navigationStack.length === 0 ? "text-indigo-400" : ""}`
13699
+ },
13700
+ "Home"
13701
+ ), currentPath.map((folder, idx) => /* @__PURE__ */ React28.createElement(React28.Fragment, { key: folder.id }, /* @__PURE__ */ React28.createElement(FiChevronRight7, { size: 10, className: "shrink-0" }), /* @__PURE__ */ React28.createElement(
13702
+ "button",
13703
+ {
13704
+ onClick: () => navigateToBreadcrumb(idx),
13705
+ className: `hover:text-white transition-colors ${idx === currentPath.length - 1 ? "text-indigo-400" : ""}`
13706
+ },
13707
+ folder.name || "Sem Nome"
13708
+ ))), navigationStack.length > 0 && /* @__PURE__ */ React28.createElement("div", { className: "ml-auto" }, /* @__PURE__ */ React28.createElement(
13709
+ "button",
13710
+ {
13711
+ onClick: navigateUp,
13712
+ className: "flex items-center gap-1 px-2 py-1 rounded bg-white/5 hover:bg-white/10 text-slate-400 hover:text-white transition-all"
13713
+ },
13714
+ /* @__PURE__ */ React28.createElement(FiArrowLeft3, { size: 10 }),
13715
+ /* @__PURE__ */ React28.createElement("span", null, "Voltar")
13716
+ ))),
13717
+ /* @__PURE__ */ React28.createElement("div", { className: "flex-1 overflow-y-auto custom-scrollbar bg-slate-950/30 p-6 space-y-4" }, currentGroups.length === 0 ? /* @__PURE__ */ React28.createElement("div", { className: "flex flex-col items-center justify-center h-full text-slate-500 gap-3 border-2 border-dashed border-white/5 rounded-xl bg-slate-900/20" }, /* @__PURE__ */ React28.createElement(FiLayers7, { size: 24, className: "opacity-20" }), /* @__PURE__ */ React28.createElement("p", { className: "text-xs text-center px-4" }, canEdit ? /* @__PURE__ */ React28.createElement(React28.Fragment, null, "Esta pasta est\xE1 vazia.", /* @__PURE__ */ React28.createElement("br", null), "Use os bot\xF5es acima para criar conte\xFAdo.") : /* @__PURE__ */ React28.createElement(React28.Fragment, null, "Nenhum conte\xFAdo dispon\xEDvel nesta pasta."))) : currentGroups.map((item, index) => /* @__PURE__ */ React28.createElement(
13718
+ BoardItem,
13560
13719
  {
13561
- key: group.id,
13720
+ key: item.id,
13562
13721
  index,
13563
- group,
13564
- onUpdate: handleUpdateGroup,
13565
- onDelete: handleDeleteGroup,
13722
+ item,
13723
+ onUpdate: handleUpdateItem,
13724
+ onDelete: handleDeleteItem,
13566
13725
  onAddSubgroup: handleAddSubgroup,
13567
13726
  onIndent: handleIndent,
13568
13727
  onOutdent: handleOutdent,
13569
13728
  searchItems: allSearchableItems,
13570
13729
  onMentionClick: handleMentionClick,
13730
+ onEnterFolder: navigateTo,
13571
13731
  canEdit
13572
13732
  }
13573
13733
  ))),
13574
- /* @__PURE__ */ React28.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-end flex-shrink-0" }, /* @__PURE__ */ React28.createElement("span", null, groups.length, " grupos raiz"))
13734
+ /* @__PURE__ */ React28.createElement("div", { className: "px-5 py-2 border-t border-white/10 bg-slate-950/50 text-xs text-slate-500 flex justify-end flex-shrink-0" }, /* @__PURE__ */ React28.createElement("span", null, currentGroups.length, " itens nesta visualiza\xE7\xE3o"))
13575
13735
  )
13576
13736
  );
13577
13737
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.6-dev.12",
3
+ "version": "1.2.6-dev.14",
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",