@mshuja288/aksuicore 0.2.1 → 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,12 @@ 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
+
10
16
  ## [0.2.1] — 2026-10-05
11
17
 
12
18
  ### Added
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
@@ -728,6 +728,11 @@ function useIsClient2() {
728
728
  () => false
729
729
  );
730
730
  }
731
+ var EXPORT_FORMAT_OPTIONS = [
732
+ { format: "csv", label: "CSV" },
733
+ { format: "xlsx", label: "Excel" },
734
+ { format: "json", label: "JSON" }
735
+ ];
731
736
  function compareColumnValues(column, left, right) {
732
737
  const leftRaw = column.display ? column.display(left) : column.value(left);
733
738
  const rightRaw = column.display ? column.display(right) : column.value(right);
@@ -770,6 +775,13 @@ function PreviewIcon() {
770
775
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "2.4", fill: "none", stroke: "currentColor", strokeWidth: "1.6" })
771
776
  ] });
772
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
+ }
773
785
  function DetailList({ lines }) {
774
786
  return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "record-detail-list", children: lines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "record-detail-row", children: [
775
787
  /* @__PURE__ */ jsxRuntime.jsx("dt", { children: line.label }),
@@ -790,6 +802,9 @@ function RecordWorkspace({
790
802
  onDelete,
791
803
  canUpdate,
792
804
  canDelete,
805
+ onDownload,
806
+ canDownload = true,
807
+ downloadBusy = false,
793
808
  toolbar,
794
809
  form
795
810
  }) {
@@ -797,6 +812,7 @@ function RecordWorkspace({
797
812
  const [filters, setFilters] = react.useState({});
798
813
  const [sort, setSort] = react.useState(null);
799
814
  const [sideOpen, setSideOpen] = react.useState(false);
815
+ const [downloadOpen, setDownloadOpen] = react.useState(false);
800
816
  const [previewEnabled, setPreviewEnabled] = react.useState(false);
801
817
  const [previewKey, setPreviewKey] = react.useState(null);
802
818
  const [tooltip, setTooltip] = react.useState(null);
@@ -842,8 +858,16 @@ function RecordWorkspace({
842
858
  const start = showAll ? 0 : (currentPage - 1) * numericPageSize;
843
859
  const pageItems = showAll ? sorted : sorted.slice(start, start + numericPageSize);
844
860
  const showAdd = canAdd && Boolean(onAdd);
861
+ const showDownload = Boolean(onDownload) && canDownload;
845
862
  const showFilters = filterableColumns.length > 0;
846
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
+ }
847
871
  function cellText(column, item) {
848
872
  const raw = column.display ? column.display(item) : column.value(item);
849
873
  return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
@@ -1043,6 +1067,33 @@ function RecordWorkspace({
1043
1067
  /* @__PURE__ */ jsxRuntime.jsx(PlusIcon, {}),
1044
1068
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: addLabel })
1045
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,
1046
1097
  showFilters ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-filters", children: [
1047
1098
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "filter-panel-head", children: [
1048
1099
  /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Filters" }),
@@ -1096,6 +1147,22 @@ function RecordWorkspace({
1096
1147
  /* @__PURE__ */ jsxRuntime.jsx(PreviewIcon, {})
1097
1148
  ] }),
1098
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,
1099
1166
  showFilters ? /* @__PURE__ */ jsxRuntime.jsxs(
1100
1167
  "button",
1101
1168
  {