playbook_ui 16.7.0.pre.alpha.play295616404 → 16.7.0.pre.alpha.tablewidths16407
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/pb_advanced_table/Components/RegularTableView.tsx +2 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +2 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/VirtualizedTableView.tsx +5 -1
- data/app/pb_kits/playbook/pb_advanced_table/Hooks/useTableState.ts +24 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/ColumnLayoutHelper.ts +123 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +76 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.jsx +2 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_column_styling.md +10 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.json +7 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.overrides.json +1 -1
- data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_column_definitions_styling.json +6 -1
- data/app/pb_kits/playbook/pb_icon/_icon.tsx +1 -45
- data/app/pb_kits/playbook/pb_icon/icon.html.erb +1 -1
- data/app/pb_kits/playbook/pb_icon/icon.rb +0 -15
- data/app/pb_kits/playbook/pb_icon/icon.test.js +1 -52
- data/dist/chunks/{_typeahead-CMWdsZeX.js → _typeahead-D2TWdJTn.js} +1 -1
- data/dist/chunks/vendor.js +2 -2
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8da495f79107327990243768d12d0c686b02cd3c9139be2021b1a2502ac1091b
|
|
4
|
+
data.tar.gz: b87d04b9c001d89e1f25889e19ec812d5e882eb04b06df284bcb3feb963567ce
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b65bd11a250d2eb7de7f99b7e9c1209ef8d425244886afb6dfc744866172989ba223a981d78b92621f880c46fdb2ee3a3167776204754a430a847f1198ea71f
|
|
7
|
+
data.tar.gz: 91f38760a01e16eaaf16db868791168edbe57581cd05057e443ac3eeaffef513ebbc37451c716d65bb0591bfa0ebd022dc019c88d9cc15f62c74f5e5a78dfb25
|
|
@@ -5,6 +5,7 @@ import { flexRender, Row, Cell } from "@tanstack/react-table"
|
|
|
5
5
|
import { GenericObject } from "../../types"
|
|
6
6
|
import { isChrome } from "../Utilities/BrowserCheck"
|
|
7
7
|
import { findColumnDefByAccessor } from "../Utilities/ColumnStylingHelper"
|
|
8
|
+
import { playbookColumnLayoutStylesFromMeta } from "../Utilities/ColumnLayoutHelper"
|
|
8
9
|
import { getRowColorClass, shouldShowLoadingIndicator } from "../Utilities/RowUtils"
|
|
9
10
|
|
|
10
11
|
import LoadingInline from "../../pb_loading_inline/_loading_inline"
|
|
@@ -94,6 +95,7 @@ const TableCellRenderer = ({
|
|
|
94
95
|
)}
|
|
95
96
|
key={`${cell.id}-data`}
|
|
96
97
|
style={{
|
|
98
|
+
...playbookColumnLayoutStylesFromMeta(column.columnDef),
|
|
97
99
|
left: isPinnedLeft
|
|
98
100
|
? i === 1 // Accounting for set min-width for first column
|
|
99
101
|
? '180px'
|
|
@@ -16,6 +16,7 @@ import { SortIconButton } from "./SortIconButton"
|
|
|
16
16
|
import { ToggleIconButton } from "./ToggleIconButton"
|
|
17
17
|
import { displayIcon } from "../Utilities/IconHelpers"
|
|
18
18
|
import { findColumnDefByAccessor } from "../Utilities/ColumnStylingHelper"
|
|
19
|
+
import { playbookColumnLayoutStylesFromMeta } from "../Utilities/ColumnLayoutHelper"
|
|
19
20
|
import { updateExpandAndCollapseState } from "../Utilities/ExpansionControlHelpers"
|
|
20
21
|
|
|
21
22
|
import { isChrome } from "../Utilities/BrowserCheck"
|
|
@@ -198,6 +199,7 @@ const isToggleExpansionEnabled =
|
|
|
198
199
|
id={cellId}
|
|
199
200
|
key={`${header?.id}-header`}
|
|
200
201
|
style={{
|
|
202
|
+
...playbookColumnLayoutStylesFromMeta(header?.column?.columnDef),
|
|
201
203
|
backgroundColor: headerBackgroundColor,
|
|
202
204
|
color: headerFontColor,
|
|
203
205
|
left: isPinnedLeft
|
|
@@ -19,6 +19,7 @@ import { LoadingCell } from "../Components/LoadingCell"
|
|
|
19
19
|
import { renderCollapsibleTrail } from "../Components/CollapsibleTrail"
|
|
20
20
|
|
|
21
21
|
import AdvancedTableContext from "../Context/AdvancedTableContext"
|
|
22
|
+
import { playbookColumnLayoutStylesFromMeta } from "../Utilities/ColumnLayoutHelper"
|
|
22
23
|
|
|
23
24
|
type VirtualizedTableViewProps = {
|
|
24
25
|
collapsibleTrail?: boolean
|
|
@@ -224,7 +225,10 @@ export const VirtualizedTableView = ({
|
|
|
224
225
|
isLastCell && 'last-cell',
|
|
225
226
|
)}
|
|
226
227
|
key={`${cell.id}-data`}
|
|
227
|
-
style={{
|
|
228
|
+
style={{
|
|
229
|
+
...playbookColumnLayoutStylesFromMeta(cell.column.columnDef),
|
|
230
|
+
width: cellWidth,
|
|
231
|
+
}}
|
|
228
232
|
>
|
|
229
233
|
{collapsibleTrail && i === 0 && row.depth > 0 && renderCollapsibleTrail(row.depth)}
|
|
230
234
|
<span id={`${cell.id}-span`}>
|
|
@@ -12,6 +12,10 @@ import {
|
|
|
12
12
|
import { GenericObject } from "../../types";
|
|
13
13
|
import { createColumnHelper } from "@tanstack/react-table";
|
|
14
14
|
import { createCellFunction } from "../Utilities/CellRendererUtils";
|
|
15
|
+
import {
|
|
16
|
+
buildPlaybookColumnLayoutStyles,
|
|
17
|
+
buildTanStackSizingFromColumn,
|
|
18
|
+
} from "../Utilities/ColumnLayoutHelper";
|
|
15
19
|
import { getParentOnlySortedRowModel } from "../Utilities/RowModelUtils";
|
|
16
20
|
|
|
17
21
|
interface UseTableStateProps {
|
|
@@ -105,11 +109,31 @@ export function useTableState({
|
|
|
105
109
|
columns: buildColumns(column.columns, false),
|
|
106
110
|
};
|
|
107
111
|
}
|
|
112
|
+
const tanStackSizing = buildTanStackSizingFromColumn(column);
|
|
113
|
+
const layoutStyles = buildPlaybookColumnLayoutStyles(column, tanStackSizing);
|
|
114
|
+
const userMeta =
|
|
115
|
+
column.meta &&
|
|
116
|
+
typeof column.meta === "object" &&
|
|
117
|
+
!Array.isArray(column.meta)
|
|
118
|
+
? column.meta
|
|
119
|
+
: {};
|
|
120
|
+
const hasLayoutStyles =
|
|
121
|
+
layoutStyles.width !== undefined ||
|
|
122
|
+
layoutStyles.minWidth !== undefined ||
|
|
123
|
+
layoutStyles.maxWidth !== undefined;
|
|
124
|
+
|
|
108
125
|
// Define the base column structure
|
|
109
126
|
const columnStructure = {
|
|
110
127
|
...columnHelper.accessor(column.accessor, {
|
|
111
128
|
header: column.header ?? column.label ?? "",
|
|
112
129
|
enableSorting: isFirstColumn || column.enableSort === true,
|
|
130
|
+
...tanStackSizing,
|
|
131
|
+
meta: {
|
|
132
|
+
...userMeta,
|
|
133
|
+
...(hasLayoutStyles
|
|
134
|
+
? { playbookColumnLayoutStyles: layoutStyles }
|
|
135
|
+
: {}),
|
|
136
|
+
},
|
|
113
137
|
}),
|
|
114
138
|
};
|
|
115
139
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { CSSProperties } from "react"
|
|
2
|
+
|
|
3
|
+
import { GenericObject } from "../../types"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Converts a Playbook column width value to a CSS length string.
|
|
7
|
+
* Numbers are treated as pixels; strings are passed through (e.g. `"12rem"`, `"200px"`).
|
|
8
|
+
*/
|
|
9
|
+
export function cssLength(
|
|
10
|
+
value: number | string | undefined | null
|
|
11
|
+
): string | undefined {
|
|
12
|
+
if (value === undefined || value === null || value === "") return undefined
|
|
13
|
+
if (typeof value === "number" && Number.isFinite(value)) return `${value}px`
|
|
14
|
+
return String(value)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const columnStylingKeys = (column: GenericObject) =>
|
|
18
|
+
(column.columnStyling || column.column_styling || {}) as GenericObject
|
|
19
|
+
|
|
20
|
+
function readStylingLength(
|
|
21
|
+
styling: GenericObject,
|
|
22
|
+
camel: string,
|
|
23
|
+
snake?: string
|
|
24
|
+
): string | number | undefined {
|
|
25
|
+
if (snake) return styling[camel] ?? styling[snake]
|
|
26
|
+
return styling[camel] as string | number | undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* TanStack Table v8 `ColumnDef` sizing fields we forward from each `columnDefinitions` entry.
|
|
31
|
+
* See AdvancedTable kit docs for precedence with `columnStyling` width keys.
|
|
32
|
+
*/
|
|
33
|
+
export const PLAYBOOK_FORWARDED_COLUMN_DEF_SIZING_KEYS = [
|
|
34
|
+
"size",
|
|
35
|
+
"minSize",
|
|
36
|
+
"maxSize",
|
|
37
|
+
] as const
|
|
38
|
+
|
|
39
|
+
export type PlaybookForwardedColumnSizing = Partial<
|
|
40
|
+
Record<(typeof PLAYBOOK_FORWARDED_COLUMN_DEF_SIZING_KEYS)[number], number>
|
|
41
|
+
>
|
|
42
|
+
|
|
43
|
+
export function buildTanStackSizingFromColumn(
|
|
44
|
+
column: GenericObject
|
|
45
|
+
): PlaybookForwardedColumnSizing {
|
|
46
|
+
const out: PlaybookForwardedColumnSizing = {}
|
|
47
|
+
PLAYBOOK_FORWARDED_COLUMN_DEF_SIZING_KEYS.forEach((key) => {
|
|
48
|
+
const v = column[key]
|
|
49
|
+
if (typeof v === "number" && Number.isFinite(v)) out[key] = v
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const styling = columnStylingKeys(column)
|
|
53
|
+
|
|
54
|
+
if (out.size === undefined && readStylingLength(styling, "width") !== undefined) {
|
|
55
|
+
const w = readStylingLength(styling, "width")
|
|
56
|
+
if (typeof w === "number" && Number.isFinite(w)) out.size = w
|
|
57
|
+
}
|
|
58
|
+
if (out.minSize === undefined && readStylingLength(styling, "minWidth", "min_width") !== undefined) {
|
|
59
|
+
const w = readStylingLength(styling, "minWidth", "min_width")
|
|
60
|
+
if (typeof w === "number" && Number.isFinite(w)) out.minSize = w
|
|
61
|
+
}
|
|
62
|
+
if (out.maxSize === undefined && readStylingLength(styling, "maxWidth", "max_width") !== undefined) {
|
|
63
|
+
const w = readStylingLength(styling, "maxWidth", "max_width")
|
|
64
|
+
if (typeof w === "number" && Number.isFinite(w)) out.maxSize = w
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return out
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Inline width styles for `<th>` / `<td>` so `table-layout: fixed` tables keep stable
|
|
72
|
+
* columns when row content changes (e.g. expand/collapse). Values mirror TanStack sizing
|
|
73
|
+
* and/or `columnStyling` width keys; string values in `columnStyling` win over numeric
|
|
74
|
+
* TanStack fields when both describe the same axis.
|
|
75
|
+
*/
|
|
76
|
+
export function buildPlaybookColumnLayoutStyles(
|
|
77
|
+
column: GenericObject,
|
|
78
|
+
tanStackSizing: PlaybookForwardedColumnSizing
|
|
79
|
+
): CSSProperties {
|
|
80
|
+
const styling = columnStylingKeys(column)
|
|
81
|
+
const styles: CSSProperties = {}
|
|
82
|
+
|
|
83
|
+
const widthFromStyling = cssLength(
|
|
84
|
+
readStylingLength(styling, "width") as string | number | undefined
|
|
85
|
+
)
|
|
86
|
+
const minFromStyling = cssLength(
|
|
87
|
+
readStylingLength(styling, "minWidth", "min_width") as string | number | undefined
|
|
88
|
+
)
|
|
89
|
+
const maxFromStyling = cssLength(
|
|
90
|
+
readStylingLength(styling, "maxWidth", "max_width") as string | number | undefined
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
const widthFromTanStack =
|
|
94
|
+
tanStackSizing.size !== undefined
|
|
95
|
+
? cssLength(tanStackSizing.size)
|
|
96
|
+
: undefined
|
|
97
|
+
const minFromTanStack =
|
|
98
|
+
tanStackSizing.minSize !== undefined
|
|
99
|
+
? cssLength(tanStackSizing.minSize)
|
|
100
|
+
: undefined
|
|
101
|
+
const maxFromTanStack =
|
|
102
|
+
tanStackSizing.maxSize !== undefined
|
|
103
|
+
? cssLength(tanStackSizing.maxSize)
|
|
104
|
+
: undefined
|
|
105
|
+
|
|
106
|
+
if (widthFromStyling !== undefined) styles.width = widthFromStyling
|
|
107
|
+
else if (widthFromTanStack !== undefined) styles.width = widthFromTanStack
|
|
108
|
+
|
|
109
|
+
if (minFromStyling !== undefined) styles.minWidth = minFromStyling
|
|
110
|
+
else if (minFromTanStack !== undefined) styles.minWidth = minFromTanStack
|
|
111
|
+
|
|
112
|
+
if (maxFromStyling !== undefined) styles.maxWidth = maxFromStyling
|
|
113
|
+
else if (maxFromTanStack !== undefined) styles.maxWidth = maxFromTanStack
|
|
114
|
+
|
|
115
|
+
return styles
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function playbookColumnLayoutStylesFromMeta(
|
|
119
|
+
columnDef: GenericObject | undefined
|
|
120
|
+
): CSSProperties {
|
|
121
|
+
const meta = columnDef?.meta as GenericObject | undefined
|
|
122
|
+
return (meta?.playbookColumnLayoutStyles || {}) as CSSProperties
|
|
123
|
+
}
|
|
@@ -774,6 +774,82 @@ test("columnStyling.cellPadding sets cell padding", () => {
|
|
|
774
774
|
expect(firstEnrollmentCell).toHaveClass('p_none')
|
|
775
775
|
});
|
|
776
776
|
|
|
777
|
+
test("columnStyling minWidth, width, and maxWidth apply to header and body cells", () => {
|
|
778
|
+
const styledColumnDefs = [
|
|
779
|
+
{
|
|
780
|
+
accessor: "year",
|
|
781
|
+
label: "Year",
|
|
782
|
+
cellAccessors: ["quarter", "month", "day"],
|
|
783
|
+
columnStyling: { minWidth: 240, width: 260, maxWidth: 400 },
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
accessor: "newEnrollments",
|
|
787
|
+
label: "New Enrollments",
|
|
788
|
+
},
|
|
789
|
+
{
|
|
790
|
+
accessor: "scheduledMeetings",
|
|
791
|
+
label: "Scheduled Meetings",
|
|
792
|
+
},
|
|
793
|
+
];
|
|
794
|
+
|
|
795
|
+
render(
|
|
796
|
+
<AdvancedTable
|
|
797
|
+
columnDefinitions={styledColumnDefs}
|
|
798
|
+
data={{ testid: testId }}
|
|
799
|
+
tableData={MOCK_DATA}
|
|
800
|
+
/>
|
|
801
|
+
);
|
|
802
|
+
|
|
803
|
+
const yearHeader = screen.getByText("Year").closest("th");
|
|
804
|
+
expect(yearHeader).toHaveStyle({ minWidth: "240px", width: "260px", maxWidth: "400px" });
|
|
805
|
+
|
|
806
|
+
const yearCell = screen.getAllByText("2021")[0].closest("td");
|
|
807
|
+
expect(yearCell).toHaveStyle({ minWidth: "240px", width: "260px", maxWidth: "400px" });
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
test("columnDefinitions size, minSize, and maxSize apply layout styles", () => {
|
|
811
|
+
const styledColumnDefs = [
|
|
812
|
+
{
|
|
813
|
+
accessor: "year",
|
|
814
|
+
label: "Year",
|
|
815
|
+
cellAccessors: ["quarter", "month", "day"],
|
|
816
|
+
},
|
|
817
|
+
{
|
|
818
|
+
accessor: "newEnrollments",
|
|
819
|
+
label: "New Enrollments",
|
|
820
|
+
size: 180,
|
|
821
|
+
minSize: 160,
|
|
822
|
+
maxSize: 320,
|
|
823
|
+
},
|
|
824
|
+
{
|
|
825
|
+
accessor: "scheduledMeetings",
|
|
826
|
+
label: "Scheduled Meetings",
|
|
827
|
+
},
|
|
828
|
+
];
|
|
829
|
+
|
|
830
|
+
render(
|
|
831
|
+
<AdvancedTable
|
|
832
|
+
columnDefinitions={styledColumnDefs}
|
|
833
|
+
data={{ testid: testId }}
|
|
834
|
+
tableData={MOCK_DATA}
|
|
835
|
+
/>
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
const enrollmentsHeader = screen.getByText("New Enrollments").closest("th");
|
|
839
|
+
expect(enrollmentsHeader).toHaveStyle({
|
|
840
|
+
width: "180px",
|
|
841
|
+
minWidth: "160px",
|
|
842
|
+
maxWidth: "320px",
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
const enrollmentsCell = screen.getAllByText("20")[0].closest("td");
|
|
846
|
+
expect(enrollmentsCell).toHaveStyle({
|
|
847
|
+
width: "180px",
|
|
848
|
+
minWidth: "160px",
|
|
849
|
+
maxWidth: "320px",
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
|
|
777
853
|
test("columnStyling.fontColor sets cell font color", () => {
|
|
778
854
|
const styledColumnDefs = [
|
|
779
855
|
{
|
|
@@ -10,6 +10,8 @@ const AdvancedTableColumnStyling = (props) => {
|
|
|
10
10
|
accessor: "year",
|
|
11
11
|
label: "Year",
|
|
12
12
|
cellAccessors: ["quarter", "month", "day"],
|
|
13
|
+
// Keeps the hierarchy column narrow and stable when rows expand (see kit docs).
|
|
14
|
+
columnStyling: { minWidth: 108, width: 124, maxWidth: 168 },
|
|
13
15
|
},
|
|
14
16
|
{
|
|
15
17
|
accessor: "newEnrollments",
|
|
@@ -6,4 +6,14 @@ The `columnStyling` prop is an optional item that can be used within `columnDefi
|
|
|
6
6
|
|
|
7
7
|
3) `fontColor`: This will allow you to control the font color for a given column.
|
|
8
8
|
|
|
9
|
+
4) **Column width (layout stability)** — optional keys on `columnStyling` (numbers are treated as **pixels**; you may also use CSS length strings such as `"12rem"` or `"200px"`):
|
|
10
|
+
|
|
11
|
+
- `minWidth`: minimum width for the column’s header and body cells (helps prevent horizontal “jump” when row content or expansion depth changes on tables using fixed layout).
|
|
12
|
+
- `width`: preferred column width.
|
|
13
|
+
- `maxWidth`: maximum column width.
|
|
14
|
+
|
|
15
|
+
The live example below narrows the **Year** column (`minWidth` / `width` / `maxWidth`) so the first column stays compact while leaving room for expand and sort controls.
|
|
16
|
+
|
|
17
|
+
The same sizing can be expressed with TanStack `ColumnDef` fields on each column definition object (merged into the underlying table model): `size` (width), `minSize`, and `maxSize` (numbers, pixels). If both are present for the same axis, **`columnStyling` string values take precedence**; otherwise `columnStyling` numeric/string values override TanStack numbers when only one source sets that axis. **Grouped columns:** apply width controls on **leaf** column definitions (the columns that have an `accessor`).
|
|
18
|
+
|
|
9
19
|
`columnStyling` can be used within the columnDefinition of all the columns or some of them, as shown. Each column has its own individual control in this way.
|
|
@@ -313,7 +313,7 @@
|
|
|
313
313
|
},
|
|
314
314
|
"column_styling_info": {
|
|
315
315
|
"presetName": "Column Styling",
|
|
316
|
-
"message": "This sample uses columnStyling on column definitions.
|
|
316
|
+
"message": "This sample uses columnStyling on column definitions. The Year column uses minWidth, width, and maxWidth for a compact, stable first column; other columns show background colors on headers and cells.",
|
|
317
317
|
"type": "info"
|
|
318
318
|
}
|
|
319
319
|
},
|
|
@@ -2628,7 +2628,12 @@
|
|
|
2628
2628
|
"quarter",
|
|
2629
2629
|
"month",
|
|
2630
2630
|
"day"
|
|
2631
|
-
]
|
|
2631
|
+
],
|
|
2632
|
+
"columnStyling": {
|
|
2633
|
+
"minWidth": 108,
|
|
2634
|
+
"width": 124,
|
|
2635
|
+
"maxWidth": 168
|
|
2636
|
+
}
|
|
2632
2637
|
},
|
|
2633
2638
|
{
|
|
2634
2639
|
"accessor": "newEnrollments",
|
|
@@ -371,7 +371,7 @@
|
|
|
371
371
|
},
|
|
372
372
|
"column_styling_info": {
|
|
373
373
|
"presetName": "Column Styling",
|
|
374
|
-
"message": "This sample uses columnStyling on column definitions.
|
|
374
|
+
"message": "This sample uses columnStyling on column definitions. The Year column uses minWidth, width, and maxWidth for a compact, stable first column; other columns show background colors on headers and cells.",
|
|
375
375
|
"type": "info"
|
|
376
376
|
}
|
|
377
377
|
}
|
data/app/pb_kits/playbook/pb_advanced_table/docs/advanced_table_column_definitions_styling.json
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
{
|
|
3
3
|
"accessor": "year",
|
|
4
4
|
"label": "Year",
|
|
5
|
-
"cellAccessors": ["quarter", "month", "day"]
|
|
5
|
+
"cellAccessors": ["quarter", "month", "day"],
|
|
6
|
+
"columnStyling": {
|
|
7
|
+
"minWidth": 108,
|
|
8
|
+
"width": 124,
|
|
9
|
+
"maxWidth": 168
|
|
10
|
+
}
|
|
6
11
|
},
|
|
7
12
|
{
|
|
8
13
|
"accessor": "newEnrollments",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { ReactSVGElement
|
|
1
|
+
import React, { ReactSVGElement } from 'react'
|
|
2
2
|
import classnames from 'classnames'
|
|
3
3
|
import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
|
|
4
4
|
import { GlobalProps, globalProps } from '../utilities/globalProps'
|
|
@@ -116,44 +116,6 @@ const sizeMap = {
|
|
|
116
116
|
declare global {
|
|
117
117
|
// eslint-disable-next-line no-var
|
|
118
118
|
var PB_ICONS: {[key: string]: React.FunctionComponent<any>}
|
|
119
|
-
interface Window {
|
|
120
|
-
PB_ICON_FA_FALLBACK_DEBUG?: boolean
|
|
121
|
-
PB_ICON_FA_FALLBACKS?: {
|
|
122
|
-
icons: { [key: string]: number },
|
|
123
|
-
entries: Array<{ icon: string, fontStyle: string }>
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const isFaFallbackDebugEnabled = (): boolean => {
|
|
129
|
-
if (typeof window !== 'undefined' && window.PB_ICON_FA_FALLBACK_DEBUG) return true
|
|
130
|
-
if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') return true
|
|
131
|
-
|
|
132
|
-
return false
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const faFallbackDataProps = (icon: string) => (
|
|
136
|
-
isFaFallbackDebugEnabled()
|
|
137
|
-
? {
|
|
138
|
-
'data-pb-icon-fa-fallback': 'true',
|
|
139
|
-
'data-pb-icon-fa-fallback-icon': icon,
|
|
140
|
-
}
|
|
141
|
-
: {}
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
const recordFaFallback = (icon: string, fontStyle: string): void => {
|
|
145
|
-
if (!isFaFallbackDebugEnabled() || typeof window === 'undefined') return
|
|
146
|
-
|
|
147
|
-
window.PB_ICON_FA_FALLBACKS ||= { icons: {}, entries: [] }
|
|
148
|
-
window.PB_ICON_FA_FALLBACKS.icons[icon] = (window.PB_ICON_FA_FALLBACKS.icons[icon] || 0) + 1
|
|
149
|
-
window.PB_ICON_FA_FALLBACKS.entries.push({ icon, fontStyle })
|
|
150
|
-
window.dispatchEvent(new CustomEvent('pb:icon-fa-fallback', {
|
|
151
|
-
detail: {
|
|
152
|
-
icon,
|
|
153
|
-
fontStyle,
|
|
154
|
-
count: window.PB_ICON_FA_FALLBACKS.icons[icon],
|
|
155
|
-
},
|
|
156
|
-
}))
|
|
157
119
|
}
|
|
158
120
|
|
|
159
121
|
const Icon = (props: IconProps) => {
|
|
@@ -206,11 +168,6 @@ const Icon = (props: IconProps) => {
|
|
|
206
168
|
}
|
|
207
169
|
|
|
208
170
|
const isFA = !iconElement && !customIcon
|
|
209
|
-
const iconName = icon as string
|
|
210
|
-
|
|
211
|
-
useEffect(() => {
|
|
212
|
-
if (isFA) recordFaFallback(iconName, fontStyle)
|
|
213
|
-
}, [fontStyle, iconName, isFA])
|
|
214
171
|
|
|
215
172
|
let classes = classnames(
|
|
216
173
|
(!iconElement && !customIcon) ? 'pb_icon_kit' : '',
|
|
@@ -306,7 +263,6 @@ const Icon = (props: IconProps) => {
|
|
|
306
263
|
{...ariaProps}
|
|
307
264
|
{...dataProps}
|
|
308
265
|
{...htmlProps}
|
|
309
|
-
{...faFallbackDataProps(iconName)}
|
|
310
266
|
className={classes}
|
|
311
267
|
id={id}
|
|
312
268
|
/>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<%= object.icon.html_safe %>
|
|
6
6
|
</span>
|
|
7
7
|
<% else %>
|
|
8
|
-
<%= pb_content_tag(:i
|
|
8
|
+
<%= pb_content_tag(:i) do %>
|
|
9
9
|
<% end %>
|
|
10
10
|
<%= content_tag(:span, nil,
|
|
11
11
|
aria: { label: "#{object.icon} icon" }.merge(object.aria),
|
|
@@ -48,21 +48,6 @@ module Playbook
|
|
|
48
48
|
emoji_regex.match?(icon)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def fa_fallback_debug_enabled?
|
|
52
|
-
return false if Rails.env.production? && ENV["PB_ICON_FA_FALLBACK_DEBUG"] != "true"
|
|
53
|
-
|
|
54
|
-
Rails.env.development? || Rails.env.test? || ENV["PB_ICON_FA_FALLBACK_DEBUG"] == "true"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def fa_fallback_data
|
|
58
|
-
return {} unless fa_fallback_debug_enabled?
|
|
59
|
-
|
|
60
|
-
{
|
|
61
|
-
pb_icon_fa_fallback: true,
|
|
62
|
-
pb_icon_fa_fallback_icon: icon,
|
|
63
|
-
}
|
|
64
|
-
end
|
|
65
|
-
|
|
66
51
|
def classname
|
|
67
52
|
generate_classname(
|
|
68
53
|
"pb_icon_kit",
|
|
@@ -6,11 +6,6 @@ import Icon from './_icon'
|
|
|
6
6
|
const testId = "icon-kit"
|
|
7
7
|
|
|
8
8
|
describe("Icon Kit", () => {
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
delete window.PB_ICON_FA_FALLBACKS
|
|
11
|
-
delete window.PB_ICON_FA_FALLBACK_DEBUG
|
|
12
|
-
})
|
|
13
|
-
|
|
14
9
|
test("renders Icon classname", () => {
|
|
15
10
|
render(
|
|
16
11
|
<Icon
|
|
@@ -170,50 +165,4 @@ describe("Icon Kit", () => {
|
|
|
170
165
|
expect(kit).toHaveClass("color_primary")
|
|
171
166
|
})
|
|
172
167
|
|
|
173
|
-
|
|
174
|
-
render(
|
|
175
|
-
<Icon
|
|
176
|
-
data={{ testid: testId }}
|
|
177
|
-
icon="not-a-playbook-icon"
|
|
178
|
-
/>
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
const kit = screen.getByTestId(testId)
|
|
182
|
-
expect(kit).toHaveAttribute("data-pb-icon-fa-fallback", "true")
|
|
183
|
-
expect(kit).toHaveAttribute("data-pb-icon-fa-fallback-icon", "not-a-playbook-icon")
|
|
184
|
-
expect(window.PB_ICON_FA_FALLBACKS.icons["not-a-playbook-icon"]).toEqual(1)
|
|
185
|
-
expect(window.PB_ICON_FA_FALLBACKS.entries).toContainEqual({
|
|
186
|
-
icon: "not-a-playbook-icon",
|
|
187
|
-
fontStyle: "far",
|
|
188
|
-
})
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
test("groups duplicate Font Awesome fallback icons in the runtime collection", () => {
|
|
192
|
-
render(
|
|
193
|
-
<>
|
|
194
|
-
<Icon icon="repeated-fallback-icon" />
|
|
195
|
-
<Icon icon="repeated-fallback-icon" />
|
|
196
|
-
</>
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
expect(window.PB_ICON_FA_FALLBACKS.icons["repeated-fallback-icon"]).toEqual(2)
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
test("emits a Font Awesome fallback event with the icon name and count", () => {
|
|
203
|
-
const fallbackListener = jest.fn()
|
|
204
|
-
window.addEventListener("pb:icon-fa-fallback", fallbackListener)
|
|
205
|
-
|
|
206
|
-
render(<Icon icon="event-fallback-icon" />)
|
|
207
|
-
|
|
208
|
-
expect(fallbackListener).toHaveBeenCalledWith(expect.objectContaining({
|
|
209
|
-
detail: {
|
|
210
|
-
icon: "event-fallback-icon",
|
|
211
|
-
fontStyle: "far",
|
|
212
|
-
count: 1,
|
|
213
|
-
},
|
|
214
|
-
}))
|
|
215
|
-
|
|
216
|
-
window.removeEventListener("pb:icon-fa-fallback", fallbackListener)
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
})
|
|
168
|
+
})
|