organify-ui 0.3.13 → 0.3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import * as ProgressPrimitive from '@radix-ui/react-progress';
16
16
  import { X, XIcon, GripVertical, Check, ChevronRight, Circle, Search, MoreHorizontal, AlertCircle, AlertTriangle, CheckCircle2, Info, Sparkles, Plus, Zap, Trash2, Calendar } from 'lucide-react';
17
17
  import { cva } from 'class-variance-authority';
18
18
  import * as SheetPrimitive from '@radix-ui/react-dialog';
19
+ import { createPortal } from 'react-dom';
19
20
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
20
21
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
21
22
  import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
@@ -7146,7 +7147,7 @@ function KanbanBoard({
7146
7147
  {
7147
7148
  "data-tour": "kanban-board",
7148
7149
  className: cn(
7149
- "bg-void snap-x snap-mandatory sm:snap-none",
7150
+ "flex h-full overflow-x-auto gap-3 p-4 bg-void snap-x snap-mandatory sm:snap-none",
7150
7151
  "scrollbar-none",
7151
7152
  className
7152
7153
  ),
@@ -7530,11 +7531,14 @@ function BoardsSwitcher({
7530
7531
  const [isOpen, setIsOpen] = React5.useState(false);
7531
7532
  const [isCreating, setIsCreating] = React5.useState(false);
7532
7533
  const [newBoardName, setNewBoardName] = React5.useState("");
7534
+ const [menuPos, setMenuPos] = React5.useState(null);
7535
+ const triggerRef = React5.useRef(null);
7533
7536
  const dropdownRef = React5.useRef(null);
7534
7537
  const createInputRef = React5.useRef(null);
7535
7538
  React5.useEffect(() => {
7539
+ if (!isOpen) return;
7536
7540
  function handleClickOutside(event) {
7537
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
7541
+ if (!triggerRef.current?.contains(event.target) && !dropdownRef.current?.contains(event.target)) {
7538
7542
  setIsOpen(false);
7539
7543
  setIsCreating(false);
7540
7544
  setNewBoardName("");
@@ -7542,10 +7546,27 @@ function BoardsSwitcher({
7542
7546
  }
7543
7547
  document.addEventListener("mousedown", handleClickOutside);
7544
7548
  return () => document.removeEventListener("mousedown", handleClickOutside);
7545
- }, []);
7549
+ }, [isOpen]);
7550
+ React5.useEffect(() => {
7551
+ if (!isOpen) return;
7552
+ const close = () => setIsOpen(false);
7553
+ window.addEventListener("scroll", close, true);
7554
+ window.addEventListener("resize", close);
7555
+ return () => {
7556
+ window.removeEventListener("scroll", close, true);
7557
+ window.removeEventListener("resize", close);
7558
+ };
7559
+ }, [isOpen]);
7546
7560
  React5.useEffect(() => {
7547
7561
  if (isCreating) createInputRef.current?.focus();
7548
7562
  }, [isCreating]);
7563
+ const handleToggle = () => {
7564
+ if (!isOpen) {
7565
+ const rect = triggerRef.current?.getBoundingClientRect();
7566
+ if (rect) setMenuPos({ top: rect.bottom + 4, left: rect.left });
7567
+ }
7568
+ setIsOpen((v) => !v);
7569
+ };
7549
7570
  const activeBoard = boards.find((b) => b.id === activeBoardId);
7550
7571
  const handleCreate = () => {
7551
7572
  const trimmed = newBoardName.trim();
@@ -7555,11 +7576,89 @@ function BoardsSwitcher({
7555
7576
  setIsCreating(false);
7556
7577
  }
7557
7578
  };
7558
- return /* @__PURE__ */ jsxs("div", { ref: dropdownRef, "data-tour": "board-switcher", className: cn("relative z-[10000]", className), children: [
7579
+ const dropdown = isOpen && menuPos ? /* @__PURE__ */ jsx(
7580
+ "div",
7581
+ {
7582
+ ref: dropdownRef,
7583
+ style: { position: "fixed", top: menuPos.top, left: menuPos.left, zIndex: 9999 },
7584
+ className: cn(
7585
+ "min-w-[240px]",
7586
+ "bg-elevated/95 backdrop-blur-xl border border-theme-subtle rounded-xl shadow-2xl",
7587
+ "animate-in fade-in slide-in-from-top-2 duration-200"
7588
+ ),
7589
+ children: /* @__PURE__ */ jsxs("div", { className: "p-1.5", children: [
7590
+ /* @__PURE__ */ jsx("div", { className: "max-h-[240px] overflow-y-auto scrollbar-none space-y-0.5", children: boards.map((board) => {
7591
+ const isActive = board.id === activeBoardId;
7592
+ return /* @__PURE__ */ jsxs(
7593
+ "button",
7594
+ {
7595
+ onClick: () => {
7596
+ onBoardChange(board.id);
7597
+ setIsOpen(false);
7598
+ },
7599
+ className: cn(
7600
+ "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs",
7601
+ "transition-colors",
7602
+ isActive ? "bg-primary/10 text-primary-light" : "text-theme hover:bg-theme-highlight"
7603
+ ),
7604
+ children: [
7605
+ /* @__PURE__ */ jsx(
7606
+ "div",
7607
+ {
7608
+ className: "w-2.5 h-2.5 rounded shrink-0",
7609
+ style: { backgroundColor: board.color || "#7C3AED" }
7610
+ }
7611
+ ),
7612
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: board.name }),
7613
+ board.visibility === "private" && /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", className: "text-theme-muted shrink-0", children: [
7614
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "7", width: "10", height: "7", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }),
7615
+ /* @__PURE__ */ jsx("path", { d: "M5 7V5a3 3 0 016 0v2", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
7616
+ ] }),
7617
+ board.isDefault && /* @__PURE__ */ jsx(Badge, { className: "text-[9px] px-1.5 py-0 h-4 bg-primary/10 text-primary-light border-primary/20", children: "Padr\xE3o" }),
7618
+ board.taskCount != null && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-theme-muted", children: board.taskCount })
7619
+ ]
7620
+ },
7621
+ board.id
7622
+ );
7623
+ }) }),
7624
+ onCreateBoard && /* @__PURE__ */ jsxs(Fragment, { children: [
7625
+ /* @__PURE__ */ jsx("div", { className: "h-px bg-theme-subtle my-1" }),
7626
+ isCreating ? /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx(
7627
+ "input",
7628
+ {
7629
+ ref: createInputRef,
7630
+ value: newBoardName,
7631
+ onChange: (e) => setNewBoardName(e.target.value),
7632
+ onKeyDown: (e) => {
7633
+ if (e.key === "Enter") handleCreate();
7634
+ if (e.key === "Escape") {
7635
+ setIsCreating(false);
7636
+ setNewBoardName("");
7637
+ }
7638
+ },
7639
+ placeholder: "Nome do board...",
7640
+ className: "w-full text-xs text-theme bg-transparent outline-none placeholder:text-theme-muted"
7641
+ }
7642
+ ) }) : /* @__PURE__ */ jsxs(
7643
+ "button",
7644
+ {
7645
+ onClick: () => setIsCreating(true),
7646
+ className: "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs text-theme-muted hover:text-theme hover:bg-theme-highlight transition-colors",
7647
+ children: [
7648
+ /* @__PURE__ */ jsx(OrgPlus, { className: "w-3 h-3" }),
7649
+ "Criar board"
7650
+ ]
7651
+ }
7652
+ )
7653
+ ] })
7654
+ ] })
7655
+ }
7656
+ ) : null;
7657
+ return /* @__PURE__ */ jsxs("div", { ref: triggerRef, "data-tour": "board-switcher", className: cn("relative inline-flex", className), children: [
7559
7658
  /* @__PURE__ */ jsxs(
7560
7659
  "button",
7561
7660
  {
7562
- onClick: () => setIsOpen(!isOpen),
7661
+ onClick: handleToggle,
7563
7662
  className: cn(
7564
7663
  "flex items-center gap-2 rounded-xl px-3 py-2",
7565
7664
  "bg-theme-glass backdrop-blur-md border border-theme-subtle",
@@ -7582,76 +7681,7 @@ function BoardsSwitcher({
7582
7681
  ]
7583
7682
  }
7584
7683
  ),
7585
- isOpen && /* @__PURE__ */ jsx("div", { className: cn(
7586
- "absolute top-full left-0 mt-1 z-[10001] min-w-[240px]",
7587
- "bg-elevated/95 backdrop-blur-xl border border-theme-subtle rounded-xl shadow-2xl",
7588
- "animate-in fade-in slide-in-from-top-2 duration-200"
7589
- ), children: /* @__PURE__ */ jsxs("div", { className: "p-1.5", children: [
7590
- /* @__PURE__ */ jsx("div", { className: "max-h-[240px] overflow-y-auto scrollbar-none space-y-0.5", children: boards.map((board) => {
7591
- const isActive = board.id === activeBoardId;
7592
- return /* @__PURE__ */ jsxs(
7593
- "button",
7594
- {
7595
- onClick: () => {
7596
- onBoardChange(board.id);
7597
- setIsOpen(false);
7598
- },
7599
- className: cn(
7600
- "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs",
7601
- "transition-colors",
7602
- isActive ? "bg-primary/10 text-primary-light" : "text-theme hover:bg-theme-highlight"
7603
- ),
7604
- children: [
7605
- /* @__PURE__ */ jsx(
7606
- "div",
7607
- {
7608
- className: "w-2.5 h-2.5 rounded shrink-0",
7609
- style: { backgroundColor: board.color || "#7C3AED" }
7610
- }
7611
- ),
7612
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: board.name }),
7613
- board.visibility === "private" && /* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", className: "text-theme-muted shrink-0", children: [
7614
- /* @__PURE__ */ jsx("rect", { x: "3", y: "7", width: "10", height: "7", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }),
7615
- /* @__PURE__ */ jsx("path", { d: "M5 7V5a3 3 0 016 0v2", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" })
7616
- ] }),
7617
- board.isDefault && /* @__PURE__ */ jsx(Badge, { className: "text-[9px] px-1.5 py-0 h-4 bg-primary/10 text-primary-light border-primary/20", children: "Padr\xE3o" }),
7618
- board.taskCount != null && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-theme-muted", children: board.taskCount })
7619
- ]
7620
- },
7621
- board.id
7622
- );
7623
- }) }),
7624
- onCreateBoard && /* @__PURE__ */ jsxs(Fragment, { children: [
7625
- /* @__PURE__ */ jsx("div", { className: "h-px bg-theme-subtle my-1" }),
7626
- isCreating ? /* @__PURE__ */ jsx("div", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx(
7627
- "input",
7628
- {
7629
- ref: createInputRef,
7630
- value: newBoardName,
7631
- onChange: (e) => setNewBoardName(e.target.value),
7632
- onKeyDown: (e) => {
7633
- if (e.key === "Enter") handleCreate();
7634
- if (e.key === "Escape") {
7635
- setIsCreating(false);
7636
- setNewBoardName("");
7637
- }
7638
- },
7639
- placeholder: "Nome do board...",
7640
- className: "w-full text-xs text-theme bg-transparent outline-none placeholder:text-theme-muted"
7641
- }
7642
- ) }) : /* @__PURE__ */ jsxs(
7643
- "button",
7644
- {
7645
- onClick: () => setIsCreating(true),
7646
- className: "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs text-theme-muted hover:text-theme hover:bg-theme-highlight transition-colors",
7647
- children: [
7648
- /* @__PURE__ */ jsx(OrgPlus, { className: "w-3 h-3" }),
7649
- "Criar board"
7650
- ]
7651
- }
7652
- )
7653
- ] })
7654
- ] }) })
7684
+ typeof document !== "undefined" && dropdown && createPortal(dropdown, document.body)
7655
7685
  ] });
7656
7686
  }
