@juv/codego-react-ui 3.2.8 → 3.3.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.
package/dist/index.cjs CHANGED
@@ -6527,15 +6527,16 @@ function validateField(field, value) {
6527
6527
  }
6528
6528
  function FieldRenderer({ field, value, onChange }) {
6529
6529
  if (field.render) return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children: field.render(value, onChange) });
6530
+ const toLabelValue = (o) => {
6531
+ if (typeof o === "string") return { label: o, value: o };
6532
+ if (Array.isArray(o)) return { label: o[0], value: o[1] };
6533
+ return o;
6534
+ };
6530
6535
  const strOptions = (field.options ?? []).map(
6531
- (o) => typeof o === "string" ? o : o.value
6532
- );
6533
- const comboOptions = (field.options ?? []).map(
6534
- (o) => typeof o === "string" ? { label: o, value: o } : o
6535
- );
6536
- const radioOptions = (field.options ?? []).map(
6537
- (o) => typeof o === "string" ? { label: o, value: o } : o
6536
+ (o) => typeof o === "string" ? o : Array.isArray(o) ? o[1] : o.value
6538
6537
  );
6538
+ const comboOptions = (field.options ?? []).map(toLabelValue);
6539
+ const radioOptions = (field.options ?? []).map(toLabelValue);
6539
6540
  switch (field.type) {
6540
6541
  case "textarea":
6541
6542
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Textarea, { value: value ?? "", onChange: (e) => onChange(e.target.value), placeholder: field.placeholder, rows: 3 });
@@ -6797,8 +6798,7 @@ function DeleteModal({
6797
6798
  itemId,
6798
6799
  onClose,
6799
6800
  onSuccess,
6800
- notif,
6801
- width
6801
+ notif
6802
6802
  }) {
6803
6803
  const [loading, setLoading] = React28.useState(false);
6804
6804
  const [error, setError] = React28.useState(null);
@@ -6820,7 +6820,7 @@ function DeleteModal({
6820
6820
  {
6821
6821
  title: "Confirm Delete",
6822
6822
  onClose,
6823
- width,
6823
+ width: "lg",
6824
6824
  footer: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
6825
6825
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Button, { variant: "outline", size: "sm", onClick: onClose, disabled: loading, children: "Cancel" }),
6826
6826
  /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Button, { variant: "danger", size: "sm", onClick: handleDelete, disabled: loading, children: [
@@ -6840,17 +6840,19 @@ function ActionBtn({
6840
6840
  defaultIcon,
6841
6841
  defaultLabel,
6842
6842
  defaultVariant,
6843
+ defaultSize,
6843
6844
  onClick
6844
6845
  }) {
6845
6846
  const mode = cfg?.displayMode ?? "icon";
6846
6847
  const icon = cfg?.icon ?? defaultIcon;
6847
6848
  const label = cfg?.label ?? defaultLabel;
6849
+ const buttonSize = cfg?.size ?? defaultSize ?? "xs";
6848
6850
  return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6849
6851
  Button,
6850
6852
  {
6851
6853
  type: "button",
6852
6854
  title: label,
6853
- size: cfg?.size ?? "xs",
6855
+ size: buttonSize,
6854
6856
  variant: cfg?.variant ?? defaultVariant,
6855
6857
  rounded: cfg?.rounded ?? "lg",
6856
6858
  gradientFrom: cfg?.gradientFrom,
@@ -6959,6 +6961,7 @@ function Table({
6959
6961
  defaultIcon: extra.icon,
6960
6962
  defaultLabel: extra.label ?? extra.key,
6961
6963
  defaultVariant: extra.variant ?? "outline",
6964
+ defaultSize: defaultActions.actionsSize,
6962
6965
  onClick: () => extra.onClick(item)
6963
6966
  },
6964
6967
  extra.key
@@ -7337,7 +7340,6 @@ function Table({
7337
7340
  baseUrl: defaultActions.baseUrl,
7338
7341
  itemId: String(deleteItem[actionIdKey] ?? ""),
7339
7342
  notif: defaultActions.onSuccessNotif,
7340
- width: defaultActions.modalWidth,
7341
7343
  onClose: () => setDeleteItem(null),
7342
7344
  onSuccess: (deleted) => {
7343
7345
  setTableData(
@@ -7433,17 +7435,19 @@ function ActionBtn2({
7433
7435
  defaultIcon,
7434
7436
  defaultLabel,
7435
7437
  defaultVariant,
7438
+ defaultSize,
7436
7439
  onClick
7437
7440
  }) {
7438
7441
  const mode = cfg?.displayMode ?? "icon";
7439
7442
  const icon = cfg?.icon ?? defaultIcon;
7440
7443
  const label = cfg?.label ?? defaultLabel;
7444
+ const buttonSize = cfg?.size ?? defaultSize ?? "xs";
7441
7445
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
7442
7446
  Button,
7443
7447
  {
7444
7448
  type: "button",
7445
7449
  title: label,
7446
- size: cfg?.size ?? "xs",
7450
+ size: buttonSize,
7447
7451
  variant: cfg?.variant ?? defaultVariant,
7448
7452
  rounded: cfg?.rounded ?? "lg",
7449
7453
  gradientFrom: cfg?.gradientFrom,
@@ -7487,15 +7491,16 @@ function DGModalShell({ title, onClose, children, footer, width = "lg" }) {
7487
7491
  }
7488
7492
  function DGFieldRenderer({ field, value, onChange }) {
7489
7493
  if (field.render) return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children: field.render(value, onChange) });
7494
+ const toLabelValue = (o) => {
7495
+ if (typeof o === "string") return { label: o, value: o };
7496
+ if (Array.isArray(o)) return { label: o[0], value: o[1] };
7497
+ return o;
7498
+ };
7490
7499
  const strOptions = (field.options ?? []).map(
7491
- (o) => typeof o === "string" ? o : o.value
7492
- );
7493
- const comboOptions = (field.options ?? []).map(
7494
- (o) => typeof o === "string" ? { label: o, value: o } : o
7495
- );
7496
- const radioOptions = (field.options ?? []).map(
7497
- (o) => typeof o === "string" ? { label: o, value: o } : o
7500
+ (o) => typeof o === "string" ? o : Array.isArray(o) ? o[1] : o.value
7498
7501
  );
7502
+ const comboOptions = (field.options ?? []).map(toLabelValue);
7503
+ const radioOptions = (field.options ?? []).map(toLabelValue);
7499
7504
  switch (field.type) {
7500
7505
  case "textarea":
7501
7506
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Textarea, { value: value ?? "", onChange: (e) => onChange(e.target.value), placeholder: field.placeholder, rows: 3 });
@@ -7666,8 +7671,7 @@ function DGDeleteModal({
7666
7671
  itemId,
7667
7672
  onClose,
7668
7673
  onSuccess,
7669
- notif,
7670
- width
7674
+ notif
7671
7675
  }) {
7672
7676
  const [loading, setLoading] = React29.useState(false);
7673
7677
  const [error, setError] = React29.useState(null);
@@ -7689,7 +7693,7 @@ function DGDeleteModal({
7689
7693
  {
7690
7694
  title: "Confirm Delete",
7691
7695
  onClose,
7692
- width,
7696
+ width: "lg",
7693
7697
  footer: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
7694
7698
  /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("button", { onClick: onClose, disabled: loading, className: "px-4 py-1.5 text-sm rounded-xl border border-border hover:bg-accent transition-colors", children: "Cancel" }),
7695
7699
  /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("button", { onClick: handleDelete, disabled: loading, className: "px-4 py-1.5 text-sm rounded-xl bg-danger text-danger-foreground hover:bg-danger-hover transition-colors flex items-center gap-1.5", children: [
@@ -7810,6 +7814,7 @@ function DataGrid({
7810
7814
  defaultIcon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.Eye, { className: "h-3.5 w-3.5" }),
7811
7815
  defaultLabel: "View",
7812
7816
  defaultVariant: "outline",
7817
+ defaultSize: defaultActions.actionsSize,
7813
7818
  onClick: () => setViewItem(row)
7814
7819
  }
7815
7820
  ),
@@ -7820,6 +7825,7 @@ function DataGrid({
7820
7825
  defaultIcon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.Pencil, { className: "h-3.5 w-3.5" }),
7821
7826
  defaultLabel: "Edit",
7822
7827
  defaultVariant: "outline",
7828
+ defaultSize: defaultActions.actionsSize,
7823
7829
  onClick: () => setEditItem(row)
7824
7830
  }
7825
7831
  ),
@@ -7830,6 +7836,7 @@ function DataGrid({
7830
7836
  defaultIcon: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_lucide_react18.Trash, { className: "h-3.5 w-3.5" }),
7831
7837
  defaultLabel: "Delete",
7832
7838
  defaultVariant: "danger",
7839
+ defaultSize: defaultActions.actionsSize,
7833
7840
  onClick: () => setDeleteItem(row)
7834
7841
  }
7835
7842
  ),
@@ -7840,6 +7847,7 @@ function DataGrid({
7840
7847
  defaultIcon: extra.icon,
7841
7848
  defaultLabel: extra.label ?? extra.key,
7842
7849
  defaultVariant: extra.variant ?? "outline",
7850
+ defaultSize: defaultActions.actionsSize,
7843
7851
  onClick: () => extra.onClick(row)
7844
7852
  },
7845
7853
  extra.key
@@ -8073,7 +8081,6 @@ function DataGrid({
8073
8081
  baseUrl: defaultActions.baseUrl,
8074
8082
  itemId: String(deleteItem[actionIdKey] ?? ""),
8075
8083
  notif: defaultActions.onSuccessNotif,
8076
- width: defaultActions.modalWidth,
8077
8084
  onClose: () => setDeleteItem(null),
8078
8085
  onSuccess: (deleted) => {
8079
8086
  setTableData((prev) => prev.filter((r) => String(r[actionIdKey]) !== String(deleted[actionIdKey])));
@@ -10877,6 +10884,8 @@ var useTheme = () => {
10877
10884
  // src/components/ui/panel.tsx
10878
10885
  var import_jsx_runtime46 = require("react/jsx-runtime");
10879
10886
  var PanelCollapsedContext = React40.createContext(false);
10887
+ var PanelGroupsContext = React40.createContext({ expandedGroups: /* @__PURE__ */ new Set(), onGroupToggle: () => {
10888
+ } });
10880
10889
  function PanelThemeToggle() {
10881
10890
  const { theme, setTheme } = useTheme();
10882
10891
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
@@ -10903,15 +10912,109 @@ function Panel({
10903
10912
  topbar,
10904
10913
  topbarTrailing,
10905
10914
  defaultCollapsed = false,
10915
+ collapsed: controlledCollapsed,
10916
+ onCollapsedChange,
10906
10917
  collapsible = false,
10907
10918
  showThemeToggle = false,
10908
10919
  defaultPage,
10920
+ currentPage: controlledPage,
10921
+ onPageChange,
10909
10922
  height = "h-[520px]",
10910
10923
  children,
10911
- className
10924
+ className,
10925
+ loading = false,
10926
+ emptyState,
10927
+ error = null,
10928
+ showGroupDividers = false,
10929
+ expandedGroups: controlledExpandedGroups,
10930
+ onGroupToggle,
10931
+ theme: themeProp,
10932
+ collapseIcon,
10933
+ expandIcon,
10934
+ meta,
10935
+ actions,
10936
+ keyboardNavigation = false,
10937
+ draggable = false,
10938
+ onSidebarReorder,
10939
+ animationDuration = 200,
10940
+ animationEasing = "ease-in-out",
10941
+ sidebarTooltip,
10942
+ mobileBreakpoint = 768,
10943
+ mobileCollapsed: controlledMobileCollapsed,
10944
+ onMobileCollapseChange
10912
10945
  }) {
10913
- const [collapsed, setCollapsed] = React40.useState(defaultCollapsed);
10914
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PanelCollapsedContext.Provider, { value: collapsed, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
10946
+ const [internalCollapsed, setInternalCollapsed] = React40.useState(defaultCollapsed);
10947
+ const [internalPage, setInternalPage] = React40.useState(defaultPage || "");
10948
+ const [internalExpandedGroups, setInternalExpandedGroups] = React40.useState(
10949
+ new Set(controlledExpandedGroups)
10950
+ );
10951
+ const [isMobile, setIsMobile] = React40.useState(false);
10952
+ const [internalMobileCollapsed, setInternalMobileCollapsed] = React40.useState(true);
10953
+ const isCollapsed = controlledCollapsed !== void 0 ? controlledCollapsed : internalCollapsed;
10954
+ const currentPage = controlledPage !== void 0 ? controlledPage : internalPage;
10955
+ const expandedGroups = controlledExpandedGroups !== void 0 ? new Set(controlledExpandedGroups) : internalExpandedGroups;
10956
+ const mobileCollapsed = controlledMobileCollapsed !== void 0 ? controlledMobileCollapsed : internalMobileCollapsed;
10957
+ const handleCollapsedChange = (value) => {
10958
+ if (controlledCollapsed === void 0) setInternalCollapsed(value);
10959
+ onCollapsedChange?.(value);
10960
+ };
10961
+ const handlePageChange = (page) => {
10962
+ if (controlledPage === void 0) setInternalPage(page);
10963
+ onPageChange?.(page);
10964
+ };
10965
+ const handleGroupToggle = (title, expanded) => {
10966
+ if (controlledExpandedGroups === void 0) {
10967
+ setInternalExpandedGroups((prev) => {
10968
+ const next = new Set(prev);
10969
+ if (expanded) next.add(title);
10970
+ else next.delete(title);
10971
+ return next;
10972
+ });
10973
+ }
10974
+ onGroupToggle?.(title, expanded);
10975
+ };
10976
+ const handleMobileCollapseChange = (value) => {
10977
+ if (controlledMobileCollapsed === void 0) setInternalMobileCollapsed(value);
10978
+ onMobileCollapseChange?.(value);
10979
+ };
10980
+ React40.useEffect(() => {
10981
+ const handleResize = () => {
10982
+ const mobile = window.innerWidth < mobileBreakpoint;
10983
+ setIsMobile(mobile);
10984
+ if (mobile && !internalMobileCollapsed) {
10985
+ handleMobileCollapseChange(true);
10986
+ }
10987
+ };
10988
+ handleResize();
10989
+ window.addEventListener("resize", handleResize);
10990
+ return () => window.removeEventListener("resize", handleResize);
10991
+ }, [mobileBreakpoint, internalMobileCollapsed]);
10992
+ const handleKeyDown = React40.useCallback(
10993
+ (e) => {
10994
+ if (!keyboardNavigation) return;
10995
+ if (e.key === "Escape" && !isCollapsed && collapsible) {
10996
+ handleCollapsedChange(true);
10997
+ }
10998
+ if (e.key === "Enter" && isCollapsed && collapsible) {
10999
+ handleCollapsedChange(false);
11000
+ }
11001
+ },
11002
+ [keyboardNavigation, isCollapsed, collapsible]
11003
+ );
11004
+ React40.useEffect(() => {
11005
+ if (keyboardNavigation) {
11006
+ window.addEventListener("keydown", handleKeyDown);
11007
+ return () => window.removeEventListener("keydown", handleKeyDown);
11008
+ }
11009
+ }, [keyboardNavigation, handleKeyDown]);
11010
+ const effectiveCollapsed = isMobile ? mobileCollapsed : isCollapsed;
11011
+ const animStyle = {
11012
+ transitionDuration: `${animationDuration}ms`,
11013
+ transitionTimingFunction: animationEasing
11014
+ };
11015
+ const hasContent = React40.Children.count(children) > 0;
11016
+ const showEmpty = !loading && !hasContent && emptyState;
11017
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PanelCollapsedContext.Provider, { value: effectiveCollapsed, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PanelGroupsContext.Provider, { value: { expandedGroups, onGroupToggle: handleGroupToggle }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
10915
11018
  "div",
10916
11019
  {
10917
11020
  className: cn(
@@ -10919,6 +11022,7 @@ function Panel({
10919
11022
  height,
10920
11023
  className
10921
11024
  ),
11025
+ style: { ...animStyle },
10922
11026
  children: [
10923
11027
  /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "pointer-events-none absolute inset-0 overflow-hidden", children: [
10924
11028
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "absolute -top-[40%] -left-[20%] h-[80%] w-[60%] rounded-full bg-primary/10 blur-[120px]" }),
@@ -10928,23 +11032,36 @@ function Panel({
10928
11032
  "aside",
10929
11033
  {
10930
11034
  className: cn(
10931
- "relative z-10 flex flex-col shrink-0 border-r border-border transition-all duration-200",
10932
- collapsed ? "w-14" : sidebarWidth
11035
+ "relative z-10 flex flex-col shrink-0 border-r border-border transition-all",
11036
+ effectiveCollapsed ? "w-14" : sidebarWidth
10933
11037
  ),
11038
+ style: { transitionDuration: `${animationDuration}ms`, transitionTimingFunction: animationEasing },
10934
11039
  children: [
10935
- (sidebarBrand || sidebarHeader) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: cn(
10936
- "shrink-0 border-b border-border",
10937
- collapsed ? "flex items-center justify-center py-3" : "flex items-center gap-2 px-4 py-3"
10938
- ), children: sidebarBrand ? collapsed ? sidebarBrand.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarBrand.image, alt: "logo", className: "h-7 w-7 rounded-md object-cover shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarBrand.icon }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
10939
- sidebarBrand.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarBrand.image, alt: "logo", className: "h-7 w-7 rounded-md object-cover shrink-0" }) : sidebarBrand.icon && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarBrand.icon }),
10940
- sidebarBrand.title && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex-1 truncate text-sm font-semibold", children: sidebarBrand.title }),
10941
- sidebarBrand.trailing && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarBrand.trailing })
10942
- ] }) : !collapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "text-sm font-semibold", children: sidebarHeader }) }),
11040
+ (sidebarBrand || sidebarHeader) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
11041
+ "div",
11042
+ {
11043
+ className: cn(
11044
+ "shrink-0 border-b border-border",
11045
+ effectiveCollapsed ? "flex items-center justify-center py-3" : "flex items-center gap-2 px-4 py-3"
11046
+ ),
11047
+ children: sidebarBrand ? effectiveCollapsed ? sidebarBrand.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarBrand.image, alt: "logo", className: "h-7 w-7 rounded-md object-cover shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarBrand.icon }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(import_jsx_runtime46.Fragment, { children: [
11048
+ sidebarBrand.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarBrand.image, alt: "logo", className: "h-7 w-7 rounded-md object-cover shrink-0" }) : sidebarBrand.icon && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarBrand.icon }),
11049
+ sidebarBrand.title && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "flex-1 truncate text-sm font-semibold", children: sidebarBrand.title }),
11050
+ sidebarBrand.trailing && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarBrand.trailing })
11051
+ ] }) : !effectiveCollapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "text-sm font-semibold", children: sidebarHeader })
11052
+ }
11053
+ ),
10943
11054
  /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex-1 overflow-y-auto py-2", children: sidebar }),
10944
- (sidebarProfile || sidebarFooter) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: cn(
10945
- "shrink-0 border-t border-border",
10946
- collapsed ? "flex items-center justify-center py-3" : "px-4 py-3"
10947
- ), children: sidebarProfile ? collapsed ? sidebarProfile.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarProfile.image, alt: "profile", className: "h-7 w-7 rounded-full object-cover shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarProfile.icon }) : sidebarProfile.content ?? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex items-center gap-2", children: sidebarProfile.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarProfile.image, alt: "profile", className: "h-7 w-7 rounded-full object-cover shrink-0" }) : sidebarProfile.icon && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarProfile.icon }) }) : !collapsed && sidebarFooter })
11055
+ (sidebarProfile || sidebarFooter) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
11056
+ "div",
11057
+ {
11058
+ className: cn(
11059
+ "shrink-0 border-t border-border",
11060
+ effectiveCollapsed ? "flex items-center justify-center py-3" : "px-4 py-3"
11061
+ ),
11062
+ children: sidebarProfile ? effectiveCollapsed ? sidebarProfile.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarProfile.image, alt: "profile", className: "h-7 w-7 rounded-full object-cover shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarProfile.icon }) : sidebarProfile.content ?? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex items-center gap-2", children: sidebarProfile.image ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("img", { src: sidebarProfile.image, alt: "profile", className: "h-7 w-7 rounded-full object-cover shrink-0" }) : sidebarProfile.icon && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { className: "shrink-0", children: sidebarProfile.icon }) }) : !effectiveCollapsed && sidebarFooter
11063
+ }
11064
+ )
10948
11065
  ]
