@tetrascience-npm/tetrascience-react-ui 0.6.0-beta.90.1 → 0.6.0-beta.91.1

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 (59) hide show
  1. package/dist/components/ai/chain-of-thought.cjs +1 -1
  2. package/dist/components/ai/chain-of-thought.cjs.map +1 -1
  3. package/dist/components/ai/chain-of-thought.js +5 -5
  4. package/dist/components/ai/chain-of-thought.js.map +1 -1
  5. package/dist/components/ai/conversation.cjs +2 -2
  6. package/dist/components/ai/conversation.cjs.map +1 -1
  7. package/dist/components/ai/conversation.js +2 -2
  8. package/dist/components/ai/conversation.js.map +1 -1
  9. package/dist/components/ai/queue.cjs +1 -1
  10. package/dist/components/ai/queue.cjs.map +1 -1
  11. package/dist/components/ai/queue.js +9 -9
  12. package/dist/components/ai/queue.js.map +1 -1
  13. package/dist/components/composed/DataAppShell/DataAppShell.cjs +1 -1
  14. package/dist/components/composed/DataAppShell/DataAppShell.cjs.map +1 -1
  15. package/dist/components/composed/DataAppShell/DataAppShell.js +1 -1
  16. package/dist/components/composed/DataAppShell/DataAppShell.js.map +1 -1
  17. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs +1 -1
  18. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs.map +1 -1
  19. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js +1 -1
  20. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js.map +1 -1
  21. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +1 -1
  22. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -1
  23. package/dist/components/composed/PlateMapEditor/WellLegend.js +8 -8
  24. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -1
  25. package/dist/components/composed/RichListItem/RichListItem.cjs +1 -1
  26. package/dist/components/composed/RichListItem/RichListItem.cjs.map +1 -1
  27. package/dist/components/composed/RichListItem/RichListItem.js +16 -16
  28. package/dist/components/composed/RichListItem/RichListItem.js.map +1 -1
  29. package/dist/components/ui/badge.cjs +1 -1
  30. package/dist/components/ui/badge.cjs.map +1 -1
  31. package/dist/components/ui/badge.js +8 -8
  32. package/dist/components/ui/badge.js.map +1 -1
  33. package/dist/components/ui/button.cjs +1 -1
  34. package/dist/components/ui/button.cjs.map +1 -1
  35. package/dist/components/ui/button.js +11 -11
  36. package/dist/components/ui/button.js.map +1 -1
  37. package/dist/components/ui/item.cjs +1 -1
  38. package/dist/components/ui/item.cjs.map +1 -1
  39. package/dist/components/ui/item.js +1 -1
  40. package/dist/components/ui/item.js.map +1 -1
  41. package/dist/components/ui/menubar.cjs +1 -1
  42. package/dist/components/ui/menubar.cjs.map +1 -1
  43. package/dist/components/ui/menubar.js +1 -1
  44. package/dist/components/ui/menubar.js.map +1 -1
  45. package/dist/components/ui/navigation-menu.cjs +1 -1
  46. package/dist/components/ui/navigation-menu.cjs.map +1 -1
  47. package/dist/components/ui/navigation-menu.js +54 -54
  48. package/dist/components/ui/navigation-menu.js.map +1 -1
  49. package/dist/components/ui/table.cjs +1 -1
  50. package/dist/components/ui/table.cjs.map +1 -1
  51. package/dist/components/ui/table.js +13 -13
  52. package/dist/components/ui/table.js.map +1 -1
  53. package/dist/components/ui/toggle.cjs +1 -1
  54. package/dist/components/ui/toggle.cjs.map +1 -1
  55. package/dist/components/ui/toggle.js +12 -12
  56. package/dist/components/ui/toggle.js.map +1 -1
  57. package/dist/index.css +1 -1
  58. package/dist/index.tailwind.css +1 -1
  59. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),B=require("class-variance-authority"),N=require("lucide-react"),q=require("react"),O=require("../tdp-link.cjs"),b=require("../../ui/breadcrumb.cjs"),A=require("../../ui/button.cjs"),h=require("../../ui/dropdown-menu.cjs"),m=require("../../ui/sheet.cjs"),x=require("../../ui/tooltip.cjs"),s=require("../../../lib/utils.cjs");function P(r){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const i in r)if(i!=="default"){const o=Object.getOwnPropertyDescriptor(r,i);Object.defineProperty(a,i,o.get?o:{enumerable:!0,get:()=>r[i]})}}return a.default=r,Object.freeze(a)}const k=P(q),S=B.cva("flex items-center justify-center rounded-lg transition-colors duration-150",{variants:{active:{true:"bg-primary/10",false:"bg-transparent"},compact:{true:"w-9 h-9 hover:bg-muted",false:"w-8 h-8"}},defaultVariants:{active:!1,compact:!0}});function D({appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:c,backToPlatformPath:u,onBackToPlatform:f,userMenu:p,compact:l,onAfterNavClick:y}){return e.jsxs(x.TooltipProvider,{children:[e.jsx("div",{className:s.cn("shrink-0 border-b border-sidebar-border",l?"flex justify-center py-2":"flex px-3 py-2.5"),children:e.jsxs(h.DropdownMenu,{children:[e.jsx(h.DropdownMenuTrigger,{asChild:!0,children:e.jsxs("button",{type:"button",className:s.cn("cursor-pointer bg-transparent border-none p-0",!l&&"flex items-center gap-3 w-full text-left"),children:[e.jsx("span",{className:s.cn("flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0",l?"w-9 h-9 text-[11px]":"w-8 h-8 text-[10px]"),children:i??r}),!l&&e.jsx("span",{className:"text-sm font-semibold text-foreground truncate leading-snug",children:a??r})]})}),e.jsxs(h.DropdownMenuContent,{side:"right",align:"start",className:"min-w-[220px]",children:[e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2.5 cursor-pointer",onClick:c,role:"button",tabIndex:0,onKeyDown:d=>{d.key==="Enter"&&c?.()},children:[e.jsx("div",{className:"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0",children:e.jsx("span",{className:"text-[10px] font-bold text-foreground",children:i??r})}),e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx("span",{className:"text-sm font-semibold text-foreground truncate",children:a??r}),o&&e.jsx("span",{className:"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5",children:o})]})]}),e.jsx(h.DropdownMenuSeparator,{}),e.jsx(h.DropdownMenuItem,{className:"gap-2.5 p-0",asChild:!0,children:u?e.jsxs(O.TDPLink,{path:u,navigationOptions:{newTab:!1},className:"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline",children:[e.jsx(N.ArrowLeft,{className:"w-4 h-4 text-muted-foreground"}),"Back to TDP Platform"]}):e.jsxs("button",{type:"button",className:"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer",onClick:f,children:[e.jsx(N.ArrowLeft,{className:"w-4 h-4 text-muted-foreground"}),"Back to TDP Platform"]})})]})]})}),e.jsx("div",{className:s.cn("flex-1 min-h-0",l?"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto":"flex flex-col py-2 overflow-y-auto"),children:t.map((d,j)=>e.jsxs(k.Fragment,{children:[j>0&&e.jsx("div",{className:s.cn("border-t border-sidebar-border",l?"w-8 my-2":"mx-3 my-1")}),!l&&d.label&&e.jsx("span",{className:"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold",children:d.label}),e.jsx("div",{className:s.cn("flex flex-col",l?"items-center gap-3 w-full":"gap-0.5"),children:d.pages.map(n=>{const g=n.icon,v=g?e.jsx(g,{className:s.cn("w-5 h-5",n.isActive?"text-primary":"text-muted-foreground")}):e.jsx("div",{className:s.cn("w-2 h-2 rounded-full",n.isActive?"bg-primary":"bg-muted-foreground/40")}),w=()=>{n.onClick?.(),y?.()};return l?e.jsxs(x.Tooltip,{children:[e.jsx(x.TooltipTrigger,{asChild:!0,children:e.jsxs("button",{type:"button",className:"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full",onClick:w,children:[e.jsx("div",{className:s.cn(S({active:n.isActive??!1,compact:!0})),children:v}),e.jsx("span",{className:s.cn("text-[10px] font-medium leading-tight text-center",n.isActive?"text-foreground font-semibold":"text-muted-foreground"),children:n.label})]})}),e.jsx(x.TooltipContent,{side:"right",children:n.label})]},n.id):e.jsxs("button",{type:"button",className:s.cn("flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1",n.isActive?"bg-sidebar-accent text-sidebar-foreground font-medium":"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground"),onClick:w,children:[e.jsx("div",{className:s.cn(S({active:n.isActive??!1,compact:!1})),children:v}),e.jsx("span",{children:n.label})]},n.id)})})]},`${j}-${d.label??""}`))}),p&&e.jsx("div",{className:s.cn("shrink-0 border-t border-sidebar-border",l?"flex flex-col items-center py-2":"p-2"),children:p})]})}function M(r){return e.jsx("nav",{"data-slot":"data-app-sidebar-rail","aria-label":"Application navigation",className:"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50",children:e.jsx(D,{compact:!0,...r})})}function L({breadcrumbs:r=[],onHelpClick:a,headerActions:i,mobileTrigger:o}){return e.jsxs("div",{"data-slot":"data-app-top-nav",className:"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2",children:[o,e.jsx(b.Breadcrumb,{className:"flex-1 min-w-0",children:e.jsx(b.BreadcrumbList,{children:r.map((t,c)=>{const u=c===r.length-1,f=!u&&(!!t.href||!!t.onClick);return e.jsxs(k.Fragment,{children:[c>0&&e.jsx(b.BreadcrumbSeparator,{children:"/"}),e.jsx(b.BreadcrumbItem,{children:u?e.jsx(b.BreadcrumbPage,{children:t.label}):f&&t.href?e.jsx(b.BreadcrumbLink,{href:t.href,children:t.label}):f&&t.onClick?e.jsx("button",{type:"button",className:"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal",onClick:t.onClick,children:t.label}):e.jsx("span",{className:"text-[13px] text-muted-foreground",children:t.label})})]},`${t.label}-${c}`)})})}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[i,a&&e.jsx(x.TooltipProvider,{children:e.jsxs(x.Tooltip,{children:[e.jsx(x.TooltipTrigger,{asChild:!0,children:e.jsx(A.Button,{variant:"ghost",size:"icon",className:"w-7 h-7 text-muted-foreground",onClick:a,"aria-label":"Help",children:e.jsx(N.HelpCircle,{className:"w-4 h-4"})})}),e.jsx(x.TooltipContent,{side:"bottom",children:"Help"})]})})]})]})}function z({appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:c,backToPlatformPath:u,onBackToPlatform:f,userMenu:p,breadcrumbs:l=[],onHelpClick:y,headerActions:d,sidebarPanel:j,showNavRail:n=!0,children:g,className:v}){const[w,C]=k.useState(!1),T={appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:c,backToPlatformPath:u,onBackToPlatform:f,userMenu:p};return e.jsx(m.Sheet,{open:w,onOpenChange:C,children:e.jsxs("div",{"data-slot":"data-app-shell",className:s.cn("flex flex-row w-full h-screen overflow-hidden",v),children:[n&&e.jsx(M,{...T}),e.jsxs(m.SheetContent,{side:"left",showCloseButton:!1,className:"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col",children:[e.jsx(m.SheetTitle,{className:"sr-only",children:"Navigation"}),e.jsx(m.SheetDescription,{className:"sr-only",children:"Application navigation menu"}),e.jsx("nav",{"aria-label":"Application navigation",className:"flex flex-col h-full",children:e.jsx(D,{compact:!1,onAfterNavClick:()=>C(!1),...T})})]}),e.jsxs("div",{className:"flex flex-1 flex-col min-w-0 overflow-hidden",children:[e.jsx(L,{breadcrumbs:l,onHelpClick:y,headerActions:d,mobileTrigger:e.jsx(m.SheetTrigger,{asChild:!0,children:e.jsx(A.Button,{variant:"ghost",size:"icon","aria-label":"Open navigation menu",className:"md:hidden w-7 h-7 shrink-0 text-muted-foreground",children:e.jsx(N.Menu,{className:"w-4 h-4"})})})}),e.jsxs("div",{className:"flex flex-1 min-h-0 overflow-hidden",children:[j,e.jsx("main",{"data-slot":"data-app-shell-content",className:"flex-1 overflow-auto bg-background",children:g})]})]})]})})}exports.DataAppShell=z;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),B=require("class-variance-authority"),N=require("lucide-react"),q=require("react"),O=require("../tdp-link.cjs"),b=require("../../ui/breadcrumb.cjs"),A=require("../../ui/button.cjs"),h=require("../../ui/dropdown-menu.cjs"),m=require("../../ui/sheet.cjs"),x=require("../../ui/tooltip.cjs"),s=require("../../../lib/utils.cjs");function P(r){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const i in r)if(i!=="default"){const o=Object.getOwnPropertyDescriptor(r,i);Object.defineProperty(a,i,o.get?o:{enumerable:!0,get:()=>r[i]})}}return a.default=r,Object.freeze(a)}const k=P(q),S=B.cva("flex items-center justify-center rounded-lg transition-colors duration-150",{variants:{active:{true:"bg-primary/10",false:"bg-transparent"},compact:{true:"w-9 h-9 hover:bg-accent",false:"w-8 h-8"}},defaultVariants:{active:!1,compact:!0}});function D({appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:c,backToPlatformPath:u,onBackToPlatform:f,userMenu:p,compact:l,onAfterNavClick:y}){return e.jsxs(x.TooltipProvider,{children:[e.jsx("div",{className:s.cn("shrink-0 border-b border-sidebar-border",l?"flex justify-center py-2":"flex px-3 py-2.5"),children:e.jsxs(h.DropdownMenu,{children:[e.jsx(h.DropdownMenuTrigger,{asChild:!0,children:e.jsxs("button",{type:"button",className:s.cn("cursor-pointer bg-transparent border-none p-0",!l&&"flex items-center gap-3 w-full text-left"),children:[e.jsx("span",{className:s.cn("flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0",l?"w-9 h-9 text-[11px]":"w-8 h-8 text-[10px]"),children:i??r}),!l&&e.jsx("span",{className:"text-sm font-semibold text-foreground truncate leading-snug",children:a??r})]})}),e.jsxs(h.DropdownMenuContent,{side:"right",align:"start",className:"min-w-[220px]",children:[e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2.5 cursor-pointer",onClick:c,role:"button",tabIndex:0,onKeyDown:d=>{d.key==="Enter"&&c?.()},children:[e.jsx("div",{className:"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0",children:e.jsx("span",{className:"text-[10px] font-bold text-foreground",children:i??r})}),e.jsxs("div",{className:"flex flex-col min-w-0",children:[e.jsx("span",{className:"text-sm font-semibold text-foreground truncate",children:a??r}),o&&e.jsx("span",{className:"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5",children:o})]})]}),e.jsx(h.DropdownMenuSeparator,{}),e.jsx(h.DropdownMenuItem,{className:"gap-2.5 p-0",asChild:!0,children:u?e.jsxs(O.TDPLink,{path:u,navigationOptions:{newTab:!1},className:"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline",children:[e.jsx(N.ArrowLeft,{className:"w-4 h-4 text-muted-foreground"}),"Back to TDP Platform"]}):e.jsxs("button",{type:"button",className:"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer",onClick:f,children:[e.jsx(N.ArrowLeft,{className:"w-4 h-4 text-muted-foreground"}),"Back to TDP Platform"]})})]})]})}),e.jsx("div",{className:s.cn("flex-1 min-h-0",l?"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto":"flex flex-col py-2 overflow-y-auto"),children:t.map((d,j)=>e.jsxs(k.Fragment,{children:[j>0&&e.jsx("div",{className:s.cn("border-t border-sidebar-border",l?"w-8 my-2":"mx-3 my-1")}),!l&&d.label&&e.jsx("span",{className:"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold",children:d.label}),e.jsx("div",{className:s.cn("flex flex-col",l?"items-center gap-3 w-full":"gap-0.5"),children:d.pages.map(n=>{const g=n.icon,v=g?e.jsx(g,{className:s.cn("w-5 h-5",n.isActive?"text-primary":"text-muted-foreground")}):e.jsx("div",{className:s.cn("w-2 h-2 rounded-full",n.isActive?"bg-primary":"bg-muted-foreground/40")}),w=()=>{n.onClick?.(),y?.()};return l?e.jsxs(x.Tooltip,{children:[e.jsx(x.TooltipTrigger,{asChild:!0,children:e.jsxs("button",{type:"button",className:"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full",onClick:w,children:[e.jsx("div",{className:s.cn(S({active:n.isActive??!1,compact:!0})),children:v}),e.jsx("span",{className:s.cn("text-[10px] font-medium leading-tight text-center",n.isActive?"text-foreground font-semibold":"text-muted-foreground"),children:n.label})]})}),e.jsx(x.TooltipContent,{side:"right",children:n.label})]},n.id):e.jsxs("button",{type:"button",className:s.cn("flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1",n.isActive?"bg-sidebar-accent text-sidebar-foreground font-medium":"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground"),onClick:w,children:[e.jsx("div",{className:s.cn(S({active:n.isActive??!1,compact:!1})),children:v}),e.jsx("span",{children:n.label})]},n.id)})})]},`${j}-${d.label??""}`))}),p&&e.jsx("div",{className:s.cn("shrink-0 border-t border-sidebar-border",l?"flex flex-col items-center py-2":"p-2"),children:p})]})}function M(r){return e.jsx("nav",{"data-slot":"data-app-sidebar-rail","aria-label":"Application navigation",className:"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50",children:e.jsx(D,{compact:!0,...r})})}function L({breadcrumbs:r=[],onHelpClick:a,headerActions:i,mobileTrigger:o}){return e.jsxs("div",{"data-slot":"data-app-top-nav",className:"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2",children:[o,e.jsx(b.Breadcrumb,{className:"flex-1 min-w-0",children:e.jsx(b.BreadcrumbList,{children:r.map((t,c)=>{const u=c===r.length-1,f=!u&&(!!t.href||!!t.onClick);return e.jsxs(k.Fragment,{children:[c>0&&e.jsx(b.BreadcrumbSeparator,{children:"/"}),e.jsx(b.BreadcrumbItem,{children:u?e.jsx(b.BreadcrumbPage,{children:t.label}):f&&t.href?e.jsx(b.BreadcrumbLink,{href:t.href,children:t.label}):f&&t.onClick?e.jsx("button",{type:"button",className:"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal",onClick:t.onClick,children:t.label}):e.jsx("span",{className:"text-[13px] text-muted-foreground",children:t.label})})]},`${t.label}-${c}`)})})}),e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[i,a&&e.jsx(x.TooltipProvider,{children:e.jsxs(x.Tooltip,{children:[e.jsx(x.TooltipTrigger,{asChild:!0,children:e.jsx(A.Button,{variant:"ghost",size:"icon",className:"w-7 h-7 text-muted-foreground",onClick:a,"aria-label":"Help",children:e.jsx(N.HelpCircle,{className:"w-4 h-4"})})}),e.jsx(x.TooltipContent,{side:"bottom",children:"Help"})]})})]})]})}function z({appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:c,backToPlatformPath:u,onBackToPlatform:f,userMenu:p,breadcrumbs:l=[],onHelpClick:y,headerActions:d,sidebarPanel:j,showNavRail:n=!0,children:g,className:v}){const[w,C]=k.useState(!1),T={appName:r,appFullName:a,appIcon:i,version:o,navGroups:t,onAppNameClick:c,backToPlatformPath:u,onBackToPlatform:f,userMenu:p};return e.jsx(m.Sheet,{open:w,onOpenChange:C,children:e.jsxs("div",{"data-slot":"data-app-shell",className:s.cn("flex flex-row w-full h-screen overflow-hidden",v),children:[n&&e.jsx(M,{...T}),e.jsxs(m.SheetContent,{side:"left",showCloseButton:!1,className:"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col",children:[e.jsx(m.SheetTitle,{className:"sr-only",children:"Navigation"}),e.jsx(m.SheetDescription,{className:"sr-only",children:"Application navigation menu"}),e.jsx("nav",{"aria-label":"Application navigation",className:"flex flex-col h-full",children:e.jsx(D,{compact:!1,onAfterNavClick:()=>C(!1),...T})})]}),e.jsxs("div",{className:"flex flex-1 flex-col min-w-0 overflow-hidden",children:[e.jsx(L,{breadcrumbs:l,onHelpClick:y,headerActions:d,mobileTrigger:e.jsx(m.SheetTrigger,{asChild:!0,children:e.jsx(A.Button,{variant:"ghost",size:"icon","aria-label":"Open navigation menu",className:"md:hidden w-7 h-7 shrink-0 text-muted-foreground",children:e.jsx(N.Menu,{className:"w-4 h-4"})})})}),e.jsxs("div",{className:"flex flex-1 min-h-0 overflow-hidden",children:[j,e.jsx("main",{"data-slot":"data-app-shell-content",className:"flex-1 overflow-auto bg-background",children:g})]})]})]})})}exports.DataAppShell=z;
