Skip to content

Commit cc84d56

Browse files
feat: extract radio into common component
1 parent 054a6aa commit cc84d56

3 files changed

Lines changed: 76 additions & 26 deletions

File tree

src/components/core/radio-group.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import cn from 'classnames';
4+
5+
const RadioGroup = ({ name, label, options, value, onChange }) => {
6+
return (
7+
<div className="flex flex-col gap-2">
8+
{label && <span className="text-text-primary text-base">{label}</span>}
9+
<div className="flex items-center">
10+
{options.map((option) => (
11+
<div key={option.value} className="flex flex-1 items-center">
12+
<label
13+
className={cn(
14+
'flex items-center gap-3 px-1.5 py-1 rounded-lg',
15+
'focus-within:outline focus-within:outline-2 focus-within:outline-primary',
16+
option.disabled ? 'cursor-not-allowed' : 'cursor-pointer'
17+
)}
18+
>
19+
<input
20+
type="radio"
21+
name={name}
22+
checked={value === option.value}
23+
onChange={() => onChange(option.value)}
24+
disabled={option.disabled}
25+
className={cn(
26+
'appearance-none w-5 h-5 shrink-0 rounded-full border-2',
27+
'checked:shadow-[inset_0_0_0_3px_white] focus:outline-none',
28+
option.disabled
29+
? 'border-gray-200 checked:bg-gray-200 checked:border-gray-200 cursor-not-allowed'
30+
: 'border-gray-400 checked:border-primary checked:bg-primary cursor-pointer'
31+
)}
32+
/>
33+
<span
34+
className={cn('text-base', option.disabled ? 'text-gray-400' : 'text-text-primary')}
35+
>
36+
{option.label}
37+
</span>
38+
</label>
39+
</div>
40+
))}
41+
</div>
42+
</div>
43+
);
44+
};
45+
46+
RadioGroup.propTypes = {
47+
name: PropTypes.string.isRequired,
48+
label: PropTypes.string,
49+
options: PropTypes.arrayOf(
50+
PropTypes.shape({
51+
value: PropTypes.string.isRequired,
52+
label: PropTypes.string.isRequired,
53+
disabled: PropTypes.bool,
54+
})
55+
).isRequired,
56+
value: PropTypes.string.isRequired,
57+
onChange: PropTypes.func.isRequired,
58+
};
59+
60+
export default RadioGroup;

src/components/core/text-input.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ const TextInput = React.forwardRef(
4949
)}
5050
{...props}
5151
/>
52-
{error && <span id={`${id}-error`} role="alert" className="text-sm text-error leading-[1.4]">{error}</span>}
52+
{error && (
53+
<span id={`${id}-error`} role="alert" className="text-sm text-error leading-[1.4]">
54+
{error}
55+
</span>
56+
)}
5357
</div>
5458
);
5559
}

src/components/link-input-modal.js

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
33
import { useTranslation } from '@/lib/i18n';
44
import BasicModal from '@/components/core/modal/basic-modal';
55
import TextInput from '@/components/core/text-input';
6+
import RadioGroup from '@/components/core/radio-group';
67

78
const LinkInputModal = ({ isOpen, onClose, onConfirm }) => {
89
const [display, setDisplay] = useState('');
@@ -85,31 +86,16 @@ const LinkInputModal = ({ isOpen, onClose, onConfirm }) => {
8586
error={urlError}
8687
required
8788
/>
88-
<div className="flex flex-col gap-2">
89-
<span className="text-text-primary text-base">{t('openMethod')}</span>
90-
<div className="flex items-center">
91-
<label className="flex flex-1 items-center gap-3 py-1 cursor-pointer">
92-
<input
93-
type="radio"
94-
name="link-open-method"
95-
checked={openInNewTab}
96-
onChange={() => setOpenInNewTab(true)}
97-
className="accent-primary w-5 h-5 shrink-0"
98-
/>
99-
<span className="text-base text-text-primary">{t('newTab')}</span>
100-
</label>
101-
<label className="flex flex-1 items-center gap-3 px-2 py-1 cursor-pointer">
102-
<input
103-
type="radio"
104-
name="link-open-method"
105-
checked={!openInNewTab}
106-
onChange={() => setOpenInNewTab(false)}
107-
className="accent-primary w-5 h-5 shrink-0"
108-
/>
109-
<span className="text-base text-text-primary">{t('currentTab')}</span>
110-
</label>
111-
</div>
112-
</div>
89+
<RadioGroup
90+
name="link-open-method"
91+
label={t('openMethod')}
92+
options={[
93+
{ value: 'new-tab', label: t('newTab') },
94+
{ value: 'current-tab', label: t('currentTab') },
95+
]}
96+
value={openInNewTab ? 'new-tab' : 'current-tab'}
97+
onChange={(val) => setOpenInNewTab(val === 'new-tab')}
98+
/>
11399
</div>
114100
</BasicModal>
115101
);

0 commit comments

Comments
 (0)