@charcoal-ui/react-sandbox 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +18 -0
- package/package.json +72 -0
- package/src/_lib/compat.ts +15 -0
- package/src/components/Carousel/index.story.tsx +86 -0
- package/src/components/Carousel/index.tsx +382 -0
- package/src/components/CarouselButton/index.story.tsx +44 -0
- package/src/components/CarouselButton/index.tsx +162 -0
- package/src/components/Filter/index.story.tsx +80 -0
- package/src/components/Filter/index.tsx +182 -0
- package/src/components/HintText/index.story.tsx +19 -0
- package/src/components/HintText/index.tsx +95 -0
- package/src/components/Layout/index.story.tsx +121 -0
- package/src/components/Layout/index.tsx +363 -0
- package/src/components/LeftMenu/index.tsx +68 -0
- package/src/components/MenuListItem/index.story.tsx +143 -0
- package/src/components/MenuListItem/index.tsx +226 -0
- package/src/components/Pager/index.story.tsx +102 -0
- package/src/components/Pager/index.tsx +255 -0
- package/src/components/Spinner/index.story.tsx +47 -0
- package/src/components/Spinner/index.tsx +86 -0
- package/src/components/SwitchCheckbox/index.story.tsx +32 -0
- package/src/components/SwitchCheckbox/index.tsx +147 -0
- package/src/components/TextEllipsis/helper.ts +57 -0
- package/src/components/TextEllipsis/index.story.tsx +41 -0
- package/src/components/TextEllipsis/index.tsx +35 -0
- package/src/components/WithIcon/index.story.tsx +145 -0
- package/src/components/WithIcon/index.tsx +158 -0
- package/src/components/icons/Base.tsx +75 -0
- package/src/components/icons/DotsIcon.tsx +33 -0
- package/src/components/icons/InfoIcon.tsx +30 -0
- package/src/components/icons/NextIcon.tsx +47 -0
- package/src/components/icons/WedgeIcon.tsx +57 -0
- package/src/foundation/contants.ts +6 -0
- package/src/foundation/hooks.ts +195 -0
- package/src/foundation/support.ts +29 -0
- package/src/foundation/utils.ts +31 -0
- package/src/index.ts +45 -0
- package/src/misc/storybook-helper.ts +17 -0
- package/src/styled.ts +3 -0
- package/src/type.d.ts +12 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import styled, { css } from 'styled-components'
|
|
3
|
+
import { useComponentAbstraction, LinkProps } from '@charcoal-ui/react'
|
|
4
|
+
import { maxWidth } from '@charcoal-ui/utils'
|
|
5
|
+
|
|
6
|
+
interface Props<T extends HTMLElement> {
|
|
7
|
+
active?: boolean
|
|
8
|
+
hover?: boolean
|
|
9
|
+
reactive?: boolean
|
|
10
|
+
children: React.ReactNode
|
|
11
|
+
onClick?: React.MouseEventHandler<T>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface FilterIconButtonProps extends Props<HTMLButtonElement> {
|
|
15
|
+
width?: number
|
|
16
|
+
height?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const FilterButton = React.forwardRef(function FilterButton(
|
|
20
|
+
{
|
|
21
|
+
onClick,
|
|
22
|
+
children,
|
|
23
|
+
active = false,
|
|
24
|
+
hover,
|
|
25
|
+
reactive = false,
|
|
26
|
+
}: Props<HTMLButtonElement>,
|
|
27
|
+
ref: React.Ref<HTMLButtonElement>
|
|
28
|
+
) {
|
|
29
|
+
return (
|
|
30
|
+
<ButtonLike
|
|
31
|
+
active={active}
|
|
32
|
+
reactive={reactive}
|
|
33
|
+
hover={hover}
|
|
34
|
+
onClick={active && !reactive ? undefined : onClick}
|
|
35
|
+
ref={ref}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</ButtonLike>
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export const FilterIconButton = React.forwardRef(function FilterIconButton(
|
|
43
|
+
{
|
|
44
|
+
onClick,
|
|
45
|
+
children,
|
|
46
|
+
active = false,
|
|
47
|
+
hover,
|
|
48
|
+
reactive = false,
|
|
49
|
+
width,
|
|
50
|
+
height,
|
|
51
|
+
}: FilterIconButtonProps,
|
|
52
|
+
ref: React.Ref<HTMLButtonElement>
|
|
53
|
+
) {
|
|
54
|
+
return (
|
|
55
|
+
<StyledButtonLike
|
|
56
|
+
active={active}
|
|
57
|
+
reactive={reactive}
|
|
58
|
+
hover={hover}
|
|
59
|
+
onClick={active && !reactive ? undefined : onClick}
|
|
60
|
+
ref={ref}
|
|
61
|
+
buttonWidth={width}
|
|
62
|
+
buttonHeight={height}
|
|
63
|
+
>
|
|
64
|
+
{children}
|
|
65
|
+
</StyledButtonLike>
|
|
66
|
+
)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
export const FilterLink = React.forwardRef(function FilterLink(
|
|
70
|
+
{
|
|
71
|
+
onClick,
|
|
72
|
+
children,
|
|
73
|
+
active = false,
|
|
74
|
+
hover,
|
|
75
|
+
reactive = false,
|
|
76
|
+
...props
|
|
77
|
+
}: Props<HTMLAnchorElement> & LinkProps,
|
|
78
|
+
ref: React.Ref<HTMLAnchorElement>
|
|
79
|
+
) {
|
|
80
|
+
const { Link } = useComponentAbstraction()
|
|
81
|
+
if (active && !reactive) {
|
|
82
|
+
return (
|
|
83
|
+
<PlainElement active hover={hover} ref={ref}>
|
|
84
|
+
{children}
|
|
85
|
+
</PlainElement>
|
|
86
|
+
)
|
|
87
|
+
} else {
|
|
88
|
+
return (
|
|
89
|
+
<Link {...props} onClick={onClick}>
|
|
90
|
+
<PlainElement
|
|
91
|
+
active={active}
|
|
92
|
+
reactive={reactive}
|
|
93
|
+
hover={hover}
|
|
94
|
+
ref={ref}
|
|
95
|
+
>
|
|
96
|
+
{children}
|
|
97
|
+
</PlainElement>
|
|
98
|
+
</Link>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
interface ButtonCssProps {
|
|
104
|
+
active?: boolean
|
|
105
|
+
hover?: boolean
|
|
106
|
+
reactive?: boolean
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const buttonCss = css`
|
|
110
|
+
display: block;
|
|
111
|
+
outline: none;
|
|
112
|
+
border: none;
|
|
113
|
+
padding: 9px 24px;
|
|
114
|
+
font-size: 14px;
|
|
115
|
+
line-height: 22px;
|
|
116
|
+
font-weight: bold;
|
|
117
|
+
border-radius: /* absurd radius, but ensures rounded corners */ 2000px;
|
|
118
|
+
transition: color 0.2s;
|
|
119
|
+
color: ${({ theme }) => theme.color.text3};
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
user-select: none;
|
|
122
|
+
background-color: transparent;
|
|
123
|
+
|
|
124
|
+
&:hover {
|
|
125
|
+
color: ${({ theme }) => theme.color.text2};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
${({ hover = false }: ButtonCssProps) =>
|
|
129
|
+
hover &&
|
|
130
|
+
css`
|
|
131
|
+
color: ${({ theme }) => theme.color.text2};
|
|
132
|
+
`}
|
|
133
|
+
|
|
134
|
+
${({ active = false }: ButtonCssProps) =>
|
|
135
|
+
active &&
|
|
136
|
+
css`
|
|
137
|
+
background-color: ${({ theme }) => theme.color.surface3};
|
|
138
|
+
color: ${({ theme }) => theme.color.text2};
|
|
139
|
+
`}
|
|
140
|
+
|
|
141
|
+
${({ active = false, reactive = false }) =>
|
|
142
|
+
active &&
|
|
143
|
+
!reactive &&
|
|
144
|
+
css`
|
|
145
|
+
cursor: default;
|
|
146
|
+
`}
|
|
147
|
+
|
|
148
|
+
@media ${({ theme }) => maxWidth(theme.breakpoint.screen1)} {
|
|
149
|
+
padding: 5px 16px;
|
|
150
|
+
}
|
|
151
|
+
`
|
|
152
|
+
|
|
153
|
+
const padding0Css = css`
|
|
154
|
+
padding: 0;
|
|
155
|
+
|
|
156
|
+
@media ${({ theme }) => maxWidth(theme.breakpoint.screen1)} {
|
|
157
|
+
padding: 0;
|
|
158
|
+
}
|
|
159
|
+
`
|
|
160
|
+
|
|
161
|
+
const ButtonLike = styled.button`
|
|
162
|
+
${buttonCss}
|
|
163
|
+
`
|
|
164
|
+
|
|
165
|
+
const PlainElement = styled.span`
|
|
166
|
+
${buttonCss}
|
|
167
|
+
`
|
|
168
|
+
|
|
169
|
+
const StyledButtonLike = styled(ButtonLike)<{
|
|
170
|
+
buttonWidth: number | undefined
|
|
171
|
+
buttonHeight: number | undefined
|
|
172
|
+
}>`
|
|
173
|
+
${padding0Css};
|
|
174
|
+
${(p) => p.buttonWidth !== undefined && `width: ${p.buttonWidth}px;`}
|
|
175
|
+
${(p) => p.buttonHeight !== undefined && `height: ${p.buttonHeight}px;`}
|
|
176
|
+
`
|
|
177
|
+
|
|
178
|
+
const Filter = styled.div`
|
|
179
|
+
display: flex;
|
|
180
|
+
`
|
|
181
|
+
|
|
182
|
+
export default Filter
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Story } from '../../_lib/compat'
|
|
3
|
+
import HintText from '.'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Sandbox/HintText',
|
|
7
|
+
component: HintText,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Template: Story<{ hintText: string; context: 'page' | 'section' }> = (
|
|
11
|
+
args
|
|
12
|
+
) => <HintText context={args.context}>{args.hintText}</HintText>
|
|
13
|
+
|
|
14
|
+
export const Default = Template.bind({})
|
|
15
|
+
Default.args = {
|
|
16
|
+
hintText:
|
|
17
|
+
'ヒントテキストだよおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお',
|
|
18
|
+
context: 'section',
|
|
19
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import styled, { css } from 'styled-components'
|
|
3
|
+
import { theme } from '../../styled'
|
|
4
|
+
import InfoIcon from '../icons/InfoIcon'
|
|
5
|
+
import { maxWidth } from '@charcoal-ui/utils'
|
|
6
|
+
|
|
7
|
+
type Context = 'page' | 'section'
|
|
8
|
+
interface Props {
|
|
9
|
+
children: React.ReactNode
|
|
10
|
+
context: Context
|
|
11
|
+
className?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default function HintText({ children, context, className }: Props) {
|
|
15
|
+
return (
|
|
16
|
+
<Container className={className} context={context}>
|
|
17
|
+
<IconWrap>
|
|
18
|
+
<InfoIcon />
|
|
19
|
+
</IconWrap>
|
|
20
|
+
<Text>{children}</Text>
|
|
21
|
+
</Container>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const Container = styled.div.attrs<Props, ReturnType<typeof styledProps>>(
|
|
26
|
+
styledProps
|
|
27
|
+
)`
|
|
28
|
+
${(p) =>
|
|
29
|
+
theme((o) => [
|
|
30
|
+
o.bg.surface3,
|
|
31
|
+
o.borderRadius(8),
|
|
32
|
+
o.padding.vertical(p.default.vertical),
|
|
33
|
+
o.padding.horizontal(p.default.horizontal),
|
|
34
|
+
])}
|
|
35
|
+
|
|
36
|
+
@media ${({ theme: t }) => maxWidth(t.breakpoint.screen1)} {
|
|
37
|
+
${(p) =>
|
|
38
|
+
theme((o) => [
|
|
39
|
+
o.padding.vertical(p.screen1.vertical),
|
|
40
|
+
o.padding.horizontal(p.screen1.horizontal),
|
|
41
|
+
])}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: flex-start;
|
|
46
|
+
${(p) =>
|
|
47
|
+
p.context === 'page' &&
|
|
48
|
+
css`
|
|
49
|
+
justify-content: center;
|
|
50
|
+
`}
|
|
51
|
+
`
|
|
52
|
+
|
|
53
|
+
const IconWrap = styled.div`
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
color: ${(p) => p.theme.color.text4};
|
|
57
|
+
height: 22px;
|
|
58
|
+
margin: -4px 4px -4px 0;
|
|
59
|
+
`
|
|
60
|
+
|
|
61
|
+
const Text = styled.p`
|
|
62
|
+
${theme((o) => [o.font.text2, o.typography(14)])}
|
|
63
|
+
margin: 0;
|
|
64
|
+
`
|
|
65
|
+
|
|
66
|
+
function styledProps(props: Props) {
|
|
67
|
+
return { ...props, ...contextToProps(props.context) }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function contextToProps(context: Context) {
|
|
71
|
+
switch (context) {
|
|
72
|
+
case 'page':
|
|
73
|
+
return {
|
|
74
|
+
default: {
|
|
75
|
+
horizontal: 40,
|
|
76
|
+
vertical: 24,
|
|
77
|
+
},
|
|
78
|
+
screen1: {
|
|
79
|
+
horizontal: 16,
|
|
80
|
+
vertical: 16,
|
|
81
|
+
},
|
|
82
|
+
} as const
|
|
83
|
+
case 'section':
|
|
84
|
+
return {
|
|
85
|
+
default: {
|
|
86
|
+
horizontal: 16,
|
|
87
|
+
vertical: 16,
|
|
88
|
+
},
|
|
89
|
+
screen1: {
|
|
90
|
+
horizontal: 16,
|
|
91
|
+
vertical: 16,
|
|
92
|
+
},
|
|
93
|
+
} as const
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import styled from 'styled-components'
|
|
3
|
+
import { dummyText } from '../../misc/storybook-helper'
|
|
4
|
+
import { theme } from '../../styled'
|
|
5
|
+
import LeftMenu from '../LeftMenu'
|
|
6
|
+
import Layout, { LayoutItem, LayoutItemBody, LayoutItemHeader } from '.'
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
title: 'Sandbox/Layout',
|
|
10
|
+
component: Layout,
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'fullscreen',
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function Basic() {
|
|
17
|
+
const menu = <DummyMenu />
|
|
18
|
+
const header = <>Header</>
|
|
19
|
+
return (
|
|
20
|
+
<Layout menu={menu} header={header}>
|
|
21
|
+
<DummyCard span={3}>Span 3</DummyCard>
|
|
22
|
+
<DummyCard span={2}>Span 2</DummyCard>
|
|
23
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
24
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
25
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
26
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
27
|
+
</Layout>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function NoMenu() {
|
|
32
|
+
const header = <>Header</>
|
|
33
|
+
return (
|
|
34
|
+
<Layout header={header}>
|
|
35
|
+
<DummyCard span={3}>Span 3</DummyCard>
|
|
36
|
+
<DummyCard span={2}>Span 2</DummyCard>
|
|
37
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
38
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
39
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
40
|
+
<DummyCard span={1}>Span 1</DummyCard>
|
|
41
|
+
</Layout>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function Wide() {
|
|
46
|
+
const menu = <DummyMenu />
|
|
47
|
+
const header = <>Header</>
|
|
48
|
+
return (
|
|
49
|
+
<Layout menu={menu} header={header} wide>
|
|
50
|
+
<LayoutItem span={3}>
|
|
51
|
+
<LayoutItemHeader>Wide</LayoutItemHeader>
|
|
52
|
+
<LayoutItemBody>
|
|
53
|
+
<Dummy>Hello, Flexible Grid Layout!</Dummy>
|
|
54
|
+
</LayoutItemBody>
|
|
55
|
+
</LayoutItem>
|
|
56
|
+
</Layout>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function Center() {
|
|
61
|
+
const header = <>Header</>
|
|
62
|
+
return (
|
|
63
|
+
<Layout header={header} wide center>
|
|
64
|
+
<LayoutItem span={3}>
|
|
65
|
+
<LayoutItemHeader>Center</LayoutItemHeader>
|
|
66
|
+
<LayoutItemBody>
|
|
67
|
+
<Dummy>Hello, Flexible Grid Layout!</Dummy>
|
|
68
|
+
</LayoutItemBody>
|
|
69
|
+
</LayoutItem>
|
|
70
|
+
</Layout>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function DummyCard({
|
|
75
|
+
span,
|
|
76
|
+
children,
|
|
77
|
+
}: {
|
|
78
|
+
span: number
|
|
79
|
+
children: React.ReactNode
|
|
80
|
+
}) {
|
|
81
|
+
return (
|
|
82
|
+
<LayoutItem span={span}>
|
|
83
|
+
<LayoutItemHeader>Dummy</LayoutItemHeader>
|
|
84
|
+
<LayoutItemBody>
|
|
85
|
+
<Dummy>{children}</Dummy>
|
|
86
|
+
</LayoutItemBody>
|
|
87
|
+
</LayoutItem>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const Dummy = styled.div`
|
|
92
|
+
${theme((o) => o.height.column(2))}
|
|
93
|
+
|
|
94
|
+
${dummyText}
|
|
95
|
+
`
|
|
96
|
+
|
|
97
|
+
function DummyMenu() {
|
|
98
|
+
const links = [
|
|
99
|
+
{
|
|
100
|
+
id: 'hello',
|
|
101
|
+
text: 'Hello',
|
|
102
|
+
to: '#hello',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: 'world',
|
|
106
|
+
text: 'World',
|
|
107
|
+
to: '#world',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'dummy',
|
|
111
|
+
text: 'Dummy',
|
|
112
|
+
to: '#dummy',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'menu',
|
|
116
|
+
text: 'Menu',
|
|
117
|
+
to: '#menu',
|
|
118
|
+
},
|
|
119
|
+
] as const
|
|
120
|
+
return <LeftMenu links={links} active="hello" />
|
|
121
|
+
}
|