@mshuja288/aksuicore 0.3.0 → 0.4.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
@@ -517,31 +517,48 @@ function Snackbar({
517
517
  );
518
518
  }
519
519
  var StatusMessage = Snackbar;
520
+ function MenuIcon({ open }) {
521
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: open ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 5l10 10M15 5 5 15", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.5 5.5h13M3.5 10h13M3.5 14.5h13", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }) });
522
+ }
520
523
  function Topbar({
521
524
  title,
522
525
  logoSrc,
523
526
  logoAlt = "Logo",
524
527
  username = "",
525
528
  onLogout,
529
+ showMenuButton = false,
530
+ menuOpen = false,
531
+ onMenuClick,
526
532
  children
527
533
  }) {
528
- const [menuOpen, setMenuOpen] = react.useState(false);
534
+ const [accountOpen, setAccountOpen] = react.useState(false);
529
535
  const menuRef = react.useRef(null);
530
536
  const initial = (username || "U").slice(0, 1).toUpperCase();
531
537
  react.useEffect(() => {
532
- if (!menuOpen) {
538
+ if (!accountOpen) {
533
539
  return;
534
540
  }
535
541
  function onPointerDown(event) {
536
542
  if (menuRef.current && !menuRef.current.contains(event.target)) {
537
- setMenuOpen(false);
543
+ setAccountOpen(false);
538
544
  }
539
545
  }
540
546
  document.addEventListener("mousedown", onPointerDown);
541
547
  return () => document.removeEventListener("mousedown", onPointerDown);
542
- }, [menuOpen]);
548
+ }, [accountOpen]);
543
549
  return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "topbar", children: [
544
550
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "topbar-brand", children: [
551
+ showMenuButton && onMenuClick ? /* @__PURE__ */ jsxRuntime.jsx(
552
+ "button",
553
+ {
554
+ type: "button",
555
+ className: "ghost topbar-menu-button",
556
+ "aria-label": menuOpen ? "Close navigation menu" : "Open navigation menu",
557
+ "aria-expanded": menuOpen,
558
+ onClick: onMenuClick,
559
+ children: /* @__PURE__ */ jsxRuntime.jsx(MenuIcon, { open: menuOpen })
560
+ }
561
+ ) : null,
545
562
  logoSrc ? /* @__PURE__ */ jsxRuntime.jsx(
546
563
  "img",
547
564
  {
@@ -564,13 +581,13 @@ function Topbar({
564
581
  type: "button",
565
582
  className: "avatar-button",
566
583
  "aria-haspopup": "menu",
567
- "aria-expanded": menuOpen,
568
- onClick: () => setMenuOpen((open) => !open),
584
+ "aria-expanded": accountOpen,
585
+ onClick: () => setAccountOpen((open) => !open),
569
586
  title: username || "Account",
570
587
  children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "avatar", children: initial })
571
588
  }
572
589
  ),
573
- menuOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "avatar-menu", role: "menu", children: [
590
+ accountOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "avatar-menu", role: "menu", children: [
574
591
  username ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "avatar-name", children: username }) : null,
575
592
  /* @__PURE__ */ jsxRuntime.jsx(
576
593
  Button,
@@ -578,7 +595,7 @@ function Topbar({
578
595
  variant: "ghost",
579
596
  role: "menuitem",
580
597
  onClick: () => {
581
- setMenuOpen(false);
598
+ setAccountOpen(false);
582
599
  onLogout();
583
600
  },
584
601
  children: "Logout"
@@ -593,9 +610,10 @@ function SideNav({
593
610
  items,
594
611
  activeId,
595
612
  onSelect,
596
- label = "Sections"
613
+ label = "Sections",
614
+ className = ""
597
615
  }) {
598
- return /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "side-nav", "aria-label": label, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
616
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { className: ["side-nav", className].filter(Boolean).join(" "), "aria-label": label, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
599
617
  "button",
600
618
  {
601
619
  type: "button",
@@ -697,28 +715,131 @@ function AppShell({
697
715
  activeNavId,
698
716
  onNavSelect,
699
717
  navLabel = "Sections",
700
- showBottomNav = true,
718
+ mobileNav = "drawer",
719
+ showBottomNav,
720
+ navDrawerOpen,
721
+ onNavDrawerOpenChange,
701
722
  topbarActions,
702
723
  children,
703
724
  screenClassName = ""
704
725
  }) {
705
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "aksui-root app-shell", children: [
706
- /* @__PURE__ */ jsxRuntime.jsx(Topbar, { title, logoSrc, logoAlt, username, onLogout, children: topbarActions }),
707
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "app-body", children: [
708
- /* @__PURE__ */ jsxRuntime.jsx(SideNav, { items: navItems, activeId: activeNavId, onSelect: onNavSelect, label: navLabel }),
709
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: ["screen", screenClassName].filter(Boolean).join(" "), children })
710
- ] }),
711
- showBottomNav ? /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "bottom-nav", "aria-label": navLabel, children: navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
712
- "button",
713
- {
714
- type: "button",
715
- className: activeNavId === item.id ? "active" : "",
716
- onClick: () => onNavSelect(item.id),
717
- children: item.short ?? item.label
718
- },
719
- item.id
720
- )) }) : null
721
- ] });
726
+ const [internalDrawerOpen, setInternalDrawerOpen] = react.useState(false);
727
+ const drawerControlled = navDrawerOpen !== void 0;
728
+ const drawerOpen = drawerControlled ? navDrawerOpen : internalDrawerOpen;
729
+ const useBottomNav = showBottomNav ?? (mobileNav === "bottom" || mobileNav === "hybrid");
730
+ const useDrawer = mobileNav === "drawer" || mobileNav === "hybrid";
731
+ const activeItem = navItems.find((item) => item.id === activeNavId);
732
+ function setDrawerOpen(open) {
733
+ if (!drawerControlled) {
734
+ setInternalDrawerOpen(open);
735
+ }
736
+ onNavDrawerOpenChange?.(open);
737
+ }
738
+ react.useEffect(() => {
739
+ if (!drawerOpen) {
740
+ return;
741
+ }
742
+ function onKeyDown(event) {
743
+ if (event.key === "Escape") {
744
+ if (!drawerControlled) {
745
+ setInternalDrawerOpen(false);
746
+ }
747
+ onNavDrawerOpenChange?.(false);
748
+ }
749
+ }
750
+ document.addEventListener("keydown", onKeyDown);
751
+ const previousOverflow = document.body.style.overflow;
752
+ document.body.style.overflow = "hidden";
753
+ return () => {
754
+ document.removeEventListener("keydown", onKeyDown);
755
+ document.body.style.overflow = previousOverflow;
756
+ };
757
+ }, [drawerControlled, drawerOpen, onNavDrawerOpenChange]);
758
+ function selectNav(id) {
759
+ onNavSelect(id);
760
+ setDrawerOpen(false);
761
+ }
762
+ return /* @__PURE__ */ jsxRuntime.jsxs(
763
+ "div",
764
+ {
765
+ className: [
766
+ "aksui-root",
767
+ "app-shell",
768
+ `mobile-nav-${mobileNav}`,
769
+ useBottomNav ? "has-bottom-nav" : "",
770
+ drawerOpen ? "nav-drawer-open" : ""
771
+ ].filter(Boolean).join(" "),
772
+ children: [
773
+ /* @__PURE__ */ jsxRuntime.jsx(
774
+ Topbar,
775
+ {
776
+ title,
777
+ logoSrc,
778
+ logoAlt,
779
+ username,
780
+ onLogout,
781
+ showMenuButton: useDrawer,
782
+ menuOpen: drawerOpen,
783
+ onMenuClick: () => setDrawerOpen(!drawerOpen),
784
+ children: topbarActions
785
+ }
786
+ ),
787
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "app-body", children: [
788
+ /* @__PURE__ */ jsxRuntime.jsx(SideNav, { items: navItems, activeId: activeNavId, onSelect: onNavSelect, label: navLabel }),
789
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ["screen", screenClassName].filter(Boolean).join(" "), children })
790
+ ] }),
791
+ useDrawer ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
792
+ /* @__PURE__ */ jsxRuntime.jsx(
793
+ "button",
794
+ {
795
+ type: "button",
796
+ className: drawerOpen ? "nav-drawer-backdrop open" : "nav-drawer-backdrop",
797
+ "aria-label": "Close navigation menu",
798
+ tabIndex: drawerOpen ? 0 : -1,
799
+ onClick: () => setDrawerOpen(false)
800
+ }
801
+ ),
802
+ /* @__PURE__ */ jsxRuntime.jsxs(
803
+ "aside",
804
+ {
805
+ className: drawerOpen ? "nav-drawer open" : "nav-drawer",
806
+ "aria-label": navLabel,
807
+ "aria-hidden": !drawerOpen,
808
+ children: [
809
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nav-drawer-head", children: [
810
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "nav-drawer-title", children: navLabel }),
811
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost nav-drawer-close", onClick: () => setDrawerOpen(false), children: "Close" })
812
+ ] }),
813
+ /* @__PURE__ */ jsxRuntime.jsx(
814
+ SideNav,
815
+ {
816
+ className: "nav-drawer-nav",
817
+ items: navItems,
818
+ activeId: activeNavId,
819
+ onSelect: selectNav,
820
+ label: navLabel
821
+ }
822
+ )
823
+ ]
824
+ }
825
+ )
826
+ ] }) : null,
827
+ useBottomNav ? /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "bottom-nav", "aria-label": navLabel, children: mobileNav === "hybrid" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
828
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "active bottom-nav-current", disabled: true, children: activeItem?.short ?? activeItem?.label ?? "Section" }),
829
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "bottom-nav-menu", onClick: () => setDrawerOpen(true), children: "Menu" })
830
+ ] }) : navItems.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
831
+ "button",
832
+ {
833
+ type: "button",
834
+ className: activeNavId === item.id ? "active" : "",
835
+ onClick: () => onNavSelect(item.id),
836
+ children: item.short ?? item.label
837
+ },
838
+ item.id
839
+ )) }) : null
840
+ ]
841
+ }
842
+ );
722
843
  }
