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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a3ea779e1668ef98a029660f1c4160ad2767ccaa2c0755c217065376a77331a
4
- data.tar.gz: 8712a84644138ca7cdb591be50afd392117c67c035cfcab5f27470a195fc91a4
3
+ metadata.gz: 8da495f79107327990243768d12d0c686b02cd3c9139be2021b1a2502ac1091b
4
+ data.tar.gz: b87d04b9c001d89e1f25889e19ec812d5e882eb04b06df284bcb3feb963567ce
5
5
  SHA512:
6
- metadata.gz: 0a6a14cac81c31a48708557878f64531909a6c813d8a410a50d9dc465d250fc4b1274bdeea3770309a5a19ef99b5d04bad0bcd2b336f421e6c780cf313cd513d
7
- data.tar.gz: ffcc469fd3ae5913bcf8da44b9856925ea1b72f56002cd868fc010380f5801f1a2c32e9c8aac1b28972a2cdfe8b375a1a59bf103870051f7a5182c881eb70e9e
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={{ width: cellWidth }}
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. You can style headers and cells for the whole table or per column.",
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. You can style headers and cells for the whole table or per column.",
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
  }
@@ -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, useEffect } from 'react'
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, data: object.data.merge(object.fa_fallback_data)) do %>
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
- test("marks Font Awesome fallback icons for runtime auditing", () => {
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
+ })