@pihanga2/shadcn 0.2.21 → 0.2.22
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/README.md +4 -1
- package/cards/attachment/attachment.component.d.ts +4 -0
- package/cards/attachment/attachment.component.js +46 -0
- package/cards/attachment/attachment.component.js.map +1 -0
- package/cards/attachment/attachment.types.d.ts +95 -0
- package/cards/attachment/attachment.types.js +7 -0
- package/cards/attachment/attachment.types.js.map +1 -0
- package/cards/attachment/attachmentGroup.component.d.ts +4 -0
- package/cards/attachment/attachmentGroup.component.js +21 -0
- package/cards/attachment/attachmentGroup.component.js.map +1 -0
- package/cards/attachment/index.d.ts +1 -0
- package/cards/attachment/index.js +16 -0
- package/cards/attachment/index.js.map +1 -0
- package/cards/bubble/bubble.component.d.ts +4 -0
- package/cards/bubble/bubble.component.js +67 -0
- package/cards/bubble/bubble.component.js.map +1 -0
- package/cards/bubble/bubble.types.d.ts +106 -0
- package/cards/bubble/bubble.types.js +7 -0
- package/cards/bubble/bubble.types.js.map +1 -0
- package/cards/bubble/bubbleGroup.component.d.ts +4 -0
- package/cards/bubble/bubbleGroup.component.js +21 -0
- package/cards/bubble/bubbleGroup.component.js.map +1 -0
- package/cards/bubble/index.d.ts +1 -0
- package/cards/bubble/index.js +16 -0
- package/cards/bubble/index.js.map +1 -0
- package/cards/dataTable/dataTable.component.js +191 -124
- package/cards/dataTable/dataTable.component.js.map +1 -1
- package/cards/dataTable/dataTable.types.d.ts +50 -0
- package/cards/dataTable/dataTable.types.js +6 -3
- package/cards/dataTable/dataTable.types.js.map +1 -1
- package/cards/dataTable/index.js +6 -6
- package/cards/dropDownMenu/dropdown-menu.ui.js +41 -41
- package/cards/input/input.component.js +4 -4
- package/cards/message/index.d.ts +1 -0
- package/cards/message/index.js +15 -0
- package/cards/message/index.js.map +1 -0
- package/cards/message/message.component.d.ts +4 -0
- package/cards/message/message.component.js +47 -0
- package/cards/message/message.component.js.map +1 -0
- package/cards/message/message.types.d.ts +56 -0
- package/cards/message/message.types.js +7 -0
- package/cards/message/message.types.js.map +1 -0
- package/cards/message/messageGroup.component.d.ts +4 -0
- package/cards/message/messageGroup.component.js +21 -0
- package/cards/message/messageGroup.component.js.map +1 -0
- package/components/ui/attachment.js +102 -0
- package/components/ui/attachment.js.map +1 -0
- package/components/ui/badge.js +7 -7
- package/components/ui/bubble.js +73 -0
- package/components/ui/bubble.js.map +1 -0
- package/components/ui/button.js +11 -11
- package/components/ui/empty.js +12 -12
- package/components/ui/field.js +16 -16
- package/components/ui/message.js +51 -0
- package/components/ui/message.js.map +1 -0
- package/components/ui/toggle-group.js +1 -1
- package/components/ui/toggle.js +1 -1
- package/package.json +16 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { cn as e } from "../../lib/utils.js";
|
|
2
2
|
import { Badge as t } from "../../components/ui/badge.js";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import { Input as n } from "../../components/ui/input.js";
|
|
4
|
+
import { Table as r, TableBody as i, TableCaption as a, TableCell as o, TableHead as s, TableHeader as ee, TableRow as c } from "../../components/ui/table.js";
|
|
5
|
+
import te, { useMemo as l, useState as u } from "react";
|
|
6
|
+
import { Card as d } from "@pihanga2/core";
|
|
7
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
8
|
+
import { Check as m, ChevronDown as h, ChevronRight as g, ChevronUp as _, ChevronsUpDown as v, X as y } from "lucide-react";
|
|
8
9
|
//#region src/cards/dataTable/dataTable.component.tsx
|
|
9
|
-
function
|
|
10
|
+
function ne(e, n, r) {
|
|
10
11
|
if (n == null) return null;
|
|
11
12
|
switch (e.type) {
|
|
12
13
|
case "number": {
|
|
@@ -20,33 +21,33 @@ function ee(e, n, r) {
|
|
|
20
21
|
}
|
|
21
22
|
case "badge": {
|
|
22
23
|
let r = String(n);
|
|
23
|
-
return /* @__PURE__ */
|
|
24
|
+
return /* @__PURE__ */ f(t, {
|
|
24
25
|
variant: e.variants?.[r] ?? "secondary",
|
|
25
26
|
children: r
|
|
26
27
|
});
|
|
27
28
|
}
|
|
28
|
-
case "boolean": return n ? /* @__PURE__ */
|
|
29
|
+
case "boolean": return n ? /* @__PURE__ */ f(m, {
|
|
29
30
|
className: "size-4 text-green-600",
|
|
30
31
|
"aria-label": "true"
|
|
31
|
-
}) : /* @__PURE__ */
|
|
32
|
+
}) : /* @__PURE__ */ f(y, {
|
|
32
33
|
className: "size-4 text-muted-foreground",
|
|
33
34
|
"aria-label": "false"
|
|
34
35
|
});
|
|
35
|
-
case "card": return /* @__PURE__ */
|
|
36
|
+
case "card": return /* @__PURE__ */ f(d, {
|
|
36
37
|
cardName: String(n),
|
|
37
38
|
parentCard: r
|
|
38
39
|
});
|
|
39
40
|
default: return String(n);
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
|
-
function
|
|
43
|
-
return e === t ?
|
|
43
|
+
function b({ columnKey: e, activeKey: t, ascending: n }) {
|
|
44
|
+
return e === t ? f(n ? _ : h, { className: "ml-1 inline size-3.5" }) : /* @__PURE__ */ f(v, { className: "ml-1 inline size-3.5 opacity-40" });
|
|
44
45
|
}
|
|
45
|
-
function
|
|
46
|
-
return /* @__PURE__ */
|
|
46
|
+
function re({ page: t, totalPages: n, onPrev: r, onNext: i }) {
|
|
47
|
+
return /* @__PURE__ */ p("div", {
|
|
47
48
|
className: "flex items-center justify-end gap-2 mt-2 px-2",
|
|
48
49
|
children: [
|
|
49
|
-
/* @__PURE__ */
|
|
50
|
+
/* @__PURE__ */ p("span", {
|
|
50
51
|
className: "text-sm text-muted-foreground",
|
|
51
52
|
children: [
|
|
52
53
|
"Page ",
|
|
@@ -55,14 +56,14 @@ function S({ page: t, totalPages: n, onPrev: r, onNext: i }) {
|
|
|
55
56
|
n
|
|
56
57
|
]
|
|
57
58
|
}),
|
|
58
|
-
/* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ f("button", {
|
|
59
60
|
type: "button",
|
|
60
61
|
className: e("rounded border px-2 py-1 text-sm transition-colors", "hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40"),
|
|
61
62
|
disabled: t === 0,
|
|
62
63
|
onClick: r,
|
|
63
64
|
children: "Previous"
|
|
64
65
|
}),
|
|
65
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ f("button", {
|
|
66
67
|
type: "button",
|
|
67
68
|
className: e("rounded border px-2 py-1 text-sm transition-colors", "hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40"),
|
|
68
69
|
disabled: t >= n - 1,
|
|
@@ -72,139 +73,205 @@ function S({ page: t, totalPages: n, onPrev: r, onNext: i }) {
|
|
|
72
73
|
]
|
|
73
74
|
});
|
|
74
75
|
}
|
|
75
|
-
function
|
|
76
|
+
function ie(e) {
|
|
76
77
|
return e.replace(/([A-Z])/g, " $1").replace(/^./, (e) => e.toUpperCase()).trim();
|
|
77
78
|
}
|
|
78
|
-
var
|
|
79
|
-
let { columns:
|
|
80
|
-
|
|
79
|
+
var x = (t) => {
|
|
80
|
+
let { columns: m, rows: _, caption: v, sortKey: y, sortAscending: x, pageSize: S, currentPage: C, stickyHeader: ae = !1, striped: oe = !1, hoverable: se = !0, compact: ce = !1, emptyCard: w, emptyText: T = "No data", className: le, cardName: E, selectable: D = !1, selectedRowIds: O, showSearch: k = !1, searchPlaceholder: ue = "Search…", searchText: A, onRowClicked: de, onSortChanged: fe, onShowDetail: pe, onHideDetail: me, onPageChanged: j, onRowsSelected: M, onAllRowsSelected: N, onSearchChanged: P } = t, [F, I] = u(/* @__PURE__ */ new Set()), [L, R] = u(new Set(O ?? [])), z = O === void 0 ? L : new Set(O), [he, ge] = u(A ?? ""), B = A === void 0 ? he : A, [_e, ve] = u(y), [ye, be] = u(x ?? !0), V = y === void 0 ? _e : y, H = x === void 0 ? ye : x, [xe, Se] = u(C ?? 0), U = C === void 0 ? xe : C, W = _.some((e) => e.detailCard != null), G = m.length + +!!W + +!!D, K = l(() => {
|
|
81
|
+
if (!k || !B.trim() || A !== void 0) return _;
|
|
82
|
+
let e = B.trim().toLowerCase();
|
|
83
|
+
return _.filter((t) => Object.values(t.data).some((t) => String(t ?? "").toLowerCase().includes(e)));
|
|
84
|
+
}, [
|
|
85
|
+
_,
|
|
86
|
+
k,
|
|
87
|
+
B,
|
|
88
|
+
A
|
|
89
|
+
]), q = l(() => V ? [...K].sort((e, t) => {
|
|
90
|
+
let n = e.data[V], r = t.data[V];
|
|
81
91
|
if (n == null && r == null) return 0;
|
|
82
92
|
if (n == null) return 1;
|
|
83
93
|
if (r == null) return -1;
|
|
84
94
|
let i = n < r ? -1 : +(n > r);
|
|
85
|
-
return
|
|
86
|
-
}) :
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
]),
|
|
91
|
-
if (!
|
|
92
|
-
let e =
|
|
93
|
-
return
|
|
95
|
+
return H ? i : -i;
|
|
96
|
+
}) : K, [
|
|
97
|
+
K,
|
|
98
|
+
V,
|
|
99
|
+
H
|
|
100
|
+
]), J = l(() => {
|
|
101
|
+
if (!S) return q;
|
|
102
|
+
let e = U * S;
|
|
103
|
+
return q.slice(e, e + S);
|
|
94
104
|
}, [
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
]),
|
|
99
|
-
let t =
|
|
100
|
-
|
|
105
|
+
q,
|
|
106
|
+
S,
|
|
107
|
+
U
|
|
108
|
+
]), Y = S ? Math.ceil(q.length / S) : 1, Ce = (e) => {
|
|
109
|
+
let t = V === e ? !H : !0;
|
|
110
|
+
ve(e), be(t), fe({
|
|
101
111
|
key: e,
|
|
102
112
|
ascending: t
|
|
103
113
|
});
|
|
104
|
-
},
|
|
105
|
-
t.stopPropagation(),
|
|
114
|
+
}, we = (e, t) => {
|
|
115
|
+
t.stopPropagation(), I((t) => {
|
|
106
116
|
let n = new Set(t);
|
|
107
|
-
return n.has(e.id) ? (n.delete(e.id),
|
|
117
|
+
return n.has(e.id) ? (n.delete(e.id), me({
|
|
108
118
|
rowId: e.id,
|
|
109
119
|
row: e
|
|
110
|
-
})) : (n.add(e.id),
|
|
120
|
+
})) : (n.add(e.id), pe({
|
|
111
121
|
rowId: e.id,
|
|
112
122
|
row: e
|
|
113
123
|
})), n;
|
|
114
124
|
});
|
|
115
|
-
},
|
|
116
|
-
|
|
125
|
+
}, Te = (e) => {
|
|
126
|
+
de({
|
|
117
127
|
rowId: e.id,
|
|
118
128
|
row: e
|
|
119
129
|
});
|
|
120
|
-
},
|
|
121
|
-
|
|
130
|
+
}, X = (e) => {
|
|
131
|
+
Se(e), S && j({
|
|
122
132
|
page: e,
|
|
123
|
-
pageSize:
|
|
133
|
+
pageSize: S
|
|
124
134
|
});
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
135
|
+
}, Z = (e) => {
|
|
136
|
+
M({ selected: q.filter((t) => e.has(t.id)) });
|
|
137
|
+
}, Ee = (e, t) => {
|
|
138
|
+
t.stopPropagation();
|
|
139
|
+
let n = new Set(z);
|
|
140
|
+
n.has(e.id) ? n.delete(e.id) : n.add(e.id), O === void 0 && R(n), Z(n);
|
|
141
|
+
}, Q = J.length > 0 && J.every((e) => z.has(e.id)), De = () => {
|
|
142
|
+
let e = !Q, t = new Set(z);
|
|
143
|
+
for (let n of J) e ? t.add(n.id) : t.delete(n.id);
|
|
144
|
+
O === void 0 && R(t), N({
|
|
145
|
+
selected: e,
|
|
146
|
+
rows: J
|
|
147
|
+
}), Z(t);
|
|
148
|
+
}, Oe = (e) => {
|
|
149
|
+
A === void 0 && ge(e), P({ text: e });
|
|
150
|
+
}, $ = ce ? "py-1 px-2" : "py-2 px-3";
|
|
151
|
+
return /* @__PURE__ */ p("div", {
|
|
152
|
+
className: e("w-full", le),
|
|
153
|
+
"data-pihanga": E,
|
|
154
|
+
children: [
|
|
155
|
+
k && /* @__PURE__ */ f("div", {
|
|
156
|
+
className: "mb-2 px-2",
|
|
157
|
+
children: /* @__PURE__ */ f(n, {
|
|
158
|
+
type: "search",
|
|
159
|
+
value: B,
|
|
160
|
+
placeholder: ue,
|
|
161
|
+
onChange: (e) => Oe(e.target.value),
|
|
162
|
+
className: "max-w-xs",
|
|
163
|
+
"aria-label": "Search table"
|
|
164
|
+
})
|
|
149
165
|
}),
|
|
150
|
-
/* @__PURE__ */ p(r, { children:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
"aria-label":
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
166
|
+
/* @__PURE__ */ p(r, { children: [
|
|
167
|
+
v && /* @__PURE__ */ f(a, { children: v }),
|
|
168
|
+
/* @__PURE__ */ f(ee, {
|
|
169
|
+
className: ae ? "sticky top-0 z-10 bg-background" : void 0,
|
|
170
|
+
children: /* @__PURE__ */ p(c, { children: [
|
|
171
|
+
D && /* @__PURE__ */ f(s, {
|
|
172
|
+
className: "w-10 px-2",
|
|
173
|
+
children: /* @__PURE__ */ f("input", {
|
|
174
|
+
type: "checkbox",
|
|
175
|
+
"aria-label": "Select all rows",
|
|
176
|
+
checked: Q,
|
|
177
|
+
onChange: De,
|
|
178
|
+
className: "h-4 w-4 rounded border-input accent-primary"
|
|
179
|
+
})
|
|
180
|
+
}),
|
|
181
|
+
W && /* @__PURE__ */ f(s, {
|
|
182
|
+
className: "w-10 px-2",
|
|
183
|
+
"aria-label": "Row details"
|
|
184
|
+
}),
|
|
185
|
+
m.map((t) => /* @__PURE__ */ f(s, {
|
|
186
|
+
style: t.width ? { width: t.width } : void 0,
|
|
187
|
+
className: e($, t.align === "center" && "text-center", t.align === "right" && "text-right", t.sortable && "cursor-pointer select-none", t.headerClassName),
|
|
188
|
+
onClick: t.sortable ? () => Ce(t.key) : void 0,
|
|
189
|
+
children: /* @__PURE__ */ p("span", {
|
|
190
|
+
className: "inline-flex items-center",
|
|
191
|
+
children: [t.title ?? ie(t.key), t.sortable && /* @__PURE__ */ f(b, {
|
|
192
|
+
columnKey: t.key,
|
|
193
|
+
activeKey: V,
|
|
194
|
+
ascending: H
|
|
195
|
+
})]
|
|
196
|
+
})
|
|
197
|
+
}, t.key))
|
|
198
|
+
] })
|
|
199
|
+
}),
|
|
200
|
+
/* @__PURE__ */ f(i, { children: J.length === 0 ? /* @__PURE__ */ f(c, { children: /* @__PURE__ */ f(o, {
|
|
201
|
+
colSpan: G,
|
|
202
|
+
className: "py-8 text-center text-muted-foreground",
|
|
203
|
+
children: w ? /* @__PURE__ */ f(d, {
|
|
204
|
+
cardName: w,
|
|
205
|
+
parentCard: E
|
|
206
|
+
}) : T
|
|
207
|
+
}) }) : J.map((t, n) => {
|
|
208
|
+
let r = F.has(t.id), i = oe && n % 2 == 1, a = z.has(t.id);
|
|
209
|
+
return /* @__PURE__ */ p(te.Fragment, { children: [/* @__PURE__ */ p(c, {
|
|
210
|
+
className: e(i && "bg-muted/30", se && "cursor-pointer"),
|
|
211
|
+
"data-state": a ? "selected" : void 0,
|
|
212
|
+
"data-expanded": r || void 0,
|
|
213
|
+
onClick: () => Te(t),
|
|
214
|
+
children: [
|
|
215
|
+
D && /* @__PURE__ */ f(o, {
|
|
216
|
+
className: "w-10 px-2",
|
|
217
|
+
children: /* @__PURE__ */ f("input", {
|
|
218
|
+
type: "checkbox",
|
|
219
|
+
"aria-label": `Select row ${t.id}`,
|
|
220
|
+
checked: a,
|
|
221
|
+
onClick: (e) => e.stopPropagation(),
|
|
222
|
+
onChange: (e) => Ee(t, e),
|
|
223
|
+
className: "h-4 w-4 rounded border-input accent-primary"
|
|
224
|
+
})
|
|
225
|
+
}),
|
|
226
|
+
W && /* @__PURE__ */ f(o, {
|
|
227
|
+
className: "w-10 px-2",
|
|
228
|
+
children: t.detailCard && /* @__PURE__ */ f("button", {
|
|
229
|
+
type: "button",
|
|
230
|
+
"aria-label": r ? "Collapse detail" : "Expand detail",
|
|
231
|
+
"aria-expanded": r,
|
|
232
|
+
className: e("flex items-center justify-center rounded p-0.5 transition-colors", "hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"),
|
|
233
|
+
onClick: (e) => we(t, e),
|
|
234
|
+
children: f(r ? h : g, { className: "size-4" })
|
|
235
|
+
})
|
|
236
|
+
}),
|
|
237
|
+
m.map((n) => {
|
|
238
|
+
let r = t.data[n.key], i = typeof n.cellClassName == "function" ? n.cellClassName(r, t) : n.cellClassName, a = typeof n.cellStyle == "function" ? n.cellStyle(r, t) : n.cellStyle;
|
|
239
|
+
return /* @__PURE__ */ f(o, {
|
|
240
|
+
className: e($, n.align === "center" && "text-center", n.align === "right" && "text-right", i),
|
|
241
|
+
style: a,
|
|
242
|
+
children: ne(n, r, E)
|
|
243
|
+
}, n.key);
|
|
244
|
+
})
|
|
245
|
+
]
|
|
246
|
+
}), r && t.detailCard && /* @__PURE__ */ f(c, {
|
|
247
|
+
className: "hover:bg-transparent",
|
|
248
|
+
onClick: (e) => e.stopPropagation(),
|
|
249
|
+
children: /* @__PURE__ */ f(o, {
|
|
250
|
+
colSpan: G,
|
|
251
|
+
className: "border-b p-0",
|
|
252
|
+
children: /* @__PURE__ */ f("div", {
|
|
253
|
+
className: "bg-muted/20 px-4 py-3",
|
|
254
|
+
children: /* @__PURE__ */ f(d, {
|
|
255
|
+
cardName: t.detailCard,
|
|
256
|
+
cardKey: `detail-${t.id}`,
|
|
257
|
+
row: t,
|
|
258
|
+
parentCard: E
|
|
259
|
+
}, `${E}-${t.id}-detail`)
|
|
260
|
+
})
|
|
172
261
|
})
|
|
173
|
-
}),
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
onClick: (e) => e.stopPropagation(),
|
|
184
|
-
children: /* @__PURE__ */ p(a, {
|
|
185
|
-
colSpan: J,
|
|
186
|
-
className: "border-b p-0",
|
|
187
|
-
children: /* @__PURE__ */ p("div", {
|
|
188
|
-
className: "bg-muted/20 px-4 py-3",
|
|
189
|
-
children: /* @__PURE__ */ p(f, {
|
|
190
|
-
cardName: t.detailCard,
|
|
191
|
-
cardKey: `detail-${t.id}`,
|
|
192
|
-
row: t,
|
|
193
|
-
parentCard: A
|
|
194
|
-
}, `${A}-${t.id}-detail`)
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
-
})] }, t.id);
|
|
198
|
-
}) })
|
|
199
|
-
] }), T && Z > 1 && /* @__PURE__ */ p(S, {
|
|
200
|
-
page: K,
|
|
201
|
-
totalPages: Z,
|
|
202
|
-
onPrev: () => Q(K - 1),
|
|
203
|
-
onNext: () => Q(K + 1)
|
|
204
|
-
})]
|
|
262
|
+
})] }, t.id);
|
|
263
|
+
}) })
|
|
264
|
+
] }),
|
|
265
|
+
S && Y > 1 && /* @__PURE__ */ f(re, {
|
|
266
|
+
page: U,
|
|
267
|
+
totalPages: Y,
|
|
268
|
+
onPrev: () => X(U - 1),
|
|
269
|
+
onNext: () => X(U + 1)
|
|
270
|
+
})
|
|
271
|
+
]
|
|
205
272
|
});
|
|
206
273
|
};
|
|
207
274
|
//#endregion
|
|
208
|
-
export {
|
|
275
|
+
export { x as DataTableComponent };
|
|
209
276
|
|
|
210
277
|
//# sourceMappingURL=dataTable.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataTable.component.js","names":[],"sources":["../../../src/cards/dataTable/dataTable.component.tsx"],"sourcesContent":["import React, {useMemo, useState} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {\n Check,\n ChevronDown,\n ChevronRight,\n ChevronUp,\n ChevronsUpDown,\n X,\n} from \"lucide-react\";\nimport {cn} from \"@/lib/utils\";\nimport {Badge} from \"@/components/ui/badge\";\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/components/ui/table\";\nimport type {\n DataTableColumn,\n DataTableEvents,\n DataTableProps,\n DataTableRow as DataTableRowType,\n} from \"./dataTable.types\";\n\n// ---------------------------------------------------------------------------\n// Cell renderer\n// ---------------------------------------------------------------------------\n\nfunction renderCell(\n column: DataTableColumn,\n value: unknown,\n parentCard: string,\n): React.ReactNode {\n if (value == null) return null;\n\n switch (column.type) {\n case \"number\": {\n const num = typeof value === \"number\" ? value : Number(value);\n return isNaN(num)\n ? String(value)\n : column.format\n ? column.format(num)\n : String(num);\n }\n\n case \"date\": {\n if (column.format) {\n return column.format(value as Date | string);\n }\n const d = value instanceof Date ? value : new Date(String(value));\n return isNaN(d.getTime()) ? String(value) : d.toLocaleDateString();\n }\n\n case \"badge\": {\n const strVal = String(value);\n const variant = column.variants?.[strVal] ?? \"secondary\";\n return <Badge variant={variant}>{strVal}</Badge>;\n }\n\n case \"boolean\": {\n return value ? (\n <Check className=\"size-4 text-green-600\" aria-label=\"true\" />\n ) : (\n <X className=\"size-4 text-muted-foreground\" aria-label=\"false\" />\n );\n }\n\n case \"card\": {\n // Cell value is expected to be a PiCardRef (string)\n return <Card cardName={String(value)} parentCard={parentCard} />;\n }\n\n default:\n // \"text\" or omitted type\n return String(value);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Sort icon\n// ---------------------------------------------------------------------------\n\nfunction SortIcon({\n columnKey,\n activeKey,\n ascending,\n}: {\n columnKey: string;\n activeKey: string | undefined;\n ascending: boolean;\n}): React.ReactNode {\n if (columnKey !== activeKey) {\n return <ChevronsUpDown className=\"ml-1 inline size-3.5 opacity-40\" />;\n }\n return ascending ? (\n <ChevronUp className=\"ml-1 inline size-3.5\" />\n ) : (\n <ChevronDown className=\"ml-1 inline size-3.5\" />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Pagination controls\n// ---------------------------------------------------------------------------\n\nfunction PaginationBar({\n page,\n totalPages,\n onPrev,\n onNext,\n}: {\n page: number;\n totalPages: number;\n onPrev: () => void;\n onNext: () => void;\n}): React.ReactNode {\n return (\n <div className=\"flex items-center justify-end gap-2 mt-2 px-2\">\n <span className=\"text-sm text-muted-foreground\">\n Page {page + 1} of {totalPages}\n </span>\n <button\n type=\"button\"\n className={cn(\n \"rounded border px-2 py-1 text-sm transition-colors\",\n \"hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n disabled={page === 0}\n onClick={onPrev}\n >\n Previous\n </button>\n <button\n type=\"button\"\n className={cn(\n \"rounded border px-2 py-1 text-sm transition-colors\",\n \"hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n disabled={page >= totalPages - 1}\n onClick={onNext}\n >\n Next\n </button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Helper: derive a human-readable title from a camelCase key\n// ---------------------------------------------------------------------------\n\nfunction keyToTitle(key: string): string {\n return key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n}\n\n// ---------------------------------------------------------------------------\n// Main data-table component\n// ---------------------------------------------------------------------------\n\nexport const DataTableComponent = (\n props: PiCardProps<DataTableProps, DataTableEvents>,\n): React.ReactNode => {\n const {\n columns,\n rows,\n caption,\n sortKey: sortKeyProp,\n sortAscending: sortAscendingProp,\n pageSize,\n currentPage: currentPageProp,\n stickyHeader = false,\n striped = false,\n hoverable = true,\n compact = false,\n emptyCard,\n emptyText = \"No data\",\n className,\n cardName,\n onRowClicked,\n onSortChanged,\n onShowDetail,\n onHideDetail,\n onPageChanged,\n } = props;\n\n // ── Expanded-rows state ──────────────────────────────────────────────────\n const [expandedRows, setExpandedRows] = useState<Set<string | number>>(\n new Set(),\n );\n\n // ── Sort state (uncontrolled; props override when present) ───────────────\n const [localSortKey, setLocalSortKey] = useState<string | undefined>(\n sortKeyProp,\n );\n const [localSortAsc, setLocalSortAsc] = useState<boolean>(\n sortAscendingProp ?? true,\n );\n const activeSortKey = sortKeyProp !== undefined ? sortKeyProp : localSortKey;\n const activeSortAsc =\n sortAscendingProp !== undefined ? sortAscendingProp : localSortAsc;\n\n // ── Pagination state (uncontrolled; props override when present) ─────────\n const [localPage, setLocalPage] = useState<number>(currentPageProp ?? 0);\n const activePage =\n currentPageProp !== undefined ? currentPageProp : localPage;\n\n // ── Derived flags ────────────────────────────────────────────────────────\n const hasDetailRows = rows.some((row) => row.detailCard != null);\n // Total column count used for detail-row colSpan\n const colCount = columns.length + (hasDetailRows ? 1 : 0);\n\n // ── Sorted rows ──────────────────────────────────────────────────────────\n const sortedRows = useMemo(() => {\n if (!activeSortKey) return rows;\n return [...rows].sort((a, b) => {\n const av = (a.data as Record<string, unknown>)[activeSortKey];\n const bv = (b.data as Record<string, unknown>)[activeSortKey];\n if (av == null && bv == null) return 0;\n if (av == null) return 1;\n if (bv == null) return -1;\n const cmp = av < bv ? -1 : av > bv ? 1 : 0;\n return activeSortAsc ? cmp : -cmp;\n });\n }, [rows, activeSortKey, activeSortAsc]);\n\n // ── Paginated slice ──────────────────────────────────────────────────────\n const paginatedRows = useMemo(() => {\n if (!pageSize) return sortedRows;\n const start = activePage * pageSize;\n return sortedRows.slice(start, start + pageSize);\n }, [sortedRows, pageSize, activePage]);\n\n const totalPages = pageSize ? Math.ceil(sortedRows.length / pageSize) : 1;\n\n // ── Handlers ─────────────────────────────────────────────────────────────\n const handleSortClick = (key: string) => {\n const newAsc = activeSortKey === key ? !activeSortAsc : true;\n setLocalSortKey(key);\n setLocalSortAsc(newAsc);\n onSortChanged({key, ascending: newAsc});\n };\n\n const handleToggleDetail = (row: DataTableRowType, e: React.MouseEvent) => {\n e.stopPropagation();\n setExpandedRows((prev) => {\n const next = new Set(prev);\n if (next.has(row.id)) {\n next.delete(row.id);\n onHideDetail({rowId: row.id, row});\n } else {\n next.add(row.id);\n onShowDetail({rowId: row.id, row});\n }\n return next;\n });\n };\n\n const handleRowClick = (row: DataTableRowType) => {\n onRowClicked({rowId: row.id, row});\n };\n\n const handlePageChange = (page: number) => {\n setLocalPage(page);\n if (pageSize) {\n onPageChanged({page, pageSize});\n }\n };\n\n // ── Cell padding ─────────────────────────────────────────────────────────\n const cellPad = compact ? \"py-1 px-2\" : \"py-2 px-3\";\n\n // ── Render ────────────────────────────────────────────────────────────────\n return (\n <div className={cn(\"w-full\", className)} data-pihanga={cardName}>\n <Table>\n {caption && <TableCaption>{caption}</TableCaption>}\n\n {/* ── Header ─────────────────────────────────────────────────────── */}\n <TableHeader\n className={\n stickyHeader ? \"sticky top-0 z-10 bg-background\" : undefined\n }\n >\n <TableRow>\n {/* Expand-toggle placeholder header cell */}\n {hasDetailRows && (\n <TableHead className=\"w-10 px-2\" aria-label=\"Row details\" />\n )}\n\n {columns.map((col) => (\n <TableHead\n key={col.key}\n style={col.width ? {width: col.width} : undefined}\n className={cn(\n cellPad,\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n col.sortable && \"cursor-pointer select-none\",\n col.headerClassName,\n )}\n onClick={\n col.sortable ? () => handleSortClick(col.key) : undefined\n }\n >\n <span className=\"inline-flex items-center\">\n {col.title ?? keyToTitle(col.key)}\n {col.sortable && (\n <SortIcon\n columnKey={col.key}\n activeKey={activeSortKey}\n ascending={activeSortAsc}\n />\n )}\n </span>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n\n {/* ── Body ───────────────────────────────────────────────────────── */}\n <TableBody>\n {paginatedRows.length === 0 ? (\n /* Empty state */\n <TableRow>\n <TableCell\n colSpan={colCount}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {emptyCard ? (\n <Card cardName={emptyCard} parentCard={cardName} />\n ) : (\n emptyText\n )}\n </TableCell>\n </TableRow>\n ) : (\n paginatedRows.map((row, rowIdx) => {\n const isExpanded = expandedRows.has(row.id);\n const isStriped = striped && rowIdx % 2 === 1;\n\n return (\n <React.Fragment key={row.id}>\n {/* ── Data row ─────────────────────────────────────────── */}\n <TableRow\n className={cn(\n isStriped && \"bg-muted/30\",\n hoverable && \"cursor-pointer\",\n )}\n data-expanded={isExpanded || undefined}\n onClick={() => handleRowClick(row)}\n >\n {/* Expand / collapse toggle */}\n {hasDetailRows && (\n <TableCell className=\"w-10 px-2\">\n {row.detailCard && (\n <button\n type=\"button\"\n aria-label={\n isExpanded ? \"Collapse detail\" : \"Expand detail\"\n }\n aria-expanded={isExpanded}\n className={cn(\n \"flex items-center justify-center rounded p-0.5 transition-colors\",\n \"hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n )}\n onClick={(e) => handleToggleDetail(row, e)}\n >\n {isExpanded ? (\n <ChevronDown className=\"size-4\" />\n ) : (\n <ChevronRight className=\"size-4\" />\n )}\n </button>\n )}\n </TableCell>\n )}\n\n {/* Data cells */}\n {columns.map((col) => {\n const value = (row.data as Record<string, unknown>)[\n col.key\n ];\n const resolvedClassName =\n typeof col.cellClassName === \"function\"\n ? col.cellClassName(value, row)\n : col.cellClassName;\n const resolvedStyle =\n typeof col.cellStyle === \"function\"\n ? col.cellStyle(value, row)\n : col.cellStyle;\n return (\n <TableCell\n key={col.key}\n className={cn(\n cellPad,\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n resolvedClassName,\n )}\n style={resolvedStyle}\n >\n {renderCell(col, value, cardName)}\n </TableCell>\n );\n })}\n </TableRow>\n\n {/* ── Detail row (full-width, shown when expanded) ──────── */}\n {isExpanded && row.detailCard && (\n <TableRow\n // Suppress the default hover/click styles on the detail row\n className=\"hover:bg-transparent\"\n onClick={(e) => e.stopPropagation()}\n >\n <TableCell colSpan={colCount} className=\"border-b p-0\">\n <div className=\"bg-muted/20 px-4 py-3\">\n {/*\n * cardKey creates a unique virtual card instance per row\n * (e.g. \"myDetailTemplate@detail-42\").\n * The `row` prop is forwarded as ctxtProps so the detail\n * card's state-mapper functions can access it via\n * `ctx.ctxtProps.row` — no need to pre-register one card\n * per row.\n */}\n <Card\n cardName={row.detailCard}\n cardKey={`detail-${row.id}`}\n row={row}\n parentCard={cardName}\n key={`${cardName}-${row.id}-detail`}\n />\n </div>\n </TableCell>\n </TableRow>\n )}\n </React.Fragment>\n );\n })\n )}\n </TableBody>\n </Table>\n\n {/* ── Pagination controls ──────────────────────────────────────────── */}\n {pageSize && totalPages > 1 && (\n <PaginationBar\n page={activePage}\n totalPages={totalPages}\n onPrev={() => handlePageChange(activePage - 1)}\n onNext={() => handlePageChange(activePage + 1)}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dataTable.component.js","names":[],"sources":["../../../src/cards/dataTable/dataTable.component.tsx"],"sourcesContent":["import React, {useMemo, useState} from \"react\";\nimport {Card, type PiCardProps} from \"@pihanga2/core\";\nimport {\n Check,\n ChevronDown,\n ChevronRight,\n ChevronUp,\n ChevronsUpDown,\n X,\n} from \"lucide-react\";\nimport {cn} from \"@/lib/utils\";\nimport {Badge} from \"@/components/ui/badge\";\nimport {Input} from \"@/components/ui/input\";\nimport {\n Table,\n TableBody,\n TableCaption,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from \"@/components/ui/table\";\nimport type {\n DataTableColumn,\n DataTableEvents,\n DataTableProps,\n DataTableRow as DataTableRowType,\n} from \"./dataTable.types\";\n\n// ---------------------------------------------------------------------------\n// Cell renderer\n// ---------------------------------------------------------------------------\n\nfunction renderCell(\n column: DataTableColumn,\n value: unknown,\n parentCard: string,\n): React.ReactNode {\n if (value == null) return null;\n\n switch (column.type) {\n case \"number\": {\n const num = typeof value === \"number\" ? value : Number(value);\n return isNaN(num)\n ? String(value)\n : column.format\n ? column.format(num)\n : String(num);\n }\n\n case \"date\": {\n if (column.format) {\n return column.format(value as Date | string);\n }\n const d = value instanceof Date ? value : new Date(String(value));\n return isNaN(d.getTime()) ? String(value) : d.toLocaleDateString();\n }\n\n case \"badge\": {\n const strVal = String(value);\n const variant = column.variants?.[strVal] ?? \"secondary\";\n return <Badge variant={variant}>{strVal}</Badge>;\n }\n\n case \"boolean\": {\n return value ? (\n <Check className=\"size-4 text-green-600\" aria-label=\"true\" />\n ) : (\n <X className=\"size-4 text-muted-foreground\" aria-label=\"false\" />\n );\n }\n\n case \"card\": {\n // Cell value is expected to be a PiCardRef (string)\n return <Card cardName={String(value)} parentCard={parentCard} />;\n }\n\n default:\n // \"text\" or omitted type\n return String(value);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Sort icon\n// ---------------------------------------------------------------------------\n\nfunction SortIcon({\n columnKey,\n activeKey,\n ascending,\n}: {\n columnKey: string;\n activeKey: string | undefined;\n ascending: boolean;\n}): React.ReactNode {\n if (columnKey !== activeKey) {\n return <ChevronsUpDown className=\"ml-1 inline size-3.5 opacity-40\" />;\n }\n return ascending ? (\n <ChevronUp className=\"ml-1 inline size-3.5\" />\n ) : (\n <ChevronDown className=\"ml-1 inline size-3.5\" />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Pagination controls\n// ---------------------------------------------------------------------------\n\nfunction PaginationBar({\n page,\n totalPages,\n onPrev,\n onNext,\n}: {\n page: number;\n totalPages: number;\n onPrev: () => void;\n onNext: () => void;\n}): React.ReactNode {\n return (\n <div className=\"flex items-center justify-end gap-2 mt-2 px-2\">\n <span className=\"text-sm text-muted-foreground\">\n Page {page + 1} of {totalPages}\n </span>\n <button\n type=\"button\"\n className={cn(\n \"rounded border px-2 py-1 text-sm transition-colors\",\n \"hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n disabled={page === 0}\n onClick={onPrev}\n >\n Previous\n </button>\n <button\n type=\"button\"\n className={cn(\n \"rounded border px-2 py-1 text-sm transition-colors\",\n \"hover:bg-accent disabled:cursor-not-allowed disabled:opacity-40\",\n )}\n disabled={page >= totalPages - 1}\n onClick={onNext}\n >\n Next\n </button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Helper: derive a human-readable title from a camelCase key\n// ---------------------------------------------------------------------------\n\nfunction keyToTitle(key: string): string {\n return key\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (s) => s.toUpperCase())\n .trim();\n}\n\n// ---------------------------------------------------------------------------\n// Main data-table component\n// ---------------------------------------------------------------------------\n\nexport const DataTableComponent = (\n props: PiCardProps<DataTableProps, DataTableEvents>,\n): React.ReactNode => {\n const {\n columns,\n rows,\n caption,\n sortKey: sortKeyProp,\n sortAscending: sortAscendingProp,\n pageSize,\n currentPage: currentPageProp,\n stickyHeader = false,\n striped = false,\n hoverable = true,\n compact = false,\n emptyCard,\n emptyText = \"No data\",\n className,\n cardName,\n selectable = false,\n selectedRowIds: selectedRowIdsProp,\n showSearch = false,\n searchPlaceholder = \"Search…\",\n searchText: searchTextProp,\n onRowClicked,\n onSortChanged,\n onShowDetail,\n onHideDetail,\n onPageChanged,\n onRowsSelected,\n onAllRowsSelected,\n onSearchChanged,\n } = props;\n\n // ── Expanded-rows state ──────────────────────────────────────────────────\n const [expandedRows, setExpandedRows] = useState<Set<string | number>>(\n new Set(),\n );\n\n // ── Selection state (uncontrolled; props override when present) ──────────\n const [localSelectedIds, setLocalSelectedIds] = useState<\n Set<string | number>\n >(new Set(selectedRowIdsProp ?? []));\n const selectedIds =\n selectedRowIdsProp !== undefined\n ? new Set(selectedRowIdsProp)\n : localSelectedIds;\n\n // ── Search state (uncontrolled; props override when present) ─────────────\n const [localSearchText, setLocalSearchText] = useState<string>(\n searchTextProp ?? \"\",\n );\n const activeSearchText =\n searchTextProp !== undefined ? searchTextProp : localSearchText;\n\n // ── Sort state (uncontrolled; props override when present) ───────────────\n const [localSortKey, setLocalSortKey] = useState<string | undefined>(\n sortKeyProp,\n );\n const [localSortAsc, setLocalSortAsc] = useState<boolean>(\n sortAscendingProp ?? true,\n );\n const activeSortKey = sortKeyProp !== undefined ? sortKeyProp : localSortKey;\n const activeSortAsc =\n sortAscendingProp !== undefined ? sortAscendingProp : localSortAsc;\n\n // ── Pagination state (uncontrolled; props override when present) ─────────\n const [localPage, setLocalPage] = useState<number>(currentPageProp ?? 0);\n const activePage =\n currentPageProp !== undefined ? currentPageProp : localPage;\n\n // ── Derived flags ────────────────────────────────────────────────────────\n const hasDetailRows = rows.some((row) => row.detailCard != null);\n // Total column count used for detail-row colSpan\n const colCount =\n columns.length + (hasDetailRows ? 1 : 0) + (selectable ? 1 : 0);\n\n // ── Search-filtered rows ─────────────────────────────────────────────────\n // Only filters client-side when `searchText` is uncontrolled; when the\n // caller controls `searchText` they are expected to filter `rows` themselves\n // (e.g. server-side search) so we pass the rows through unchanged.\n const searchedRows = useMemo(() => {\n if (!showSearch || !activeSearchText.trim()) return rows;\n if (searchTextProp !== undefined) return rows;\n const needle = activeSearchText.trim().toLowerCase();\n return rows.filter((row) =>\n Object.values(row.data as Record<string, unknown>).some((value) =>\n String(value ?? \"\")\n .toLowerCase()\n .includes(needle),\n ),\n );\n }, [rows, showSearch, activeSearchText, searchTextProp]);\n\n // ── Sorted rows ──────────────────────────────────────────────────────────\n const sortedRows = useMemo(() => {\n if (!activeSortKey) return searchedRows;\n return [...searchedRows].sort((a, b) => {\n const av = (a.data as Record<string, unknown>)[activeSortKey];\n const bv = (b.data as Record<string, unknown>)[activeSortKey];\n if (av == null && bv == null) return 0;\n if (av == null) return 1;\n if (bv == null) return -1;\n const cmp = av < bv ? -1 : av > bv ? 1 : 0;\n return activeSortAsc ? cmp : -cmp;\n });\n }, [searchedRows, activeSortKey, activeSortAsc]);\n\n // ── Paginated slice ──────────────────────────────────────────────────────\n const paginatedRows = useMemo(() => {\n if (!pageSize) return sortedRows;\n const start = activePage * pageSize;\n return sortedRows.slice(start, start + pageSize);\n }, [sortedRows, pageSize, activePage]);\n\n const totalPages = pageSize ? Math.ceil(sortedRows.length / pageSize) : 1;\n\n // ── Handlers ─────────────────────────────────────────────────────────────\n const handleSortClick = (key: string) => {\n const newAsc = activeSortKey === key ? !activeSortAsc : true;\n setLocalSortKey(key);\n setLocalSortAsc(newAsc);\n onSortChanged({key, ascending: newAsc});\n };\n\n const handleToggleDetail = (row: DataTableRowType, e: React.MouseEvent) => {\n e.stopPropagation();\n setExpandedRows((prev) => {\n const next = new Set(prev);\n if (next.has(row.id)) {\n next.delete(row.id);\n onHideDetail({rowId: row.id, row});\n } else {\n next.add(row.id);\n onShowDetail({rowId: row.id, row});\n }\n return next;\n });\n };\n\n const handleRowClick = (row: DataTableRowType) => {\n onRowClicked({rowId: row.id, row});\n };\n\n const handlePageChange = (page: number) => {\n setLocalPage(page);\n if (pageSize) {\n onPageChanged({page, pageSize});\n }\n };\n\n const emitSelected = (ids: Set<string | number>) => {\n const selected = sortedRows.filter((row) => ids.has(row.id));\n onRowsSelected({selected});\n };\n\n const handleRowSelectToggle = (\n row: DataTableRowType,\n e: React.MouseEvent | React.ChangeEvent,\n ) => {\n e.stopPropagation();\n const next = new Set(selectedIds);\n if (next.has(row.id)) {\n next.delete(row.id);\n } else {\n next.add(row.id);\n }\n if (selectedRowIdsProp === undefined) {\n setLocalSelectedIds(next);\n }\n emitSelected(next);\n };\n\n const allOnPageSelected =\n paginatedRows.length > 0 &&\n paginatedRows.every((row) => selectedIds.has(row.id));\n\n const handleSelectAllToggle = () => {\n const selectAll = !allOnPageSelected;\n const next = new Set(selectedIds);\n for (const row of paginatedRows) {\n if (selectAll) {\n next.add(row.id);\n } else {\n next.delete(row.id);\n }\n }\n if (selectedRowIdsProp === undefined) {\n setLocalSelectedIds(next);\n }\n onAllRowsSelected({selected: selectAll, rows: paginatedRows});\n emitSelected(next);\n };\n\n const handleSearchChange = (text: string) => {\n if (searchTextProp === undefined) {\n setLocalSearchText(text);\n }\n onSearchChanged({text});\n };\n\n // ── Cell padding ─────────────────────────────────────────────────────────\n const cellPad = compact ? \"py-1 px-2\" : \"py-2 px-3\";\n\n // ── Render ────────────────────────────────────────────────────────────────\n return (\n <div className={cn(\"w-full\", className)} data-pihanga={cardName}>\n {/* ── Search bar ─────────────────────────────────────────────────────── */}\n {showSearch && (\n <div className=\"mb-2 px-2\">\n <Input\n type=\"search\"\n value={activeSearchText}\n placeholder={searchPlaceholder}\n onChange={(e) => handleSearchChange(e.target.value)}\n className=\"max-w-xs\"\n aria-label=\"Search table\"\n />\n </div>\n )}\n\n <Table>\n {caption && <TableCaption>{caption}</TableCaption>}\n\n {/* ── Header ─────────────────────────────────────────────────────── */}\n <TableHeader\n className={\n stickyHeader ? \"sticky top-0 z-10 bg-background\" : undefined\n }\n >\n <TableRow>\n {/* Select-all checkbox header cell */}\n {selectable && (\n <TableHead className=\"w-10 px-2\">\n <input\n type=\"checkbox\"\n aria-label=\"Select all rows\"\n checked={allOnPageSelected}\n onChange={handleSelectAllToggle}\n className=\"h-4 w-4 rounded border-input accent-primary\"\n />\n </TableHead>\n )}\n\n {/* Expand-toggle placeholder header cell */}\n {hasDetailRows && (\n <TableHead className=\"w-10 px-2\" aria-label=\"Row details\" />\n )}\n\n {columns.map((col) => (\n <TableHead\n key={col.key}\n style={col.width ? {width: col.width} : undefined}\n className={cn(\n cellPad,\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n col.sortable && \"cursor-pointer select-none\",\n col.headerClassName,\n )}\n onClick={\n col.sortable ? () => handleSortClick(col.key) : undefined\n }\n >\n <span className=\"inline-flex items-center\">\n {col.title ?? keyToTitle(col.key)}\n {col.sortable && (\n <SortIcon\n columnKey={col.key}\n activeKey={activeSortKey}\n ascending={activeSortAsc}\n />\n )}\n </span>\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n\n {/* ── Body ───────────────────────────────────────────────────────── */}\n <TableBody>\n {paginatedRows.length === 0 ? (\n /* Empty state */\n <TableRow>\n <TableCell\n colSpan={colCount}\n className=\"py-8 text-center text-muted-foreground\"\n >\n {emptyCard ? (\n <Card cardName={emptyCard} parentCard={cardName} />\n ) : (\n emptyText\n )}\n </TableCell>\n </TableRow>\n ) : (\n paginatedRows.map((row, rowIdx) => {\n const isExpanded = expandedRows.has(row.id);\n const isStriped = striped && rowIdx % 2 === 1;\n const isSelected = selectedIds.has(row.id);\n\n return (\n <React.Fragment key={row.id}>\n {/* ── Data row ─────────────────────────────────────────── */}\n <TableRow\n className={cn(\n isStriped && \"bg-muted/30\",\n hoverable && \"cursor-pointer\",\n )}\n data-state={isSelected ? \"selected\" : undefined}\n data-expanded={isExpanded || undefined}\n onClick={() => handleRowClick(row)}\n >\n {/* Row selection checkbox */}\n {selectable && (\n <TableCell className=\"w-10 px-2\">\n <input\n type=\"checkbox\"\n aria-label={`Select row ${row.id}`}\n checked={isSelected}\n onClick={(e) => e.stopPropagation()}\n onChange={(e) => handleRowSelectToggle(row, e)}\n className=\"h-4 w-4 rounded border-input accent-primary\"\n />\n </TableCell>\n )}\n\n {/* Expand / collapse toggle */}\n {hasDetailRows && (\n <TableCell className=\"w-10 px-2\">\n {row.detailCard && (\n <button\n type=\"button\"\n aria-label={\n isExpanded ? \"Collapse detail\" : \"Expand detail\"\n }\n aria-expanded={isExpanded}\n className={cn(\n \"flex items-center justify-center rounded p-0.5 transition-colors\",\n \"hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n )}\n onClick={(e) => handleToggleDetail(row, e)}\n >\n {isExpanded ? (\n <ChevronDown className=\"size-4\" />\n ) : (\n <ChevronRight className=\"size-4\" />\n )}\n </button>\n )}\n </TableCell>\n )}\n\n {/* Data cells */}\n {columns.map((col) => {\n const value = (row.data as Record<string, unknown>)[\n col.key\n ];\n const resolvedClassName =\n typeof col.cellClassName === \"function\"\n ? col.cellClassName(value, row)\n : col.cellClassName;\n const resolvedStyle =\n typeof col.cellStyle === \"function\"\n ? col.cellStyle(value, row)\n : col.cellStyle;\n return (\n <TableCell\n key={col.key}\n className={cn(\n cellPad,\n col.align === \"center\" && \"text-center\",\n col.align === \"right\" && \"text-right\",\n resolvedClassName,\n )}\n style={resolvedStyle}\n >\n {renderCell(col, value, cardName)}\n </TableCell>\n );\n })}\n </TableRow>\n\n {/* ── Detail row (full-width, shown when expanded) ──────── */}\n {isExpanded && row.detailCard && (\n <TableRow\n // Suppress the default hover/click styles on the detail row\n className=\"hover:bg-transparent\"\n onClick={(e) => e.stopPropagation()}\n >\n <TableCell colSpan={colCount} className=\"border-b p-0\">\n <div className=\"bg-muted/20 px-4 py-3\">\n {/*\n * cardKey creates a unique virtual card instance per row\n * (e.g. \"myDetailTemplate@detail-42\").\n * The `row` prop is forwarded as ctxtProps so the detail\n * card's state-mapper functions can access it via\n * `ctx.ctxtProps.row` — no need to pre-register one card\n * per row.\n */}\n <Card\n cardName={row.detailCard}\n cardKey={`detail-${row.id}`}\n row={row}\n parentCard={cardName}\n key={`${cardName}-${row.id}-detail`}\n />\n </div>\n </TableCell>\n </TableRow>\n )}\n </React.Fragment>\n );\n })\n )}\n </TableBody>\n </Table>\n\n {/* ── Pagination controls ──────────────────────────────────────────── */}\n {pageSize && totalPages > 1 && (\n <PaginationBar\n page={activePage}\n totalPages={totalPages}\n onPrev={() => handlePageChange(activePage - 1)}\n onNext={() => handlePageChange(activePage + 1)}\n />\n )}\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -8,6 +8,9 @@ export declare const DATA_TABLE_ACTION: {
|
|
|
8
8
|
SHOW_DETAIL: string;
|
|
9
9
|
HIDE_DETAIL: string;
|
|
10
10
|
PAGE_CHANGED: string;
|
|
11
|
+
ROWS_SELECTED: string;
|
|
12
|
+
ALL_ROWS_SELECTED: string;
|
|
13
|
+
SEARCH_CHANGED: string;
|
|
11
14
|
};
|
|
12
15
|
export declare const onDataTableRowClicked: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
13
16
|
cardID: string;
|
|
@@ -24,6 +27,15 @@ export declare const onDataTableHideDetail: <S extends import('@pihanga2/core').
|
|
|
24
27
|
export declare const onDataTablePageChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
25
28
|
cardID: string;
|
|
26
29
|
} & DataTablePageChangedEvent>) => void;
|
|
30
|
+
export declare const onDataTableRowsSelected: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
31
|
+
cardID: string;
|
|
32
|
+
} & DataTableRowsSelectedEvent<Record<string, unknown>>>) => void;
|
|
33
|
+
export declare const onDataTableAllRowsSelected: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
34
|
+
cardID: string;
|
|
35
|
+
} & DataTableAllRowsSelectedEvent<Record<string, unknown>>>) => void;
|
|
36
|
+
export declare const onDataTableSearchChanged: <S extends import('@pihanga2/core').ReduxState>(register: import('@pihanga2/core/types').PiRegisterMinimal, f: import('@pihanga2/core').ReduceF<S, import('@pihanga2/core').ReduxAction & {
|
|
37
|
+
cardID: string;
|
|
38
|
+
} & DataTableSearchChangedEvent>) => void;
|
|
27
39
|
/** Shared base for all column definitions */
|
|
28
40
|
export type DataTableColumnBase = {
|
|
29
41
|
/** Key into the row's `data` object used to retrieve the cell value */
|
|
@@ -159,6 +171,27 @@ export type DataTableProps<T = Record<string, unknown>> = {
|
|
|
159
171
|
emptyCard?: PiCardRef;
|
|
160
172
|
/** Fallback text when `rows` is empty and `emptyCard` is not set */
|
|
161
173
|
emptyText?: string;
|
|
174
|
+
/**
|
|
175
|
+
* When true, a checkbox column is rendered so rows can be selected.
|
|
176
|
+
* Selection state is uncontrolled unless `selectedRowIds` is provided.
|
|
177
|
+
*/
|
|
178
|
+
selectable?: boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Ids of the currently selected rows.
|
|
181
|
+
* When provided, selection becomes controlled — pair with `onRowsSelected`
|
|
182
|
+
* to update it from your redux store.
|
|
183
|
+
*/
|
|
184
|
+
selectedRowIds?: (string | number)[];
|
|
185
|
+
/** Show a search input above the table that filters rows client-side. */
|
|
186
|
+
showSearch?: boolean;
|
|
187
|
+
/** Placeholder text for the search input. */
|
|
188
|
+
searchPlaceholder?: string;
|
|
189
|
+
/**
|
|
190
|
+
* Current search text.
|
|
191
|
+
* When provided the search box becomes controlled — pair with
|
|
192
|
+
* `onSearchChanged` to filter `rows` yourself (e.g. server-side).
|
|
193
|
+
*/
|
|
194
|
+
searchText?: string;
|
|
162
195
|
className?: string;
|
|
163
196
|
};
|
|
164
197
|
export type DataTableRowClickedEvent = {
|
|
@@ -180,12 +213,29 @@ export type DataTablePageChangedEvent = {
|
|
|
180
213
|
page: number;
|
|
181
214
|
pageSize: number;
|
|
182
215
|
};
|
|
216
|
+
export type DataTableRowsSelectedEvent<T = Record<string, unknown>> = {
|
|
217
|
+
/** All currently-selected rows (on the current page unless server-driven) */
|
|
218
|
+
selected: DataTableRow<T>[];
|
|
219
|
+
};
|
|
220
|
+
export type DataTableAllRowsSelectedEvent<T = Record<string, unknown>> = {
|
|
221
|
+
/** Whether the header checkbox selected (true) or cleared (false) all rows */
|
|
222
|
+
selected: boolean;
|
|
223
|
+
/** Rows affected by the select-all toggle (visible/paginated rows) */
|
|
224
|
+
rows: DataTableRow<T>[];
|
|
225
|
+
};
|
|
226
|
+
export type DataTableSearchChangedEvent = {
|
|
227
|
+
/** New search text */
|
|
228
|
+
text: string;
|
|
229
|
+
};
|
|
183
230
|
export type DataTableEvents = {
|
|
184
231
|
onRowClicked: DataTableRowClickedEvent;
|
|
185
232
|
onSortChanged: DataTableSortChangedEvent;
|
|
186
233
|
onShowDetail: DataTableDetailEvent;
|
|
187
234
|
onHideDetail: DataTableDetailEvent;
|
|
188
235
|
onPageChanged: DataTablePageChangedEvent;
|
|
236
|
+
onRowsSelected: DataTableRowsSelectedEvent;
|
|
237
|
+
onAllRowsSelected: DataTableAllRowsSelectedEvent;
|
|
238
|
+
onSearchChanged: DataTableSearchChangedEvent;
|
|
189
239
|
};
|
|
190
240
|
/** Configuration for a single field shown in the detail panel. */
|
|
191
241
|
export type DataTableRowDetailField = {
|
|
@@ -6,9 +6,12 @@ var r = "shad/data-table", i = e(r), a = n(r, [
|
|
|
6
6
|
"sort_changed",
|
|
7
7
|
"show_detail",
|
|
8
8
|
"hide_detail",
|
|
9
|
-
"page_changed"
|
|
10
|
-
|
|
9
|
+
"page_changed",
|
|
10
|
+
"rows_selected",
|
|
11
|
+
"all_rows_selected",
|
|
12
|
+
"search_changed"
|
|
13
|
+
]), o = t(a.ROW_CLICKED), s = t(a.SORT_CHANGED), c = t(a.SHOW_DETAIL), l = t(a.HIDE_DETAIL), u = t(a.PAGE_CHANGED), d = t(a.ROWS_SELECTED), f = t(a.ALL_ROWS_SELECTED), p = t(a.SEARCH_CHANGED), m = "shad/data-table-row-detail", h = e(m);
|
|
11
14
|
//#endregion
|
|
12
|
-
export { a as DATA_TABLE_ACTION, r as DATA_TABLE_CARD,
|
|
15
|
+
export { a as DATA_TABLE_ACTION, r as DATA_TABLE_CARD, m as DATA_TABLE_ROW_DETAIL_CARD, i as DataTable, h as DataTableRowDetail, f as onDataTableAllRowsSelected, l as onDataTableHideDetail, u as onDataTablePageChanged, o as onDataTableRowClicked, d as onDataTableRowsSelected, p as onDataTableSearchChanged, c as onDataTableShowDetail, s as onDataTableSortChanged };
|
|
13
16
|
|
|
14
17
|
//# sourceMappingURL=dataTable.types.js.map
|