723
844
  function useIsClient2() {
724
845
  return react.useSyncExternalStore(
@@ -728,11 +849,57 @@ function useIsClient2() {
728
849
  () => false
729
850
  );
730
851
  }
852
+ function useHoverTooltipsEnabled() {
853
+ return react.useSyncExternalStore(
854
+ (onStoreChange) => {
855
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
856
+ return () => {
857
+ };
858
+ }
859
+ const media = window.matchMedia("(hover: hover) and (pointer: fine)");
860
+ media.addEventListener("change", onStoreChange);
861
+ return () => media.removeEventListener("change", onStoreChange);
862
+ },
863
+ () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(hover: hover) and (pointer: fine)").matches,
864
+ () => false
865
+ );
866
+ }
731
867
  var EXPORT_FORMAT_OPTIONS = [
732
868
  { format: "csv", label: "CSV" },
733
869
  { format: "xlsx", label: "Excel" },
734
870
  { format: "json", label: "JSON" }
735
871
  ];
872
+ function defaultVisibleKeys(columns) {
873
+ return columns.filter((column) => column.defaultVisible !== false).map((column) => column.key);
874
+ }
875
+ function readStoredColumnKeys(prefsKey, fallback, allowed) {
876
+ if (!prefsKey || typeof window === "undefined") {
877
+ return fallback;
878
+ }
879
+ try {
880
+ const raw = window.localStorage.getItem(prefsKey);
881
+ if (!raw) {
882
+ return fallback;
883
+ }
884
+ const parsed = JSON.parse(raw);
885
+ if (!Array.isArray(parsed)) {
886
+ return fallback;
887
+ }
888
+ const keys = parsed.filter((entry) => typeof entry === "string" && allowed.has(entry));
889
+ return keys.length > 0 ? keys : fallback;
890
+ } catch {
891
+ return fallback;
892
+ }
893
+ }
894
+ function writeStoredColumnKeys(prefsKey, keys) {
895
+ if (!prefsKey || typeof window === "undefined") {
896
+ return;
897
+ }
898
+ try {
899
+ window.localStorage.setItem(prefsKey, JSON.stringify(keys));
900
+ } catch {
901
+ }
902
+ }
736
903
  function compareColumnValues(column, left, right) {
737
904
  const leftRaw = column.display ? column.display(left) : column.value(left);
738
905
  const rightRaw = column.display ? column.display(right) : column.value(right);
@@ -766,6 +933,9 @@ function ResetIcon() {
766
933
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 4.2v4h4", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" })
767
934
  ] });
768
935
  }
936
+ function ColumnsIcon() {
937
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4.5h3.5v11H4zM8.25 4.5h3.5v11h-3.5zM12.5 4.5H16v11h-3.5z", fill: "none", stroke: "currentColor", strokeWidth: "1.5" }) });
938
+ }
769
939
  function ChevronIcon({ open }) {
770
940
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { className: open ? "side-rail-chevron open" : "side-rail-chevron", viewBox: "0 0 20 20", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 4.5 13.5 10 8 15.5", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) });
771
941
  }
@@ -782,6 +952,26 @@ function DownloadIcon() {
782
952
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 15.5h12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
783
953
  ] });
