@mshuja288/aksuicore 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -847,11 +847,31 @@ function useIsClient2() {
847
847
  () => false
848
848
  );
849
849
  }
850
+ function useHoverTooltipsEnabled() {
851
+ return useSyncExternalStore(
852
+ (onStoreChange) => {
853
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
854
+ return () => {
855
+ };
856
+ }
857
+ const media = window.matchMedia("(hover: hover) and (pointer: fine)");
858
+ media.addEventListener("change", onStoreChange);
859
+ return () => media.removeEventListener("change", onStoreChange);
860
+ },
861
+ () => typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(hover: hover) and (pointer: fine)").matches,
862
+ () => false
863
+ );
864
+ }
850
865
  var EXPORT_FORMAT_OPTIONS = [
851
866
  { format: "csv", label: "CSV" },
852
867
  { format: "xlsx", label: "Excel" },
853
868
  { format: "json", label: "JSON" }
854
869
  ];
870
+ var BULK_IMPORT_MODE_OPTIONS = [
871
+ { mode: "insert", label: "Insert" },
872
+ { mode: "update", label: "Update" },
873
+ { mode: "upsert", label: "Upsert" }
874
+ ];
855
875
  function defaultVisibleKeys(columns) {
856
876
  return columns.filter((column) => column.defaultVisible !== false).map((column) => column.key);
857
877
  }
