Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: radiobutton: multiple radio buttons on the same page doesnt work as intended #253

Merged
merged 2 commits into from
Jul 25, 2022
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
6 changes: 5 additions & 1 deletion src/components/Dialog/BaseDialog/BaseDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export const BaseDialog: FC<BaseDialogProps> = React.forwardRef(
actionButtonOneProps,
actionButtonTwoProps,
actionButtonThreeProps,
closeButtonProps,
closeIcon = IconName.mdiClose,
parent = document.body,
visible,
onClose,
Expand Down Expand Up @@ -106,8 +108,10 @@ export const BaseDialog: FC<BaseDialogProps> = React.forwardRef(
<NeutralButton {...actionButtonOneProps} />
)}
<NeutralButton
iconProps={{ path: IconName.mdiClose }}
ariaLabel={'Close'}
iconProps={{ path: closeIcon }}
onClick={onClose}
{...closeButtonProps}
/>
</span>
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/components/Dialog/BaseDialog/BaseDialog.types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React, { Ref } from 'react';
import { OcBaseProps } from '../../OcBase';
import { ButtonProps } from '../../Button';
import { IconName } from '../../Icon';

export type CloseButtonProps = Omit<ButtonProps, 'onClick' | 'icon'>;

type EventType =
| React.KeyboardEvent<HTMLDivElement>
Expand All @@ -22,6 +25,14 @@ export interface BaseDialogProps
* Props for the third header action button
*/
actionButtonThreeProps?: ButtonProps;
/**
* Close button extra props
*/
closeButtonProps?: CloseButtonProps;
/**
* Close icon name
*/
closeIcon?: IconName;
/**
* Dialog is visible or not
*/
Expand Down
4 changes: 4 additions & 0 deletions src/components/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const Dialog: FC<DialogProps> = React.forwardRef(
actionButtonOneProps,
actionButtonTwoProps,
actionButtonThreeProps,
closeButtonProps,
closeIcon,
parent = document.body,
size = DialogSize.medium,
headerClassNames,
Expand Down Expand Up @@ -52,6 +54,8 @@ export const Dialog: FC<DialogProps> = React.forwardRef(
actionButtonOneProps={actionButtonOneProps}
actionButtonTwoProps={actionButtonTwoProps}
actionButtonThreeProps={actionButtonThreeProps}
closeButtonProps={closeButtonProps}
closeIcon={closeIcon}
dialogClassNames={dialogClasses}
headerClassNames={headerClasses}
bodyClassNames={bodyClasses}
Expand Down
4 changes: 4 additions & 0 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const Modal: FC<ModalProps> = React.forwardRef(
actionButtonOneProps,
actionButtonTwoProps,
actionButtonThreeProps,
closeButtonProps,
closeIcon,
size = ModalSize.medium,
headerClassNames,
bodyClassNames,
Expand Down Expand Up @@ -51,6 +53,8 @@ export const Modal: FC<ModalProps> = React.forwardRef(
actionButtonOneProps={actionButtonOneProps}
actionButtonTwoProps={actionButtonTwoProps}
actionButtonThreeProps={actionButtonThreeProps}
closeButtonProps={closeButtonProps}
closeIcon={closeIcon}
dialogWrapperClassNames={modalWrapperClassNames}
dialogClassNames={modalClasses}
headerClassNames={headerClasses}
Expand Down
43 changes: 43 additions & 0 deletions src/components/Panel/Panel.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,33 @@ const Top_Story: ComponentStory<typeof Panel> = (args) => {

export const Top = Top_Story.bind({});

const Header_Actions_Story: ComponentStory<typeof Panel> = (args) => {
const [visible, setVisible] = useState<boolean>(false);
return (
<>
<PrimaryButton
text={'Open panel'}
onClick={() => setVisible(true)}
/>
<Panel
{...args}
footer={
<div>
<PrimaryButton
text={'Close'}
onClick={() => setVisible(false)}
/>
</div>
}
visible={visible}
onClose={() => setVisible(false)}
/>
</>
);
};

export const Header_Actions = Header_Actions_Story.bind({});

const panelArgs: Object = {
size: PanelSize.small,
visible: false,
Expand Down Expand Up @@ -467,3 +494,19 @@ Top.args = {
size: PanelSize.small,
placement: 'top',
};

Header_Actions.args = {
...panelArgs,
actionButtonOneProps: {
iconProps: { path: IconName.mdiCogOutline },
},
actionButtonTwoProps: {
iconProps: {
path: IconName.mdiHistory,
},
},
actionButtonThreeProps: {
iconProps: { path: IconName.mdiDatabaseArrowDownOutline },
},
size: PanelSize.medium,
};
24 changes: 22 additions & 2 deletions src/components/Panel/Panel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import Enzyme, { mount, ReactWrapper } from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import MatchMediaMock from 'jest-matchmedia-mock';
import { Panel } from './';
import { create } from 'react-test-renderer';
import { Tab, Tabs } from '../Tabs';
import { IconName } from '../Icon';

Enzyme.configure({ adapter: new Adapter() });

Expand Down Expand Up @@ -65,4 +64,25 @@ describe('Panel', () => {
wrapper.find('.panel-backdrop').at(0).simulate('click');
expect(onClose).toHaveBeenCalledTimes(2);
});

test('panel header actions exist', () => {
wrapper.setProps({
visible: true,
actionButtonOneProps: {
classNames: 'header-action-button-1',
iconProps: { path: IconName.mdiCogOutline },
},
actionButtonTwoProps: {
classNames: 'header-action-button-2',
iconProps: { path: IconName.mdiHistory },
},
actionButtonThreeProps: {
classNames: 'header-action-button-3',
iconProps: { path: IconName.mdiDatabaseArrowDownOutline },
},
});
expect(wrapper.find('.header-action-button-1').length).toBeTruthy();
expect(wrapper.find('.header-action-button-2').length).toBeTruthy();
expect(wrapper.find('.header-action-button-3').length).toBeTruthy();
});
});
30 changes: 22 additions & 8 deletions src/components/Panel/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const PANEL_WIDTHS: Record<PanelSize, number> = Object.freeze({
export const Panel = React.forwardRef<PanelRef, PanelProps>(
(
{
actionButtonOneProps,
actionButtonTwoProps,
actionButtonThreeProps,
size = PanelSize.medium,
visible = false,
closable = true,
Expand Down Expand Up @@ -108,14 +111,25 @@ export const Panel = React.forwardRef<PanelRef, PanelProps>(
const getHeader = (): JSX.Element => (
<div className={headerClasses}>
<div>{title}</div>
{closable && (
<NeutralButton
iconProps={{ path: closeIcon }}
ariaLabel={'Close'}
onClick={onClose}
{...closeButtonProps}
/>
)}
<span className={styles.headerButtons}>
{actionButtonThreeProps && (
<NeutralButton {...actionButtonThreeProps} />
)}
{actionButtonTwoProps && (
<NeutralButton {...actionButtonTwoProps} />
)}
{actionButtonOneProps && (
<NeutralButton {...actionButtonOneProps} />
)}
{closable && (
<NeutralButton
iconProps={{ path: closeIcon }}
ariaLabel={'Close'}
onClick={onClose}
{...closeButtonProps}
/>
)}
</span>
</div>
);

Expand Down
12 changes: 12 additions & 0 deletions src/components/Panel/Panel.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ type EventType =
export type CloseButtonProps = Omit<ButtonProps, 'onClick' | 'icon'>;

export interface PanelProps extends Omit<OcBaseProps<HTMLElement>, 'title'> {
/**
* Props for the first header action button
*/
actionButtonOneProps?: ButtonProps;
/**
* Props for the second header action button
*/
actionButtonTwoProps?: ButtonProps;
/**
* Props for the third header action button
*/
actionButtonThreeProps?: ButtonProps;
/**
* Autofocus on the panel on visible
* @default true
Expand Down
8 changes: 8 additions & 0 deletions src/components/Panel/panel.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@
top: 0;
display: flex;
justify-content: space-between;

&-buttons {
align-items: flex-end;
align-self: start;
height: fit-content;
justify-content: right;
white-space: nowrap;
}
}

.body {
Expand Down
72 changes: 68 additions & 4 deletions src/components/RadioButton/RadioButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { Stories } from '@storybook/addon-docs';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RadioButton, RadioButtonValue, RadioGroup } from './';
import { Stack } from '../Stack';

export default {
title: 'Radio Button',
Expand Down Expand Up @@ -106,9 +107,23 @@ export default {
},
} as ComponentMeta<typeof RadioButton>;

const RadioButton_Story: ComponentStory<typeof RadioButton> = (args) => (
<RadioButton {...args} />
);
const RadioButton_Story: ComponentStory<typeof RadioButton> = (args) => {
const [selected, setSelected] = useState<RadioButtonValue>('label1');

const radioChangeHandler = (
e?: React.ChangeEvent<HTMLInputElement>
): void => {
setSelected(e.target.value);
};

return (
<RadioButton
{...args}
checked={selected === 'Label1'}
onChange={radioChangeHandler}
/>
);
};

export const Radio_Button = RadioButton_Story.bind({});

Expand All @@ -128,6 +143,50 @@ const RadioGroup_Story: ComponentStory<typeof RadioGroup> = (args) => {

export const Radio_Group = RadioGroup_Story.bind({});

const Bespoke_RadioGroup_Story: ComponentStory<typeof RadioButton> = (args) => {
const [selected, setSelected] = useState<RadioButtonValue>('label1');

const radioChangeHandler = (
e?: React.ChangeEvent<HTMLInputElement>
): void => {
setSelected(e.target.value);
};

return (
<Stack direction="vertical" gap="m">
<RadioButton
{...args}
ariaLabel={'Label 1'}
checked={selected === 'label1'}
id={'myRadioButtonId1'}
label={'Label 1'}
onChange={radioChangeHandler}
value={'label1'}
/>
<RadioButton
{...args}
ariaLabel={'Label 2'}
checked={selected === 'label2'}
id={'myRadioButtonId2'}
label={'Label 2'}
onChange={radioChangeHandler}
value={'label2'}
/>
<RadioButton
{...args}
ariaLabel={'Label 3'}
checked={selected === 'label3'}
id={'myRadioButtonId3'}
label={'Label 3'}
onChange={radioChangeHandler}
value={'label3'}
/>
</Stack>
);
};

export const Bespoke_Radio_Group = Bespoke_RadioGroup_Story.bind({});

const radioButtonArgs: Object = {
allowDisabledFocus: false,
ariaLabel: 'Label',
Expand All @@ -136,7 +195,7 @@ const radioButtonArgs: Object = {
classNames: 'my-radiobutton-class',
disabled: false,
name: 'myRadioButtonName',
value: 'Label',
value: 'Label1',
id: 'myRadioButtonId',
};

Expand All @@ -155,3 +214,8 @@ Radio_Group.args = {
})),
layout: 'vertical',
};

Bespoke_Radio_Group.args = {
...radioButtonArgs,
name: 'roleGroupName',
};
Loading