Skip to content

Commit

Permalink
convert radio.js to tsx (#1102)
Browse files Browse the repository at this point in the history
* convert radio.js to tsx

* change code style
  • Loading branch information
ChancellorO authored Nov 29, 2023
1 parent 38e769b commit a6c172d
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 131 deletions.
2 changes: 1 addition & 1 deletion src/components/TextEditor/components/EditorRadio.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { CODE_AND_OUTPUT, CODE_ONLY, OUTPUT_ONLY } from '../../../constants';
import Radio from '../../common/Radio.js';
import Radio from '../../common/Radio';

const EditorRadio = function (props) {
let options = [];
Expand Down
116 changes: 0 additions & 116 deletions src/components/common/Radio.js

This file was deleted.

22 changes: 8 additions & 14 deletions src/components/common/Radio.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { shallow } from 'enzyme';
import React from 'react';
import Radio from './Radio.js';
import Radio from './Radio';

const validOptions = [
{
Expand Down Expand Up @@ -43,10 +43,7 @@ describe('Radio', () => {
// on click option, invalid handle click does not cause error
const component = shallow(<Radio options={validOptions} />);
expect(() => {
component
.find('.radio-option')
.at(0)
.simulate('click');
component.find('.radio-option').at(0).simulate('click');
}).not.toThrow();
});

Expand Down Expand Up @@ -107,7 +104,10 @@ describe('Radio', () => {
<Radio
options={validOptions}
optionStyle={{
width: 2000, height: 2000, backgroundColor: '#FFF', color: '#000',
width: 2000,
height: 2000,
backgroundColor: '#FFF',
color: '#000',
}}
bgColor="#333"
color="#444"
Expand All @@ -128,10 +128,7 @@ describe('Radio', () => {
expect(clickFn.mock.calls[0][0]).toBe('pear');

// clicking a non selected option causes the selected value to change
component
.find('.radio-option')
.at(0)
.simulate('click');
component.find('.radio-option').at(0).simulate('click');
expect(clickFn.mock.calls[1][0]).toBe('banana');
expect(component.state().selected).toBe('banana');
expect(component.find('.radio-option-selected').text()).toBe('Nice');
Expand Down Expand Up @@ -163,10 +160,7 @@ describe('Radio', () => {
expect(component2.state().selected).toStrictEqual(['banana', 'apple', 'pear']);

// click on already selected value, make sure it gets removed
component2
.find('.radio-option-selected')
.at(0)
.simulate('click');
component2.find('.radio-option-selected').at(0).simulate('click');
expect(clickFn.mock.calls[1][0]).toStrictEqual(['apple', 'pear']);
expect(component2.state().selected).toStrictEqual(['apple', 'pear']);
});
Expand Down
165 changes: 165 additions & 0 deletions src/components/common/Radio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import React from 'react';
import '../../styles/Radio.scss';
/**
* Props
*
* options: (array of jsons) content for each box
* each json should look like {
* display: "Text to be displayed",
* (optional) value: the hidden value correlating to the display value (defaults to the index)
* }
* defaultSelected: (same type as options' value key) the option that will be default selected
* CAREFUL: if handleClick causes Radio to be re-rendered, make sure you're fine
* with this variable always being the defaultSelected
* containerStyle: (json) overrides the style on the outer container
* optionStyle: (json) overrides the style on each individual option
* selectedOptionStyle: (json) overrides the style on the selected option
* bgColor: (string) color of the non selected options
* color: (string) color of the non selected options text
* selectedBgColor: (string) color of the selected option
* selectedColor: (string) color of the selected options text
* handleClick: (func) function to be called when an option is clicked
* should have 1 parameter (value) which is the value
* (from the options prop) that is selected (defaults to index)
* allowMultipleSelected: (bool) if true, allows multiple options to be selected
* changes handle click to be called with all selected values
*/

interface OptionItem {
display: string;
value: string;
}

interface RadioProps<T> {
defaultSelected: T;
allowMultipleSelected: boolean;
options: OptionItem[];
containerStyle: any;
optionStyle: any;
selectedOptionStyle: any;
selectedBgColor: any;
selectedColor: any;
bgColor: any;
color: any;
handleClick: (arg0: string) => string;
}

interface RadioState {
selected?: any;
}

class Radio<T> extends React.Component <RadioProps<T>, RadioState> {
// static defaultProps: Partial<RadioProps<string>> = defaultProps;
constructor(props: RadioProps<T>) {
super(props);

const { allowMultipleSelected, defaultSelected } = this.props;

let selected: T | T[] | undefined = defaultSelected;
if (allowMultipleSelected) {
selected = selected || [];
}

this.state = {
selected,
};
}

updateSelectedState = (selected_value: string, alreadySelected: boolean): void => {
const { allowMultipleSelected, handleClick } = this.props;

if (allowMultipleSelected) {
const { selected } = this.state;
let newState = selected;
if (alreadySelected) {
const i = selected.indexOf(selected_value);
if (i >= 0) newState.splice(i, 1);
} else {
newState = selected.concat([selected_value]);
}
if (handleClick) {
handleClick(newState);
}
this.setState({ selected: newState });
} else {
if (handleClick) {
handleClick(selected_value);
}
this.setState({ selected: selected_value });
}
};

renderOption = ({ display, value }: OptionItem, index: number): JSX.Element => {
// if no value is provided, use the index
// value = value || index;
const { selected } = this.state;
const { allowMultipleSelected, options } = this.props;
const isSelected = value === selected
|| (allowMultipleSelected && selected.includes(value));
// attach -selected if the value matches the selected state
const className = `radio-option${isSelected ? '-selected' : ''}`;
// add an id of radio-left if its the first option or radio-right if its the last option
let idValue;
if (index === 0) {
idValue = 'radio-left';
} else if (index === options.length - 1) {
idValue = 'radio-right';
} else {
idValue = '';
}
const id = idValue;

let newOptionStyle;
const {
optionStyle, selectedOptionStyle, selectedBgColor, selectedColor, bgColor, color,
} = this.props;
if (isSelected) {
newOptionStyle = {

...optionStyle || {},
...selectedOptionStyle || {},
...(selectedBgColor ? { backgroundColor: selectedBgColor } : {}),
...(selectedColor ? { color: selectedColor } : {}),
};
} else {
newOptionStyle = {

...optionStyle || {},
...(bgColor ? { backgroundColor: bgColor } : {}),
...(color ? { color } : {}),
};
}

return (
<div
role="button"
tabIndex={0}
className={className}
onClick={() => this.updateSelectedState(value, isSelected)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
this.updateSelectedState(value, isSelected);
}
}}
style={newOptionStyle}
id={id}
key={index}
>
{display}
</div>
);
};

render() {
const { containerStyle, options } = this.props;
const optionsMap = options || [];

return (
<div className="radio-selector" style={containerStyle}>
{optionsMap.map(this.renderOption)}
</div>
);
}
}

export default Radio;

0 comments on commit a6c172d

Please sign in to comment.