Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/lib/components/Button/Button.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getRootSizeClassName } from '../_helpers/getRootSizeClassName';
import { resolveContextOrProp } from '../_helpers/resolveContextOrProp';
import { transferProps } from '../_helpers/transferProps';
import { ButtonGroupContext } from '../ButtonGroup';
import { InputGroupContext } from '../InputGroup/InputGroupContext';
import getRootLabelVisibilityClassName from './helpers/getRootLabelVisibilityClassName';
import getRootPriorityClassName from './helpers/getRootPriorityClassName';
import styles from './Button.scss';
Expand All @@ -28,8 +29,14 @@ export const Button = React.forwardRef((props, ref) => {
color,
...restProps
} = props;
const buttonGroupContext = useContext(ButtonGroupContext);
const inputGroupContext = useContext(InputGroupContext);

const context = useContext(ButtonGroupContext);
if (buttonGroupContext && inputGroupContext) {
throw new Error('Button cannot be placed both in `ButtonGroup` and `InputGroup`.');
}

const primaryContext = buttonGroupContext ?? inputGroupContext;

return (
/* No worries, `type` is always assigned correctly through props. */
Expand All @@ -39,20 +46,21 @@ export const Button = React.forwardRef((props, ref) => {
className={classNames(
styles.root,
getRootPriorityClassName(
resolveContextOrProp(context && context.priority, priority),
resolveContextOrProp(buttonGroupContext && buttonGroupContext.priority, priority),
styles,
),
getRootColorClassName(color, styles),
getRootSizeClassName(
resolveContextOrProp(context && context.size, size),
resolveContextOrProp(primaryContext && primaryContext.size, size),
styles,
),
getRootLabelVisibilityClassName(labelVisibility, styles),
resolveContextOrProp(context && context.block, block) && styles.isRootBlock,
context && styles.isRootGrouped,
resolveContextOrProp(buttonGroupContext && buttonGroupContext.block, block) && styles.isRootBlock,
buttonGroupContext && styles.isRootInButtonGroup,
inputGroupContext && styles.isRootInInputGroup,
feedbackIcon && styles.hasRootFeedback,
)}
disabled={resolveContextOrProp(context && context.disabled, disabled) || !!feedbackIcon}
disabled={resolveContextOrProp(buttonGroupContext && buttonGroupContext.disabled, disabled) || !!feedbackIcon}
id={id}
ref={ref}
>
Expand Down Expand Up @@ -171,8 +179,8 @@ Button.propTypes = {
/**
* Size of the button.
*
* Ignored if the component is rendered within `ButtonGroup` component
* as the value is inherited in such case.
* Ignored if the component is rendered within `ButtonGroup` or `InputGroup` component as the value is inherited in
* such case.
*/
size: PropTypes.oneOf(['small', 'medium', 'large']),
/**
Expand Down
9 changes: 6 additions & 3 deletions src/lib/components/Button/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@
color: transparent;
}

.isRootGrouped {
.isRootInButtonGroup,
.isRootInInputGroup {
z-index: map.get(settings.$group-z-indexes, button);

&:not(:first-child) {
Expand All @@ -96,8 +97,10 @@
}
}

.isRootGrouped .startCorner,
.isRootGrouped .endCorner {
.isRootInButtonGroup .startCorner,
.isRootInInputGroup .startCorner,
.isRootInButtonGroup .endCorner,
.isRootInInputGroup .endCorner {
z-index: map.get(settings.$group-z-indexes, button-overflowing-elements);
}

Expand Down
10 changes: 5 additions & 5 deletions src/lib/components/Button/_priorities.scss
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@
@include tools.button-color(flat, dark);
}

.isRootPriorityFilled.isRootGrouped:not(:first-child)::before,
.isRootPriorityFlat.isRootGrouped:not(:first-child)::before {
.isRootPriorityFilled.isRootInButtonGroup:not(:first-child)::before,
.isRootPriorityFlat.isRootInButtonGroup:not(:first-child)::before {
content: "";
position: absolute;
top: calc(-1 * #{theme.$border-width});
Expand All @@ -147,18 +147,18 @@
transform: translateX(calc(-0.5 * var(--rui-local-gap) - 50%));
}

.isRootPriorityFilled.isRootGrouped:not(:first-child) {
.isRootPriorityFilled.isRootInButtonGroup:not(:first-child) {
--rui-local-gap: #{theme.$group-filled-gap};
--rui-local-separator-width: #{theme.$group-filled-separator-width};
--rui-local-separator-color: #{theme.$group-filled-separator-color};
}

.isRootPriorityFlat.isRootGrouped:not(:first-child) {
.isRootPriorityFlat.isRootInButtonGroup:not(:first-child) {
--rui-local-gap: #{theme.$group-flat-gap};
--rui-local-separator-width: #{theme.$group-flat-separator-width};
--rui-local-separator-color: #{theme.$group-flat-separator-color};
}

.isRootPriorityOutline.isRootGrouped:not(:first-child) {
.isRootPriorityOutline.isRootInButtonGroup:not(:first-child) {
--rui-local-gap: #{theme.$group-outline-gap};
}
6 changes: 6 additions & 0 deletions src/lib/components/ButtonGroup/__tests__/ButtonGroup.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '@testing-library/react';
import { blockPropTest } from '../../../../../tests/propTests/blockPropTest';
import { childrenEmptyPropTest } from '../../../../../tests/propTests/childrenEmptyPropTest';
import { idPropTest } from '../../../../../tests/propTests/idPropTest';
import { Button } from '../../Button';
import { ButtonGroup } from '../ButtonGroup';

Expand All @@ -16,6 +17,11 @@ describe('rendering', () => {
it.each([
...blockPropTest,
...childrenEmptyPropTest,
...idPropTest,
[
{},
(rootElement) => expect(within(rootElement).getByRole('button')).toHaveClass('isRootInButtonGroup'),
],
[
{ children: <Button label="label text" /> },
(rootElement) => expect(within(rootElement).getByText('label text')),
Expand Down
5 changes: 5 additions & 0 deletions src/lib/components/FormLayout/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
ToolbarItem,
FormLayout,
FormLayoutCustomField,
InputGroup,
} from '../..'

## Basic Usage
Expand Down Expand Up @@ -441,6 +442,10 @@ This is a demo of all components supported by FormLayout.
options={options}
value={fruit}
/>
<InputGroup label="Promo code">
<TextField label="Promo code" />
<Button label="Submit" />
</InputGroup>
</FormLayout>
</div>
)
Expand Down
34 changes: 25 additions & 9 deletions src/lib/components/FormLayout/__tests__/FormLayout.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import {
within,
} from '@testing-library/react';
import { childrenEmptyPropTest } from '../../../../../tests/propTests/childrenEmptyPropTest';
import { idPropTest } from '../../../../../tests/propTests/idPropTest';
import { Button } from '../../Button';
import { CheckboxField } from '../../CheckboxField';
import { InputGroup } from '../../InputGroup';
import { Radio } from '../../Radio';
import { SelectField } from '../../SelectField';
import { TextArea } from '../../TextArea';
Expand All @@ -14,7 +17,7 @@ import { FormLayout } from '../FormLayout';
import { FormLayoutCustomField } from '../FormLayoutCustomField';

const defaultProps = {
children: <FormLayoutCustomField id="nested-id">content</FormLayoutCustomField>,
children: <FormLayoutCustomField id="custom-field-id">content</FormLayoutCustomField>,
};

describe('rendering', () => {
Expand All @@ -36,18 +39,31 @@ describe('rendering', () => {
(rootElement) => expect(rootElement).not.toHaveClass('isRootAutoWidth'),
],
...childrenEmptyPropTest,
...idPropTest,
[
{ children: <FormLayoutCustomField>other content text</FormLayoutCustomField> },
(rootElement) => expect(within(rootElement).getByText('other content text')),
],
[
{ children: <CheckboxField label="label" /> },
(rootElement) => expect(within(rootElement).getByRole('checkbox')),
(rootElement) => expect(within(rootElement).getByRole('checkbox').closest('label')).toHaveClass('isRootInFormLayout'),
],
[
{
children: (
<InputGroup id="input-group-id" label="input group">
<TextField key="text field" label="text field" />
<Button key="button" label="button" />
</InputGroup>
),
},
(rootElement) => expect(within(rootElement).getByTestId('input-group-id')).toHaveClass('isRootInFormLayout'),
],
[
{
children: (
<Radio
id="radio-id"
label="label"
options={[{
label: 'label',
Expand All @@ -56,7 +72,7 @@ describe('rendering', () => {
/>
),
},
(rootElement) => expect(within(rootElement).getByRole('radio')),
(rootElement) => expect(within(rootElement).getByTestId('radio-id')).toHaveClass('isRootInFormLayout'),
],
[
{
Expand All @@ -70,32 +86,32 @@ describe('rendering', () => {
/>
),
},
(rootElement) => expect(within(rootElement).getByRole('combobox')),
(rootElement) => expect(within(rootElement).getByRole('combobox').closest('label')).toHaveClass('isRootInFormLayout'),
],
[
{ children: <TextArea label="label" /> },
(rootElement) => expect(within(rootElement).getByRole('textbox')),
(rootElement) => expect(within(rootElement).getByRole('textbox').closest('label')).toHaveClass('isRootInFormLayout'),
],
[
{ children: <TextField label="label" /> },
(rootElement) => expect(within(rootElement).getByRole('textbox')),
(rootElement) => expect(within(rootElement).getByRole('textbox').closest('label')).toHaveClass('isRootInFormLayout'),
],
[
{ children: <Toggle label="label" /> },
(rootElement) => expect(within(rootElement).getByRole('checkbox')),
(rootElement) => expect(within(rootElement).getByRole('checkbox').closest('label')).toHaveClass('isRootInFormLayout'),
],
[
{ fieldLayout: 'horizontal' },
(rootElement) => {
expect(rootElement).toHaveClass('isRootFieldLayoutHorizontal');
expect(within(rootElement).getByTestId('nested-id')).toHaveClass('isRootLayoutHorizontal');
expect(within(rootElement).getByTestId('custom-field-id')).toHaveClass('isRootLayoutHorizontal');
},
],
[
{ fieldLayout: 'vertical' },
(rootElement) => {
expect(rootElement).toHaveClass('isRootFieldLayoutVertical');
expect(within(rootElement).getByTestId('nested-id')).toHaveClass('isRootLayoutVertical');
expect(within(rootElement).getByTestId('custom-field-id')).toHaveClass('isRootLayoutVertical');
},
],
[
Expand Down
Loading