784
954
  }
955
+ function MoreIcon() {
956
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
957
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "10", r: "1.5", fill: "currentColor" }),
958
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "1.5", fill: "currentColor" }),
959
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "15.5", cy: "10", r: "1.5", fill: "currentColor" })
960
+ ] });
961
+ }
962
+ function ToolsIcon() {
963
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
964
+ "path",
965
+ {
966
+ d: "M11.5 3.5h5v5M16.2 3.8 10 10M8.2 5.2H3.8v11h11V12",
967
+ fill: "none",
968
+ stroke: "currentColor",
969
+ strokeWidth: "1.6",
970
+ strokeLinecap: "round",
971
+ strokeLinejoin: "round"
972
+ }
973
+ ) });
974
+ }
785
975
  function DetailList({ lines }) {
786
976
  return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "record-detail-list", children: lines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "record-detail-row", children: [
787
977
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: line.label }),
@@ -805,24 +995,85 @@ function RecordWorkspace({
805
995
  onDownload,
806
996
  canDownload = true,
807
997
  downloadBusy = false,
998
+ showColumnPicker = true,
999
+ columnPrefsKey,
1000
+ visibleColumnKeys,
1001
+ defaultVisibleColumnKeys,
1002
+ onVisibleColumnKeysChange,
808
1003
  toolbar,
809
1004
  form
810
1005
  }) {
811
- const filterableColumns = columns.filter((column) => column.filterable !== false);
1006
+ const allowedKeys = react.useMemo(() => new Set(columns.map((column) => column.key)), [columns]);
1007
+ const fallbackKeys = react.useMemo(
1008
+ () => defaultVisibleColumnKeys ?? defaultVisibleKeys(columns),
1009
+ [columns, defaultVisibleColumnKeys]
1010
+ );
1011
+ const isControlled = visibleColumnKeys !== void 0;
1012
+ const [internalVisibleKeys, setInternalVisibleKeys] = react.useState(
1013
+ () => readStoredColumnKeys(columnPrefsKey, fallbackKeys, allowedKeys)
1014
+ );
812
1015
  const [filters, setFilters] = react.useState({});
813
1016
  const [sort, setSort] = react.useState(null);
814
1017
  const [sideOpen, setSideOpen] = react.useState(false);
1018
+ const [toolsDrawerOpen, setToolsDrawerOpen] = react.useState(false);
815
1019
  const [downloadOpen, setDownloadOpen] = react.useState(false);
1020
+ const [columnsOpen, setColumnsOpen] = react.useState(false);
816
1021
  const [previewEnabled, setPreviewEnabled] = react.useState(false);
817
1022
  const [previewKey, setPreviewKey] = react.useState(null);
818
1023
  const [tooltip, setTooltip] = react.useState(null);
819
1024
  const [pageSize, setPageSize] = react.useState("15");
820
1025
  const [page, setPage] = react.useState(1);
1026
+ const [actionsMenu, setActionsMenu] = react.useState(null);
1027
+ const actionsMenuRef = react.useRef(null);
821
1028
  const isClient = useIsClient2();
1029
+ const hoverTooltipsEnabled = useHoverTooltipsEnabled();
1030
+ react.useEffect(() => {
1031
+ if (isControlled) {
1032
+ return;
1033
+ }
1034
+ setInternalVisibleKeys(readStoredColumnKeys(columnPrefsKey, fallbackKeys, allowedKeys));
1035
+ }, [allowedKeys, columnPrefsKey, fallbackKeys, isControlled]);
1036
+ const resolvedVisibleKeys = react.useMemo(() => {
1037
+ const source = isControlled ? visibleColumnKeys : internalVisibleKeys;
1038
+ const filtered2 = source.filter((key) => allowedKeys.has(key));
1039
+ return filtered2.length > 0 ? filtered2 : fallbackKeys.filter((key) => allowedKeys.has(key));
1040
+ }, [allowedKeys, fallbackKeys, internalVisibleKeys, isControlled, visibleColumnKeys]);
1041
+ const visibleColumns = react.useMemo(() => {
1042
+ const byKey = new Map(columns.map((column) => [column.key, column]));
1043
+ return resolvedVisibleKeys.map((key) => byKey.get(key)).filter((column) => Boolean(column));
1044
+ }, [columns, resolvedVisibleKeys]);
1045
+ function setVisibleKeys(next) {
1046
+ const unique = Array.from(new Set(next.filter((key) => allowedKeys.has(key))));
1047
+ const safe = unique.length > 0 ? unique : fallbackKeys.filter((key) => allowedKeys.has(key));
1048
+ if (!isControlled) {
1049
+ setInternalVisibleKeys(safe);
1050
+ writeStoredColumnKeys(columnPrefsKey, safe);
1051
+ }
1052
+ onVisibleColumnKeysChange?.(safe);
1053
+ }
1054
+ function toggleColumnVisible(key, checked) {
1055
+ if (checked) {
1056
+ if (resolvedVisibleKeys.includes(key)) {
1057
+ return;
1058
+ }
1059
+ setVisibleKeys([...resolvedVisibleKeys, key]);
1060
+ return;
1061
+ }
1062
+ if (resolvedVisibleKeys.length <= 1) {
1063
+ return;
1064
+ }
1065
+ setVisibleKeys(resolvedVisibleKeys.filter((entry) => entry !== key));
1066
+ }
1067
+ function selectAllColumns() {
1068
+ setVisibleKeys(columns.map((column) => column.key));
1069
+ }
1070
+ function resetColumns() {
1071
+ setVisibleKeys(fallbackKeys);
1072
+ }
1073
+ const filterableColumns = visibleColumns.filter((column) => column.filterable !== false);
822
1074
  const filtered = react.useMemo(() => {
823
- const activeFilters = columns.filter((column) => column.filterable !== false);
824
1075
  return items.filter(
825
- (item) => activeFilters.every((column) => {
1076
+ (item) => filterableColumns.every((column) => {
826
1077
  const query = (filters[column.key] ?? "").trim();
827
1078
  if (!query) {
828
1079
  return true;
@@ -835,22 +1086,24 @@ function RecordWorkspace({
835
1086
  return text.toLowerCase().includes(query.toLowerCase());
836
1087
  })
837
1088
  );
838
- }, [items, filters, columns]);
1089
+ }, [items, filters, filterableColumns]);
839
1090
  const sorted = react.useMemo(() => {
840
1091
  if (!sort) {
841
1092
  return filtered;
842
1093
  }
843
- const column = columns.find((entry) => entry.key === sort.key);
1094
+ const column = visibleColumns.find((entry) => entry.key === sort.key);
844
1095
  if (!column || column.sortable === false) {
845
1096
  return filtered;
846
1097
  }
847
1098
  const direction = sort.direction === "asc" ? 1 : -1;
848
1099
  return [...filtered].sort((left, right) => compareColumnValues(column, left, right) * direction);
849
- }, [filtered, sort, columns]);
1100
+ }, [filtered, sort, visibleColumns]);
850
1101
  const activeFilterCount = react.useMemo(
851
1102
  () => filterableColumns.reduce((count, column) => count + ((filters[column.key] ?? "").trim() ? 1 : 0), 0),
852
1103
  [filterableColumns, filters]
853
1104
  );
1105
+ const hiddenColumnCount = columns.length - visibleColumns.length;
1106
+ const toolsBadgeCount = activeFilterCount + (hiddenColumnCount > 0 ? 1 : 0) + (previewEnabled ? 1 : 0);
854
1107
  const showAll = pageSize === "all";
855
1108
  const numericPageSize = showAll ? Math.max(sorted.length, 1) : Number(pageSize);
856
1109
  const pageCount = showAll ? 1 : Math.max(1, Math.ceil(sorted.length / numericPageSize));
@@ -860,12 +1113,47 @@ function RecordWorkspace({
860
1113
  const showAdd = canAdd && Boolean(onAdd);
861
1114
  const showDownload = Boolean(onDownload) && canDownload;
862
1115
  const showFilters = filterableColumns.length > 0;
1116
+ const showColumns = showColumnPicker && columns.length > 0;
863
1117
  const previewItem = previewKey === null ? null : sorted.find((item) => rowKey(item) === previewKey) ?? null;
1118
+ const exportColumns = visibleColumns.map((column) => ({
1119
+ key: column.exportKey ?? column.key,
1120
+ header: column.header
1121
+ }));
1122
+ const canShowTooltip = hoverTooltipsEnabled && !previewEnabled && actionsMenu === null;
1123
+ react.useEffect(() => {
1124
+ if (actionsMenu === null) {
1125
+ return;
1126
+ }
1127
+ function onPointerDown(event) {
1128
+ if (actionsMenuRef.current && !actionsMenuRef.current.contains(event.target)) {
1129
+ setActionsMenu(null);
1130
+ }
1131
+ }
1132
+ document.addEventListener("mousedown", onPointerDown);
1133
+ return () => document.removeEventListener("mousedown", onPointerDown);
1134
+ }, [actionsMenu]);
1135
+ react.useEffect(() => {
1136
+ if (!toolsDrawerOpen) {
1137
+ return;
1138
+ }
1139
+ function onKeyDown(event) {
1140
+ if (event.key === "Escape") {
1141
+ setToolsDrawerOpen(false);
1142
+ }
1143
+ }
1144
+ document.addEventListener("keydown", onKeyDown);
1145
+ const previousOverflow = document.body.style.overflow;
1146
+ document.body.style.overflow = "hidden";
1147
+ return () => {
1148
+ document.removeEventListener("keydown", onKeyDown);
1149
+ document.body.style.overflow = previousOverflow;
1150
+ };
1151
+ }, [toolsDrawerOpen]);
864
1152
  function requestDownload(format) {
865
1153
  if (!onDownload || downloadBusy) {
866
1154
  return;
867
1155
  }
868
- onDownload(format);
1156
+ onDownload(format, exportColumns);
869
1157
  setDownloadOpen(false);
870
1158
  }
871
1159
  function cellText(column, item) {
@@ -873,12 +1161,12 @@ function RecordWorkspace({
873
1161
  return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
874
1162
  }
875
1163
  function detailLines(item) {
876
- return columns.map((column) => ({
1164
+ return visibleColumns.map((column) => ({
877
1165
  label: column.header,
878
1166
  value: cellText(column, item)
879
1167
  }));
880
1168
  }
881
- const previewTitle = previewItem && columns[0] ? cellText(columns[0], previewItem) : null;
1169
+ const previewTitle = previewItem && visibleColumns[0] ? cellText(visibleColumns[0], previewItem) : null;
882
1170
  function changeFilter(key, value) {
883
1171
  setFilters((current) => ({ ...current, [key]: value }));
884
1172
  setPage(1);
@@ -915,14 +1203,317 @@ function RecordWorkspace({
915
1203
  }
916
1204
  }
917
1205
  function showTooltip(item, event) {
1206
+ if (!canShowTooltip) {
1207
+ return;
1208
+ }
918
1209
  const padding = 16;
919
1210
  const width = 280;
920
1211
  const x = Math.min(event.clientX + 14, window.innerWidth - width - padding);
921
1212
  const y = Math.min(event.clientY + 14, window.innerHeight - padding - 24);
922
1213
  setTooltip({ x, y, lines: detailLines(item) });
923
1214
  }
1215
+ function openRowActions(item, event) {
1216
+ event.stopPropagation();
1217
+ setTooltip(null);
1218
+ const key = rowKey(item);
1219
+ if (actionsMenu?.key === key) {
1220
+ setActionsMenu(null);
1221
+ return;
1222
+ }
1223
+ const rect = event.currentTarget.getBoundingClientRect();
1224
+ const menuWidth = 168;
1225
+ const menuHeight = 148;
1226
+ const x = Math.min(Math.max(8, rect.right - menuWidth), window.innerWidth - menuWidth - 8);
1227
+ const y = Math.min(rect.bottom + 6, window.innerHeight - menuHeight - 8);
1228
+ setActionsMenu({ key, item, x, y });
1229
+ }
924
1230
  const summary = sorted.length === 0 ? "0 records" : showAll ? `1\u2013${sorted.length} of ${sorted.length}` : `${start + 1}\u2013${Math.min(start + numericPageSize, sorted.length)} of ${sorted.length}`;
925
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "list-workspace", "aria-label": title, children: [
1231
+ function renderToolsBody({ compactIcons }) {
1232
+ if (compactIcons) {
1233
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-icons", children: [
1234
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "side-rail-icon preview-check-icon", title: "Preview", children: [
1235
+ /* @__PURE__ */ jsxRuntime.jsx(
1236
+ "input",
1237
+ {
1238
+ type: "checkbox",
1239
+ checked: previewEnabled,
1240
+ onChange: (event) => setPreviewEnabledValue(event.target.checked),
1241
+ "aria-label": "Preview"
1242
+ }
1243
+ ),
1244
+ /* @__PURE__ */ jsxRuntime.jsx(PreviewIcon, {})
1245
+ ] }),
1246
+ showAdd ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost side-rail-icon", title: addLabel, "aria-label": addLabel, onClick: onAdd, children: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}) }) : null,
1247
+ showColumns ? /* @__PURE__ */ jsxRuntime.jsxs(
1248
+ "button",
1249
+ {
1250
+ type: "button",
1251
+ className: "ghost side-rail-icon",
1252
+ title: "Columns",
1253
+ "aria-label": "Columns",
1254
+ onClick: () => {
1255
+ setSideOpen(true);
1256
+ setColumnsOpen(true);
1257
+ },
1258
+ children: [
1259
+ /* @__PURE__ */ jsxRuntime.jsx(ColumnsIcon, {}),
1260
+ hiddenColumnCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "filter-badge", children: hiddenColumnCount }) : null
1261
+ ]
1262
+ }
1263
+ ) : null,
1264
+ showDownload ? /* @__PURE__ */ jsxRuntime.jsx(
1265
+ "button",
1266
+ {
1267
+ type: "button",
1268
+ className: "ghost side-rail-icon",
1269
+ title: "Download",
1270
+ "aria-label": "Download",
1271
+ disabled: downloadBusy,
1272
+ onClick: () => {
1273
+ setSideOpen(true);
1274
+ setDownloadOpen(true);
1275
+ },
1276
+ children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {})
1277
+ }
1278
+ ) : null,
1279
+ showFilters ? /* @__PURE__ */ jsxRuntime.jsxs(
1280
+ "button",
1281
+ {
1282
+ type: "button",
1283
+ className: "ghost side-rail-icon",
1284
+ title: "Show filters",
1285
+ "aria-label": "Show filters",
1286
+ onClick: () => setSideOpen(true),
1287
+ children: [
1288
+ /* @__PURE__ */ jsxRuntime.jsx(FilterIcon, {}),
1289
+ activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "filter-badge", children: activeFilterCount }) : null
1290
+ ]
1291
+ }
1292
+ ) : null,
1293
+ showFilters ? /* @__PURE__ */ jsxRuntime.jsx(
1294
+ "button",
1295
+ {
1296
+ type: "button",
1297
+ className: "ghost side-rail-icon",
1298
+ title: "Reset filters",
1299
+ "aria-label": "Reset filters",
1300
+ disabled: activeFilterCount === 0,
1301
+ onClick: clearFilters,
1302
+ children: /* @__PURE__ */ jsxRuntime.jsx(ResetIcon, {})
1303
+ }
1304
+ ) : null
1305
+ ] });
1306
+ }
1307
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-body", children: [
1308
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "preview-check", children: [
1309
+ /* @__PURE__ */ jsxRuntime.jsx(
1310
+ "input",
1311
+ {
1312
+ type: "checkbox",
1313
+ checked: previewEnabled,
1314
+ onChange: (event) => setPreviewEnabledValue(event.target.checked),
1315
+ "aria-label": "Preview"
1316
+ }
1317
+ ),
1318
+ /* @__PURE__ */ jsxRuntime.jsx(PreviewIcon, {}),
1319
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "Preview" })
1320
+ ] }),
1321
+ showAdd ? /* @__PURE__ */ jsxRuntime.jsxs(
1322
+ "button",
1323
+ {
1324
+ type: "button",
1325
+ className: "side-rail-add",
1326
+ onClick: () => {
1327
+ setToolsDrawerOpen(false);
1328
+ onAdd?.();
1329
+ },
1330
+ children: [
1331
+ /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}),
1332
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: addLabel })
1333
+ ]
1334
+ }
1335
+ ) : null,
1336
+ showColumns ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-columns", children: [
1337
+ /* @__PURE__ */ jsxRuntime.jsxs(
1338
+ "button",
1339
+ {
1340
+ type: "button",
1341
+ className: "ghost side-rail-columns-toggle",
1342
+ "aria-expanded": columnsOpen,
1343
+ onClick: () => setColumnsOpen((open) => !open),
1344
+ children: [
1345
+ /* @__PURE__ */ jsxRuntime.jsx(ColumnsIcon, {}),
1346
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1347
+ "Columns",
1348
+ hiddenColumnCount > 0 ? ` (${visibleColumns.length}/${columns.length})` : ""
1349
+ ] })
1350
+ ]
1351
+ }
1352
+ ),
1353
+ columnsOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-columns-panel", role: "group", "aria-label": "Visible columns", children: [
1354
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-columns-actions", children: [
1355
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost", onClick: selectAllColumns, children: "Select all" }),
1356
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost", onClick: resetColumns, children: "Reset" })
1357
+ ] }),
1358
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "side-rail-columns-list", children: columns.map((column) => {
1359
+ const checked = resolvedVisibleKeys.includes(column.key);
1360
+ const disableUncheck = checked && resolvedVisibleKeys.length <= 1;
1361
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "side-rail-column-option", children: [
1362
+ /* @__PURE__ */ jsxRuntime.jsx(
1363
+ "input",
1364
+ {
1365
+ type: "checkbox",
1366
+ checked,
1367
+ disabled: disableUncheck,
1368
+ onChange: (event) => toggleColumnVisible(column.key, event.target.checked)
1369
+ }
1370
+ ),
1371
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: column.header })
1372
+ ] }, column.key);
1373
+ }) })
1374
+ ] }) : null
1375
+ ] }) : null,
1376
+ showDownload ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-download", children: [
1377
+ /* @__PURE__ */ jsxRuntime.jsxs(
1378
+ "button",
1379
+ {
1380
+ type: "button",
1381
+ className: "ghost side-rail-download-toggle",
1382
+ "aria-expanded": downloadOpen,
1383
+ disabled: downloadBusy,
1384
+ onClick: () => setDownloadOpen((open) => !open),
1385
+ children: [
1386
+ /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {}),
1387
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: downloadBusy ? "Downloading\u2026" : "Download" })
1388
+ ]
1389
+ }
1390
+ ),
1391
+ downloadOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "side-rail-download-formats", role: "group", "aria-label": "Download format", children: EXPORT_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
1392
+ "button",
1393
+ {
1394
+ type: "button",
1395
+ className: "ghost side-rail-download-format",
1396
+ disabled: downloadBusy,
1397
+ onClick: () => requestDownload(option.format),
1398
+ children: option.label
1399
+ },
1400
+ option.format
1401
+ )) }) : null
1402
+ ] }) : null,
1403
+ showFilters ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-filters", children: [
1404
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "filter-panel-head", children: [
1405
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Filters" }),
1406
+ /* @__PURE__ */ jsxRuntime.jsxs(
1407
+ "button",
1408
+ {
1409
+ type: "button",
1410
+ className: "ghost filter-clear",
1411
+ title: "Reset filters",
1412
+ "aria-label": "Reset filters",
1413
+ disabled: activeFilterCount === 0,
1414
+ onClick: clearFilters,
1415
+ children: [
1416
+ /* @__PURE__ */ jsxRuntime.jsx(ResetIcon, {}),
1417
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reset" })
1418
+ ]
1419
+ }
1420
+ )
1421
+ ] }),
1422
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "filter-panel-stack", children: filterableColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1423
+ column.header,
1424
+ column.filterOptions ? /* @__PURE__ */ jsxRuntime.jsx(
1425
+ Select,
1426
+ {
1427
+ value: filters[column.key] ?? "",
1428
+ options: [{ value: "", label: column.filterPlaceholder ?? "All" }, ...column.filterOptions],
1429
+ onChange: (value) => changeFilter(column.key, value),
1430
+ placeholder: column.filterPlaceholder ?? "All"
1431
+ }
1432
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1433
+ "input",
1434
+ {
1435
+ value: filters[column.key] ?? "",
1436
+ onChange: (event) => changeFilter(column.key, event.target.value),
1437
+ placeholder: `Filter ${column.header.toLowerCase()}`
1438
+ }
1439
+ )
1440
+ ] }, column.key)) })
1441
+ ] }) : null
1442
+ ] });
1443
+ }
1444
+ function renderRowActions(item) {
1445
+ const key = rowKey(item);
1446
+ const updateAllowed = canUpdate ? canUpdate(item) : Boolean(onUpdate);
1447
+ const deleteAllowed = canDelete ? canDelete(item) : Boolean(onDelete);
1448
+ const hasActions = Boolean(onView || onUpdate || onDelete);
1449
+ if (!hasActions) {
1450
+ return null;
1451
+ }
1452
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1453
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "row-actions row-actions-desktop", children: [
1454
+ onView ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost row-action", onClick: () => onView(item), children: "View" }) : null,
1455
+ onUpdate ? /* @__PURE__ */ jsxRuntime.jsx(
1456
+ "button",
1457
+ {
1458
+ type: "button",
1459
+ className: "ghost row-action",
1460
+ disabled: !updateAllowed,
1461
+ title: updateAllowed ? "Update" : "Update is not available",
1462
+ onClick: () => onUpdate(item),
1463
+ children: "Update"
1464
+ }
1465
+ ) : null,
1466
+ onDelete ? /* @__PURE__ */ jsxRuntime.jsx(
1467
+ "button",
1468
+ {
1469
+ type: "button",
1470
+ className: "ghost row-action danger",
1471
+ disabled: !deleteAllowed,
1472
+ title: deleteAllowed ? "Delete" : "Delete is not available",
1473
+ onClick: () => onDelete(item),
1474
+ children: "Delete"
1475
+ }
1476
+ ) : null
1477
+ ] }),
1478
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "row-actions row-actions-mobile", children: /* @__PURE__ */ jsxRuntime.jsx(
1479
+ "button",
1480
+ {
1481
+ type: "button",
1482
+ className: actionsMenu?.key === key ? "ghost row-action-menu-trigger open" : "ghost row-action-menu-trigger",
1483
+ "aria-haspopup": "menu",
1484
+ "aria-expanded": actionsMenu?.key === key,
1485
+ "aria-label": "Row actions",
1486
+ onClick: (event) => openRowActions(item, event),
1487
+ children: /* @__PURE__ */ jsxRuntime.jsx(MoreIcon, {})
1488
+ }
1489
+ ) })
1490
+ ] });
1491
+ }
1492
+ const actionsMenuItem = actionsMenu?.item;
1493
+ const actionsUpdateAllowed = actionsMenuItem ? canUpdate ? canUpdate(actionsMenuItem) : Boolean(onUpdate) : false;
1494
+ const actionsDeleteAllowed = actionsMenuItem ? canDelete ? canDelete(actionsMenuItem) : Boolean(onDelete) : false;
1495
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: toolsDrawerOpen ? "list-workspace tools-drawer-open" : "list-workspace", "aria-label": title, children: [
1496
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tools-mobile-bar", children: [
1497
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tools-mobile-bar-start", children: showAdd ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "tools-mobile-add", onClick: onAdd, children: [
1498
+ /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}),
1499
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: addLabel })
1500
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "tools-mobile-title", children: title }) }),
1501
+ /* @__PURE__ */ jsxRuntime.jsxs(
1502
+ "button",
1503
+ {
1504
+ type: "button",
1505
+ className: "ghost tools-mobile-toggle",
1506
+ "aria-expanded": toolsDrawerOpen,
1507
+ "aria-controls": "aksui-tools-drawer",
1508
+ onClick: () => setToolsDrawerOpen(true),
1509
+ children: [
1510
+ /* @__PURE__ */ jsxRuntime.jsx(ToolsIcon, {}),
1511
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Tools" }),
1512
+ toolsBadgeCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "filter-badge", children: toolsBadgeCount }) : null
1513
+ ]
1514
+ }
1515
+ )
1516
+ ] }),
926
1517
  /* @__PURE__ */ jsxRuntime.jsxs(
927
1518
  "div",
928
1519
  {
@@ -932,7 +1523,7 @@ function RecordWorkspace({
932
1523
  toolbar ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "table-card-bar", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "table-card-context", children: toolbar }) }) : null,