7657
7687
  BoardsSwitcher.displayName = "BoardsSwitcher";
@@ -7669,29 +7699,117 @@ function SprintFilter({
7669
7699
  className
7670
7700
  }) {
7671
7701
  const [isOpen, setIsOpen] = React5.useState(false);
7702
+ const [menuPos, setMenuPos] = React5.useState(null);
7703
+ const triggerRef = React5.useRef(null);
7672
7704
  const dropdownRef = React5.useRef(null);
7673
7705
  React5.useEffect(() => {
7706
+ if (!isOpen) return;
7674
7707
  function handleClickOutside(event) {
7675
- if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
7708
+ if (!triggerRef.current?.contains(event.target) && !dropdownRef.current?.contains(event.target)) {
7676
7709
  setIsOpen(false);
7677
7710
  }
7678
7711
  }
7679
7712
  document.addEventListener("mousedown", handleClickOutside);
7680
7713
  return () => document.removeEventListener("mousedown", handleClickOutside);
7681
- }, []);
7714
+ }, [isOpen]);
7715
+ React5.useEffect(() => {
7716
+ if (!isOpen) return;
7717
+ const close = () => setIsOpen(false);
7718
+ window.addEventListener("scroll", close, true);
7719
+ window.addEventListener("resize", close);
7720
+ return () => {
7721
+ window.removeEventListener("scroll", close, true);
7722
+ window.removeEventListener("resize", close);
7723
+ };
7724
+ }, [isOpen]);
7725
+ const handleToggle = () => {
7726
+ if (!isOpen) {
7727
+ const rect = triggerRef.current?.getBoundingClientRect();
7728
+ if (rect) setMenuPos({ top: rect.bottom + 4, left: rect.left });
7729
+ }
7730
+ setIsOpen((v) => !v);
7731
+ };
7682
7732
  const selectedSprint = selectedSprintId ? sprints.find((s) => s.id === selectedSprintId) : null;
