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