wip: タブコンポーネントを追加
This commit is contained in:
parent
063781478b
commit
d03eeeb9f3
79
packages/frontend/src/components/primitives/Tab.tsx
Normal file
79
packages/frontend/src/components/primitives/Tab.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
import { styled } from '@/libs/stitches';
|
||||
|
||||
export type TabProp = {
|
||||
children: React.ReactElement<TabItem> | React.ReactElement<TabItem>[]
|
||||
value?: string;
|
||||
onChange?: (newValue: string) => void;
|
||||
};
|
||||
|
||||
export type TabItem = {
|
||||
value: string;
|
||||
children: string;
|
||||
};
|
||||
|
||||
export const TabItem: React.FC<TabItem> = (p: TabItem) => {
|
||||
return {
|
||||
props: p,
|
||||
key: null,
|
||||
type: null,
|
||||
};
|
||||
};
|
||||
|
||||
const Container = styled('div', {
|
||||
position: 'relative',
|
||||
});
|
||||
|
||||
const Ul = styled('ul', {
|
||||
display: 'flex',
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
});
|
||||
|
||||
const Li = styled('li', {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: '$m',
|
||||
margin: 0,
|
||||
borderBottom: '2px solid $muted',
|
||||
color: '$muted',
|
||||
|
||||
variants: {
|
||||
active: {
|
||||
true: {
|
||||
color: '$primary',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const Tab: React.FC<TabProp> = (p) => {
|
||||
const c = Array.isArray(p.children) ? p.children.map(c => c.props) : [p.children.props];
|
||||
const [value, setValue] = useState(c[0].value);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (!p.value) return;
|
||||
setValue(p.value);
|
||||
}, [p.value]);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Ul>
|
||||
{c.map(item => (
|
||||
<Li key={item.value} role="button" active={item.value === value} onClick={() => {
|
||||
if (item.value === value) return;
|
||||
console.log(item.value);
|
||||
setValue(item.value);
|
||||
p.onChange?.(item.value);
|
||||
}}>
|
||||
{item.children}
|
||||
</Li>
|
||||
))}
|
||||
</Ul>
|
||||
</Container>
|
||||
);
|
||||
};
|
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta } from '@storybook/react';
|
||||
|
||||
import { Tab, TabItem } from '@/components/primitives/Tab';
|
||||
|
||||
const meta = {
|
||||
component: Tab,
|
||||
parameters: {
|
||||
layouts: 'centered',
|
||||
},
|
||||
} satisfies Meta<typeof Tab>;
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Default = () => (
|
||||
<Tab>
|
||||
<TabItem value="home">ホーム</TabItem>
|
||||
<TabItem value="notification">通知</TabItem>
|
||||
<TabItem value="explore">みつける</TabItem>
|
||||
</Tab>
|
||||
);
|
Loading…
Reference in New Issue
Block a user