Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/assets/SvgIcon/InfoCircleSolidSvgIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';

const InfoCircleSolidSvgIcon = (props: SvgIconProps) => (
<SvgIcon
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 18C15.3137 18 18 15.3137 18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18ZM12 10C12.5523 10 13 9.55228 13 9C13 8.44772 12.5523 8 12 8C11.4477 8 11 8.44772 11 9C11 9.55228 11.4477 10 12 10ZM11 12C11 11.4477 11.4477 11 12 11C12.5523 11 13 11.4477 13 12V15C13 15.5523 12.5523 16 12 16C11.4477 16 11 15.5523 11 15V12Z"
fill="currentColor"
/>
</SvgIcon>
);

export default InfoCircleSolidSvgIcon;
67 changes: 44 additions & 23 deletions src/components/Dropdown/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,32 @@ import Button from '../Button';
import Dropdown from './Dropdown';
import { DropDownItem } from './Dropdown.type';
import DropdownV2 from './DropdownV2';
import DropdownV3 from './DropdownV3';

const list: DropDownItem[] = [
{ id: 'A001', value: 'A001', name: 'Distributor 1' },
{ id: 'A002', value: 'A002', name: 'Distributor 2' },
{ id: 'A003', value: 'A003', name: 'Distributor 3' },
{ id: 'A004', value: 'A004', name: 'Distributor 4' },
{ id: 'A005', value: 'A005', name: 'Distributor 5' },
{ id: 'A006', value: 'A006', name: 'Distributor 6' },
{ id: 'A007', value: 'A007', name: 'Distributor 7' },
{ id: 'A008', value: 'A008', name: 'Distributor 8' },
{ id: 'A009', value: 'A009', name: 'Distributor 9' },
{ id: 'A010', value: 'A010', name: 'Distributor 10' },
{ id: 'A011', value: 'A011', name: 'Distributor 11' },
{ id: 'A012', value: 'A012', name: 'Distributor 12' },
{ id: 'A013', value: 'A013', name: 'Distributor 13' },
{ id: 'A014', value: 'A014', name: 'Distributor 14' },
{ id: 'A015', value: 'A015', name: 'Distributor 15' },
{ id: 'A016', value: 'A016', name: 'Distributor 16' },
{ id: 'A017', value: 'A017', name: 'Distributor 17' },
{ id: 'A018', value: 'A018', name: 'Distributor 18' },
{ id: 'A019', value: 'A019', name: 'Distributor 19' },
{
id: 'A001',
value: 'A001',
name: 'Distributor',
},
{
id: 'A002',
value: 'A002',
name: 'Distributor A',
},
{
id: 'A003',
value: 'A003',
name: 'Distributor B',
},
{
id: 'A004',
value: 'A004',
name: 'Distributor C',
},
{
id: 'A004',
value: 'A004',
name: 'Very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long',
id: 'A020',
value: 'A020',
name: 'Very long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long long',
},
];

Expand Down Expand Up @@ -231,3 +231,24 @@ export const Version2: Story = {
);
},
};

export const Version3: Story = {
args: {
mode: 'dark',
list,
placeholder: 'Please Select Item',
},
render: (args) => {
const [selectedId, setSelectedId] = useState<string | undefined>();

return (
<div>
<DropdownV3
{...args}
selectedId={selectedId}
onSelect={(value) => setSelectedId(value as string)}
/>
</div>
);
},
};
227 changes: 227 additions & 0 deletions src/components/Dropdown/DropdownV3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
import React, { useState, useEffect, useRef } from 'react';
import classNames from 'classnames';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp';
import { Popper as MuIPopper } from '@mui/material';
import { DropDownItem, DropDownProps } from './Dropdown.type';
import ClickAwayListener from '@mui/material/ClickAwayListener';
import Icon from '../Icon/Icon';
import CheckSvg from '../../assets/image/svg/check.svg';

const Root = styled(Box)(({ theme }) => ({
fontFamily: '"Noto Sans TC", "Noto Sans"',
fontSize: '0.875rem',
lineHeight: 1.5,
minWidth: 220,
height: 40,
userSelect: 'none',
cursor: 'pointer',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
color: theme.color.secondary.$80,
backgroundColor: '#FFF',
padding: '8px 0px 8px 16px',
borderRadius: 4,
// Ellipsis for selected text
'.Dropdown-selected-text': {
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
flex: 1,
minWidth: 0,
marginRight: 8,
display: 'block',
fontFamily: '"Noto Sans TC", "Noto Sans"',
fontSize: '0.875rem',
lineHeight: 1.5,
},
'&.dark': {
color: 'white',
backgroundColor: 'rgba(0, 0 ,0, 0.2)',
},
'&.Dropdown-empty': {
color: theme.color.secondary.$60,
'&.dark': {
color: theme.color.secondary.$80,
},
},
'&.Dropdown--disabled': {
opacity: 0.3,
pointerEvents: 'none',
},
}));