933
1524
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "table-wrap", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "data-table", children: [
934
1525
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
935
- columns.map((column) => {
1526
+ visibleColumns.map((column) => {
936
1527
  const sortable = column.sortable !== false;
937
1528
  const active = sort?.key === column.key ? sort.direction : null;
938
1529
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -957,55 +1548,23 @@ function RecordWorkspace({
957
1548
  }),
958
1549
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: "actions-col", children: "Actions" })
959
1550
  ] }) }),
960
- /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: pageItems.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: columns.length + 1, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "hint table-empty", children: items.length === 0 ? empty : "No records match the current filters." }) }) }) : pageItems.map((item) => {
1551
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: pageItems.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: visibleColumns.length + 1, children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "hint table-empty", children: items.length === 0 ? empty : "No records match the current filters." }) }) }) : pageItems.map((item) => {
961
1552
  const key = rowKey(item);
962
- const updateAllowed = canUpdate ? canUpdate(item) : Boolean(onUpdate);
963
- const deleteAllowed = canDelete ? canDelete(item) : Boolean(onDelete);
964
1553
  const selected = previewEnabled && previewKey === key;
965
1554
  return /* @__PURE__ */ jsxRuntime.jsxs(
966
1555
  "tr",
967
1556
  {
968
1557
  className: selected ? "data-row selected" : "data-row",
969
1558
  onMouseEnter: (event) => {
970
- if (!previewEnabled) {
971
- showTooltip(item, event);
972
- }
1559
+ showTooltip(item, event);
973
1560
  focusRecord(item);
974
1561
  },
975
- onMouseMove: (event) => {
976
- if (!previewEnabled) {
977
- showTooltip(item, event);
978
- }
979
- },
1562
+ onMouseMove: (event) => showTooltip(item, event),
980
1563
  onMouseLeave: () => setTooltip(null),
981
1564
  onClick: () => focusRecord(item),
982
1565
  children: [
983
- columns.map((column) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: cellText(column, item) }, column.key)),
984
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: "actions-col", onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "row-actions", children: [
985
- onView ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost row-action", onClick: () => onView(item), children: "View" }) : null,
986
- onUpdate ? /* @__PURE__ */ jsxRuntime.jsx(
987
- "button",
988
- {
989
- type: "button",
990
- className: "ghost row-action",
991
- disabled: !updateAllowed,
992
- title: updateAllowed ? "Update" : "Update is not available",
993
- onClick: () => onUpdate(item),
994
- children: "Update"
995
- }
996
- ) : null,
997
- onDelete ? /* @__PURE__ */ jsxRuntime.jsx(
998
- "button",
999
- {
1000
- type: "button",
1001
- className: "ghost row-action danger",
1002
- disabled: !deleteAllowed,
1003
- title: deleteAllowed ? "Delete" : "Delete is not available",
1004
- onClick: () => onDelete(item),
1005
- children: "Delete"
1006
- }
1007
- ) : null
1008
- ] }) })
1566
+ visibleColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: cellText(column, item) }, column.key)),
1567
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "actions-col", onClick: (event) => event.stopPropagation(), children: renderRowActions(item) })
1009
1568
  ]
