Skip to content

Commit bfc320c

Browse files
authored
refactor(TextDirectionContext): rewrite in typescript (#18752)
1 parent b1fc4fc commit bfc320c

File tree

7 files changed

+78
-69
lines changed

7 files changed

+78
-69
lines changed

packages/react/src/components/Text/Text.stories.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ export const SetTextDirection = () => {
7777
}
7878
return 'auto';
7979
}}>
80+
{/* // TODO: These radio buttons don't work. */}
8081
<RadioButtonGroup
8182
legendText={legendText}
8283
name="radio-button-group"
@@ -123,6 +124,7 @@ export const UsageExamples = () => {
123124
<Text>{rtlText}</Text>
124125
</Button>
125126
<div style={{ width: 400 }}>
127+
{/* // TODO: This dropdown doesn't work. */}
126128
<Dropdown
127129
id="default"
128130
titleText="Using <Text> with `itemToElement`"

packages/react/src/components/Text/Text.tsx

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,46 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
77

88
import PropTypes from 'prop-types';
9-
import React, { ReactNode, useContext } from 'react';
10-
import { TextDir } from './TextDirection';
11-
import { TextDirectionContext } from './TextDirectionContext';
9+
import React, {
10+
Children,
11+
forwardRef,
12+
useContext,
13+
type ElementType,
14+
type FC,
15+
type ReactElement,
16+
type ReactNode,
17+
} from 'react';
1218
import {
1319
PolymorphicComponentPropWithRef,
1420
PolymorphicRef,
1521
} from '../../internal/PolymorphicProps';
22+
import { TextDirectionContext, type TextDir } from '.';
1623

1724
export interface TextBaseProps {
18-
dir?: TextDir | undefined;
25+
dir?: TextDir;
1926
children?: ReactNode;
2027
}
2128

22-
export type TextProps<T extends React.ElementType> =
23-
PolymorphicComponentPropWithRef<T, TextBaseProps>;
29+
export type TextProps<T extends ElementType> = PolymorphicComponentPropWithRef<
30+
T,
31+
TextBaseProps
32+
>;
2433

25-
type TextComponent = <T extends React.ElementType = 'span'>(
26-
props: TextProps<T>
27-
) => React.ReactElement | any;
34+
type TextComponent = <T extends ElementType = 'span'>(
35+
props: TextProps<T> & { ref?: PolymorphicRef<T> }
36+
) => ReactElement | null;
2837

29-
const Text: TextComponent = React.forwardRef(
30-
<T extends React.ElementType = 'span'>(
38+
export const Text = forwardRef(
39+
<T extends ElementType = 'span'>(
3140
{ as, children, dir = 'auto', ...rest }: TextProps<T>,
3241
ref?: PolymorphicRef<T>
3342
) => {
34-
// TODO: Update with context typing once its been converted to TS
35-
const context = useContext<any>(TextDirectionContext);
43+
const context = useContext(TextDirectionContext);
3644
const textProps: { dir?: TextDir } = {};
3745
const BaseComponent = as ?? 'span';
3846
const value = {
@@ -71,9 +79,9 @@ const Text: TextComponent = React.forwardRef(
7179
</TextDirectionContext.Provider>
7280
);
7381
}
74-
);
82+
) as TextComponent;
7583

76-
(Text as React.FC).propTypes = {
84+
(Text as FC).propTypes = {
7785
/**
7886
* Provide a custom element type used to render the outermost node
7987
*/
@@ -95,12 +103,12 @@ const Text: TextComponent = React.forwardRef(
95103
dir: PropTypes.oneOf(['ltr', 'rtl', 'auto']),
96104
};
97105

98-
function getTextFromChildren(children: ReactNode) {
106+
const getTextFromChildren = (children: ReactNode) => {
99107
if (typeof children === 'string') {
100108
return children;
101109
}
102110

103-
const text = React.Children.map(children, (child) => {
111+
const text = Children.map(children, (child) => {
104112
if (typeof child === 'string') {
105113
return child;
106114
}
@@ -114,6 +122,4 @@ function getTextFromChildren(children: ReactNode) {
114122
}
115123

116124
return text;
117-
}
118-
119-
export { Text };
125+
};

packages/react/src/components/Text/TextDirection.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
77

88
import PropTypes from 'prop-types';
99
import React, { ReactNode, useEffect, useMemo, useRef } from 'react';
10-
import { TextDirectionContext } from './TextDirectionContext';
11-
12-
export type TextDir = 'ltr' | 'rtl' | 'auto' | string;
13-
export type GetTextDirection = (text: string | string[] | undefined) => TextDir;
10+
import {
11+
TextDirectionContext,
12+
type GetTextDirection,
13+
type TextDir,
14+
type TextDirectionContextType,
15+
} from '.';
1416

1517
export interface TextDirectionProps {
16-
children: ReactNode | undefined;
18+
children: ReactNode;
1719
dir?: TextDir;
1820
getTextDirection?: GetTextDirection;
1921
}
2022

21-
function TextDirection({
23+
export const TextDirection = ({
2224
children,
2325
dir = 'auto',
2426
getTextDirection,
25-
}: TextDirectionProps) {
27+
}: TextDirectionProps) => {
2628
const savedCallback = useRef(getTextDirection);
27-
const value = useMemo(() => {
29+
const value = useMemo<TextDirectionContextType>(() => {
2830
return {
2931
direction: dir,
3032
getTextDirection: savedCallback,
@@ -33,14 +35,16 @@ function TextDirection({
3335

3436
useEffect(() => {
3537
savedCallback.current = getTextDirection;
38+
// TODO: Is this `useEffect` supposed to have a dependency on
39+
// `getTextDirection`?
3640
});
3741

3842
return (
3943
<TextDirectionContext.Provider value={value}>
4044
{children}
4145
</TextDirectionContext.Provider>
4246
);
43-
}
47+
};
4448

4549
TextDirection.propTypes = {
4650
/**
@@ -60,5 +64,3 @@ TextDirection.propTypes = {
6064
*/
6165
getTextDirection: PropTypes.func,
6266
};
63-
64-
export { TextDirection };

packages/react/src/components/Text/TextDirectionContext.js

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright IBM Corp. 2016, 2025
3+
*
4+
* This source code is licensed under the Apache-2.0 license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import { createContext, type MutableRefObject } from 'react';
9+
10+
export type TextDir = 'ltr' | 'rtl' | 'auto' | string;
11+
12+
export type GetTextDirection = (text: string | string[] | undefined) => TextDir;
13+
14+
export interface TextDirectionContextType {
15+
direction: TextDir;
16+
getTextDirection: MutableRefObject<GetTextDirection | undefined>;
17+
}
18+
19+
export const TextDirectionContext = createContext<TextDirectionContextType>({
20+
direction: 'auto',
21+
getTextDirection: { current: undefined },
22+
});
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import React from 'react';
9-
import { Text, TextProps } from './Text';
8+
import React, { type ElementType } from 'react';
9+
import { Text, TextProps } from '.';
1010

1111
/**
1212
* Create a text component wrapper for a given text node type. Useful for
1313
* returning a `Text` component for a text node like a `<label>`.
1414
* @param {string} element
1515
* @param {string} displayName
1616
*/
17-
export function createTextComponent(
18-
element: React.ElementType,
17+
export const createTextComponent = (
18+
element: ElementType,
1919
displayName: string
20-
) {
21-
function TextWrapper(props: TextProps<React.ElementType>) {
20+
) => {
21+
const TextWrapper = (props: TextProps<ElementType>) => {
2222
return <Text as={element} {...props} />;
23-
}
23+
};
2424

2525
if (__DEV__) {
2626
TextWrapper.displayName = displayName;
2727
}
2828

2929
return TextWrapper;
30-
}
30+
};
Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,15 @@
11
/**
2-
* Copyright IBM Corp. 2016, 2023
2+
* Copyright IBM Corp. 2016, 2025
33
*
44
* This source code is licensed under the Apache-2.0 license found in the
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import {
9-
TextDirection,
10-
TextDirectionProps,
11-
GetTextDirection,
12-
TextDir,
13-
} from './TextDirection';
14-
import { Text, TextBaseProps, TextProps } from './Text';
158
import { createTextComponent } from './createTextComponent';
169

17-
export { TextDirection, Text };
18-
export type {
19-
TextBaseProps,
20-
TextProps,
21-
TextDirectionProps,
22-
GetTextDirection,
23-
TextDir,
24-
};
10+
export * from './Text';
11+
export * from './TextDirection';
12+
export * from './TextDirectionContext';
2513

2614
export const Label = createTextComponent('label', 'Label');
2715
export const Legend = createTextComponent('legend', 'Legend');

0 commit comments

Comments
 (0)