const List = styled(Box)(({ theme }) => ({
backgroundColor: '#FFF',
margin: '8px auto',
borderRadius: 4,
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.1)',
'&.dark': {
color: 'white',
backgroundColor: theme.color.secondary.$100,
},
}));

const Popper = styled(MuIPopper)(({ theme }) => ({
maxHeight: '200px',
overflow: 'auto',
}));

const Item = styled(Box, { label: 'Dropdown-item' })(({ theme }) => ({
fontFamily: '"Noto Sans TC", "Noto Sans"',
fontSize: '0.875rem',
lineHeight: 1.5,
cursor: 'pointer',
display: 'flex',
alignItems: 'center',

width: '100%', // Ensure item fills parent width
'&:hover': {
backgroundColor: 'rgba(0, 0, 0, .05)',
},

'.Dropdown-icon': {
width: 24,
minWidth: 24,
maxWidth: 24,
flexShrink: 0,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginRight: 8,
},
'.Dropdown-item-text': {
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
flex: 1,
minWidth: 0,
width: '100%', // Ensure text fills available space
fontFamily: '"Noto Sans TC", "Noto Sans"',
fontSize: '0.875rem',
lineHeight: 1.5,
},
}));

const DropdownV3: React.FC<DropDownProps> = (props) => {
const {
list,
itemProps,
placeholder,
selectedId,
disabled,
onSelect,
popperProps,
selectionId,
mode = 'light',
...otherProps
} = props;
const selectRef = useRef<HTMLDivElement>(null);
const [selectedItem, setSelectedItem] = useState<DropDownItem | null>(null);
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
if (selectedId && selectedId !== selectedItem?.id) {
for (let i = 0; i < list.length; i++) {
if (selectedId === list[i].id) {
setSelectedItem(list[i]);
break;
}
}
} else if (selectedId === undefined) {
setSelectedItem(null);
}
}, [selectedId]);

useEffect(() => {
for (let i = 0; i < list.length; i++) {
if (selectedId === list[i].id) {
setSelectedItem(list[i]);
break;
}
}
}, [list]);

const handleOnClickSelect = () => {
setIsOpen(true);
};

const handleOnClickAway = () => {
setIsOpen(false);
};

const handleOnClick = (item: DropDownItem) => {
setIsOpen(false);
onSelect(item.value, item);
};

const items = list
.filter((item) => item.id !== selectionId)
.map((item) => (
<Item
key={`dropdown-item-${item.id}`}
className="Dropdown-item"
onClick={() => handleOnClick(item)}
{...itemProps}
>
<Icon className="Dropdown-icon">
{selectedItem?.id === item.id && <img src={CheckSvg} />}
</Icon>
<span className="Dropdown-item-text">{item.name}</span>
</Item>
));

return (
<>
<Root
ref={selectRef}
className={classNames(
'Dropdown-root',
{
'Dropdown-empty': !selectedId,
},
{
'Dropdown--disabled': disabled,
},
{
dark: mode === 'dark',
light: mode === 'light',
},
)}
onClick={handleOnClickSelect}
{...otherProps}
>
<span className="Dropdown-selected-text">
{selectedItem?.name ?? placeholder}
</span>
<Icon className="Dropdown-icon">
{isOpen ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
</Icon>
</Root>
<Popper
anchorEl={selectRef.current}
open={isOpen}
placement="bottom"
className="Dropdown-popper"
{...popperProps}
>
<ClickAwayListener onClickAway={handleOnClickAway}>
<List
className={classNames({
dark: mode === 'dark',
light: mode === 'light',
})}
style={{ width: selectRef.current?.offsetWidth ?? 'auto' }}
>
{items}
</List>
</ClickAwayListener>
</Popper>
</>
);
};

export default DropdownV3;
20 changes: 20 additions & 0 deletions src/components/Tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import TooltipIcon from './TooltipIcon';

const meta: Meta<typeof TooltipIcon> = {
title: 'Components/TooltipIcon',
component: TooltipIcon,
};

export default meta;

type Story = StoryObj<typeof TooltipIcon>;
export const Default: Story = {
render: () => (
<TooltipIcon
title="TLorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur quia ipsam nobis modi nihil iusto ea nam voluptates error velit aliquid ex dolorum rerum reiciendis quaerat omnis, sint doloribus. Illo."
text="Tooltip text"
/>
),
};
Loading