10949
11066
  }
10950
11067
  ),
@@ -10954,16 +11071,22 @@ function Panel({
10954
11071
  collapsible && sidebar && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
10955
11072
  Tooltip,
10956
11073
  {
10957
- content: collapsed ? "Expand sidebar" : "Collapse sidebar",
11074
+ content: effectiveCollapsed ? "Expand sidebar" : "Collapse sidebar",
10958
11075
  side: "bottom",
10959
11076
  children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
10960
11077
  "button",
10961
11078
  {
10962
11079
  type: "button",
10963
- onClick: () => setCollapsed((c) => !c),
11080
+ onClick: () => {
11081
+ if (isMobile) {
11082
+ handleMobileCollapseChange(!mobileCollapsed);
11083
+ } else {
11084
+ handleCollapsedChange(!isCollapsed);
11085
+ }
11086
+ },
10964
11087
  className: "text-muted-foreground hover:text-foreground transition-colors",
10965
- "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
10966
- children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react25.PanelLeftOpen, { className: "h-5 w-5" }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react25.PanelLeftClose, { className: "h-5 w-5" })
11088
+ "aria-label": effectiveCollapsed ? "Expand sidebar" : "Collapse sidebar",
11089
+ children: effectiveCollapsed ? expandIcon || /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react25.PanelLeftOpen, { className: "h-5 w-5" }) : collapseIcon || /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react25.PanelLeftClose, { className: "h-5 w-5" })
10967
11090
  }
