@homebound/beam 2.99.1 → 2.100.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/dist/components/Icon.d.ts +1 -1
- package/dist/components/Table/GridTable.d.ts +3 -3
- package/dist/components/Table/GridTable.js +1 -3
- package/dist/components/Table/SortHeader.js +6 -1
- package/dist/components/Table/sortRows.d.ts +1 -1
- package/dist/components/Table/sortRows.js +8 -12
- package/dist/components/Table/useSortState.d.ts +1 -0
- package/dist/components/Table/useSortState.js +30 -14
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ export interface IconProps extends AriaAttributes, DOMProps {
|
|
|
9
9
|
/** The size of the icon in increments, i.e. 1 == 8px, default is 3 == 24px. */
|
|
10
10
|
inc?: number;
|
|
11
11
|
/** Styles overrides */
|
|
12
|
-
xss?: Xss<Margin>;
|
|
12
|
+
xss?: Xss<Margin | "visibility">;
|
|
13
13
|
}
|
|
14
14
|
export declare const Icon: React.MemoExoticComponent<(props: IconProps) => import("@emotion/react/jsx-runtime").JSX.Element>;
|
|
15
15
|
/**
|
|
@@ -103,13 +103,13 @@ export declare type RowTuple<R extends Kinded> = [GridDataRow<R> | undefined, Re
|
|
|
103
103
|
export declare type GridSortConfig<S> = {
|
|
104
104
|
on: "client";
|
|
105
105
|
/** The optional initial column (index in columns) and direction to sort. */
|
|
106
|
-
initial?: [S | GridColumn<any>, Direction];
|
|
106
|
+
initial?: [S | GridColumn<any>, Direction] | undefined;
|
|
107
107
|
} | {
|
|
108
108
|
on: "server";
|
|
109
109
|
/** The current sort by value + direction (if server-side sorting). */
|
|
110
110
|
value?: [S, Direction];
|
|
111
|
-
/** Callback for when the column is sorted (if server-side sorting). */
|
|
112
|
-
onSort: (orderBy: S, direction: Direction) => void;
|
|
111
|
+
/** Callback for when the column is sorted (if server-side sorting). Parameters set to `undefined` is a signal to return to the initial sort state */
|
|
112
|
+
onSort: (orderBy: S | undefined, direction: Direction | undefined) => void;
|
|
113
113
|
};
|
|
114
114
|
export interface GridTableProps<R extends Kinded, S, X> {
|
|
115
115
|
id?: string;
|
|
@@ -92,12 +92,10 @@ function GridTable(props) {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
const [sortState, setSortKey] = (0, useSortState_1.useSortState)(columns, sorting);
|
|
95
|
-
// Disclaimer that technically even though this is a useMemo, sortRows is mutating `rows` directly
|
|
96
95
|
const maybeSorted = (0, react_1.useMemo)(() => {
|
|
97
96
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client" && sortState) {
|
|
98
97
|
// If using client-side sort, the sortState use S = number
|
|
99
|
-
(0, sortRows_1.sortRows)(columns, rows, sortState);
|
|
100
|
-
return rows;
|
|
98
|
+
return (0, sortRows_1.sortRows)(columns, rows, sortState);
|
|
101
99
|
}
|
|
102
100
|
return rows;
|
|
103
101
|
}, [columns, rows, sorting, sortState]);
|
|
@@ -6,6 +6,7 @@ const react_1 = require("react");
|
|
|
6
6
|
const Icon_1 = require("../Icon");
|
|
7
7
|
const GridSortContext_1 = require("./GridSortContext");
|
|
8
8
|
const Css_1 = require("../../Css");
|
|
9
|
+
const hooks_1 = require("../../hooks");
|
|
9
10
|
const useTestIds_1 = require("../../utils/useTestIds");
|
|
10
11
|
/**
|
|
11
12
|
* Wraps column header names with up/down sorting icons.
|
|
@@ -20,8 +21,12 @@ const useTestIds_1 = require("../../utils/useTestIds");
|
|
|
20
21
|
*/
|
|
21
22
|
function SortHeader(props) {
|
|
22
23
|
const { content, xss } = props;
|
|
24
|
+
const { isHovered, hoverProps } = (0, hooks_1.useHover)({});
|
|
23
25
|
const { sorted, toggleSort } = (0, react_1.useContext)(GridSortContext_1.GridSortContext);
|
|
24
26
|
const tid = (0, useTestIds_1.useTestIds)(props, "sortHeader");
|
|
25
|
-
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({}, tid, { css: { ...Css_1.Css.df.aic.cursorPointer.selectNone.$, ...xss }, onClick: toggleSort }, { children: [content,
|
|
27
|
+
return ((0, jsx_runtime_1.jsxs)("div", Object.assign({}, tid, { css: { ...Css_1.Css.df.aic.h100.cursorPointer.selectNone.$, ...xss } }, hoverProps, { onClick: toggleSort }, { children: [content, (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.fs0.$ }, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, Object.assign({ icon: sorted === "DESC" ? "sortDown" : "sortUp", color: sorted !== undefined ? Css_1.Palette.LightBlue700 : Css_1.Palette.Gray400, xss: Css_1.Css.ml1
|
|
28
|
+
.visibility("hidden")
|
|
29
|
+
.if(isHovered || sorted !== undefined)
|
|
30
|
+
.visibility("visible").$, inc: 2 }, tid.icon), void 0) }), void 0)] }), void 0));
|
|
26
31
|
}
|
|
27
32
|
exports.SortHeader = SortHeader;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { GridCellContent, GridColumn, GridDataRow, GridSortConfig, Kinded } from "./GridTable";
|
|
3
3
|
import { SortState } from "./useSortState";
|
|
4
|
-
export declare function sortRows<R extends Kinded>(columns: GridColumn<R>[], rows: GridDataRow<R>[], sortState: SortState<number>):
|
|
4
|
+
export declare function sortRows<R extends Kinded>(columns: GridColumn<R>[], rows: GridDataRow<R>[], sortState: SortState<number>): GridDataRow<R>[];
|
|
5
5
|
export declare function ensureClientSideSortValueIsSortable(sorting: GridSortConfig<any> | undefined, isHeader: boolean, column: GridColumn<any>, idx: number, maybeContent: ReactNode | GridCellContent): void;
|
|
@@ -2,21 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureClientSideSortValueIsSortable = exports.sortRows = void 0;
|
|
4
4
|
const GridTable_1 = require("./GridTable");
|
|
5
|
-
//
|
|
6
|
-
// read from an immutable store like the apollo cache, but we basically always make
|
|
7
|
-
// a copy in the process of adding our `kind` tags.
|
|
8
|
-
//
|
|
9
|
-
// I suppose that is an interesting idea, would we ever want to render a GQL query/cache
|
|
10
|
-
// result directly into the table without first doing a kind-mapping? Like maybe we could
|
|
11
|
-
// use __typename as the kind.
|
|
5
|
+
// Returns a shallow copy of the `rows` parameter sorted based on `sortState`
|
|
12
6
|
function sortRows(columns, rows, sortState) {
|
|
13
|
-
sortBatch(columns, rows, sortState);
|
|
7
|
+
const sorted = sortBatch(columns, rows, sortState);
|
|
14
8
|
// Recursively sort child rows
|
|
15
|
-
|
|
9
|
+
sorted.forEach((row, i) => {
|
|
16
10
|
if (row.children) {
|
|
17
|
-
sortRows(columns, row.children, sortState);
|
|
11
|
+
sorted[i] = { ...sorted[i], children: sortRows(columns, row.children, sortState) };
|
|
18
12
|
}
|
|
19
|
-
}
|
|
13
|
+
});
|
|
14
|
+
return sorted;
|
|
20
15
|
}
|
|
21
16
|
exports.sortRows = sortRows;
|
|
22
17
|
function sortBatch(columns, batch, sortState) {
|
|
@@ -24,7 +19,8 @@ function sortBatch(columns, batch, sortState) {
|
|
|
24
19
|
const [value, direction] = sortState;
|
|
25
20
|
const column = columns[value];
|
|
26
21
|
const invert = direction === "DESC";
|
|
27
|
-
|
|
22
|
+
// Make a shallow copy for sorting to avoid mutating the original list
|
|
23
|
+
return [...batch].sort((a, b) => {
|
|
28
24
|
const v1 = sortValue((0, GridTable_1.applyRowFn)(column, a));
|
|
29
25
|
const v2 = sortValue((0, GridTable_1.applyRowFn)(column, b));
|
|
30
26
|
const v1e = v1 === null || v1 === undefined;
|
|
@@ -10,3 +10,4 @@ import { Direction, GridColumn, GridSortConfig, Kinded } from "./GridTable";
|
|
|
10
10
|
export declare type SortState<S> = readonly [S, Direction];
|
|
11
11
|
/** Small custom hook that wraps the "setSortColumn inverts the current sort" logic. */
|
|
12
12
|
export declare function useSortState<R extends Kinded, S>(columns: GridColumn<R, S>[], sorting?: GridSortConfig<S>): [SortState<S> | undefined, (value: S) => void];
|
|
13
|
+
export declare function deriveSortState<S>(currentSortState: SortState<S> | undefined, clickedKey: S, initialSortState: SortState<S> | undefined): SortState<S> | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useSortState = void 0;
|
|
3
|
+
exports.deriveSortState = exports.useSortState = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const GridTable_1 = require("./GridTable");
|
|
6
6
|
/** Small custom hook that wraps the "setSortColumn inverts the current sort" logic. */
|
|
@@ -8,34 +8,34 @@ function useSortState(columns, sorting) {
|
|
|
8
8
|
// If we're server-side sorting, use the caller's `sorting.value` prop to initialize our internal
|
|
9
9
|
// `useState`. After this, we ignore `sorting.value` because we assume it should match what our
|
|
10
10
|
// `setSortState` just changed anyway (in response to the user sorting a column).
|
|
11
|
-
const
|
|
11
|
+
const initialSortState = (0, react_1.useMemo)(() => {
|
|
12
12
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client") {
|
|
13
13
|
const { initial } = sorting;
|
|
14
|
-
if (initial) {
|
|
14
|
+
if (initial === undefined && "initial" in sorting) {
|
|
15
|
+
// if explicitly set to `undefined`, then do not sort
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
else if (initial) {
|
|
15
19
|
const key = typeof initial[0] === "number" ? initial[0] : columns.indexOf(initial[0]);
|
|
16
20
|
return [key, initial[1]];
|
|
17
21
|
}
|
|
18
22
|
else {
|
|
19
23
|
// If no explicit sorting, assume 1st column ascending
|
|
20
24
|
const firstSortableColumn = columns.findIndex((c) => c.clientSideSort !== false);
|
|
21
|
-
return [firstSortableColumn,
|
|
25
|
+
return [firstSortableColumn, GridTable_1.ASC];
|
|
22
26
|
}
|
|
23
27
|
}
|
|
24
28
|
else {
|
|
25
29
|
return sorting === null || sorting === void 0 ? void 0 : sorting.value;
|
|
26
30
|
}
|
|
27
|
-
});
|
|
28
|
-
|
|
31
|
+
}, [sorting, columns]);
|
|
32
|
+
const [sortState, setSortState] = (0, react_1.useState)(initialSortState);
|
|
33
|
+
// Make a custom setSortKey that is useState-like but contains the ASC->DESC->RESET logic.
|
|
29
34
|
const setSortKey = (0, react_1.useCallback)((clickedKey) => {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
// If clickedKey === currentKey, then toggle direction
|
|
33
|
-
clickedKey === currentKey
|
|
34
|
-
? [currentKey, currentDirection === GridTable_1.ASC ? GridTable_1.DESC : GridTable_1.ASC]
|
|
35
|
-
: // Otherwise, use the new key, and default to ascending
|
|
36
|
-
[clickedKey, GridTable_1.ASC];
|
|
37
|
-
setSortState([newKey, newDirection]);
|
|
35
|
+
const newState = deriveSortState(sortState, clickedKey, initialSortState);
|
|
36
|
+
setSortState(newState);
|
|
38
37
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "server") {
|
|
38
|
+
const [newKey, newDirection] = newState !== null && newState !== void 0 ? newState : [undefined, undefined];
|
|
39
39
|
sorting.onSort(newKey, newDirection);
|
|
40
40
|
}
|
|
41
41
|
},
|
|
@@ -44,3 +44,19 @@ function useSortState(columns, sorting) {
|
|
|
44
44
|
return [sortState, setSortKey];
|
|
45
45
|
}
|
|
46
46
|
exports.useSortState = useSortState;
|
|
47
|
+
// Exported for testing purposes
|
|
48
|
+
function deriveSortState(currentSortState, clickedKey, initialSortState) {
|
|
49
|
+
const [currentKey, currentDirection] = currentSortState || [];
|
|
50
|
+
// If the current sort state is not defined, or clicking a new column, then sort ASC on the clicked key
|
|
51
|
+
if (!currentSortState || clickedKey !== currentKey) {
|
|
52
|
+
return [clickedKey, GridTable_1.ASC];
|
|
53
|
+
}
|
|
54
|
+
// Otherwise when clicking the current column, toggle through sort states
|
|
55
|
+
if (currentDirection === GridTable_1.ASC) {
|
|
56
|
+
// if ASC -> go to desc
|
|
57
|
+
return [clickedKey, GridTable_1.DESC];
|
|
58
|
+
}
|
|
59
|
+
// Else, direction is already DESC, so revert to original sort value.
|
|
60
|
+
return initialSortState;
|
|
61
|
+
}
|
|
62
|
+
exports.deriveSortState = deriveSortState;
|