2
2
  //# sourceMappingURL=DataAppShell.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataAppShell.cjs","sources":["../../../../src/components/composed/DataAppShell/DataAppShell.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport {\n ArrowLeft,\n HelpCircle,\n Menu,\n type LucideIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { TDPLink } from \"@/components/composed/tdp-link\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NavPage {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Lucide icon or custom React SVG component */\n icon?: LucideIcon | React.FC<React.SVGProps<SVGSVGElement>>;\n /** Whether this page is currently active */\n isActive?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport interface NavGroup {\n /** Optional group label shown as a section header in expanded nav */\n label?: string;\n /** Page entries in this group */\n pages: NavPage[];\n}\n\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string;\n /** If provided, renders as a link */\n href?: string;\n /** Click handler (used when no href is provided) */\n onClick?: () => void;\n}\n\nexport interface DataAppShellProps {\n // -- Sidebar --\n /** Application name/abbreviation shown in the logo button */\n appName: string;\n /** Full application name shown in the app dropdown and mobile nav header */\n appFullName?: string;\n /** Custom icon element shown in the logo area */\n appIcon?: React.ReactNode;\n /** Optional version string shown below the app name/icon in the sidebar header */\n version?: string;\n /** Navigation groups; each group contains one or more pages */\n navGroups: NavGroup[];\n /** Callback when the app name / icon is clicked in the dropdown */\n onAppNameClick?: () => void;\n /** TDP path to navigate to when \"Back to TDP Platform\" is clicked (uses TDPLink — requires TdpNavigationProvider) */\n backToPlatformPath?: string;\n /** Fallback callback when \"Back to TDP Platform\" is clicked and no backToPlatformPath is set */\n onBackToPlatform?: () => void;\n /** Slot rendered at the bottom of the sidebar (e.g. user avatar + menu) */\n userMenu?: React.ReactNode;\n\n // -- Top nav --\n /** Breadcrumb items from root to current page */\n breadcrumbs?: BreadcrumbItemConfig[];\n /** Callback when the help button is clicked; omit to hide the button */\n onHelpClick?: () => void;\n /** Slot for right-side actions in the top nav (e.g. data count pills, next button) */\n headerActions?: React.ReactNode;\n\n // -- Shell --\n /** Slot rendered between the icon rail and the content (e.g. WorkflowPanel) */\n sidebarPanel?: React.ReactNode;\n /** Show the desktop icon nav rail. Set false to reclaim width when the panel is collapsed. */\n showNavRail?: boolean; // default true\n /** Main content area */\n children: React.ReactNode;\n /** Additional className for the root container */\n className?: string;\n}\n\n// =============================================================================\n// Sidebar shared body (used by desktop rail + mobile Sheet)\n// =============================================================================\n\ninterface SidebarBodyProps\n extends Pick<\n DataAppShellProps,\n | \"appName\"\n | \"appFullName\"\n | \"appIcon\"\n | \"version\"\n | \"navGroups\"\n | \"onAppNameClick\"\n | \"backToPlatformPath\"\n | \"onBackToPlatform\"\n | \"userMenu\"\n > {\n /**\n * compact=true → narrow icon rail (60px): icons + tiny labels stacked, tooltips on hover\n * compact=false → expanded mobile sheet (220px): icon + label side-by-side rows\n */\n compact: boolean;\n /** Called after a nav page item is clicked — used by mobile sheet to close itself */\n onAfterNavClick?: () => void;\n}\n\nconst pageIconVariants = cva(\n \"flex items-center justify-center rounded-lg transition-colors duration-150\",\n {\n variants: {\n active: {\n true: \"bg-primary/10\",\n false: \"bg-transparent\",\n },\n compact: {\n true: \"w-9 h-9 hover:bg-muted\",\n false: \"w-8 h-8\",\n },\n },\n defaultVariants: { active: false, compact: true },\n }\n);\n\nfunction SidebarBody({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n compact,\n onAfterNavClick,\n}: SidebarBodyProps) {\n return (\n <TooltipProvider>\n {/* ── Header: app icon / name + version ──────────────────────────────── */}\n <div\n className={cn(\n \"shrink-0 border-b border-sidebar-border\",\n compact ? \"flex justify-center py-2\" : \"flex px-3 py-2.5\"\n )}\n >\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"cursor-pointer bg-transparent border-none p-0\",\n !compact && \"flex items-center gap-3 w-full text-left\"\n )}\n >\n {/* Icon */}\n <span\n className={cn(\n \"flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0\",\n compact ? \"w-9 h-9 text-[11px]\" : \"w-8 h-8 text-[10px]\"\n )}\n >\n {appIcon ?? appName}\n </span>\n\n {/* Name (expanded only — no version here) */}\n {!compact && (\n <span className=\"text-sm font-semibold text-foreground truncate leading-snug\">\n {appFullName ?? appName}\n </span>\n )}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"min-w-[220px]\">\n <div\n className=\"flex items-center gap-3 px-3 py-2.5 cursor-pointer\"\n onClick={onAppNameClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onAppNameClick?.();\n }}\n >\n <div className=\"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0\">\n <span className=\"text-[10px] font-bold text-foreground\">\n {appIcon ?? appName}\n </span>\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {appFullName ?? appName}\n </span>\n {version && (\n <span className=\"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5\">\n {version}\n </span>\n )}\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"gap-2.5 p-0\" asChild>\n {backToPlatformPath ? (\n <TDPLink\n path={backToPlatformPath}\n navigationOptions={{ newTab: false }}\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline\"\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </TDPLink>\n ) : (\n <button\n type=\"button\"\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer\"\n onClick={onBackToPlatform}\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </button>\n )}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* ── Nav groups ──────────────────────────────────────────────────────── */}\n <div\n className={cn(\n \"flex-1 min-h-0\",\n compact\n ? \"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto\"\n : \"flex flex-col py-2 overflow-y-auto\"\n )}\n >\n {navGroups.map((group, groupIndex) => (\n <React.Fragment key={`${groupIndex}-${group.label ?? \"\"}`}>\n {groupIndex > 0 && (\n <div\n className={cn(\n \"border-t border-sidebar-border\",\n compact ? \"w-8 my-2\" : \"mx-3 my-1\"\n )}\n />\n )}\n {!compact && group.label && (\n <span className=\"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold\">\n {group.label}\n </span>\n )}\n <div\n className={cn(\n \"flex flex-col\",\n compact ? \"items-center gap-3 w-full\" : \"gap-0.5\"\n )}\n >\n {group.pages.map((page) => {\n const Icon = page.icon;\n const iconEl = Icon ? (\n <Icon\n className={cn(\n \"w-5 h-5\",\n page.isActive ? \"text-primary\" : \"text-muted-foreground\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"w-2 h-2 rounded-full\",\n page.isActive ? \"bg-primary\" : \"bg-muted-foreground/40\"\n )}\n />\n );\n\n const handleClick = () => {\n page.onClick?.();\n onAfterNavClick?.();\n };\n\n if (compact) {\n return (\n <Tooltip key={page.id}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full\"\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: true }))}>\n {iconEl}\n </div>\n <span\n className={cn(\n \"text-[10px] font-medium leading-tight text-center\",\n page.isActive\n ? \"text-foreground font-semibold\"\n : \"text-muted-foreground\"\n )}\n >\n {page.label}\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{page.label}</TooltipContent>\n </Tooltip>\n );\n }\n\n // Expanded (mobile) row\n return (\n <button\n key={page.id}\n type=\"button\"\n className={cn(\n \"flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1\",\n page.isActive\n ? \"bg-sidebar-accent text-sidebar-foreground font-medium\"\n : \"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground\"\n )}\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: false }))}>\n {iconEl}\n </div>\n <span>{page.label}</span>\n </button>\n );\n })}\n </div>\n </React.Fragment>\n ))}\n </div>\n\n {/* ── Bottom: user menu slot ──────────────────────────────────────────── */}\n {userMenu && (\n <div\n className={cn(\n \"shrink-0 border-t border-sidebar-border\",\n compact ? \"flex flex-col items-center py-2\" : \"p-2\"\n )}\n >\n {userMenu}\n </div>\n )}\n </TooltipProvider>\n );\n}\n\n// =============================================================================\n// Icon rail sidebar (desktop only — hidden on mobile)\n// =============================================================================\n\nfunction IconRailSidebar(props: Omit<SidebarBodyProps, \"compact\" | \"onAfterNavClick\">) {\n return (\n <nav\n data-slot=\"data-app-sidebar-rail\"\n aria-label=\"Application navigation\"\n className=\"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50\"\n >\n <SidebarBody compact {...props} />\n </nav>\n );\n}\n\n// =============================================================================\n// Top nav\n// =============================================================================\n\nfunction TopNav({\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n mobileTrigger,\n}: {\n breadcrumbs?: BreadcrumbItemConfig[];\n onHelpClick?: () => void;\n headerActions?: React.ReactNode;\n mobileTrigger?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"data-app-top-nav\"\n className=\"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2\"\n >\n {/* Mobile hamburger (hidden on md+) */}\n {mobileTrigger}\n\n {/* Left: Breadcrumbs */}\n <Breadcrumb className=\"flex-1 min-w-0\">\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const isClickable = !isLast && (!!item.href || !!item.onClick);\n return (\n <React.Fragment key={`${item.label}-${index}`}>\n {index > 0 && <BreadcrumbSeparator>/</BreadcrumbSeparator>}\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : isClickable && item.href ? (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n ) : isClickable && item.onClick ? (\n <button\n type=\"button\"\n className=\"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal\"\n onClick={item.onClick}\n >\n {item.label}\n </button>\n ) : (\n <span className=\"text-[13px] text-muted-foreground\">{item.label}</span>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n\n {/* Right: header actions + help */}\n <div className=\"flex items-center gap-2 shrink-0\">\n {headerActions}\n\n {onHelpClick && (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"w-7 h-7 text-muted-foreground\"\n onClick={onHelpClick}\n aria-label=\"Help\"\n >\n <HelpCircle className=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">Help</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShell\n// =============================================================================\n\nfunction DataAppShell({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n sidebarPanel,\n showNavRail = true,\n children,\n className,\n}: DataAppShellProps) {\n const [mobileNavOpen, setMobileNavOpen] = React.useState(false);\n\n const sidebarProps = {\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n };\n\n return (\n <Sheet open={mobileNavOpen} onOpenChange={setMobileNavOpen}>\n <div\n data-slot=\"data-app-shell\"\n className={cn(\"flex flex-row w-full h-screen overflow-hidden\", className)}\n >\n {/* Desktop icon rail (hidden on mobile, or when showNavRail is false) */}\n {showNavRail && <IconRailSidebar {...sidebarProps} />}\n\n {/* Mobile sidebar Sheet */}\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col\"\n >\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SheetDescription className=\"sr-only\">\n Application navigation menu\n </SheetDescription>\n <nav aria-label=\"Application navigation\" className=\"flex flex-col h-full\">\n <SidebarBody\n compact={false}\n onAfterNavClick={() => setMobileNavOpen(false)}\n {...sidebarProps}\n />\n </nav>\n </SheetContent>\n\n {/* Right: top nav + panel + content */}\n <div className=\"flex flex-1 flex-col min-w-0 overflow-hidden\">\n <TopNav\n breadcrumbs={breadcrumbs}\n onHelpClick={onHelpClick}\n headerActions={headerActions}\n mobileTrigger={\n <SheetTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Open navigation menu\"\n className=\"md:hidden w-7 h-7 shrink-0 text-muted-foreground\"\n >\n <Menu className=\"w-4 h-4\" />\n </Button>\n </SheetTrigger>\n }\n />\n\n <div className=\"flex flex-1 min-h-0 overflow-hidden\">\n {/* Sidebar panel slot (e.g. WorkflowPanel) */}\n {sidebarPanel}\n\n {/* Content area */}\n <main\n data-slot=\"data-app-shell-content\"\n className=\"flex-1 overflow-auto bg-background\"\n >\n {children}\n </main>\n </div>\n </div>\n </div>\n </Sheet>\n );\n}\n\nexport default DataAppShell;\nexport { DataAppShell };\n"],"names":["pageIconVariants","cva","SidebarBody","appName","appFullName","appIcon","version","navGroups","onAppNameClick","backToPlatformPath","onBackToPlatform","userMenu","compact","onAfterNavClick","TooltipProvider","jsx","cn","DropdownMenu","DropdownMenuTrigger","jsxs","DropdownMenuContent","e","DropdownMenuSeparator","DropdownMenuItem","TDPLink","ArrowLeft","group","groupIndex","React","page","Icon","iconEl","handleClick","Tooltip","TooltipTrigger","TooltipContent","IconRailSidebar","props","TopNav","breadcrumbs","onHelpClick","headerActions","mobileTrigger","Breadcrumb","BreadcrumbList","item","index","isLast","isClickable","BreadcrumbSeparator","BreadcrumbItem","BreadcrumbPage","BreadcrumbLink","Button","HelpCircle","DataAppShell","sidebarPanel","showNavRail","children","className","mobileNavOpen","setMobileNavOpen","sidebarProps","Sheet","SheetContent","SheetTitle","SheetDescription","SheetTrigger","Menu"],"mappings":"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"}
