Skip to content

Commit

Permalink
feat(react): add support for layout and text direction (#9013)
Browse files Browse the repository at this point in the history
* feat(react): add support for layout and text direction

* refactor(react): update RadioButton to use Text

* feat(react): add text and layout dir components

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
joshblack and kodiakhq[bot] authored Aug 12, 2021
1 parent 7c9adb6 commit 59604a5
Show file tree
Hide file tree
Showing 17 changed files with 655 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -591,11 +591,16 @@ exports[`DataTable selection -- radio buttons should render 1`] = `
<span
className="bx--radio-button__appearance"
/>
<span
<Text
className="bx--visually-hidden"
>
Select row
</span>
<span
className="bx--visually-hidden"
dir="auto"
>
Select row
</span>
</Text>
</label>
</div>
</RadioButton>
Expand Down Expand Up @@ -677,11 +682,16 @@ exports[`DataTable selection -- radio buttons should render 1`] = `
<span
className="bx--radio-button__appearance"
/>
<span
<Text
className="bx--visually-hidden"
>
Select row
</span>
<span
className="bx--visually-hidden"
dir="auto"
>
Select row
</span>
</Text>
</label>
</div>
</RadioButton>
Expand Down Expand Up @@ -763,11 +773,16 @@ exports[`DataTable selection -- radio buttons should render 1`] = `
<span
className="bx--radio-button__appearance"
/>
<span
<Text
className="bx--visually-hidden"
>
Select row
</span>
<span
className="bx--visually-hidden"
dir="auto"
>
Select row
</span>
</Text>
</label>
</div>
</RadioButton>
Expand Down
55 changes: 55 additions & 0 deletions packages/react/src/components/Layout/LayoutDirection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import PropTypes from 'prop-types';
import React from 'react';
import { LayoutDirectionContext } from './LayoutDirectionContext';

function LayoutDirection({
as: BaseComponent = 'div',
children,
dir,
...rest
}) {
const value = React.useMemo(() => {
return {
direction: dir,
};
}, [dir]);

return (
<LayoutDirectionContext.Provider value={value}>
<BaseComponent dir={dir} {...rest}>
{children}
</BaseComponent>
</LayoutDirectionContext.Provider>
);
}

LayoutDirection.propTypes = {
/**
* Customize the element type used to render the outermost node
*/
as: PropTypes.oneOfType([
PropTypes.func,
PropTypes.string,
PropTypes.elementType,
]),

/**
* Provide child elements or components to be rendered inside of this
* component
*/
children: PropTypes.node,

/**
* Specify the layout direction of this part of the page
*/
dir: PropTypes.oneOf(['ltr', 'rtl']).isRequired,
};

export { LayoutDirectionContext, LayoutDirection };
12 changes: 12 additions & 0 deletions packages/react/src/components/Layout/LayoutDirectionContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';

export const LayoutDirectionContext = React.createContext({
direction: 'ltr',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { render, screen } from '@testing-library/react';
import React from 'react';
import { LayoutDirection } from '../';

describe('LayoutDirection', () => {
it('should render its children in a node that has a `dir` attribute', () => {
render(
<LayoutDirection dir="rtl" data-testid="test">
<span>test</span>
</LayoutDirection>
);

const node = screen.getByTestId('test');
expect(node).toHaveAttribute('dir', 'rtl');
});

it('should support customizing the outermost node through the `as` prop', () => {
render(
<LayoutDirection as="section" data-testid="test" dir="rtl">
<span>test</span>
</LayoutDirection>
);

const node = screen.getByTestId('test');
expect(node.tagName).toBe('SECTION');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { render } from '@testing-library/react';
import React from 'react';
import { LayoutDirection, useLayoutDirection } from '../';

describe('useLayoutDirection', () => {
it('should provide a default value', () => {
const calls = [];

function TestComponent() {
const value = useLayoutDirection();
calls.push(value);
return null;
}

render(<TestComponent />);

expect(calls[0]).toEqual({
direction: 'ltr',
});
});

it('should provide the current direction from context', () => {
const calls = [];

function TestComponent() {
const value = useLayoutDirection();
calls.push(value);
return null;
}

render(
<LayoutDirection dir="rtl">
<TestComponent />
<LayoutDirection dir="ltr">
<TestComponent />
</LayoutDirection>
</LayoutDirection>
);

expect(calls).toEqual([
{
direction: 'rtl',
},
{
direction: 'ltr',
},
]);
});
});
9 changes: 9 additions & 0 deletions packages/react/src/components/Layout/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

export { LayoutDirection } from './LayoutDirection';
export { useLayoutDirection } from './useLayoutDirection';
16 changes: 16 additions & 0 deletions packages/react/src/components/Layout/useLayoutDirection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import { useContext } from 'react';
import { LayoutDirectionContext } from './LayoutDirectionContext';

/**
* Get access to the current layout direction in context
*/
export function useLayoutDirection() {
return useContext(LayoutDirectionContext);
}
3 changes: 2 additions & 1 deletion packages/react/src/components/RadioButton/RadioButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { warning } from '../../internal/warning';
import uid from '../../tools/uniqueId';
import { Text } from '../Text';

const { prefix } = settings;

Expand Down Expand Up @@ -133,7 +134,7 @@ class RadioButton extends React.Component {
/>
<label htmlFor={this.uid} className={`${prefix}--radio-button__label`}>
<span className={`${prefix}--radio-button__appearance`} />
{labelText && <span className={innerLabelClasses}>{labelText}</span>}
{labelText && <Text className={innerLabelClasses}>{labelText}</Text>}
</label>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React from 'react';
import classNames from 'classnames';
import { warning } from '../../internal/warning';
import { settings } from 'carbon-components';
import { Legend } from '../Text';

const { prefix } = settings;

Expand Down Expand Up @@ -148,7 +149,7 @@ export default class RadioButtonGroup extends React.Component {
<div className={`${prefix}--form-item`}>
<fieldset className={wrapperClasses} disabled={disabled}>
{legendText && (
<legend className={`${prefix}--label`}>{legendText}</legend>
<Legend className={`${prefix}--label`}>{legendText}</Legend>
)}
{this.getRadioButtons()}
</fieldset>
Expand Down
90 changes: 90 additions & 0 deletions packages/react/src/components/Text/Text-story.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Copyright IBM Corp. 2016, 2018
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import { LayoutDirection } from '../Layout';
import { TextDirection, Text } from '../Text';
import RadioButtonGroup from '../RadioButtonGroup';
import RadioButton from '../RadioButton';

export default {
title: 'Experimental/unstable_Text',
parameters: {
component: Text,
},
};

export const Default = () => (
<>
<p>
<Text>Hello world</Text>
</p>
<p>
<Text>لكن لا بد أن أوضح لك أن كل</Text>
</p>
</>
);

export const LayoutAndText = () => (
<LayoutDirection dir="ltr">
<p>
Ipsum ipsa repellat doloribus magni architecto totam Laborum maxime
ratione nobis voluptatibus facilis nostrum, necessitatibus magnam Maxime
esse consequatur nemo sit repellat Dignissimos rem nobis hic reprehenderit
ducimus? Fuga voluptatem?
</p>
<LayoutDirection dir="rtl">
<Text as="p">
المغلوطة حول استنكار النشوة وتمجيد الألم نشأت بالفعل، وسأعرض لك التفاصيل
لتكتشف حقيقة وأساس تلك السعادة البشرية، فلا أحد يرفض أو يكره أو يتجنب
الشعور بالسعادة، ولكن بفضل هؤ.
</Text>
</LayoutDirection>
<p>
Ipsum ipsa repellat doloribus magni architecto totam Laborum maxime
ratione nobis voluptatibus facilis nostrum, necessitatibus magnam Maxime
esse consequatur nemo sit repellat Dignissimos rem nobis hic reprehenderit
ducimus? Fuga voluptatem?
</p>
</LayoutDirection>
);

export const SetTextDirection = () => {
const legendText = 'הכותרת שלי!';

return (
<TextDirection
getTextDirection={(text) => {
if (text === legendText) {
return 'ltr';
}
return 'auto';
}}>
<RadioButtonGroup
legendText={legendText}
name="radio-button-group"
defaultSelected="radio-1"
style={{ maxWidth: '400px' }}>
<RadioButton
labelText="שלום עולם Option 1"
value="radio-1"
id="radio-1"
/>
<RadioButton
labelText="שלום עולם Option 2"
value="radio-1"
id="radio-1"
/>
<RadioButton
labelText="שלום עולם Option 3"
value="radio-1"
id="radio-1"
/>
</RadioButtonGroup>
</TextDirection>
);
};
Loading

0 comments on commit 59604a5

Please sign in to comment.