@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.
Files changed (170) hide show
  1. package/.storybook/main.ts +14 -0
  2. package/.storybook/preview.tsx +25 -0
  3. package/.storybook/vitest.setup.ts +7 -0
  4. package/dist/chunk-DKo7XVKm.mjs +33 -0
  5. package/dist/index.d.mts +1720 -0
  6. package/dist/index.d.mts.map +1 -0
  7. package/dist/index.mjs +10594 -0
  8. package/dist/index.mjs.map +1 -0
  9. package/dist/style.css +2299 -0
  10. package/package.json +47 -0
  11. package/src/components/Accordion/Accordion.module.css +75 -0
  12. package/src/components/Accordion/Accordion.spec.tsx +18 -0
  13. package/src/components/Accordion/Accordion.stories.tsx +61 -0
  14. package/src/components/Accordion/Accordion.tsx +89 -0
  15. package/src/components/ActionHalfModal/ActionHalfModal.module.css +180 -0
  16. package/src/components/ActionHalfModal/ActionHalfModal.spec.tsx +57 -0
  17. package/src/components/ActionHalfModal/ActionHalfModal.stories.tsx +469 -0
  18. package/src/components/ActionHalfModal/ActionHalfModal.tsx +269 -0
  19. package/src/components/ActionModal/ActionModal.module.css +145 -0
  20. package/src/components/ActionModal/ActionModal.spec.tsx +57 -0
  21. package/src/components/ActionModal/ActionModal.stories.tsx +302 -0
  22. package/src/components/ActionModal/ActionModal.tsx +232 -0
  23. package/src/components/Bold/Bold.module.css +4 -0
  24. package/src/components/Bold/Bold.spec.tsx +24 -0
  25. package/src/components/Bold/Bold.stories.tsx +54 -0
  26. package/src/components/Bold/Bold.tsx +31 -0
  27. package/src/components/Box/Box.module.css +46 -0
  28. package/src/components/Box/Box.spec.tsx +188 -0
  29. package/src/components/Box/Box.tsx +242 -0
  30. package/src/components/Button/Button.module.css +261 -0
  31. package/src/components/Button/Button.spec.tsx +82 -0
  32. package/src/components/Button/Button.tsx +99 -0
  33. package/src/components/Button/ButtonTypes.ts +107 -0
  34. package/src/components/Button/LinkButton.spec.tsx +86 -0
  35. package/src/components/Button/LinkButton.tsx +80 -0
  36. package/src/components/Button/VariantIcon.tsx +20 -0
  37. package/src/components/Button/useIcon.tsx +16 -0
  38. package/src/components/ButtonCard/ButtonCard.module.css +35 -0
  39. package/src/components/ButtonCard/ButtonCard.spec.tsx +18 -0
  40. package/src/components/ButtonCard/ButtonCard.stories.tsx +54 -0
  41. package/src/components/ButtonCard/ButtonCard.tsx +18 -0
  42. package/src/components/Center/Center.module.css +19 -0
  43. package/src/components/Center/Center.spec.tsx +143 -0
  44. package/src/components/Center/Center.tsx +108 -0
  45. package/src/components/Checkbox/Checkbox.module.css +124 -0
  46. package/src/components/Checkbox/Checkbox.spec.tsx +17 -0
  47. package/src/components/Checkbox/Checkbox.stories.tsx +213 -0
  48. package/src/components/Checkbox/Checkbox.tsx +50 -0
  49. package/src/components/CheckboxCard/CheckboxCard.module.css +102 -0
  50. package/src/components/CheckboxCard/CheckboxCard.spec.tsx +16 -0
  51. package/src/components/CheckboxCard/CheckboxCard.stories.tsx +205 -0
  52. package/src/components/CheckboxCard/CheckboxCard.tsx +53 -0
  53. package/src/components/CheckboxGroup/CheckboxGroup.module.css +16 -0
  54. package/src/components/CheckboxGroup/CheckboxGroup.spec.tsx +17 -0
  55. package/src/components/CheckboxGroup/CheckboxGroup.tsx +64 -0
  56. package/src/components/Color/Color.module.css +3 -0
  57. package/src/components/Color/Color.spec.tsx +24 -0
  58. package/src/components/Color/Color.stories.tsx +71 -0
  59. package/src/components/Color/Color.tsx +28 -0
  60. package/src/components/Divider/Divider.module.css +9 -0
  61. package/src/components/Divider/Divider.spec.tsx +42 -0
  62. package/src/components/Divider/Divider.stories.tsx +77 -0
  63. package/src/components/Divider/Divider.tsx +49 -0
  64. package/src/components/ErrorMessage/ErrorMessage.module.css +8 -0
  65. package/src/components/ErrorMessage/ErrorMessage.spec.tsx +12 -0
  66. package/src/components/ErrorMessage/ErrorMessage.tsx +20 -0
  67. package/src/components/Flex/Flex.module.css +24 -0
  68. package/src/components/Flex/Flex.spec.tsx +188 -0
  69. package/src/components/Flex/Flex.tsx +173 -0
  70. package/src/components/FlexItem/FlexItem.module.css +14 -0
  71. package/src/components/FlexItem/FlexItem.spec.tsx +84 -0
  72. package/src/components/FlexItem/FlexItem.tsx +106 -0
  73. package/src/components/Heading/Heading.module.css +131 -0
  74. package/src/components/Heading/Heading.tsx +86 -0
  75. package/src/components/HelperMessage/HelperMessage.module.css +8 -0
  76. package/src/components/HelperMessage/HelperMessage.tsx +15 -0
  77. package/src/components/Icon/Icon.module.css +6 -0
  78. package/src/components/Icon/Icon.spec.tsx +24 -0
  79. package/src/components/Icon/Icon.stories.tsx +100 -0
  80. package/src/components/Icon/Icon.tsx +101 -0
  81. package/src/components/Input/Input.module.css +51 -0
  82. package/src/components/Input/Input.spec.tsx +14 -0
  83. package/src/components/Input/Input.tsx +27 -0
  84. package/src/components/Label/Label.module.css +14 -0
  85. package/src/components/Label/Label.tsx +39 -0
  86. package/src/components/LinkCard/LinkCard.module.css +72 -0
  87. package/src/components/LinkCard/LinkCard.tsx +96 -0
  88. package/src/components/MessageHalfModal/MessageHalfModal.module.css +181 -0
  89. package/src/components/MessageHalfModal/MessageHalfModal.spec.tsx +73 -0
  90. package/src/components/MessageHalfModal/MessageHalfModal.stories.tsx +242 -0
  91. package/src/components/MessageHalfModal/MessageHalfModal.tsx +194 -0
  92. package/src/components/MessageModal/MessageModal.module.css +149 -0
  93. package/src/components/MessageModal/MessageModal.spec.tsx +57 -0
  94. package/src/components/MessageModal/MessageModal.stories.tsx +223 -0
  95. package/src/components/MessageModal/MessageModal.tsx +178 -0
  96. package/src/components/Pre/Pre.module.css +8 -0
  97. package/src/components/Pre/Pre.spec.tsx +11 -0
  98. package/src/components/Pre/Pre.stories.tsx +76 -0
  99. package/src/components/Pre/Pre.tsx +40 -0
  100. package/src/components/RadioButton/RadioButton.module.css +92 -0
  101. package/src/components/RadioButton/RadioButton.spec.tsx +25 -0
  102. package/src/components/RadioButton/RadioButton.tsx +55 -0
  103. package/src/components/RadioCard/RadioCard.module.css +109 -0
  104. package/src/components/RadioCard/RadioCard.tsx +61 -0
  105. package/src/components/RadioGroup/RadioGroup.module.css +16 -0
  106. package/src/components/RadioGroup/RadioGroup.spec.tsx +17 -0
  107. package/src/components/RadioGroup/RadioGroup.tsx +60 -0
  108. package/src/components/Select/Select.module.css +70 -0
  109. package/src/components/Select/Select.spec.tsx +12 -0
  110. package/src/components/Select/Select.tsx +56 -0
  111. package/src/components/Stack/Stack.module.css +10 -0
  112. package/src/components/Stack/Stack.spec.tsx +177 -0
  113. package/src/components/Stack/Stack.tsx +151 -0
  114. package/src/components/Stepper/Stepper.module.css +137 -0
  115. package/src/components/Stepper/Stepper.spec.tsx +198 -0
  116. package/src/components/Stepper/Stepper.stories.tsx +192 -0
  117. package/src/components/Stepper/Stepper.tsx +70 -0
  118. package/src/components/Stepper/StepperItem.tsx +113 -0
  119. package/src/components/Text/Text.module.css +168 -0
  120. package/src/components/Text/Text.tsx +192 -0
  121. package/src/components/TextArea/TextArea.module.css +46 -0
  122. package/src/components/TextArea/TextArea.spec.tsx +13 -0
  123. package/src/components/TextArea/TextArea.tsx +29 -0
  124. package/src/components/Toggle/Toggle.module.css +71 -0
  125. package/src/components/Toggle/Toggle.spec.tsx +21 -0
  126. package/src/components/Toggle/Toggle.tsx +56 -0
  127. package/src/font.ts +2 -0
  128. package/src/hooks/useScrollable.ts +58 -0
  129. package/src/icons/AppleIcon.tsx +14 -0
  130. package/src/icons/GoogleIcon.tsx +27 -0
  131. package/src/icons/LINEIcon.tsx +16 -0
  132. package/src/index.ts +35 -0
  133. package/src/sharedComponents/RequiredLabel/RequiredLabel.module.css +10 -0
  134. package/src/sharedComponents/RequiredLabel/RequiredLabel.tsx +8 -0
  135. package/src/sharedComponents/VisuallyHidden/VisuallyHidden.module.css +15 -0
  136. package/src/sharedComponents/VisuallyHidden/VisuallyHidden.tsx +22 -0
  137. package/src/stories/Accordion.stories.portable.ts +4 -0
  138. package/src/stories/Box.stories.tsx +474 -0
  139. package/src/stories/Button.stories.tsx +262 -0
  140. package/src/stories/Center.stories.tsx +126 -0
  141. package/src/stories/ErrorMessage.stories.tsx +19 -0
  142. package/src/stories/Flex.stories.tsx +345 -0
  143. package/src/stories/Form.stories.tsx +83 -0
  144. package/src/stories/Heading.stories.tsx +263 -0
  145. package/src/stories/HelperMessage.stories.tsx +22 -0
  146. package/src/stories/Input.stories.tsx +145 -0
  147. package/src/stories/Label.stories.tsx +32 -0
  148. package/src/stories/LinkButton.stories.tsx +207 -0
  149. package/src/stories/LinkCard.stories.tsx +90 -0
  150. package/src/stories/RadioButton.stories.tsx +168 -0
  151. package/src/stories/RadioCard.stories.tsx +236 -0
  152. package/src/stories/Select.stories.tsx +97 -0
  153. package/src/stories/Stack.stories.tsx +167 -0
  154. package/src/stories/Text.stories.tsx +396 -0
  155. package/src/stories/TextArea.stories.tsx +49 -0
  156. package/src/stories/Toggle.stories.tsx +30 -0
  157. package/src/test/vitest-jest-dom.d.ts +12 -0
  158. package/src/types/attributes.ts +6 -0
  159. package/src/types/global.d.ts +11 -0
  160. package/src/types/icon.ts +3 -0
  161. package/src/types/style.ts +254 -0
  162. package/src/utils/component.ts +8 -0
  163. package/src/utils/style.spec.ts +57 -0
  164. package/src/utils/style.ts +387 -0
  165. package/src/utils/types.ts +8 -0
  166. package/tsconfig.json +18 -0
  167. package/tsconfig.spec-lint.tsbuildinfo +1 -0
  168. package/tsconfig.tsbuildinfo +1 -0
  169. package/vite.config.ts +50 -0
  170. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,60 @@