1010
1569
  },
1011
1570
  key
@@ -1032,7 +1591,7 @@ function RecordWorkspace({
1032
1591
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "preview-kicker", children: "Preview" }),
1033
1592
  /* @__PURE__ */ jsxRuntime.jsx("h3", { children: previewTitle ?? "No record selected" })
1034
1593
  ] }) }),
1035
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "preview-panel-body", children: previewItem ? /* @__PURE__ */ jsxRuntime.jsx(DetailList, { lines: detailLines(previewItem) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "preview-empty", children: "Hover or click a row to preview its details here." }) })
1594
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "preview-panel-body", children: previewItem ? /* @__PURE__ */ jsxRuntime.jsx(DetailList, { lines: detailLines(previewItem) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "preview-empty", children: "Select a row to preview its details here." }) })
1036
1595
  ] }) : null,
1037
1596
  /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: sideOpen ? "side-rail open" : "side-rail", "aria-label": "Actions and filters", children: [
1038
1597
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1049,153 +1608,102 @@ function RecordWorkspace({
1049
1608
  ]
1050
1609
  }
1051
1610
  ),
1052
- sideOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-body", children: [
1053
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "preview-check", children: [
1054
- /* @__PURE__ */ jsxRuntime.jsx(
1055
- "input",
1056
- {
1057
- type: "checkbox",
1058
- checked: previewEnabled,
1059
- onChange: (event) => setPreviewEnabledValue(event.target.checked),
1060
- "aria-label": "Preview"
1061
- }
1062
- ),
1063
- /* @__PURE__ */ jsxRuntime.jsx(PreviewIcon, {}),
1064
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "Preview" })
1065
- ] }),
1066
- showAdd ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "side-rail-add", onClick: onAdd, children: [
1067
- /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}),
1068
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: addLabel })
1069
- ] }) : null,
1070
- showDownload ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-download", children: [
1071
- /* @__PURE__ */ jsxRuntime.jsxs(
1072
- "button",
1073
- {
1074
- type: "button",
1075
- className: "ghost side-rail-download-toggle",
1076
- "aria-expanded": downloadOpen,
1077
- disabled: downloadBusy,
1078
- onClick: () => setDownloadOpen((open) => !open),
1079
- children: [
1080
- /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {}),
1081
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: downloadBusy ? "Downloading\u2026" : "Download" })
1082
- ]
1083
- }
1084
- ),
1085
- downloadOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "side-rail-download-formats", role: "group", "aria-label": "Download format", children: EXPORT_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
1086
- "button",
1087
- {
1088
- type: "button",
1089
- className: "ghost side-rail-download-format",
1090
- disabled: downloadBusy,
1091
- onClick: () => requestDownload(option.format),
1092
- children: option.label
1093
- },
1094
- option.format
1095
- )) }) : null
1096
- ] }) : null,
1097
- showFilters ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-filters", children: [
1098
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "filter-panel-head", children: [
1099
- /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Filters" }),
1100
- /* @__PURE__ */ jsxRuntime.jsxs(
1101
- "button",
1102
- {
1103
- type: "button",
1104
- className: "ghost filter-clear",
1105
- title: "Reset filters",
1106
- "aria-label": "Reset filters",
1107
- disabled: activeFilterCount === 0,
1108
- onClick: clearFilters,
1109
- children: [
1110
- /* @__PURE__ */ jsxRuntime.jsx(ResetIcon, {}),
1111
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reset" })
1112
- ]
1113
- }
1114
- )
1115
- ] }),
1116
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "filter-panel-stack", children: filterableColumns.map((column) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1117
- column.header,
1118
- column.filterOptions ? /* @__PURE__ */ jsxRuntime.jsx(
1119
- Select,
1120
- {
1121
- value: filters[column.key] ?? "",
1122
- options: [{ value: "", label: column.filterPlaceholder ?? "All" }, ...column.filterOptions],
1123
- onChange: (value) => changeFilter(column.key, value),
1124
- placeholder: column.filterPlaceholder ?? "All"
1125
- }
1126
- ) : /* @__PURE__ */ jsxRuntime.jsx(
1127
- "input",
1128
- {
1129
- value: filters[column.key] ?? "",
1130
- onChange: (event) => changeFilter(column.key, event.target.value),
1131
- placeholder: `Filter ${column.header.toLowerCase()}`
1132
- }
1133
- )
1134
- ] }, column.key)) })
1135
- ] }) : null
1136
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-icons", children: [
1137
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "side-rail-icon preview-check-icon", title: "Preview", children: [
1138
- /* @__PURE__ */ jsxRuntime.jsx(
1139
- "input",
1140
- {
1141
- type: "checkbox",
1142
- checked: previewEnabled,
1143
- onChange: (event) => setPreviewEnabledValue(event.target.checked),
1144
- "aria-label": "Preview"
1145
- }
1146
- ),
1147
- /* @__PURE__ */ jsxRuntime.jsx(PreviewIcon, {})
1148
- ] }),
1149
- showAdd ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost side-rail-icon", title: addLabel, "aria-label": addLabel, onClick: onAdd, children: /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}) }) : null,
1150
- showDownload ? /* @__PURE__ */ jsxRuntime.jsx(
1151
- "button",
1152
- {
1153
- type: "button",
1154
- className: "ghost side-rail-icon",
1155
- title: "Download",
1156
- "aria-label": "Download",
1157
- "aria-expanded": downloadOpen,
1158
- disabled: downloadBusy,
1159
- onClick: () => {
1160
- setSideOpen(true);
1161
- setDownloadOpen(true);
1162
- },
1163
- children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {})
1164
- }
1165
- ) : null,
1166
- showFilters ? /* @__PURE__ */ jsxRuntime.jsxs(
1167
- "button",
1168
- {
1169
- type: "button",
1170
- className: "ghost side-rail-icon",
1171
- title: "Show filters",
1172
- "aria-label": "Show filters",
1173
- onClick: () => setSideOpen(true),
1174
- children: [
1175
- /* @__PURE__ */ jsxRuntime.jsx(FilterIcon, {}),
1176
- activeFilterCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "filter-badge", children: activeFilterCount }) : null
1177
- ]
1178
- }
1179
- ) : null,
1180
- showFilters ? /* @__PURE__ */ jsxRuntime.jsx(
1181
- "button",
1182
- {
1183
- type: "button",
1184
- className: "ghost side-rail-icon",
1185
- title: "Reset filters",
1186
- "aria-label": "Reset filters",
1187
- disabled: activeFilterCount === 0,
1188
- onClick: clearFilters,
1189
- children: /* @__PURE__ */ jsxRuntime.jsx(ResetIcon, {})
1190
- }
1191
- ) : null
1192
- ] })
1611
+ sideOpen ? renderToolsBody({ compactIcons: false }) : renderToolsBody({ compactIcons: true })
1193
1612
  ] })
