Skip to content

Commit 19ed2ec

Browse files
feat(Text): replace with UI5 Web Component (#5988)
BREAKING CHANGE: the `Text` component has been replaced with the `ui5-text` web component, please visit our [Migration Guide](https://sap.github.io/ui5-webcomponents-react/main/?path=/docs/migration-guide--docs) for more details. BREAKING CHANGE: **ExpandableText**: the inherited props `hyphenated` and `emptyIndicator` from the `Text` have been removed. BREAKING CHANGE: **ExpandableText**: the `portalContainer` prop has been removed as it's not needed anymore --------- Co-authored-by: Lukas Harbarth <[email protected]>
1 parent f5f9101 commit 19ed2ec

38 files changed

+200
-388
lines changed

docs/MigrationGuide.mdx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,35 @@ Please use the following components instead:
306306

307307
Also, the namings of internal `data-component-name` attributes have been adjusted accordingly. E.g. `data-component-name="DynamicPageTitleSubHeader"` has been renamed to `data-component-name="ObjectPageTitleSubHeader"`
308308

309+
### Text
310+
311+
The `Text` component has been replaced with the `ui5-text` Web Component.
312+
313+
The following props have been removed:
314+
315+
- `wrapping`
316+
Can be achieved via the `maxLines` property. If `maxLines` is set to `1`, the text will not wrap, otherwise it will wrap.
317+
- `renderWhitespace`
318+
Can be achieved by adding `white-space: pre-wrap;` via inline styles or `className` to the `Text` component.
319+
- `hyphenated` and `emptyIndicator`
320+
These props are currently not supported by the new `ui5-text` component. You can follow this [feature request](https://github.com/SAP/ui5-webcomponents/issues/9244) for updates.
321+
322+
```tsx
323+
// v1
324+
import { Text } from '@ui5/webcomponents-react';
325+
326+
function MyComponent() {
327+
return <Text wrapping={false}>Lorem Impsum</Text>;
328+
}
329+
330+
// v2
331+
import { Text } from '@ui5/webcomponents-react';
332+
333+
function MyComponent() {
334+
return <Text maxLines={1}>Lorem Impsum</Text>;
335+
}
336+
```
337+
309338
## Components with API Changes
310339

311340
### ActionSheet
@@ -338,6 +367,12 @@ function MyComponent() {
338367
}
339368
```
340369

370+
### Expandable Text
371+
372+
The prop `portalContainer` has been removed as it is no longer needed due to the [popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) which is now used in the UI5 Web Components.
373+
As the underlying `Text` component has been replaced with the UI5 Web Component, some inherited props `hyphenated` and `emptyIndicator` from the `Text` component have been removed.
374+
You can follow this [feature request](https://github.com/SAP/ui5-webcomponents/issues/9244) for updates.
375+
341376
## Enum Changes
342377

343378
For a better alignment with the UI5 Web Components, the following enums have been renamed:

packages/main/src/components/AnalyticalCardHeader/AnalyticalCardHeader.cy.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { ThemingParameters } from '@ui5/webcomponents-react-base';
33
import { DeviationIndicator, ValueColor } from '../../enums';
44
import type { CardPropTypes } from '../../webComponents/Card/index.js';
55
import { Card } from '../../webComponents/Card/index.js';
6+
import { Text } from '../../webComponents/Text/index.js';
67
import { NumericSideIndicator } from '../NumericSideIndicator';
7-
import { Text } from '../Text';
88
import type { AnalyticalCardHeaderPropTypes } from './index';
99
import { AnalyticalCardHeader } from './index';
1010
import { cypressPassThroughTestsFactory } from '@/cypress/support/utils';

packages/main/src/components/AnalyticalTable/AnalyticalTable.stories.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@ import {
1515
FlexBoxJustifyContent,
1616
TextAlign
1717
} from '../../enums/index.js';
18-
import { Button, MultiComboBox, MultiComboBoxItem, Option, Select, Tag } from '../../webComponents/index.js';
18+
import { Button, MultiComboBox, MultiComboBoxItem, Option, Select, Tag, Text } from '../../webComponents/index.js';
1919
import { FlexBox } from '../FlexBox';
20-
import { Text } from '../Text';
2120
import { AnalyticalTable } from './index.js';
2221

2322
const meta = {

packages/main/src/components/AnalyticalTable/AnalyticalTableHooks.stories.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import type { Meta, StoryObj } from '@storybook/react';
66
import InputType from '@ui5/webcomponents/dist/types/InputType.js';
77
import React, { useReducer, useState } from 'react';
88
import { AnalyticalTableSelectionMode, FlexBoxAlignItems, FlexBoxDirection } from '../../enums';
9-
import { Button, CheckBox, Input, Label, ToggleButton } from '../../webComponents';
9+
import { Button, CheckBox, Input, Label, ToggleButton, Text } from '../../webComponents';
1010
import { FlexBox } from '../FlexBox';
11-
import { Text } from '../Text';
1211
import meta from './AnalyticalTable.stories';
1312
import * as AnalyticalTableHooks from './pluginHooks/AnalyticalTableHooks';
1413
import { AnalyticalTable } from './index';

packages/main/src/components/AnalyticalTable/ColumnHeader/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type {
1515
} from 'react';
1616
import { useRef, useState } from 'react';
1717
import { Icon } from '../../../webComponents/Icon/index.js';
18-
import { Text } from '../../Text/index.js';
18+
import { Text } from '../../../webComponents/Text/index.js';
1919
import type { ColumnType } from '../types/ColumnType.js';
2020
import type { DivWithCustomScrollProp } from '../types/index.js';
2121
import { classNames, styleData } from './ColumnHeader.module.css.js';
@@ -200,7 +200,7 @@ export const ColumnHeader = (props: ColumnHeaderProps) => {
200200
<div className={classNames.header} data-h-align={column.hAlign}>
201201
<Text
202202
title={tooltip}
203-
wrapping={false}
203+
maxLines={1}
204204
style={textStyle}
205205
className={clsx(
206206
classNames.text,

packages/main/src/components/AnalyticalTable/defaults/Column/PopIn.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useStylesheet } from '@ui5/webcomponents-react-base';
22
import { makeRenderer } from 'react-table';
33
import { FlexBoxAlignItems, FlexBoxDirection, FlexBoxWrap } from '../../../../enums/index.js';
4+
import { Text } from '../../../../webComponents/Text/index.js';
45
import { FlexBox } from '../../../FlexBox/index.js';
5-
import { Text } from '../../../Text/index.js';
66
import { classNames, styleData } from './PopIn.module.css.js';
77

88
export const PopIn = (instance) => {
@@ -43,15 +43,15 @@ export const PopIn = (instance) => {
4343
const cell = item.column.Cell;
4444
if (typeof cell === 'string') {
4545
return (
46-
<Text wrapping={false} title={cell}>
46+
<Text maxLines={1} title={cell}>
4747
{cell}
4848
</Text>
4949
);
5050
}
5151
return makeRenderer({ ...instance, ...popInInstanceProps, isPopIn: true }, item.column)(item.column.Cell);
5252
}
5353
return popInInstanceProps?.value ? (
54-
<Text wrapping={false} title={popInInstanceProps.value}>
54+
<Text maxLines={1} title={popInInstanceProps.value}>
5555
{popInInstanceProps.value}
5656
</Text>
5757
) : null;

packages/main/src/components/AnalyticalTable/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ import {
4848
SELECT_PRESS_SPACE,
4949
UNSELECT_PRESS_SPACE
5050
} from '../../i18n/i18n-defaults.js';
51+
import { Text } from '../../webComponents/Text/index.js';
5152
import { FlexBox } from '../FlexBox/index.js';
52-
import { Text } from '../Text/index.js';
5353
import { classNames, styleData } from './AnalyticalTable.module.css.js';
5454
import { ColumnHeaderContainer } from './ColumnHeader/ColumnHeaderContainer.js';
5555
import { DefaultColumn } from './defaults/Column/index.js';

packages/main/src/components/ExpandableText/ExpandableText.module.css

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
.expandableText {
2-
composes: text from '../Text/Text.module.css';
2+
font-family: var(--sapFontFamily);
3+
font-size: var(--sapFontSize);
4+
font-weight: normal;
5+
color: var(--sapTextColor);
6+
display: inline-block;
7+
box-sizing: border-box;
8+
white-space: pre-line;
9+
word-wrap: break-word;
10+
max-width: 100%;
311
}
412

513
.text {
614
display: inline;
715
}
816

17+
.renderWhitespace {
18+
white-space: pre-wrap;
19+
}
20+
921
.ellipsis {
1022
word-spacing: 0.125rem;
1123
}
@@ -17,4 +29,3 @@
1729
.popover::part(content) {
1830
padding: 1rem;
1931
}
20-

packages/main/src/components/ExpandableText/index.tsx

Lines changed: 38 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,16 @@
33
import LinkAccessibleRole from '@ui5/webcomponents/dist/types/LinkAccessibleRole.js';
44
import { useI18nBundle, useIsomorphicId, useStylesheet } from '@ui5/webcomponents-react-base';
55
import { clsx } from 'clsx';
6-
import { forwardRef, useEffect, useRef, useState } from 'react';
7-
import { createPortal } from 'react-dom';
6+
import { forwardRef, useState } from 'react';
87
import { CLOSE_POPOVER, SHOW_FULL_TEXT, SHOW_LESS, SHOW_MORE } from '../../i18n/i18n-defaults.js';
9-
import { useCanRenderPortal } from '../../internal/ssr.js';
10-
import { getUi5TagWithSuffix } from '../../internal/utils.js';
118
import type { CommonProps } from '../../types/index.js';
12-
import type { LinkDomRef } from '../../webComponents/index.js';
139
import { Link } from '../../webComponents/index.js';
1410
import { ResponsivePopover } from '../../webComponents/ResponsivePopover/index.js';
15-
import type { TextPropTypes } from '../Text/index.js';
16-
import { Text } from '../Text/index.js';
11+
import type { TextPropTypes } from '../../webComponents/Text/index.js';
12+
import { Text } from '../../webComponents/Text/index.js';
1713
import { classNames, styleData } from './ExpandableText.module.css.js';
1814

19-
export interface ExpandableTextPropTypes
20-
extends Omit<TextPropTypes, 'maxLines' | 'wrapping' | 'children'>,
21-
CommonProps {
15+
export interface ExpandableTextPropTypes extends Omit<TextPropTypes, 'maxLines' | 'children'>, CommonProps {
2216
/**
2317
* Determines the text to be displayed.
2418
*/
@@ -34,13 +28,9 @@ export interface ExpandableTextPropTypes
3428
*/
3529
showOverflowInPopover?: boolean;
3630
/**
37-
* Defines where modals are rendered into via `React.createPortal`.
38-
*
39-
* You can find out more about this [here](https://sap.github.io/ui5-webcomponents-react/?path=/docs/knowledge-base-working-with-portals--page).
40-
*
41-
* @default document.body
31+
* Defines how white-space inside <code>Text</code> is handled. If set to true, sequences of white space are preserved.
4232
*/
43-
portalContainer?: Element;
33+
renderWhitespace?: boolean;
4434
}
4535

4636
/**
@@ -51,23 +41,12 @@ export interface ExpandableTextPropTypes
5141
* @since 1.23.0
5242
*/
5343
const ExpandableText = forwardRef<HTMLSpanElement, ExpandableTextPropTypes>((props, ref) => {
54-
const {
55-
children,
56-
emptyIndicator,
57-
renderWhitespace,
58-
hyphenated,
59-
showOverflowInPopover,
60-
maxCharacters = 100,
61-
portalContainer,
62-
className,
63-
...rest
64-
} = props;
44+
const { children, showOverflowInPopover, maxCharacters = 100, renderWhitespace, className, ...rest } = props;
6545

6646
useStylesheet(styleData, ExpandableText.displayName);
6747

6848
const [collapsed, setCollapsed] = useState(true);
6949
const [popoverOpen, setPopoverOpen] = useState(false);
70-
const linkRef = useRef<LinkDomRef>(null);
7150
const uniqueId = useIsomorphicId();
7251
const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
7352
const trimmedChildren = renderWhitespace ? children : children?.replace(/\s+/g, ' ').trim();
@@ -87,64 +66,39 @@ const ExpandableText = forwardRef<HTMLSpanElement, ExpandableTextPropTypes>((pro
8766
setPopoverOpen(false);
8867
};
8968

90-
useEffect(() => {
91-
const tagName = getUi5TagWithSuffix('ui5-link');
92-
void customElements.whenDefined(tagName).then(() => {
93-
if (linkRef.current) {
94-
if (showOverflowInPopover) {
95-
linkRef.current.accessibilityAttributes = { hasPopup: 'dialog' };
96-
} else {
97-
linkRef.current.accessibilityAttributes = { expanded: !collapsed };
98-
}
99-
}
100-
});
101-
}, [collapsed, showOverflowInPopover]);
102-
103-
const canRenderPortal = useCanRenderPortal();
104-
if (showOverflowInPopover && !canRenderPortal) {
105-
return null;
106-
}
10769
return (
108-
<span className={clsx(classNames.expandableText, className)} {...rest} ref={ref}>
109-
<Text
110-
emptyIndicator={emptyIndicator}
111-
renderWhitespace={renderWhitespace}
112-
hyphenated={hyphenated}
113-
className={classNames.text}
114-
>
115-
{strippedChildren}
116-
</Text>
117-
{isOverflow && (
118-
<>
119-
<span className={classNames.ellipsis}>{showOverflowInPopover || collapsed ? '… ' : ' '}</span>
120-
<Link
121-
accessibleName={
122-
showOverflowInPopover
123-
? collapsed
124-
? i18nBundle.getText(SHOW_FULL_TEXT)
125-
: i18nBundle.getText(CLOSE_POPOVER)
126-
: undefined
127-
}
128-
accessibleRole={LinkAccessibleRole.Button}
129-
onClick={handleClick}
130-
ref={linkRef}
131-
id={`${uniqueId}-link`}
132-
>
133-
{collapsed ? i18nBundle.getText(SHOW_MORE) : i18nBundle.getText(SHOW_LESS)}
134-
</Link>
135-
</>
136-
)}
137-
{showOverflowInPopover &&
138-
popoverOpen &&
139-
createPortal(
140-
<ResponsivePopover opener={`${uniqueId}-link`} open onClose={closePopover} className={classNames.popover}>
141-
<Text renderWhitespace={renderWhitespace} hyphenated={hyphenated} className={classNames.text}>
142-
{children}
143-
</Text>
144-
</ResponsivePopover>,
145-
portalContainer ?? document.body
70+
<>
71+
<span className={clsx(classNames.expandableText, className)} {...rest} ref={ref}>
72+
<Text className={clsx(classNames.text, renderWhitespace && classNames.renderWhitespace)}>
73+
{strippedChildren}
74+
</Text>
75+
{isOverflow && (
76+
<>
77+
<span className={classNames.ellipsis}>{showOverflowInPopover || collapsed ? '… ' : ' '}</span>
78+
<Link
79+
accessibleName={
80+
showOverflowInPopover
81+
? collapsed
82+
? i18nBundle.getText(SHOW_FULL_TEXT)
83+
: i18nBundle.getText(CLOSE_POPOVER)
84+
: undefined
85+
}
86+
accessibleRole={LinkAccessibleRole.Button}
87+
accessibilityAttributes={showOverflowInPopover ? { hasPopup: 'dialog' } : { expanded: !collapsed }}
88+
onClick={handleClick}
89+
id={`${uniqueId}-link`}
90+
>
91+
{collapsed ? i18nBundle.getText(SHOW_MORE) : i18nBundle.getText(SHOW_LESS)}
92+
</Link>
93+
</>
14694
)}
147-
</span>
95+
</span>
96+
{showOverflowInPopover && popoverOpen && (
97+
<ResponsivePopover opener={`${uniqueId}-link`} open onClose={closePopover} className={classNames.popover}>
98+
<Text className={clsx(classNames.text, renderWhitespace && classNames.renderWhitespace)}>{children}</Text>
99+
</ResponsivePopover>
100+
)}
101+
</>
148102
);
149103
});
150104

packages/main/src/components/FilterBar/FilterBar.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import {
2222
Title,
2323
Token
2424
} from '../../webComponents/index.js';
25+
import { Text } from '../../webComponents/Text/index.js';
2526
import { FilterGroupItem } from '../FilterGroupItem/index.js';
2627
import { FlexBox } from '../FlexBox/index.js';
27-
import { Text } from '../Text/index.js';
2828
import { VariantManagement } from '../VariantManagement/index.js';
2929
import { VariantItem } from '../VariantManagement/VariantItem.js';
3030
import { FilterBar } from './index.js';

packages/main/src/components/Loader/Loader.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { FlexBoxDirection, LoaderType } from '../../enums/index.js';
66
import { Card } from '../../webComponents/Card/index.js';
77
import { CardHeader } from '../../webComponents/CardHeader/index.js';
88
import { Icon } from '../../webComponents/Icon/index.js';
9+
import { Text } from '../../webComponents/Text/index.js';
910
import { FlexBox } from '../FlexBox/index.js';
10-
import { Text } from '../Text/index.js';
1111
import { Loader } from './index.js';
1212

1313
const meta = {

packages/main/src/components/MessageBox/index.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ import {
2828
YES
2929
} from '../../i18n/i18n-defaults.js';
3030
import type { ButtonPropTypes, DialogDomRef, DialogPropTypes } from '../../webComponents/index.js';
31-
import { Button, Dialog, Icon, Title } from '../../webComponents/index.js';
32-
import { Text } from '../Text/index.js';
31+
import { Button, Dialog, Icon, Text, Title } from '../../webComponents/index.js';
3332
import { classNames, styleData } from './MessageBox.module.css.js';
3433

3534
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents

packages/main/src/components/MessageViewButton/MessageViewButton.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Meta, StoryObj } from '@storybook/react';
22
import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
3+
import { Text } from '../../webComponents/Text/index.js';
34
import { FlexBox } from '../FlexBox/index.js';
4-
import { Text } from '../Text/index.js';
55
import { MessageViewButton } from './index.js';
66

77
const meta = {

packages/main/src/components/NumericSideIndicator/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { clsx } from 'clsx';
55
import { forwardRef } from 'react';
66
import { ValueColor } from '../../enums/index.js';
77
import type { CommonProps } from '../../types/index.js';
8-
import { Text } from '../Text/index.js';
8+
import { Text } from '../../webComponents/Text/index.js';
99
import { classNames, styleData } from './NumericSideIndicator.module.css.js';
1010

1111
export interface NumericSideIndicatorPropTypes extends CommonProps {

packages/main/src/components/ResponsiveGridLayout/ResponsiveGridLayout.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { StoryObj, Meta } from '@storybook/react';
22
import { ThemingParameters } from '@ui5/webcomponents-react-base';
3-
import { Text } from '../Text/index.js';
3+
import { Text } from '../../webComponents/Text/index.js';
44
import { ResponsiveGridLayout } from './index.js';
55

66
const meta = {

packages/main/src/components/SelectDialog/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import type {
2424
ListItemStandardDomRef
2525
} from '../../webComponents/index.js';
2626
import { Button, Dialog, Icon, Input, List, Title } from '../../webComponents/index.js';
27-
import { Text } from '../Text/index.js';
27+
import { Text } from '../../webComponents/Text/index.js';
2828
import { Toolbar } from '../Toolbar/index.js';
2929
import { classNames, styleData } from './SelectDialog.module.css.js';
3030

0 commit comments

Comments
 (0)