7683
7733
  const displayLabel = selectedSprint ? selectedSprint.name : selectedSprintId === null ? "Todas as tarefas" : activeSprint?.name ?? "Todas as tarefas";
7684
7734
  const sortedSprints = React5.useMemo(() => {
7685
7735
  const order = { ACTIVE: 0, PLANNED: 1, COMPLETED: 2 };
7686
7736
  return [...sprints].sort((a, b) => (order[a.status] ?? 9) - (order[b.status] ?? 9));
7687
7737
  }, [sprints]);
7688
- return /* @__PURE__ */ jsxs("div", { ref: dropdownRef, "data-tour": "sprint-switcher", className: cn("relative z-[10000]", className), children: [
7689
- /* @__PURE__ */ jsxs(
7738
+ const dropdown = isOpen && menuPos ? /* @__PURE__ */ jsx(
7739
+ "div",
7740
+ {
7741
+ ref: dropdownRef,
7742
+ style: { position: "fixed", top: menuPos.top, left: menuPos.left, zIndex: 9999 },
7743
+ className: cn(
7744
+ "min-w-[220px]",
7745
+ "bg-elevated/95 backdrop-blur-xl border border-theme-subtle rounded-xl shadow-2xl",
7746
+ "animate-in fade-in slide-in-from-top-2 duration-200"
7747
+ ),
7748
+ children: /* @__PURE__ */ jsxs("div", { className: "p-1.5 max-h-[280px] overflow-y-auto scrollbar-none", children: [
7749
+ /* @__PURE__ */ jsxs(
7750
+ "button",
7751
+ {
7752
+ onClick: () => {
7753
+ onSprintChange(null);
7754
+ setIsOpen(false);
7755
+ },
7756
+ className: cn(
7757
+ "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs",
7758
+ "transition-colors",
7759
+ selectedSprintId === null ? "bg-primary/10 text-primary-light" : "text-theme-muted hover:bg-theme-highlight hover:text-theme"
7760
+ ),
7761
+ children: [
7762
+ /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-theme-muted shrink-0" }),
7763
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: "Todas as tarefas" })
7764
+ ]
7765
+ }
7766
+ ),
7767
+ sortedSprints.length > 0 && /* @__PURE__ */ jsx("div", { className: "h-px bg-theme-subtle my-1" }),
7768
+ sortedSprints.map((sprint) => {
7769
+ const config = statusConfig2[sprint.status];
7770
+ const isSelected = selectedSprintId === sprint.id;
7771
+ return /* @__PURE__ */ jsxs(
7772
+ "button",
7773
+ {
7774
+ onClick: () => {
7775
+ onSprintChange(sprint.id);
7776
+ setIsOpen(false);
7777
+ },
7778
+ className: cn(
7779
+ "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs",
7780
+ "transition-colors",
7781
+ isSelected ? "bg-primary/10 text-primary-light" : "text-theme hover:bg-theme-highlight"
7782
+ ),
7783
+ children: [
7784
+ /* @__PURE__ */ jsx(
7785
+ "span",
7786
+ {
7787
+ className: cn("w-2 h-2 rounded-full shrink-0", {
7788
+ "bg-emerald-400": sprint.status === "ACTIVE",
7789
+ "bg-blue-400": sprint.status === "PLANNED",
7790
+ "bg-theme-muted": sprint.status === "COMPLETED"
7791
+ })
7792
+ }
7793
+ ),
7794
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: sprint.name }),
7795
+ /* @__PURE__ */ jsx(Badge, { className: cn("text-[9px] px-1.5 py-0 h-4 border", config.className), children: config.label }),
7796
+ sprint.taskCount != null && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-theme-muted", children: sprint.taskCount })
7797
+ ]
7798
+ },
7799
+ sprint.id
7800
+ );
7801
+ }),
7802
+ sortedSprints.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center text-xs text-theme-muted", children: "Nenhuma sprint criada" })
7803
+ ] })
7804
+ }
7805
+ ) : null;
7806
+ return /* @__PURE__ */ jsxs("div", { "data-tour": "sprint-switcher", className: cn("relative", className), children: [
7807
+ /* @__PURE__ */ jsx("div", { ref: triggerRef, className: "inline-flex", children: /* @__PURE__ */ jsxs(
7690
7808
  Button,
7691
7809
  {
7692
7810
  variant: "ghost",
7693
7811
  size: "sm",
7694
- onClick: () => setIsOpen(!isOpen),
7812
+ onClick: handleToggle,
7695
7813
  className: cn(
7696
7814
  "h-8 gap-1.5 text-xs font-medium",
7697
7815
  compact ? "px-2" : "px-3 gap-2",
@@ -7705,67 +7823,8 @@ function SprintFilter({
7705
7823
  /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", className: cn("transition-transform shrink-0", isOpen && "rotate-180"), children: /* @__PURE__ */ jsx("path", { d: "M2.5 3.75L5 6.25L7.5 3.75", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }) })
7706
7824
  ]
7707
7825
  }
7708
- ),
7709
- isOpen && /* @__PURE__ */ jsx("div", { className: cn(
7710
- "absolute top-full left-0 mt-1 z-[10001] min-w-[220px]",
7711
- "bg-elevated/95 backdrop-blur-xl border border-theme-subtle rounded-xl shadow-2xl",
7712
- "animate-in fade-in slide-in-from-top-2 duration-200"
7713
- ), children: /* @__PURE__ */ jsxs("div", { className: "p-1.5 max-h-[280px] overflow-y-auto scrollbar-none", children: [
7714
- /* @__PURE__ */ jsxs(
7715
- "button",
7716
- {
7717
- onClick: () => {
7718
- onSprintChange(null);
7719
- setIsOpen(false);
7720
- },
7721
- className: cn(
7722
- "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs",
7723
- "transition-colors",
7724
- selectedSprintId === null ? "bg-primary/10 text-primary-light" : "text-theme-muted hover:bg-theme-highlight hover:text-theme"
7725
- ),
7726
- children: [
7727
- /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-theme-muted shrink-0" }),
7728
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: "Todas as tarefas" })
7729
- ]
7730
- }
7731
- ),
7732
- sortedSprints.length > 0 && /* @__PURE__ */ jsx("div", { className: "h-px bg-theme-subtle my-1" }),
7733
- sortedSprints.map((sprint) => {
7734
- const config = statusConfig2[sprint.status];
7735
- const isSelected = selectedSprintId === sprint.id;
7736
- return /* @__PURE__ */ jsxs(
7737
- "button",
7738
- {
7739
- onClick: () => {
7740
- onSprintChange(sprint.id);
7741
- setIsOpen(false);
7742
- },
7743
- className: cn(
7744
- "w-full flex items-center gap-2 px-3 py-2 rounded-lg text-xs",
7745
- "transition-colors",
7746
- isSelected ? "bg-primary/10 text-primary-light" : "text-theme hover:bg-theme-highlight"
7747
- ),
7748
- children: [
7749
- /* @__PURE__ */ jsx(
7750
- "span",
7751
- {
7752
- className: cn("w-2 h-2 rounded-full shrink-0", {
7753
- "bg-emerald-400": sprint.status === "ACTIVE",
7754
- "bg-blue-400": sprint.status === "PLANNED",
7755
- "bg-theme-muted": sprint.status === "COMPLETED"
7756
- })
7757
- }
7758
- ),
7759
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-left truncate", children: sprint.name }),
7760
- /* @__PURE__ */ jsx(Badge, { className: cn("text-[9px] px-1.5 py-0 h-4 border", config.className), children: config.label }),
7761
- sprint.taskCount != null && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-theme-muted", children: sprint.taskCount })
7762
- ]
7763
- },
7764
- sprint.id
7765
- );
7766
- }),
7767
- sortedSprints.length === 0 && /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center text-xs text-theme-muted", children: "Nenhuma sprint criada" })
7768
- ] }) })
7826
+ ) }),
7827
+ typeof document !== "undefined" && dropdown && createPortal(dropdown, document.body)
7769
7828
  ] });
7770
7829
  }
7771
7830
  SprintFilter.displayName = "SprintFilter";