@lv-x-software-house/x_view 1.2.5-dev.17 → 1.2.5-dev.19

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 +199 -60
  2. package/dist/index.mjs +204 -65
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -619,29 +619,26 @@ function XViewSidebar({
619
619
  const [isFilterMenuOpen, setIsFilterMenuOpen] = (0, import_react2.useState)(false);
620
620
  const [filterCategory, setFilterCategory] = (0, import_react2.useState)("Type");
621
621
  const [filterValue, setFilterValue] = (0, import_react2.useState)("");
622
+ const [isTypeDropdownOpen, setIsTypeDropdownOpen] = (0, import_react2.useState)(false);
623
+ const [highlightedTypeIndex, setHighlightedTypeIndex] = (0, import_react2.useState)(-1);
622
624
  const containerRef = (0, import_react2.useRef)(null);
623
625
  const inputRef = (0, import_react2.useRef)(null);
624
626
  const filterMenuRef = (0, import_react2.useRef)(null);
627
+ const typeDropdownRef = (0, import_react2.useRef)(null);
625
628
  const ability = (0, import_react2.useMemo)(() => {
626
629
  return defineAbilityFor(userRole);
627
630
  }, [userRole]);
628
631
  const contextLabel = (0, import_react2.useMemo)(() => {
629
632
  if (!viewType || !viewName) return null;
630
- console.log("XViewSidebar: contextLabel viewType", viewType);
631
- try {
632
- const typeLower = viewType.toLowerCase();
633
- if (typeLower === "database") {
634
- return `Dataset: ${viewName}`;
635
- } else if (typeLower === "view") {
636
- return `View: ${viewName}`;
637
- } else if (typeLower === "node") {
638
- return `Node: ${viewName}`;
639
- }
640
- return `${viewType}: ${viewName}`;
641
- } catch (err) {
642
- console.error("XViewSidebar: Erro no contextLabel ao converter viewType:", viewType, err);
643
- return `${viewType}: ${viewName}`;
644
- }
633
+ const typeLower = String(viewType).toLowerCase();
634
+ if (typeLower === "database") {
635
+ return `Dataset: ${viewName}`;
636
+ } else if (typeLower === "view") {
637
+ return `View: ${viewName}`;
638
+ } else if (typeLower === "node") {
639
+ return `Node: ${viewName}`;
640
+ }
641
+ return `${viewType}: ${viewName}`;
645
642
  }, [viewType, viewName]);
646
643
  const normalize = (str = "") => {
647
644
  if (str === void 0 || str === null) {
@@ -654,7 +651,6 @@ function XViewSidebar({
654
651
  []
655
652
  );
656
653
  const availableTypes = (0, import_react2.useMemo)(() => {
657
- console.log("XViewSidebar: recalculando availableTypes, dbNodes count:", dbNodes == null ? void 0 : dbNodes.length);
658
654
  const typesSet = /* @__PURE__ */ new Set();
659
655
  (dbNodes || []).forEach((node) => {
660
656
  if (Array.isArray(node.type)) {
@@ -665,10 +661,13 @@ function XViewSidebar({
665
661
  typesSet.add(node.type);
666
662
  }
667
663
  });
668
- const result = Array.from(typesSet).sort();
669
- console.log("XViewSidebar: availableTypes final:", result);
670
- return result;
664
+ return Array.from(typesSet).sort();
671
665
  }, [dbNodes]);
666
+ const filteredTypes = (0, import_react2.useMemo)(() => {
667
+ if (!filterValue.trim()) return availableTypes;
668
+ const search = filterValue.toLowerCase().trim();
669
+ return availableTypes.filter((t) => t.toLowerCase().includes(search));
670
+ }, [availableTypes, filterValue]);
672
671
  const filteredAndSorted = (0, import_react2.useMemo)(() => {
673
672
  const base = Array.isArray(dbNodes) ? dbNodes : [];
674
673
  let pool = base;
@@ -681,22 +680,13 @@ function XViewSidebar({
681
680
  });
682
681
  }
683
682
  if (activeFilters.length > 0) {
684
- console.log("XViewSidebar: aplicando activeFilters:", activeFilters);
685
683
  pool = pool.filter((node) => {
686
684
  return activeFilters.every((filter) => {
687
- try {
688
- if (filter.type === "Type") {
689
- const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
690
- return nodeTypes.some((t) => {
691
- if (t === void 0) console.log("XViewSidebar: t \xE9 undefined no node:", node.id);
692
- if (filter.value === void 0) console.log("XViewSidebar: filter.value \xE9 undefined");
693
- return String(t).toLowerCase() === String(filter.value).toLowerCase();
694
- });
695
- } else if (filter.type === "Color") {
696
- return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
697
- }
698
- } catch (err) {
699
- console.error("XViewSidebar: Erro ao filtrar node:", node, "com filtro:", filter, err);
685
+ if (filter.type === "Type") {
686
+ const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
687
+ return nodeTypes.some((t) => String(t).toLowerCase() === String(filter.value).toLowerCase());
688
+ } else if (filter.type === "Color") {
689
+ return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
700
690
  }
701
691
  return true;
702
692
  });
@@ -718,12 +708,15 @@ function XViewSidebar({
718
708
  if (filterMenuRef.current && !filterMenuRef.current.contains(event.target)) {
719
709
  setIsFilterMenuOpen(false);
720
710
  }
711
+ if (typeDropdownRef.current && !typeDropdownRef.current.contains(event.target)) {
712
+ setIsTypeDropdownOpen(false);
713
+ }
721
714
  };
722
- if (isFilterMenuOpen) {
715
+ if (isFilterMenuOpen || isTypeDropdownOpen) {
723
716
  document.addEventListener("mousedown", handleClickOutside);
724
717
  }
725
718
  return () => document.removeEventListener("mousedown", handleClickOutside);
726
- }, [isFilterMenuOpen]);
719
+ }, [isFilterMenuOpen, isTypeDropdownOpen]);
727
720
  (0, import_react2.useEffect)(() => {
728
721
  if (!query) setSelectedNodeId(null);
729
722
  }, [query]);
@@ -777,6 +770,35 @@ function XViewSidebar({
777
770
  const handleRemoveFilter = (index) => {
778
771
  setActiveFilters((prev) => prev.filter((_, i) => i !== index));
779
772
  };
773
+ const handleTypeKeyDown = (e) => {
774
+ if (!isTypeDropdownOpen) {
775
+ setIsTypeDropdownOpen(true);
776
+ }
777
+ if (e.key === "ArrowDown") {
778
+ e.preventDefault();
779
+ setHighlightedTypeIndex(
780
+ (prev) => prev < filteredTypes.length - 1 ? prev + 1 : prev
781
+ );
782
+ } else if (e.key === "ArrowUp") {
783
+ e.preventDefault();
784
+ setHighlightedTypeIndex((prev) => prev > 0 ? prev - 1 : 0);
785
+ } else if (e.key === "Enter") {
786
+ e.preventDefault();
787
+ if (highlightedTypeIndex >= 0 && filteredTypes[highlightedTypeIndex]) {
788
+ setFilterValue(filteredTypes[highlightedTypeIndex]);
789
+ setIsTypeDropdownOpen(false);
790
+ setHighlightedTypeIndex(-1);
791
+ } else {
792
+ handleAddFilter();
793
+ }
794
+ } else if (e.key === "Escape") {
795
+ e.preventDefault();
796
+ setIsTypeDropdownOpen(false);
797
+ setHighlightedTypeIndex(-1);
798
+ } else if (e.key === "Tab") {
799
+ setIsTypeDropdownOpen(false);
800
+ }
801
+ };
780
802
  const ToggleButton = /* @__PURE__ */ import_react2.default.createElement(
781
803
  "button",
782
804
  {
@@ -907,18 +929,36 @@ function XViewSidebar({
907
929
  className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white shadow-sm" : "text-slate-400 hover:text-slate-200"}`
908
930
  },
909
931
  opt
910
- )))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), filterCategory === "Type" ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react2.default.createElement(
932
+ )))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), filterCategory === "Type" ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative", ref: typeDropdownRef }, /* @__PURE__ */ import_react2.default.createElement(
911
933
  "input",
912
934
  {
913
- list: "typeOptions",
914
935
  type: "text",
915
936
  value: filterValue,
916
- onChange: (e) => setFilterValue(e.target.value),
937
+ onChange: (e) => {
938
+ setFilterValue(e.target.value);
939
+ if (!isTypeDropdownOpen) setIsTypeDropdownOpen(true);
940
+ setHighlightedTypeIndex(-1);
941
+ },
942
+ onFocus: () => setIsTypeDropdownOpen(true),
943
+ onKeyDown: handleTypeKeyDown,
917
944
  placeholder: "Ex: Concept",
918
945
  className: "w-full bg-slate-800 p-2 text-xs rounded border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white",
919
946
  autoFocus: true
920
947
  }
921
- ), /* @__PURE__ */ import_react2.default.createElement("datalist", { id: "typeOptions" }, availableTypes.map((t) => /* @__PURE__ */ import_react2.default.createElement("option", { key: t, value: t })))) : /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative flex items-center" }, /* @__PURE__ */ import_react2.default.createElement(
948
+ ), isTypeDropdownOpen && filteredTypes.length > 0 && /* @__PURE__ */ import_react2.default.createElement("div", { className: "absolute z-[60] left-0 right-0 mt-1 max-h-48 overflow-y-auto bg-slate-900/95 backdrop-blur-xl border border-white/10 rounded-md shadow-2xl custom-scrollbar" }, filteredTypes.map((t, idx) => /* @__PURE__ */ import_react2.default.createElement(
949
+ "div",
950
+ {
951
+ key: t,
952
+ className: `px-3 py-2 text-xs cursor-pointer transition-colors ${idx === highlightedTypeIndex ? "bg-indigo-600 text-white" : "text-slate-300 hover:bg-white/10"}`,
953
+ onMouseDown: (e) => {
954
+ e.preventDefault();
955
+ setFilterValue(t);
956
+ setIsTypeDropdownOpen(false);
957
+ setHighlightedTypeIndex(-1);
958
+ }
959
+ },
960
+ t
961
+ )))) : /* @__PURE__ */ import_react2.default.createElement("div", { className: "relative flex items-center" }, /* @__PURE__ */ import_react2.default.createElement(
922
962
  "div",
923
963
  {
924
964
  className: "absolute left-2 w-3 h-3 rounded-full border border-white/20 shadow-sm",
@@ -7688,7 +7728,7 @@ function ColorPicker({ color, onChange, disabled }) {
7688
7728
  style: { backgroundColor: preset },
7689
7729
  title: preset
7690
7730
  },
7691
- color.toLowerCase() === preset.toLowerCase() && /* @__PURE__ */ import_react13.default.createElement(import_fi11.FiCheck, { className: `drop-shadow-md ${["#ffffff", "#4df5cb", "#84cc16", "#f59e0b"].includes(preset) ? "text-black" : "text-white"}`, size: 12 })
7731
+ (color || "").toLowerCase() === (preset || "").toLowerCase() && /* @__PURE__ */ import_react13.default.createElement(import_fi11.FiCheck, { className: `drop-shadow-md ${["#ffffff", "#4df5cb", "#84cc16", "#f59e0b"].includes(preset) ? "text-black" : "text-white"}`, size: 12 })
7692
7732
  )))), /* @__PURE__ */ import_react13.default.createElement("style", null, `
7693
7733
  .custom-react-colorful .react-colorful {
7694
7734
  width: 100%;
@@ -8341,6 +8381,7 @@ function InSceneQuestForm({
8341
8381
  // NOVA PROP
8342
8382
  viewMembers = []
8343
8383
  }) {
8384
+ var _a, _b;
8344
8385
  const [name, setName] = (0, import_react16.useState)("");
8345
8386
  const [assigneeId, setAssigneeId] = (0, import_react16.useState)("");
8346
8387
  const [types, setTypes] = (0, import_react16.useState)(["quest"]);
@@ -8350,6 +8391,8 @@ function InSceneQuestForm({
8350
8391
  const [intensity, setIntensity] = (0, import_react16.useState)(0);
8351
8392
  const [description, setDescription] = (0, import_react16.useState)("");
8352
8393
  const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react16.useState)(false);
8394
+ const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react16.useState)(false);
8395
+ const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react16.useState)("");
8353
8396
  const [customProps, setCustomProps] = (0, import_react16.useState)([]);
8354
8397
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = (0, import_react16.useState)(false);
8355
8398
  const propsEndRef = (0, import_react16.useRef)(null);
@@ -8358,8 +8401,8 @@ function InSceneQuestForm({
8358
8401
  const newProp = createNewCustomProperty(customProps);
8359
8402
  setCustomProps([...customProps, newProp]);
8360
8403
  setTimeout(() => {
8361
- var _a;
8362
- (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
8404
+ var _a2;
8405
+ (_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
8363
8406
  }, 100);
8364
8407
  };
8365
8408
  const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
@@ -8477,16 +8520,59 @@ function InSceneQuestForm({
8477
8520
  },
8478
8521
  /* @__PURE__ */ import_react16.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8479
8522
  s
8480
- )))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), /* @__PURE__ */ import_react16.default.createElement(
8481
- "select",
8523
+ )))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react16.default.createElement(
8524
+ "button",
8482
8525
  {
8483
- value: assigneeId,
8484
- onChange: (e) => setAssigneeId(e.target.value),
8485
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors text-slate-200"
8526
+ type: "button",
8527
+ onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
8528
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
8486
8529
  },
8487
- /* @__PURE__ */ import_react16.default.createElement("option", { value: "" }, "Nenhum"),
8488
- viewMembers.map((member) => /* @__PURE__ */ import_react16.default.createElement("option", { key: member.id, value: member.id }, member.name || member.email || member.id))
8489
- )), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ import_react16.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
8530
+ /* @__PURE__ */ import_react16.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiUser, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ import_react16.default.createElement("span", { className: "text-slate-200 font-medium" }, ((_a = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _a.name) || ((_b = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _b.email) || "Nenhum")),
8531
+ /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isAssigneeDropdownOpen ? "rotate-180" : ""}` })
8532
+ ), isAssigneeDropdownOpen && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
8533
+ setIsAssigneeDropdownOpen(false);
8534
+ setAssigneeSearchQuery("");
8535
+ } }), /* @__PURE__ */ import_react16.default.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiSearch, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ import_react16.default.createElement(
8536
+ "input",
8537
+ {
8538
+ type: "text",
8539
+ autoFocus: true,
8540
+ placeholder: "Buscar membro...",
8541
+ value: assigneeSearchQuery,
8542
+ onChange: (e) => setAssigneeSearchQuery(e.target.value),
8543
+ className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
8544
+ onClick: (e) => e.stopPropagation()
8545
+ }
8546
+ )), /* @__PURE__ */ import_react16.default.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ import_react16.default.createElement(
8547
+ "li",
8548
+ {
8549
+ onClick: () => {
8550
+ setAssigneeId("");
8551
+ setIsAssigneeDropdownOpen(false);
8552
+ setAssigneeSearchQuery("");
8553
+ },
8554
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!assigneeId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8555
+ },
8556
+ "Nenhum"
8557
+ ), viewMembers.filter((member) => {
8558
+ const search = assigneeSearchQuery.toLowerCase();
8559
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
8560
+ }).map((member) => /* @__PURE__ */ import_react16.default.createElement(
8561
+ "li",
8562
+ {
8563
+ key: member.id,
8564
+ onClick: () => {
8565
+ setAssigneeId(member.id);
8566
+ setIsAssigneeDropdownOpen(false);
8567
+ setAssigneeSearchQuery("");
8568
+ },
8569
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${assigneeId === member.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8570
+ },
8571
+ member.name || member.email || member.id
8572
+ )), viewMembers.filter((member) => {
8573
+ const search = assigneeSearchQuery.toLowerCase();
8574
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
8575
+ }).length === 0 && assigneeSearchQuery && /* @__PURE__ */ import_react16.default.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__PURE__ */ import_react16.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react16.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react16.default.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ import_react16.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react16.default.createElement(import_fi14.FiX, { size: 12 })))), /* @__PURE__ */ import_react16.default.createElement(
8490
8576
  "input",
8491
8577
  {
8492
8578
  type: "text",
@@ -9105,6 +9191,8 @@ function QuestDetailsPanel({
9105
9191
  const [description, setDescription] = (0, import_react18.useState)((node == null ? void 0 : node.description) ?? "");
9106
9192
  const [intensity, setIntensity] = (0, import_react18.useState)((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
9107
9193
  const [isStatusDropdownOpen, setIsStatusDropdownOpen] = (0, import_react18.useState)(false);
9194
+ const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = (0, import_react18.useState)(false);
9195
+ const [assigneeSearchQuery, setAssigneeSearchQuery] = (0, import_react18.useState)("");
9108
9196
  const [customProps, setCustomProps] = (0, import_react18.useState)(() => extractCustomPropsFromNode(node || {}));
9109
9197
  const [showTypeSuggestions, setShowTypeSuggestions] = (0, import_react18.useState)(false);
9110
9198
  const [filteredTypes, setFilteredTypes] = (0, import_react18.useState)([]);
@@ -9388,20 +9476,71 @@ function QuestDetailsPanel({
9388
9476
  },
9389
9477
  /* @__PURE__ */ import_react18.default.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
9390
9478
  s
9391
- )))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), canEdit ? /* @__PURE__ */ import_react18.default.createElement(
9392
- "select",
9479
+ )))))), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), canEdit ? /* @__PURE__ */ import_react18.default.createElement("div", { className: "relative" }, /* @__PURE__ */ import_react18.default.createElement(
9480
+ "button",
9393
9481
  {
9394
- value: assigneeId,
9395
- onChange: (e) => {
9396
- setAssigneeId(e.target.value);
9482
+ type: "button",
9483
+ onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
9484
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
9485
+ },
9486
+ /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiUser, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ import_react18.default.createElement("span", { className: "text-slate-200 font-medium" }, isAssigneeUndefined ? "Undefined" : (assigneeMember == null ? void 0 : assigneeMember.name) || (assigneeMember == null ? void 0 : assigneeMember.email) || "Nenhum")),
9487
+ /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiChevronDown, { className: `text-slate-400 transition-transform duration-200 ${isAssigneeDropdownOpen ? "rotate-180" : ""}` })
9488
+ ), isAssigneeDropdownOpen && /* @__PURE__ */ import_react18.default.createElement(import_react18.default.Fragment, null, /* @__PURE__ */ import_react18.default.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
9489
+ setIsAssigneeDropdownOpen(false);
9490
+ setAssigneeSearchQuery("");
9491
+ } }), /* @__PURE__ */ import_react18.default.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiSearch, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ import_react18.default.createElement(
9492
+ "input",
9493
+ {
9494
+ type: "text",
9495
+ autoFocus: true,
9496
+ placeholder: "Buscar membro...",
9497
+ value: assigneeSearchQuery,
9498
+ onChange: (e) => setAssigneeSearchQuery(e.target.value),
9499
+ className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
9500
+ onClick: (e) => e.stopPropagation()
9501
+ }
9502
+ )), /* @__PURE__ */ import_react18.default.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ import_react18.default.createElement(
9503
+ "li",
9504
+ {
9505
+ onClick: () => {
9506
+ setAssigneeId("");
9507
+ setHasUnsavedChanges(true);
9508
+ setIsAssigneeDropdownOpen(false);
9509
+ setAssigneeSearchQuery("");
9510
+ },
9511
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!assigneeId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9512
+ },
9513
+ "Nenhum"
9514
+ ), isAssigneeUndefined && /* @__PURE__ */ import_react18.default.createElement(
9515
+ "li",
9516
+ {
9517
+ onClick: () => {
9518
+ setIsAssigneeDropdownOpen(false);
9519
+ setAssigneeSearchQuery("");
9520
+ },
9521
+ className: "px-3 py-2.5 text-sm cursor-pointer bg-red-500/10 text-red-300 flex items-center gap-2"
9522
+ },
9523
+ "Undefined (Removido)"
9524
+ ), viewMembers.filter((member) => {
9525
+ const search = assigneeSearchQuery.toLowerCase();
9526
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
9527
+ }).map((member) => /* @__PURE__ */ import_react18.default.createElement(
9528
+ "li",
9529
+ {
9530
+ key: member.id,
9531
+ onClick: () => {
9532
+ setAssigneeId(member.id);
9397
9533
  setHasUnsavedChanges(true);
9534
+ setIsAssigneeDropdownOpen(false);
9535
+ setAssigneeSearchQuery("");
9398
9536
  },
9399
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors text-slate-200"
9537
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${assigneeId === member.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9400
9538
  },
9401
- /* @__PURE__ */ import_react18.default.createElement("option", { value: "" }, "Nenhum"),
9402
- isAssigneeUndefined && /* @__PURE__ */ import_react18.default.createElement("option", { value: assigneeId }, "Undefined"),
9403
- viewMembers.map((member) => /* @__PURE__ */ import_react18.default.createElement("option", { key: member.id, value: member.id }, member.name || member.email || member.id))
9404
- ) : /* @__PURE__ */ import_react18.default.createElement("div", { className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 text-slate-400" }, assigneeId ? assigneeMember ? assigneeMember.name || assigneeMember.email : "Undefined" : "Nenhum")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react18.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiX, { size: 12 })))), canEdit && /* @__PURE__ */ import_react18.default.createElement(
9539
+ member.name || member.email || member.id
9540
+ )), viewMembers.filter((member) => {
9541
+ const search = assigneeSearchQuery.toLowerCase();
9542
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
9543
+ }).length === 0 && assigneeSearchQuery && /* @__PURE__ */ import_react18.default.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado"))))) : /* @__PURE__ */ import_react18.default.createElement("div", { className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 text-slate-400 flex items-center gap-2" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiUser, { className: "opacity-50", size: 14 }), assigneeId ? assigneeMember ? assigneeMember.name || assigneeMember.email : "Undefined" : "Nenhum")), /* @__PURE__ */ import_react18.default.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ import_react18.default.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ import_react18.default.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ import_react18.default.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ import_react18.default.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ import_react18.default.createElement(import_fi16.FiX, { size: 12 })))), canEdit && /* @__PURE__ */ import_react18.default.createElement(
9405
9544
  "input",
9406
9545
  {
9407
9546
  type: "text",
package/dist/index.mjs CHANGED
@@ -580,29 +580,26 @@ function XViewSidebar({
580
580
  const [isFilterMenuOpen, setIsFilterMenuOpen] = useState2(false);
581
581
  const [filterCategory, setFilterCategory] = useState2("Type");
582
582
  const [filterValue, setFilterValue] = useState2("");
583
+ const [isTypeDropdownOpen, setIsTypeDropdownOpen] = useState2(false);
584
+ const [highlightedTypeIndex, setHighlightedTypeIndex] = useState2(-1);
583
585
  const containerRef = useRef2(null);
584
586
  const inputRef = useRef2(null);
585
587
  const filterMenuRef = useRef2(null);
588
+ const typeDropdownRef = useRef2(null);
586
589
  const ability = useMemo2(() => {
587
590
  return defineAbilityFor(userRole);
588
591
  }, [userRole]);
589
592
  const contextLabel = useMemo2(() => {
590
593
  if (!viewType || !viewName) return null;
591
- console.log("XViewSidebar: contextLabel viewType", viewType);
592
- try {
593
- const typeLower = viewType.toLowerCase();
594
- if (typeLower === "database") {
595
- return `Dataset: ${viewName}`;
596
- } else if (typeLower === "view") {
597
- return `View: ${viewName}`;
598
- } else if (typeLower === "node") {
599
- return `Node: ${viewName}`;
600
- }
601
- return `${viewType}: ${viewName}`;
602
- } catch (err) {
603
- console.error("XViewSidebar: Erro no contextLabel ao converter viewType:", viewType, err);
604
- return `${viewType}: ${viewName}`;
605
- }
594
+ const typeLower = String(viewType).toLowerCase();
595
+ if (typeLower === "database") {
596
+ return `Dataset: ${viewName}`;
597
+ } else if (typeLower === "view") {
598
+ return `View: ${viewName}`;
599
+ } else if (typeLower === "node") {
600
+ return `Node: ${viewName}`;
601
+ }
602
+ return `${viewType}: ${viewName}`;
606
603
  }, [viewType, viewName]);
607
604
  const normalize = (str = "") => {
608
605
  if (str === void 0 || str === null) {
@@ -615,7 +612,6 @@ function XViewSidebar({
615
612
  []
616
613
  );
617
614
  const availableTypes = useMemo2(() => {
618
- console.log("XViewSidebar: recalculando availableTypes, dbNodes count:", dbNodes == null ? void 0 : dbNodes.length);
619
615
  const typesSet = /* @__PURE__ */ new Set();
620
616
  (dbNodes || []).forEach((node) => {
621
617
  if (Array.isArray(node.type)) {
@@ -626,10 +622,13 @@ function XViewSidebar({
626
622
  typesSet.add(node.type);
627
623
  }
628
624
  });
629
- const result = Array.from(typesSet).sort();
630
- console.log("XViewSidebar: availableTypes final:", result);
631
- return result;
625
+ return Array.from(typesSet).sort();
632
626
  }, [dbNodes]);
627
+ const filteredTypes = useMemo2(() => {
628
+ if (!filterValue.trim()) return availableTypes;
629
+ const search = filterValue.toLowerCase().trim();
630
+ return availableTypes.filter((t) => t.toLowerCase().includes(search));
631
+ }, [availableTypes, filterValue]);
633
632
  const filteredAndSorted = useMemo2(() => {
634
633
  const base = Array.isArray(dbNodes) ? dbNodes : [];
635
634
  let pool = base;
@@ -642,22 +641,13 @@ function XViewSidebar({
642
641
  });
643
642
  }
644
643
  if (activeFilters.length > 0) {
645
- console.log("XViewSidebar: aplicando activeFilters:", activeFilters);
646
644
  pool = pool.filter((node) => {
647
645
  return activeFilters.every((filter) => {
648
- try {
649
- if (filter.type === "Type") {
650
- const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
651
- return nodeTypes.some((t) => {
652
- if (t === void 0) console.log("XViewSidebar: t \xE9 undefined no node:", node.id);
653
- if (filter.value === void 0) console.log("XViewSidebar: filter.value \xE9 undefined");
654
- return String(t).toLowerCase() === String(filter.value).toLowerCase();
655
- });
656
- } else if (filter.type === "Color") {
657
- return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
658
- }
659
- } catch (err) {
660
- console.error("XViewSidebar: Erro ao filtrar node:", node, "com filtro:", filter, err);
646
+ if (filter.type === "Type") {
647
+ const nodeTypes = Array.isArray(node.type) ? node.type : [node.type];
648
+ return nodeTypes.some((t) => String(t).toLowerCase() === String(filter.value).toLowerCase());
649
+ } else if (filter.type === "Color") {
650
+ return String(node.color).toLowerCase() === String(filter.value).toLowerCase();
661
651
  }
662
652
  return true;
663
653
  });
@@ -679,12 +669,15 @@ function XViewSidebar({
679
669
  if (filterMenuRef.current && !filterMenuRef.current.contains(event.target)) {
680
670
  setIsFilterMenuOpen(false);
681
671
  }
672
+ if (typeDropdownRef.current && !typeDropdownRef.current.contains(event.target)) {
673
+ setIsTypeDropdownOpen(false);
674
+ }
682
675
  };
683
- if (isFilterMenuOpen) {
676
+ if (isFilterMenuOpen || isTypeDropdownOpen) {
684
677
  document.addEventListener("mousedown", handleClickOutside);
685
678
  }
686
679
  return () => document.removeEventListener("mousedown", handleClickOutside);
687
- }, [isFilterMenuOpen]);
680
+ }, [isFilterMenuOpen, isTypeDropdownOpen]);
688
681
  useEffect2(() => {
689
682
  if (!query) setSelectedNodeId(null);
690
683
  }, [query]);
@@ -738,6 +731,35 @@ function XViewSidebar({
738
731
  const handleRemoveFilter = (index) => {
739
732
  setActiveFilters((prev) => prev.filter((_, i) => i !== index));
740
733
  };
734
+ const handleTypeKeyDown = (e) => {
735
+ if (!isTypeDropdownOpen) {
736
+ setIsTypeDropdownOpen(true);
737
+ }
738
+ if (e.key === "ArrowDown") {
739
+ e.preventDefault();
740
+ setHighlightedTypeIndex(
741
+ (prev) => prev < filteredTypes.length - 1 ? prev + 1 : prev
742
+ );
743
+ } else if (e.key === "ArrowUp") {
744
+ e.preventDefault();
745
+ setHighlightedTypeIndex((prev) => prev > 0 ? prev - 1 : 0);
746
+ } else if (e.key === "Enter") {
747
+ e.preventDefault();
748
+ if (highlightedTypeIndex >= 0 && filteredTypes[highlightedTypeIndex]) {
749
+ setFilterValue(filteredTypes[highlightedTypeIndex]);
750
+ setIsTypeDropdownOpen(false);
751
+ setHighlightedTypeIndex(-1);
752
+ } else {
753
+ handleAddFilter();
754
+ }
755
+ } else if (e.key === "Escape") {
756
+ e.preventDefault();
757
+ setIsTypeDropdownOpen(false);
758
+ setHighlightedTypeIndex(-1);
759
+ } else if (e.key === "Tab") {
760
+ setIsTypeDropdownOpen(false);
761
+ }
762
+ };
741
763
  const ToggleButton = /* @__PURE__ */ React2.createElement(
742
764
  "button",
743
765
  {
@@ -868,18 +890,36 @@ function XViewSidebar({
868
890
  className: `flex-1 text-xs py-1 rounded transition-colors ${filterCategory === opt ? "bg-indigo-600 text-white shadow-sm" : "text-slate-400 hover:text-slate-200"}`
869
891
  },
870
892
  opt
871
- )))), /* @__PURE__ */ React2.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), filterCategory === "Type" ? /* @__PURE__ */ React2.createElement("div", { className: "relative" }, /* @__PURE__ */ React2.createElement(
893
+ )))), /* @__PURE__ */ React2.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React2.createElement("label", { className: "text-[10px] uppercase text-slate-400 font-semibold tracking-wider" }, "Valor"), filterCategory === "Type" ? /* @__PURE__ */ React2.createElement("div", { className: "relative", ref: typeDropdownRef }, /* @__PURE__ */ React2.createElement(
872
894
  "input",
873
895
  {
874
- list: "typeOptions",
875
896
  type: "text",
876
897
  value: filterValue,
877
- onChange: (e) => setFilterValue(e.target.value),
898
+ onChange: (e) => {
899
+ setFilterValue(e.target.value);
900
+ if (!isTypeDropdownOpen) setIsTypeDropdownOpen(true);
901
+ setHighlightedTypeIndex(-1);
902
+ },
903
+ onFocus: () => setIsTypeDropdownOpen(true),
904
+ onKeyDown: handleTypeKeyDown,
878
905
  placeholder: "Ex: Concept",
879
906
  className: "w-full bg-slate-800 p-2 text-xs rounded border border-white/10 focus:outline-none focus:border-indigo-500/50 text-white",
880
907
  autoFocus: true
881
908
  }
882
- ), /* @__PURE__ */ React2.createElement("datalist", { id: "typeOptions" }, availableTypes.map((t) => /* @__PURE__ */ React2.createElement("option", { key: t, value: t })))) : /* @__PURE__ */ React2.createElement("div", { className: "relative flex items-center" }, /* @__PURE__ */ React2.createElement(
909
+ ), isTypeDropdownOpen && filteredTypes.length > 0 && /* @__PURE__ */ React2.createElement("div", { className: "absolute z-[60] left-0 right-0 mt-1 max-h-48 overflow-y-auto bg-slate-900/95 backdrop-blur-xl border border-white/10 rounded-md shadow-2xl custom-scrollbar" }, filteredTypes.map((t, idx) => /* @__PURE__ */ React2.createElement(
910
+ "div",
911
+ {
912
+ key: t,
913
+ className: `px-3 py-2 text-xs cursor-pointer transition-colors ${idx === highlightedTypeIndex ? "bg-indigo-600 text-white" : "text-slate-300 hover:bg-white/10"}`,
914
+ onMouseDown: (e) => {
915
+ e.preventDefault();
916
+ setFilterValue(t);
917
+ setIsTypeDropdownOpen(false);
918
+ setHighlightedTypeIndex(-1);
919
+ }
920
+ },
921
+ t
922
+ )))) : /* @__PURE__ */ React2.createElement("div", { className: "relative flex items-center" }, /* @__PURE__ */ React2.createElement(
883
923
  "div",
884
924
  {
885
925
  className: "absolute left-2 w-3 h-3 rounded-full border border-white/20 shadow-sm",
@@ -7680,7 +7720,7 @@ function ColorPicker({ color, onChange, disabled }) {
7680
7720
  style: { backgroundColor: preset },
7681
7721
  title: preset
7682
7722
  },
7683
- color.toLowerCase() === preset.toLowerCase() && /* @__PURE__ */ React12.createElement(FiCheck6, { className: `drop-shadow-md ${["#ffffff", "#4df5cb", "#84cc16", "#f59e0b"].includes(preset) ? "text-black" : "text-white"}`, size: 12 })
7723
+ (color || "").toLowerCase() === (preset || "").toLowerCase() && /* @__PURE__ */ React12.createElement(FiCheck6, { className: `drop-shadow-md ${["#ffffff", "#4df5cb", "#84cc16", "#f59e0b"].includes(preset) ? "text-black" : "text-white"}`, size: 12 })
7684
7724
  )))), /* @__PURE__ */ React12.createElement("style", null, `
7685
7725
  .custom-react-colorful .react-colorful {
7686
7726
  width: 100%;
@@ -8307,7 +8347,7 @@ function InSceneVersionForm({
8307
8347
 
8308
8348
  // src/components/InSceneQuestForm.jsx
8309
8349
  import React15, { useState as useState16, useRef as useRef12 } from "react";
8310
- import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4, FiChevronDown as FiChevronDown5 } from "react-icons/fi";
8350
+ import { FiPlus as FiPlus5, FiCheck as FiCheck9, FiEdit2 as FiEdit26, FiTarget, FiX as FiX4, FiChevronDown as FiChevronDown5, FiUser, FiSearch as FiSearch4 } from "react-icons/fi";
8311
8351
  var QUEST_STATUS_COLORS2 = {
8312
8352
  "Backlog": "#64748b",
8313
8353
  "In Progress": "#eab308",
@@ -8333,6 +8373,7 @@ function InSceneQuestForm({
8333
8373
  // NOVA PROP
8334
8374
  viewMembers = []
8335
8375
  }) {
8376
+ var _a, _b;
8336
8377
  const [name, setName] = useState16("");
8337
8378
  const [assigneeId, setAssigneeId] = useState16("");
8338
8379
  const [types, setTypes] = useState16(["quest"]);
@@ -8342,6 +8383,8 @@ function InSceneQuestForm({
8342
8383
  const [intensity, setIntensity] = useState16(0);
8343
8384
  const [description, setDescription] = useState16("");
8344
8385
  const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState16(false);
8386
+ const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = useState16(false);
8387
+ const [assigneeSearchQuery, setAssigneeSearchQuery] = useState16("");
8345
8388
  const [customProps, setCustomProps] = useState16([]);
8346
8389
  const [isDescriptionModalOpen, setIsDescriptionModalOpen] = useState16(false);
8347
8390
  const propsEndRef = useRef12(null);
@@ -8350,8 +8393,8 @@ function InSceneQuestForm({
8350
8393
  const newProp = createNewCustomProperty(customProps);
8351
8394
  setCustomProps([...customProps, newProp]);
8352
8395
  setTimeout(() => {
8353
- var _a;
8354
- (_a = propsEndRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "center" });
8396
+ var _a2;
8397
+ (_a2 = propsEndRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth", block: "center" });
8355
8398
  }, 100);
8356
8399
  };
8357
8400
  const handleRemoveProp = (index) => setCustomProps(customProps.filter((_, i) => i !== index));
@@ -8469,16 +8512,59 @@ function InSceneQuestForm({
8469
8512
  },
8470
8513
  /* @__PURE__ */ React15.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS2[s] } }),
8471
8514
  s
8472
- )))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), /* @__PURE__ */ React15.createElement(
8473
- "select",
8515
+ )))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), /* @__PURE__ */ React15.createElement("div", { className: "relative" }, /* @__PURE__ */ React15.createElement(
8516
+ "button",
8474
8517
  {
8475
- value: assigneeId,
8476
- onChange: (e) => setAssigneeId(e.target.value),
8477
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors text-slate-200"
8518
+ type: "button",
8519
+ onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
8520
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
8478
8521
  },
8479
- /* @__PURE__ */ React15.createElement("option", { value: "" }, "Nenhum"),
8480
- viewMembers.map((member) => /* @__PURE__ */ React15.createElement("option", { key: member.id, value: member.id }, member.name || member.email || member.id))
8481
- )), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8522
+ /* @__PURE__ */ React15.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React15.createElement(FiUser, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React15.createElement("span", { className: "text-slate-200 font-medium" }, ((_a = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _a.name) || ((_b = viewMembers.find((m) => m.id === assigneeId)) == null ? void 0 : _b.email) || "Nenhum")),
8523
+ /* @__PURE__ */ React15.createElement(FiChevronDown5, { className: `text-slate-400 transition-transform duration-200 ${isAssigneeDropdownOpen ? "rotate-180" : ""}` })
8524
+ ), isAssigneeDropdownOpen && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
8525
+ setIsAssigneeDropdownOpen(false);
8526
+ setAssigneeSearchQuery("");
8527
+ } }), /* @__PURE__ */ React15.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ React15.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ React15.createElement(FiSearch4, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ React15.createElement(
8528
+ "input",
8529
+ {
8530
+ type: "text",
8531
+ autoFocus: true,
8532
+ placeholder: "Buscar membro...",
8533
+ value: assigneeSearchQuery,
8534
+ onChange: (e) => setAssigneeSearchQuery(e.target.value),
8535
+ className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
8536
+ onClick: (e) => e.stopPropagation()
8537
+ }
8538
+ )), /* @__PURE__ */ React15.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ React15.createElement(
8539
+ "li",
8540
+ {
8541
+ onClick: () => {
8542
+ setAssigneeId("");
8543
+ setIsAssigneeDropdownOpen(false);
8544
+ setAssigneeSearchQuery("");
8545
+ },
8546
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!assigneeId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8547
+ },
8548
+ "Nenhum"
8549
+ ), viewMembers.filter((member) => {
8550
+ const search = assigneeSearchQuery.toLowerCase();
8551
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
8552
+ }).map((member) => /* @__PURE__ */ React15.createElement(
8553
+ "li",
8554
+ {
8555
+ key: member.id,
8556
+ onClick: () => {
8557
+ setAssigneeId(member.id);
8558
+ setIsAssigneeDropdownOpen(false);
8559
+ setAssigneeSearchQuery("");
8560
+ },
8561
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${assigneeId === member.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
8562
+ },
8563
+ member.name || member.email || member.id
8564
+ )), viewMembers.filter((member) => {
8565
+ const search = assigneeSearchQuery.toLowerCase();
8566
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
8567
+ }).length === 0 && assigneeSearchQuery && /* @__PURE__ */ React15.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado")))))), /* @__PURE__ */ React15.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React15.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React15.createElement("div", { className: "relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 focus-within:ring-2 focus-within:ring-indigo-400/60 transition-all" }, types.map((t, index) => /* @__PURE__ */ React15.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, t !== "quest" && /* @__PURE__ */ React15.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React15.createElement(FiX4, { size: 12 })))), /* @__PURE__ */ React15.createElement(
8482
8568
  "input",
8483
8569
  {
8484
8570
  type: "text",
@@ -9057,7 +9143,7 @@ function NodeDetailsPanel({
9057
9143
 
9058
9144
  // src/components/QuestDetailsPanel.jsx
9059
9145
  import React17, { useState as useState18, useEffect as useEffect16, useRef as useRef14 } from "react";
9060
- import { FiPlus as FiPlus7, FiX as FiX6, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink6, FiTarget as FiTarget2, FiChevronDown as FiChevronDown6 } from "react-icons/fi";
9146
+ import { FiPlus as FiPlus7, FiX as FiX6, FiCheck as FiCheck11, FiEdit2 as FiEdit28, FiLoader as FiLoader3, FiBookOpen as FiBookOpen4, FiLink as FiLink6, FiTarget as FiTarget2, FiChevronDown as FiChevronDown6, FiUser as FiUser2, FiSearch as FiSearch5 } from "react-icons/fi";
9061
9147
  var QUEST_STATUS_COLORS3 = {
9062
9148
  "Backlog": "#64748b",
9063
9149
  "In Progress": "#eab308",
@@ -9097,6 +9183,8 @@ function QuestDetailsPanel({
9097
9183
  const [description, setDescription] = useState18((node == null ? void 0 : node.description) ?? "");
9098
9184
  const [intensity, setIntensity] = useState18((node == null ? void 0 : node.intensity) !== void 0 ? node.intensity : 0);
9099
9185
  const [isStatusDropdownOpen, setIsStatusDropdownOpen] = useState18(false);
9186
+ const [isAssigneeDropdownOpen, setIsAssigneeDropdownOpen] = useState18(false);
9187
+ const [assigneeSearchQuery, setAssigneeSearchQuery] = useState18("");
9100
9188
  const [customProps, setCustomProps] = useState18(() => extractCustomPropsFromNode(node || {}));
9101
9189
  const [showTypeSuggestions, setShowTypeSuggestions] = useState18(false);
9102
9190
  const [filteredTypes, setFilteredTypes] = useState18([]);
@@ -9380,20 +9468,71 @@ function QuestDetailsPanel({
9380
9468
  },
9381
9469
  /* @__PURE__ */ React17.createElement("span", { className: "w-3 h-3 rounded-full", style: { backgroundColor: QUEST_STATUS_COLORS3[s] } }),
9382
9470
  s
9383
- )))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), canEdit ? /* @__PURE__ */ React17.createElement(
9384
- "select",
9471
+ )))))), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5 relative mt-2" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Assignee (Respons\xE1vel)"), canEdit ? /* @__PURE__ */ React17.createElement("div", { className: "relative" }, /* @__PURE__ */ React17.createElement(
9472
+ "button",
9385
9473
  {
9386
- value: assigneeId,
9387
- onChange: (e) => {
9388
- setAssigneeId(e.target.value);
9474
+ type: "button",
9475
+ onClick: () => setIsAssigneeDropdownOpen(!isAssigneeDropdownOpen),
9476
+ className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors flex items-center justify-between"
9477
+ },
9478
+ /* @__PURE__ */ React17.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React17.createElement(FiUser2, { className: "text-slate-400", size: 14 }), /* @__PURE__ */ React17.createElement("span", { className: "text-slate-200 font-medium" }, isAssigneeUndefined ? "Undefined" : (assigneeMember == null ? void 0 : assigneeMember.name) || (assigneeMember == null ? void 0 : assigneeMember.email) || "Nenhum")),
9479
+ /* @__PURE__ */ React17.createElement(FiChevronDown6, { className: `text-slate-400 transition-transform duration-200 ${isAssigneeDropdownOpen ? "rotate-180" : ""}` })
9480
+ ), isAssigneeDropdownOpen && /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement("div", { className: "fixed inset-0 z-40", onClick: () => {
9481
+ setIsAssigneeDropdownOpen(false);
9482
+ setAssigneeSearchQuery("");
9483
+ } }), /* @__PURE__ */ React17.createElement("div", { className: "absolute top-full left-0 mt-1.5 w-full bg-slate-900 border border-white/10 rounded-lg shadow-[0_8px_30px_rgba(0,0,0,0.5)] z-50 overflow-hidden flex flex-col" }, /* @__PURE__ */ React17.createElement("div", { className: "p-2 border-b border-white/5 bg-white/5 flex items-center gap-2" }, /* @__PURE__ */ React17.createElement(FiSearch5, { className: "text-slate-500", size: 14 }), /* @__PURE__ */ React17.createElement(
9484
+ "input",
9485
+ {
9486
+ type: "text",
9487
+ autoFocus: true,
9488
+ placeholder: "Buscar membro...",
9489
+ value: assigneeSearchQuery,
9490
+ onChange: (e) => setAssigneeSearchQuery(e.target.value),
9491
+ className: "bg-transparent border-none outline-none text-xs text-white placeholder-slate-500 w-full",
9492
+ onClick: (e) => e.stopPropagation()
9493
+ }
9494
+ )), /* @__PURE__ */ React17.createElement("ul", { className: "max-h-48 overflow-y-auto custom-scrollbar" }, /* @__PURE__ */ React17.createElement(
9495
+ "li",
9496
+ {
9497
+ onClick: () => {
9498
+ setAssigneeId("");
9499
+ setHasUnsavedChanges(true);
9500
+ setIsAssigneeDropdownOpen(false);
9501
+ setAssigneeSearchQuery("");
9502
+ },
9503
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${!assigneeId ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9504
+ },
9505
+ "Nenhum"
9506
+ ), isAssigneeUndefined && /* @__PURE__ */ React17.createElement(
9507
+ "li",
9508
+ {
9509
+ onClick: () => {
9510
+ setIsAssigneeDropdownOpen(false);
9511
+ setAssigneeSearchQuery("");
9512
+ },
9513
+ className: "px-3 py-2.5 text-sm cursor-pointer bg-red-500/10 text-red-300 flex items-center gap-2"
9514
+ },
9515
+ "Undefined (Removido)"
9516
+ ), viewMembers.filter((member) => {
9517
+ const search = assigneeSearchQuery.toLowerCase();
9518
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
9519
+ }).map((member) => /* @__PURE__ */ React17.createElement(
9520
+ "li",
9521
+ {
9522
+ key: member.id,
9523
+ onClick: () => {
9524
+ setAssigneeId(member.id);
9389
9525
  setHasUnsavedChanges(true);
9526
+ setIsAssigneeDropdownOpen(false);
9527
+ setAssigneeSearchQuery("");
9390
9528
  },
9391
- className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 hover:border-white/20 focus:outline-none focus:ring-2 focus:ring-indigo-400/60 transition-colors text-slate-200"
9529
+ className: `px-3 py-2.5 text-sm cursor-pointer transition-colors flex items-center gap-2 ${assigneeId === member.id ? "bg-indigo-500/20 text-white" : "text-slate-300 hover:bg-white/5 hover:text-white"}`
9392
9530
  },
9393
- /* @__PURE__ */ React17.createElement("option", { value: "" }, "Nenhum"),
9394
- isAssigneeUndefined && /* @__PURE__ */ React17.createElement("option", { value: assigneeId }, "Undefined"),
9395
- viewMembers.map((member) => /* @__PURE__ */ React17.createElement("option", { key: member.id, value: member.id }, member.name || member.email || member.id))
9396
- ) : /* @__PURE__ */ React17.createElement("div", { className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 text-slate-400" }, assigneeId ? assigneeMember ? assigneeMember.name || assigneeMember.email : "Undefined" : "Nenhum")), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React17.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement(
9531
+ member.name || member.email || member.id
9532
+ )), viewMembers.filter((member) => {
9533
+ const search = assigneeSearchQuery.toLowerCase();
9534
+ return (member.name || "").toLowerCase().includes(search) || (member.email || "").toLowerCase().includes(search);
9535
+ }).length === 0 && assigneeSearchQuery && /* @__PURE__ */ React17.createElement("li", { className: "px-3 py-4 text-xs text-slate-500 text-center italic" }, "Nenhum membro encontrado"))))) : /* @__PURE__ */ React17.createElement("div", { className: "w-full bg-slate-800/70 p-2.5 text-sm rounded-lg border border-white/10 text-slate-400 flex items-center gap-2" }, /* @__PURE__ */ React17.createElement(FiUser2, { className: "opacity-50", size: 14 }), assigneeId ? assigneeMember ? assigneeMember.name || assigneeMember.email : "Undefined" : "Nenhum")), /* @__PURE__ */ React17.createElement("div", { className: "space-y-1.5" }, /* @__PURE__ */ React17.createElement("label", { className: "text-xs text-slate-300" }, "Tipos Adicionais"), /* @__PURE__ */ React17.createElement("div", { className: `relative w-full bg-slate-800/70 p-1.5 min-h-[42px] flex flex-wrap gap-1.5 rounded-lg border border-white/10 ${canEdit ? "focus-within:ring-2 focus-within:ring-indigo-400/60" : ""} transition-all` }, types.map((t, index) => /* @__PURE__ */ React17.createElement("span", { key: index, className: `flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-medium border ${t === "quest" ? "bg-sky-500/20 text-sky-200 border-sky-500/30" : "bg-indigo-500/30 text-indigo-100 border-indigo-500/20"}` }, t, canEdit && t !== "quest" && /* @__PURE__ */ React17.createElement("button", { type: "button", onClick: () => handleRemoveType(index), className: "hover:text-white transition-colors" }, /* @__PURE__ */ React17.createElement(FiX6, { size: 12 })))), canEdit && /* @__PURE__ */ React17.createElement(
9397
9536
  "input",
9398
9537
  {
9399
9538
  type: "text",
@@ -10271,7 +10410,7 @@ function AncestryLinkDetailsPanel({ data, onClose, onOpenImageViewer, onOpenRefe
10271
10410
  // src/components/AncestryBoard.jsx
10272
10411
  import React24, { useState as useState24, useMemo as useMemo11, useEffect as useEffect21, useRef as useRef18 } from "react";
10273
10412
  import {
10274
- FiSearch as FiSearch4,
10413
+ FiSearch as FiSearch6,
10275
10414
  FiLayers as FiLayers6,
10276
10415
  FiCornerUpRight as FiCornerUpRight4,
10277
10416
  FiPlay,
@@ -10396,7 +10535,7 @@ var GroupItem = ({
10396
10535
  `,
10397
10536
  title: "Adicionar Ancestralidade a este grupo"
10398
10537
  },
10399
- isPickingForThisGroup ? /* @__PURE__ */ React24.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React24.createElement(FiSearch4, { size: 12 }),
10538
+ isPickingForThisGroup ? /* @__PURE__ */ React24.createElement(FiCheckCircle, { size: 12 }) : /* @__PURE__ */ React24.createElement(FiSearch6, { size: 12 }),
10400
10539
  isPickingForThisGroup ? "Selecionando..." : "Adicionar"
10401
10540
  ), /* @__PURE__ */ React24.createElement(
10402
10541
  "button",
@@ -10731,7 +10870,7 @@ function AncestryBoard({
10731
10870
  `
10732
10871
  },
10733
10872
  /* @__PURE__ */ React24.createElement("div", { className: "p-3 border-b border-white/5 bg-slate-900/50" }, /* @__PURE__ */ React24.createElement("div", { className: "relative group" }, /* @__PURE__ */ React24.createElement(
10734
- FiSearch4,
10873
+ FiSearch6,
10735
10874
  {
10736
10875
  className: `absolute left-3 top-1/2 -translate-y-1/2 transition-colors ${pickingGroupId ? "text-indigo-400" : "text-slate-500 group-focus-within:text-indigo-400"}`
10737
10876
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lv-x-software-house/x_view",
3
- "version": "1.2.5-dev.17",
3
+ "version": "1.2.5-dev.19",
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",