Skip to content

Commit 6109d75

Browse files
authored
feat: InlineSelect ability (#5963)
* feat: InlineSelect ability * refactor: Unnecessary optional chaining removed * chore: css indentation * refactor: Inline Select style updates and improvements * refactor: Removed unnecessary added types * refactor: Tailwind border radius values adjusted * refactor: Inline select dropdown radius * refactor: Unnecessary pixel usage * refactor: Inline select trigger border-radius * refactor: Revert rounded-xs to rounded
1 parent 3138682 commit 6109d75

File tree

4 files changed

+115
-21
lines changed

4 files changed

+115
-21
lines changed

components/Common/Select/index.module.css

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
dark:data-[placeholder]:text-neutral-200;
4242
}
4343

44+
.trigger span {
45+
@apply flex
46+
items-center
47+
gap-2;
48+
}
49+
4450
.icon {
4551
@apply h-5
4652
w-5
@@ -77,8 +83,43 @@
7783
dark:data-[highlighted]:bg-green-600;
7884
}
7985

86+
.text span {
87+
@apply flex
88+
items-center
89+
gap-2;
90+
}
91+
8092
.label {
8193
@apply text-neutral-600
8294
dark:text-neutral-400;
8395
}
8496
}
97+
98+
.inline {
99+
.trigger {
100+
@apply min-w-fit
101+
px-2.5
102+
py-2
103+
text-sm
104+
font-medium;
105+
}
106+
107+
.icon {
108+
@apply h-4
109+
w-4;
110+
}
111+
112+
.text {
113+
@apply text-neutral-900
114+
data-[highlighted]:bg-neutral-100
115+
data-[highlighted]:text-neutral-900
116+
dark:text-white
117+
dark:data-[highlighted]:bg-neutral-900;
118+
}
119+
120+
&.dropdown {
121+
@apply mt-1
122+
w-[calc(100%+1.5rem)]
123+
rounded;
124+
}
125+
}

components/Common/Select/index.stories.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,29 @@ export const DropdownLabel: Story = {
6262
},
6363
};
6464

65+
export const InlineSelect: Story = {
66+
args: {
67+
values: [
68+
{
69+
value: 'linux',
70+
label: 'Linux',
71+
iconImageUrl: '/static/images/logos/platform-linux.svg',
72+
},
73+
{
74+
value: 'macos',
75+
label: 'MacOS',
76+
iconImageUrl: '/static/images/logos/platform-apple.svg',
77+
},
78+
{
79+
value: 'windows',
80+
label: 'Windows',
81+
iconImageUrl: '/static/images/logos/platform-microsoft.svg',
82+
},
83+
],
84+
dropdownLabel: 'Platform',
85+
defaultValue: 'macos',
86+
inline: true,
87+
},
88+
};
89+
6590
export default { component: Select } as Meta;

components/Common/Select/index.tsx

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import { ChevronDownIcon } from '@heroicons/react/24/outline';
22
import * as Primitive from '@radix-ui/react-select';
3-
import { useId } from 'react';
3+
import classNames from 'classnames';
4+
import Image from 'next/image';
5+
import { useId, useMemo } from 'react';
46
import type { FC } from 'react';
57

68
import styles from './index.module.css';
79

10+
type SelectValue = {
11+
label: string;
12+
value: string;
13+
iconImageUrl?: string;
14+
};
15+
816
type SelectProps = {
9-
values: ({ label: string; value: string } | string)[];
17+
values: SelectValue[] | string[];
1018
defaultValue?: string;
1119
placeholder?: string;
1220
dropdownLabel?: string;
1321
label?: string;
22+
inline?: boolean;
1423
onChange?: (value: string) => void;
1524
};
1625

@@ -20,12 +29,23 @@ const Select: FC<SelectProps> = ({
2029
placeholder,
2130
label,
2231
dropdownLabel,
32+
inline,
2333
onChange,
2434
}) => {
2535
const id = useId();
36+
const mappedValues = useMemo(() => {
37+
const [firstItem] = values;
38+
39+
const items =
40+
typeof firstItem === 'string'
41+
? values.map(value => ({ value, label: value }))
42+
: values;
43+
44+
return items as SelectValue[];
45+
}, [values]);
2646

2747
return (
28-
<div className={styles.select}>
48+
<div className={classNames(styles.select, { [styles.inline]: inline })}>
2949
{label && (
3050
<label className={styles.label} htmlFor={id}>
3151
{label}
@@ -34,35 +54,43 @@ const Select: FC<SelectProps> = ({
3454
<Primitive.Root defaultValue={defaultValue} onValueChange={onChange}>
3555
<Primitive.Trigger
3656
className={styles.trigger}
37-
aria-label={label}
57+
aria-label={label || dropdownLabel}
3858
id={id}
3959
>
4060
<Primitive.Value placeholder={placeholder} />
4161
<ChevronDownIcon className={styles.icon} />
4262
</Primitive.Trigger>
4363
<Primitive.Portal>
44-
<Primitive.Content className={styles.dropdown}>
64+
<Primitive.Content
65+
position={inline ? 'popper' : 'item-aligned'}
66+
className={classNames(styles.dropdown, { [styles.inline]: inline })}
67+
>
4568
<Primitive.Viewport>
4669
<Primitive.Group>
4770
{dropdownLabel && (
4871
<Primitive.Label className={`${styles.item} ${styles.label}`}>
4972
{dropdownLabel}
5073
</Primitive.Label>
5174
)}
52-
{values.map(item => {
53-
const value = typeof item === 'string' ? item : item.value;
54-
const label = typeof item === 'string' ? item : item.label;
55-
56-
return (
57-
<Primitive.Item
58-
key={value}
59-
value={value}
60-
className={`${styles.item} ${styles.text}`}
61-
>
62-
<Primitive.ItemText>{label}</Primitive.ItemText>
63-
</Primitive.Item>
64-
);
65-
})}
75+
{mappedValues.map(({ value, label, iconImageUrl }) => (
76+
<Primitive.Item
77+
key={value}
78+
value={value}
79+
className={`${styles.item} ${styles.text}`}
80+
>
81+
<Primitive.ItemText>
82+
{iconImageUrl && (
83+
<Image
84+
src={iconImageUrl}
85+
alt={label}
86+
width={16}
87+
height={16}
88+
/>
89+
)}
90+
{label}
91+
</Primitive.ItemText>
92+
</Primitive.Item>
93+
))}
6694
</Primitive.Group>
6795
</Primitive.Viewport>
6896
</Primitive.Content>

styles/new/base.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
}
44

55
code {
6-
@apply rounded-[4px]
6+
@apply rounded
77
bg-neutral-100
8-
px-[4px]
8+
px-1
99
font-ibm-plex-mono
1010
text-base
1111
font-semibold

0 commit comments

Comments
 (0)