@patternfly/react-core 6.2.1-prerelease.5 → 6.2.1-prerelease.7
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/CHANGELOG.md +12 -0
- package/components/package.json +1 -1
- package/deprecated/package.json +1 -1
- package/dist/dynamic/components/AboutModal/package.json +1 -1
- package/dist/dynamic/components/Accordion/package.json +1 -1
- package/dist/dynamic/components/ActionList/package.json +1 -1
- package/dist/dynamic/components/Alert/package.json +1 -1
- package/dist/dynamic/components/Avatar/package.json +1 -1
- package/dist/dynamic/components/BackToTop/package.json +1 -1
- package/dist/dynamic/components/Backdrop/package.json +1 -1
- package/dist/dynamic/components/BackgroundImage/package.json +1 -1
- package/dist/dynamic/components/Badge/package.json +1 -1
- package/dist/dynamic/components/Banner/package.json +1 -1
- package/dist/dynamic/components/Brand/package.json +1 -1
- package/dist/dynamic/components/Breadcrumb/package.json +1 -1
- package/dist/dynamic/components/Button/package.json +1 -1
- package/dist/dynamic/components/CalendarMonth/package.json +1 -1
- package/dist/dynamic/components/Card/package.json +1 -1
- package/dist/dynamic/components/Checkbox/package.json +1 -1
- package/dist/dynamic/components/ClipboardCopy/package.json +1 -1
- package/dist/dynamic/components/CodeBlock/package.json +1 -1
- package/dist/dynamic/components/Content/package.json +1 -1
- package/dist/dynamic/components/DataList/package.json +1 -1
- package/dist/dynamic/components/DatePicker/package.json +1 -1
- package/dist/dynamic/components/DescriptionList/package.json +1 -1
- package/dist/dynamic/components/Divider/package.json +1 -1
- package/dist/dynamic/components/Drawer/package.json +1 -1
- package/dist/dynamic/components/Dropdown/package.json +1 -1
- package/dist/dynamic/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/components/EmptyState/package.json +1 -1
- package/dist/dynamic/components/ExpandableSection/package.json +1 -1
- package/dist/dynamic/components/FileUpload/package.json +1 -1
- package/dist/dynamic/components/Form/package.json +1 -1
- package/dist/dynamic/components/FormSelect/package.json +1 -1
- package/dist/dynamic/components/HelperText/package.json +1 -1
- package/dist/dynamic/components/Hint/package.json +1 -1
- package/dist/dynamic/components/Icon/package.json +1 -1
- package/dist/dynamic/components/InputGroup/package.json +1 -1
- package/dist/dynamic/components/JumpLinks/package.json +1 -1
- package/dist/dynamic/components/Label/package.json +1 -1
- package/dist/dynamic/components/List/package.json +1 -1
- package/dist/dynamic/components/LoginPage/package.json +1 -1
- package/dist/dynamic/components/Masthead/package.json +1 -1
- package/dist/dynamic/components/Menu/package.json +1 -1
- package/dist/dynamic/components/MenuToggle/package.json +1 -1
- package/dist/dynamic/components/Modal/package.json +1 -1
- package/dist/dynamic/components/MultipleFileUpload/package.json +1 -1
- package/dist/dynamic/components/Nav/package.json +1 -1
- package/dist/dynamic/components/NotificationBadge/package.json +1 -1
- package/dist/dynamic/components/NotificationDrawer/package.json +1 -1
- package/dist/dynamic/components/NumberInput/package.json +1 -1
- package/dist/dynamic/components/OverflowMenu/package.json +1 -1
- package/dist/dynamic/components/Page/package.json +1 -1
- package/dist/dynamic/components/Pagination/package.json +1 -1
- package/dist/dynamic/components/Panel/package.json +1 -1
- package/dist/dynamic/components/Popover/package.json +1 -1
- package/dist/dynamic/components/Progress/package.json +1 -1
- package/dist/dynamic/components/ProgressStepper/package.json +1 -1
- package/dist/dynamic/components/Radio/package.json +1 -1
- package/dist/dynamic/components/SearchInput/package.json +1 -1
- package/dist/dynamic/components/Select/package.json +1 -1
- package/dist/dynamic/components/Sidebar/package.json +1 -1
- package/dist/dynamic/components/SimpleList/package.json +1 -1
- package/dist/dynamic/components/Skeleton/package.json +1 -1
- package/dist/dynamic/components/SkipToContent/package.json +1 -1
- package/dist/dynamic/components/Slider/package.json +1 -1
- package/dist/dynamic/components/Spinner/package.json +1 -1
- package/dist/dynamic/components/Switch/package.json +1 -1
- package/dist/dynamic/components/Tabs/package.json +1 -1
- package/dist/dynamic/components/TextArea/package.json +1 -1
- package/dist/dynamic/components/TextInput/package.json +1 -1
- package/dist/dynamic/components/TextInputGroup/package.json +1 -1
- package/dist/dynamic/components/TimePicker/package.json +1 -1
- package/dist/dynamic/components/Timestamp/package.json +1 -1
- package/dist/dynamic/components/Title/package.json +1 -1
- package/dist/dynamic/components/ToggleGroup/package.json +1 -1
- package/dist/dynamic/components/Toolbar/package.json +1 -1
- package/dist/dynamic/components/Tooltip/package.json +1 -1
- package/dist/dynamic/components/TreeView/package.json +1 -1
- package/dist/dynamic/components/Truncate/package.json +1 -1
- package/dist/dynamic/components/Wizard/hooks/package.json +1 -1
- package/dist/dynamic/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/Chip/package.json +1 -1
- package/dist/dynamic/deprecated/components/DragDrop/package.json +1 -1
- package/dist/dynamic/deprecated/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/deprecated/components/Modal/package.json +1 -1
- package/dist/dynamic/deprecated/components/Tile/package.json +1 -1
- package/dist/dynamic/deprecated/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/package.json +1 -1
- package/dist/dynamic/helpers/FocusTrap/FocusTrap/package.json +1 -1
- package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
- package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
- package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
- package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
- package/dist/dynamic/helpers/constants/package.json +1 -1
- package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
- package/dist/dynamic/helpers/fileUtils/package.json +1 -1
- package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
- package/dist/dynamic/helpers/package.json +1 -1
- package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
- package/dist/dynamic/helpers/typeUtils/package.json +1 -1
- package/dist/dynamic/helpers/useInterval/package.json +1 -1
- package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
- package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
- package/dist/dynamic/helpers/util/package.json +1 -1
- package/dist/dynamic/layouts/Bullseye/package.json +1 -1
- package/dist/dynamic/layouts/Flex/package.json +1 -1
- package/dist/dynamic/layouts/Gallery/package.json +1 -1
- package/dist/dynamic/layouts/Grid/package.json +1 -1
- package/dist/dynamic/layouts/Level/package.json +1 -1
- package/dist/dynamic/layouts/Split/package.json +1 -1
- package/dist/dynamic/layouts/Stack/package.json +1 -1
- package/dist/dynamic/styles/package.json +1 -1
- package/dist/esm/components/Divider/Divider.d.ts +2 -0
- package/dist/esm/components/Divider/Divider.d.ts.map +1 -1
- package/dist/esm/components/Divider/Divider.js +2 -2
- package/dist/esm/components/Divider/Divider.js.map +1 -1
- package/dist/esm/components/Nav/NavItemSeparator.d.ts.map +1 -1
- package/dist/esm/components/Nav/NavItemSeparator.js +2 -2
- package/dist/esm/components/Nav/NavItemSeparator.js.map +1 -1
- package/dist/esm/components/Toolbar/ToolbarItem.d.ts.map +1 -1
- package/dist/esm/components/Toolbar/ToolbarItem.js +4 -3
- package/dist/esm/components/Toolbar/ToolbarItem.js.map +1 -1
- package/dist/esm/components/Truncate/Truncate.d.ts +11 -1
- package/dist/esm/components/Truncate/Truncate.d.ts.map +1 -1
- package/dist/esm/components/Truncate/Truncate.js +43 -6
- package/dist/esm/components/Truncate/Truncate.js.map +1 -1
- package/dist/js/components/Divider/Divider.d.ts +2 -0
- package/dist/js/components/Divider/Divider.d.ts.map +1 -1
- package/dist/js/components/Divider/Divider.js +2 -2
- package/dist/js/components/Divider/Divider.js.map +1 -1
- package/dist/js/components/Nav/NavItemSeparator.d.ts.map +1 -1
- package/dist/js/components/Nav/NavItemSeparator.js +2 -2
- package/dist/js/components/Nav/NavItemSeparator.js.map +1 -1
- package/dist/js/components/Toolbar/ToolbarItem.d.ts.map +1 -1
- package/dist/js/components/Toolbar/ToolbarItem.js +4 -3
- package/dist/js/components/Toolbar/ToolbarItem.js.map +1 -1
- package/dist/js/components/Truncate/Truncate.d.ts +11 -1
- package/dist/js/components/Truncate/Truncate.d.ts.map +1 -1
- package/dist/js/components/Truncate/Truncate.js +42 -5
- package/dist/js/components/Truncate/Truncate.js.map +1 -1
- package/dist/umd/assets/{output-BitEYrQK.css → output-sf2Bj9Mn.css} +15737 -15737
- package/dist/umd/react-core.min.js +3 -3
- package/helpers/package.json +1 -1
- package/layouts/package.json +1 -1
- package/next/package.json +1 -1
- package/package.json +2 -2
- package/src/components/Alert/examples/Alert.md +0 -3
- package/src/components/Divider/Divider.tsx +4 -1
- package/src/components/Divider/__tests__/Divider.test.tsx +10 -0
- package/src/components/Nav/NavItemSeparator.tsx +2 -1
- package/src/components/Toolbar/ToolbarItem.tsx +11 -1
- package/src/components/Truncate/Truncate.tsx +109 -22
- package/src/components/Truncate/__tests__/Truncate.test.tsx +70 -2
- package/src/components/Truncate/__tests__/__snapshots__/Truncate.test.tsx.snap +37 -0
- package/src/components/Truncate/examples/Truncate.md +32 -36
- package/src/components/Truncate/examples/TruncateCustomTooltipPosition.tsx +10 -0
- package/src/components/Truncate/examples/TruncateDefault.tsx +7 -0
- package/src/components/Truncate/examples/TruncateMaxChars.tsx +27 -0
- package/src/components/Truncate/examples/TruncateMiddle.tsx +11 -0
- package/src/components/Truncate/examples/TruncateStart.tsx +7 -0
package/helpers/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.2.1-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"6.2.1-prerelease.6","private":true}
|
package/layouts/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.2.1-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"6.2.1-prerelease.6","private":true}
|
package/next/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.2.1-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"6.2.1-prerelease.6","private":true}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-core",
|
|
3
|
-
"version": "6.2.1-prerelease.
|
|
3
|
+
"version": "6.2.1-prerelease.7",
|
|
4
4
|
"description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
|
|
5
5
|
"main": "dist/js/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"react": "^17 || ^18",
|
|
64
64
|
"react-dom": "^17 || ^18"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "a871a671931ed6e48419509ce2129e879656a84c"
|
|
67
67
|
}
|
|
@@ -149,9 +149,6 @@ const AlertTimeout: React.FunctionComponent = () => {
|
|
|
149
149
|
<Button variant="secondary" onClick={onClick}>
|
|
150
150
|
Add alert
|
|
151
151
|
</Button>
|
|
152
|
-
<Button variant="secondary" onClick={() => setAlerts([])}>
|
|
153
|
-
Remove all alerts
|
|
154
|
-
</Button>
|
|
155
152
|
<AlertGroup hasAnimations isLiveRegion>{alerts}</AlertGroup>
|
|
156
153
|
</Fragment>
|
|
157
154
|
);
|
|
@@ -31,6 +31,8 @@ export interface DividerProps extends React.HTMLProps<HTMLElement> {
|
|
|
31
31
|
xl?: 'vertical' | 'horizontal';
|
|
32
32
|
'2xl'?: 'vertical' | 'horizontal';
|
|
33
33
|
};
|
|
34
|
+
/** The ARIA role of the divider when the component property has a value other than "hr". */
|
|
35
|
+
role?: 'separator' | 'presentation';
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
export const Divider: React.FunctionComponent<DividerProps> = ({
|
|
@@ -38,6 +40,7 @@ export const Divider: React.FunctionComponent<DividerProps> = ({
|
|
|
38
40
|
component = DividerVariant.hr,
|
|
39
41
|
inset,
|
|
40
42
|
orientation,
|
|
43
|
+
role = 'separator',
|
|
41
44
|
...props
|
|
42
45
|
}: DividerProps) => {
|
|
43
46
|
const Component: any = component;
|
|
@@ -50,7 +53,7 @@ export const Divider: React.FunctionComponent<DividerProps> = ({
|
|
|
50
53
|
formatBreakpointMods(orientation, styles),
|
|
51
54
|
className
|
|
52
55
|
)}
|
|
53
|
-
{...(component !== 'hr' && { role
|
|
56
|
+
{...(component !== 'hr' && { role })}
|
|
54
57
|
{...props}
|
|
55
58
|
/>
|
|
56
59
|
);
|
|
@@ -91,6 +91,16 @@ test(`Test all insets`, () => {
|
|
|
91
91
|
});
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
test('Does not render with value passed to role by default', () => {
|
|
95
|
+
render(<Divider role="presentation" />);
|
|
96
|
+
expect(screen.queryByRole('presentation')).not.toBeInTheDocument();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('Renders with value passed to role when component is not "hr"', () => {
|
|
100
|
+
render(<Divider component="li" role="presentation" />);
|
|
101
|
+
expect(screen.getByRole('presentation')).toBeInTheDocument();
|
|
102
|
+
});
|
|
103
|
+
|
|
94
104
|
test('Matches the snapshot', () => {
|
|
95
105
|
const { asFragment } = render(<Divider />);
|
|
96
106
|
expect(asFragment()).toMatchSnapshot();
|
|
@@ -2,6 +2,7 @@ import { Divider, DividerProps } from '../Divider';
|
|
|
2
2
|
|
|
3
3
|
export const NavItemSeparator: React.FunctionComponent<DividerProps> = ({
|
|
4
4
|
component = 'li',
|
|
5
|
+
role = 'presentation',
|
|
5
6
|
...props
|
|
6
|
-
}: DividerProps) => <Divider component={component} {...props} />;
|
|
7
|
+
}: DividerProps) => <Divider component={component} role={role} {...props} />;
|
|
7
8
|
NavItemSeparator.displayName = 'NavItemSeparator';
|
|
@@ -185,10 +185,19 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
|
|
|
185
185
|
children,
|
|
186
186
|
isAllExpanded,
|
|
187
187
|
isOverflowContainer,
|
|
188
|
+
role,
|
|
188
189
|
...props
|
|
189
190
|
}: ToolbarItemProps) => {
|
|
190
191
|
if (variant === ToolbarItemVariant.separator) {
|
|
191
|
-
|
|
192
|
+
const isDividerRoleValid = role === 'separator' || role === 'presentation';
|
|
193
|
+
return (
|
|
194
|
+
<Divider
|
|
195
|
+
className={css(className)}
|
|
196
|
+
orientation={{ default: 'vertical' }}
|
|
197
|
+
{...props}
|
|
198
|
+
{...(isDividerRoleValid && { role: role as 'separator' | 'presentation' })}
|
|
199
|
+
/>
|
|
200
|
+
);
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
return (
|
|
@@ -217,6 +226,7 @@ export const ToolbarItem: React.FunctionComponent<ToolbarItemProps> = ({
|
|
|
217
226
|
)}
|
|
218
227
|
{...(variant === 'label' && { 'aria-hidden': true })}
|
|
219
228
|
id={id}
|
|
229
|
+
role={role}
|
|
220
230
|
{...props}
|
|
221
231
|
>
|
|
222
232
|
{children}
|
|
@@ -22,8 +22,18 @@ export interface TruncateProps extends React.HTMLProps<HTMLSpanElement> {
|
|
|
22
22
|
className?: string;
|
|
23
23
|
/** Text to truncate */
|
|
24
24
|
content: string;
|
|
25
|
-
/** The number of characters displayed in the second half of
|
|
25
|
+
/** The number of characters displayed in the second half of a middle truncation. This will be overridden by
|
|
26
|
+
* the maxCharsDisplayed prop.
|
|
27
|
+
*/
|
|
26
28
|
trailingNumChars?: number;
|
|
29
|
+
/** The maximum number of characters to display before truncating. This will always truncate content
|
|
30
|
+
* when its length exceeds the value passed to this prop, and container width/resizing will not affect truncation.
|
|
31
|
+
*/
|
|
32
|
+
maxCharsDisplayed?: number;
|
|
33
|
+
/** The content to use to signify omission of characters when using the maxCharsDisplayed prop.
|
|
34
|
+
* By default this will render an ellipsis.
|
|
35
|
+
*/
|
|
36
|
+
omissionContent?: string;
|
|
27
37
|
/** Where the text will be truncated */
|
|
28
38
|
position?: 'start' | 'middle' | 'end';
|
|
29
39
|
/** Tooltip position */
|
|
@@ -49,13 +59,15 @@ export interface TruncateProps extends React.HTMLProps<HTMLSpanElement> {
|
|
|
49
59
|
refToGetParent?: React.RefObject<any>;
|
|
50
60
|
}
|
|
51
61
|
|
|
52
|
-
const
|
|
62
|
+
const sliceTrailingContent = (str: string, slice: number) => [str.slice(0, str.length - slice), str.slice(-slice)];
|
|
53
63
|
|
|
54
64
|
export const Truncate: React.FunctionComponent<TruncateProps> = ({
|
|
55
65
|
className,
|
|
56
66
|
position = 'end',
|
|
57
67
|
tooltipPosition = 'top',
|
|
58
68
|
trailingNumChars = 7,
|
|
69
|
+
maxCharsDisplayed,
|
|
70
|
+
omissionContent = '\u2026',
|
|
59
71
|
content,
|
|
60
72
|
refToGetParent,
|
|
61
73
|
...props
|
|
@@ -63,11 +75,17 @@ export const Truncate: React.FunctionComponent<TruncateProps> = ({
|
|
|
63
75
|
const [isTruncated, setIsTruncated] = useState(true);
|
|
64
76
|
const [parentElement, setParentElement] = useState<HTMLElement>(null);
|
|
65
77
|
const [textElement, setTextElement] = useState<HTMLElement>(null);
|
|
78
|
+
const [shouldRenderByMaxChars, setShouldRenderByMaxChars] = useState(maxCharsDisplayed > 0);
|
|
66
79
|
|
|
67
80
|
const textRef = useRef<HTMLElement>(null);
|
|
68
81
|
const subParentRef = useRef<HTMLDivElement>(null);
|
|
69
82
|
const observer = useRef(null);
|
|
70
83
|
|
|
84
|
+
if (maxCharsDisplayed <= 0) {
|
|
85
|
+
// eslint-disable-next-line no-console
|
|
86
|
+
console.warn('Truncate: the maxCharsDisplayed must be greater than 0, otherwise no content will be visible.');
|
|
87
|
+
}
|
|
88
|
+
|
|
71
89
|
const getActualWidth = (element: Element) => {
|
|
72
90
|
const computedStyle = getComputedStyle(element);
|
|
73
91
|
|
|
@@ -100,7 +118,7 @@ export const Truncate: React.FunctionComponent<TruncateProps> = ({
|
|
|
100
118
|
}, [textRef, subParentRef, textElement, parentElement]);
|
|
101
119
|
|
|
102
120
|
useEffect(() => {
|
|
103
|
-
if (textElement && parentElement && !observer.current) {
|
|
121
|
+
if (textElement && parentElement && !observer.current && !shouldRenderByMaxChars) {
|
|
104
122
|
const totalTextWidth = calculateTotalTextWidth(textElement, trailingNumChars, content);
|
|
105
123
|
const textWidth = position === 'middle' ? totalTextWidth : textElement.scrollWidth;
|
|
106
124
|
|
|
@@ -115,31 +133,100 @@ export const Truncate: React.FunctionComponent<TruncateProps> = ({
|
|
|
115
133
|
observer();
|
|
116
134
|
};
|
|
117
135
|
}
|
|
118
|
-
}, [textElement, parentElement, trailingNumChars, content, position]);
|
|
136
|
+
}, [textElement, parentElement, trailingNumChars, content, position, shouldRenderByMaxChars]);
|
|
119
137
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (shouldRenderByMaxChars) {
|
|
140
|
+
setIsTruncated(content.length > maxCharsDisplayed);
|
|
141
|
+
}
|
|
142
|
+
}, [shouldRenderByMaxChars]);
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
setShouldRenderByMaxChars(maxCharsDisplayed > 0);
|
|
146
|
+
}, [maxCharsDisplayed]);
|
|
147
|
+
|
|
148
|
+
const renderResizeObserverContent = () => {
|
|
149
|
+
if (position === TruncatePosition.end || position === TruncatePosition.start) {
|
|
150
|
+
return (
|
|
151
|
+
<>
|
|
152
|
+
<span ref={textRef} className={truncateStyles[position]}>
|
|
153
|
+
{content}
|
|
154
|
+
{position === TruncatePosition.start && <Fragment>‎</Fragment>}
|
|
132
155
|
</span>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
156
|
+
</>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const shouldSliceContent = content.length - trailingNumChars > minWidthCharacters;
|
|
161
|
+
return (
|
|
162
|
+
<>
|
|
137
163
|
<Fragment>
|
|
138
164
|
<span ref={textRef} className={styles.truncateStart}>
|
|
139
|
-
{content}
|
|
165
|
+
{shouldSliceContent ? sliceTrailingContent(content, trailingNumChars)[0] : content}
|
|
140
166
|
</span>
|
|
167
|
+
{shouldSliceContent && (
|
|
168
|
+
<span className={styles.truncateEnd}>{sliceTrailingContent(content, trailingNumChars)[1]}</span>
|
|
169
|
+
)}
|
|
141
170
|
</Fragment>
|
|
142
|
-
|
|
171
|
+
</>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const renderMaxDisplayContent = () => {
|
|
176
|
+
const renderVisibleContent = (contentToRender: string) => (
|
|
177
|
+
<span className={`${styles.truncate}__text`}>{contentToRender}</span>
|
|
178
|
+
);
|
|
179
|
+
if (!isTruncated) {
|
|
180
|
+
return renderVisibleContent(content);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const omissionElement = (
|
|
184
|
+
<span className={`${styles.truncate}__omission`} aria-hidden="true">
|
|
185
|
+
{omissionContent}
|
|
186
|
+
</span>
|
|
187
|
+
);
|
|
188
|
+
const renderVisuallyHiddenContent = (contentToHide: string) => (
|
|
189
|
+
<span className="pf-v6-screen-reader">{contentToHide}</span>
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
if (position === TruncatePosition.start) {
|
|
193
|
+
return (
|
|
194
|
+
<>
|
|
195
|
+
{renderVisuallyHiddenContent(content.slice(0, maxCharsDisplayed * -1))}
|
|
196
|
+
{omissionElement}
|
|
197
|
+
{renderVisibleContent(content.slice(maxCharsDisplayed * -1))}
|
|
198
|
+
</>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
if (position === TruncatePosition.end) {
|
|
202
|
+
return (
|
|
203
|
+
<>
|
|
204
|
+
{renderVisibleContent(content.slice(0, maxCharsDisplayed))}
|
|
205
|
+
{omissionElement}
|
|
206
|
+
{renderVisuallyHiddenContent(content.slice(maxCharsDisplayed))}
|
|
207
|
+
</>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const trueMiddleStart = Math.floor(maxCharsDisplayed / 2);
|
|
212
|
+
const trueMiddleEnd = Math.ceil(maxCharsDisplayed / 2) * -1;
|
|
213
|
+
return (
|
|
214
|
+
<>
|
|
215
|
+
{renderVisibleContent(content.slice(0, trueMiddleStart))}
|
|
216
|
+
{omissionElement}
|
|
217
|
+
{renderVisuallyHiddenContent(content.slice(trueMiddleStart, trueMiddleEnd))}
|
|
218
|
+
{renderVisibleContent(content.slice(trueMiddleEnd))}
|
|
219
|
+
</>
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const truncateBody = (
|
|
224
|
+
<span
|
|
225
|
+
ref={subParentRef}
|
|
226
|
+
className={css(styles.truncate, shouldRenderByMaxChars && styles.modifiers.fixed, className)}
|
|
227
|
+
{...props}
|
|
228
|
+
>
|
|
229
|
+
{!shouldRenderByMaxChars ? renderResizeObserverContent() : renderMaxDisplayContent()}
|
|
143
230
|
</span>
|
|
144
231
|
);
|
|
145
232
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
1
|
+
import { render, screen, within } from '@testing-library/react';
|
|
2
2
|
import { Truncate } from '../Truncate';
|
|
3
3
|
import styles from '@patternfly/react-styles/css/components/Truncate/truncate';
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
@@ -24,7 +24,7 @@ test(`renders with class ${styles.truncate}`, () => {
|
|
|
24
24
|
|
|
25
25
|
const test = screen.getByLabelText('test-id');
|
|
26
26
|
|
|
27
|
-
expect(test).toHaveClass(styles.truncate);
|
|
27
|
+
expect(test).toHaveClass(styles.truncate, { exact: true });
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test('renders with custom class name passed via prop', () => {
|
|
@@ -148,3 +148,71 @@ test('renders with inherited element props spread to the component', () => {
|
|
|
148
148
|
|
|
149
149
|
expect(screen.getByTestId('test-id')).toHaveAccessibleName('labelling-id');
|
|
150
150
|
});
|
|
151
|
+
|
|
152
|
+
describe('Truncation with maxCharsDisplayed', () => {
|
|
153
|
+
test(`Does not render with class ${styles.modifiers.fixed} when maxCharsDisplayed is 0`, () => {
|
|
154
|
+
render(<Truncate maxCharsDisplayed={0} data-testid="truncate-component" content="Test content" />);
|
|
155
|
+
|
|
156
|
+
expect(screen.getByTestId('truncate-component')).not.toHaveClass(styles.modifiers.fixed);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test(`Renders with class ${styles.modifiers.fixed} when maxCharsDisplayed is greater than 0`, () => {
|
|
160
|
+
render(<Truncate maxCharsDisplayed={1} data-testid="truncate-component" content="Test content" />);
|
|
161
|
+
|
|
162
|
+
expect(screen.getByTestId('truncate-component')).toHaveClass(styles.modifiers.fixed);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('Renders with hidden truncated content at end by default when maxCharsDisplayed is passed', () => {
|
|
166
|
+
render(<Truncate content="Default end position content truncated" maxCharsDisplayed={6} />);
|
|
167
|
+
|
|
168
|
+
expect(screen.getByText('Defaul')).toHaveClass(`${styles.truncate}__text`, { exact: true });
|
|
169
|
+
expect(screen.getByText('t end position content truncated')).toHaveClass('pf-v6-screen-reader');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('Renders with hidden truncated content at middle position when maxCharsDisplayed is passed and position="middle"', () => {
|
|
173
|
+
render(<Truncate position="middle" content="Middle position contents being truncated" maxCharsDisplayed={10} />);
|
|
174
|
+
|
|
175
|
+
expect(screen.getByText('Middl')).toHaveClass(`${styles.truncate}__text`, { exact: true });
|
|
176
|
+
expect(screen.getByText('e position contents being trun')).toHaveClass('pf-v6-screen-reader');
|
|
177
|
+
expect(screen.getByText('cated')).toHaveClass(`${styles.truncate}__text`, { exact: true });
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('Renders with hidden truncated content at start when maxCharsDisplayed is passed and position="start"', () => {
|
|
181
|
+
render(<Truncate position="start" content="Start position content truncated" maxCharsDisplayed={6} />);
|
|
182
|
+
|
|
183
|
+
expect(screen.getByText('Start position content tru')).toHaveClass('pf-v6-screen-reader');
|
|
184
|
+
expect(screen.getByText('ncated')).toHaveClass(`${styles.truncate}__text`, { exact: true });
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('Renders full content when maxCharsDisplayed exceeds the length of the content', () => {
|
|
188
|
+
render(<Truncate content="This full content is rendered" maxCharsDisplayed={90} />);
|
|
189
|
+
|
|
190
|
+
expect(screen.getByText('This full content is rendered')).toHaveClass(`${styles.truncate}__text`, { exact: true });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test('Renders ellipsis as omission content by default', () => {
|
|
194
|
+
render(<Truncate content="Test truncation content" maxCharsDisplayed={5} />);
|
|
195
|
+
|
|
196
|
+
expect(screen.getByText('\u2026')).toHaveClass(`${styles.truncate}__omission`, { exact: true });
|
|
197
|
+
expect(screen.getByText('\u2026')).toHaveAttribute('aria-hidden', 'true');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('Renders custom omission content when omissionContent is passed', () => {
|
|
201
|
+
render(<Truncate omissionContent="---" content="Test truncation content" maxCharsDisplayed={5} />);
|
|
202
|
+
|
|
203
|
+
expect(screen.getByText('---')).toHaveClass(`${styles.truncate}__omission`, { exact: true });
|
|
204
|
+
expect(screen.getByText('---')).toHaveAttribute('aria-hidden', 'true');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('Does not render omission content when maxCharsDisplayed exceeds the length of the content ', () => {
|
|
208
|
+
render(<Truncate content="Test truncation content" maxCharsDisplayed={99} />);
|
|
209
|
+
|
|
210
|
+
expect(screen.queryByText('\u2026')).not.toBeInTheDocument();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test('Matches snapshot with default position', () => {
|
|
214
|
+
const { asFragment } = render(<Truncate content="Test truncation content" maxCharsDisplayed={3} />);
|
|
215
|
+
|
|
216
|
+
expect(asFragment()).toMatchSnapshot();
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
|
+
exports[`Truncation with maxCharsDisplayed Matches snapshot with default position 1`] = `
|
|
4
|
+
<DocumentFragment>
|
|
5
|
+
<div
|
|
6
|
+
data-testid="Tooltip-mock"
|
|
7
|
+
>
|
|
8
|
+
<div
|
|
9
|
+
data-testid="Tooltip-mock-content-container"
|
|
10
|
+
>
|
|
11
|
+
Test Test truncation content
|
|
12
|
+
</div>
|
|
13
|
+
<p>
|
|
14
|
+
position: top
|
|
15
|
+
</p>
|
|
16
|
+
<span
|
|
17
|
+
class="pf-v6-c-truncate pf-m-fixed"
|
|
18
|
+
>
|
|
19
|
+
<span
|
|
20
|
+
class="pf-v6-c-truncate__text"
|
|
21
|
+
>
|
|
22
|
+
Tes
|
|
23
|
+
</span>
|
|
24
|
+
<span
|
|
25
|
+
aria-hidden="true"
|
|
26
|
+
class="pf-v6-c-truncate__omission"
|
|
27
|
+
>
|
|
28
|
+
…
|
|
29
|
+
</span>
|
|
30
|
+
<span
|
|
31
|
+
class="pf-v6-screen-reader"
|
|
32
|
+
>
|
|
33
|
+
t truncation content
|
|
34
|
+
</span>
|
|
35
|
+
</span>
|
|
36
|
+
</div>
|
|
37
|
+
</DocumentFragment>
|
|
38
|
+
`;
|
|
39
|
+
|
|
3
40
|
exports[`renders default truncation 1`] = `
|
|
4
41
|
<DocumentFragment>
|
|
5
42
|
<div
|
|
@@ -9,50 +9,46 @@ import './TruncateExamples.css';
|
|
|
9
9
|
|
|
10
10
|
## Examples
|
|
11
11
|
|
|
12
|
+
The default behavior of the `Truncate` component is to truncate based on whether the content can fit within the width of its parent container, and to prevent text from wrapping. The following examples that use this default behavior render the `<Truncate>` component inside a resizable container, allowing you to see how the parent container width affects the truncation.
|
|
13
|
+
|
|
12
14
|
### Default
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'}
|
|
19
|
-
/>
|
|
20
|
-
</div>
|
|
15
|
+
|
|
16
|
+
By default content will be truncated at its end when it cannot fit entirely inside its parent container.
|
|
17
|
+
|
|
18
|
+
```ts file="./TruncateDefault.tsx"
|
|
19
|
+
|
|
21
20
|
```
|
|
22
21
|
|
|
23
22
|
### Middle
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
|
|
30
|
-
trailingNumChars={10}
|
|
31
|
-
position={'middle'}
|
|
32
|
-
/>
|
|
33
|
-
</div>
|
|
23
|
+
|
|
24
|
+
When passing a `position` property with a value of "middle", the position of the truncation will change based on the parent container's width and the amount of `trailingNumChars` passed in. The `trailingNumChars` will always be displayed, while the rest of the content will be truncated based on the parent container width.
|
|
25
|
+
|
|
26
|
+
```ts file="./TruncateMiddle.tsx"
|
|
27
|
+
|
|
34
28
|
```
|
|
35
29
|
|
|
36
30
|
### Start
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'}
|
|
43
|
-
position={'start'}
|
|
44
|
-
/>
|
|
45
|
-
</div>
|
|
31
|
+
|
|
32
|
+
You can truncate content at its start by passing the `position` property with a value of "start". This can be useful if you have several strings to truncate that have similar text at the start, but unique text at the end that you want to have visible.
|
|
33
|
+
|
|
34
|
+
```ts file="./TruncateStart.tsx"
|
|
35
|
+
|
|
46
36
|
```
|
|
47
37
|
|
|
48
|
-
###
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
### With custom tooltip position
|
|
39
|
+
|
|
40
|
+
You can customize the position of the `<Tooltip>` that is rendered by passing in the `tooltipPosition` property. The following example overrides the default "top" position with a "bottom" position.
|
|
41
|
+
|
|
42
|
+
```ts file="./TruncateCustomTooltipPosition.tsx"
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Based on max characters
|
|
47
|
+
|
|
48
|
+
Rather than observing container width, you can have truncation be based on a maximum amount of characters that should always be displayed via the `maxCharsDisplayed` property. While the content's parent container width will not have an affect on whether truncation occurs, it will affect whether the content wraps. This property must be set to a value larger than `0`, otherwise the component will fall back to observing container width.
|
|
49
|
+
|
|
50
|
+
Truncating based on a maximum amount of characters will truncate the content at the end by default. When the `position` property is set to "middle", the truncation will split the content as evenly as possible, providing a more "true middle" truncation.
|
|
51
|
+
|
|
52
|
+
```ts file="./TruncateMaxChars.tsx"
|
|
51
53
|
|
|
52
|
-
<div className="truncate-example-resize">
|
|
53
|
-
<Truncate
|
|
54
|
-
content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'}
|
|
55
|
-
tooltipPosition={'bottom'}
|
|
56
|
-
/>
|
|
57
|
-
</div>
|
|
58
54
|
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Truncate } from '@patternfly/react-core';
|
|
2
|
+
|
|
3
|
+
export const TruncateCustomTooltipPosition: React.FunctionComponent = () => (
|
|
4
|
+
<div className="truncate-example-resize">
|
|
5
|
+
<Truncate
|
|
6
|
+
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
|
|
7
|
+
tooltipPosition={'bottom'}
|
|
8
|
+
/>
|
|
9
|
+
</div>
|
|
10
|
+
);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Truncate } from '@patternfly/react-core';
|
|
2
|
+
|
|
3
|
+
export const TruncateDefault: React.FunctionComponent = () => (
|
|
4
|
+
<div className="truncate-example-resize">
|
|
5
|
+
<Truncate content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'} />
|
|
6
|
+
</div>
|
|
7
|
+
);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Truncate, TruncatePosition } from '@patternfly/react-core';
|
|
2
|
+
|
|
3
|
+
export const TruncateMaxChars: React.FunctionComponent = () => (
|
|
4
|
+
<>
|
|
5
|
+
<div>Truncated at end position:</div>
|
|
6
|
+
<Truncate
|
|
7
|
+
maxCharsDisplayed={15}
|
|
8
|
+
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
|
|
9
|
+
/>
|
|
10
|
+
<br />
|
|
11
|
+
<br />
|
|
12
|
+
<div>Truncated at middle position:</div>
|
|
13
|
+
<Truncate
|
|
14
|
+
maxCharsDisplayed={15}
|
|
15
|
+
position={TruncatePosition.middle}
|
|
16
|
+
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
|
|
17
|
+
/>
|
|
18
|
+
<br />
|
|
19
|
+
<br />
|
|
20
|
+
<div>Truncated at start position:</div>
|
|
21
|
+
<Truncate
|
|
22
|
+
maxCharsDisplayed={15}
|
|
23
|
+
position={TruncatePosition.start}
|
|
24
|
+
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
|
|
25
|
+
/>
|
|
26
|
+
</>
|
|
27
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Truncate } from '@patternfly/react-core';
|
|
2
|
+
|
|
3
|
+
export const TruncateMiddle: React.FunctionComponent = () => (
|
|
4
|
+
<div className="truncate-example-resize">
|
|
5
|
+
<Truncate
|
|
6
|
+
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
|
|
7
|
+
trailingNumChars={10}
|
|
8
|
+
position={'middle'}
|
|
9
|
+
/>
|
|
10
|
+
</div>
|
|
11
|
+
);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Truncate } from '@patternfly/react-core';
|
|
2
|
+
|
|
3
|
+
export const TruncateStart: React.FunctionComponent = () => (
|
|
4
|
+
<div className="truncate-example-resize">
|
|
5
|
+
<Truncate content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'} position={'start'} />
|
|
6
|
+
</div>
|
|
7
|
+
);
|