@ubie/vitals-ui-consumer 0.0.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/.storybook/main.ts +14 -0
- package/.storybook/preview.tsx +25 -0
- package/.storybook/vitest.setup.ts +7 -0
- package/dist/chunk-DKo7XVKm.mjs +33 -0
- package/dist/index.d.mts +1720 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +10594 -0
- package/dist/index.mjs.map +1 -0
- package/dist/style.css +2299 -0
- package/package.json +47 -0
- package/src/components/Accordion/Accordion.module.css +75 -0
- package/src/components/Accordion/Accordion.spec.tsx +18 -0
- package/src/components/Accordion/Accordion.stories.tsx +61 -0
- package/src/components/Accordion/Accordion.tsx +89 -0
- package/src/components/ActionHalfModal/ActionHalfModal.module.css +180 -0
- package/src/components/ActionHalfModal/ActionHalfModal.spec.tsx +57 -0
- package/src/components/ActionHalfModal/ActionHalfModal.stories.tsx +469 -0
- package/src/components/ActionHalfModal/ActionHalfModal.tsx +269 -0
- package/src/components/ActionModal/ActionModal.module.css +145 -0
- package/src/components/ActionModal/ActionModal.spec.tsx +57 -0
- package/src/components/ActionModal/ActionModal.stories.tsx +302 -0
- package/src/components/ActionModal/ActionModal.tsx +232 -0
- package/src/components/Bold/Bold.module.css +4 -0
- package/src/components/Bold/Bold.spec.tsx +24 -0
- package/src/components/Bold/Bold.stories.tsx +54 -0
- package/src/components/Bold/Bold.tsx +31 -0
- package/src/components/Box/Box.module.css +46 -0
- package/src/components/Box/Box.spec.tsx +188 -0
- package/src/components/Box/Box.tsx +242 -0
- package/src/components/Button/Button.module.css +261 -0
- package/src/components/Button/Button.spec.tsx +82 -0
- package/src/components/Button/Button.tsx +99 -0
- package/src/components/Button/ButtonTypes.ts +107 -0
- package/src/components/Button/LinkButton.spec.tsx +86 -0
- package/src/components/Button/LinkButton.tsx +80 -0
- package/src/components/Button/VariantIcon.tsx +20 -0
- package/src/components/Button/useIcon.tsx +16 -0
- package/src/components/ButtonCard/ButtonCard.module.css +35 -0
- package/src/components/ButtonCard/ButtonCard.spec.tsx +18 -0
- package/src/components/ButtonCard/ButtonCard.stories.tsx +54 -0
- package/src/components/ButtonCard/ButtonCard.tsx +18 -0
- package/src/components/Center/Center.module.css +19 -0
- package/src/components/Center/Center.spec.tsx +143 -0
- package/src/components/Center/Center.tsx +108 -0
- package/src/components/Checkbox/Checkbox.module.css +124 -0
- package/src/components/Checkbox/Checkbox.spec.tsx +17 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +213 -0
- package/src/components/Checkbox/Checkbox.tsx +50 -0
- package/src/components/CheckboxCard/CheckboxCard.module.css +102 -0
- package/src/components/CheckboxCard/CheckboxCard.spec.tsx +16 -0
- package/src/components/CheckboxCard/CheckboxCard.stories.tsx +205 -0
- package/src/components/CheckboxCard/CheckboxCard.tsx +53 -0
- package/src/components/CheckboxGroup/CheckboxGroup.module.css +16 -0
- package/src/components/CheckboxGroup/CheckboxGroup.spec.tsx +17 -0
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +64 -0
- package/src/components/Color/Color.module.css +3 -0
- package/src/components/Color/Color.spec.tsx +24 -0
- package/src/components/Color/Color.stories.tsx +71 -0
- package/src/components/Color/Color.tsx +28 -0
- package/src/components/Divider/Divider.module.css +9 -0
- package/src/components/Divider/Divider.spec.tsx +42 -0
- package/src/components/Divider/Divider.stories.tsx +77 -0
- package/src/components/Divider/Divider.tsx +49 -0
- package/src/components/ErrorMessage/ErrorMessage.module.css +8 -0
- package/src/components/ErrorMessage/ErrorMessage.spec.tsx +12 -0
- package/src/components/ErrorMessage/ErrorMessage.tsx +20 -0
- package/src/components/Flex/Flex.module.css +24 -0
- package/src/components/Flex/Flex.spec.tsx +188 -0
- package/src/components/Flex/Flex.tsx +173 -0
- package/src/components/FlexItem/FlexItem.module.css +14 -0
- package/src/components/FlexItem/FlexItem.spec.tsx +84 -0
- package/src/components/FlexItem/FlexItem.tsx +106 -0
- package/src/components/Heading/Heading.module.css +131 -0
- package/src/components/Heading/Heading.tsx +86 -0
- package/src/components/HelperMessage/HelperMessage.module.css +8 -0
- package/src/components/HelperMessage/HelperMessage.tsx +15 -0
- package/src/components/Icon/Icon.module.css +6 -0
- package/src/components/Icon/Icon.spec.tsx +24 -0
- package/src/components/Icon/Icon.stories.tsx +100 -0
- package/src/components/Icon/Icon.tsx +101 -0
- package/src/components/Input/Input.module.css +51 -0
- package/src/components/Input/Input.spec.tsx +14 -0
- package/src/components/Input/Input.tsx +27 -0
- package/src/components/Label/Label.module.css +14 -0
- package/src/components/Label/Label.tsx +39 -0
- package/src/components/LinkCard/LinkCard.module.css +72 -0
- package/src/components/LinkCard/LinkCard.tsx +96 -0
- package/src/components/MessageHalfModal/MessageHalfModal.module.css +181 -0
- package/src/components/MessageHalfModal/MessageHalfModal.spec.tsx +73 -0
- package/src/components/MessageHalfModal/MessageHalfModal.stories.tsx +242 -0
- package/src/components/MessageHalfModal/MessageHalfModal.tsx +194 -0
- package/src/components/MessageModal/MessageModal.module.css +149 -0
- package/src/components/MessageModal/MessageModal.spec.tsx +57 -0
- package/src/components/MessageModal/MessageModal.stories.tsx +223 -0
- package/src/components/MessageModal/MessageModal.tsx +178 -0
- package/src/components/Pre/Pre.module.css +8 -0
- package/src/components/Pre/Pre.spec.tsx +11 -0
- package/src/components/Pre/Pre.stories.tsx +76 -0
- package/src/components/Pre/Pre.tsx +40 -0
- package/src/components/RadioButton/RadioButton.module.css +92 -0
- package/src/components/RadioButton/RadioButton.spec.tsx +25 -0
- package/src/components/RadioButton/RadioButton.tsx +55 -0
- package/src/components/RadioCard/RadioCard.module.css +109 -0
- package/src/components/RadioCard/RadioCard.tsx +61 -0
- package/src/components/RadioGroup/RadioGroup.module.css +16 -0
- package/src/components/RadioGroup/RadioGroup.spec.tsx +17 -0
- package/src/components/RadioGroup/RadioGroup.tsx +60 -0
- package/src/components/Select/Select.module.css +70 -0
- package/src/components/Select/Select.spec.tsx +12 -0
- package/src/components/Select/Select.tsx +56 -0
- package/src/components/Stack/Stack.module.css +10 -0
- package/src/components/Stack/Stack.spec.tsx +177 -0
- package/src/components/Stack/Stack.tsx +151 -0
- package/src/components/Stepper/Stepper.module.css +137 -0
- package/src/components/Stepper/Stepper.spec.tsx +198 -0
- package/src/components/Stepper/Stepper.stories.tsx +192 -0
- package/src/components/Stepper/Stepper.tsx +70 -0
- package/src/components/Stepper/StepperItem.tsx +113 -0
- package/src/components/Text/Text.module.css +168 -0
- package/src/components/Text/Text.tsx +192 -0
- package/src/components/TextArea/TextArea.module.css +46 -0
- package/src/components/TextArea/TextArea.spec.tsx +13 -0
- package/src/components/TextArea/TextArea.tsx +29 -0
- package/src/components/Toggle/Toggle.module.css +71 -0
- package/src/components/Toggle/Toggle.spec.tsx +21 -0
- package/src/components/Toggle/Toggle.tsx +56 -0
- package/src/font.ts +2 -0
- package/src/hooks/useScrollable.ts +58 -0
- package/src/icons/AppleIcon.tsx +14 -0
- package/src/icons/GoogleIcon.tsx +27 -0
- package/src/icons/LINEIcon.tsx +16 -0
- package/src/index.ts +35 -0
- package/src/sharedComponents/RequiredLabel/RequiredLabel.module.css +10 -0
- package/src/sharedComponents/RequiredLabel/RequiredLabel.tsx +8 -0
- package/src/sharedComponents/VisuallyHidden/VisuallyHidden.module.css +15 -0
- package/src/sharedComponents/VisuallyHidden/VisuallyHidden.tsx +22 -0
- package/src/stories/Accordion.stories.portable.ts +4 -0
- package/src/stories/Box.stories.tsx +474 -0
- package/src/stories/Button.stories.tsx +262 -0
- package/src/stories/Center.stories.tsx +126 -0
- package/src/stories/ErrorMessage.stories.tsx +19 -0
- package/src/stories/Flex.stories.tsx +345 -0
- package/src/stories/Form.stories.tsx +83 -0
- package/src/stories/Heading.stories.tsx +263 -0
- package/src/stories/HelperMessage.stories.tsx +22 -0
- package/src/stories/Input.stories.tsx +145 -0
- package/src/stories/Label.stories.tsx +32 -0
- package/src/stories/LinkButton.stories.tsx +207 -0
- package/src/stories/LinkCard.stories.tsx +90 -0
- package/src/stories/RadioButton.stories.tsx +168 -0
- package/src/stories/RadioCard.stories.tsx +236 -0
- package/src/stories/Select.stories.tsx +97 -0
- package/src/stories/Stack.stories.tsx +167 -0
- package/src/stories/Text.stories.tsx +396 -0
- package/src/stories/TextArea.stories.tsx +49 -0
- package/src/stories/Toggle.stories.tsx +30 -0
- package/src/test/vitest-jest-dom.d.ts +12 -0
- package/src/types/attributes.ts +6 -0
- package/src/types/global.d.ts +11 -0
- package/src/types/icon.ts +3 -0
- package/src/types/style.ts +254 -0
- package/src/utils/component.ts +8 -0
- package/src/utils/style.spec.ts +57 -0
- package/src/utils/style.ts +387 -0
- package/src/utils/types.ts +8 -0
- package/tsconfig.json +18 -0
- package/tsconfig.spec-lint.tsbuildinfo +1 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vite.config.ts +50 -0
- package/vitest.shims.d.ts +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { CSSProperties, forwardRef, type HTMLAttributes, type PropsWithChildren } from "react";
|
|
5
|
+
import styles from "./FlexItem.module.css";
|
|
6
|
+
import { CSSWidth, MarginProps, PaddingProps, WidthProps } from "../../types/style";
|
|
7
|
+
import { marginVariables, paddingVariables } from "../../utils/style";
|
|
8
|
+
|
|
9
|
+
type FlexProperty = {
|
|
10
|
+
grow?: number;
|
|
11
|
+
shrink?: number;
|
|
12
|
+
basis?: CSSWidth;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type AllowedDivAttributes = Omit<HTMLAttributes<HTMLDivElement>, "className">;
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
/**
|
|
19
|
+
* flexの値を指定。 growなどを指定したい場合はオブジェクトで指定
|
|
20
|
+
* @default none
|
|
21
|
+
*/
|
|
22
|
+
flex?: "none" | FlexProperty;
|
|
23
|
+
} & Omit<WidthProps, "width"> &
|
|
24
|
+
MarginProps &
|
|
25
|
+
PaddingProps &
|
|
26
|
+
AllowedDivAttributes;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* FlexやStackの子として配置し、レイアウトを調整
|
|
30
|
+
*/
|
|
31
|
+
export const FlexItem = forwardRef<HTMLDivElement, PropsWithChildren<Props>>(
|
|
32
|
+
(
|
|
33
|
+
{
|
|
34
|
+
children,
|
|
35
|
+
flex = "none",
|
|
36
|
+
minWidth = "auto",
|
|
37
|
+
maxWidth = "none",
|
|
38
|
+
m,
|
|
39
|
+
mx,
|
|
40
|
+
my,
|
|
41
|
+
mt,
|
|
42
|
+
mr,
|
|
43
|
+
mb,
|
|
44
|
+
ml,
|
|
45
|
+
p,
|
|
46
|
+
px,
|
|
47
|
+
py,
|
|
48
|
+
pt,
|
|
49
|
+
pr,
|
|
50
|
+
pb,
|
|
51
|
+
pl,
|
|
52
|
+
...rest
|
|
53
|
+
},
|
|
54
|
+
ref,
|
|
55
|
+
) => {
|
|
56
|
+
const flexObj: { [key: string]: string } =
|
|
57
|
+
typeof flex === "object"
|
|
58
|
+
? {
|
|
59
|
+
"--flex-grow": flex.grow != null ? flex.grow.toString() : "0",
|
|
60
|
+
"--flex-shrink": flex.shrink != null ? flex.shrink.toString() : "1",
|
|
61
|
+
"--flex-basis": flex.basis ?? "auto",
|
|
62
|
+
}
|
|
63
|
+
: {};
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<div
|
|
67
|
+
className={clsx(
|
|
68
|
+
styles.flexItem,
|
|
69
|
+
flex === "none" && styles.none,
|
|
70
|
+
typeof flex === "object" && styles.longhand,
|
|
71
|
+
)}
|
|
72
|
+
ref={ref}
|
|
73
|
+
style={
|
|
74
|
+
{
|
|
75
|
+
"--min-width": minWidth,
|
|
76
|
+
"--max-width": maxWidth,
|
|
77
|
+
...flexObj,
|
|
78
|
+
...paddingVariables({
|
|
79
|
+
p,
|
|
80
|
+
px,
|
|
81
|
+
py,
|
|
82
|
+
pt,
|
|
83
|
+
pr,
|
|
84
|
+
pb,
|
|
85
|
+
pl,
|
|
86
|
+
}),
|
|
87
|
+
...marginVariables({
|
|
88
|
+
m,
|
|
89
|
+
mx,
|
|
90
|
+
my,
|
|
91
|
+
mt,
|
|
92
|
+
mr,
|
|
93
|
+
mb,
|
|
94
|
+
ml,
|
|
95
|
+
}),
|
|
96
|
+
} as CSSProperties
|
|
97
|
+
}
|
|
98
|
+
{...rest}
|
|
99
|
+
>
|
|
100
|
+
{children}
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
FlexItem.displayName = "FlexItem";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
.heading {
|
|
2
|
+
position: relative;
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
font-weight: normal;
|
|
5
|
+
hyphens: auto;
|
|
6
|
+
color: var(--color-on-surface);
|
|
7
|
+
overflow-wrap: anywhere;
|
|
8
|
+
|
|
9
|
+
--medium-leading-border-width: 4px;
|
|
10
|
+
--large-leading-border-width: 5px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.heading.bold {
|
|
14
|
+
font-weight: bold;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:where(.heading) {
|
|
18
|
+
margin: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.heading.left {
|
|
22
|
+
text-align: left;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.heading.center {
|
|
26
|
+
text-align: center;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.heading.right {
|
|
30
|
+
text-align: right;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.heading.main {
|
|
34
|
+
color: var(--color-on-surface);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.heading > a {
|
|
38
|
+
color: var(--color-primary);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@media (hover: hover) {
|
|
42
|
+
.heading > a:hover {
|
|
43
|
+
color: var(--color-ubie-blue-700);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.heading > a:active {
|
|
48
|
+
text-decoration: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.heading.white {
|
|
52
|
+
color: var(--color-ubie-white);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.heading.white,
|
|
56
|
+
.heading.white > a {
|
|
57
|
+
color: var(--color-ubie-white);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@media (hover: hover) {
|
|
61
|
+
.heading.white > a:hover {
|
|
62
|
+
text-decoration: none;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.heading.white > a:active {
|
|
67
|
+
position: relative;
|
|
68
|
+
top: 1px;
|
|
69
|
+
text-decoration: underline;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.heading.xxs {
|
|
73
|
+
font-size: var(--text-heading-xxs-size);
|
|
74
|
+
line-height: var(--text-heading-xxs-line);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.heading.xs {
|
|
78
|
+
font-size: var(--text-heading-xs-size);
|
|
79
|
+
line-height: var(--text-heading-xs-line);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.heading.sm {
|
|
83
|
+
font-size: var(--text-heading-sm-size);
|
|
84
|
+
line-height: var(--text-heading-sm-line);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.heading.md {
|
|
88
|
+
font-size: var(--text-heading-md-size);
|
|
89
|
+
line-height: var(--text-heading-md-line);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.heading.lg {
|
|
93
|
+
font-size: var(--text-heading-lg-size);
|
|
94
|
+
line-height: var(--text-heading-lg-line);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.heading.xl {
|
|
98
|
+
font-size: var(--text-heading-xl-size);
|
|
99
|
+
line-height: var(--text-heading-xl-line);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.heading.leadingBorder {
|
|
103
|
+
padding-left: calc(var(--size-spacing-sm) + var(--medium-leading-border-width));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.heading.leadingBorder::before {
|
|
107
|
+
position: absolute;
|
|
108
|
+
top: 0;
|
|
109
|
+
left: 0;
|
|
110
|
+
display: block;
|
|
111
|
+
width: var(--medium-leading-border-width);
|
|
112
|
+
height: 100%;
|
|
113
|
+
vertical-align: top;
|
|
114
|
+
content: "";
|
|
115
|
+
background-color: var(--color-ubie-blue-600);
|
|
116
|
+
border-radius: 3px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.heading.lg.leadingBorder,
|
|
120
|
+
.heading.xl.leadingBorder {
|
|
121
|
+
padding-left: calc(var(--size-spacing-sm) + var(--large-leading-border-width));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.heading.lg.leadingBorder::before,
|
|
125
|
+
.heading.xl.leadingBorder::before {
|
|
126
|
+
width: var(--large-leading-border-width);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.heading.noWrap {
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { clsx } from "clsx";
|
|
2
|
+
import styles from "./Heading.module.css";
|
|
3
|
+
import { CustomDataAttributeProps } from "../../types/attributes"; // 追加したインポート
|
|
4
|
+
import { HeadingFontSize, TextColorVariant } from "../../types/style";
|
|
5
|
+
import { HTMLTagname } from "../../utils/types";
|
|
6
|
+
import type { FC, PropsWithChildren } from "react";
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
/**
|
|
10
|
+
* テキストの配置。指定しない場合、親要素の配置を継承
|
|
11
|
+
*/
|
|
12
|
+
textAlign?: "left" | "center" | "right";
|
|
13
|
+
/**
|
|
14
|
+
* サイズ。Typographyトークンの値を指定
|
|
15
|
+
* xs=16px, sm=18px, md=20px, lg=24px, xl=28px
|
|
16
|
+
* @default md
|
|
17
|
+
*/
|
|
18
|
+
size?: HeadingFontSize;
|
|
19
|
+
/**
|
|
20
|
+
* 行の先頭にボーダーを表示
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
leadingBorder?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* レンダリングされるHTML要素
|
|
26
|
+
* @default p
|
|
27
|
+
*/
|
|
28
|
+
as?: HTMLTagname;
|
|
29
|
+
/**
|
|
30
|
+
* テキストのカラーバリエーション
|
|
31
|
+
* @default secondary
|
|
32
|
+
*/
|
|
33
|
+
color?: Extract<TextColorVariant, "main" | "white">;
|
|
34
|
+
/**
|
|
35
|
+
* HTMLのID属性
|
|
36
|
+
*/
|
|
37
|
+
id?: string;
|
|
38
|
+
/**
|
|
39
|
+
* HTMLのfor属性。label要素の場合に使用
|
|
40
|
+
*/
|
|
41
|
+
htmlFor?: string;
|
|
42
|
+
/**
|
|
43
|
+
* 太字とするかどうか、falseの場合はnormal
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
46
|
+
bold?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 領域が狭い場合でも折り返えさない
|
|
49
|
+
*/
|
|
50
|
+
noWrap?: boolean;
|
|
51
|
+
} & CustomDataAttributeProps;
|
|
52
|
+
|
|
53
|
+
const Heading: FC<PropsWithChildren<Props>> = ({
|
|
54
|
+
textAlign,
|
|
55
|
+
children,
|
|
56
|
+
size = "md",
|
|
57
|
+
color = "main",
|
|
58
|
+
leadingBorder,
|
|
59
|
+
as: HeadingComponent = "p",
|
|
60
|
+
id,
|
|
61
|
+
htmlFor,
|
|
62
|
+
bold = true,
|
|
63
|
+
noWrap = false,
|
|
64
|
+
...otherProps
|
|
65
|
+
}) => {
|
|
66
|
+
const className = clsx(
|
|
67
|
+
styles.heading,
|
|
68
|
+
textAlign ? styles[textAlign] : null,
|
|
69
|
+
styles[size],
|
|
70
|
+
// For leadingBorder, only the main text colour is supported.
|
|
71
|
+
leadingBorder ? styles.secondary : styles[color],
|
|
72
|
+
leadingBorder ? styles.leadingBorder : null,
|
|
73
|
+
bold && styles.bold,
|
|
74
|
+
noWrap && styles.noWrap,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<HeadingComponent className={className} id={id} htmlFor={htmlFor} {...otherProps}>
|
|
79
|
+
{children}
|
|
80
|
+
</HeadingComponent>
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
Heading.displayName = "Heading";
|
|
85
|
+
|
|
86
|
+
export { Heading };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import styles from "./HelperMessage.module.css";
|
|
4
|
+
import { CustomDataAttributeProps } from "../../types/attributes"; // 追加したインポート
|
|
5
|
+
import type { FC, ReactNode } from "react";
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
} & CustomDataAttributeProps;
|
|
10
|
+
|
|
11
|
+
export const HelperMessage: FC<Props> = ({ children, ...otherProps }) => (
|
|
12
|
+
<p className={styles.message} {...otherProps}>
|
|
13
|
+
{children}
|
|
14
|
+
</p>
|
|
15
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { composeStory } from "@storybook/react-vite";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import Meta, { WithCustomDataAttribute, WithId } from "./Icon.stories";
|
|
4
|
+
|
|
5
|
+
const WithCustomDataAttributeStory = composeStory(WithCustomDataAttribute, Meta);
|
|
6
|
+
const WithIdStory = composeStory(WithId, Meta);
|
|
7
|
+
|
|
8
|
+
describe("Icon", () => {
|
|
9
|
+
test("Add custom data attributes", async () => {
|
|
10
|
+
render(<WithCustomDataAttributeStory />);
|
|
11
|
+
|
|
12
|
+
const iconElement = await screen.findByTestId("testid");
|
|
13
|
+
|
|
14
|
+
expect(iconElement).toBeInTheDocument();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("Add id", async () => {
|
|
18
|
+
render(<WithIdStory />);
|
|
19
|
+
|
|
20
|
+
const iconElement = await screen.findByTestId("testid");
|
|
21
|
+
|
|
22
|
+
expect(iconElement).toHaveAttribute("id", "icon-id");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { ComponentProps } from "react";
|
|
3
|
+
import { Icon, Flex, Box, Stack } from "../../index";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
component: Icon,
|
|
7
|
+
} satisfies Meta<typeof Icon>;
|
|
8
|
+
|
|
9
|
+
const defaultArgs: Partial<ComponentProps<typeof Icon>> = {
|
|
10
|
+
icon: "UbieIcon",
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof Icon>;
|
|
14
|
+
|
|
15
|
+
export const Default: Story = {
|
|
16
|
+
render: (args) => <Icon {...args} />,
|
|
17
|
+
args: defaultArgs,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const Size: Story = {
|
|
21
|
+
render: (args) => (
|
|
22
|
+
<>
|
|
23
|
+
<Flex alignItems="center" spacing="sm">
|
|
24
|
+
<Icon {...args} size="xs" />
|
|
25
|
+
<Icon {...args} size="sm" />
|
|
26
|
+
<Icon {...args} size="md" />
|
|
27
|
+
<Icon {...args} size="lg" />
|
|
28
|
+
<Icon {...args} size="xl" />
|
|
29
|
+
<Icon {...args} size="xxl" />
|
|
30
|
+
<Icon {...args} size="xxxl" />
|
|
31
|
+
<Icon {...args} size="xxxxl" />
|
|
32
|
+
</Flex>
|
|
33
|
+
</>
|
|
34
|
+
),
|
|
35
|
+
args: defaultArgs,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const SizeAlias: Story = {
|
|
39
|
+
render: (args) => (
|
|
40
|
+
<>
|
|
41
|
+
<Flex alignItems="center" spacing="sm">
|
|
42
|
+
<Icon {...args} size="2xl" />
|
|
43
|
+
<Icon {...args} size="3xl" />
|
|
44
|
+
<Icon {...args} size="4xl" />
|
|
45
|
+
</Flex>
|
|
46
|
+
</>
|
|
47
|
+
),
|
|
48
|
+
args: defaultArgs,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const Color: Story = {
|
|
52
|
+
render: (args) => (
|
|
53
|
+
<Flex alignItems="center" spacing="sm" wrap>
|
|
54
|
+
<Icon {...args} color="blue" />
|
|
55
|
+
<Icon {...args} color="pink" />
|
|
56
|
+
<Icon {...args} color="orange" />
|
|
57
|
+
<Icon {...args} color="purple" />
|
|
58
|
+
<Icon {...args} color="green" />
|
|
59
|
+
<Icon {...args} color="red" />
|
|
60
|
+
<Icon {...args} color="black" />
|
|
61
|
+
<Box pt="xxs" pr="xxs" pb="xxs" pl="xxs" backgroundColor="blackInverseDarken">
|
|
62
|
+
<Icon {...args} color="white" />
|
|
63
|
+
</Box>
|
|
64
|
+
</Flex>
|
|
65
|
+
),
|
|
66
|
+
args: defaultArgs,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const CaseOnlyIcon: Story = {
|
|
70
|
+
render: () => (
|
|
71
|
+
<Stack spacing="sm">
|
|
72
|
+
<p>
|
|
73
|
+
ラベルや付随する文章を伴わずにアイコン単独で使う場合、アイコンが保つ意味を<code>label</code>{" "}
|
|
74
|
+
propで付与します
|
|
75
|
+
<br />
|
|
76
|
+
例: アイコンボタンなど
|
|
77
|
+
</p>
|
|
78
|
+
<div>
|
|
79
|
+
<Icon icon="SetupIcon" label="設定" />
|
|
80
|
+
</div>
|
|
81
|
+
</Stack>
|
|
82
|
+
),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const WithCustomDataAttribute: Story = {
|
|
86
|
+
render: (args) => <Icon {...args} />,
|
|
87
|
+
args: {
|
|
88
|
+
...defaultArgs,
|
|
89
|
+
"data-testid": "testid",
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const WithId: Story = {
|
|
94
|
+
render: (args) => <Icon {...args} />,
|
|
95
|
+
args: {
|
|
96
|
+
...defaultArgs,
|
|
97
|
+
id: "icon-id",
|
|
98
|
+
"data-testid": "testid",
|
|
99
|
+
},
|
|
100
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as Icons from "@ubie/vitals-icon";
|
|
2
|
+
import styles from "./Icon.module.css";
|
|
3
|
+
import { CustomDataAttributeProps } from "../../types/attributes";
|
|
4
|
+
import { IconName } from "../../types/icon";
|
|
5
|
+
import { IconColorVariant } from "../../types/style";
|
|
6
|
+
import { iconColorVariable } from "../../utils/style";
|
|
7
|
+
import type { CSSProperties, FC, SVGProps } from "react";
|
|
8
|
+
|
|
9
|
+
type IconSize = "xs" | "sm" | "md" | "lg" | "xl" | "xxl" | "xxxl" | "xxxxl";
|
|
10
|
+
type IconSizeAlias = "2xl" | "3xl" | "4xl";
|
|
11
|
+
type SizeProp = IconSize | IconSizeAlias;
|
|
12
|
+
|
|
13
|
+
const toIconSizeEmValue = (size: IconSize): string => {
|
|
14
|
+
switch (size) {
|
|
15
|
+
case "xs":
|
|
16
|
+
return "1rem";
|
|
17
|
+
case "sm":
|
|
18
|
+
return "1.25rem";
|
|
19
|
+
case "md":
|
|
20
|
+
return "1.5rem";
|
|
21
|
+
case "lg":
|
|
22
|
+
return "1.75rem";
|
|
23
|
+
case "xl":
|
|
24
|
+
return "2rem";
|
|
25
|
+
case "xxl":
|
|
26
|
+
return "4rem";
|
|
27
|
+
case "xxxl":
|
|
28
|
+
return "5rem";
|
|
29
|
+
case "xxxxl":
|
|
30
|
+
return "6.5rem";
|
|
31
|
+
default:
|
|
32
|
+
const _: never = size;
|
|
33
|
+
// oxlint-disable-next-line restrict-template-expressions
|
|
34
|
+
throw new Error(`Unknown size: ${size}`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const normalizeSize = (icon: IconSize | IconSizeAlias): IconSize => {
|
|
39
|
+
switch (icon) {
|
|
40
|
+
case "2xl":
|
|
41
|
+
return "xxl";
|
|
42
|
+
case "3xl":
|
|
43
|
+
return "xxxl";
|
|
44
|
+
case "4xl":
|
|
45
|
+
return "xxxxl";
|
|
46
|
+
default:
|
|
47
|
+
return icon;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type Props = {
|
|
52
|
+
/**
|
|
53
|
+
* アイコンの種類
|
|
54
|
+
*/
|
|
55
|
+
icon: IconName;
|
|
56
|
+
/**
|
|
57
|
+
* 色。指定しない場合はinheritとなり、親要素のcolorプロパティを継承します
|
|
58
|
+
*/
|
|
59
|
+
color?: IconColorVariant;
|
|
60
|
+
/**
|
|
61
|
+
* サイズ
|
|
62
|
+
* xs=16px, sm=20px, md=24px, lg=28px, xl=32px, xxl=64px, xxxl=80px, xxxxl=104px
|
|
63
|
+
* 2xl、3xl、4xlはdeprecatedな指定となります
|
|
64
|
+
* @default md
|
|
65
|
+
*/
|
|
66
|
+
size?: SizeProp;
|
|
67
|
+
/**
|
|
68
|
+
* ネイティブの`id`属性。ページで固有のIDを指定
|
|
69
|
+
*/
|
|
70
|
+
id?: string;
|
|
71
|
+
/**
|
|
72
|
+
* アイコンが何を表すかを説明するテキスト
|
|
73
|
+
* 単に装飾的なアイコンの場合は指定しない
|
|
74
|
+
*/
|
|
75
|
+
label?: string;
|
|
76
|
+
} & CustomDataAttributeProps;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* アイコンコンポーネント。labelを指定しない場合は単に装飾的なアイコンであるとみなされ、aria-hiddenが付与されます
|
|
80
|
+
*/
|
|
81
|
+
export const Icon: FC<Props> = ({ icon, color, size = "md", label, ...otherProps }) => {
|
|
82
|
+
const iconComponents = Icons as Record<IconName, FC<SVGProps<SVGSVGElement>>>;
|
|
83
|
+
const IconComponent = iconComponents[icon];
|
|
84
|
+
const _sizeValue = toIconSizeEmValue(normalizeSize(size));
|
|
85
|
+
const colorVariant = iconColorVariable(color);
|
|
86
|
+
return (
|
|
87
|
+
<IconComponent
|
|
88
|
+
role="img"
|
|
89
|
+
aria-hidden={label === undefined || label === "" ? true : undefined}
|
|
90
|
+
aria-label={label}
|
|
91
|
+
className={styles.icon}
|
|
92
|
+
style={
|
|
93
|
+
{
|
|
94
|
+
...colorVariant,
|
|
95
|
+
"--size": _sizeValue,
|
|
96
|
+
} as CSSProperties
|
|
97
|
+
}
|
|
98
|
+
{...otherProps}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.input {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
width: 100%;
|
|
4
|
+
padding: var(--size-spacing-md) var(--size-spacing-sm) 0.875rem;
|
|
5
|
+
font-size: var(--text-body-md-narrow-size);
|
|
6
|
+
line-height: var(--text-body-md-narrow-line);
|
|
7
|
+
color: var(--color-on-surface);
|
|
8
|
+
text-align: inherit;
|
|
9
|
+
appearance: none;
|
|
10
|
+
caret-color: var(--color-ubie-blue-600);
|
|
11
|
+
background-color: var(--color-ubie-white);
|
|
12
|
+
border: 1px solid var(--color-outline);
|
|
13
|
+
border-bottom: 2px solid var(--color-outline);
|
|
14
|
+
border-radius: 8px 8px 0 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.input.isInvalid,
|
|
18
|
+
.input:user-invalid {
|
|
19
|
+
background: var(--color-error-container);
|
|
20
|
+
border-bottom-color: var(--color-error);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@supports not (selector(:user-invalid)) {
|
|
24
|
+
.input:invalid {
|
|
25
|
+
background: var(--color-error-container);
|
|
26
|
+
border-bottom-color: var(--color-error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.input:disabled {
|
|
31
|
+
color: var(--color-placeholder);
|
|
32
|
+
background-color: var(--color-outline-variant);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.input::placeholder {
|
|
36
|
+
color: var(--color-placeholder);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.input:disabled::placeholder {
|
|
40
|
+
color: var(--color-placeholder);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.input:focus {
|
|
44
|
+
border-bottom-color: var(--color-ubie-blue-500);
|
|
45
|
+
outline: none;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.input[type="date"] {
|
|
49
|
+
height: 3.5rem;
|
|
50
|
+
line-height: 1;
|
|
51
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
import { createRef } from "react";
|
|
3
|
+
import { Input } from "./Input";
|
|
4
|
+
|
|
5
|
+
describe("Input", () => {
|
|
6
|
+
it("access to DOM through ref prop", () => {
|
|
7
|
+
const ref = createRef<HTMLInputElement>();
|
|
8
|
+
|
|
9
|
+
render(<Input name="test" defaultValue="test" ref={ref} />);
|
|
10
|
+
expect(ref.current).not.toBeNull();
|
|
11
|
+
expect(ref.current?.tagName).toBe("INPUT");
|
|
12
|
+
expect(ref.current?.type).toBe("text");
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import { forwardRef, InputHTMLAttributes } from "react";
|
|
5
|
+
import styles from "./Input.module.css";
|
|
6
|
+
import { CustomDataAttributeProps } from "../../types/attributes"; // 追加したインポート
|
|
7
|
+
|
|
8
|
+
type Props = {
|
|
9
|
+
/**
|
|
10
|
+
* 有効でない入力を保持しているかどうか
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
isInvalid?: boolean;
|
|
14
|
+
} & Omit<InputHTMLAttributes<HTMLInputElement>, "invalid"> &
|
|
15
|
+
CustomDataAttributeProps;
|
|
16
|
+
|
|
17
|
+
export const Input = forwardRef<HTMLInputElement, Props>(({ isInvalid, ...props }, ref) => {
|
|
18
|
+
const className = clsx(
|
|
19
|
+
{ [styles.isInvalid]: isInvalid && !props.disabled },
|
|
20
|
+
styles.input,
|
|
21
|
+
props.className,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return <input {...props} className={className} ref={ref} aria-invalid={isInvalid} />;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
Input.displayName = "Input";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.label {
|
|
2
|
+
display: flex;
|
|
3
|
+
gap: var(--size-spacing-xs);
|
|
4
|
+
align-items: flex-start;
|
|
5
|
+
font-size: var(--text-body-sm-size);
|
|
6
|
+
font-weight: bold;
|
|
7
|
+
hyphens: auto;
|
|
8
|
+
color: var(--color-on-surface-variant);
|
|
9
|
+
overflow-wrap: anywhere;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
legend.label {
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|