jp.ui.app.ds 1.0.0
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/.storybook/main.ts +31 -0
- package/.storybook/preview.tsx +38 -0
- package/package.json +41 -0
- package/rollup.config.js +31 -0
- package/src/index.ts +1 -0
- package/src/matherial3/button/common-button.style.ts +35 -0
- package/src/matherial3/button/common-button.tsx +40 -0
- package/src/matherial3/button/filled-button.stories.ts +33 -0
- package/src/matherial3/button/filled-button.tsx +20 -0
- package/src/matherial3/button/index.ts +9 -0
- package/src/matherial3/button/outlined-button.stories.ts +33 -0
- package/src/matherial3/button/outlined-button.tsx +18 -0
- package/src/matherial3/button/text-button.stories.ts +33 -0
- package/src/matherial3/button/text-button.tsx +17 -0
- package/src/matherial3/checkbox/checkbox.stories.ts +29 -0
- package/src/matherial3/checkbox/checkbox.style.tsx +53 -0
- package/src/matherial3/checkbox/checkbox.tsx +49 -0
- package/src/matherial3/checkbox/index.ts +5 -0
- package/src/matherial3/helpers/backdrop/backdrop.style.ts +14 -0
- package/src/matherial3/helpers/backdrop/backdrop.tsx +9 -0
- package/src/matherial3/helpers/backdrop/index.ts +5 -0
- package/src/matherial3/helpers/index.ts +19 -0
- package/src/matherial3/helpers/no-style-button/index.ts +5 -0
- package/src/matherial3/helpers/no-style-button/no-style-button.style.ts +12 -0
- package/src/matherial3/helpers/outside-click.ts +17 -0
- package/src/matherial3/helpers/popup/index.ts +1 -0
- package/src/matherial3/helpers/popup/popup.style.tsx +14 -0
- package/src/matherial3/helpers/popup/popup.tsx +17 -0
- package/src/matherial3/helpers/stack/column-center.tsx +22 -0
- package/src/matherial3/helpers/stack/column-left.tsx +22 -0
- package/src/matherial3/helpers/stack/index.ts +13 -0
- package/src/matherial3/helpers/stack/row-center.tsx +19 -0
- package/src/matherial3/helpers/stack/row-start.tsx +20 -0
- package/src/matherial3/helpers/stack/stack.tsx +16 -0
- package/src/matherial3/helpers/svg-icon/index.ts +5 -0
- package/src/matherial3/helpers/svg-icon/svg-icon.tsx +46 -0
- package/src/matherial3/index.ts +2 -0
- package/src/matherial3/typography/body.tsx +19 -0
- package/src/matherial3/typography/display.tsx +19 -0
- package/src/matherial3/typography/headline.tsx +19 -0
- package/src/matherial3/typography/index.ts +13 -0
- package/src/matherial3/typography/label.tsx +19 -0
- package/src/matherial3/typography/m3-typography.tsx +45 -0
- package/src/matherial3/typography/title.tsx +19 -0
- package/src/matherial3/typography/typography-size.ts +1 -0
- package/tsconfig.json +30 -0
- package/types/emotion.d.ts +12 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { StorybookConfig } from '@storybook/react-webpack5';
|
|
2
|
+
|
|
3
|
+
const config: StorybookConfig = {
|
|
4
|
+
stories: [
|
|
5
|
+
"../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
|
|
6
|
+
],
|
|
7
|
+
addons: [
|
|
8
|
+
"@storybook/addon-webpack5-compiler-swc",
|
|
9
|
+
"@storybook/addon-docs",
|
|
10
|
+
"@storybook/addon-themes",
|
|
11
|
+
],
|
|
12
|
+
framework: {
|
|
13
|
+
name: "@storybook/react-webpack5",
|
|
14
|
+
options: {}
|
|
15
|
+
},
|
|
16
|
+
webpackFinal: config => {
|
|
17
|
+
// remove svg from existing rule
|
|
18
|
+
const fileLoaderRule = config.module.rules.find(
|
|
19
|
+
(rule) => rule.test && rule.test.test('.svg')
|
|
20
|
+
)
|
|
21
|
+
fileLoaderRule.exclude = /\.svg$/
|
|
22
|
+
|
|
23
|
+
config.module.rules.push({
|
|
24
|
+
test: /\.svg$/,
|
|
25
|
+
use: ['@svgr/webpack'],
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
return config
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
export default config;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Preview } from '@storybook/react-webpack5';
|
|
2
|
+
import { Global, css, ThemeProvider } from '@emotion/react';
|
|
3
|
+
import { withThemeFromJSXProvider } from '@storybook/addon-themes';
|
|
4
|
+
import { ColorSchema, getDarkTheme, getLightTheme } from '@choochoochoo/jp.theme';
|
|
5
|
+
|
|
6
|
+
const GlobalStyles = () => (
|
|
7
|
+
<Global
|
|
8
|
+
styles={css`
|
|
9
|
+
body {
|
|
10
|
+
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
11
|
+
}
|
|
12
|
+
`}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const preview: Preview = {
|
|
17
|
+
parameters: {
|
|
18
|
+
controls: {
|
|
19
|
+
matchers: {
|
|
20
|
+
color: /(background|color)$/i,
|
|
21
|
+
date: /Date$/i,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
decorators: [
|
|
26
|
+
withThemeFromJSXProvider({
|
|
27
|
+
themes: {
|
|
28
|
+
light: getLightTheme<object>(ColorSchema.DEFAULT, {}),
|
|
29
|
+
dark: getDarkTheme<object>('color_schema__default', {}),
|
|
30
|
+
},
|
|
31
|
+
defaultTheme: 'light',
|
|
32
|
+
Provider: ThemeProvider,
|
|
33
|
+
GlobalStyles,
|
|
34
|
+
})
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default preview;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jp.ui.app.ds",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
10
|
+
"dev": "storybook dev -p 6006",
|
|
11
|
+
"build:storybook": "storybook build",
|
|
12
|
+
"build": "rollup -c"
|
|
13
|
+
},
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@emotion/react": "11.14.0",
|
|
18
|
+
"@emotion/styled": "11.14.1",
|
|
19
|
+
"@rollup/plugin-commonjs": "28.0.8",
|
|
20
|
+
"@rollup/plugin-terser": "0.4.4",
|
|
21
|
+
"@rollup/plugin-typescript": "12.2.0",
|
|
22
|
+
"@storybook/addon-docs": "9.1.13",
|
|
23
|
+
"@storybook/addon-themes": "9.1.13",
|
|
24
|
+
"@storybook/addon-webpack5-compiler-swc": "4.0.1",
|
|
25
|
+
"@storybook/react-webpack5": "9.1.13",
|
|
26
|
+
"@svgr/rollup": "8.1.0",
|
|
27
|
+
"@svgr/webpack": "8.1.0",
|
|
28
|
+
"@types/node": "24.9.1",
|
|
29
|
+
"@types/react": "19.2.2",
|
|
30
|
+
"react": "^19.2.0",
|
|
31
|
+
"react-dom": "^19.2.0",
|
|
32
|
+
"rollup": "4.52.5",
|
|
33
|
+
"rollup-plugin-dts": "6.2.3",
|
|
34
|
+
"storybook": "9.1.13",
|
|
35
|
+
"typescript": "5.9.3"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@choochoochoo/jp.theme": "1.0.0",
|
|
39
|
+
"@material-design-icons/svg": "0.14.15"
|
|
40
|
+
}
|
|
41
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
2
|
+
import typescript from '@rollup/plugin-typescript';
|
|
3
|
+
import { dts } from 'rollup-plugin-dts';
|
|
4
|
+
import terser from '@rollup/plugin-terser';
|
|
5
|
+
import svgr from '@svgr/rollup'
|
|
6
|
+
|
|
7
|
+
const config = [
|
|
8
|
+
{
|
|
9
|
+
input: 'src/index.ts',
|
|
10
|
+
output: [
|
|
11
|
+
{
|
|
12
|
+
file: 'dist/index.js',
|
|
13
|
+
format: 'es',
|
|
14
|
+
sourcemap: true,
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
plugins: [
|
|
18
|
+
commonjs(),
|
|
19
|
+
typescript(),
|
|
20
|
+
svgr(),
|
|
21
|
+
// terser(),
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
input: './dist/index.d.ts',
|
|
26
|
+
output: [{ file: 'dist/index.d.ts', format: 'es' }],
|
|
27
|
+
plugins: [dts()],
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
export default config;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './matherial3';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
|
|
3
|
+
import { NoStyleButton } from '../helpers/no-style-button';
|
|
4
|
+
|
|
5
|
+
export const filled_button_border_radius = 100;
|
|
6
|
+
|
|
7
|
+
type CommonButtonStyledProps = {
|
|
8
|
+
borderColor?: string;
|
|
9
|
+
backgroundColor?: string;
|
|
10
|
+
hoverColor?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const CommonButtonStyled = styled(NoStyleButton)<CommonButtonStyledProps>`
|
|
14
|
+
background-color: ${({ backgroundColor }: { backgroundColor?: string }) => backgroundColor ?? 'transparent'};
|
|
15
|
+
border: 1px solid ${({ borderColor }: CommonButtonStyledProps) => borderColor ?? 'transparent'};
|
|
16
|
+
border-radius: ${filled_button_border_radius}px;
|
|
17
|
+
padding: 10px 24px;
|
|
18
|
+
position: relative;
|
|
19
|
+
|
|
20
|
+
:hover {
|
|
21
|
+
::before {
|
|
22
|
+
left: 0;
|
|
23
|
+
bottom: 0;
|
|
24
|
+
content: "\\00a0";
|
|
25
|
+
position: absolute;
|
|
26
|
+
right: 0;
|
|
27
|
+
pointer-events: none;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
30
|
+
background-color: ${({ hoverColor }: { hoverColor?: string }) => hoverColor};
|
|
31
|
+
opacity: 0.08;
|
|
32
|
+
border-radius: ${filled_button_border_radius}px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useTheme, Theme } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
import { Label } from '../typography';
|
|
5
|
+
|
|
6
|
+
import { CommonButtonStyled } from './common-button.style';
|
|
7
|
+
|
|
8
|
+
export type CommonTypeStyle = {
|
|
9
|
+
text: string;
|
|
10
|
+
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
|
|
11
|
+
className?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
textColor?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type componentTypeStyle = CommonTypeStyle & {
|
|
17
|
+
backgroundColor?: string;
|
|
18
|
+
textColor: string;
|
|
19
|
+
borderColor?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const CommonButton = ({ text, onClick, className, backgroundColor, textColor, borderColor, disabled }: componentTypeStyle) => {
|
|
23
|
+
const theme = useTheme() as Theme;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<CommonButtonStyled
|
|
27
|
+
title={text}
|
|
28
|
+
onClick={onClick}
|
|
29
|
+
className={className}
|
|
30
|
+
backgroundColor={backgroundColor}
|
|
31
|
+
borderColor={borderColor}
|
|
32
|
+
hoverColor={theme.m3Schema.onPrimaryContainer}
|
|
33
|
+
disabled={disabled}
|
|
34
|
+
>
|
|
35
|
+
<Label color={textColor} size="lg">
|
|
36
|
+
{text}
|
|
37
|
+
</Label>
|
|
38
|
+
</CommonButtonStyled>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { fn } from 'storybook/test';
|
|
3
|
+
|
|
4
|
+
import { FilledButton } from './filled-button';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'm3/button/FilledButton',
|
|
8
|
+
component: FilledButton,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
argTypes: {
|
|
14
|
+
text: 'text',
|
|
15
|
+
},
|
|
16
|
+
args: { onClick: fn() },
|
|
17
|
+
} satisfies Meta<typeof FilledButton>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
text: 'Button',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Disabled: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
text: 'disabled',
|
|
31
|
+
disabled: true,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useTheme, Theme } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
import { CommonButton, CommonTypeStyle } from './common-button';
|
|
5
|
+
|
|
6
|
+
export const FilledButton = ({ text, onClick, className, disabled }: CommonTypeStyle) => {
|
|
7
|
+
const theme = useTheme() as Theme;
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<CommonButton
|
|
11
|
+
text={text}
|
|
12
|
+
onClick={onClick}
|
|
13
|
+
backgroundColor={disabled ? `${theme.m3Schema.onSurface}1f` : theme.m3Schema.primary}
|
|
14
|
+
borderColor={disabled ? 'transparent' : theme.m3Schema.primary}
|
|
15
|
+
textColor={disabled ? `${theme.m3Schema.onSurface}b0` : theme.m3Schema.onPrimary}
|
|
16
|
+
className={className}
|
|
17
|
+
disabled={disabled}
|
|
18
|
+
/>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { fn } from 'storybook/test';
|
|
3
|
+
|
|
4
|
+
import { OutlinedButton } from './outlined-button';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'm3/button/OutlinedButton',
|
|
8
|
+
component: OutlinedButton,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
argTypes: {
|
|
14
|
+
text: 'text',
|
|
15
|
+
},
|
|
16
|
+
args: { onClick: fn() },
|
|
17
|
+
} satisfies Meta<typeof OutlinedButton>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
text: 'default',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Disabled: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
text: 'disabled',
|
|
31
|
+
disabled: true,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useTheme, Theme } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
import { CommonButton, CommonTypeStyle } from './common-button';
|
|
5
|
+
|
|
6
|
+
export const OutlinedButton = ({ text, onClick, className }: CommonTypeStyle) => {
|
|
7
|
+
const theme = useTheme() as Theme;
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<CommonButton
|
|
11
|
+
text={text}
|
|
12
|
+
onClick={onClick}
|
|
13
|
+
textColor={theme.m3Schema.primary}
|
|
14
|
+
borderColor={theme.m3Schema.outline}
|
|
15
|
+
className={className}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { fn } from 'storybook/test';
|
|
3
|
+
|
|
4
|
+
import { TextButton } from './text-button';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'm3/button/TextButton',
|
|
8
|
+
component: TextButton,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
argTypes: {
|
|
14
|
+
text: 'text',
|
|
15
|
+
},
|
|
16
|
+
args: { onClick: fn() },
|
|
17
|
+
} satisfies Meta<typeof TextButton>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
text: 'Button',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const Disabled: Story = {
|
|
29
|
+
args: {
|
|
30
|
+
text: 'disabled',
|
|
31
|
+
disabled: true,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useTheme, Theme } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
import { CommonButton, CommonTypeStyle } from './common-button';
|
|
5
|
+
|
|
6
|
+
export const TextButton = ({ text, onClick, className, textColor }: CommonTypeStyle) => {
|
|
7
|
+
const theme = useTheme() as Theme;
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<CommonButton
|
|
11
|
+
text={text}
|
|
12
|
+
onClick={onClick}
|
|
13
|
+
textColor={textColor ?? theme.m3Schema.primary}
|
|
14
|
+
className={className}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-webpack5';
|
|
2
|
+
import { fn } from 'storybook/test';
|
|
3
|
+
|
|
4
|
+
import { Checkbox } from './checkbox';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'm3/Checkbox',
|
|
8
|
+
component: Checkbox,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered',
|
|
11
|
+
},
|
|
12
|
+
tags: ['autodocs'],
|
|
13
|
+
args: { onChange: fn(), checked: false },
|
|
14
|
+
} satisfies Meta<typeof Checkbox>;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
checked: false,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Checked: Story = {
|
|
26
|
+
args: {
|
|
27
|
+
checked: true,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
import { Theme } from '@emotion/react';
|
|
3
|
+
import { SvgIcon } from '../helpers';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export const CheckboxRootWrapper = styled.div`
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
position: relative;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
-webkit-tap-highlight-color: transparent;
|
|
13
|
+
background-color: transparent;
|
|
14
|
+
outline: 0;
|
|
15
|
+
border: 0;
|
|
16
|
+
margin: 0;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
user-select: none;
|
|
19
|
+
vertical-align: middle;
|
|
20
|
+
appearance: none;
|
|
21
|
+
text-decoration: none;
|
|
22
|
+
border-radius: 50%;
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
export const CheckboxCheckedIcon = styled(SvgIcon)`
|
|
26
|
+
svg {
|
|
27
|
+
path {
|
|
28
|
+
fill: ${({ theme }: { theme?: Theme }) => theme?.m3Schema.onSurfaceVariant};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
export const CheckboxUncheckedIcon = styled(SvgIcon)`
|
|
34
|
+
svg {
|
|
35
|
+
path {
|
|
36
|
+
fill: ${({ theme }: { theme?: Theme }) => theme?.m3Schema.onSurfaceVariant};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
export const CheckboxInput = styled.input`
|
|
42
|
+
cursor: inherit;
|
|
43
|
+
position: absolute;
|
|
44
|
+
opacity: 0;
|
|
45
|
+
width: 100%;
|
|
46
|
+
height: 100%;
|
|
47
|
+
top: 0;
|
|
48
|
+
left: 0;
|
|
49
|
+
margin: 0;
|
|
50
|
+
padding: 0;
|
|
51
|
+
z-index: 1;
|
|
52
|
+
`;
|
|
53
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import CheckBoxIcon from '@material-design-icons/svg/filled/check_box.svg';
|
|
4
|
+
import CheckBoxOutlineBlankIcon from '@material-design-icons/svg/filled/check_box_outline_blank.svg';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CheckboxRootWrapper,
|
|
8
|
+
CheckboxInput,
|
|
9
|
+
CheckboxUncheckedIcon,
|
|
10
|
+
CheckboxCheckedIcon,
|
|
11
|
+
} from './checkbox.style';
|
|
12
|
+
|
|
13
|
+
export type CheckboxProps = {
|
|
14
|
+
checked: boolean;
|
|
15
|
+
onChange?: (checked: boolean) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const Checkbox = ({ checked, onChange }: CheckboxProps) => {
|
|
19
|
+
return (
|
|
20
|
+
<div>
|
|
21
|
+
<CheckboxRootWrapper>
|
|
22
|
+
<CheckboxInput
|
|
23
|
+
type="checkbox"
|
|
24
|
+
checked={checked}
|
|
25
|
+
onChange={useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
|
26
|
+
if (onChange) {
|
|
27
|
+
onChange(event.target.checked);
|
|
28
|
+
}
|
|
29
|
+
}, [onChange])}
|
|
30
|
+
/>
|
|
31
|
+
{
|
|
32
|
+
checked ? (
|
|
33
|
+
<CheckboxCheckedIcon
|
|
34
|
+
width={24}
|
|
35
|
+
height={24}
|
|
36
|
+
icon={CheckBoxIcon}
|
|
37
|
+
/>
|
|
38
|
+
) : (
|
|
39
|
+
<CheckboxUncheckedIcon
|
|
40
|
+
width={24}
|
|
41
|
+
height={24}
|
|
42
|
+
icon={CheckBoxOutlineBlankIcon}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
</CheckboxRootWrapper>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
|
|
3
|
+
export const BackdropStyled = styled.div`
|
|
4
|
+
background-color: ${({ theme }) => theme.m3Schema.scrim}85;
|
|
5
|
+
position: fixed;
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
top: 0;
|
|
10
|
+
left: 0;
|
|
11
|
+
right: 0;
|
|
12
|
+
bottoM: 0;
|
|
13
|
+
z-index: -1;
|
|
14
|
+
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Backdrop } from './backdrop';
|
|
2
|
+
import { NoStyleButton } from './no-style-button';
|
|
3
|
+
import { Popup } from './popup';
|
|
4
|
+
import { ColumnLeft, ColumnCenter, RowCenter, RowStart, Stack} from './stack';
|
|
5
|
+
import { useOutsideClick } from './outside-click';
|
|
6
|
+
import { SvgIcon } from './svg-icon';
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
Backdrop,
|
|
10
|
+
NoStyleButton,
|
|
11
|
+
Popup,
|
|
12
|
+
ColumnLeft,
|
|
13
|
+
ColumnCenter,
|
|
14
|
+
RowCenter,
|
|
15
|
+
RowStart,
|
|
16
|
+
Stack,
|
|
17
|
+
useOutsideClick,
|
|
18
|
+
SvgIcon,
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
|
|
3
|
+
export const NoStyleButton = styled.button`
|
|
4
|
+
background-color: transparent;
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
border: none;
|
|
7
|
+
padding: 0;
|
|
8
|
+
margin: 0;
|
|
9
|
+
-webkit-tap-highlight-color: transparent;
|
|
10
|
+
appearance: none;
|
|
11
|
+
user-select: none;
|
|
12
|
+
`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MutableRefObject, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
export const useOutsideClick = (ref: MutableRefObject<HTMLElement | undefined | null>, callback: (event: MouseEvent) => void) => {
|
|
4
|
+
const handleClickOutside = (event: DocumentEventMap['mousedown']) => {
|
|
5
|
+
const target = event.target as HTMLElement;
|
|
6
|
+
if (ref.current && !ref.current?.contains(target)) {
|
|
7
|
+
callback(event);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
13
|
+
return () => {
|
|
14
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Popup } from './popup';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
|
|
3
|
+
export type PopupStyleType = {
|
|
4
|
+
zIndex: number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const PopupStyle = styled.div`
|
|
8
|
+
position: fixed;
|
|
9
|
+
z-index: ${({ zIndex }: PopupStyleType) => zIndex};
|
|
10
|
+
top: 0;
|
|
11
|
+
left: 0;
|
|
12
|
+
right: 0;
|
|
13
|
+
bottoM: 0;
|
|
14
|
+
`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { PopupStyle } from './popup.style';
|
|
4
|
+
|
|
5
|
+
type componentType = {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
zIndex: number;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Popup = ({ children, zIndex, className }: componentType) => {
|
|
12
|
+
return (
|
|
13
|
+
<PopupStyle zIndex={zIndex} className={className}>
|
|
14
|
+
{children}
|
|
15
|
+
</PopupStyle>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { SerializedStyles } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
import { Stack } from './stack';
|
|
5
|
+
|
|
6
|
+
type componentType = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
css?: SerializedStyles;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ColumnCenter = ({ children, css }: componentType) => {
|
|
12
|
+
return (
|
|
13
|
+
<Stack
|
|
14
|
+
direction="column"
|
|
15
|
+
alignItems="center"
|
|
16
|
+
justifyContent="center"
|
|
17
|
+
css={css}
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</Stack>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { SerializedStyles } from '@emotion/react';
|
|
3
|
+
|
|
4
|
+
import { Stack } from './stack';
|
|
5
|
+
|
|
6
|
+
type componentType = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
css?: SerializedStyles;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ColumnLeft = ({ children, css }: componentType) => {
|
|
12
|
+
return (
|
|
13
|
+
<Stack
|
|
14
|
+
direction="column"
|
|
15
|
+
alignItems="start"
|
|
16
|
+
justifyContent="center"
|
|
17
|
+
css={css}
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</Stack>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ColumnLeft } from './column-left';
|
|
2
|
+
import { ColumnCenter } from './column-center';
|
|
3
|
+
import { RowCenter } from './row-center';
|
|
4
|
+
import { RowStart } from './row-start';
|
|
5
|
+
import { Stack } from './stack';
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
ColumnLeft,
|
|
9
|
+
ColumnCenter,
|
|
10
|
+
RowCenter,
|
|
11
|
+
RowStart,
|
|
12
|
+
Stack,
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Stack } from './stack';
|
|
4
|
+
|
|
5
|
+
type componentType = {
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const RowCenter = ({ children }: componentType) => {
|
|
10
|
+
return (
|
|
11
|
+
<Stack
|
|
12
|
+
direction="row"
|
|
13
|
+
alignItems="center"
|
|
14
|
+
justifyContent="center"
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</Stack>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Stack } from './stack';
|
|
5
|
+
|
|
6
|
+
type componentType = {
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const RowStart = ({ children }: componentType) => {
|
|
11
|
+
return (
|
|
12
|
+
<Stack
|
|
13
|
+
direction="row"
|
|
14
|
+
alignItems="start"
|
|
15
|
+
justifyContent="center"
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</Stack>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import styled from '@emotion/styled';
|
|
2
|
+
|
|
3
|
+
type componentType = {
|
|
4
|
+
direction: 'row' | 'column'
|
|
5
|
+
justifyContent: 'start' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'end'
|
|
6
|
+
alignItems: 'stretch' | 'center' | 'start' | 'end'
|
|
7
|
+
gap?: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Stack = styled.div`
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: ${({ direction }: componentType) => direction};
|
|
13
|
+
justify-content: ${({ justifyContent }: componentType) => justifyContent};
|
|
14
|
+
align-items: ${({ alignItems }: componentType) => alignItems};
|
|
15
|
+
gap: ${({ gap }: componentType) => gap ? `${gap}px` : 'initial'};
|
|
16
|
+
`;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
|
|
4
|
+
type componentTypeStyle = {
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
color?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const SvgIconStyle = styled.div`
|
|
12
|
+
display: flex;
|
|
13
|
+
width: ${({ width }: componentTypeStyle) => width}px;
|
|
14
|
+
height: ${({ height }: componentTypeStyle) => height}px;
|
|
15
|
+
|
|
16
|
+
svg {
|
|
17
|
+
width: ${({ width }: componentTypeStyle) => width}px;
|
|
18
|
+
height: ${({ height }: componentTypeStyle) => height}px;
|
|
19
|
+
}
|
|
20
|
+
path {
|
|
21
|
+
fill: ${({ color }: componentTypeStyle) => color};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
circle {
|
|
25
|
+
fill: ${({ color }: componentTypeStyle) => color};
|
|
26
|
+
};
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
type componentType = {
|
|
30
|
+
icon: string;
|
|
31
|
+
} & componentTypeStyle;
|
|
32
|
+
|
|
33
|
+
export const SvgIcon = ({ icon, width, height, color, className }: componentType) => {
|
|
34
|
+
const Icon = icon;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<SvgIconStyle
|
|
38
|
+
width={width}
|
|
39
|
+
height={height}
|
|
40
|
+
color={color}
|
|
41
|
+
className={className}
|
|
42
|
+
>
|
|
43
|
+
<Icon />
|
|
44
|
+
</SvgIconStyle>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { TextStyle, TypographyProps } from './m3-typography';
|
|
5
|
+
|
|
6
|
+
export const Body = ({ size, color, children, className }: TypographyProps) => {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TextStyle
|
|
11
|
+
className={className}
|
|
12
|
+
body={theme.m3TextStyle.body}
|
|
13
|
+
size={size}
|
|
14
|
+
color={color}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</TextStyle>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { TextStyle, TypographyProps } from './m3-typography';
|
|
5
|
+
|
|
6
|
+
export const Display = ({ size, color, children, className }: TypographyProps) => {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TextStyle
|
|
11
|
+
className={className}
|
|
12
|
+
body={theme.m3TextStyle.display}
|
|
13
|
+
size={size}
|
|
14
|
+
color={color}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</TextStyle>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { TextStyle, TypographyProps } from './m3-typography';
|
|
5
|
+
|
|
6
|
+
export const Headline = ({ size, color, children, className }: TypographyProps) => {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TextStyle
|
|
11
|
+
className={className}
|
|
12
|
+
body={theme.m3TextStyle.headline}
|
|
13
|
+
size={size}
|
|
14
|
+
color={color}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</TextStyle>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { TextStyle, TypographyProps } from './m3-typography';
|
|
5
|
+
|
|
6
|
+
export const Label = ({ size, color, children, className }: TypographyProps) => {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TextStyle
|
|
11
|
+
className={className}
|
|
12
|
+
body={theme.m3TextStyle.label}
|
|
13
|
+
size={size}
|
|
14
|
+
color={color}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</TextStyle>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import { Theme } from '@emotion/react'
|
|
4
|
+
import { M3TextStylesBody } from '@choochoochoo/jp.theme';
|
|
5
|
+
|
|
6
|
+
import { TypographySize } from './typography-size';
|
|
7
|
+
|
|
8
|
+
export function getTextStyle (styleBody: M3TextStylesBody, size: TypographySize) {
|
|
9
|
+
switch (size) {
|
|
10
|
+
case 'lg': {
|
|
11
|
+
return styleBody.large;
|
|
12
|
+
}
|
|
13
|
+
case 'sm': {
|
|
14
|
+
return styleBody.small;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return styleBody.medium;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type TypographyProps = {
|
|
22
|
+
color: string;
|
|
23
|
+
size: TypographySize;
|
|
24
|
+
children: React.ReactNode;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type TextStyleType = {
|
|
29
|
+
body: M3TextStylesBody;
|
|
30
|
+
size: TypographySize;
|
|
31
|
+
color: string;
|
|
32
|
+
theme?: Theme;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const TextStyle = styled.div(({ body, size, color }: TextStyleType) => ({
|
|
36
|
+
fontFamily: `${getTextStyle(body, size).fontFamilyName}`,
|
|
37
|
+
fontStyle: 'normal',
|
|
38
|
+
fontWeight: `${getTextStyle(body, size).fontWeight}`,
|
|
39
|
+
fontSize: `${getTextStyle(body, size).fontSize}px`,
|
|
40
|
+
lineHeight: `${getTextStyle(body, size).lineHeight}px`,
|
|
41
|
+
letterSpacing: `${getTextStyle(body, size).letterSpacing}px`,
|
|
42
|
+
color: `${color}`,
|
|
43
|
+
margin: 0,
|
|
44
|
+
}))
|
|
45
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useTheme } from '@emotion/react';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
|
|
4
|
+
import { TextStyle, TypographyProps } from './m3-typography';
|
|
5
|
+
|
|
6
|
+
export const Title = ({ size, color, children, className }: TypographyProps) => {
|
|
7
|
+
const theme = useTheme();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<TextStyle
|
|
11
|
+
className={className}
|
|
12
|
+
body={theme.m3TextStyle.title}
|
|
13
|
+
size={size}
|
|
14
|
+
color={color}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</TextStyle>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type TypographySize = 'sm' | 'md' | 'lg';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Default
|
|
4
|
+
"target": "es5",
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"forceConsistentCasingInFileNames": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
|
|
10
|
+
// Added
|
|
11
|
+
"jsx": "react",
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"sourceMap": true,
|
|
14
|
+
"outDir": "dist",
|
|
15
|
+
"moduleResolution": "node",
|
|
16
|
+
"allowSyntheticDefaultImports": true,
|
|
17
|
+
"typeRoots": [
|
|
18
|
+
"node_modules/@types",
|
|
19
|
+
"types"
|
|
20
|
+
],
|
|
21
|
+
"allowImportingTsExtensions": true,
|
|
22
|
+
"emitDeclarationOnly": true,
|
|
23
|
+
"declaration": true,
|
|
24
|
+
"declarationDir": "dist"
|
|
25
|
+
},
|
|
26
|
+
"exclude": [
|
|
27
|
+
"src/**/*.stories.ts",
|
|
28
|
+
"src/**/*.stories.tsx"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '@emotion/react';
|
|
2
|
+
import { M3Palettes, M3Schema, M3TextStyles, ThemesEnum } from '@choochoochoo/jp.theme';
|
|
3
|
+
|
|
4
|
+
declare module '@emotion/react' {
|
|
5
|
+
export interface Theme {
|
|
6
|
+
themeId: ThemesEnum;
|
|
7
|
+
m3Schema: M3Schema;
|
|
8
|
+
m3TextStyle: M3TextStyles;
|
|
9
|
+
m3Palettes: M3Palettes;
|
|
10
|
+
ext: object;
|
|
11
|
+
}
|
|
12
|
+
}
|