@mshuja288/aksuicore 0.2.0 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ Versioning follows [VERSIONING.md](./VERSIONING.md).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] — 2026-10-12
11
+
12
+ ### Added
13
+
14
+ - `RecordWorkspace` download control: optional `onDownload(format)` with CSV / Excel / JSON choices in the side rail (`ExportDownloadFormat` type exported)
15
+
16
+ ## [0.2.1] — 2026-10-05
17
+
18
+ ### Added
19
+
20
+ - `ConfirmDeleteDialog` for in-app delete confirmation (Cancel / Delete) before destructive actions
21
+
10
22
  ## [0.2.0] — 2026-10-05
11
23
 
12
24
  ### Changed
package/README.md CHANGED
@@ -4,7 +4,7 @@ Shared React UI library for Ikssam apps — reusable **primitives** and **templa
4
4
 
5
5
  ## Status
6
6
 
7
- `v0.2.0` — package renamed to `@mshuja288/aksuicore`. Published on npmjs. See [CHANGELOG.md](./CHANGELOG.md).
7
+ `v0.3.0` — RecordWorkspace download (CSV / Excel / JSON). Published on npmjs. See [CHANGELOG.md](./CHANGELOG.md).
8
8
 
9
9
  ## AppShell API
10
10
 
package/dist/aksui.css CHANGED
@@ -1211,6 +1211,65 @@ button.side-rail-add:hover {
1211
1211
  background: #2a3546;
1212
1212
  }
1213
1213
 
1214
+ .side-rail-download {
1215
+ display: grid;
1216
+ gap: 8px;
1217
+ }
1218
+
1219
+ button.side-rail-download-toggle {
1220
+ display: inline-flex;
1221
+ align-items: center;
1222
+ justify-content: center;
1223
+ gap: 8px;
1224
+ width: 100%;
1225
+ padding: 10px 12px;
1226
+ border: 1px solid var(--aks-border, #d7dde5);
1227
+ border-radius: var(--aks-radius);
1228
+ background: #fff;
1229
+ color: var(--aks-brand);
1230
+ box-shadow: none;
1231
+ }
1232
+
1233
+ button.side-rail-download-toggle svg {
1234
+ width: 18px;
1235
+ height: 18px;
1236
+ }
1237
+
1238
+ button.side-rail-download-toggle:hover:not(:disabled) {
1239
+ background: #f5f7fa;
1240
+ }
1241
+
1242
+ button.side-rail-download-toggle:disabled {
1243
+ opacity: 0.55;
1244
+ cursor: default;
1245
+ }
1246
+
1247
+ .side-rail-download-formats {
1248
+ display: grid;
1249
+ grid-template-columns: repeat(3, minmax(0, 1fr));
1250
+ gap: 6px;
1251
+ }
1252
+
1253
+ button.side-rail-download-format {
1254
+ padding: 8px 6px;
1255
+ border: 1px solid var(--aks-border, #d7dde5);
1256
+ border-radius: var(--aks-radius);
1257
+ background: #fff;
1258
+ color: var(--aks-brand);
1259
+ font-size: 12px;
1260
+ font-weight: 600;
1261
+ box-shadow: none;
1262
+ }
1263
+
1264
+ button.side-rail-download-format:hover:not(:disabled) {
1265
+ background: #f5f7fa;
1266
+ }
1267
+
1268
+ button.side-rail-download-format:disabled {
1269
+ opacity: 0.45;
1270
+ cursor: default;
1271
+ }
1272
+
1214
1273
  .side-rail-filters {
1215
1274
  display: grid;
1216
1275
  gap: 12px;
package/dist/index.cjs CHANGED
@@ -436,6 +436,21 @@ function Dialog({
436
436
  ) });
437
437
  }
438
438
  var FormDialog = Dialog;
439
+ function ConfirmDeleteDialog({
440
+ open,
441
+ message,
442
+ pending = false,
443
+ onCancel,
444
+ onConfirm
445
+ }) {
446
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { title: "Confirm delete", open, onClose: pending ? () => void 0 : onCancel, wide: false, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "card-form", children: [
447
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "hint", children: message }),
448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "actions", children: [
449
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", onClick: onCancel, disabled: pending, children: "Cancel" }),
450
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "danger", onClick: onConfirm, disabled: pending, children: pending ? "Deleting\u2026" : "Delete" })
451
+ ] })
452
+ ] }) });
453
+ }
439
454
  function useIsClient() {
440
455
  return react.useSyncExternalStore(
441
456
  () => () => {
@@ -713,6 +728,11 @@ function useIsClient2() {
713
728
  () => false
714
729
  );
715
730
  }
731
+ var EXPORT_FORMAT_OPTIONS = [
732
+ { format: "csv", label: "CSV" },
733
+ { format: "xlsx", label: "Excel" },
734
+ { format: "json", label: "JSON" }
735
+ ];
716
736
  function compareColumnValues(column, left, right) {
717
737
  const leftRaw = column.display ? column.display(left) : column.value(left);
718
738
  const rightRaw = column.display ? column.display(right) : column.value(right);
@@ -755,6 +775,13 @@ function PreviewIcon() {
755
775
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "2.4", fill: "none", stroke: "currentColor", strokeWidth: "1.6" })
756
776
  ] });