@@ -928,6 +948,13 @@ function PreviewIcon() {
928
948
  /* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "2.4", fill: "none", stroke: "currentColor", strokeWidth: "1.6" })
929
949
  ] });
930
950
  }
951
+ function UploadIcon() {
952
+ return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
953
+ /* @__PURE__ */ jsx("path", { d: "M10 16.5V7.3", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
954
+ /* @__PURE__ */ jsx("path", { d: "M6.5 10.8 10 7.2l3.5 3.6", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }),
955
+ /* @__PURE__ */ jsx("path", { d: "M4 4.5h12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
956
+ ] });
957
+ }
931
958
  function DownloadIcon() {
932
959
  return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
933
960
  /* @__PURE__ */ jsx("path", { d: "M10 3.5v8.2", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
@@ -942,6 +969,19 @@ function MoreIcon() {
942
969
  /* @__PURE__ */ jsx("circle", { cx: "15.5", cy: "10", r: "1.5", fill: "currentColor" })
943
970
  ] });
944
971
  }
972
+ function ToolsIcon() {
973
+ return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
974
+ "path",
975
+ {
976
+ d: "M11.5 3.5h5v5M16.2 3.8 10 10M8.2 5.2H3.8v11h11V12",
977
+ fill: "none",
978
+ stroke: "currentColor",
979
+ strokeWidth: "1.6",
980
+ strokeLinecap: "round",
981
+ strokeLinejoin: "round"
982
+ }
983
+ ) });
984
+ }
945
985
  function DetailList({ lines }) {
946
986
  return /* @__PURE__ */ jsx("dl", { className: "record-detail-list", children: lines.map((line) => /* @__PURE__ */ jsxs("div", { className: "record-detail-row", children: [
947
987
  /* @__PURE__ */ jsx("dt", { children: line.label }),
@@ -964,7 +1004,11 @@ function RecordWorkspace({
964
1004
  canDelete,
965
1005
  onDownload,
966
1006
  canDownload = true,
1007
+ canExport,
967
1008
  downloadBusy = false,
1009
+ onBulkImport,
1010
+ canImport = true,
1011
+ importBusy = false,
968
1012
  showColumnPicker = true,
969
1013
  columnPrefsKey,
970
1014
  visibleColumnKeys,
@@ -985,16 +1029,23 @@ function RecordWorkspace({
985
1029
  const [filters, setFilters] = useState({});
986
1030
  const [sort, setSort] = useState(null);
987
1031
  const [sideOpen, setSideOpen] = useState(false);
1032
+ const [toolsDrawerOpen, setToolsDrawerOpen] = useState(false);
988
1033
  const [downloadOpen, setDownloadOpen] = useState(false);
1034
+ const [bulkOpen, setBulkOpen] = useState(false);
1035
+ const [bulkMode, setBulkMode] = useState("upsert");
1036
+ const [bulkFile, setBulkFile] = useState(null);
1037
+ const [bulkReport, setBulkReport] = useState(null);
1038
+ const bulkFileInputRef = useRef(null);
989
1039
  const [columnsOpen, setColumnsOpen] = useState(false);
990
1040
  const [previewEnabled, setPreviewEnabled] = useState(false);
991
1041
  const [previewKey, setPreviewKey] = useState(null);
992
1042
  const [tooltip, setTooltip] = useState(null);
993
1043
  const [pageSize, setPageSize] = useState("15");
994
1044
  const [page, setPage] = useState(1);
995
- const [actionsMenuKey, setActionsMenuKey] = useState(null);
1045
+ const [actionsMenu, setActionsMenu] = useState(null);
996
1046
  const actionsMenuRef = useRef(null);
997
1047
  const isClient = useIsClient2();
1048
+ const hoverTooltipsEnabled = useHoverTooltipsEnabled();
998
1049
  useEffect(() => {
999
1050
  if (isControlled) {
1000
1051
  return;
@@ -1071,6 +1122,7 @@ function RecordWorkspace({
1071
1122
  [filterableColumns, filters]
1072
1123
  );
1073
1124
  const hiddenColumnCount = columns.length - visibleColumns.length;
1125
+ const toolsBadgeCount = activeFilterCount + (hiddenColumnCount > 0 ? 1 : 0) + (previewEnabled ? 1 : 0);
1074
1126
  const showAll = pageSize === "all";
1075
1127
  const numericPageSize = showAll ? Math.max(sorted.length, 1) : Number(pageSize);
1076
1128
  const pageCount = showAll ? 1 : Math.max(1, Math.ceil(sorted.length / numericPageSize));
@@ -1078,7 +1130,9 @@ function RecordWorkspace({
1078
1130
  const start = showAll ? 0 : (currentPage - 1) * numericPageSize;
1079
1131
  const pageItems = showAll ? sorted : sorted.slice(start, start + numericPageSize);
1080
1132
  const showAdd = canAdd && Boolean(onAdd);
1081
- const showDownload = Boolean(onDownload) && canDownload;
1133
+ const exportAllowed = (canExport ?? true) && canDownload;
1134
+ const showDownload = Boolean(onDownload) && exportAllowed;
1135
+ const showBulkImport = Boolean(onBulkImport) && canImport;
1082
1136
  const showFilters = filterableColumns.length > 0;
1083
1137
  const showColumns = showColumnPicker && columns.length > 0;
1084
1138
  const previewItem = previewKey === null ? null : sorted.find((item) => rowKey(item) === previewKey) ?? null;
@@ -1086,18 +1140,36 @@ function RecordWorkspace({
1086
1140
  key: column.exportKey ?? column.key,
1087
1141
  header: column.header
1088
1142
  }));
1143
+ const canShowTooltip = hoverTooltipsEnabled && !previewEnabled && actionsMenu === null;
1089
1144
  useEffect(() => {
1090
- if (actionsMenuKey === null) {
1145
+ if (actionsMenu === null) {
1091
1146
  return;
1092
1147
  }
1093
1148
  function onPointerDown(event) {
1094
1149
  if (actionsMenuRef.current && !actionsMenuRef.current.contains(event.target)) {
1095
- setActionsMenuKey(null);
1150
+ setActionsMenu(null);
1096
1151
  }
1097
1152
  }
1098
1153
  document.addEventListener("mousedown", onPointerDown);
1099
1154
  return () => document.removeEventListener("mousedown", onPointerDown);
1100
- }, [actionsMenuKey]);
1155
+ }, [actionsMenu]);
1156
+ useEffect(() => {
1157
+ if (!toolsDrawerOpen) {
1158
+ return;
1159
+ }
1160
+ function onKeyDown(event) {
1161
+ if (event.key === "Escape") {
1162
+ setToolsDrawerOpen(false);
1163
+ }
1164
+ }
1165
+ document.addEventListener("keydown", onKeyDown);
1166
+ const previousOverflow = document.body.style.overflow;
1167
+ document.body.style.overflow = "hidden";
1168
+ return () => {
1169
+ document.removeEventListener("keydown", onKeyDown);
1170
+ document.body.style.overflow = previousOverflow;
1171
+ };
1172
+ }, [toolsDrawerOpen]);
1101
1173
  function requestDownload(format) {
1102
1174
  if (!onDownload || downloadBusy) {
1103
1175
  return;
@@ -1105,6 +1177,29 @@ function RecordWorkspace({
1105
1177
  onDownload(format, exportColumns);
1106
1178
  setDownloadOpen(false);
1107
1179
  }
1180
+ async function submitBulkImport() {
1181
+ if (!onBulkImport || importBusy || !bulkFile) {
1182
+ return;
1183
+ }
1184
+ setBulkReport(null);
1185
+ try {
1186
+ const report = await onBulkImport(bulkMode, bulkFile);
1187
+ setBulkReport(report);
1188
+ if (report.applied) {
1189
+ setBulkFile(null);
1190
+ if (bulkFileInputRef.current) {
1191
+ bulkFileInputRef.current.value = "";
1192
+ }
1193
+ }
1194
+ } catch {
1195
+ setBulkReport({
1196
+ totalRows: 0,
1197
+ failed: 1,
1198
+ applied: false,
1199
+ errors: [{ row: 0, code: "ImportFailed", message: "Import request failed." }]
1200
+ });
1201
+ }
1202
+ }
1108
1203
  function cellText(column, item) {
1109
1204
  const raw = column.display ? column.display(item) : column.value(item);
1110
1205
  return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
@@ -1152,13 +1247,330 @@ function RecordWorkspace({
1152
1247
  }
1153
1248
  }
1154
1249
  function showTooltip(item, event) {
1250
+ if (!canShowTooltip) {
1251
+ return;
1252
+ }
1155
1253
  const padding = 16;
1156
1254
  const width = 280;
1157
1255
  const x = Math.min(event.clientX + 14, window.innerWidth - width - padding);
1158
1256
  const y = Math.min(event.clientY + 14, window.innerHeight - padding - 24);
1159
1257
  setTooltip({ x, y, lines: detailLines(item) });
1160
1258
  }
1259
+ function openRowActions(item, event) {
1260
+ event.stopPropagation();
1261
+ setTooltip(null);
1262
+ const key = rowKey(item);
1263
+ if (actionsMenu?.key === key) {
1264
+ setActionsMenu(null);
1265
+ return;
1266
+ }
1267
+ const rect = event.currentTarget.getBoundingClientRect();
1268
+ const menuWidth = 168;
1269
+ const menuHeight = 148;
1270
+ const x = Math.min(Math.max(8, rect.right - menuWidth), window.innerWidth - menuWidth - 8);
1271
+ const y = Math.min(rect.bottom + 6, window.innerHeight - menuHeight - 8);
1272
+ setActionsMenu({ key, item, x, y });
1273
+ }
1161
1274
  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}`;
1275
+ function renderToolsBody({ compactIcons }) {
1276
+ if (compactIcons) {
1277
+ return /* @__PURE__ */ jsxs("div", { className: "side-rail-icons", children: [
1278
+ /* @__PURE__ */ jsxs("label", { className: "side-rail-icon preview-check-icon", title: "Preview", children: [
1279
+ /* @__PURE__ */ jsx(
1280
+ "input",
1281
+ {
1282
+ type: "checkbox",
1283
+ checked: previewEnabled,
1284
+ onChange: (event) => setPreviewEnabledValue(event.target.checked),
1285
+ "aria-label": "Preview"
1286
+ }
1287
+ ),
1288
+ /* @__PURE__ */ jsx(PreviewIcon, {})
1289
+ ] }),
1290
+ showAdd ? /* @__PURE__ */ jsx("button", { type: "button", className: "ghost side-rail-icon", title: addLabel, "aria-label": addLabel, onClick: onAdd, children: /* @__PURE__ */ jsx(PlusIcon, {}) }) : null,
1291
+ showColumns ? /* @__PURE__ */ jsxs(
1292
+ "button",
1293
+ {
1294
+ type: "button",
1295
+ className: "ghost side-rail-icon",
1296
+ title: "Columns",
1297
+ "aria-label": "Columns",
1298
+ onClick: () => {
1299
+ setSideOpen(true);
1300
+ setColumnsOpen(true);
1301
+ },
1302
+ children: [
1303
+ /* @__PURE__ */ jsx(ColumnsIcon, {}),
1304
+ hiddenColumnCount > 0 ? /* @__PURE__ */ jsx("span", { className: "filter-badge", children: hiddenColumnCount }) : null
1305
+ ]
1306
+ }
1307
+ ) : null,
1308
+ showDownload ? /* @__PURE__ */ jsx(
1309
+ "button",
1310
+ {
1311
+ type: "button",
1312
+ className: "ghost side-rail-icon",
1313
+ title: "Download",
1314
+ "aria-label": "Download",
1315
+ disabled: downloadBusy,
1316
+ onClick: () => {
1317
+ setSideOpen(true);
1318
+ setDownloadOpen(true);
1319
+ },
1320
+ children: /* @__PURE__ */ jsx(DownloadIcon, {})
1321
+ }
1322
+ ) : null,
1323
+ showBulkImport ? /* @__PURE__ */ jsx(
1324
+ "button",
1325
+ {
1326
+ type: "button",
1327
+ className: "ghost side-rail-icon",
1328
+ title: "Bulk entry",
1329
+ "aria-label": "Bulk entry",
1330
+ disabled: importBusy,
1331
+ onClick: () => {
1332
+ setSideOpen(true);
1333
+ setBulkOpen(true);
1334
+ },
1335
+ children: /* @__PURE__ */ jsx(UploadIcon, {})
1336
+ }
1337
+ ) : null,
1338
+ showFilters ? /* @__PURE__ */ jsxs(
1339
+ "button",
1340
+ {
1341
+ type: "button",
1342
+ className: "ghost side-rail-icon",
1343
+ title: "Show filters",
1344
+ "aria-label": "Show filters",
1345
+ onClick: () => setSideOpen(true),
1346
+ children: [
1347
+ /* @__PURE__ */ jsx(FilterIcon, {}),
1348
+ activeFilterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "filter-badge", children: activeFilterCount }) : null
1349
+ ]
1350
+ }
1351
+ ) : null,
1352
+ showFilters ? /* @__PURE__ */ jsx(
1353
+ "button",
1354
+ {
1355
+ type: "button",
1356
+ className: "ghost side-rail-icon",
1357
+ title: "Reset filters",
1358
+ "aria-label": "Reset filters",
1359
+ disabled: activeFilterCount === 0,
1360
+ onClick: clearFilters,
1361
+ children: /* @__PURE__ */ jsx(ResetIcon, {})
1362
+ }
1363
+ ) : null
1364
+ ] });
1365
+ }
1366
+ return /* @__PURE__ */ jsxs("div", { className: "side-rail-body", children: [
1367
+ /* @__PURE__ */ jsxs("div", { className: "preview-check", children: [
1368
+ /* @__PURE__ */ jsx(
1369
+ "input",
1370
+ {
1371
+ type: "checkbox",
1372
+ checked: previewEnabled,
1373
+ onChange: (event) => setPreviewEnabledValue(event.target.checked),
1374
+ "aria-label": "Preview"
1375
+ }
1376
+ ),
1377
+ /* @__PURE__ */ jsx(PreviewIcon, {}),
1378
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "Preview" })
1379
+ ] }),
1380
+ showAdd ? /* @__PURE__ */ jsxs(
1381
+ "button",
1382
+ {
1383
+ type: "button",
1384
+ className: "side-rail-add",
1385
+ onClick: () => {
1386
+ setToolsDrawerOpen(false);
1387
+ onAdd?.();
1388
+ },
1389
+ children: [
1390
+ /* @__PURE__ */ jsx(PlusIcon, {}),
1391
+ /* @__PURE__ */ jsx("span", { children: addLabel })
1392
+ ]
1393
+ }
1394
+ ) : null,
1395
+ showColumns ? /* @__PURE__ */ jsxs("div", { className: "side-rail-columns", children: [
1396
+ /* @__PURE__ */ jsxs(
1397
+ "button",
1398
+ {
1399
+ type: "button",
1400
+ className: "ghost side-rail-columns-toggle",
1401
+ "aria-expanded": columnsOpen,
1402
+ onClick: () => setColumnsOpen((open) => !open),
1403
+ children: [
1404
+ /* @__PURE__ */ jsx(ColumnsIcon, {}),
1405
+ /* @__PURE__ */ jsxs("span", { children: [
1406
+ "Columns",
1407
+ hiddenColumnCount > 0 ? ` (${visibleColumns.length}/${columns.length})` : ""
1408
+ ] })
1409
+ ]
1410
+ }
1411
+ ),
1412
+ columnsOpen ? /* @__PURE__ */ jsxs("div", { className: "side-rail-columns-panel", role: "group", "aria-label": "Visible columns", children: [
1413
+ /* @__PURE__ */ jsxs("div", { className: "side-rail-columns-actions", children: [
1414
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ghost", onClick: selectAllColumns, children: "Select all" }),
1415
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ghost", onClick: resetColumns, children: "Reset" })
1416
+ ] }),
1417
+ /* @__PURE__ */ jsx("div", { className: "side-rail-columns-list", children: columns.map((column) => {
1418
+ const checked = resolvedVisibleKeys.includes(column.key);
1419
+ const disableUncheck = checked && resolvedVisibleKeys.length <= 1;
1420
+ return /* @__PURE__ */ jsxs("label", { className: "side-rail-column-option", children: [
1421
+ /* @__PURE__ */ jsx(
1422
+ "input",
1423
+ {
1424
+ type: "checkbox",
1425
+ checked,
1426
+ disabled: disableUncheck,
1427
+ onChange: (event) => toggleColumnVisible(column.key, event.target.checked)
1428
+ }
1429
+ ),
1430
+ /* @__PURE__ */ jsx("span", { children: column.header })
1431
+ ] }, column.key);
1432
+ }) })
1433
+ ] }) : null
1434
+ ] }) : null,
1435
+ showDownload ? /* @__PURE__ */ jsxs("div", { className: "side-rail-download", children: [
1436
+ /* @__PURE__ */ jsxs(
1437
+ "button",
1438
+ {
1439
+ type: "button",
1440
+ className: "ghost side-rail-download-toggle",
1441
+ "aria-expanded": downloadOpen,
1442
+ disabled: downloadBusy,
1443
+ onClick: () => setDownloadOpen((open) => !open),
1444
+ children: [
1445
+ /* @__PURE__ */ jsx(DownloadIcon, {}),
1446
+ /* @__PURE__ */ jsx("span", { children: downloadBusy ? "Downloading\u2026" : "Download" })
1447
+ ]
1448
+ }
1449
+ ),
1450
+ downloadOpen ? /* @__PURE__ */ jsx("div", { className: "side-rail-download-formats", role: "group", "aria-label": "Download format", children: EXPORT_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ jsx(
1451
+ "button",
1452
+ {
1453
+ type: "button",
1454
+ className: "ghost side-rail-download-format",
1455
+ disabled: downloadBusy,
1456
+ onClick: () => requestDownload(option.format),
1457
+ children: option.label
1458
+ },
1459
+ option.format
1460
+ )) }) : null
1461
+ ] }) : null,
1462
+ showBulkImport ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk", children: [
1463
+ /* @__PURE__ */ jsxs(
1464
+ "button",
1465
+ {
1466
+ type: "button",
1467
+ className: "ghost side-rail-bulk-toggle",
1468
+ "aria-expanded": bulkOpen,
1469
+ disabled: importBusy,
1470
+ onClick: () => setBulkOpen((open) => !open),
1471
+ children: [
1472
+ /* @__PURE__ */ jsx(UploadIcon, {}),
1473
+ /* @__PURE__ */ jsx("span", { children: importBusy ? "Importing\u2026" : "Bulk entry" })
1474
+ ]
1475
+ }
1476
+ ),
1477
+ bulkOpen ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk-panel", role: "group", "aria-label": "Bulk entry", children: [
1478
+ /* @__PURE__ */ jsxs("label", { className: "side-rail-bulk-mode", children: [
1479
+ "Mode",
1480
+ /* @__PURE__ */ jsx(
1481
+ Select,
1482
+ {
1483
+ value: bulkMode,
1484
+ options: BULK_IMPORT_MODE_OPTIONS.map((option) => ({ value: option.mode, label: option.label })),
1485
+ onChange: (value) => setBulkMode(value)
1486
+ }
1487
+ )
1488
+ ] }),
1489
+ /* @__PURE__ */ jsxs("label", { className: "side-rail-bulk-file", children: [
1490
+ "File",
1491
+ /* @__PURE__ */ jsx(
1492
+ "input",
1493
+ {
1494
+ ref: bulkFileInputRef,
1495
+ type: "file",
1496
+ accept: ".csv,.xlsx,.json",
1497
+ disabled: importBusy,
1498
+ onChange: (event) => {
1499
+ setBulkFile(event.target.files?.[0] ?? null);
1500
+ setBulkReport(null);
1501
+ }
1502
+ }
1503
+ )
1504
+ ] }),
1505
+ /* @__PURE__ */ jsx(
1506
+ "button",
1507
+ {
1508
+ type: "button",
1509
+ className: "side-rail-bulk-submit",
1510
+ disabled: importBusy || !bulkFile,
1511
+ onClick: () => void submitBulkImport(),
1512
+ children: importBusy ? "Importing\u2026" : "Import"
1513
+ }
1514
+ ),
1515
+ bulkReport ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk-report", role: "status", children: [
1516
+ /* @__PURE__ */ jsx("p", { children: bulkReport.applied ? `Applied ${bulkReport.totalRows} row(s).` : `${bulkReport.failed} error(s) in ${bulkReport.totalRows} row(s).` }),
1517
+ bulkReport.errors.length > 0 ? /* @__PURE__ */ jsxs("ul", { className: "side-rail-bulk-errors", children: [
1518
+ bulkReport.errors.slice(0, 8).map((error, index) => /* @__PURE__ */ jsxs("li", { children: [
1519
+ "Row ",
1520
+ error.row,
1521
+ ": ",
1522
+ error.message
1523
+ ] }, `${error.row}-${error.code}-${index}`)),
1524
+ bulkReport.errors.length > 8 ? /* @__PURE__ */ jsxs("li", { children: [
1525
+ "\u2026and ",
1526
+ bulkReport.errors.length - 8,
1527
+ " more"
1528
+ ] }) : null
1529
+ ] }) : null
1530
+ ] }) : null
1531
+ ] }) : null
1532
+ ] }) : null,
1533
+ showFilters ? /* @__PURE__ */ jsxs("div", { className: "side-rail-filters", children: [
1534
+ /* @__PURE__ */ jsxs("div", { className: "filter-panel-head", children: [
1535
+ /* @__PURE__ */ jsx("h3", { children: "Filters" }),
1536
+ /* @__PURE__ */ jsxs(
1537
+ "button",
1538
+ {
1539
+ type: "button",
1540
+ className: "ghost filter-clear",
1541
+ title: "Reset filters",
1542
+ "aria-label": "Reset filters",
1543
+ disabled: activeFilterCount === 0,
1544
+ onClick: clearFilters,
1545
+ children: [
1546
+ /* @__PURE__ */ jsx(ResetIcon, {}),
1547
+ /* @__PURE__ */ jsx("span", { children: "Reset" })
1548
+ ]
1549
+ }
1550
+ )
1551
+ ] }),
1552
+ /* @__PURE__ */ jsx("div", { className: "filter-panel-stack", children: filterableColumns.map((column) => /* @__PURE__ */ jsxs("label", { children: [
1553
+ column.header,
1554
+ column.filterOptions ? /* @__PURE__ */ jsx(
1555
+ Select,
1556
+ {
1557
+ value: filters[column.key] ?? "",
1558
+ options: [{ value: "", label: column.filterPlaceholder ?? "All" }, ...column.filterOptions],
1559
+ onChange: (value) => changeFilter(column.key, value),
1560
+ placeholder: column.filterPlaceholder ?? "All"
1561
+ }
1562
+ ) : /* @__PURE__ */ jsx(
1563
+ "input",
1564
+ {
1565
+ value: filters[column.key] ?? "",
1566
+ onChange: (event) => changeFilter(column.key, event.target.value),
1567
+ placeholder: `Filter ${column.header.toLowerCase()}`
1568
+ }
1569
+ )
1570
+ ] }, column.key)) })
1571
+ ] }) : null
1572
+ ] });
1573
+ }
1162
1574
  function renderRowActions(item) {
1163
1575
  const key = rowKey(item);
1164
1576
  const updateAllowed = canUpdate ? canUpdate(item) : Boolean(onUpdate);
@@ -1193,66 +1605,45 @@ function RecordWorkspace({
1193
1605
  }
1194
1606
  ) : null
1195
1607
  ] }),
1196
- /* @__PURE__ */ jsxs("div", { className: "row-actions row-actions-mobile", ref: actionsMenuKey === key ? actionsMenuRef : void 0, children: [
1197
- /* @__PURE__ */ jsx(
1198
- "button",
1199
- {
1200
- type: "button",
1201
- className: "ghost row-action-menu-trigger",
1202
- "aria-haspopup": "menu",
1203
- "aria-expanded": actionsMenuKey === key,
1204
- "aria-label": "Row actions",
1205
- onClick: () => setActionsMenuKey((current) => current === key ? null : key),
1206
- children: /* @__PURE__ */ jsx(MoreIcon, {})
1207
- }
1208
- ),
1209
- actionsMenuKey === key ? /* @__PURE__ */ jsxs("div", { className: "row-action-menu", role: "menu", children: [
1210
- onView ? /* @__PURE__ */ jsx(
1211
- "button",
1212
- {
1213
- type: "button",
1214
- role: "menuitem",
1215
- className: "ghost",
1216
- onClick: () => {
1217
- setActionsMenuKey(null);
1218
- onView(item);
1219
- },
1220
- children: "View"
1221
- }
1222
- ) : null,
1223
- onUpdate ? /* @__PURE__ */ jsx(
1224
- "button",
1225
- {
1226
- type: "button",
1227
- role: "menuitem",
1228
- className: "ghost",
1229
- disabled: !updateAllowed,
1230
- onClick: () => {
1231
- setActionsMenuKey(null);
1232
- onUpdate(item);
1233
- },
1234
- children: "Update"
1235
- }
1236
- ) : null,
1237
- onDelete ? /* @__PURE__ */ jsx(
1238
- "button",
1239
- {
1240
- type: "button",
1241
- role: "menuitem",
1242
- className: "ghost danger",
1243
- disabled: !deleteAllowed,
1244
- onClick: () => {
1245
- setActionsMenuKey(null);
1246
- onDelete(item);
1247
- },
1248
- children: "Delete"
1249
- }
1250
- ) : null
1251
- ] }) : null
1252
- ] })
1608
+ /* @__PURE__ */ jsx("div", { className: "row-actions row-actions-mobile", children: /* @__PURE__ */ jsx(
1609
+ "button",
1610
+ {
1611
+ type: "button",
1612
+ className: actionsMenu?.key === key ? "ghost row-action-menu-trigger open" : "ghost row-action-menu-trigger",
1613
+ "aria-haspopup": "menu",
1614
+ "aria-expanded": actionsMenu?.key === key,
1615
+ "aria-label": "Row actions",
1616
+ onClick: (event) => openRowActions(item, event),
1617
+ children: /* @__PURE__ */ jsx(MoreIcon, {})
1618
+ }
1619
+ ) })
1253
1620
  ] });
1254
1621
  }
1255
- return /* @__PURE__ */ jsxs("div", { className: "list-workspace", "aria-label": title, children: [
1622
+ const actionsMenuItem = actionsMenu?.item;
1623
+ const actionsUpdateAllowed = actionsMenuItem ? canUpdate ? canUpdate(actionsMenuItem) : Boolean(onUpdate) : false;
1624
+ const actionsDeleteAllowed = actionsMenuItem ? canDelete ? canDelete(actionsMenuItem) : Boolean(onDelete) : false;
1625
+ return /* @__PURE__ */ jsxs("div", { className: toolsDrawerOpen ? "list-workspace tools-drawer-open" : "list-workspace", "aria-label": title, children: [
1626
+ /* @__PURE__ */ jsxs("div", { className: "tools-mobile-bar", children: [
1627
+ /* @__PURE__ */ jsx("div", { className: "tools-mobile-bar-start", children: showAdd ? /* @__PURE__ */ jsxs("button", { type: "button", className: "tools-mobile-add", onClick: onAdd, children: [
1628
+ /* @__PURE__ */ jsx(PlusIcon, {}),
1629
+ /* @__PURE__ */ jsx("span", { children: addLabel })
1630
+ ] }) : /* @__PURE__ */ jsx("p", { className: "tools-mobile-title", children: title }) }),
1631
+ /* @__PURE__ */ jsxs(
1632
+ "button",
1633
+ {
1634
+ type: "button",
1635
+ className: "ghost tools-mobile-toggle",
1636
+ "aria-expanded": toolsDrawerOpen,
1637
+ "aria-controls": "aksui-tools-drawer",
1638
+ onClick: () => setToolsDrawerOpen(true),
1639
+ children: [
1640
+ /* @__PURE__ */ jsx(ToolsIcon, {}),
1641
+ /* @__PURE__ */ jsx("span", { children: "Tools" }),
1642
+ toolsBadgeCount > 0 ? /* @__PURE__ */ jsx("span", { className: "filter-badge", children: toolsBadgeCount }) : null
1643
+ ]
1644
+ }
1645
+ )
1646
+ ] }),
1256
1647
  /* @__PURE__ */ jsxs(
1257
1648
  "div",
1258
1649
  {
@@ -1295,16 +1686,10 @@ function RecordWorkspace({
1295
1686
  {
1296
1687
  className: selected ? "data-row selected" : "data-row",
1297
1688
  onMouseEnter: (event) => {
1298
- if (!previewEnabled) {
1299
- showTooltip(item, event);
1300
- }
1689
+ showTooltip(item, event);
1301
1690
  focusRecord(item);
1302
1691
  },
1303
- onMouseMove: (event) => {
1304
- if (!previewEnabled) {
1305
- showTooltip(item, event);
1306
- }
1307
- },
1692
+ onMouseMove: (event) => showTooltip(item, event),
1308
1693
  onMouseLeave: () => setTooltip(null),
1309
1694
  onClick: () => focusRecord(item),
1310
1695
  children: [
@@ -1336,7 +1721,7 @@ function RecordWorkspace({
1336
1721
  /* @__PURE__ */ jsx("p", { className: "preview-kicker", children: "Preview" }),
1337
1722
  /* @__PURE__ */ jsx("h3", { children: previewTitle ?? "No record selected" })
1338
1723
  ] }) }),
1339
- /* @__PURE__ */ jsx("div", { className: "preview-panel-body", children: previewItem ? /* @__PURE__ */ jsx(DetailList, { lines: detailLines(previewItem) }) : /* @__PURE__ */ jsx("p", { className: "preview-empty", children: "Hover or click a row to preview its details here." }) })
1724
+ /* @__PURE__ */ jsx("div", { className: "preview-panel-body", children: previewItem ? /* @__PURE__ */ jsx(DetailList, { lines: detailLines(previewItem) }) : /* @__PURE__ */ jsx("p", { className: "preview-empty", children: "Select a row to preview its details here." }) })
1340
1725
  ] }) : null,
1341
1726
  /* @__PURE__ */ jsxs("aside", { className: sideOpen ? "side-rail open" : "side-rail", "aria-label": "Actions and filters", children: [
1342
1727
  /* @__PURE__ */ jsxs(
@@ -1353,210 +1738,102 @@ function RecordWorkspace({
1353
1738
  ]
1354
1739
  }
1355
1740
  ),
1356
- sideOpen ? /* @__PURE__ */ jsxs("div", { className: "side-rail-body", children: [
1357
- /* @__PURE__ */ jsxs("div", { className: "preview-check", children: [
1358
- /* @__PURE__ */ jsx(
1359
- "input",
1360
- {
1361
- type: "checkbox",
1362
- checked: previewEnabled,
1363
- onChange: (event) => setPreviewEnabledValue(event.target.checked),
1364
- "aria-label": "Preview"
1365
- }
1366
- ),
1367
- /* @__PURE__ */ jsx(PreviewIcon, {}),
1368
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "Preview" })
1369
- ] }),
1370
- showAdd ? /* @__PURE__ */ jsxs("button", { type: "button", className: "side-rail-add", onClick: onAdd, children: [
1371
- /* @__PURE__ */ jsx(PlusIcon, {}),
1372
- /* @__PURE__ */ jsx("span", { children: addLabel })
1373
- ] }) : null,
1374
- showColumns ? /* @__PURE__ */ jsxs("div", { className: "side-rail-columns", children: [
1375
- /* @__PURE__ */ jsxs(
1376
- "button",
1377
- {
1378
- type: "button",
1379
- className: "ghost side-rail-columns-toggle",
1380
- "aria-expanded": columnsOpen,
1381
- onClick: () => setColumnsOpen((open) => !open),
1382
- children: [
1383
- /* @__PURE__ */ jsx(ColumnsIcon, {}),
1384
- /* @__PURE__ */ jsxs("span", { children: [
1385
- "Columns",
1386
- hiddenColumnCount > 0 ? ` (${visibleColumns.length}/${columns.length})` : ""
1387
- ] })
1388
- ]
1389
- }
1390
- ),
1391
- columnsOpen ? /* @__PURE__ */ jsxs("div", { className: "side-rail-columns-panel", role: "group", "aria-label": "Visible columns", children: [
1392
- /* @__PURE__ */ jsxs("div", { className: "side-rail-columns-actions", children: [
1393
- /* @__PURE__ */ jsx("button", { type: "button", className: "ghost", onClick: selectAllColumns, children: "Select all" }),
1394
- /* @__PURE__ */ jsx("button", { type: "button", className: "ghost", onClick: resetColumns, children: "Reset" })
1395
- ] }),
1396
- /* @__PURE__ */ jsx("div", { className: "side-rail-columns-list", children: columns.map((column) => {
1397
- const checked = resolvedVisibleKeys.includes(column.key);
1398
- const disableUncheck = checked && resolvedVisibleKeys.length <= 1;
1399
- return /* @__PURE__ */ jsxs("label", { className: "side-rail-column-option", children: [
1400
- /* @__PURE__ */ jsx(
1401
- "input",
1402
- {
1403
- type: "checkbox",
1404
- checked,
1405
- disabled: disableUncheck,
1406
- onChange: (event) => toggleColumnVisible(column.key, event.target.checked)
1407
- }
1408
- ),
1409
- /* @__PURE__ */ jsx("span", { children: column.header })
1410
- ] }, column.key);
1411
- }) })
1412
- ] }) : null
1413
- ] }) : null,
1414
- showDownload ? /* @__PURE__ */ jsxs("div", { className: "side-rail-download", children: [
1415
- /* @__PURE__ */ jsxs(
1416
- "button",
1417
- {
1418
- type: "button",
1419
- className: "ghost side-rail-download-toggle",
1420
- "aria-expanded": downloadOpen,
1421
- disabled: downloadBusy,
1422
- onClick: () => setDownloadOpen((open) => !open),
1423
- children: [
1424
- /* @__PURE__ */ jsx(DownloadIcon, {}),
1425
- /* @__PURE__ */ jsx("span", { children: downloadBusy ? "Downloading\u2026" : "Download" })
1426
- ]
1427
- }
1428
- ),
1429
- downloadOpen ? /* @__PURE__ */ jsx("div", { className: "side-rail-download-formats", role: "group", "aria-label": "Download format", children: EXPORT_FORMAT_OPTIONS.map((option) => /* @__PURE__ */ jsx(
1430
- "button",
1431
- {
1432
- type: "button",
1433
- className: "ghost side-rail-download-format",
1434
- disabled: downloadBusy,
1435
- onClick: () => requestDownload(option.format),
1436
- children: option.label
1437
- },
1438
- option.format
1439
- )) }) : null
1440
- ] }) : null,
1441
- showFilters ? /* @__PURE__ */ jsxs("div", { className: "side-rail-filters", children: [
1442
- /* @__PURE__ */ jsxs("div", { className: "filter-panel-head", children: [
1443
- /* @__PURE__ */ jsx("h3", { children: "Filters" }),
1444
- /* @__PURE__ */ jsxs(
1445
- "button",
1446
- {
1447
- type: "button",
1448
- className: "ghost filter-clear",
1449
- title: "Reset filters",
1450
- "aria-label": "Reset filters",
1451
- disabled: activeFilterCount === 0,
1452
- onClick: clearFilters,
1453
- children: [
1454
- /* @__PURE__ */ jsx(ResetIcon, {}),
1455
- /* @__PURE__ */ jsx("span", { children: "Reset" })
1456
- ]
1457
- }
1458
- )
1459
- ] }),
1460
- /* @__PURE__ */ jsx("div", { className: "filter-panel-stack", children: filterableColumns.map((column) => /* @__PURE__ */ jsxs("label", { children: [
1461
- column.header,
1462
- column.filterOptions ? /* @__PURE__ */ jsx(
1463
- Select,
1464
- {
1465
- value: filters[column.key] ?? "",
1466
- options: [{ value: "", label: column.filterPlaceholder ?? "All" }, ...column.filterOptions],
1467
- onChange: (value) => changeFilter(column.key, value),
1468
- placeholder: column.filterPlaceholder ?? "All"
1469
- }
1470
- ) : /* @__PURE__ */ jsx(
1471
- "input",
1472
- {
1473
- value: filters[column.key] ?? "",
1474
- onChange: (event) => changeFilter(column.key, event.target.value),
1475
- placeholder: `Filter ${column.header.toLowerCase()}`
1476
- }
1477
- )
1478
- ] }, column.key)) })
1479
- ] }) : null
1480
- ] }) : /* @__PURE__ */ jsxs("div", { className: "side-rail-icons", children: [
1481
- /* @__PURE__ */ jsxs("label", { className: "side-rail-icon preview-check-icon", title: "Preview", children: [
1482
- /* @__PURE__ */ jsx(
1483
- "input",
1484
- {
1485
- type: "checkbox",
1486
- checked: previewEnabled,
1487
- onChange: (event) => setPreviewEnabledValue(event.target.checked),
1488
- "aria-label": "Preview"
1489
- }
1490
- ),
1491
- /* @__PURE__ */ jsx(PreviewIcon, {})
1492
- ] }),
1493
- showAdd ? /* @__PURE__ */ jsx("button", { type: "button", className: "ghost side-rail-icon", title: addLabel, "aria-label": addLabel, onClick: onAdd, children: /* @__PURE__ */ jsx(PlusIcon, {}) }) : null,
1494
- showColumns ? /* @__PURE__ */ jsxs(
1495
- "button",
1496
- {
1497
- type: "button",
1498
- className: "ghost side-rail-icon",
1499
- title: "Columns",
1500
- "aria-label": "Columns",
1501
- onClick: () => {
1502
- setSideOpen(true);
1503
- setColumnsOpen(true);
1504
- },
1505
- children: [
1506
- /* @__PURE__ */ jsx(ColumnsIcon, {}),
1507
- hiddenColumnCount > 0 ? /* @__PURE__ */ jsx("span", { className: "filter-badge", children: hiddenColumnCount }) : null
1508
- ]
1509
- }
1510
- ) : null,
1511
- showDownload ? /* @__PURE__ */ jsx(
1512
- "button",
1513
- {
1514
- type: "button",
1515
- className: "ghost side-rail-icon",
1516
- title: "Download",
1517
- "aria-label": "Download",
1518
- "aria-expanded": downloadOpen,
1519
- disabled: downloadBusy,
1520
- onClick: () => {
1521
- setSideOpen(true);
1522
- setDownloadOpen(true);
1523
- },
1524
- children: /* @__PURE__ */ jsx(DownloadIcon, {})
1525
- }
1526
- ) : null,
1527
- showFilters ? /* @__PURE__ */ jsxs(
1528
- "button",
1529
- {
1530
- type: "button",
1531
- className: "ghost side-rail-icon",
1532
- title: "Show filters",
1533
- "aria-label": "Show filters",
1534
- onClick: () => setSideOpen(true),
1535
- children: [
1536
- /* @__PURE__ */ jsx(FilterIcon, {}),
1537
- activeFilterCount > 0 ? /* @__PURE__ */ jsx("span", { className: "filter-badge", children: activeFilterCount }) : null
1538
- ]
1539
- }
1540
- ) : null,
1541
- showFilters ? /* @__PURE__ */ jsx(
1542
- "button",
1543
- {
1544
- type: "button",
1545
- className: "ghost side-rail-icon",
1546
- title: "Reset filters",
1547
- "aria-label": "Reset filters",
1548
- disabled: activeFilterCount === 0,
1549
- onClick: clearFilters,
1550
- children: /* @__PURE__ */ jsx(ResetIcon, {})
1551
- }
1552
- ) : null
1553
- ] })
1741
+ sideOpen ? renderToolsBody({ compactIcons: false }) : renderToolsBody({ compactIcons: true })
1554
1742
  ] })
1555
1743
  ]
1556
1744
  }
1557
1745
  ),
1746
+ isClient ? createPortal(
1747
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1748
+ /* @__PURE__ */ jsx(
1749
+ "button",
1750
+ {
1751
+ type: "button",
1752
+ className: toolsDrawerOpen ? "tools-drawer-backdrop open" : "tools-drawer-backdrop",
1753
+ "aria-label": "Close tools",
1754
+ tabIndex: toolsDrawerOpen ? 0 : -1,
1755
+ onClick: () => setToolsDrawerOpen(false)
1756
+ }
1757
+ ),
1758
+ /* @__PURE__ */ jsxs(
1759
+ "aside",
1760
+ {
1761
+ id: "aksui-tools-drawer",
1762
+ className: toolsDrawerOpen ? "tools-drawer open" : "tools-drawer",
1763
+ "aria-label": "Workspace tools",
1764
+ "aria-hidden": !toolsDrawerOpen,
1765
+ children: [
1766
+ /* @__PURE__ */ jsxs("div", { className: "tools-drawer-head", children: [
1767
+ /* @__PURE__ */ jsxs("div", { children: [
1768
+ /* @__PURE__ */ jsx("p", { className: "tools-drawer-kicker", children: "Workspace" }),
1769
+ /* @__PURE__ */ jsx("h3", { children: "Tools" })
1770
+ ] }),
1771
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ghost tools-drawer-close", onClick: () => setToolsDrawerOpen(false), children: "Close" })
1772
+ ] }),
1773
+ /* @__PURE__ */ jsx("div", { className: "tools-drawer-body", children: renderToolsBody({ compactIcons: false }) })
1774
+ ]
1775
+ }
1776
+ )
1777
+ ] }),
1778
+ document.body
1779
+ ) : null,
1558
1780
  form,
1559
- isClient && tooltip && !previewEnabled ? createPortal(
1781
+ isClient && actionsMenu && actionsMenuItem ? createPortal(
1782
+ /* @__PURE__ */ jsxs(
1783
+ "div",
1784
+ {
1785
+ ref: actionsMenuRef,
1786
+ className: "row-action-menu row-action-menu-portal",
1787
+ role: "menu",
1788
+ style: { left: actionsMenu.x, top: actionsMenu.y },
1789
+ children: [
1790
+ onView ? /* @__PURE__ */ jsx(
1791
+ "button",
1792
+ {
1793
+ type: "button",
1794
+ role: "menuitem",
1795
+ className: "ghost",
1796
+ onClick: () => {
1797
+ setActionsMenu(null);
1798
+ onView(actionsMenuItem);
1799
+ },
1800
+ children: "View"
1801
+ }
1802
+ ) : null,
1803
+ onUpdate ? /* @__PURE__ */ jsx(
1804
+ "button",
1805
+ {
1806
+ type: "button",
1807
+ role: "menuitem",
1808
+ className: "ghost",
1809
+ disabled: !actionsUpdateAllowed,
1810
+ onClick: () => {
1811
+ setActionsMenu(null);
1812
+ onUpdate(actionsMenuItem);
1813
+ },
1814
+ children: "Update"
1815
+ }
1816
+ ) : null,
1817
+ onDelete ? /* @__PURE__ */ jsx(
1818
+ "button",
1819
+ {
1820
+ type: "button",
1821
+ role: "menuitem",
1822
+ className: "ghost danger",
1823
+ disabled: !actionsDeleteAllowed,
1824
+ onClick: () => {
1825
+ setActionsMenu(null);
1826
+ onDelete(actionsMenuItem);
1827
+ },
1828
+ children: "Delete"
1829
+ }
1830
+ ) : null
1831
+ ]
1832
+ }
1833
+ ),
1834
+ document.body
1835
+ ) : null,
1836
+ isClient && tooltip && canShowTooltip ? createPortal(
1560
1837
  /* @__PURE__ */ jsxs("div", { className: "record-tooltip", style: { left: tooltip.x, top: tooltip.y }, role: "tooltip", children: [
1561
1838
  /* @__PURE__ */ jsx("p", { className: "record-tooltip-title", children: title }),
1562
1839
  /* @__PURE__ */ jsx(DetailList, { lines: tooltip.lines })