forked from EightfoldAI/octuple
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add checkbox and radio button components (EightfoldAI#56)
* feat: add Checkbox and RadioButton components * fix: update styles according to figma, implement comments on pr * fix: remove colors, styling polish * fix: resolve errors in console * fix: resolve console errors for checkbox * fix: resolve comments, add style variables, refactor * fix: connect radio and checkbox to input with htmlFor={id} and use provider pattern for radio group * fix: sync/resolve with main * chore: refactor * chore: refactor radio * chore: remove rem conversion from css, add keydown handlers * fix: focus-visible on checkbox/radio, adjust tabindex, use arrow keys when tab pressed * fix: initial radio button selected, index was off after tab * fix: off index update when tab and clicking * fix: shift + tab to go to prev section, current radio always has focus * chore: add unit tests * fix: update tests * fix: update snapshots * fix: update snapshot yarn * chore: snapshots: updates snapshots * fix: useState on id's for snapshot tests to pass Co-authored-by: yash <yash@MacBook-Pro-Yash-Kelkar-RQMM9RC70H.local> Co-authored-by: yash <yash@MBPYashMM9RC70H.home> Co-authored-by: yash <yash@MBPYashMM9RC70H.socal.rr.com> Co-authored-by: Dylan Kilgore <dkilgore@eightfold.ai>
- Loading branch information
1 parent
a00a1c8
commit fe3caf7
Showing
19 changed files
with
86,944 additions
and
6 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Git LFS file not shown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react'; | ||
import { CheckBox, CheckBoxGroup } from '../index'; | ||
|
||
export default { | ||
title: 'Check Box', | ||
component: CheckBox, | ||
}; | ||
|
||
export const Box = () => { | ||
const checkboxGroupItems = [ | ||
{ | ||
checked: true, | ||
name: 'group', | ||
value: 'First', | ||
id: 'test-1', | ||
}, | ||
{ | ||
checked: true, | ||
name: 'group', | ||
value: 'Second', | ||
id: 'test-2', | ||
}, | ||
{ | ||
checked: true, | ||
name: 'group', | ||
value: 'Third', | ||
id: 'test-3', | ||
}, | ||
]; | ||
|
||
return ( | ||
<> | ||
<h1>Check Boxes</h1> | ||
<h2>Default Check Box</h2> | ||
<CheckBox checked={true} id="test-4" /> | ||
<h2>Label Check Box</h2> | ||
<CheckBox checked={true} value="Label" id="test-5" /> | ||
<h2>Check Box Groups</h2> | ||
<CheckBoxGroup items={checkboxGroupItems} /> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react'; | ||
import Enzyme, { mount } from 'enzyme'; | ||
import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; | ||
import { CheckBox } from '../'; | ||
|
||
Enzyme.configure({ adapter: new Adapter() }); | ||
|
||
describe('RadioButton', () => { | ||
/* | ||
* Functionality Tests | ||
*/ | ||
test('Checkbox renders', () => { | ||
const wrapper = mount(<CheckBox checked={true} />); | ||
expect( | ||
wrapper.containsMatchingElement(<CheckBox checked={true} />) | ||
).toEqual(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, { FC, useState } from 'react'; | ||
import { CheckBoxProps } from '../'; | ||
import { mergeClasses, generateId } from '../../../shared/utilities'; | ||
|
||
import styles from './checkbox.module.scss'; | ||
|
||
export const CheckBox: FC<CheckBoxProps> = ({ | ||
ariaLabel, | ||
checked = false, | ||
defaultChecked, | ||
disabled = false, | ||
name, | ||
value = '', | ||
id, | ||
onChange, | ||
}) => { | ||
const [checkBoxId] = useState<string>(id || generateId()); | ||
const [isChecked, setIsChecked] = useState<boolean>(checked); | ||
|
||
const checkBoxCheckClassNames: string = mergeClasses([ | ||
styles.checkmark, | ||
{ [styles.disabled]: disabled }, | ||
]); | ||
|
||
const toggleChecked = (): void => { | ||
if (!disabled) setIsChecked(!isChecked); | ||
}; | ||
|
||
const handleKeyDown = (event: React.KeyboardEvent) => { | ||
if (event.key !== 'Tab') event.preventDefault(); | ||
if (event.key === 'Enter' || event.key === ' ') toggleChecked(); | ||
}; | ||
|
||
return ( | ||
<div className={styles.selector} onKeyDown={handleKeyDown}> | ||
<input | ||
aria-label={ariaLabel} | ||
checked={isChecked} | ||
defaultChecked={defaultChecked} | ||
disabled={disabled} | ||
id={checkBoxId} | ||
onChange={onChange ? onChange : toggleChecked} | ||
name={name} | ||
tabIndex={-1} | ||
type={'checkbox'} | ||
value={value} | ||
readOnly | ||
/> | ||
<label | ||
htmlFor={checkBoxId} | ||
className={value === '' ? styles.labelNoValue : ''} | ||
> | ||
<span className={checkBoxCheckClassNames} tabIndex={0}></span> | ||
<span className={styles.selectorLabel}>{value}</span> | ||
</label> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React, { FC } from 'react'; | ||
import { CheckBoxProps } from '../'; | ||
import { CheckBox } from './CheckBox'; | ||
import { generateId } from '../../../shared/utilities'; | ||
|
||
export const CheckBoxGroup: FC<CheckBoxProps> = ({ | ||
defaultChecked = true, | ||
items, | ||
onChange, | ||
}) => { | ||
return ( | ||
<> | ||
{items.map((item, index) => ( | ||
<CheckBox | ||
ariaLabel={item.ariaLabel} | ||
checked={item.checked ? item.checked : defaultChecked} | ||
id={item.id || generateId()} | ||
key={index} | ||
name={item.name} | ||
value={item.value} | ||
onChange={onChange} | ||
/> | ||
))} | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
.selector { | ||
margin-bottom: $selector-margin-bottom; | ||
flex-shrink: 1; | ||
position: relative; | ||
display: flex; | ||
text-overflow: elipses; | ||
vertical-align: baseline; | ||
|
||
input { | ||
position: absolute; | ||
background: none; | ||
opacity: 0; | ||
height: $selector-input-width; | ||
width: $selector-input-height; | ||
top: $space-xxxs; | ||
left: $space-xxxs; | ||
cursor: pointer; | ||
} | ||
|
||
input:checked + label { | ||
.checkmark { | ||
background-color: var(--primary-color); | ||
border: $space-xxxs solid var(--primary-color); | ||
|
||
&.disabled { | ||
opacity: 50%; | ||
|
||
&:hover { | ||
background-color: var(--primary-color); | ||
border: $space-xxxs solid var(--primary-color); | ||
} | ||
|
||
&:focus, | ||
&:focus-visible { | ||
outline: none; | ||
} | ||
|
||
&:active { | ||
transform: none; | ||
background-color: var(--primary-color); | ||
border: $space-xxxs solid var(--primary-color); | ||
} | ||
} | ||
|
||
&:hover { | ||
background-color: var(--primary-color-60); | ||
border: $space-xxxs solid var(--primary-color-60); | ||
} | ||
|
||
&:focus, | ||
&:focus-visible { | ||
outline: $space-xxxs solid var(--primary-color-50); | ||
outline-offset: $selector-outline-offset; | ||
} | ||
|
||
&:active { | ||
transform: scale(0.98); | ||
background-color: var(--primary-color-80); | ||
border: $space-xxxs solid var(--primary-color-80); | ||
} | ||
|
||
&:after { | ||
left: $checkmark-after-left; | ||
top: $checkmark-after-top; | ||
width: $checkmark-after-width; | ||
height: $icon-font-size-material-xs; | ||
border: solid white; | ||
border-width: 0 $space-xxxs $space-xxxs 0; | ||
-webkit-transform: rotate(45deg); | ||
-ms-transform: rotate(45deg); | ||
transform: rotate(45deg); | ||
display: block; | ||
} | ||
} | ||
} | ||
|
||
.checkmark { | ||
height: $checkmark-height; | ||
width: $checkmark-width; | ||
position: absolute; | ||
left: 0; | ||
border-radius: $corner-radius-s; | ||
cursor: pointer; | ||
border: $space-xxxs solid var(--grey-color-70); | ||
|
||
&.disabled { | ||
opacity: 50%; | ||
|
||
&:hover { | ||
border: $space-xxxs solid var(--grey-color-70); | ||
} | ||
|
||
&:focus, | ||
&:focus-visible { | ||
outline: none; | ||
border: $space-xxxs solid var(--grey-color-70); | ||
} | ||
|
||
&:active { | ||
border: $space-xxxs solid var(--grey-color-70); | ||
} | ||
} | ||
|
||
&:hover { | ||
border: $space-xxxs solid var(--primary-color-60); | ||
} | ||
|
||
&:focus, | ||
&:focus-visible { | ||
border: $space-xxxs solid var(--primary-color); | ||
outline: $space-xxxs solid var(--primary-color-50); | ||
outline-offset: $selector-outline-offset; | ||
} | ||
|
||
&:active { | ||
border: $space-xxxs solid var(--primary-color-80); | ||
} | ||
|
||
&:after { | ||
content: ''; | ||
position: absolute; | ||
display: none; | ||
} | ||
} | ||
|
||
label { | ||
display: flex; | ||
align-items: flex-start; | ||
cursor: pointer; | ||
position: relative; | ||
user-select: none; | ||
vertical-align: baseline; | ||
} | ||
|
||
.selector-label { | ||
margin-left: $selector-label-margin-left; | ||
font-size: medium; | ||
margin-top: $space-xxxs; | ||
} | ||
} | ||
|
||
.label-no-value { | ||
margin-bottom: $label-no-value-margin-bottom; | ||
} |
36 changes: 36 additions & 0 deletions
36
src/components/Selectors/RadioButton/RadioButton.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import React from 'react'; | ||
import { RadioButton, RadioGroup } from '../index'; | ||
import { RadioButtonChecked } from '../Selectors.types'; | ||
|
||
export default { | ||
title: 'Radio Button', | ||
component: RadioButton, | ||
}; | ||
|
||
export const Radio = () => { | ||
const radioGroupItems = [1, 2, 3].map((i) => ({ | ||
value: `Radio${i}`, | ||
name: 'group', | ||
id: `oea2exk-${i}`, | ||
})); | ||
|
||
return ( | ||
<> | ||
<h1>Radio Buttons</h1> | ||
<h2>Default Radio Button</h2> | ||
<RadioButton checked={true} id="asdfasdf" /> | ||
<h2>Label Radio Button</h2> | ||
<RadioButton checked={true} value="Label" id="zxcvzxcv" /> | ||
<h2>Radio Button Groups</h2> | ||
<RadioGroup | ||
onChange={_radioClicked} | ||
activeRadioButton={'Radio1'} | ||
radioGroupItems={radioGroupItems} | ||
/> | ||
</> | ||
); | ||
}; | ||
|
||
function _radioClicked(radio: RadioButtonChecked): void { | ||
console.log(radio); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react'; | ||
import Enzyme, { mount } from 'enzyme'; | ||
import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; | ||
import { RadioButton } from '../'; | ||
|
||
Enzyme.configure({ adapter: new Adapter() }); | ||
|
||
describe('RadioButton', () => { | ||
/* | ||
* Functionality Tests | ||
*/ | ||
test('Radio button renders', () => { | ||
const wrapper = mount(<RadioButton checked={true} />); | ||
expect( | ||
wrapper.containsMatchingElement(<RadioButton checked={true} />) | ||
).toEqual(true); | ||
}); | ||
}); |
Oops, something went wrong.