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

feat: InlineSelect ability #5963

Merged
merged 11 commits into from
Oct 6, 2023
41 changes: 41 additions & 0 deletions components/Common/Select/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
dark:data-[placeholder]:text-neutral-200;
}

.trigger span {
@apply flex
items-center
gap-2;
}

.icon {
@apply h-5
w-5
Expand Down Expand Up @@ -77,8 +83,43 @@
dark:data-[highlighted]:bg-green-600;
}

.text span {
@apply flex
items-center
gap-2;
}

.label {
@apply text-neutral-600
dark:text-neutral-400;
}
}

.inline {
.trigger {
@apply min-w-fit
px-2.5
py-2
text-sm
font-medium;
}

.icon {
@apply h-4
w-4;
}

.text {
@apply text-neutral-900
data-[highlighted]:bg-neutral-100
data-[highlighted]:text-neutral-900
dark:text-white
dark:data-[highlighted]:bg-neutral-900;
}

&.dropdown {
@apply mt-1
w-[calc(100%+1.5rem)]
rounded;
}
}
25 changes: 25 additions & 0 deletions components/Common/Select/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,29 @@ export const DropdownLabel: Story = {
},
};

export const InlineSelect: Story = {
args: {
values: [
{
value: 'linux',
label: 'Linux',
iconImageUrl: '/static/images/logos/platform-linux.svg',
},
{
value: 'macos',
label: 'MacOS',
iconImageUrl: '/static/images/logos/platform-apple.svg',
},
{
value: 'windows',
label: 'Windows',
iconImageUrl: '/static/images/logos/platform-microsoft.svg',
},
],
dropdownLabel: 'Platform',
defaultValue: 'macos',
inline: true,
},
};

export default { component: Select } as Meta;
66 changes: 47 additions & 19 deletions components/Common/Select/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import * as Primitive from '@radix-ui/react-select';
import { useId } from 'react';
import classNames from 'classnames';
import Image from 'next/image';
import { useId, useMemo } from 'react';
import type { FC } from 'react';

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

type SelectValue = {
label: string;
value: string;
iconImageUrl?: string;
};

type SelectProps = {
values: ({ label: string; value: string } | string)[];
values: SelectValue[] | string[];
defaultValue?: string;
placeholder?: string;
dropdownLabel?: string;
label?: string;
inline?: boolean;
onChange?: (value: string) => void;
};

Expand All @@ -20,12 +29,23 @@ const Select: FC<SelectProps> = ({
placeholder,
label,
dropdownLabel,
inline,
onChange,
}) => {
const id = useId();
const mappedValues = useMemo(() => {
const [firstItem] = values;

const items =
typeof firstItem === 'string'
? values.map(value => ({ value, label: value }))
: values;

return items as SelectValue[];
}, [values]);

return (
<div className={styles.select}>
<div className={classNames(styles.select, { [styles.inline]: inline })}>
{label && (
<label className={styles.label} htmlFor={id}>
{label}
Expand All @@ -34,35 +54,43 @@ const Select: FC<SelectProps> = ({
<Primitive.Root defaultValue={defaultValue} onValueChange={onChange}>
<Primitive.Trigger
className={styles.trigger}
aria-label={label}
aria-label={label || dropdownLabel}
id={id}
>
<Primitive.Value placeholder={placeholder} />
<ChevronDownIcon className={styles.icon} />
</Primitive.Trigger>
<Primitive.Portal>
<Primitive.Content className={styles.dropdown}>
<Primitive.Content
position={inline ? 'popper' : 'item-aligned'}
className={classNames(styles.dropdown, { [styles.inline]: inline })}
>
<Primitive.Viewport>
<Primitive.Group>
{dropdownLabel && (
<Primitive.Label className={`${styles.item} ${styles.label}`}>
{dropdownLabel}
</Primitive.Label>
)}
{values.map(item => {
const value = typeof item === 'string' ? item : item.value;
const label = typeof item === 'string' ? item : item.label;

return (
<Primitive.Item
key={value}
value={value}
className={`${styles.item} ${styles.text}`}
>
<Primitive.ItemText>{label}</Primitive.ItemText>
</Primitive.Item>
);
})}
{mappedValues.map(({ value, label, iconImageUrl }) => (
<Primitive.Item
key={value}
value={value}
className={`${styles.item} ${styles.text}`}
>
<Primitive.ItemText>
{iconImageUrl && (
<Image
src={iconImageUrl}
alt={label}
width={16}
height={16}
/>
)}
{label}
</Primitive.ItemText>
</Primitive.Item>
))}
</Primitive.Group>
</Primitive.Viewport>
</Primitive.Content>
Expand Down
4 changes: 2 additions & 2 deletions styles/new/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
}

code {
@apply rounded-[4px]
@apply rounded
ovflowd marked this conversation as resolved.
Show resolved Hide resolved
bg-neutral-100
px-[4px]
px-1
font-ibm-plex-mono
text-base
font-semibold
Expand Down
Loading