1
+ {"version":3,"file":"DataAppShell.cjs","sources":["../../../../src/components/composed/DataAppShell/DataAppShell.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport {\n ArrowLeft,\n HelpCircle,\n Menu,\n type LucideIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { TDPLink } from \"@/components/composed/tdp-link\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NavPage {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Lucide icon or custom React SVG component */\n icon?: LucideIcon | React.FC<React.SVGProps<SVGSVGElement>>;\n /** Whether this page is currently active */\n isActive?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport interface NavGroup {\n /** Optional group label shown as a section header in expanded nav */\n label?: string;\n /** Page entries in this group */\n pages: NavPage[];\n}\n\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string;\n /** If provided, renders as a link */\n href?: string;\n /** Click handler (used when no href is provided) */\n onClick?: () => void;\n}\n\nexport interface DataAppShellProps {\n // -- Sidebar --\n /** Application name/abbreviation shown in the logo button */\n appName: string;\n /** Full application name shown in the app dropdown and mobile nav header */\n appFullName?: string;\n /** Custom icon element shown in the logo area */\n appIcon?: React.ReactNode;\n /** Optional version string shown below the app name/icon in the sidebar header */\n version?: string;\n /** Navigation groups; each group contains one or more pages */\n navGroups: NavGroup[];\n /** Callback when the app name / icon is clicked in the dropdown */\n onAppNameClick?: () => void;\n /** TDP path to navigate to when \"Back to TDP Platform\" is clicked (uses TDPLink — requires TdpNavigationProvider) */\n backToPlatformPath?: string;\n /** Fallback callback when \"Back to TDP Platform\" is clicked and no backToPlatformPath is set */\n onBackToPlatform?: () => void;\n /** Slot rendered at the bottom of the sidebar (e.g. user avatar + menu) */\n userMenu?: React.ReactNode;\n\n // -- Top nav --\n /** Breadcrumb items from root to current page */\n breadcrumbs?: BreadcrumbItemConfig[];\n /** Callback when the help button is clicked; omit to hide the button */\n onHelpClick?: () => void;\n /** Slot for right-side actions in the top nav (e.g. data count pills, next button) */\n headerActions?: React.ReactNode;\n\n // -- Shell --\n /** Slot rendered between the icon rail and the content (e.g. WorkflowPanel) */\n sidebarPanel?: React.ReactNode;\n /** Show the desktop icon nav rail. Set false to reclaim width when the panel is collapsed. */\n showNavRail?: boolean; // default true\n /** Main content area */\n children: React.ReactNode;\n /** Additional className for the root container */\n className?: string;\n}\n\n// =============================================================================\n// Sidebar shared body (used by desktop rail + mobile Sheet)\n// =============================================================================\n\ninterface SidebarBodyProps\n extends Pick<\n DataAppShellProps,\n | \"appName\"\n | \"appFullName\"\n | \"appIcon\"\n | \"version\"\n | \"navGroups\"\n | \"onAppNameClick\"\n | \"backToPlatformPath\"\n | \"onBackToPlatform\"\n | \"userMenu\"\n > {\n /**\n * compact=true → narrow icon rail (60px): icons + tiny labels stacked, tooltips on hover\n * compact=false → expanded mobile sheet (220px): icon + label side-by-side rows\n */\n compact: boolean;\n /** Called after a nav page item is clicked — used by mobile sheet to close itself */\n onAfterNavClick?: () => void;\n}\n\nconst pageIconVariants = cva(\n \"flex items-center justify-center rounded-lg transition-colors duration-150\",\n {\n variants: {\n active: {\n true: \"bg-primary/10\",\n false: \"bg-transparent\",\n },\n compact: {\n true: \"w-9 h-9 hover:bg-accent\",\n false: \"w-8 h-8\",\n },\n },\n defaultVariants: { active: false, compact: true },\n }\n);\n\nfunction SidebarBody({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n compact,\n onAfterNavClick,\n}: SidebarBodyProps) {\n return (\n <TooltipProvider>\n {/* ── Header: app icon / name + version ──────────────────────────────── */}\n <div\n className={cn(\n \"shrink-0 border-b border-sidebar-border\",\n compact ? \"flex justify-center py-2\" : \"flex px-3 py-2.5\"\n )}\n >\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"cursor-pointer bg-transparent border-none p-0\",\n !compact && \"flex items-center gap-3 w-full text-left\"\n )}\n >\n {/* Icon */}\n <span\n className={cn(\n \"flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0\",\n compact ? \"w-9 h-9 text-[11px]\" : \"w-8 h-8 text-[10px]\"\n )}\n >\n {appIcon ?? appName}\n </span>\n\n {/* Name (expanded only — no version here) */}\n {!compact && (\n <span className=\"text-sm font-semibold text-foreground truncate leading-snug\">\n {appFullName ?? appName}\n </span>\n )}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"min-w-[220px]\">\n <div\n className=\"flex items-center gap-3 px-3 py-2.5 cursor-pointer\"\n onClick={onAppNameClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onAppNameClick?.();\n }}\n >\n <div className=\"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0\">\n <span className=\"text-[10px] font-bold text-foreground\">\n {appIcon ?? appName}\n </span>\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {appFullName ?? appName}\n </span>\n {version && (\n <span className=\"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5\">\n {version}\n </span>\n )}\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"gap-2.5 p-0\" asChild>\n {backToPlatformPath ? (\n <TDPLink\n path={backToPlatformPath}\n navigationOptions={{ newTab: false }}\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline\"\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </TDPLink>\n ) : (\n <button\n type=\"button\"\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer\"\n onClick={onBackToPlatform}\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </button>\n )}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* ── Nav groups ──────────────────────────────────────────────────────── */}\n <div\n className={cn(\n \"flex-1 min-h-0\",\n compact\n ? \"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto\"\n : \"flex flex-col py-2 overflow-y-auto\"\n )}\n >\n {navGroups.map((group, groupIndex) => (\n <React.Fragment key={`${groupIndex}-${group.label ?? \"\"}`}>\n {groupIndex > 0 && (\n <div\n className={cn(\n \"border-t border-sidebar-border\",\n compact ? \"w-8 my-2\" : \"mx-3 my-1\"\n )}\n />\n )}\n {!compact && group.label && (\n <span className=\"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold\">\n {group.label}\n </span>\n )}\n <div\n className={cn(\n \"flex flex-col\",\n compact ? \"items-center gap-3 w-full\" : \"gap-0.5\"\n )}\n >\n {group.pages.map((page) => {\n const Icon = page.icon;\n const iconEl = Icon ? (\n <Icon\n className={cn(\n \"w-5 h-5\",\n page.isActive ? \"text-primary\" : \"text-muted-foreground\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"w-2 h-2 rounded-full\",\n page.isActive ? \"bg-primary\" : \"bg-muted-foreground/40\"\n )}\n />\n );\n\n const handleClick = () => {\n page.onClick?.();\n onAfterNavClick?.();\n };\n\n if (compact) {\n return (\n <Tooltip key={page.id}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full\"\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: true }))}>\n {iconEl}\n </div>\n <span\n className={cn(\n \"text-[10px] font-medium leading-tight text-center\",\n page.isActive\n ? \"text-foreground font-semibold\"\n : \"text-muted-foreground\"\n )}\n >\n {page.label}\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{page.label}</TooltipContent>\n </Tooltip>\n );\n }\n\n // Expanded (mobile) row\n return (\n <button\n key={page.id}\n type=\"button\"\n className={cn(\n \"flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1\",\n page.isActive\n ? \"bg-sidebar-accent text-sidebar-foreground font-medium\"\n : \"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground\"\n )}\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: false }))}>\n {iconEl}\n </div>\n <span>{page.label}</span>\n </button>\n );\n })}\n </div>\n </React.Fragment>\n ))}\n </div>\n\n {/* ── Bottom: user menu slot ──────────────────────────────────────────── */}\n {userMenu && (\n <div\n className={cn(\n \"shrink-0 border-t border-sidebar-border\",\n compact ? \"flex flex-col items-center py-2\" : \"p-2\"\n )}\n >\n {userMenu}\n </div>\n )}\n </TooltipProvider>\n );\n}\n\n// =============================================================================\n// Icon rail sidebar (desktop only — hidden on mobile)\n// =============================================================================\n\nfunction IconRailSidebar(props: Omit<SidebarBodyProps, \"compact\" | \"onAfterNavClick\">) {\n return (\n <nav\n data-slot=\"data-app-sidebar-rail\"\n aria-label=\"Application navigation\"\n className=\"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50\"\n >\n <SidebarBody compact {...props} />\n </nav>\n );\n}\n\n// =============================================================================\n// Top nav\n// =============================================================================\n\nfunction TopNav({\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n mobileTrigger,\n}: {\n breadcrumbs?: BreadcrumbItemConfig[];\n onHelpClick?: () => void;\n headerActions?: React.ReactNode;\n mobileTrigger?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"data-app-top-nav\"\n className=\"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2\"\n >\n {/* Mobile hamburger (hidden on md+) */}\n {mobileTrigger}\n\n {/* Left: Breadcrumbs */}\n <Breadcrumb className=\"flex-1 min-w-0\">\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const isClickable = !isLast && (!!item.href || !!item.onClick);\n return (\n <React.Fragment key={`${item.label}-${index}`}>\n {index > 0 && <BreadcrumbSeparator>/</BreadcrumbSeparator>}\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : isClickable && item.href ? (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n ) : isClickable && item.onClick ? (\n <button\n type=\"button\"\n className=\"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal\"\n onClick={item.onClick}\n >\n {item.label}\n </button>\n ) : (\n <span className=\"text-[13px] text-muted-foreground\">{item.label}</span>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n\n {/* Right: header actions + help */}\n <div className=\"flex items-center gap-2 shrink-0\">\n {headerActions}\n\n {onHelpClick && (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"w-7 h-7 text-muted-foreground\"\n onClick={onHelpClick}\n aria-label=\"Help\"\n >\n <HelpCircle className=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">Help</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShell\n// =============================================================================\n\nfunction DataAppShell({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n sidebarPanel,\n showNavRail = true,\n children,\n className,\n}: DataAppShellProps) {\n const [mobileNavOpen, setMobileNavOpen] = React.useState(false);\n\n const sidebarProps = {\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n };\n\n return (\n <Sheet open={mobileNavOpen} onOpenChange={setMobileNavOpen}>\n <div\n data-slot=\"data-app-shell\"\n className={cn(\"flex flex-row w-full h-screen overflow-hidden\", className)}\n >\n {/* Desktop icon rail (hidden on mobile, or when showNavRail is false) */}\n {showNavRail && <IconRailSidebar {...sidebarProps} />}\n\n {/* Mobile sidebar Sheet */}\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col\"\n >\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SheetDescription className=\"sr-only\">\n Application navigation menu\n </SheetDescription>\n <nav aria-label=\"Application navigation\" className=\"flex flex-col h-full\">\n <SidebarBody\n compact={false}\n onAfterNavClick={() => setMobileNavOpen(false)}\n {...sidebarProps}\n />\n </nav>\n </SheetContent>\n\n {/* Right: top nav + panel + content */}\n <div className=\"flex flex-1 flex-col min-w-0 overflow-hidden\">\n <TopNav\n breadcrumbs={breadcrumbs}\n onHelpClick={onHelpClick}\n headerActions={headerActions}\n mobileTrigger={\n <SheetTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Open navigation menu\"\n className=\"md:hidden w-7 h-7 shrink-0 text-muted-foreground\"\n >\n <Menu className=\"w-4 h-4\" />\n </Button>\n </SheetTrigger>\n }\n />\n\n <div className=\"flex flex-1 min-h-0 overflow-hidden\">\n {/* Sidebar panel slot (e.g. WorkflowPanel) */}\n {sidebarPanel}\n\n {/* Content area */}\n <main\n data-slot=\"data-app-shell-content\"\n className=\"flex-1 overflow-auto bg-background\"\n >\n {children}\n </main>\n </div>\n </div>\n </div>\n </Sheet>\n );\n}\n\nexport default DataAppShell;\nexport { DataAppShell };\n"],"names":["pageIconVariants","cva","SidebarBody","appName","appFullName","appIcon","version","navGroups","onAppNameClick","backToPlatformPath","onBackToPlatform","userMenu","compact","onAfterNavClick","TooltipProvider","jsx","cn","DropdownMenu","DropdownMenuTrigger","jsxs","DropdownMenuContent","e","DropdownMenuSeparator","DropdownMenuItem","TDPLink","ArrowLeft","group","groupIndex","React","page","Icon","iconEl","handleClick","Tooltip","TooltipTrigger","TooltipContent","IconRailSidebar","props","TopNav","breadcrumbs","onHelpClick","headerActions","mobileTrigger","Breadcrumb","BreadcrumbList","item","index","isLast","isClickable","BreadcrumbSeparator","BreadcrumbItem","BreadcrumbPage","BreadcrumbLink","Button","HelpCircle","DataAppShell","sidebarPanel","showNavRail","children","className","mobileNavOpen","setMobileNavOpen","sidebarProps","Sheet","SheetContent","SheetTitle","SheetDescription","SheetTrigger","Menu"],"mappings":"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"}
@@ -18,7 +18,7 @@ const C = M(
18
18
  false: "bg-transparent"
19
19
  },
20
20
  compact: {
21
- true: "w-9 h-9 hover:bg-muted",
21
+ true: "w-9 h-9 hover:bg-accent",
22
22
  false: "w-8 h-8"
23
23
  }
24
24
  },
@@ -1 +1 @@
1
- {"version":3,"file":"DataAppShell.js","sources":["../../../../src/components/composed/DataAppShell/DataAppShell.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport {\n ArrowLeft,\n HelpCircle,\n Menu,\n type LucideIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { TDPLink } from \"@/components/composed/tdp-link\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NavPage {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Lucide icon or custom React SVG component */\n icon?: LucideIcon | React.FC<React.SVGProps<SVGSVGElement>>;\n /** Whether this page is currently active */\n isActive?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport interface NavGroup {\n /** Optional group label shown as a section header in expanded nav */\n label?: string;\n /** Page entries in this group */\n pages: NavPage[];\n}\n\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string;\n /** If provided, renders as a link */\n href?: string;\n /** Click handler (used when no href is provided) */\n onClick?: () => void;\n}\n\nexport interface DataAppShellProps {\n // -- Sidebar --\n /** Application name/abbreviation shown in the logo button */\n appName: string;\n /** Full application name shown in the app dropdown and mobile nav header */\n appFullName?: string;\n /** Custom icon element shown in the logo area */\n appIcon?: React.ReactNode;\n /** Optional version string shown below the app name/icon in the sidebar header */\n version?: string;\n /** Navigation groups; each group contains one or more pages */\n navGroups: NavGroup[];\n /** Callback when the app name / icon is clicked in the dropdown */\n onAppNameClick?: () => void;\n /** TDP path to navigate to when \"Back to TDP Platform\" is clicked (uses TDPLink — requires TdpNavigationProvider) */\n backToPlatformPath?: string;\n /** Fallback callback when \"Back to TDP Platform\" is clicked and no backToPlatformPath is set */\n onBackToPlatform?: () => void;\n /** Slot rendered at the bottom of the sidebar (e.g. user avatar + menu) */\n userMenu?: React.ReactNode;\n\n // -- Top nav --\n /** Breadcrumb items from root to current page */\n breadcrumbs?: BreadcrumbItemConfig[];\n /** Callback when the help button is clicked; omit to hide the button */\n onHelpClick?: () => void;\n /** Slot for right-side actions in the top nav (e.g. data count pills, next button) */\n headerActions?: React.ReactNode;\n\n // -- Shell --\n /** Slot rendered between the icon rail and the content (e.g. WorkflowPanel) */\n sidebarPanel?: React.ReactNode;\n /** Show the desktop icon nav rail. Set false to reclaim width when the panel is collapsed. */\n showNavRail?: boolean; // default true\n /** Main content area */\n children: React.ReactNode;\n /** Additional className for the root container */\n className?: string;\n}\n\n// =============================================================================\n// Sidebar shared body (used by desktop rail + mobile Sheet)\n// =============================================================================\n\ninterface SidebarBodyProps\n extends Pick<\n DataAppShellProps,\n | \"appName\"\n | \"appFullName\"\n | \"appIcon\"\n | \"version\"\n | \"navGroups\"\n | \"onAppNameClick\"\n | \"backToPlatformPath\"\n | \"onBackToPlatform\"\n | \"userMenu\"\n > {\n /**\n * compact=true → narrow icon rail (60px): icons + tiny labels stacked, tooltips on hover\n * compact=false → expanded mobile sheet (220px): icon + label side-by-side rows\n */\n compact: boolean;\n /** Called after a nav page item is clicked — used by mobile sheet to close itself */\n onAfterNavClick?: () => void;\n}\n\nconst pageIconVariants = cva(\n \"flex items-center justify-center rounded-lg transition-colors duration-150\",\n {\n variants: {\n active: {\n true: \"bg-primary/10\",\n false: \"bg-transparent\",\n },\n compact: {\n true: \"w-9 h-9 hover:bg-muted\",\n false: \"w-8 h-8\",\n },\n },\n defaultVariants: { active: false, compact: true },\n }\n);\n\nfunction SidebarBody({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n compact,\n onAfterNavClick,\n}: SidebarBodyProps) {\n return (\n <TooltipProvider>\n {/* ── Header: app icon / name + version ──────────────────────────────── */}\n <div\n className={cn(\n \"shrink-0 border-b border-sidebar-border\",\n compact ? \"flex justify-center py-2\" : \"flex px-3 py-2.5\"\n )}\n >\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"cursor-pointer bg-transparent border-none p-0\",\n !compact && \"flex items-center gap-3 w-full text-left\"\n )}\n >\n {/* Icon */}\n <span\n className={cn(\n \"flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0\",\n compact ? \"w-9 h-9 text-[11px]\" : \"w-8 h-8 text-[10px]\"\n )}\n >\n {appIcon ?? appName}\n </span>\n\n {/* Name (expanded only — no version here) */}\n {!compact && (\n <span className=\"text-sm font-semibold text-foreground truncate leading-snug\">\n {appFullName ?? appName}\n </span>\n )}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"min-w-[220px]\">\n <div\n className=\"flex items-center gap-3 px-3 py-2.5 cursor-pointer\"\n onClick={onAppNameClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onAppNameClick?.();\n }}\n >\n <div className=\"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0\">\n <span className=\"text-[10px] font-bold text-foreground\">\n {appIcon ?? appName}\n </span>\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {appFullName ?? appName}\n </span>\n {version && (\n <span className=\"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5\">\n {version}\n </span>\n )}\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"gap-2.5 p-0\" asChild>\n {backToPlatformPath ? (\n <TDPLink\n path={backToPlatformPath}\n navigationOptions={{ newTab: false }}\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline\"\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </TDPLink>\n ) : (\n <button\n type=\"button\"\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer\"\n onClick={onBackToPlatform}\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </button>\n )}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* ── Nav groups ──────────────────────────────────────────────────────── */}\n <div\n className={cn(\n \"flex-1 min-h-0\",\n compact\n ? \"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto\"\n : \"flex flex-col py-2 overflow-y-auto\"\n )}\n >\n {navGroups.map((group, groupIndex) => (\n <React.Fragment key={`${groupIndex}-${group.label ?? \"\"}`}>\n {groupIndex > 0 && (\n <div\n className={cn(\n \"border-t border-sidebar-border\",\n compact ? \"w-8 my-2\" : \"mx-3 my-1\"\n )}\n />\n )}\n {!compact && group.label && (\n <span className=\"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold\">\n {group.label}\n </span>\n )}\n <div\n className={cn(\n \"flex flex-col\",\n compact ? \"items-center gap-3 w-full\" : \"gap-0.5\"\n )}\n >\n {group.pages.map((page) => {\n const Icon = page.icon;\n const iconEl = Icon ? (\n <Icon\n className={cn(\n \"w-5 h-5\",\n page.isActive ? \"text-primary\" : \"text-muted-foreground\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"w-2 h-2 rounded-full\",\n page.isActive ? \"bg-primary\" : \"bg-muted-foreground/40\"\n )}\n />\n );\n\n const handleClick = () => {\n page.onClick?.();\n onAfterNavClick?.();\n };\n\n if (compact) {\n return (\n <Tooltip key={page.id}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full\"\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: true }))}>\n {iconEl}\n </div>\n <span\n className={cn(\n \"text-[10px] font-medium leading-tight text-center\",\n page.isActive\n ? \"text-foreground font-semibold\"\n : \"text-muted-foreground\"\n )}\n >\n {page.label}\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{page.label}</TooltipContent>\n </Tooltip>\n );\n }\n\n // Expanded (mobile) row\n return (\n <button\n key={page.id}\n type=\"button\"\n className={cn(\n \"flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1\",\n page.isActive\n ? \"bg-sidebar-accent text-sidebar-foreground font-medium\"\n : \"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground\"\n )}\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: false }))}>\n {iconEl}\n </div>\n <span>{page.label}</span>\n </button>\n );\n })}\n </div>\n </React.Fragment>\n ))}\n </div>\n\n {/* ── Bottom: user menu slot ──────────────────────────────────────────── */}\n {userMenu && (\n <div\n className={cn(\n \"shrink-0 border-t border-sidebar-border\",\n compact ? \"flex flex-col items-center py-2\" : \"p-2\"\n )}\n >\n {userMenu}\n </div>\n )}\n </TooltipProvider>\n );\n}\n\n// =============================================================================\n// Icon rail sidebar (desktop only — hidden on mobile)\n// =============================================================================\n\nfunction IconRailSidebar(props: Omit<SidebarBodyProps, \"compact\" | \"onAfterNavClick\">) {\n return (\n <nav\n data-slot=\"data-app-sidebar-rail\"\n aria-label=\"Application navigation\"\n className=\"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50\"\n >\n <SidebarBody compact {...props} />\n </nav>\n );\n}\n\n// =============================================================================\n// Top nav\n// =============================================================================\n\nfunction TopNav({\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n mobileTrigger,\n}: {\n breadcrumbs?: BreadcrumbItemConfig[];\n onHelpClick?: () => void;\n headerActions?: React.ReactNode;\n mobileTrigger?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"data-app-top-nav\"\n className=\"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2\"\n >\n {/* Mobile hamburger (hidden on md+) */}\n {mobileTrigger}\n\n {/* Left: Breadcrumbs */}\n <Breadcrumb className=\"flex-1 min-w-0\">\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const isClickable = !isLast && (!!item.href || !!item.onClick);\n return (\n <React.Fragment key={`${item.label}-${index}`}>\n {index > 0 && <BreadcrumbSeparator>/</BreadcrumbSeparator>}\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : isClickable && item.href ? (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n ) : isClickable && item.onClick ? (\n <button\n type=\"button\"\n className=\"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal\"\n onClick={item.onClick}\n >\n {item.label}\n </button>\n ) : (\n <span className=\"text-[13px] text-muted-foreground\">{item.label}</span>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n\n {/* Right: header actions + help */}\n <div className=\"flex items-center gap-2 shrink-0\">\n {headerActions}\n\n {onHelpClick && (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"w-7 h-7 text-muted-foreground\"\n onClick={onHelpClick}\n aria-label=\"Help\"\n >\n <HelpCircle className=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">Help</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShell\n// =============================================================================\n\nfunction DataAppShell({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n sidebarPanel,\n showNavRail = true,\n children,\n className,\n}: DataAppShellProps) {\n const [mobileNavOpen, setMobileNavOpen] = React.useState(false);\n\n const sidebarProps = {\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n };\n\n return (\n <Sheet open={mobileNavOpen} onOpenChange={setMobileNavOpen}>\n <div\n data-slot=\"data-app-shell\"\n className={cn(\"flex flex-row w-full h-screen overflow-hidden\", className)}\n >\n {/* Desktop icon rail (hidden on mobile, or when showNavRail is false) */}\n {showNavRail && <IconRailSidebar {...sidebarProps} />}\n\n {/* Mobile sidebar Sheet */}\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col\"\n >\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SheetDescription className=\"sr-only\">\n Application navigation menu\n </SheetDescription>\n <nav aria-label=\"Application navigation\" className=\"flex flex-col h-full\">\n <SidebarBody\n compact={false}\n onAfterNavClick={() => setMobileNavOpen(false)}\n {...sidebarProps}\n />\n </nav>\n </SheetContent>\n\n {/* Right: top nav + panel + content */}\n <div className=\"flex flex-1 flex-col min-w-0 overflow-hidden\">\n <TopNav\n breadcrumbs={breadcrumbs}\n onHelpClick={onHelpClick}\n headerActions={headerActions}\n mobileTrigger={\n <SheetTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Open navigation menu\"\n className=\"md:hidden w-7 h-7 shrink-0 text-muted-foreground\"\n >\n <Menu className=\"w-4 h-4\" />\n </Button>\n </SheetTrigger>\n }\n />\n\n <div className=\"flex flex-1 min-h-0 overflow-hidden\">\n {/* Sidebar panel slot (e.g. WorkflowPanel) */}\n {sidebarPanel}\n\n {/* Content area */}\n <main\n data-slot=\"data-app-shell-content\"\n className=\"flex-1 overflow-auto bg-background\"\n >\n {children}\n </main>\n </div>\n </div>\n </div>\n </Sheet>\n );\n}\n\nexport default DataAppShell;\nexport { DataAppShell };\n"],"names":["pageIconVariants","cva","SidebarBody","appName","appFullName","appIcon","version","navGroups","onAppNameClick","backToPlatformPath","onBackToPlatform","userMenu","compact","onAfterNavClick","TooltipProvider","jsx","cn","DropdownMenu","DropdownMenuTrigger","jsxs","DropdownMenuContent","e","DropdownMenuSeparator","DropdownMenuItem","TDPLink","ArrowLeft","group","groupIndex","React","page","Icon","iconEl","handleClick","Tooltip","TooltipTrigger","TooltipContent","IconRailSidebar","props","TopNav","breadcrumbs","onHelpClick","headerActions","mobileTrigger","Breadcrumb","BreadcrumbList","item","index","isLast","isClickable","BreadcrumbSeparator","BreadcrumbItem","BreadcrumbPage","BreadcrumbLink","Button","HelpCircle","DataAppShell","sidebarPanel","showNavRail","children","className","mobileNavOpen","setMobileNavOpen","sidebarProps","Sheet","SheetContent","SheetTitle","SheetDescription","SheetTrigger","Menu"],"mappings":"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"}
1
+ {"version":3,"file":"DataAppShell.js","sources":["../../../../src/components/composed/DataAppShell/DataAppShell.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport {\n ArrowLeft,\n HelpCircle,\n Menu,\n type LucideIcon,\n} from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { TDPLink } from \"@/components/composed/tdp-link\";\nimport {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n} from \"@/components/ui/breadcrumb\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetTitle,\n SheetTrigger,\n} from \"@/components/ui/sheet\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface NavPage {\n /** Unique identifier */\n id: string;\n /** Display label */\n label: string;\n /** Lucide icon or custom React SVG component */\n icon?: LucideIcon | React.FC<React.SVGProps<SVGSVGElement>>;\n /** Whether this page is currently active */\n isActive?: boolean;\n /** Click handler */\n onClick?: () => void;\n}\n\nexport interface NavGroup {\n /** Optional group label shown as a section header in expanded nav */\n label?: string;\n /** Page entries in this group */\n pages: NavPage[];\n}\n\nexport interface BreadcrumbItemConfig {\n /** Display label */\n label: string;\n /** If provided, renders as a link */\n href?: string;\n /** Click handler (used when no href is provided) */\n onClick?: () => void;\n}\n\nexport interface DataAppShellProps {\n // -- Sidebar --\n /** Application name/abbreviation shown in the logo button */\n appName: string;\n /** Full application name shown in the app dropdown and mobile nav header */\n appFullName?: string;\n /** Custom icon element shown in the logo area */\n appIcon?: React.ReactNode;\n /** Optional version string shown below the app name/icon in the sidebar header */\n version?: string;\n /** Navigation groups; each group contains one or more pages */\n navGroups: NavGroup[];\n /** Callback when the app name / icon is clicked in the dropdown */\n onAppNameClick?: () => void;\n /** TDP path to navigate to when \"Back to TDP Platform\" is clicked (uses TDPLink — requires TdpNavigationProvider) */\n backToPlatformPath?: string;\n /** Fallback callback when \"Back to TDP Platform\" is clicked and no backToPlatformPath is set */\n onBackToPlatform?: () => void;\n /** Slot rendered at the bottom of the sidebar (e.g. user avatar + menu) */\n userMenu?: React.ReactNode;\n\n // -- Top nav --\n /** Breadcrumb items from root to current page */\n breadcrumbs?: BreadcrumbItemConfig[];\n /** Callback when the help button is clicked; omit to hide the button */\n onHelpClick?: () => void;\n /** Slot for right-side actions in the top nav (e.g. data count pills, next button) */\n headerActions?: React.ReactNode;\n\n // -- Shell --\n /** Slot rendered between the icon rail and the content (e.g. WorkflowPanel) */\n sidebarPanel?: React.ReactNode;\n /** Show the desktop icon nav rail. Set false to reclaim width when the panel is collapsed. */\n showNavRail?: boolean; // default true\n /** Main content area */\n children: React.ReactNode;\n /** Additional className for the root container */\n className?: string;\n}\n\n// =============================================================================\n// Sidebar shared body (used by desktop rail + mobile Sheet)\n// =============================================================================\n\ninterface SidebarBodyProps\n extends Pick<\n DataAppShellProps,\n | \"appName\"\n | \"appFullName\"\n | \"appIcon\"\n | \"version\"\n | \"navGroups\"\n | \"onAppNameClick\"\n | \"backToPlatformPath\"\n | \"onBackToPlatform\"\n | \"userMenu\"\n > {\n /**\n * compact=true → narrow icon rail (60px): icons + tiny labels stacked, tooltips on hover\n * compact=false → expanded mobile sheet (220px): icon + label side-by-side rows\n */\n compact: boolean;\n /** Called after a nav page item is clicked — used by mobile sheet to close itself */\n onAfterNavClick?: () => void;\n}\n\nconst pageIconVariants = cva(\n \"flex items-center justify-center rounded-lg transition-colors duration-150\",\n {\n variants: {\n active: {\n true: \"bg-primary/10\",\n false: \"bg-transparent\",\n },\n compact: {\n true: \"w-9 h-9 hover:bg-accent\",\n false: \"w-8 h-8\",\n },\n },\n defaultVariants: { active: false, compact: true },\n }\n);\n\nfunction SidebarBody({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n compact,\n onAfterNavClick,\n}: SidebarBodyProps) {\n return (\n <TooltipProvider>\n {/* ── Header: app icon / name + version ──────────────────────────────── */}\n <div\n className={cn(\n \"shrink-0 border-b border-sidebar-border\",\n compact ? \"flex justify-center py-2\" : \"flex px-3 py-2.5\"\n )}\n >\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"cursor-pointer bg-transparent border-none p-0\",\n !compact && \"flex items-center gap-3 w-full text-left\"\n )}\n >\n {/* Icon */}\n <span\n className={cn(\n \"flex items-center justify-center rounded-lg bg-sidebar-accent border border-sidebar-border font-bold text-foreground shrink-0\",\n compact ? \"w-9 h-9 text-[11px]\" : \"w-8 h-8 text-[10px]\"\n )}\n >\n {appIcon ?? appName}\n </span>\n\n {/* Name (expanded only — no version here) */}\n {!compact && (\n <span className=\"text-sm font-semibold text-foreground truncate leading-snug\">\n {appFullName ?? appName}\n </span>\n )}\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent side=\"right\" align=\"start\" className=\"min-w-[220px]\">\n <div\n className=\"flex items-center gap-3 px-3 py-2.5 cursor-pointer\"\n onClick={onAppNameClick}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") onAppNameClick?.();\n }}\n >\n <div className=\"w-8 h-8 rounded-lg bg-sidebar-accent border border-sidebar-border flex items-center justify-center shrink-0\">\n <span className=\"text-[10px] font-bold text-foreground\">\n {appIcon ?? appName}\n </span>\n </div>\n <div className=\"flex flex-col min-w-0\">\n <span className=\"text-sm font-semibold text-foreground truncate\">\n {appFullName ?? appName}\n </span>\n {version && (\n <span className=\"text-[10px] text-muted-foreground/70 font-mono leading-none mt-0.5\">\n {version}\n </span>\n )}\n </div>\n </div>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"gap-2.5 p-0\" asChild>\n {backToPlatformPath ? (\n <TDPLink\n path={backToPlatformPath}\n navigationOptions={{ newTab: false }}\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 !no-underline hover:!no-underline\"\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </TDPLink>\n ) : (\n <button\n type=\"button\"\n className=\"flex items-center gap-2.5 w-full px-2 py-1.5 bg-transparent border-none cursor-pointer\"\n onClick={onBackToPlatform}\n >\n <ArrowLeft className=\"w-4 h-4 text-muted-foreground\" />\n Back to TDP Platform\n </button>\n )}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n\n {/* ── Nav groups ──────────────────────────────────────────────────────── */}\n <div\n className={cn(\n \"flex-1 min-h-0\",\n compact\n ? \"flex flex-col items-center gap-1 px-2 pt-3 overflow-y-auto\"\n : \"flex flex-col py-2 overflow-y-auto\"\n )}\n >\n {navGroups.map((group, groupIndex) => (\n <React.Fragment key={`${groupIndex}-${group.label ?? \"\"}`}>\n {groupIndex > 0 && (\n <div\n className={cn(\n \"border-t border-sidebar-border\",\n compact ? \"w-8 my-2\" : \"mx-3 my-1\"\n )}\n />\n )}\n {!compact && group.label && (\n <span className=\"px-3 py-1 text-[10px] uppercase tracking-widest text-muted-foreground/60 font-semibold\">\n {group.label}\n </span>\n )}\n <div\n className={cn(\n \"flex flex-col\",\n compact ? \"items-center gap-3 w-full\" : \"gap-0.5\"\n )}\n >\n {group.pages.map((page) => {\n const Icon = page.icon;\n const iconEl = Icon ? (\n <Icon\n className={cn(\n \"w-5 h-5\",\n page.isActive ? \"text-primary\" : \"text-muted-foreground\"\n )}\n />\n ) : (\n <div\n className={cn(\n \"w-2 h-2 rounded-full\",\n page.isActive ? \"bg-primary\" : \"bg-muted-foreground/40\"\n )}\n />\n );\n\n const handleClick = () => {\n page.onClick?.();\n onAfterNavClick?.();\n };\n\n if (compact) {\n return (\n <Tooltip key={page.id}>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n className=\"flex flex-col items-center gap-0.5 cursor-pointer bg-transparent border-none p-0 w-full\"\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: true }))}>\n {iconEl}\n </div>\n <span\n className={cn(\n \"text-[10px] font-medium leading-tight text-center\",\n page.isActive\n ? \"text-foreground font-semibold\"\n : \"text-muted-foreground\"\n )}\n >\n {page.label}\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"right\">{page.label}</TooltipContent>\n </Tooltip>\n );\n }\n\n // Expanded (mobile) row\n return (\n <button\n key={page.id}\n type=\"button\"\n className={cn(\n \"flex items-center gap-3 w-full px-3 py-2 text-sm cursor-pointer bg-transparent border-none text-left transition-colors duration-150 rounded-md mx-1\",\n page.isActive\n ? \"bg-sidebar-accent text-sidebar-foreground font-medium\"\n : \"text-muted-foreground hover:bg-sidebar-accent/60 hover:text-foreground\"\n )}\n onClick={handleClick}\n >\n <div className={cn(pageIconVariants({ active: page.isActive ?? false, compact: false }))}>\n {iconEl}\n </div>\n <span>{page.label}</span>\n </button>\n );\n })}\n </div>\n </React.Fragment>\n ))}\n </div>\n\n {/* ── Bottom: user menu slot ──────────────────────────────────────────── */}\n {userMenu && (\n <div\n className={cn(\n \"shrink-0 border-t border-sidebar-border\",\n compact ? \"flex flex-col items-center py-2\" : \"p-2\"\n )}\n >\n {userMenu}\n </div>\n )}\n </TooltipProvider>\n );\n}\n\n// =============================================================================\n// Icon rail sidebar (desktop only — hidden on mobile)\n// =============================================================================\n\nfunction IconRailSidebar(props: Omit<SidebarBodyProps, \"compact\" | \"onAfterNavClick\">) {\n return (\n <nav\n data-slot=\"data-app-sidebar-rail\"\n aria-label=\"Application navigation\"\n className=\"hidden md:flex w-[60px] flex-col shrink-0 bg-sidebar border-r border-sidebar-border h-full z-50\"\n >\n <SidebarBody compact {...props} />\n </nav>\n );\n}\n\n// =============================================================================\n// Top nav\n// =============================================================================\n\nfunction TopNav({\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n mobileTrigger,\n}: {\n breadcrumbs?: BreadcrumbItemConfig[];\n onHelpClick?: () => void;\n headerActions?: React.ReactNode;\n mobileTrigger?: React.ReactNode;\n}) {\n return (\n <div\n data-slot=\"data-app-top-nav\"\n className=\"flex items-center h-10 px-3 bg-sidebar border-b border-sidebar-border sticky top-0 z-40 w-full gap-2\"\n >\n {/* Mobile hamburger (hidden on md+) */}\n {mobileTrigger}\n\n {/* Left: Breadcrumbs */}\n <Breadcrumb className=\"flex-1 min-w-0\">\n <BreadcrumbList>\n {breadcrumbs.map((item, index) => {\n const isLast = index === breadcrumbs.length - 1;\n const isClickable = !isLast && (!!item.href || !!item.onClick);\n return (\n <React.Fragment key={`${item.label}-${index}`}>\n {index > 0 && <BreadcrumbSeparator>/</BreadcrumbSeparator>}\n <BreadcrumbItem>\n {isLast ? (\n <BreadcrumbPage>{item.label}</BreadcrumbPage>\n ) : isClickable && item.href ? (\n <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>\n ) : isClickable && item.onClick ? (\n <button\n type=\"button\"\n className=\"text-[13px] text-primary hover:underline cursor-pointer bg-transparent border-none p-0 font-normal\"\n onClick={item.onClick}\n >\n {item.label}\n </button>\n ) : (\n <span className=\"text-[13px] text-muted-foreground\">{item.label}</span>\n )}\n </BreadcrumbItem>\n </React.Fragment>\n );\n })}\n </BreadcrumbList>\n </Breadcrumb>\n\n {/* Right: header actions + help */}\n <div className=\"flex items-center gap-2 shrink-0\">\n {headerActions}\n\n {onHelpClick && (\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"w-7 h-7 text-muted-foreground\"\n onClick={onHelpClick}\n aria-label=\"Help\"\n >\n <HelpCircle className=\"w-4 h-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"bottom\">Help</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// DataAppShell\n// =============================================================================\n\nfunction DataAppShell({\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n breadcrumbs = [],\n onHelpClick,\n headerActions,\n sidebarPanel,\n showNavRail = true,\n children,\n className,\n}: DataAppShellProps) {\n const [mobileNavOpen, setMobileNavOpen] = React.useState(false);\n\n const sidebarProps = {\n appName,\n appFullName,\n appIcon,\n version,\n navGroups,\n onAppNameClick,\n backToPlatformPath,\n onBackToPlatform,\n userMenu,\n };\n\n return (\n <Sheet open={mobileNavOpen} onOpenChange={setMobileNavOpen}>\n <div\n data-slot=\"data-app-shell\"\n className={cn(\"flex flex-row w-full h-screen overflow-hidden\", className)}\n >\n {/* Desktop icon rail (hidden on mobile, or when showNavRail is false) */}\n {showNavRail && <IconRailSidebar {...sidebarProps} />}\n\n {/* Mobile sidebar Sheet */}\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"p-0 bg-sidebar border-r border-sidebar-border data-[side=left]:w-[220px] data-[side=left]:sm:w-[220px] data-[side=left]:sm:max-w-[220px] flex flex-col\"\n >\n <SheetTitle className=\"sr-only\">Navigation</SheetTitle>\n <SheetDescription className=\"sr-only\">\n Application navigation menu\n </SheetDescription>\n <nav aria-label=\"Application navigation\" className=\"flex flex-col h-full\">\n <SidebarBody\n compact={false}\n onAfterNavClick={() => setMobileNavOpen(false)}\n {...sidebarProps}\n />\n </nav>\n </SheetContent>\n\n {/* Right: top nav + panel + content */}\n <div className=\"flex flex-1 flex-col min-w-0 overflow-hidden\">\n <TopNav\n breadcrumbs={breadcrumbs}\n onHelpClick={onHelpClick}\n headerActions={headerActions}\n mobileTrigger={\n <SheetTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label=\"Open navigation menu\"\n className=\"md:hidden w-7 h-7 shrink-0 text-muted-foreground\"\n >\n <Menu className=\"w-4 h-4\" />\n </Button>\n </SheetTrigger>\n }\n />\n\n <div className=\"flex flex-1 min-h-0 overflow-hidden\">\n {/* Sidebar panel slot (e.g. WorkflowPanel) */}\n {sidebarPanel}\n\n {/* Content area */}\n <main\n data-slot=\"data-app-shell-content\"\n className=\"flex-1 overflow-auto bg-background\"\n >\n {children}\n </main>\n </div>\n </div>\n </div>\n </Sheet>\n );\n}\n\nexport default DataAppShell;\nexport { DataAppShell };\n"],"names":["pageIconVariants","cva","SidebarBody","appName","appFullName","appIcon","version","navGroups","onAppNameClick","backToPlatformPath","onBackToPlatform","userMenu","compact","onAfterNavClick","TooltipProvider","jsx","cn","DropdownMenu","DropdownMenuTrigger","jsxs","DropdownMenuContent","e","DropdownMenuSeparator","DropdownMenuItem","TDPLink","ArrowLeft","group","groupIndex","React","page","Icon","iconEl","handleClick","Tooltip","TooltipTrigger","TooltipContent","IconRailSidebar","props","TopNav","breadcrumbs","onHelpClick","headerActions","mobileTrigger","Breadcrumb","BreadcrumbList","item","index","isLast","isClickable","BreadcrumbSeparator","BreadcrumbItem","BreadcrumbPage","BreadcrumbLink","Button","HelpCircle","DataAppShell","sidebarPanel","showNavRail","children","className","mobileNavOpen","setMobileNavOpen","sidebarProps","Sheet","SheetContent","SheetTitle","SheetDescription","SheetTrigger","Menu"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),X=require("react"),Y=require("./PlatePaintGrid.cjs"),h=require("./wellGrid.cjs"),Z=require("../../ui/separator.cjs"),j=require("../../../lib/utils.cjs");function $(l){const s=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const t in l)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(l,t);Object.defineProperty(s,t,n.get?n:{enumerable:!0,get:()=>l[t]})}}return s.default=l,Object.freeze(s)}const ee=$(X);function te(l,s){return s.map(t=>{const n=l[t.key];if(n==null||n==="")return null;if(t.kind==="select")return(t.options??[]).find(o=>o.value===n)?.label??String(n);if(t.kind==="multiselect"){const i=Array.isArray(n)?n:[];return i.length===0?null:i.map(o=>(t.options??[]).find(c=>c.value===o)?.label??o).join(", ")}return t.kind==="boolean"?n?t.label:null:String(n)}).filter(Boolean)}function ne({format:l,rows:s,columns:t,values:n,selection:i,onSelectionChange:o,colorForWell:c,fields:m,renderHoverSummary:y,onHoveredWellChange:g,hoveredWellId:x,toolbar:f,hideSelectionControls:N=!1,selectAllLabel:P="Select all",deselectAllLabel:w="Deselect all",emptyWellFillColor:S,wellShape:k,framed:q,wrapWell:C,highlightedWellIds:O,onWellDoubleClick:A,selectionFillMode:G,flashWellId:H,flashWellKey:D,cellSize:M,autoScale:R,minCellSize:F,maxCellSize:T,groups:d,activeGroupId:_,onGroupClick:z,className:B}){const E=h.resolveDimensions(l,s,t),[I,J]=ee.useState(null),p=x!==void 0,a=p?x:I,K=()=>o(new Set(h.allPositions(E))),L=()=>o(new Set),u=a?n.get(a):void 0,Q=u&&m?te(u,m):[],U=a?y?.(u,a)??[a,...Q].join(" • "):" ",v=!N,V=!!f||v;return e.jsxs("div",{"data-slot":"plate-map-grid",className:j.cn("flex flex-col gap-1.5",B),children:[V?e.jsxs("div",{className:"flex flex-wrap items-center justify-start gap-3",children:[f,v?e.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[e.jsx("button",{type:"button",className:"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline",onClick:K,children:P}),e.jsx("span",{className:"text-muted-foreground/60",children:"·"}),e.jsx("button",{type:"button",className:"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline",onClick:L,children:w})]}):null]}):null,e.jsx("div",{className:"h-5 text-xs text-muted-foreground",children:U}),e.jsx(Y.PlatePaintGrid,{format:l,rows:s,columns:t,values:n,selection:i,onSelectionChange:o,colorForWell:c,emptyWellFillColor:S,wellShape:k,framed:q,wrapWell:C,highlightedWellIds:O,onWellHover:r=>{p||J(r),g?.(r)},onWellDoubleClick:A,selectionFillMode:G,flashWellId:H,flashWellKey:D,cellSize:M,autoScale:R,minCellSize:F,maxCellSize:T}),d&&d.length>0?e.jsxs(e.Fragment,{children:[e.jsx(Z.Separator,{className:"mt-2"}),e.jsx("div",{className:"flex max-h-28 flex-wrap gap-3 overflow-y-auto pt-1",children:d.map(r=>{const W=r.id===_,b=r.count??r.wellIds?.length;return e.jsxs("button",{type:"button",disabled:r.disabled,onClick:()=>z?.(r),className:j.cn("flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors","text-muted-foreground hover:bg-muted/60",W&&"bg-muted text-foreground ring-1 ring-primary/40",r.disabled&&"pointer-events-none opacity-50"),title:r.label,children:[e.jsx("span",{className:"size-7 rounded-full border",style:{backgroundColor:r.color,borderColor:r.borderColor},"aria-hidden":!0}),e.jsx("span",{className:"w-full truncate text-foreground",children:r.label}),b===void 0?null:e.jsxs("span",{className:"text-[0.7rem] leading-none text-muted-foreground",children:[b," wells"]})]},r.id)})})]}):null]})}exports.PlateMapGrid=ne;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),X=require("react"),Y=require("./PlatePaintGrid.cjs"),h=require("./wellGrid.cjs"),Z=require("../../ui/separator.cjs"),j=require("../../../lib/utils.cjs");function $(l){const s=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const t in l)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(l,t);Object.defineProperty(s,t,n.get?n:{enumerable:!0,get:()=>l[t]})}}return s.default=l,Object.freeze(s)}const ee=$(X);function te(l,s){return s.map(t=>{const n=l[t.key];if(n==null||n==="")return null;if(t.kind==="select")return(t.options??[]).find(o=>o.value===n)?.label??String(n);if(t.kind==="multiselect"){const i=Array.isArray(n)?n:[];return i.length===0?null:i.map(o=>(t.options??[]).find(c=>c.value===o)?.label??o).join(", ")}return t.kind==="boolean"?n?t.label:null:String(n)}).filter(Boolean)}function ne({format:l,rows:s,columns:t,values:n,selection:i,onSelectionChange:o,colorForWell:c,fields:m,renderHoverSummary:y,onHoveredWellChange:g,hoveredWellId:x,toolbar:f,hideSelectionControls:N=!1,selectAllLabel:P="Select all",deselectAllLabel:w="Deselect all",emptyWellFillColor:S,wellShape:k,framed:q,wrapWell:C,highlightedWellIds:O,onWellDoubleClick:A,selectionFillMode:G,flashWellId:H,flashWellKey:D,cellSize:M,autoScale:R,minCellSize:F,maxCellSize:T,groups:d,activeGroupId:_,onGroupClick:z,className:B}){const E=h.resolveDimensions(l,s,t),[I,J]=ee.useState(null),p=x!==void 0,a=p?x:I,K=()=>o(new Set(h.allPositions(E))),L=()=>o(new Set),u=a?n.get(a):void 0,Q=u&&m?te(u,m):[],U=a?y?.(u,a)??[a,...Q].join(" • "):" ",v=!N,V=!!f||v;return e.jsxs("div",{"data-slot":"plate-map-grid",className:j.cn("flex flex-col gap-1.5",B),children:[V?e.jsxs("div",{className:"flex flex-wrap items-center justify-start gap-3",children:[f,v?e.jsxs("div",{className:"flex items-center gap-2 text-xs",children:[e.jsx("button",{type:"button",className:"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline",onClick:K,children:P}),e.jsx("span",{className:"text-muted-foreground/60",children:"·"}),e.jsx("button",{type:"button",className:"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline",onClick:L,children:w})]}):null]}):null,e.jsx("div",{className:"h-5 text-xs text-muted-foreground",children:U}),e.jsx(Y.PlatePaintGrid,{format:l,rows:s,columns:t,values:n,selection:i,onSelectionChange:o,colorForWell:c,emptyWellFillColor:S,wellShape:k,framed:q,wrapWell:C,highlightedWellIds:O,onWellHover:r=>{p||J(r),g?.(r)},onWellDoubleClick:A,selectionFillMode:G,flashWellId:H,flashWellKey:D,cellSize:M,autoScale:R,minCellSize:F,maxCellSize:T}),d&&d.length>0?e.jsxs(e.Fragment,{children:[e.jsx(Z.Separator,{className:"mt-2"}),e.jsx("div",{className:"flex max-h-28 flex-wrap gap-3 overflow-y-auto pt-1",children:d.map(r=>{const W=r.id===_,b=r.count??r.wellIds?.length;return e.jsxs("button",{type:"button",disabled:r.disabled,onClick:()=>z?.(r),className:j.cn("flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors","text-muted-foreground hover:bg-accent/60",W&&"bg-muted text-foreground ring-1 ring-primary/40",r.disabled&&"pointer-events-none opacity-50"),title:r.label,children:[e.jsx("span",{className:"size-7 rounded-full border",style:{backgroundColor:r.color,borderColor:r.borderColor},"aria-hidden":!0}),e.jsx("span",{className:"w-full truncate text-foreground",children:r.label}),b===void 0?null:e.jsxs("span",{className:"text-[0.7rem] leading-none text-muted-foreground",children:[b," wells"]})]},r.id)})})]}):null]})}exports.PlateMapGrid=ne;
2
2
  //# sourceMappingURL=PlateMapGrid.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"PlateMapGrid.cjs","sources":["../../../../src/components/composed/PlateMapEditor/PlateMapGrid.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { PlatePaintGrid } from \"./PlatePaintGrid\";\nimport { allPositions, resolveDimensions } from \"./wellGrid\";\n\nimport type { WellShape } from \"./PlatePaintGrid\";\nimport type { PlateFormat, PlateMapGroupOption, WellField, WellId, WellRecord } from \"./types\";\n\nimport { Separator } from \"@/components/ui/separator\";\nimport { cn } from \"@/lib/utils\";\n\nfunction formatHoverFields<T extends WellRecord>(entry: T, fields: WellField<T>[]): string[] {\n return fields\n .map((f) => {\n const v = entry[f.key];\n if (v === undefined || v === null || v === \"\") return null;\n if (f.kind === \"select\") {\n const opt = (f.options ?? []).find((o) => o.value === v);\n return opt?.label ?? String(v);\n }\n if (f.kind === \"multiselect\") {\n const arr = Array.isArray(v) ? (v as string[]) : [];\n if (arr.length === 0) return null;\n return arr.map((item) => (f.options ?? []).find((o) => o.value === item)?.label ?? item).join(\", \");\n }\n if (f.kind === \"boolean\") {\n return v ? f.label : null;\n }\n return String(v);\n })\n .filter(Boolean) as string[];\n}\n\nexport interface PlateMapGridProps<T extends WellRecord = WellRecord> {\n format: PlateFormat;\n rows?: number;\n columns?: number;\n values: Map<WellId, T>;\n selection: Set<WellId>;\n onSelectionChange: (next: Set<WellId>) => void;\n /** Resolves the SVG fill color for a well. */\n colorForWell: (well: T | undefined, wellId: WellId) => string;\n /** Field schema used to build the default hover summary string. */\n fields?: WellField<T>[];\n /** Custom hover summary for the strip above the grid. */\n renderHoverSummary?: (well: T | undefined, wellId: WellId) => React.ReactNode;\n /** Fires whenever the currently hovered well changes (null on leave). */\n onHoveredWellChange?: (wellId: WellId | null) => void;\n /**\n * Controlled hovered well id. When provided, the panel reflects this value\n * instead of tracking hover internally — useful for syncing the hover\n * summary with external state (e.g. resetting it on a plate switch).\n */\n hoveredWellId?: WellId | null;\n /** Controls rendered to the left of the built-in select/deselect links. */\n toolbar?: React.ReactNode;\n /** Hide the built-in \"Select all\" / \"Deselect all\" links. */\n hideSelectionControls?: boolean;\n selectAllLabel?: string;\n deselectAllLabel?: string;\n /** Fill color for empty wells. Pass `null` to delegate empty wells to `colorForWell`. */\n emptyWellFillColor?: string | null;\n /** Well shape forwarded to `PlatePaintGrid`. Defaults to `\"rect\"`. */\n wellShape?: WellShape;\n /** When true, wraps the grid in a card-like plate frame (rounded + border + soft shadow). */\n framed?: boolean;\n /** Render-prop that places a node inside each absolute-positioned well cell. */\n wrapWell?: (wellId: WellId, cellSize: number) => React.ReactNode;\n /** Wells to highlight (e.g. when hovering a legend item externally). */\n highlightedWellIds?: ReadonlySet<WellId>;\n onWellDoubleClick?: (wellId: WellId) => void;\n selectionFillMode?: \"selection\" | \"well\";\n flashWellId?: WellId;\n flashWellKey?: number;\n /** Fixed well size. When unset, the grid grows with the available width. */\n cellSize?: number;\n autoScale?: boolean;\n minCellSize?: number;\n maxCellSize?: number;\n /** Optional grouped well shortcuts rendered under the grid. */\n groups?: PlateMapGroupOption[];\n activeGroupId?: string;\n onGroupClick?: (group: PlateMapGroupOption) => void;\n className?: string;\n}\n\n/**\n * Card-agnostic plate grid panel. Renders the selection toolbar, hover\n * summary, the interactive `PlatePaintGrid`, and optional group shortcuts —\n * and owns the ephemeral hover state internally. The plate title, plate\n * selector, and actions menu are intentionally NOT part of this panel; compose\n * `PlateMapPlateSelector` and `PlateMapActionsMenu` around it for full layout\n * freedom.\n */\nexport function PlateMapGrid<T extends WellRecord = WellRecord>({\n format,\n rows,\n columns,\n values,\n selection,\n onSelectionChange,\n colorForWell,\n fields,\n renderHoverSummary,\n onHoveredWellChange,\n hoveredWellId,\n toolbar,\n hideSelectionControls = false,\n selectAllLabel = \"Select all\",\n deselectAllLabel = \"Deselect all\",\n emptyWellFillColor,\n wellShape,\n framed,\n wrapWell,\n highlightedWellIds,\n onWellDoubleClick,\n selectionFillMode,\n flashWellId,\n flashWellKey,\n cellSize,\n autoScale,\n minCellSize,\n maxCellSize,\n groups,\n activeGroupId,\n onGroupClick,\n className,\n}: PlateMapGridProps<T>) {\n const dims = resolveDimensions(format, rows, columns);\n const [internalHoverPos, setInternalHoverPos] = React.useState<WellId | null>(null);\n const isHoverControlled = hoveredWellId !== undefined;\n const hoverPos = isHoverControlled ? hoveredWellId : internalHoverPos;\n\n const selectAll = () => onSelectionChange(new Set(allPositions(dims)));\n const deselectAll = () => onSelectionChange(new Set());\n\n const hoverEntry = hoverPos ? values.get(hoverPos) : undefined;\n const hoverFields = hoverEntry && fields ? formatHoverFields(hoverEntry, fields) : [];\n const hoverSummary = hoverPos\n ? (renderHoverSummary?.(hoverEntry, hoverPos) ?? [hoverPos, ...hoverFields].join(\" • \"))\n : \" \";\n\n const showSelectionControls = !hideSelectionControls;\n const showToolbarRow = !!toolbar || showSelectionControls;\n\n return (\n <div data-slot=\"plate-map-grid\" className={cn(\"flex flex-col gap-1.5\", className)}>\n {showToolbarRow ? (\n <div className=\"flex flex-wrap items-center justify-start gap-3\">\n {toolbar}\n {showSelectionControls ? (\n <div className=\"flex items-center gap-2 text-xs\">\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={selectAll}\n >\n {selectAllLabel}\n </button>\n <span className=\"text-muted-foreground/60\">·</span>\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={deselectAll}\n >\n {deselectAllLabel}\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n <div className=\"h-5 text-xs text-muted-foreground\">{hoverSummary}</div>\n <PlatePaintGrid\n format={format}\n rows={rows}\n columns={columns}\n values={values}\n selection={selection}\n onSelectionChange={onSelectionChange}\n colorForWell={colorForWell}\n emptyWellFillColor={emptyWellFillColor}\n wellShape={wellShape}\n framed={framed}\n wrapWell={wrapWell}\n highlightedWellIds={highlightedWellIds}\n onWellHover={(wellId) => {\n if (!isHoverControlled) setInternalHoverPos(wellId);\n onHoveredWellChange?.(wellId);\n }}\n onWellDoubleClick={onWellDoubleClick}\n selectionFillMode={selectionFillMode}\n flashWellId={flashWellId}\n flashWellKey={flashWellKey}\n cellSize={cellSize}\n autoScale={autoScale}\n minCellSize={minCellSize}\n maxCellSize={maxCellSize}\n />\n {groups && groups.length > 0 ? (\n <>\n <Separator className=\"mt-2\" />\n <div className=\"flex max-h-28 flex-wrap gap-3 overflow-y-auto pt-1\">\n {groups.map((group) => {\n const isActive = group.id === activeGroupId;\n const count = group.count ?? group.wellIds?.length;\n return (\n <button\n key={group.id}\n type=\"button\"\n disabled={group.disabled}\n onClick={() => onGroupClick?.(group)}\n className={cn(\n \"flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors\",\n \"text-muted-foreground hover:bg-muted/60\",\n isActive && \"bg-muted text-foreground ring-1 ring-primary/40\",\n group.disabled && \"pointer-events-none opacity-50\",\n )}\n title={group.label}\n >\n <span\n className=\"size-7 rounded-full border\"\n style={{\n backgroundColor: group.color,\n borderColor: group.borderColor,\n }}\n aria-hidden\n />\n <span className=\"w-full truncate text-foreground\">{group.label}</span>\n {count === undefined ? null : (\n <span className=\"text-[0.7rem] leading-none text-muted-foreground\">{count} wells</span>\n )}\n </button>\n );\n })}\n </div>\n </>\n ) : null}\n </div>\n );\n}\n"],"names":["formatHoverFields","entry","fields","f","v","arr","item","o","PlateMapGrid","format","rows","columns","values","selection","onSelectionChange","colorForWell","renderHoverSummary","onHoveredWellChange","hoveredWellId","toolbar","hideSelectionControls","selectAllLabel","deselectAllLabel","emptyWellFillColor","wellShape","framed","wrapWell","highlightedWellIds","onWellDoubleClick","selectionFillMode","flashWellId","flashWellKey","cellSize","autoScale","minCellSize","maxCellSize","groups","activeGroupId","onGroupClick","className","dims","resolveDimensions","internalHoverPos","setInternalHoverPos","React","isHoverControlled","hoverPos","selectAll","allPositions","deselectAll","hoverEntry","hoverFields","hoverSummary","showSelectionControls","showToolbarRow","jsxs","cn","jsx","PlatePaintGrid","wellId","Fragment","Separator","group","isActive","count"],"mappings":"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"}
