@agilant/toga-blox 1.0.162 → 1.0.163
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/TableCell/TableCell.js +13 -16
- package/dist/components/TableRow/TableRow.d.ts +2 -2
- package/dist/components/TableRow/TableRow.js +14 -14
- package/dist/components/TableRow/TableRow.stories.d.ts +4 -13
- package/dist/components/TableRow/TableRow.stories.js +22 -44
- package/dist/components/TableRow/TableRow.test.js +11 -5
- package/package.json +1 -1
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// src/components/TableCell/TableCell.tsx
|
|
2
3
|
import { useState } from "react";
|
|
3
4
|
const MAX_CHARS = 30;
|
|
4
|
-
const TableCell = ({ cell, isLastCell, hasInfiniteScroll, linkText = "text-purple-500
|
|
5
|
+
const TableCell = ({ cell, isLastCell, hasInfiniteScroll, linkText = "text-purple-500 ml-1 underline", }) => {
|
|
5
6
|
const [expanded, setExpanded] = useState(false);
|
|
6
|
-
|
|
7
|
+
// Determine if we need a toggle
|
|
7
8
|
const isString = typeof cell.value === "string";
|
|
8
9
|
const fullText = isString ? cell.value : "";
|
|
9
10
|
const isLong = isString && fullText.length > MAX_CHARS;
|
|
11
|
+
const hasToggle = hasInfiniteScroll && isLong;
|
|
10
12
|
const truncated = fullText.slice(0, MAX_CHARS);
|
|
11
|
-
|
|
12
|
-
const tableDataCls = "relative overflow-hidden font-light text-sm text-left z-0 px-5";
|
|
13
|
-
const cellContainerCls = "min-h-[40px] flex items-center group select-none" +
|
|
14
|
-
(hasInfiniteScroll && isLong ? " cursor-pointer" : "");
|
|
15
|
-
/* ---------- toggle ---------- */
|
|
13
|
+
// Only stop propagation / toggle when hasToggle is true
|
|
16
14
|
const handleToggle = (e) => {
|
|
17
15
|
e.stopPropagation();
|
|
18
|
-
|
|
19
|
-
setExpanded((prev) => !prev);
|
|
16
|
+
setExpanded((prev) => !prev);
|
|
20
17
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
/*
|
|
18
|
+
const baseTdCls = "relative overflow-hidden font-light text-sm text-left px-5";
|
|
19
|
+
const cellWrapperCls = "min-h-[40px] flex items-center";
|
|
20
|
+
return (_jsx("td", { ...cell.getCellProps(), className: isLastCell ? "" : baseTdCls, children: _jsx("div", { className: cellWrapperCls, ...(hasToggle
|
|
21
|
+
? { onClick: handleToggle, style: { cursor: "pointer" } }
|
|
22
|
+
: {}), children: hasToggle ? (!expanded ? (_jsxs(_Fragment, { children: [truncated, _jsx("span", { className: "inline group-hover:hidden", children: "\u2026" }), _jsx("span", { className: linkText, children: "Show more" })] })) : (_jsxs(_Fragment, { children: [fullText, _jsx("span", { className: linkText, children: "Show less" })] }))) : (
|
|
23
|
+
/* no toggle: render normally, clicks bubble to row */
|
|
27
24
|
cell.render("Cell")) }) }));
|
|
28
25
|
};
|
|
29
26
|
export default TableCell;
|
|
@@ -8,10 +8,10 @@ export interface TableRowProps<T extends DataWithUUID> {
|
|
|
8
8
|
activeRowColor?: string;
|
|
9
9
|
rowHoverClasses?: string;
|
|
10
10
|
globalTrimActive?: boolean;
|
|
11
|
-
hasInfiniteScroll
|
|
11
|
+
hasInfiniteScroll: boolean;
|
|
12
12
|
rowUuid?: string;
|
|
13
13
|
columnInputs?: string[];
|
|
14
|
-
onRowClick
|
|
14
|
+
onRowClick: (index: number, rowUuid: string, event: React.MouseEvent<HTMLTableRowElement, MouseEvent>) => void;
|
|
15
15
|
hasDropDown?: boolean;
|
|
16
16
|
onFetchRowData?: (uuid: string) => Promise<void> | void;
|
|
17
17
|
loadingIndicator?: ReactNode;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// src/components/TableRow/TableRow.tsx
|
|
2
3
|
import { Fragment, useState } from "react";
|
|
3
4
|
import { motion, AnimatePresence } from "framer-motion";
|
|
4
5
|
import TableCell from "../TableCell";
|
|
@@ -8,30 +9,29 @@ import TableCell from "../TableCell";
|
|
|
8
9
|
const TableRow = ({
|
|
9
10
|
/* react‑table */
|
|
10
11
|
row, prepareRow,
|
|
11
|
-
/* visual
|
|
12
|
-
activeIndex, activeRowColor = "bg-pink-100", rowHoverClasses = "hover:bg-
|
|
13
|
-
/* cell
|
|
14
|
-
globalTrimActive
|
|
15
|
-
/*
|
|
12
|
+
/* visual */
|
|
13
|
+
activeIndex, activeRowColor = "bg-pink-100", rowHoverClasses = "hover:bg-navy-100 hover:cursor-pointer",
|
|
14
|
+
/* cell props */
|
|
15
|
+
globalTrimActive = false, hasInfiniteScroll,
|
|
16
|
+
/* meta */
|
|
16
17
|
rowUuid, columnInputs,
|
|
17
|
-
/*
|
|
18
|
+
/* click handler */
|
|
18
19
|
onRowClick,
|
|
19
|
-
/*
|
|
20
|
+
/* dropdown */
|
|
20
21
|
hasDropDown = false, onFetchRowData, loadingIndicator, errorIndicator, expandedContent, }) => {
|
|
21
|
-
/* prepare row
|
|
22
|
+
/* prepare react-table row */
|
|
22
23
|
prepareRow(row);
|
|
23
24
|
const isActive = activeIndex === row.index;
|
|
24
25
|
let rowClasses = "border-primary";
|
|
25
|
-
if (isActive)
|
|
26
|
+
if (isActive)
|
|
26
27
|
rowClasses += ` activeRow ${activeRowColor}`;
|
|
27
|
-
|
|
28
|
-
/* local state for dropdown expansion */
|
|
28
|
+
/* local dropdown state */
|
|
29
29
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
30
30
|
const [isLoading, setIsLoading] = useState(false);
|
|
31
31
|
const [error, setError] = useState(null);
|
|
32
|
-
/*
|
|
33
|
-
const handleRowClick = async (
|
|
34
|
-
onRowClick
|
|
32
|
+
/* row‑click: call your passed‑in handler, then dropdown logic */
|
|
33
|
+
const handleRowClick = async (e) => {
|
|
34
|
+
onRowClick(row.index, rowUuid ?? "", e);
|
|
35
35
|
if (hasDropDown) {
|
|
36
36
|
setIsExpanded((prev) => !prev);
|
|
37
37
|
if (onFetchRowData && rowUuid) {
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import { Meta } from "@storybook/react";
|
|
1
|
+
import { Meta, StoryFn } from "@storybook/react";
|
|
2
2
|
import TableRow from "./TableRow";
|
|
3
|
-
declare const
|
|
4
|
-
export default
|
|
3
|
+
declare const meta: Meta<typeof TableRow>;
|
|
4
|
+
export default meta;
|
|
5
5
|
export declare const Default: any;
|
|
6
6
|
export declare const ExpandableRow: any;
|
|
7
|
-
export declare const MultipleRows:
|
|
8
|
-
(): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
parameters: {
|
|
10
|
-
docs: {
|
|
11
|
-
description: {
|
|
12
|
-
story: string;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
};
|
|
7
|
+
export declare const MultipleRows: StoryFn;
|
|
@@ -58,7 +58,6 @@ const makeCells = (d) => [
|
|
|
58
58
|
];
|
|
59
59
|
const cellsForRow1 = makeCells(sampleData);
|
|
60
60
|
const cellsForRow2 = makeCells(sampleData2);
|
|
61
|
-
/* react‑table’s Row type is mocked for Storybook preview */
|
|
62
61
|
const makeMockRow = (d, idx, cells) => ({
|
|
63
62
|
index: idx,
|
|
64
63
|
id: String(idx),
|
|
@@ -71,37 +70,36 @@ const makeMockRow = (d, idx, cells) => ({
|
|
|
71
70
|
});
|
|
72
71
|
const mockRow = makeMockRow(sampleData, 0, cellsForRow1);
|
|
73
72
|
const mockRow2 = makeMockRow(sampleData2, 1, cellsForRow2);
|
|
74
|
-
const prepareRow = () => { }; // no‑op for
|
|
73
|
+
const prepareRow = () => { }; // no‑op for Storybook
|
|
75
74
|
/* ------------------------------------------------------------------ */
|
|
76
75
|
/* STORYBOOK CONFIG */
|
|
77
76
|
/* ------------------------------------------------------------------ */
|
|
78
|
-
|
|
77
|
+
const meta = {
|
|
79
78
|
title: "Table/TableRow",
|
|
80
79
|
component: TableRow,
|
|
81
80
|
tags: ["autodocs"],
|
|
81
|
+
decorators: [
|
|
82
|
+
(Story) => (_jsx("div", { onClickCapture: (e) => {
|
|
83
|
+
const t = e.target.innerText;
|
|
84
|
+
if (t === "Show more" || t === "Show less") {
|
|
85
|
+
alert("from cell");
|
|
86
|
+
}
|
|
87
|
+
}, children: _jsx(Story, {}) })),
|
|
88
|
+
],
|
|
82
89
|
argTypes: {
|
|
83
|
-
hasInfiniteScroll: {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
hasDropDown: {
|
|
88
|
-
control: "boolean",
|
|
89
|
-
description: "Whether this row has the sliding dropdown section.",
|
|
90
|
-
},
|
|
90
|
+
hasInfiniteScroll: { control: "boolean" },
|
|
91
|
+
hasDropDown: { control: "boolean" },
|
|
92
|
+
onRowClick: { action: "row clicked" },
|
|
91
93
|
},
|
|
92
94
|
parameters: {
|
|
93
95
|
layout: "centered",
|
|
94
|
-
docs: {
|
|
95
|
-
description: {
|
|
96
|
-
component: "Demonstrates the reusable **TableRow** and nested **TableCell**: click a truncated cell to ‘Show more / Show less’, and (optionally) expand the entire row via dropdown.",
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
96
|
},
|
|
100
97
|
};
|
|
98
|
+
export default meta;
|
|
101
99
|
/* ------------------------------------------------------------------ */
|
|
102
100
|
/* TEMPLATE */
|
|
103
101
|
/* ------------------------------------------------------------------ */
|
|
104
|
-
const Template = (args) => (_jsx("table", { className: "min-w-[700px]", children: _jsx("tbody", { children: _jsx(TableRow, { ...args }) }) }));
|
|
102
|
+
const Template = (args) => (_jsx("table", { className: "min-w-[700px]", children: _jsx("tbody", { children: _jsx(TableRow, { ...args, hasInfiniteScroll: args.hasInfiniteScroll ?? true, onRowClick: args.onRowClick ?? (() => alert("from row")) }) }) }));
|
|
105
103
|
/* ------------------------------------------------------------------ */
|
|
106
104
|
/* STORIES */
|
|
107
105
|
/* ------------------------------------------------------------------ */
|
|
@@ -109,17 +107,12 @@ export const Default = Template.bind({});
|
|
|
109
107
|
Default.args = {
|
|
110
108
|
row: mockRow,
|
|
111
109
|
prepareRow,
|
|
112
|
-
hasInfiniteScroll: true,
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
docs: {
|
|
119
|
-
description: {
|
|
120
|
-
story: "Click the **address** cell to toggle between its truncated preview and the full text.",
|
|
121
|
-
},
|
|
122
|
-
},
|
|
110
|
+
hasInfiniteScroll: true, // ✅ required
|
|
111
|
+
onRowClick: () => alert("from row"), // ✅ required
|
|
112
|
+
globalTrimActive: false, // optional
|
|
113
|
+
hasDropDown: false, // optional
|
|
114
|
+
rowUuid: sampleData.uuid, // optional
|
|
115
|
+
// (you can omit activeIndex, columnInputs, rowHoverClasses—they’re optional)
|
|
123
116
|
};
|
|
124
117
|
export const ExpandableRow = Template.bind({});
|
|
125
118
|
ExpandableRow.args = {
|
|
@@ -127,19 +120,4 @@ ExpandableRow.args = {
|
|
|
127
120
|
hasDropDown: true,
|
|
128
121
|
expandedContent: sampleData.expandedContent,
|
|
129
122
|
};
|
|
130
|
-
|
|
131
|
-
docs: {
|
|
132
|
-
description: {
|
|
133
|
-
story: "Row showcasing **both** the cell truncate/expand **and** the sliding dropdown. " +
|
|
134
|
-
"Click the address cell for ‘Show more’, and click the row itself for the dropdown.",
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
export const MultipleRows = () => (_jsx("table", { className: "min-w-[700px]", children: _jsxs("tbody", { children: [_jsx(TableRow, { row: mockRow, prepareRow: prepareRow, hasInfiniteScroll: true, hasDropDown: true, expandedContent: sampleData.expandedContent, rowUuid: sampleData.uuid }), _jsx(TableRow, { row: mockRow2, prepareRow: prepareRow, hasInfiniteScroll: true, hasDropDown: false, rowUuid: sampleData2.uuid })] }) }));
|
|
139
|
-
MultipleRows.parameters = {
|
|
140
|
-
docs: {
|
|
141
|
-
description: {
|
|
142
|
-
story: "Two‑row table: the first row includes both cell truncation and a dropdown; the second row is static.",
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
};
|
|
123
|
+
export const MultipleRows = () => (_jsx("table", { className: "min-w-[700px]", children: _jsxs("tbody", { children: [_jsx(TableRow, { row: mockRow, prepareRow: prepareRow, hasInfiniteScroll: true, onRowClick: () => alert("from row"), globalTrimActive: false, hasDropDown: true, rowUuid: sampleData.uuid, expandedContent: sampleData.expandedContent }), _jsx(TableRow, { row: mockRow2, prepareRow: prepareRow, hasInfiniteScroll: true, onRowClick: () => alert("from row"), globalTrimActive: false, hasDropDown: false, rowUuid: sampleData2.uuid })] }) }));
|
|
@@ -21,16 +21,20 @@ describe("TableRow - Branch Coverage Tests", () => {
|
|
|
21
21
|
getRowProps: vi.fn(() => ({ key: "row-props-0" })),
|
|
22
22
|
};
|
|
23
23
|
it("covers isActive = true (row is active)", () => {
|
|
24
|
-
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: { ...baseMockRow, index: 5 }, prepareRow: mockPrepareRow, activeIndex: 5
|
|
24
|
+
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: { ...baseMockRow, index: 5 }, prepareRow: mockPrepareRow, activeIndex: 5, hasInfiniteScroll: false, onRowClick: function (index, rowUuid, event) {
|
|
25
|
+
throw new Error("Function not implemented.");
|
|
26
|
+
} }) }) }));
|
|
25
27
|
expect(screen.getByTestId("table-row")).toHaveClass("activeRow");
|
|
26
28
|
});
|
|
27
29
|
it("covers isActive = false (row is NOT active)", () => {
|
|
28
|
-
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: { ...baseMockRow, index: 2 }, prepareRow: mockPrepareRow, activeIndex: 5
|
|
30
|
+
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: { ...baseMockRow, index: 2 }, prepareRow: mockPrepareRow, activeIndex: 5, hasInfiniteScroll: false, onRowClick: function (index, rowUuid, event) {
|
|
31
|
+
throw new Error("Function not implemented.");
|
|
32
|
+
} }) }) }));
|
|
29
33
|
expect(screen.getByTestId("table-row")).not.toHaveClass("activeRow");
|
|
30
34
|
});
|
|
31
35
|
it("covers onRowClick = defined + rowUuid = provided", () => {
|
|
32
36
|
const mockOnRowClick = vi.fn();
|
|
33
|
-
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: baseMockRow, prepareRow: mockPrepareRow, onRowClick: mockOnRowClick, rowUuid: "some-uuid" }) }) }));
|
|
37
|
+
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: baseMockRow, prepareRow: mockPrepareRow, onRowClick: mockOnRowClick, rowUuid: "some-uuid", hasInfiniteScroll: false }) }) }));
|
|
34
38
|
fireEvent.click(screen.getByTestId("table-row"));
|
|
35
39
|
expect(mockOnRowClick).toHaveBeenCalledWith(baseMockRow.index, // 0
|
|
36
40
|
"some-uuid", expect.anything() // Synthetic event
|
|
@@ -38,13 +42,15 @@ describe("TableRow - Branch Coverage Tests", () => {
|
|
|
38
42
|
});
|
|
39
43
|
it("covers onRowClick = defined + rowUuid = undefined (so calls empty string)", () => {
|
|
40
44
|
const mockOnRowClick = vi.fn();
|
|
41
|
-
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: baseMockRow, prepareRow: mockPrepareRow, onRowClick: mockOnRowClick }) }) }));
|
|
45
|
+
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: baseMockRow, prepareRow: mockPrepareRow, onRowClick: mockOnRowClick, hasInfiniteScroll: false }) }) }));
|
|
42
46
|
fireEvent.click(screen.getByTestId("table-row"));
|
|
43
47
|
expect(mockOnRowClick).toHaveBeenCalledWith(baseMockRow.index, // 0
|
|
44
48
|
"", expect.anything());
|
|
45
49
|
});
|
|
46
50
|
it("covers onRowClick = NOT defined", () => {
|
|
47
|
-
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: baseMockRow, prepareRow: mockPrepareRow
|
|
51
|
+
render(_jsx("table", { children: _jsx("tbody", { children: _jsx(TableRow, { row: baseMockRow, prepareRow: mockPrepareRow, hasInfiniteScroll: false, onRowClick: function (index, rowUuid, event) {
|
|
52
|
+
throw new Error("Function not implemented.");
|
|
53
|
+
} }) }) }));
|
|
48
54
|
// onRowClick not provided; just ensure no crash
|
|
49
55
|
fireEvent.click(screen.getByTestId("table-row"));
|
|
50
56
|
});
|