10968
11091
  )
10969
11092
  }
@@ -10975,11 +11098,16 @@ function Panel({
10975
11098
  showThemeToggle && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(PanelThemeToggle, {})
10976
11099
  ] })
10977
11100
  ] }),
10978
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("main", { className: "flex-1 overflow-y-auto p-4", children })
11101
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("main", { className: "flex-1 overflow-y-auto p-4", children: [
11102
+ error && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "mb-4 p-3 rounded-md bg-destructive/10 text-destructive text-sm", children: error }),
11103
+ loading && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(import_lucide_react25.Loader2, { className: "h-6 w-6 animate-spin text-muted-foreground" }) }),
11104
+ showEmpty && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "flex items-center justify-center h-full text-muted-foreground", children: emptyState }),
11105
+ !loading && !showEmpty && children
11106
+ ] })
10979
11107
  ] })
10980
11108
  ]
10981
11109
  }
10982
- ) });
11110
+ ) }) });
10983
11111
  }
10984
11112
  function PanelSidebarItem({
10985
11113
  icon: Icon,
@@ -11010,10 +11138,20 @@ function PanelSidebarGroup({
11010
11138
  children
11011
11139
  }) {
11012
11140
  const collapsed = React40.useContext(PanelCollapsedContext);
11141
+ const { expandedGroups, onGroupToggle } = React40.useContext(PanelGroupsContext);
11142
+ const isExpanded = title ? expandedGroups.has(title) : true;
11013
11143
  return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("div", { className: "px-2 py-1", children: [
11014
- title && !collapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("p", { className: "mb-1 px-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground", children: title }),
11144
+ title && !collapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
11145
+ "button",
11146
+ {
11147
+ type: "button",
11148
+ onClick: () => onGroupToggle(title, !isExpanded),
11149
+ className: "mb-1 px-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground hover:text-foreground transition-colors w-full text-left",
11150
+ children: title
11151
+ }
11152
+ ),
11015
11153
  title && collapsed && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("div", { className: "mx-1 mb-1 h-px bg-border" }),
11016
- /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("main", { className: "space-y-0.5", children })
11154
+ (!title || isExpanded) && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("main", { className: "space-y-0.5", children })
11017
11155
  ] });
11018
11156
  }
11019
11157