1
+ {"version":3,"file":"PlateMapGrid.cjs","sources":["../../../../src/components/composed/PlateMapEditor/PlateMapGrid.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { PlatePaintGrid } from \"./PlatePaintGrid\";\nimport { allPositions, resolveDimensions } from \"./wellGrid\";\n\nimport type { WellShape } from \"./PlatePaintGrid\";\nimport type { PlateFormat, PlateMapGroupOption, WellField, WellId, WellRecord } from \"./types\";\n\nimport { Separator } from \"@/components/ui/separator\";\nimport { cn } from \"@/lib/utils\";\n\nfunction formatHoverFields<T extends WellRecord>(entry: T, fields: WellField<T>[]): string[] {\n return fields\n .map((f) => {\n const v = entry[f.key];\n if (v === undefined || v === null || v === \"\") return null;\n if (f.kind === \"select\") {\n const opt = (f.options ?? []).find((o) => o.value === v);\n return opt?.label ?? String(v);\n }\n if (f.kind === \"multiselect\") {\n const arr = Array.isArray(v) ? (v as string[]) : [];\n if (arr.length === 0) return null;\n return arr.map((item) => (f.options ?? []).find((o) => o.value === item)?.label ?? item).join(\", \");\n }\n if (f.kind === \"boolean\") {\n return v ? f.label : null;\n }\n return String(v);\n })\n .filter(Boolean) as string[];\n}\n\nexport interface PlateMapGridProps<T extends WellRecord = WellRecord> {\n format: PlateFormat;\n rows?: number;\n columns?: number;\n values: Map<WellId, T>;\n selection: Set<WellId>;\n onSelectionChange: (next: Set<WellId>) => void;\n /** Resolves the SVG fill color for a well. */\n colorForWell: (well: T | undefined, wellId: WellId) => string;\n /** Field schema used to build the default hover summary string. */\n fields?: WellField<T>[];\n /** Custom hover summary for the strip above the grid. */\n renderHoverSummary?: (well: T | undefined, wellId: WellId) => React.ReactNode;\n /** Fires whenever the currently hovered well changes (null on leave). */\n onHoveredWellChange?: (wellId: WellId | null) => void;\n /**\n * Controlled hovered well id. When provided, the panel reflects this value\n * instead of tracking hover internally — useful for syncing the hover\n * summary with external state (e.g. resetting it on a plate switch).\n */\n hoveredWellId?: WellId | null;\n /** Controls rendered to the left of the built-in select/deselect links. */\n toolbar?: React.ReactNode;\n /** Hide the built-in \"Select all\" / \"Deselect all\" links. */\n hideSelectionControls?: boolean;\n selectAllLabel?: string;\n deselectAllLabel?: string;\n /** Fill color for empty wells. Pass `null` to delegate empty wells to `colorForWell`. */\n emptyWellFillColor?: string | null;\n /** Well shape forwarded to `PlatePaintGrid`. Defaults to `\"rect\"`. */\n wellShape?: WellShape;\n /** When true, wraps the grid in a card-like plate frame (rounded + border + soft shadow). */\n framed?: boolean;\n /** Render-prop that places a node inside each absolute-positioned well cell. */\n wrapWell?: (wellId: WellId, cellSize: number) => React.ReactNode;\n /** Wells to highlight (e.g. when hovering a legend item externally). */\n highlightedWellIds?: ReadonlySet<WellId>;\n onWellDoubleClick?: (wellId: WellId) => void;\n selectionFillMode?: \"selection\" | \"well\";\n flashWellId?: WellId;\n flashWellKey?: number;\n /** Fixed well size. When unset, the grid grows with the available width. */\n cellSize?: number;\n autoScale?: boolean;\n minCellSize?: number;\n maxCellSize?: number;\n /** Optional grouped well shortcuts rendered under the grid. */\n groups?: PlateMapGroupOption[];\n activeGroupId?: string;\n onGroupClick?: (group: PlateMapGroupOption) => void;\n className?: string;\n}\n\n/**\n * Card-agnostic plate grid panel. Renders the selection toolbar, hover\n * summary, the interactive `PlatePaintGrid`, and optional group shortcuts —\n * and owns the ephemeral hover state internally. The plate title, plate\n * selector, and actions menu are intentionally NOT part of this panel; compose\n * `PlateMapPlateSelector` and `PlateMapActionsMenu` around it for full layout\n * freedom.\n */\nexport function PlateMapGrid<T extends WellRecord = WellRecord>({\n format,\n rows,\n columns,\n values,\n selection,\n onSelectionChange,\n colorForWell,\n fields,\n renderHoverSummary,\n onHoveredWellChange,\n hoveredWellId,\n toolbar,\n hideSelectionControls = false,\n selectAllLabel = \"Select all\",\n deselectAllLabel = \"Deselect all\",\n emptyWellFillColor,\n wellShape,\n framed,\n wrapWell,\n highlightedWellIds,\n onWellDoubleClick,\n selectionFillMode,\n flashWellId,\n flashWellKey,\n cellSize,\n autoScale,\n minCellSize,\n maxCellSize,\n groups,\n activeGroupId,\n onGroupClick,\n className,\n}: PlateMapGridProps<T>) {\n const dims = resolveDimensions(format, rows, columns);\n const [internalHoverPos, setInternalHoverPos] = React.useState<WellId | null>(null);\n const isHoverControlled = hoveredWellId !== undefined;\n const hoverPos = isHoverControlled ? hoveredWellId : internalHoverPos;\n\n const selectAll = () => onSelectionChange(new Set(allPositions(dims)));\n const deselectAll = () => onSelectionChange(new Set());\n\n const hoverEntry = hoverPos ? values.get(hoverPos) : undefined;\n const hoverFields = hoverEntry && fields ? formatHoverFields(hoverEntry, fields) : [];\n const hoverSummary = hoverPos\n ? (renderHoverSummary?.(hoverEntry, hoverPos) ?? [hoverPos, ...hoverFields].join(\" • \"))\n : \" \";\n\n const showSelectionControls = !hideSelectionControls;\n const showToolbarRow = !!toolbar || showSelectionControls;\n\n return (\n <div data-slot=\"plate-map-grid\" className={cn(\"flex flex-col gap-1.5\", className)}>\n {showToolbarRow ? (\n <div className=\"flex flex-wrap items-center justify-start gap-3\">\n {toolbar}\n {showSelectionControls ? (\n <div className=\"flex items-center gap-2 text-xs\">\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={selectAll}\n >\n {selectAllLabel}\n </button>\n <span className=\"text-muted-foreground/60\">·</span>\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={deselectAll}\n >\n {deselectAllLabel}\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n <div className=\"h-5 text-xs text-muted-foreground\">{hoverSummary}</div>\n <PlatePaintGrid\n format={format}\n rows={rows}\n columns={columns}\n values={values}\n selection={selection}\n onSelectionChange={onSelectionChange}\n colorForWell={colorForWell}\n emptyWellFillColor={emptyWellFillColor}\n wellShape={wellShape}\n framed={framed}\n wrapWell={wrapWell}\n highlightedWellIds={highlightedWellIds}\n onWellHover={(wellId) => {\n if (!isHoverControlled) setInternalHoverPos(wellId);\n onHoveredWellChange?.(wellId);\n }}\n onWellDoubleClick={onWellDoubleClick}\n selectionFillMode={selectionFillMode}\n flashWellId={flashWellId}\n flashWellKey={flashWellKey}\n cellSize={cellSize}\n autoScale={autoScale}\n minCellSize={minCellSize}\n maxCellSize={maxCellSize}\n />\n {groups && groups.length > 0 ? (\n <>\n <Separator className=\"mt-2\" />\n <div className=\"flex max-h-28 flex-wrap gap-3 overflow-y-auto pt-1\">\n {groups.map((group) => {\n const isActive = group.id === activeGroupId;\n const count = group.count ?? group.wellIds?.length;\n return (\n <button\n key={group.id}\n type=\"button\"\n disabled={group.disabled}\n onClick={() => onGroupClick?.(group)}\n className={cn(\n \"flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors\",\n \"text-muted-foreground hover:bg-accent/60\",\n isActive && \"bg-muted text-foreground ring-1 ring-primary/40\",\n group.disabled && \"pointer-events-none opacity-50\",\n )}\n title={group.label}\n >\n <span\n className=\"size-7 rounded-full border\"\n style={{\n backgroundColor: group.color,\n borderColor: group.borderColor,\n }}\n aria-hidden\n />\n <span className=\"w-full truncate text-foreground\">{group.label}</span>\n {count === undefined ? null : (\n <span className=\"text-[0.7rem] leading-none text-muted-foreground\">{count} wells</span>\n )}\n </button>\n );\n })}\n </div>\n </>\n ) : null}\n </div>\n );\n}\n"],"names":["formatHoverFields","entry","fields","f","v","arr","item","o","PlateMapGrid","format","rows","columns","values","selection","onSelectionChange","colorForWell","renderHoverSummary","onHoveredWellChange","hoveredWellId","toolbar","hideSelectionControls","selectAllLabel","deselectAllLabel","emptyWellFillColor","wellShape","framed","wrapWell","highlightedWellIds","onWellDoubleClick","selectionFillMode","flashWellId","flashWellKey","cellSize","autoScale","minCellSize","maxCellSize","groups","activeGroupId","onGroupClick","className","dims","resolveDimensions","internalHoverPos","setInternalHoverPos","React","isHoverControlled","hoverPos","selectAll","allPositions","deselectAll","hoverEntry","hoverFields","hoverSummary","showSelectionControls","showToolbarRow","jsxs","cn","jsx","PlatePaintGrid","wellId","Fragment","Separator","group","isActive","count"],"mappings":"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"}
@@ -118,7 +118,7 @@ function ae({
118
118
  onClick: () => q?.(e),
119
119
  className: y(
120
120
  "flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors",
121
- "text-muted-foreground hover:bg-muted/60",
121
+ "text-muted-foreground hover:bg-accent/60",
122
122
  X && "bg-muted text-foreground ring-1 ring-primary/40",
123
123
  e.disabled && "pointer-events-none opacity-50"
124
124
  ),
@@ -1 +1 @@
1
- {"version":3,"file":"PlateMapGrid.js","sources":["../../../../src/components/composed/PlateMapEditor/PlateMapGrid.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { PlatePaintGrid } from \"./PlatePaintGrid\";\nimport { allPositions, resolveDimensions } from \"./wellGrid\";\n\nimport type { WellShape } from \"./PlatePaintGrid\";\nimport type { PlateFormat, PlateMapGroupOption, WellField, WellId, WellRecord } from \"./types\";\n\nimport { Separator } from \"@/components/ui/separator\";\nimport { cn } from \"@/lib/utils\";\n\nfunction formatHoverFields<T extends WellRecord>(entry: T, fields: WellField<T>[]): string[] {\n return fields\n .map((f) => {\n const v = entry[f.key];\n if (v === undefined || v === null || v === \"\") return null;\n if (f.kind === \"select\") {\n const opt = (f.options ?? []).find((o) => o.value === v);\n return opt?.label ?? String(v);\n }\n if (f.kind === \"multiselect\") {\n const arr = Array.isArray(v) ? (v as string[]) : [];\n if (arr.length === 0) return null;\n return arr.map((item) => (f.options ?? []).find((o) => o.value === item)?.label ?? item).join(\", \");\n }\n if (f.kind === \"boolean\") {\n return v ? f.label : null;\n }\n return String(v);\n })\n .filter(Boolean) as string[];\n}\n\nexport interface PlateMapGridProps<T extends WellRecord = WellRecord> {\n format: PlateFormat;\n rows?: number;\n columns?: number;\n values: Map<WellId, T>;\n selection: Set<WellId>;\n onSelectionChange: (next: Set<WellId>) => void;\n /** Resolves the SVG fill color for a well. */\n colorForWell: (well: T | undefined, wellId: WellId) => string;\n /** Field schema used to build the default hover summary string. */\n fields?: WellField<T>[];\n /** Custom hover summary for the strip above the grid. */\n renderHoverSummary?: (well: T | undefined, wellId: WellId) => React.ReactNode;\n /** Fires whenever the currently hovered well changes (null on leave). */\n onHoveredWellChange?: (wellId: WellId | null) => void;\n /**\n * Controlled hovered well id. When provided, the panel reflects this value\n * instead of tracking hover internally — useful for syncing the hover\n * summary with external state (e.g. resetting it on a plate switch).\n */\n hoveredWellId?: WellId | null;\n /** Controls rendered to the left of the built-in select/deselect links. */\n toolbar?: React.ReactNode;\n /** Hide the built-in \"Select all\" / \"Deselect all\" links. */\n hideSelectionControls?: boolean;\n selectAllLabel?: string;\n deselectAllLabel?: string;\n /** Fill color for empty wells. Pass `null` to delegate empty wells to `colorForWell`. */\n emptyWellFillColor?: string | null;\n /** Well shape forwarded to `PlatePaintGrid`. Defaults to `\"rect\"`. */\n wellShape?: WellShape;\n /** When true, wraps the grid in a card-like plate frame (rounded + border + soft shadow). */\n framed?: boolean;\n /** Render-prop that places a node inside each absolute-positioned well cell. */\n wrapWell?: (wellId: WellId, cellSize: number) => React.ReactNode;\n /** Wells to highlight (e.g. when hovering a legend item externally). */\n highlightedWellIds?: ReadonlySet<WellId>;\n onWellDoubleClick?: (wellId: WellId) => void;\n selectionFillMode?: \"selection\" | \"well\";\n flashWellId?: WellId;\n flashWellKey?: number;\n /** Fixed well size. When unset, the grid grows with the available width. */\n cellSize?: number;\n autoScale?: boolean;\n minCellSize?: number;\n maxCellSize?: number;\n /** Optional grouped well shortcuts rendered under the grid. */\n groups?: PlateMapGroupOption[];\n activeGroupId?: string;\n onGroupClick?: (group: PlateMapGroupOption) => void;\n className?: string;\n}\n\n/**\n * Card-agnostic plate grid panel. Renders the selection toolbar, hover\n * summary, the interactive `PlatePaintGrid`, and optional group shortcuts —\n * and owns the ephemeral hover state internally. The plate title, plate\n * selector, and actions menu are intentionally NOT part of this panel; compose\n * `PlateMapPlateSelector` and `PlateMapActionsMenu` around it for full layout\n * freedom.\n */\nexport function PlateMapGrid<T extends WellRecord = WellRecord>({\n format,\n rows,\n columns,\n values,\n selection,\n onSelectionChange,\n colorForWell,\n fields,\n renderHoverSummary,\n onHoveredWellChange,\n hoveredWellId,\n toolbar,\n hideSelectionControls = false,\n selectAllLabel = \"Select all\",\n deselectAllLabel = \"Deselect all\",\n emptyWellFillColor,\n wellShape,\n framed,\n wrapWell,\n highlightedWellIds,\n onWellDoubleClick,\n selectionFillMode,\n flashWellId,\n flashWellKey,\n cellSize,\n autoScale,\n minCellSize,\n maxCellSize,\n groups,\n activeGroupId,\n onGroupClick,\n className,\n}: PlateMapGridProps<T>) {\n const dims = resolveDimensions(format, rows, columns);\n const [internalHoverPos, setInternalHoverPos] = React.useState<WellId | null>(null);\n const isHoverControlled = hoveredWellId !== undefined;\n const hoverPos = isHoverControlled ? hoveredWellId : internalHoverPos;\n\n const selectAll = () => onSelectionChange(new Set(allPositions(dims)));\n const deselectAll = () => onSelectionChange(new Set());\n\n const hoverEntry = hoverPos ? values.get(hoverPos) : undefined;\n const hoverFields = hoverEntry && fields ? formatHoverFields(hoverEntry, fields) : [];\n const hoverSummary = hoverPos\n ? (renderHoverSummary?.(hoverEntry, hoverPos) ?? [hoverPos, ...hoverFields].join(\" • \"))\n : \" \";\n\n const showSelectionControls = !hideSelectionControls;\n const showToolbarRow = !!toolbar || showSelectionControls;\n\n return (\n <div data-slot=\"plate-map-grid\" className={cn(\"flex flex-col gap-1.5\", className)}>\n {showToolbarRow ? (\n <div className=\"flex flex-wrap items-center justify-start gap-3\">\n {toolbar}\n {showSelectionControls ? (\n <div className=\"flex items-center gap-2 text-xs\">\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={selectAll}\n >\n {selectAllLabel}\n </button>\n <span className=\"text-muted-foreground/60\">·</span>\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={deselectAll}\n >\n {deselectAllLabel}\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n <div className=\"h-5 text-xs text-muted-foreground\">{hoverSummary}</div>\n <PlatePaintGrid\n format={format}\n rows={rows}\n columns={columns}\n values={values}\n selection={selection}\n onSelectionChange={onSelectionChange}\n colorForWell={colorForWell}\n emptyWellFillColor={emptyWellFillColor}\n wellShape={wellShape}\n framed={framed}\n wrapWell={wrapWell}\n highlightedWellIds={highlightedWellIds}\n onWellHover={(wellId) => {\n if (!isHoverControlled) setInternalHoverPos(wellId);\n onHoveredWellChange?.(wellId);\n }}\n onWellDoubleClick={onWellDoubleClick}\n selectionFillMode={selectionFillMode}\n flashWellId={flashWellId}\n flashWellKey={flashWellKey}\n cellSize={cellSize}\n autoScale={autoScale}\n minCellSize={minCellSize}\n maxCellSize={maxCellSize}\n />\n {groups && groups.length > 0 ? (\n <>\n <Separator className=\"mt-2\" />\n <div className=\"flex max-h-28 flex-wrap gap-3 overflow-y-auto pt-1\">\n {groups.map((group) => {\n const isActive = group.id === activeGroupId;\n const count = group.count ?? group.wellIds?.length;\n return (\n <button\n key={group.id}\n type=\"button\"\n disabled={group.disabled}\n onClick={() => onGroupClick?.(group)}\n className={cn(\n \"flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors\",\n \"text-muted-foreground hover:bg-muted/60\",\n isActive && \"bg-muted text-foreground ring-1 ring-primary/40\",\n group.disabled && \"pointer-events-none opacity-50\",\n )}\n title={group.label}\n >\n <span\n className=\"size-7 rounded-full border\"\n style={{\n backgroundColor: group.color,\n borderColor: group.borderColor,\n }}\n aria-hidden\n />\n <span className=\"w-full truncate text-foreground\">{group.label}</span>\n {count === undefined ? null : (\n <span className=\"text-[0.7rem] leading-none text-muted-foreground\">{count} wells</span>\n )}\n </button>\n );\n })}\n </div>\n </>\n ) : null}\n </div>\n );\n}\n"],"names":["formatHoverFields","entry","fields","f","v","o","arr","item","PlateMapGrid","format","rows","columns","values","selection","onSelectionChange","colorForWell","renderHoverSummary","onHoveredWellChange","hoveredWellId","toolbar","hideSelectionControls","selectAllLabel","deselectAllLabel","emptyWellFillColor","wellShape","framed","wrapWell","highlightedWellIds","onWellDoubleClick","selectionFillMode","flashWellId","flashWellKey","cellSize","autoScale","minCellSize","maxCellSize","groups","activeGroupId","onGroupClick","className","dims","resolveDimensions","internalHoverPos","setInternalHoverPos","React","isHoverControlled","hoverPos","selectAll","allPositions","deselectAll","hoverEntry","hoverFields","hoverSummary","showSelectionControls","showToolbarRow","jsxs","cn","jsx","PlatePaintGrid","wellId","Fragment","Separator","group","isActive","count"],"mappings":"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"}
1
+ {"version":3,"file":"PlateMapGrid.js","sources":["../../../../src/components/composed/PlateMapEditor/PlateMapGrid.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { PlatePaintGrid } from \"./PlatePaintGrid\";\nimport { allPositions, resolveDimensions } from \"./wellGrid\";\n\nimport type { WellShape } from \"./PlatePaintGrid\";\nimport type { PlateFormat, PlateMapGroupOption, WellField, WellId, WellRecord } from \"./types\";\n\nimport { Separator } from \"@/components/ui/separator\";\nimport { cn } from \"@/lib/utils\";\n\nfunction formatHoverFields<T extends WellRecord>(entry: T, fields: WellField<T>[]): string[] {\n return fields\n .map((f) => {\n const v = entry[f.key];\n if (v === undefined || v === null || v === \"\") return null;\n if (f.kind === \"select\") {\n const opt = (f.options ?? []).find((o) => o.value === v);\n return opt?.label ?? String(v);\n }\n if (f.kind === \"multiselect\") {\n const arr = Array.isArray(v) ? (v as string[]) : [];\n if (arr.length === 0) return null;\n return arr.map((item) => (f.options ?? []).find((o) => o.value === item)?.label ?? item).join(\", \");\n }\n if (f.kind === \"boolean\") {\n return v ? f.label : null;\n }\n return String(v);\n })\n .filter(Boolean) as string[];\n}\n\nexport interface PlateMapGridProps<T extends WellRecord = WellRecord> {\n format: PlateFormat;\n rows?: number;\n columns?: number;\n values: Map<WellId, T>;\n selection: Set<WellId>;\n onSelectionChange: (next: Set<WellId>) => void;\n /** Resolves the SVG fill color for a well. */\n colorForWell: (well: T | undefined, wellId: WellId) => string;\n /** Field schema used to build the default hover summary string. */\n fields?: WellField<T>[];\n /** Custom hover summary for the strip above the grid. */\n renderHoverSummary?: (well: T | undefined, wellId: WellId) => React.ReactNode;\n /** Fires whenever the currently hovered well changes (null on leave). */\n onHoveredWellChange?: (wellId: WellId | null) => void;\n /**\n * Controlled hovered well id. When provided, the panel reflects this value\n * instead of tracking hover internally — useful for syncing the hover\n * summary with external state (e.g. resetting it on a plate switch).\n */\n hoveredWellId?: WellId | null;\n /** Controls rendered to the left of the built-in select/deselect links. */\n toolbar?: React.ReactNode;\n /** Hide the built-in \"Select all\" / \"Deselect all\" links. */\n hideSelectionControls?: boolean;\n selectAllLabel?: string;\n deselectAllLabel?: string;\n /** Fill color for empty wells. Pass `null` to delegate empty wells to `colorForWell`. */\n emptyWellFillColor?: string | null;\n /** Well shape forwarded to `PlatePaintGrid`. Defaults to `\"rect\"`. */\n wellShape?: WellShape;\n /** When true, wraps the grid in a card-like plate frame (rounded + border + soft shadow). */\n framed?: boolean;\n /** Render-prop that places a node inside each absolute-positioned well cell. */\n wrapWell?: (wellId: WellId, cellSize: number) => React.ReactNode;\n /** Wells to highlight (e.g. when hovering a legend item externally). */\n highlightedWellIds?: ReadonlySet<WellId>;\n onWellDoubleClick?: (wellId: WellId) => void;\n selectionFillMode?: \"selection\" | \"well\";\n flashWellId?: WellId;\n flashWellKey?: number;\n /** Fixed well size. When unset, the grid grows with the available width. */\n cellSize?: number;\n autoScale?: boolean;\n minCellSize?: number;\n maxCellSize?: number;\n /** Optional grouped well shortcuts rendered under the grid. */\n groups?: PlateMapGroupOption[];\n activeGroupId?: string;\n onGroupClick?: (group: PlateMapGroupOption) => void;\n className?: string;\n}\n\n/**\n * Card-agnostic plate grid panel. Renders the selection toolbar, hover\n * summary, the interactive `PlatePaintGrid`, and optional group shortcuts —\n * and owns the ephemeral hover state internally. The plate title, plate\n * selector, and actions menu are intentionally NOT part of this panel; compose\n * `PlateMapPlateSelector` and `PlateMapActionsMenu` around it for full layout\n * freedom.\n */\nexport function PlateMapGrid<T extends WellRecord = WellRecord>({\n format,\n rows,\n columns,\n values,\n selection,\n onSelectionChange,\n colorForWell,\n fields,\n renderHoverSummary,\n onHoveredWellChange,\n hoveredWellId,\n toolbar,\n hideSelectionControls = false,\n selectAllLabel = \"Select all\",\n deselectAllLabel = \"Deselect all\",\n emptyWellFillColor,\n wellShape,\n framed,\n wrapWell,\n highlightedWellIds,\n onWellDoubleClick,\n selectionFillMode,\n flashWellId,\n flashWellKey,\n cellSize,\n autoScale,\n minCellSize,\n maxCellSize,\n groups,\n activeGroupId,\n onGroupClick,\n className,\n}: PlateMapGridProps<T>) {\n const dims = resolveDimensions(format, rows, columns);\n const [internalHoverPos, setInternalHoverPos] = React.useState<WellId | null>(null);\n const isHoverControlled = hoveredWellId !== undefined;\n const hoverPos = isHoverControlled ? hoveredWellId : internalHoverPos;\n\n const selectAll = () => onSelectionChange(new Set(allPositions(dims)));\n const deselectAll = () => onSelectionChange(new Set());\n\n const hoverEntry = hoverPos ? values.get(hoverPos) : undefined;\n const hoverFields = hoverEntry && fields ? formatHoverFields(hoverEntry, fields) : [];\n const hoverSummary = hoverPos\n ? (renderHoverSummary?.(hoverEntry, hoverPos) ?? [hoverPos, ...hoverFields].join(\" • \"))\n : \" \";\n\n const showSelectionControls = !hideSelectionControls;\n const showToolbarRow = !!toolbar || showSelectionControls;\n\n return (\n <div data-slot=\"plate-map-grid\" className={cn(\"flex flex-col gap-1.5\", className)}>\n {showToolbarRow ? (\n <div className=\"flex flex-wrap items-center justify-start gap-3\">\n {toolbar}\n {showSelectionControls ? (\n <div className=\"flex items-center gap-2 text-xs\">\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={selectAll}\n >\n {selectAllLabel}\n </button>\n <span className=\"text-muted-foreground/60\">·</span>\n <button\n type=\"button\"\n className=\"font-medium text-primary underline-offset-2 hover:text-primary/80 hover:underline\"\n onClick={deselectAll}\n >\n {deselectAllLabel}\n </button>\n </div>\n ) : null}\n </div>\n ) : null}\n <div className=\"h-5 text-xs text-muted-foreground\">{hoverSummary}</div>\n <PlatePaintGrid\n format={format}\n rows={rows}\n columns={columns}\n values={values}\n selection={selection}\n onSelectionChange={onSelectionChange}\n colorForWell={colorForWell}\n emptyWellFillColor={emptyWellFillColor}\n wellShape={wellShape}\n framed={framed}\n wrapWell={wrapWell}\n highlightedWellIds={highlightedWellIds}\n onWellHover={(wellId) => {\n if (!isHoverControlled) setInternalHoverPos(wellId);\n onHoveredWellChange?.(wellId);\n }}\n onWellDoubleClick={onWellDoubleClick}\n selectionFillMode={selectionFillMode}\n flashWellId={flashWellId}\n flashWellKey={flashWellKey}\n cellSize={cellSize}\n autoScale={autoScale}\n minCellSize={minCellSize}\n maxCellSize={maxCellSize}\n />\n {groups && groups.length > 0 ? (\n <>\n <Separator className=\"mt-2\" />\n <div className=\"flex max-h-28 flex-wrap gap-3 overflow-y-auto pt-1\">\n {groups.map((group) => {\n const isActive = group.id === activeGroupId;\n const count = group.count ?? group.wellIds?.length;\n return (\n <button\n key={group.id}\n type=\"button\"\n disabled={group.disabled}\n onClick={() => onGroupClick?.(group)}\n className={cn(\n \"flex w-16 flex-col items-center gap-1 rounded-md px-1 py-1 text-center text-xs transition-colors\",\n \"text-muted-foreground hover:bg-accent/60\",\n isActive && \"bg-muted text-foreground ring-1 ring-primary/40\",\n group.disabled && \"pointer-events-none opacity-50\",\n )}\n title={group.label}\n >\n <span\n className=\"size-7 rounded-full border\"\n style={{\n backgroundColor: group.color,\n borderColor: group.borderColor,\n }}\n aria-hidden\n />\n <span className=\"w-full truncate text-foreground\">{group.label}</span>\n {count === undefined ? null : (\n <span className=\"text-[0.7rem] leading-none text-muted-foreground\">{count} wells</span>\n )}\n </button>\n );\n })}\n </div>\n </>\n ) : null}\n </div>\n );\n}\n"],"names":["formatHoverFields","entry","fields","f","v","o","arr","item","PlateMapGrid","format","rows","columns","values","selection","onSelectionChange","colorForWell","renderHoverSummary","onHoveredWellChange","hoveredWellId","toolbar","hideSelectionControls","selectAllLabel","deselectAllLabel","emptyWellFillColor","wellShape","framed","wrapWell","highlightedWellIds","onWellDoubleClick","selectionFillMode","flashWellId","flashWellKey","cellSize","autoScale","minCellSize","maxCellSize","groups","activeGroupId","onGroupClick","className","dims","resolveDimensions","internalHoverPos","setInternalHoverPos","React","isHoverControlled","hoverPos","selectAll","allPositions","deselectAll","hoverEntry","hoverFields","hoverSummary","showSelectionControls","showToolbarRow","jsxs","cn","jsx","PlatePaintGrid","wellId","Fragment","Separator","group","isActive","count"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),x=require("lucide-react"),g=require("react"),f=require("../../ui/button.cjs"),c=require("../../ui/card.cjs"),s=require("../../../lib/utils.cjs");function b(r){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const l in r)if(l!=="default"){const a=Object.getOwnPropertyDescriptor(r,l);Object.defineProperty(n,l,a.get?a:{enumerable:!0,get:()=>r[l]})}}return n.default=r,Object.freeze(n)}const j=b(g);function p({items:r,renderItem:n,onHoverEnter:l,onHoverLeave:a,onRemove:d,removeLabel:i="Remove",emptyLabel:u="No items",className:o}){return r.length===0?t.jsx("div",{className:s.cn("text-xs text-muted-foreground",o),"data-slot":"well-legend-empty",children:u}):t.jsx("div",{className:s.cn("flex flex-col gap-1.5",o),"data-slot":"well-legend",children:r.map(e=>n?t.jsx(j.Fragment,{children:n(e)},e.id):t.jsx(c.Card,{size:"sm","data-slot":"well-legend-item","data-disabled":e.disabled||void 0,className:s.cn("py-2 hover:bg-muted/40",e.disabled&&"opacity-50"),onMouseEnter:()=>l?.(e.id),onMouseLeave:()=>a?.(e.id),children:t.jsxs(c.CardContent,{className:"flex items-start gap-2",children:[t.jsx("span",{"aria-hidden":!0,className:"mt-0.5 size-3.5 shrink-0 rounded-sm border border-foreground/20",style:{backgroundColor:e.color}}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsx("div",{className:"truncate text-xs font-medium",children:e.label}),e.meta?t.jsx("div",{className:"truncate text-[0.65rem] text-muted-foreground",children:e.meta}):null]}),d?t.jsx(f.Button,{type:"button",variant:"ghost",size:"icon-xs","aria-label":`${i} ${typeof e.label=="string"?e.label:e.id}`,onClick:()=>d(e.id),children:t.jsx(x.X,{"aria-hidden":!0})}):null]})},e.id))})}exports.WellLegend=p;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),x=require("lucide-react"),g=require("react"),f=require("../../ui/button.cjs"),c=require("../../ui/card.cjs"),s=require("../../../lib/utils.cjs");function b(r){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const l in r)if(l!=="default"){const a=Object.getOwnPropertyDescriptor(r,l);Object.defineProperty(n,l,a.get?a:{enumerable:!0,get:()=>r[l]})}}return n.default=r,Object.freeze(n)}const j=b(g);function p({items:r,renderItem:n,onHoverEnter:l,onHoverLeave:a,onRemove:d,removeLabel:i="Remove",emptyLabel:u="No items",className:o}){return r.length===0?t.jsx("div",{className:s.cn("text-xs text-muted-foreground",o),"data-slot":"well-legend-empty",children:u}):t.jsx("div",{className:s.cn("flex flex-col gap-1.5",o),"data-slot":"well-legend",children:r.map(e=>n?t.jsx(j.Fragment,{children:n(e)},e.id):t.jsx(c.Card,{size:"sm","data-slot":"well-legend-item","data-disabled":e.disabled||void 0,className:s.cn("py-2 hover:bg-accent/40",e.disabled&&"opacity-50"),onMouseEnter:()=>l?.(e.id),onMouseLeave:()=>a?.(e.id),children:t.jsxs(c.CardContent,{className:"flex items-start gap-2",children:[t.jsx("span",{"aria-hidden":!0,className:"mt-0.5 size-3.5 shrink-0 rounded-sm border border-foreground/20",style:{backgroundColor:e.color}}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsx("div",{className:"truncate text-xs font-medium",children:e.label}),e.meta?t.jsx("div",{className:"truncate text-[0.65rem] text-muted-foreground",children:e.meta}):null]}),d?t.jsx(f.Button,{type:"button",variant:"ghost",size:"icon-xs","aria-label":`${i} ${typeof e.label=="string"?e.label:e.id}`,onClick:()=>d(e.id),children:t.jsx(x.X,{"aria-hidden":!0})}):null]})},e.id))})}exports.WellLegend=p;
2
2
  //# sourceMappingURL=WellLegend.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"WellLegend.cjs","sources":["../../../../src/components/composed/PlateMapEditor/WellLegend.tsx"],"sourcesContent":["import { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface WellLegendItem {\n id: string;\n label: React.ReactNode;\n color: string;\n /** Optional secondary text shown beneath the label. */\n meta?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport interface WellLegendProps {\n items: WellLegendItem[];\n /** Render-prop for fully custom cards. Bypasses the default card layout. */\n renderItem?: (item: WellLegendItem) => React.ReactNode;\n onHoverEnter?: (id: string) => void;\n onHoverLeave?: (id: string) => void;\n onRemove?: (id: string) => void;\n removeLabel?: string;\n emptyLabel?: string;\n className?: string;\n}\n\nexport function WellLegend({\n items,\n renderItem,\n onHoverEnter,\n onHoverLeave,\n onRemove,\n removeLabel = \"Remove\",\n emptyLabel = \"No items\",\n className,\n}: WellLegendProps) {\n if (items.length === 0) {\n return (\n <div className={cn(\"text-xs text-muted-foreground\", className)} data-slot=\"well-legend-empty\">\n {emptyLabel}\n </div>\n );\n }\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)} data-slot=\"well-legend\">\n {items.map((item) => {\n if (renderItem) return <React.Fragment key={item.id}>{renderItem(item)}</React.Fragment>;\n return (\n <Card\n key={item.id}\n size=\"sm\"\n data-slot=\"well-legend-item\"\n data-disabled={item.disabled || undefined}\n className={cn(\"py-2 hover:bg-muted/40\", item.disabled && \"opacity-50\")}\n onMouseEnter={() => onHoverEnter?.(item.id)}\n onMouseLeave={() => onHoverLeave?.(item.id)}\n >\n <CardContent className=\"flex items-start gap-2\">\n <span\n aria-hidden\n className=\"mt-0.5 size-3.5 shrink-0 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: item.color }}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-xs font-medium\">{item.label}</div>\n {item.meta ? (\n <div className=\"truncate text-[0.65rem] text-muted-foreground\">{item.meta}</div>\n ) : null}\n </div>\n {onRemove ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={`${removeLabel} ${typeof item.label === \"string\" ? item.label : item.id}`}\n onClick={() => onRemove(item.id)}\n >\n <X aria-hidden />\n </Button>\n ) : null}\n </CardContent>\n </Card>\n );\n })}\n </div>\n );\n}\n"],"names":["WellLegend","items","renderItem","onHoverEnter","onHoverLeave","onRemove","removeLabel","emptyLabel","className","jsx","cn","item","React","Card","jsxs","CardContent","Button","X"],"mappings":"giBA4BO,SAASA,EAAW,CACzB,MAAAC,EACA,WAAAC,EACA,aAAAC,EACA,aAAAC,EACA,SAAAC,EACA,YAAAC,EAAc,SACd,WAAAC,EAAa,WACb,UAAAC,CACF,EAAoB,CAClB,OAAIP,EAAM,SAAW,EAEjBQ,MAAC,OAAI,UAAWC,EAAAA,GAAG,gCAAiCF,CAAS,EAAG,YAAU,oBACvE,SAAAD,CAAA,CACH,EAKFE,EAAAA,IAAC,MAAA,CAAI,UAAWC,EAAAA,GAAG,wBAAyBF,CAAS,EAAG,YAAU,cAC/D,SAAAP,EAAM,IAAKU,GACNT,EAAmBO,MAACG,EAAM,SAAN,CAA8B,SAAAV,EAAWS,CAAI,GAAzBA,EAAK,EAAsB,EAErEF,EAAAA,IAACI,EAAAA,KAAA,CAEC,KAAK,KACL,YAAU,mBACV,gBAAeF,EAAK,UAAY,OAChC,UAAWD,EAAAA,GAAG,yBAA0BC,EAAK,UAAY,YAAY,EACrE,aAAc,IAAMR,IAAeQ,EAAK,EAAE,EAC1C,aAAc,IAAMP,IAAeO,EAAK,EAAE,EAE1C,SAAAG,EAAAA,KAACC,EAAAA,YAAA,CAAY,UAAU,yBACrB,SAAA,CAAAN,EAAAA,IAAC,OAAA,CACC,cAAW,GACX,UAAU,kEACV,MAAO,CAAE,gBAAiBE,EAAK,KAAA,CAAM,CAAA,EAEvCG,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAL,EAAAA,IAAC,MAAA,CAAI,UAAU,+BAAgC,SAAAE,EAAK,MAAM,EACzDA,EAAK,KACJF,MAAC,MAAA,CAAI,UAAU,gDAAiD,SAAAE,EAAK,KAAK,EACxE,IAAA,EACN,EACCN,EACCI,EAAAA,IAACO,EAAAA,OAAA,CACC,KAAK,SACL,QAAQ,QACR,KAAK,UACL,aAAY,GAAGV,CAAW,IAAI,OAAOK,EAAK,OAAU,SAAWA,EAAK,MAAQA,EAAK,EAAE,GACnF,QAAS,IAAMN,EAASM,EAAK,EAAE,EAE/B,SAAAF,EAAAA,IAACQ,EAAAA,EAAA,CAAE,cAAW,EAAA,CAAC,CAAA,CAAA,EAEf,IAAA,CAAA,CACN,CAAA,EA/BKN,EAAK,EAAA,CAkCf,CAAA,CACH,CAEJ"}