1194
1613
  ]
1195
1614
  }
1196
1615
  ),
1616
+ isClient ? reactDom.createPortal(
1617
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1618
+ /* @__PURE__ */ jsxRuntime.jsx(
1619
+ "button",
1620
+ {
1621
+ type: "button",
1622
+ className: toolsDrawerOpen ? "tools-drawer-backdrop open" : "tools-drawer-backdrop",
1623
+ "aria-label": "Close tools",
1624
+ tabIndex: toolsDrawerOpen ? 0 : -1,
1625
+ onClick: () => setToolsDrawerOpen(false)
1626
+ }
1627
+ ),
1628
+ /* @__PURE__ */ jsxRuntime.jsxs(
1629
+ "aside",
1630
+ {
1631
+ id: "aksui-tools-drawer",
1632
+ className: toolsDrawerOpen ? "tools-drawer open" : "tools-drawer",
1633
+ "aria-label": "Workspace tools",
1634
+ "aria-hidden": !toolsDrawerOpen,
1635
+ children: [
1636
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "tools-drawer-head", children: [
1637
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1638
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "tools-drawer-kicker", children: "Workspace" }),
1639
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Tools" })
1640
+ ] }),
1641
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "ghost tools-drawer-close", onClick: () => setToolsDrawerOpen(false), children: "Close" })
1642
+ ] }),
1643
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tools-drawer-body", children: renderToolsBody({ compactIcons: false }) })
1644
+ ]
1645
+ }
1646
+ )
1647
+ ] }),
1648
+ document.body
1649
+ ) : null,
1197
1650
  form,