757
777
  }
778
+ function DownloadIcon() {
779
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
780
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3.5v8.2", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
781
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6.5 9.2 10 12.8l3.5-3.6", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }),
782
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 15.5h12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
783
+ ] });
784
+ }
758
785
  function DetailList({ lines }) {
759
786
  return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "record-detail-list", children: lines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "record-detail-row", children: [
760
787
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: line.label }),
@@ -775,6 +802,9 @@ function RecordWorkspace({
775
802
  onDelete,
776
803
  canUpdate,
777
804
  canDelete,
805
+ onDownload,
806
+ canDownload = true,
807
+ downloadBusy = false,
778
808
  toolbar,
779
809
  form
780
810
  }) {
@@ -782,6 +812,7 @@ function RecordWorkspace({
782
812
  const [filters, setFilters] = react.useState({});
783
813
  const [sort, setSort] = react.useState(null);
784
814
  const [sideOpen, setSideOpen] = react.useState(false);
815
+ const [downloadOpen, setDownloadOpen] = react.useState(false);
785
816
  const [previewEnabled, setPreviewEnabled] = react.useState(false);
786
817
  const [previewKey, setPreviewKey] = react.useState(null);
787
818
  const [tooltip, setTooltip] = react.useState(null);
@@ -827,8 +858,16 @@ function RecordWorkspace({
827
858
  const start = showAll ? 0 : (currentPage - 1) * numericPageSize;
828
859
  const pageItems = showAll ? sorted : sorted.slice(start, start + numericPageSize);
829
860
  const showAdd = canAdd && Boolean(onAdd);
861
+ const showDownload = Boolean(onDownload) && canDownload;
830
862
  const showFilters = filterableColumns.length > 0;
831
863
  const previewItem = previewKey === null ? null : sorted.find((item) => rowKey(item) === previewKey) ?? null;
864
+ function requestDownload(format) {
865
+ if (!onDownload || downloadBusy) {
866
+ return;
867
+ }
868
+ onDownload(format);
869
+ setDownloadOpen(false);
870
+ }
832
871
  function cellText(column, item) {
833
872
  const raw = column.display ? column.display(item) : column.value(item);
834
873
  return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
@@ -1028,6 +1067,33 @@ function RecordWorkspace({
1028
1067
  /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}),
1029
1068
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: addLabel })
1030
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,
1031
1097
  showFilters ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-filters", children: [
1032
1098
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "filter-panel-head", children: [
1033
1099
  /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Filters" }),
@@ -1081,6 +1147,22 @@ function RecordWorkspace({
1081
1147
  /* @__PURE__ */ jsxRuntime.jsx(PreviewIcon, {})
1082
1148
  ] }),
1083
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,
1084
1166
  showFilters ? /* @__PURE__ */ jsxRuntime.jsxs(
1085
1167
  "button",
1086
1168
  {
@@ -1127,6 +1209,7 @@ var RecordTable = RecordWorkspace;
1127
1209
  exports.AppSelect = AppSelect;
1128
1210
  exports.AppShell = AppShell;
1129
1211
  exports.Button = Button;
1212
+ exports.ConfirmDeleteDialog = ConfirmDeleteDialog;
1130
1213
  exports.DateField = DateField;
1131
1214
  exports.Dialog = Dialog;
1132
1215
  exports.FormActions = FormActions;