1
+ "use client";
2
+
3
+ import { forwardRef, useMemo } from "react";
4
+ import styles from "./RadioGroup.module.css";
5
+ import { RequiredLabel } from "../../sharedComponents/RequiredLabel/RequiredLabel";
6
+ import { CustomDataAttributeProps } from "../../types/attributes"; // 追加したインポート
7
+ import { Flex } from "../Flex/Flex";
8
+ import { RadioButton } from "../RadioButton/RadioButton";
9
+ import { RadioCard } from "../RadioCard/RadioCard";
10
+ import type { ReactElement } from "react";
11
+
12
+ export type Props = {
13
+ children: ReactElement<typeof RadioButton>[] | ReactElement<typeof RadioCard>[];
14
+ /**
15
+ * ラジオグループの見出し(legend要素)
16
+ */
17
+ label?: string;
18
+ /**
19
+ * 必須マークを表示するか
20
+ * 注意: trueとしてもinput要素のrequired属性は付与されません
21
+ */
22
+ showRequiredLabel?: boolean;
23
+ /**
24
+ * ラジオボタンの配置方向
25
+ * @default column
26
+ */
27
+ direction?: "column" | "row";
28
+ } & CustomDataAttributeProps;
29
+
30
+ export const RadioGroup = forwardRef<HTMLFieldSetElement, Props>(
31
+ ({ children, label, showRequiredLabel = false, direction = "column", ...otherProps }, ref) => {
32
+ const childrenIsCard = children.some((child) => child.type === RadioCard);
33
+ const childenIsBlock = direction === "row" || (childrenIsCard && direction === "column");
34
+
35
+ const wrap = useMemo(() => {
36
+ return direction === "row";
37
+ }, [direction]);
38
+
39
+ return (
40
+ <fieldset className={styles.wrapper} ref={ref} {...otherProps}>
41
+ {label && (
42
+ <legend className={styles.legend}>
43
+ {label}
44
+ {showRequiredLabel && <RequiredLabel />}
45
+ </legend>
46
+ )}
47
+ <Flex
48
+ spacing={childrenIsCard ? "sm" : "md"}
49
+ alignItems={childenIsBlock ? "normal" : undefined}
50
+ direction={direction}
51
+ wrap={wrap}
52
+ >
53
+ {children}
54
+ </Flex>
55
+ </fieldset>
56
+ );
57
+ },
58
+ );
59
+
60
+ RadioGroup.displayName = "RadioGroup";
@@ -0,0 +1,70 @@
1
+ .wrapper {
2
+ position: relative;
3
+ }
4
+
5
+ .select {
6
+ display: flex;
7
+ align-items: center;
8
+ justify-content: space-between;
9
+ width: 100%;
10
+ min-height: 54px;
11
+ padding: 0 64px 0 16px;
12
+ font-size: var(--text-body-md-size);
13
+ font-weight: bold;
14
+ line-height: 54px;
15
+ color: var(--color-on-surface);
16
+ appearance: none;
17
+ caret-color: var(--color-ubie-blue-600);
18
+ background-color: var(--color-ubie-white);
19
+ border: 2px solid var(--color-outline);
20
+ border-radius: 8px;
21
+ transition: border-color 0.3s var(--ease-out-quint);
22
+ }
23
+
24
+ .select::placeholder {
25
+ color: var(--color-placeholder);
26
+ }
27
+
28
+ .select:focus {
29
+ outline: none;
30
+ }
31
+
32
+ .select:focus-visible {
33
+ border-color: var(--color-ubie-blue-500);
34
+ }
35
+
36
+ @media (hover: hover) {
37
+ .select:hover {
38
+ border: 2px solid var(--color-ubie-blue-400);
39
+ }
40
+ }
41
+
42
+ .icon {
43
+ position: absolute;
44
+ top: 50%;
45
+ right: 16px;
46
+ width: 24px;
47
+ height: 24px;
48
+ color: var(--color-ubie-blue-600);
49
+ pointer-events: none;
50
+ transform: translateY(-50%);
51
+ }
52
+
53
+ .disabled .select {
54
+ color: var(--color-on-surface-variant);
55
+ background-color: var(--color-outline-variant);
56
+ border-color: var(--color-outline);
57
+ }
58
+
59
+ .disabled .icon {
60
+ color: var(--color-on-surface-variant);
61
+ }
62
+
63
+ .isInvalid .select {
64
+ background: var(--color-error-container);
65
+ border-color: var(--color-error);
66
+ }
67
+
68
+ .isInvalid .icon {
69
+ color: var(--color-ubie-red-700);
70
+ }
@@ -0,0 +1,12 @@
1
+ import { render } from "@testing-library/react";
2
+ import { createRef } from "react";
3
+ import { Select } from "./Select";
4
+
5
+ describe("Select", () => {
6
+ it("access to DOM through ref prop", () => {
7
+ const ref = createRef<HTMLSelectElement>();
8
+ render(<Select ref={ref}>Test</Select>);
9
+ expect(ref.current).not.toBeNull();
10
+ expect(ref.current?.tagName).toBe("SELECT");
11
+ });
12
+ });
@@ -0,0 +1,56 @@
1
+ "use client";
2
+
3
+ import { UnfoldMoreIcon } from "@ubie/vitals-icon";
4
+ import clsx from "clsx";
5
+ import { forwardRef, InputHTMLAttributes } from "react";
6
+ import styles from "./Select.module.css";
7
+ import { CustomDataAttributeProps } from "../../types/attributes";
8
+
9
+ type Props = CustomDataAttributeProps & {
10
+ /**
11
+ * ネイティブ要素の `id` 属性。ページで固有のIDを指定
12
+ */
13
+ id?: string;
14
+ /**
15
+ * 有効でない入力を保持しているかどうか
16
+ * @default false
17
+ */
18
+ isInvalid?: boolean;
19
+ /**
20
+ * フィールドを無効化する
21
+ */
22
+ disabled?: boolean;
23
+ /**
24
+ * CSSのクラス
25
+ */
26
+ className?: string;
27
+ } & Omit<InputHTMLAttributes<HTMLSelectElement>, "id" | "disabled">;
28
+
29
+ const Select = forwardRef<HTMLSelectElement, Props>(
30
+ ({ isInvalid = false, disabled = false, children, className, ...props }, ref) => {
31
+ return (
32
+ <div
33
+ className={clsx(
34
+ { [styles.isInvalid]: isInvalid, [styles.disabled]: disabled },
35
+ styles.wrapper,
36
+ className,
37
+ )}
38
+ >
39
+ <select
40
+ {...props}
41
+ disabled={disabled}
42
+ className={styles.select}
43
+ ref={ref}
44
+ aria-invalid={isInvalid}
45
+ >
46
+ {children}
47
+ </select>
48
+ <UnfoldMoreIcon aria-hidden className={styles.icon} />
49
+ </div>
50
+ );
51
+ },
52
+ );
53
+
54
+ Select.displayName = "Select";
55
+
56
+ export { Select };
@@ -0,0 +1,10 @@
1
+ .stack {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--gap);
5
+ width: var(--width);
6
+ min-width: var(--min-width);
7
+ max-width: var(--max-width);
8
+ padding: var(--padding-top) var(--padding-right) var(--padding-bottom) var(--padding-left);
9
+ margin: var(--margin-top) var(--margin-right) var(--margin-bottom) var(--margin-left);
10
+ }
@@ -0,0 +1,177 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { Stack } from "./Stack";
3
+
4
+ describe("<Stack>", () => {
5
+ it("has all the margins through m prop", () => {
6
+ render(
7
+ <Stack spacing="xs" m="xxs" data-testid="box">
8
+ test
9
+ </Stack>,
10
+ );
11
+ const div = screen.getByTestId("box");
12
+
13
+ expect(div).toHaveStyle("--margin-top: var(--size-spacing-xxs)");
14
+ expect(div).toHaveStyle("--margin-right: var(--size-spacing-xxs)");
15
+ expect(div).toHaveStyle("--margin-bottom: var(--size-spacing-xxs)");
16
+ expect(div).toHaveStyle("--margin-left: var(--size-spacing-xxs)");
17
+ });
18
+
19
+ it("has a horizontal margins through mx prop", () => {
20
+ render(
21
+ <Stack spacing="xs" mx="xxs" data-testid="box">
22
+ Test
23
+ </Stack>,
24
+ );
25
+ const div = screen.getByTestId("box");
26
+
27
+ expect(div).toHaveStyle("--margin-top: 0");
28
+ expect(div).toHaveStyle("--margin-right: var(--size-spacing-xxs)");
29
+ expect(div).toHaveStyle("--margin-bottom: 0");
30
+ expect(div).toHaveStyle("--margin-left: var(--size-spacing-xxs)");
31
+ });
32
+
33
+ it("has a vertical margins of through my prop", () => {
34
+ render(
35
+ <Stack spacing="xs" my="xxs" data-testid="box">
36
+ Test
37
+ </Stack>,
38
+ );
39
+ const div = screen.getByTestId("box");
40
+
41
+ expect(div).toHaveStyle("--margin-top: var(--size-spacing-xxs)");
42
+ expect(div).toHaveStyle("--margin-right: 0");
43
+ expect(div).toHaveStyle("--margin-bottom: var(--size-spacing-xxs)");
44
+ expect(div).toHaveStyle("--margin-left: 0");
45
+ });
46
+
47
+ it("has all margins through individual margin props", () => {
48
+ render(
49
+ <Stack spacing="xs" mt="xxs" mr="xs" mb="sm" ml="md" data-testid="box">
50
+ Test
51
+ </Stack>,
52
+ );
53
+ const div = screen.getByTestId("box");
54
+
55
+ expect(div).toHaveStyle("--margin-top: var(--size-spacing-xxs)");
56
+ expect(div).toHaveStyle("--margin-right: var(--size-spacing-xs)");
57
+ expect(div).toHaveStyle("--margin-bottom: var(--size-spacing-sm)");
58
+ expect(div).toHaveStyle("--margin-left: var(--size-spacing-md)");
59
+ });
60
+
61
+ it("gives priority to individual margin props", () => {
62
+ render(
63
+ <Stack spacing="xs" m="xxs" mx="xs" my="xs" mt="sm" mr="md" mb="lg" ml="xl" data-testid="box">
64
+ Test
65
+ </Stack>,
66
+ );
67
+ const div = screen.getByTestId("box");
68
+
69
+ expect(div).toHaveStyle("--margin-top: var(--size-spacing-sm)");
70
+ expect(div).toHaveStyle("--margin-right: var(--size-spacing-md)");
71
+ expect(div).toHaveStyle("--margin-bottom: var(--size-spacing-lg)");
72
+ expect(div).toHaveStyle("--margin-left: var(--size-spacing-xl)");
73
+ });
74
+
75
+ it("has all the paddings through p prop", () => {
76
+ render(
77
+ <Stack spacing="xs" p="xxs" data-testid="box">
78
+ Test
79
+ </Stack>,
80
+ );
81
+ const div = screen.getByTestId("box");
82
+
83
+ expect(div).toHaveStyle("--padding-top: var(--size-spacing-xxs)");
84
+ expect(div).toHaveStyle("--padding-right: var(--size-spacing-xxs)");
85
+ expect(div).toHaveStyle("--padding-bottom: var(--size-spacing-xxs)");
86
+ expect(div).toHaveStyle("--padding-left: var(--size-spacing-xxs)");
87
+ });
88
+
89
+ it("has a horizontal paddings through px prop", () => {
90
+ render(
91
+ <Stack spacing="xs" px="xxs" data-testid="box">
92
+ Test
93
+ </Stack>,
94
+ );
95
+ const div = screen.getByTestId("box");
96
+
97
+ expect(div).toHaveStyle("--padding-top: 0");
98
+ expect(div).toHaveStyle("--padding-right: var(--size-spacing-xxs)");
99
+ expect(div).toHaveStyle("--padding-bottom: 0");
100
+ expect(div).toHaveStyle("--padding-left: var(--size-spacing-xxs)");
101
+ });
102
+
103
+ it("has a vertical paddings of through px prop", () => {
104
+ render(
105
+ <Stack spacing="xs" py="xxs" data-testid="box">
106
+ Test
107
+ </Stack>,
108
+ );
109
+ const div = screen.getByTestId("box");
110
+
111
+ expect(div).toHaveStyle("--padding-top: var(--size-spacing-xxs)");
112
+ expect(div).toHaveStyle("--padding-right: 0");
113
+ expect(div).toHaveStyle("--padding-bottom: var(--size-spacing-xxs)");
114
+ expect(div).toHaveStyle("--padding-left: 0");
115
+ });
116
+
117
+ it("has all paddings through individual padding props", () => {
118
+ render(
119
+ <Stack spacing="xs" pt="xxs" pr="xs" pb="sm" pl="md" data-testid="box">
120
+ Test
121
+ </Stack>,
122
+ );
123
+ const div = screen.getByTestId("box");
124
+
125
+ expect(div).toHaveStyle("--padding-top: var(--size-spacing-xxs)");
126
+ expect(div).toHaveStyle("--padding-right: var(--size-spacing-xs)");
127
+ expect(div).toHaveStyle("--padding-bottom: var(--size-spacing-sm)");
128
+ expect(div).toHaveStyle("--padding-left: var(--size-spacing-md)");
129
+ });
130
+
131
+ it("gives priority to individual padding props", () => {
132
+ render(
133
+ <Stack spacing="xs" p="xxs" px="xs" py="xs" pt="sm" pr="md" pb="lg" pl="xl" data-testid="box">
134
+ Test
135
+ </Stack>,
136
+ );
137
+ const div = screen.getByTestId("box");
138
+
139
+ expect(div).toHaveStyle("--padding-top: var(--size-spacing-sm)");
140
+ expect(div).toHaveStyle("--padding-right: var(--size-spacing-md)");
141
+ expect(div).toHaveStyle("--padding-bottom: var(--size-spacing-lg)");
142
+ expect(div).toHaveStyle("--padding-left: var(--size-spacing-xl)");
143
+ });
144
+
145
+ it("receives width", () => {
146
+ render(
147
+ <Stack width="100px" data-testid="flex-item">
148
+ Test
149
+ </Stack>,
150
+ );
151
+ const div = screen.getByTestId("flex-item");
152
+
153
+ expect(div).toHaveStyle("--width: 100px");
154
+ });
155
+
156
+ it("receives max-width", () => {
157
+ render(
158
+ <Stack maxWidth="100px" data-testid="flex-item">
159
+ Test
160
+ </Stack>,
161
+ );
162
+ const div = screen.getByTestId("flex-item");
163
+
164
+ expect(div).toHaveStyle("--max-width: 100px");
165
+ });
166
+
167
+ it("receives min-width", () => {
168
+ render(
169
+ <Stack minWidth="100px" data-testid="flex-item">
170
+ Test
171
+ </Stack>,
172
+ );
173
+ const div = screen.getByTestId("flex-item");
174
+
175
+ expect(div).toHaveStyle("--min-width: 100px");
176
+ });
177
+ });
@@ -0,0 +1,151 @@
1
+ "use client";
2
+
3
+ import { clsx } from "clsx";
4
+ import { cloneElement, isValidElement, useMemo } from "react";
5
+ import styles from "./Stack.module.css";
6
+ import { CustomDataAttributeProps } from "../../types/attributes"; // 追加したインポート
7
+ import { AlignItems, JustifyContent, Spacing, WidthProps } from "../../types/style";
8
+ import { gapVariables, marginVariables, paddingVariables, widthVariables } from "../../utils/style";
9
+ import { HTMLTagname } from "../../utils/types";
10
+ import { Box } from "../Box/Box";
11
+ import type { MarginProps, PaddingProps } from "../../types/style";
12
+ import type { ComponentType, FC, ReactElement, ReactNode } from "react";
13
+
14
+ type Props = {
15
+ /**
16
+ * レンダリングされるコンポーネントまたはHTML要素
17
+ * @default div
18
+ */
19
+ as?: HTMLTagname | ReactElement<ComponentType<typeof Box>>;
20
+ /**
21
+ * 水平方向における子要素のレイアウトを定める。
22
+ * @default stretch
23
+ */
24
+ alignItems?: AlignItems;
25
+ /**
26
+ * 垂直方向における子要素のレイアウトを定める。
27
+ * @deprecated directionが削除されたため必要なくなりました
28
+ */
29
+ justifyContent?: JustifyContent;
30
+ /**
31
+ * CSSのクラス
32
+ * @deprecated マージンなどをつけたい場合は<Box>を使ってください
33
+ */
34
+ className?: string;
35
+ /**
36
+ * 子要素
37
+ */
38
+ children: ReactNode;
39
+ } & (
40
+ | {
41
+ /**
42
+ * 子要素の間隔。指定しない場合は0
43
+ * xxs=4px, xs=8px, sm=12px, md=16px, lg=24px, xl=40px, xxl=64px
44
+ */
45
+ spacing: Spacing;
46
+ gap?: never;
47
+ }
48
+ | {
49
+ /**
50
+ * spacingのエイリアス(どちらかしか指定できません)
51
+ * xxs=4px, xs=8px, sm=12px, md=16px, lg=24px, xl=40px, xxl=64px
52
+ */
53
+ gap: Spacing;
54
+ spacing?: never;
55
+ }
56
+ | {
57
+ gap?: never;
58
+ spacing?: never;
59
+ }
60
+ ) &
61
+ MarginProps &
62
+ PaddingProps &
63
+ WidthProps &
64
+ CustomDataAttributeProps;
65
+
66
+ /**
67
+ * Stackコンポーネント
68
+ * 一方向に一定のリズムで要素を積み上げるレイアウト
69
+ */
70
+ export const Stack: FC<Props> = ({
71
+ as: StackComponent = "div",
72
+ children,
73
+ className,
74
+ spacing,
75
+ gap,
76
+ alignItems = "stretch",
77
+ justifyContent = "flex-start",
78
+ p,
79
+ px,
80
+ py,
81
+ pt,
82
+ pr,
83
+ pb,
84
+ pl,
85
+ m,
86
+ mx,
87
+ my,
88
+ mt,
89
+ mr,
90
+ mb,
91
+ ml,
92
+ width,
93
+ minWidth,
94
+ maxWidth,
95
+ ...otherProps
96
+ }) => {
97
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
98
+ const createElement = (props: any, children: ReactNode) => {
99
+ if (isValidElement(StackComponent)) {
100
+ return cloneElement(StackComponent, StackComponent.props, <div {...props}>{children}</div>);
101
+ } else {
102
+ return <StackComponent {...props}>{children}</StackComponent>;
103
+ }
104
+ };
105
+
106
+ const _spacing = useMemo(() => {
107
+ if (gap != null) {
108
+ return gap;
109
+ } else if (spacing != null) {
110
+ return spacing;
111
+ } else {
112
+ return undefined;
113
+ }
114
+ }, [gap, spacing]);
115
+
116
+ return createElement(
117
+ {
118
+ className: clsx(className, styles.stack),
119
+ style: {
120
+ alignItems: `${alignItems}`,
121
+ justifyContent: `${justifyContent}`,
122
+ ...gapVariables(_spacing),
123
+ ...paddingVariables({
124
+ p,
125
+ px,
126
+ py,
127
+ pt,
128
+ pr,
129
+ pb,
130
+ pl,
131
+ }),
132
+ ...marginVariables({
133
+ m,
134
+ mx,
135
+ my,
136
+ mt,
137
+ mr,
138
+ mb,
139
+ ml,
140
+ }),
141
+ ...widthVariables({
142
+ width,
143
+ minWidth,
144
+ maxWidth,
145
+ }),
146
+ },
147
+ ...otherProps,
148
+ },
149
+ children,
150
+ );
151
+ };
@@ -0,0 +1,137 @@
1
+ .stepper {
2
+ display: flex;
3
+ flex-direction: row;
4
+ align-items: stretch;
5
+ justify-content: stretch;
6
+ margin: var(--margin-top) var(--margin-right) var(--margin-bottom) var(--margin-left);
7
+ }
8
+
9
+ .stepperItem {
10
+ position: relative;
11
+ display: flex;
12
+ flex: 1;
13
+ flex-direction: column;
14
+ gap: 8px;
15
+ align-items: center;
16
+ }
17
+
18
+ .borderLine {
19
+ position: absolute;
20
+ top: 12px; /* Center the line with the 24px icon (12px from top) */
21
+ right: 0;
22
+ left: 0;
23
+ z-index: 1;
24
+ display: flex;
25
+ flex-direction: row;
26
+ align-items: center;
27
+ }
28
+
29
+ .iconSpacer {
30
+ flex-shrink: 0;
31
+ width: 32px;
32
+ }
33
+
34
+ .leftBorder,
35
+ .rightBorder {
36
+ display: flex;
37
+ flex: 1;
38
+ align-items: center;
39
+ }
40
+
41
+ .border.hidden {
42
+ display: none;
43
+ }
44
+
45
+ .border {
46
+ width: 100%;
47
+ height: 2px;
48
+ background-color: var(--stepper-border-color, var(--color-ubie-gray-300));
49
+ }
50
+
51
+ .iconWrapper {
52
+ position: relative;
53
+ z-index: 2;
54
+ display: flex;
55
+ flex-shrink: 0;
56
+ align-items: center;
57
+ justify-content: center;
58
+ width: 24px;
59
+ height: 24px;
60
+ }
61
+
62
+ /* Border color variants */
63
+ .borderColorBlue {
64
+ --stepper-border-color: var(--color-ubie-blue-600);
65
+ }
66
+
67
+ .borderColorGray {
68
+ --stepper-border-color: var(--color-ubie-gray-300);
69
+ }
70
+
71
+ /* Circle styles for different statuses */
72
+ .doneCircle {
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: center;
76
+ width: 24px;
77
+ height: 24px;
78
+ padding: 2px;
79
+ color: var(--color-ubie-blue-600);
80
+ background-color: #fff;
81
+ border: 2px solid var(--color-ubie-blue-600);
82
+ border-radius: 50%;
83
+ }
84
+
85
+ .currentCircle {
86
+ position: relative;
87
+ width: 24px;
88
+ height: 24px;
89
+ background-color: var(--color-ubie-blue-600);
90
+ border-radius: 50%;
91
+ }
92
+
93
+ .undoneCircle {
94
+ width: 24px;
95
+ height: 24px;
96
+ background-color: #fff;
97
+ border: 2px solid var(--stepper-border-color, var(--color-ubie-gray-300));
98
+ border-radius: 50%;
99
+ }
100
+
101
+ /* Icon colors for custom icons */
102
+ .current .iconWrapper {
103
+ color: var(--color-ubie-blue-600);
104
+ }
105
+
106
+ .done .iconWrapper {
107
+ color: var(--color-ubie-blue-600);
108
+ }
109
+
110
+ .undone .iconWrapper {
111
+ color: var(--color-ubie-gray-300);
112
+ }
113
+
114
+ .label {
115
+ width: 100%;
116
+ font-family: sans-serif;
117
+ font-size: 12px;
118
+ line-height: 1.5;
119
+ text-align: center;
120
+ word-wrap: break-word;
121
+ white-space: pre-wrap;
122
+ }
123
+
124
+ .currentLabel {
125
+ font-weight: 600;
126
+ color: #000;
127
+ }
128
+
129
+ .doneLabel {
130
+ font-weight: 400;
131
+ color: #000;
132
+ }
133
+
134
+ .undoneLabel {
135
+ font-weight: 400;
136
+ color: #000;
137
+ }