@eyesee/ui-components 0.15.1 → 0.17.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.
@@ -1,7 +1,7 @@
1
1
  import { jsxs as m, jsx as r } from "react/jsx-runtime";
2
- import { useState as E, useRef as L, useEffect as R } from "react";
2
+ import { useState as L, useRef as R, useEffect as S } from "react";
3
3
  import p from "clsx";
4
- import { ChevronDownIcon as S } from "../icons-v2/ChevronDownIcon.js";
4
+ import { ChevronDownIcon as W } from "../icons-v2/ChevronDownIcon.js";
5
5
  import { ChevronUpIcon as A } from "../icons-v2/ChevronUpIcon.js";
6
6
  import U from "../../hooks/useClickOutside.js";
7
7
  import { ListItem as q } from "../ListItem/ListItem.js";
@@ -13,36 +13,36 @@ function Z({
13
13
  options: f = [],
14
14
  onClick: u = () => {
15
15
  },
16
- className: v,
16
+ className: N,
17
17
  iconSize: h = "m",
18
- size: N = "md",
19
- variant: O = "primary",
20
- type: g = "fill",
18
+ size: O = "md",
19
+ variant: g = "primary",
20
+ type: y = "fill",
21
21
  pressed: d = !1,
22
22
  icon: s = null,
23
23
  tooltipContent: b = null,
24
- tooltipTitle: y,
24
+ tooltipTitle: D,
25
25
  disabled: i = !1,
26
- fullWidth: D = !1,
26
+ fullWidth: I = !1,
27
27
  dropdownAlign: x = "start",
28
28
  tooltipProps: k = { position: "bottom", variant: "light" },
29
29
  dropdownCustomContent: c = null,
30
30
  ...B
31
31
  }) {
32
- const [l, o] = E(!1), I = L(null);
33
- U(I, () => o(!1));
32
+ const [l, o] = L(!1), w = R(null);
33
+ U(w, () => o(!1));
34
34
  const T = (n) => {
35
35
  u(n), o(!1);
36
36
  };
37
- R(() => {
37
+ S(() => {
38
38
  i && l && o(!1);
39
39
  }, [i, l]);
40
- const t = f.length > 0 || !!c, W = s && !a && !t, j = s && !a, C = !!b, w = /* @__PURE__ */ m(
40
+ const t = f.length > 0 || !!c, j = s && !a && !t, C = s && !a, E = !!b, v = /* @__PURE__ */ m(
41
41
  "div",
42
42
  {
43
- ref: I,
43
+ ref: w,
44
44
  "data-button-wrapper": !0,
45
- className: p(e.wrapper, v, D && e.fullWidth),
45
+ className: p(e.wrapper, N, I && e.fullWidth),
46
46
  ...B,
47
47
  children: [
48
48
  /* @__PURE__ */ m(
@@ -51,12 +51,12 @@ function Z({
51
51
  type: "button",
52
52
  className: p(
53
53
  e.button,
54
- e[N],
55
54
  e[O],
56
55
  e[g],
56
+ e[y],
57
57
  t && e.hasDropdown,
58
- W && e.iconOnly,
59
- j && e.isIcon,
58
+ j && e.iconOnly,
59
+ C && e.isIcon,
60
60
  d && e.pressed
61
61
  ),
62
62
  onClick: () => t ? o((n) => !n) : u(),
@@ -78,7 +78,7 @@ function Z({
78
78
  ]
79
79
  }
80
80
  ),
81
- t && /* @__PURE__ */ r("span", { className: e.buttonArrow, children: l ? /* @__PURE__ */ r(A, { iconSize: h }) : /* @__PURE__ */ r(S, { iconSize: h }) })
81
+ t && /* @__PURE__ */ r("span", { className: e.buttonArrow, children: l ? /* @__PURE__ */ r(A, { iconSize: h }) : /* @__PURE__ */ r(W, { iconSize: h }) })
82
82
  ]
83
83
  }
84
84
  ),
@@ -98,7 +98,7 @@ function Z({
98
98
  ]
99
99
  }
100
100
  );
101
- return C ? /* @__PURE__ */ r(F, { title: y, content: b, ...k, children: w }) : w;
101
+ return E ? /* @__PURE__ */ r(F, { title: D, content: b, ...k, fullWidth: I, children: v }) : v;
102
102
  }
103
103
  export {
104
104
  Z as Button
@@ -1,65 +1,58 @@
1
- import { jsxs as f, Fragment as p, jsx as m } from "react/jsx-runtime";
2
- import { useRef as I, useState as E } from "react";
3
- import { createPortal as M } from "react-dom";
4
- import P from "../ImagePlaceholder.js";
5
- import u from "./ImageHoverPreview.module.scss.js";
6
- const w = 200, r = 8, d = 8, x = () => document.getElementById("modal") ?? document.body, g = (t, e, a) => Math.min(Math.max(t, e), a);
7
- function j({ previewSize: t = w, ...e }) {
8
- const a = I(null), [s, i] = E(null);
1
+ import { jsxs as f, Fragment as p, jsx as i } from "react/jsx-runtime";
2
+ import { useRef as P, useState as I } from "react";
3
+ import { createPortal as E } from "react-dom";
4
+ import u from "../ImagePlaceholder.js";
5
+ import M from "./ImageHoverPreview.module.scss.js";
6
+ const w = 200, n = 8, d = 8, A = () => document.getElementById("modal") ?? document.body, h = (t, r, a) => Math.min(Math.max(t, r), a);
7
+ function B({ previewSize: t = w, ...r }) {
8
+ const a = P(null), [s, m] = I(null);
9
9
  return /* @__PURE__ */ f(p, { children: [
10
- /* @__PURE__ */ m(
11
- P,
10
+ /* @__PURE__ */ i(
11
+ u,
12
12
  {
13
- ...e,
13
+ ...r,
14
14
  imageAreaRef: a,
15
15
  onImageAreaMouseEnter: (l) => {
16
16
  var c;
17
17
  l.stopPropagation();
18
- const o = (c = a.current) == null ? void 0 : c.getBoundingClientRect();
19
- if (!o) return;
20
- let n = o.right + d;
21
- n + t > window.innerWidth - r && (n = o.left - t - d), n = g(
18
+ const e = (c = a.current) == null ? void 0 : c.getBoundingClientRect();
19
+ if (!e) return;
20
+ let o = e.right + d;
21
+ o + t > window.innerWidth - n && (o = e.left - t - d), o = h(
22
+ o,
22
23
  n,
23
- r,
24
- window.innerWidth - t - r
24
+ window.innerWidth - t - n
25
25
  );
26
- const h = g(
27
- o.top + o.height / 2 - t / 2,
28
- r,
29
- window.innerHeight - t - r
26
+ const g = h(
27
+ e.top + e.height / 2 - t / 2,
28
+ n,
29
+ window.innerHeight - t - n
30
30
  );
31
- i({ top: h, left: n });
31
+ m({ top: g, left: o });
32
32
  },
33
33
  onImageAreaMouseLeave: (l) => {
34
- l.stopPropagation(), i(null);
34
+ l.stopPropagation(), m(null);
35
35
  }
36
36
  }
37
37
  ),
38
- s && M(
39
- /* @__PURE__ */ m(
38
+ s && E(
39
+ /* @__PURE__ */ i(
40
40
  "div",
41
41
  {
42
- className: u.preview,
42
+ className: M.preview,
43
43
  style: {
44
44
  top: s.top,
45
45
  left: s.left,
46
46
  width: t,
47
47
  height: t
48
48
  },
49
- children: /* @__PURE__ */ m(
50
- "img",
51
- {
52
- src: e.url,
53
- alt: e.text ?? "",
54
- className: u.previewImage
55
- }
56
- )
49
+ children: /* @__PURE__ */ i(u, { url: r.url })
57
50
  }
58
51
  ),
59
- x()
52
+ A()
60
53
  )
61
54
  ] });
62
55
  }
63
56
  export {
64
- j as ImageHoverPreview
57
+ B as ImageHoverPreview
65
58
  };
@@ -1,9 +1,7 @@
1
- const e = "_preview_18mb5_3", p = "_previewImage_18mb5_12", r = {
2
- preview: e,
3
- previewImage: p
1
+ const e = "_preview_10zam_3", t = {
2
+ preview: e
4
3
  };
5
4
  export {
6
- r as default,
7
- e as preview,
8
- p as previewImage
5
+ t as default,
6
+ e as preview
9
7
  };
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Flexible table with per-column custom headers and cells, plus optional infinite scroll.
3
+ *
4
+ * @param {TableProps} props
5
+ * @returns {import('react').ReactElement}
6
+ *
7
+ * @example <caption>Columns, rows, infinite scroll</caption>
8
+ * import { Button, Checkbox, Table } from '@eyesee/ui-components';
9
+ *
10
+ * const columns = [
11
+ * {
12
+ * id: 'select',
13
+ * width: 'max-content',
14
+ * align: 'center',
15
+ * renderHeader: () => <Checkbox aria-label="Select all" />,
16
+ * renderCell: (row, rowIndex) => (
17
+ * <Checkbox checked={row.selected} aria-label={`Select row ${rowIndex + 1}`} />
18
+ * ),
19
+ * },
20
+ * {
21
+ * id: 'name',
22
+ * headerTitle: 'Product',
23
+ * renderCell: (row, rowIndex, column) => row.name,
24
+ * },
25
+ * {
26
+ * id: 'qty',
27
+ * width: 96,
28
+ * align: 'end',
29
+ * renderHeader: (column) => <strong>{column.headerTitle ?? 'Qty'}</strong>,
30
+ * headerTitle: 'Qty',
31
+ * renderCell: (row) => row.qty,
32
+ * },
33
+ * {
34
+ * id: 'actions',
35
+ * width: '10rem',
36
+ * align: 'center',
37
+ * renderHeader: () => null,
38
+ * renderCell: (row) => <Button text="Edit" onClick={() => editRow(row.id)} />,
39
+ * },
40
+ * ];
41
+ *
42
+ * // Shape is yours — fields below match only what `columns` / callbacks read.
43
+ * const rows = [
44
+ * { id: 1, name: 'Granola pack', qty: 12, selected: true },
45
+ * { id: 2, name: 'Shelf display', qty: 3, selected: false },
46
+ * ];
47
+ *
48
+ * <Table
49
+ * aria-label="Orders"
50
+ * rowHeight={80}
51
+ * headerHeight={56}
52
+ * columns={columns}
53
+ * rows={rows}
54
+ * getRowKey={(row) => row.id}
55
+ * isRowSubtle={(row) => row.selected}
56
+ * hasMore={hasNextPage}
57
+ * isLoadingMore={isFetchingNextPage}
58
+ * onLoadMore={fetchNextPage}
59
+ * loadMoreThreshold={50}
60
+ * loadingMoreContent="Loading more…"
61
+ * />
62
+ *
63
+ * @example <caption>Client-side sort</caption>
64
+ * import { Table, useTableClientSort } from '@eyesee/ui-components';
65
+ *
66
+ * const sortableColumns = [
67
+ * {
68
+ * id: 'name',
69
+ * headerTitle: 'Product',
70
+ * sortable: true,
71
+ * sortValue: (row) => row.name,
72
+ * renderCell: (row) => row.name,
73
+ * },
74
+ * ];
75
+ *
76
+ * const { sort, onSortChange, sortedRows } = useTableClientSort({
77
+ * rows,
78
+ * columns: sortableColumns,
79
+ * });
80
+ *
81
+ * <Table
82
+ * aria-label="Orders"
83
+ * columns={sortableColumns}
84
+ * rows={sortedRows}
85
+ * sort={sort}
86
+ * onSortChange={onSortChange}
87
+ * />
88
+ *
89
+ * @example <caption>Server-side sort (fetch in parent)</caption>
90
+ * <Table
91
+ * aria-label="Orders"
92
+ * columns={sortableColumns}
93
+ * rows={rowsFromApi}
94
+ * sort={sort}
95
+ * onSortChange={handleSortChange}
96
+ * isSortLoading={isFetchingSort}
97
+ * sortError={sortFetchError}
98
+ * />
99
+ */
100
+ export function Table({ columns, rows, getRowKey, "aria-label": ariaLabel, hasMore, isLoadingMore, onLoadMore, loadMoreThreshold, loadingMoreContent, isRowSubtle, rowHeight, headerHeight, sort, onSortChange, isSortLoading, sortError, }: TableProps): import("react").ReactElement;
101
+ export type TableColumn = {
102
+ /**
103
+ * Unique column key.
104
+ */
105
+ id: string;
106
+ /**
107
+ * Default header label when `renderHeader` is omitted.
108
+ */
109
+ headerTitle?: string;
110
+ /**
111
+ * Custom header cell content. Receives the column definition.
112
+ */
113
+ renderHeader?: (column: TableColumn) => import("react").ReactNode;
114
+ /**
115
+ * Custom body cell content.
116
+ */
117
+ renderCell: (row: any, rowIndex: number, column: TableColumn) => import("react").ReactNode;
118
+ /**
119
+ * Column width (e.g. `128`, `'128px'`, `'max-content'`). Omit `width` for a fluid column that
120
+ * shares remaining space.
121
+ */
122
+ width?: string | number;
123
+ /**
124
+ * Horizontal alignment inside the cell. Default `'start'`.
125
+ */
126
+ align?: "start" | "center" | "end";
127
+ /**
128
+ * When true and `onSortChange` is set on {@link Table}, the default header (`headerTitle`) is
129
+ * sort arrows (up applies/clears asc, down applies/clears desc). Custom `renderHeader` must wire
130
+ * sort UI yourself; `aria-sort` is still applied on the column header.
131
+ */
132
+ sortable?: boolean;
133
+ /**
134
+ * Used with {@link useTableClientSort} / {@link sortTableRows} for client-side sort (not read by
135
+ * {@link Table} itself).
136
+ */
137
+ sortValue?: (row: any) => string | number | null | undefined;
138
+ };
139
+ export type TableSort = {
140
+ /**
141
+ * Active sort column id.
142
+ */
143
+ columnId: string;
144
+ /**
145
+ * Sort direction.
146
+ */
147
+ direction: "asc" | "desc";
148
+ };
149
+ export type TableSortChangeHandler = (sort: TableSort | null) => void;
150
+ export type TableLoadMoreHandler = () => void;
151
+ export type TableRowKeyGetter = (row: any, index: number) => string | number;
152
+ export type TableRowSubtlePredicate = (row: any, index: number) => boolean;
153
+ export type TableProps = {
154
+ /**
155
+ * Column definitions (order defines layout).
156
+ */
157
+ columns: TableColumn[];
158
+ /**
159
+ * Arbitrary row objects from your app. `Table` does not read fixed keys — only what you use in
160
+ * `renderCell`, `getRowKey`, and `isRowSubtle`.
161
+ */
162
+ rows: any[];
163
+ /**
164
+ * Stable React key per row. Default uses `row.id` or the row index.
165
+ */
166
+ getRowKey?: TableRowKeyGetter;
167
+ /**
168
+ * Accessible name for the table region. Parent must define height (`height: 100%` or flex
169
+ * child with `flex: 1` and `min-height: 0`) so the table can fill it and scroll internally.
170
+ */
171
+ "aria-label"?: string;
172
+ /**
173
+ * When true, scrolling near the bottom can trigger `onLoadMore`. Default `false`.
174
+ */
175
+ hasMore?: boolean;
176
+ /**
177
+ * Suppresses duplicate `onLoadMore` calls while a page is loading. Default `false`.
178
+ */
179
+ isLoadingMore?: boolean;
180
+ /**
181
+ * Called when the user scrolls within `loadMoreThreshold` px of the bottom.
182
+ */
183
+ onLoadMore?: TableLoadMoreHandler;
184
+ /**
185
+ * Distance from the bottom (px) that triggers `onLoadMore`. Default `50`.
186
+ */
187
+ loadMoreThreshold?: number;
188
+ /**
189
+ * Shown at the bottom while `isLoadingMore` is true.
190
+ */
191
+ loadingMoreContent?: import("react").ReactNode;
192
+ /**
193
+ * When true for a row, applies the subtle background (selected/highlight row).
194
+ */
195
+ isRowSubtle?: TableRowSubtlePredicate;
196
+ /**
197
+ * Fixed body row height (e.g. `80`). Default `80`.
198
+ */
199
+ rowHeight?: string | number;
200
+ /**
201
+ * Fixed header row height (e.g. `56`). Default `56`.
202
+ */
203
+ headerHeight?: string | number;
204
+ /**
205
+ * Active sort (controlled). Default `null`.
206
+ */
207
+ sort?: TableSort | null;
208
+ /**
209
+ * Fired when sort arrows are used. Update `sort` and supply `rows` (e.g. fetch sorted data from
210
+ * the server, or use {@link useTableClientSort} and pass `sortedRows`).
211
+ */
212
+ onSortChange?: TableSortChangeHandler;
213
+ /**
214
+ * When true (e.g. while fetching server-sorted `rows`), body rows are hidden and a loader is
215
+ * shown until new data arrives. Default `false`.
216
+ */
217
+ isSortLoading?: boolean;
218
+ /**
219
+ * When set (and not `isSortLoading`), body rows are hidden and an error message is shown instead
220
+ * (same slot as the sort loader). Clear on retry or the next successful fetch. Default
221
+ * `undefined`.
222
+ */
223
+ sortError?: import("react").ReactNode;
224
+ };
225
+ export { getTableSortFromArrowClick, sortTableRows } from "./tableSort/tableSortUtils";
@@ -0,0 +1,135 @@
1
+ import { jsx as t, jsxs as C } from "react/jsx-runtime";
2
+ import { useRef as I, useCallback as K, useEffect as R } from "react";
3
+ import d from "clsx";
4
+ import { LoaderIcon as W } from "../icons-v2/LoaderIcon.js";
5
+ import { renderTableColumnHeader as $ } from "./TableColumnHeader/TableColumnHeader.js";
6
+ import r from "./Table.module.scss.js";
7
+ import { Infobox as q } from "../Infobox/Infobox.js";
8
+ function v(e) {
9
+ if (e != null)
10
+ return typeof e == "number" ? `${e}px` : e;
11
+ }
12
+ function D(e) {
13
+ return e.map((a) => a.width == null ? "minmax(0, 1fr)" : v(a.width)).join(" ");
14
+ }
15
+ function x(e) {
16
+ if (e === "start") return r.alignStart;
17
+ if (e === "center") return r.alignCenter;
18
+ if (e === "end") return r.alignEnd;
19
+ }
20
+ function J(e, a) {
21
+ if (e.sortable)
22
+ return !a || a.columnId !== e.id ? "none" : a.direction === "asc" ? "ascending" : "descending";
23
+ }
24
+ function Y({
25
+ columns: e,
26
+ rows: a,
27
+ getRowKey: T = (n, h) => (n == null ? void 0 : n.id) ?? h,
28
+ "aria-label": j,
29
+ hasMore: b = !1,
30
+ isLoadingMore: c = !1,
31
+ onLoadMore: f,
32
+ loadMoreThreshold: g = 50,
33
+ loadingMoreContent: k = "Loading…",
34
+ isRowSubtle: u,
35
+ rowHeight: w = 80,
36
+ headerHeight: B = 56,
37
+ sort: N = null,
38
+ onSortChange: H,
39
+ isSortLoading: i = !1,
40
+ sortError: m
41
+ }) {
42
+ const n = I(!1), h = K(
43
+ (l) => {
44
+ if (!b || c || i || !f)
45
+ return;
46
+ const s = l.currentTarget;
47
+ if (s.scrollHeight - s.scrollTop - s.clientHeight > g) {
48
+ n.current = !1;
49
+ return;
50
+ }
51
+ n.current || (n.current = !0, f());
52
+ },
53
+ [b, c, i, g, f]
54
+ );
55
+ R(() => {
56
+ c || (n.current = !1);
57
+ }, [c]);
58
+ const A = D(e), F = { height: v(B) }, z = { height: v(w) }, E = i || !!m;
59
+ let p = null;
60
+ return i ? p = /* @__PURE__ */ t(
61
+ W,
62
+ {
63
+ iconSize: "xl",
64
+ strokeColor: "var(--color--text--default--body-lighter)",
65
+ animated: !0
66
+ }
67
+ ) : m && (p = /* @__PURE__ */ t(q, { title: "Error sorting table", text: m, status: "error", fullWidth: !0 })), /* @__PURE__ */ t("div", { className: r.table, children: /* @__PURE__ */ C(
68
+ "div",
69
+ {
70
+ className: r.scrollArea,
71
+ onScroll: h,
72
+ role: "table",
73
+ "aria-label": j,
74
+ "aria-busy": i || void 0,
75
+ children: [
76
+ /* @__PURE__ */ C("div", { className: r.gridTable, style: { gridTemplateColumns: A }, children: [
77
+ /* @__PURE__ */ t("div", { role: "rowgroup", className: r.rowgroup, children: /* @__PURE__ */ t("div", { className: r.header, role: "row", style: F, children: e.map((l) => /* @__PURE__ */ t(
78
+ "div",
79
+ {
80
+ role: "columnheader",
81
+ "aria-sort": J(l, N),
82
+ className: d(
83
+ r.cell,
84
+ x(l.align ?? "start")
85
+ ),
86
+ children: $(
87
+ l,
88
+ N,
89
+ H,
90
+ i
91
+ )
92
+ },
93
+ l.id
94
+ )) }) }),
95
+ /* @__PURE__ */ t("div", { className: r.body, role: "rowgroup", children: E ? /* @__PURE__ */ t("div", { role: "row", className: d(r.row, r.statusRow), children: /* @__PURE__ */ t(
96
+ "div",
97
+ {
98
+ role: "cell",
99
+ className: r.infoContent,
100
+ "aria-live": i ? "polite" : "assertive",
101
+ children: p
102
+ }
103
+ ) }) : a.map((l, s) => {
104
+ const y = T(l, s), G = (u == null ? void 0 : u(l, s)) ?? !1;
105
+ return /* @__PURE__ */ t(
106
+ "div",
107
+ {
108
+ role: "row",
109
+ className: d(r.row, G && r.subtle),
110
+ style: z,
111
+ children: e.map((o) => /* @__PURE__ */ t(
112
+ "div",
113
+ {
114
+ role: "cell",
115
+ className: d(
116
+ r.cell,
117
+ x(o.align ?? "start")
118
+ ),
119
+ children: o.renderCell(l, s, o)
120
+ },
121
+ o.id
122
+ ))
123
+ },
124
+ y
125
+ );
126
+ }) })
127
+ ] }),
128
+ c ? /* @__PURE__ */ t("div", { className: r.loadMore, "aria-live": "polite", children: k }) : null
129
+ ]
130
+ }
131
+ ) });
132
+ }
133
+ export {
134
+ Y as Table
135
+ };
@@ -0,0 +1,33 @@
1
+ const o = "_table_181fo_3", _ = "_scrollArea_181fo_16", n = "_gridTable_181fo_23", t = "_rowgroup_181fo_28", e = "_header_181fo_32", l = "_row_181fo_28", r = "_body_181fo_50", a = "_subtle_181fo_60", s = "_cell_181fo_64", c = "_alignStart_181fo_74", f = "_alignCenter_181fo_77", d = "_alignEnd_181fo_80", g = "_infoContent_181fo_84", i = "_loadMore_181fo_95", b = {
2
+ table: o,
3
+ scrollArea: _,
4
+ gridTable: n,
5
+ rowgroup: t,
6
+ header: e,
7
+ row: l,
8
+ body: r,
9
+ subtle: a,
10
+ cell: s,
11
+ alignStart: c,
12
+ alignCenter: f,
13
+ alignEnd: d,
14
+ infoContent: g,
15
+ loadMore: i
16
+ };
17
+ export {
18
+ f as alignCenter,
19
+ d as alignEnd,
20
+ c as alignStart,
21
+ r as body,
22
+ s as cell,
23
+ b as default,
24
+ n as gridTable,
25
+ e as header,
26
+ g as infoContent,
27
+ i as loadMore,
28
+ l as row,
29
+ t as rowgroup,
30
+ _ as scrollArea,
31
+ a as subtle,
32
+ o as table
33
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @param {object} props
3
+ * @param {TableColumnHeaderColumn} props.column
4
+ * @param {TableSort|null} props.sort
5
+ * @param {TableSortChangeHandler} props.onSortChange
6
+ * @param {boolean} [props.isSortLoading]
7
+ * @returns {import('react').ReactElement}
8
+ */
9
+ export function TableSortableHeader({ column, sort, onSortChange, isSortLoading }: {
10
+ column: TableColumnHeaderColumn;
11
+ sort: TableSort | null;
12
+ onSortChange: TableSortChangeHandler;
13
+ isSortLoading?: boolean;
14
+ }): import("react").ReactElement;
15
+ /**
16
+ * @param {TableColumnHeaderColumn} column
17
+ * @param {TableSort|null} sort
18
+ * @param {TableSortChangeHandler} [onSortChange]
19
+ * @param {boolean} [isSortLoading]
20
+ * @returns {import('react').ReactNode}
21
+ */
22
+ export function renderTableColumnHeader(column: TableColumnHeaderColumn, sort: TableSort | null, onSortChange?: TableSortChangeHandler, isSortLoading?: boolean): import("react").ReactNode;
23
+ export type TableColumnHeaderColumn = {
24
+ id: string;
25
+ headerTitle?: string;
26
+ renderHeader?: (column: TableColumnHeaderColumn) => import("react").ReactNode;
27
+ sortable?: boolean;
28
+ };
29
+ export type TableSort = {
30
+ columnId: string;
31
+ direction: "asc" | "desc";
32
+ };
33
+ export type TableSortChangeHandler = (sort: TableSort | null) => void;
@@ -0,0 +1,60 @@
1
+ import { jsx as i, jsxs as l } from "react/jsx-runtime";
2
+ import { ArrowDownIcon as f } from "../../icons-v2/ArrowDownIcon.js";
3
+ import { ArrowUpIcon as p } from "../../icons-v2/ArrowUpIcon.js";
4
+ import { Button as c } from "../../Button/Button.js";
5
+ import { getTableSortFromArrowClick as h } from "../tableSort/tableSortUtils.js";
6
+ import n from "./TableColumnHeader.module.scss.js";
7
+ function b(e) {
8
+ return e.headerTitle ? /* @__PURE__ */ i("span", { className: n.headerTitle, children: e.headerTitle }) : null;
9
+ }
10
+ function x({ column: e, sort: r, onSortChange: t, isSortLoading: a = !1 }) {
11
+ const d = (r == null ? void 0 : r.columnId) === e.id ? r.direction : null, s = (o) => {
12
+ a || t(h(r, e.id, o));
13
+ };
14
+ return /* @__PURE__ */ l("div", { className: n.sortHeader, children: [
15
+ /* @__PURE__ */ i("span", { className: n.headerTitle, children: e.headerTitle }),
16
+ /* @__PURE__ */ l("span", { className: n.sortIcons, children: [
17
+ /* @__PURE__ */ i(
18
+ c,
19
+ {
20
+ type: "blank",
21
+ variant: "neutral",
22
+ size: "xxxxs",
23
+ onClick: () => s("asc"),
24
+ disabled: a,
25
+ pressed: d === "asc",
26
+ "aria-label": `Sort ${e.headerTitle} ascending`,
27
+ icon: /* @__PURE__ */ i(p, { iconSize: "s" })
28
+ }
29
+ ),
30
+ /* @__PURE__ */ i(
31
+ c,
32
+ {
33
+ type: "blank",
34
+ variant: "neutral",
35
+ size: "xxxxs",
36
+ pressed: d === "desc",
37
+ icon: /* @__PURE__ */ i(f, { iconSize: "s" }),
38
+ onClick: () => s("desc"),
39
+ disabled: a,
40
+ "aria-label": `Sort ${e.headerTitle} descending`
41
+ }
42
+ )
43
+ ] })
44
+ ] });
45
+ }
46
+ function w(e, r, t, a) {
47
+ return e.renderHeader ? e.renderHeader(e) : e.sortable && t && e.headerTitle ? /* @__PURE__ */ i(
48
+ x,
49
+ {
50
+ column: e,
51
+ sort: r,
52
+ onSortChange: t,
53
+ isSortLoading: a
54
+ }
55
+ ) : b(e);
56
+ }
57
+ export {
58
+ x as TableSortableHeader,
59
+ w as renderTableColumnHeader
60
+ };