1198
- isClient && tooltip && !previewEnabled ? reactDom.createPortal(
1651
+ isClient && actionsMenu && actionsMenuItem ? reactDom.createPortal(
1652
+ /* @__PURE__ */ jsxRuntime.jsxs(
1653
+ "div",
1654
+ {
1655
+ ref: actionsMenuRef,
1656
+ className: "row-action-menu row-action-menu-portal",
1657
+ role: "menu",
1658
+ style: { left: actionsMenu.x, top: actionsMenu.y },
1659
+ children: [
1660
+ onView ? /* @__PURE__ */ jsxRuntime.jsx(
1661
+ "button",
1662
+ {
1663
+ type: "button",
1664
+ role: "menuitem",
1665
+ className: "ghost",
1666
+ onClick: () => {
1667
+ setActionsMenu(null);
1668
+ onView(actionsMenuItem);
1669
+ },
1670
+ children: "View"
1671
+ }
1672
+ ) : null,
1673
+ onUpdate ? /* @__PURE__ */ jsxRuntime.jsx(
1674
+ "button",
1675
+ {
1676
+ type: "button",
1677
+ role: "menuitem",
1678
+ className: "ghost",
1679
+ disabled: !actionsUpdateAllowed,
1680
+ onClick: () => {
1681
+ setActionsMenu(null);
1682
+ onUpdate(actionsMenuItem);
1683
+ },
1684
+ children: "Update"
1685
+ }
1686
+ ) : null,
1687
+ onDelete ? /* @__PURE__ */ jsxRuntime.jsx(
1688
+ "button",
1689
+ {
1690
+ type: "button",
1691
+ role: "menuitem",
1692
+ className: "ghost danger",
1693
+ disabled: !actionsDeleteAllowed,
1694
+ onClick: () => {
1695
+ setActionsMenu(null);
1696
+ onDelete(actionsMenuItem);
1697
+ },
1698
+ children: "Delete"
1699
+ }
1700
+ ) : null
1701
+ ]
1702
+ }
1703
+ ),
1704
+ document.body
1705
+ ) : null,
1706
+ isClient && tooltip && canShowTooltip ? reactDom.createPortal(
1199
1707
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "record-tooltip", style: { left: tooltip.x, top: tooltip.y }, role: "tooltip", children: [
1200
1708
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "record-tooltip-title", children: title }),
1201
1709
  /* @__PURE__ */ jsxRuntime.jsx(DetailList, { lines: tooltip.lines })