1
+ {"version":3,"file":"WellLegend.cjs","sources":["../../../../src/components/composed/PlateMapEditor/WellLegend.tsx"],"sourcesContent":["import { X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface WellLegendItem {\n id: string;\n label: React.ReactNode;\n color: string;\n /** Optional secondary text shown beneath the label. */\n meta?: React.ReactNode;\n disabled?: boolean;\n}\n\nexport interface WellLegendProps {\n items: WellLegendItem[];\n /** Render-prop for fully custom cards. Bypasses the default card layout. */\n renderItem?: (item: WellLegendItem) => React.ReactNode;\n onHoverEnter?: (id: string) => void;\n onHoverLeave?: (id: string) => void;\n onRemove?: (id: string) => void;\n removeLabel?: string;\n emptyLabel?: string;\n className?: string;\n}\n\nexport function WellLegend({\n items,\n renderItem,\n onHoverEnter,\n onHoverLeave,\n onRemove,\n removeLabel = \"Remove\",\n emptyLabel = \"No items\",\n className,\n}: WellLegendProps) {\n if (items.length === 0) {\n return (\n <div className={cn(\"text-xs text-muted-foreground\", className)} data-slot=\"well-legend-empty\">\n {emptyLabel}\n </div>\n );\n }\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)} data-slot=\"well-legend\">\n {items.map((item) => {\n if (renderItem) return <React.Fragment key={item.id}>{renderItem(item)}</React.Fragment>;\n return (\n <Card\n key={item.id}\n size=\"sm\"\n data-slot=\"well-legend-item\"\n data-disabled={item.disabled || undefined}\n className={cn(\"py-2 hover:bg-accent/40\", item.disabled && \"opacity-50\")}\n onMouseEnter={() => onHoverEnter?.(item.id)}\n onMouseLeave={() => onHoverLeave?.(item.id)}\n >\n <CardContent className=\"flex items-start gap-2\">\n <span\n aria-hidden\n className=\"mt-0.5 size-3.5 shrink-0 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: item.color }}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate text-xs font-medium\">{item.label}</div>\n {item.meta ? (\n <div className=\"truncate text-[0.65rem] text-muted-foreground\">{item.meta}</div>\n ) : null}\n </div>\n {onRemove ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={`${removeLabel} ${typeof item.label === \"string\" ? item.label : item.id}`}\n onClick={() => onRemove(item.id)}\n >\n <X aria-hidden />\n </Button>\n ) : null}\n </CardContent>\n </Card>\n );\n })}\n </div>\n );\n}\n"],"names":["WellLegend","items","renderItem","onHoverEnter","onHoverLeave","onRemove","removeLabel","emptyLabel","className","jsx","cn","item","React","Card","jsxs","CardContent","Button","X"],"mappings":"giBA4BO,SAASA,EAAW,CACzB,MAAAC,EACA,WAAAC,EACA,aAAAC,EACA,aAAAC,EACA,SAAAC,EACA,YAAAC,EAAc,SACd,WAAAC,EAAa,WACb,UAAAC,CACF,EAAoB,CAClB,OAAIP,EAAM,SAAW,EAEjBQ,MAAC,OAAI,UAAWC,EAAAA,GAAG,gCAAiCF,CAAS,EAAG,YAAU,oBACvE,SAAAD,CAAA,CACH,EAKFE,EAAAA,IAAC,MAAA,CAAI,UAAWC,EAAAA,GAAG,wBAAyBF,CAAS,EAAG,YAAU,cAC/D,SAAAP,EAAM,IAAKU,GACNT,EAAmBO,MAACG,EAAM,SAAN,CAA8B,SAAAV,EAAWS,CAAI,GAAzBA,EAAK,EAAsB,EAErEF,EAAAA,IAACI,EAAAA,KAAA,CAEC,KAAK,KACL,YAAU,mBACV,gBAAeF,EAAK,UAAY,OAChC,UAAWD,EAAAA,GAAG,0BAA2BC,EAAK,UAAY,YAAY,EACtE,aAAc,IAAMR,IAAeQ,EAAK,EAAE,EAC1C,aAAc,IAAMP,IAAeO,EAAK,EAAE,EAE1C,SAAAG,EAAAA,KAACC,EAAAA,YAAA,CAAY,UAAU,yBACrB,SAAA,CAAAN,EAAAA,IAAC,OAAA,CACC,cAAW,GACX,UAAU,kEACV,MAAO,CAAE,gBAAiBE,EAAK,KAAA,CAAM,CAAA,EAEvCG,EAAAA,KAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAL,EAAAA,IAAC,MAAA,CAAI,UAAU,+BAAgC,SAAAE,EAAK,MAAM,EACzDA,EAAK,KACJF,MAAC,MAAA,CAAI,UAAU,gDAAiD,SAAAE,EAAK,KAAK,EACxE,IAAA,EACN,EACCN,EACCI,EAAAA,IAACO,EAAAA,OAAA,CACC,KAAK,SACL,QAAQ,QACR,KAAK,UACL,aAAY,GAAGV,CAAW,IAAI,OAAOK,EAAK,OAAU,SAAWA,EAAK,MAAQA,EAAK,EAAE,GACnF,QAAS,IAAMN,EAASM,EAAK,EAAE,EAE/B,SAAAF,EAAAA,IAACQ,EAAAA,EAAA,CAAE,cAAW,EAAA,CAAC,CAAA,CAAA,EAEf,IAAA,CAAA,CACN,CAAA,EA/BKN,EAAK,EAAA,CAkCf,CAAA,CACH,CAEJ"}