@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,302 @@
1
+ import { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { ComponentProps, useState } from "react";
3
+ import { ActionModal } from "./ActionModal";
4
+
5
+ export default {
6
+ title: "Modal/ActionModal",
7
+ component: ActionModal,
8
+ } satisfies Meta<typeof ActionModal>;
9
+
10
+ type Story = StoryObj<typeof ActionModal>;
11
+
12
+ const defaultArgs: Partial<ComponentProps<typeof ActionModal>> = {
13
+ header: "モーダル",
14
+ overlayOpacity: "normal",
15
+ primaryActionLabel: "回答結果を見る",
16
+ fixedHeight: false,
17
+ isStatic: false,
18
+ stickyHeader: false,
19
+ stickyFooter: false,
20
+ } as const satisfies Partial<ComponentProps<typeof ActionModal>>;
21
+
22
+ const LongBody = () => (
23
+ <>
24
+ <p style={{ margin: 0 }}>
25
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has
26
+ been the industry&apos;s standard dummy text ever since the 1500s, when an unknown printer
27
+ took a galley of type and scrambled it to make a type specimen book. It has survived not only
28
+ five centuries, but also the leap into electronic typesetting, remaining essentially
29
+ unchanged. It was popularised in the 1960s with the release of Letraset sheets containing
30
+ Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker
31
+ including versions of Lorem Ipsum.
32
+ </p>
33
+ <p style={{ margin: "12px 0 0" }}>
34
+ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of
35
+ classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a
36
+ Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin
37
+ words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in
38
+ classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections
39
+ 1.10.32 and 1.10.33 of &quot;de Finibus Bonorum et Malorum&quot; (The Extremes of Good and
40
+ Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very
41
+ popular during the Renaissance. The first line of Lorem Ipsum, &quot;Lorem ipsum dolor sit
42
+ amet..&quot;, comes from a line in section 1.10.32.
43
+ </p>
44
+ </>
45
+ );
46
+
47
+ export const Default: Story = {
48
+ render: (args) => {
49
+ const [open, setOpen] = useState(true);
50
+
51
+ return (
52
+ <>
53
+ <button type="button" onClick={() => setOpen(true)}>
54
+ Open Modal
55
+ </button>
56
+ <ActionModal
57
+ {...args}
58
+ open={open}
59
+ onPrimaryAction={() => setOpen(false)}
60
+ onClose={() => setOpen(false)}
61
+ >
62
+ <LongBody />
63
+ </ActionModal>
64
+ </>
65
+ );
66
+ },
67
+ args: defaultArgs,
68
+ };
69
+
70
+ export const Secondary: Story = {
71
+ render: (args) => {
72
+ const [open, setOpen] = useState(false);
73
+
74
+ return (
75
+ <>
76
+ <button type="button" onClick={() => setOpen(true)}>
77
+ Open Modal
78
+ </button>
79
+ <ActionModal
80
+ {...args}
81
+ open={open}
82
+ onPrimaryAction={() => setOpen(false)}
83
+ secondaryActionLabel={"このまま回答を続ける"}
84
+ onSecondaryAction={() => setOpen(false)}
85
+ onClose={() => setOpen(false)}
86
+ >
87
+ <LongBody />
88
+ </ActionModal>
89
+ </>
90
+ );
91
+ },
92
+ args: defaultArgs,
93
+ };
94
+
95
+ export const FixedHeight: Story = {
96
+ render: (args) => {
97
+ const [open, setOpen] = useState(false);
98
+
99
+ return (
100
+ <>
101
+ <button type="button" onClick={() => setOpen(true)}>
102
+ Open Modal
103
+ </button>
104
+ <ActionModal
105
+ {...args}
106
+ open={open}
107
+ onPrimaryAction={() => setOpen(false)}
108
+ onClose={() => setOpen(false)}
109
+ >
110
+ <p>contents</p>
111
+ <p>contents</p>
112
+ <p>contents</p>
113
+ <p>contents</p>
114
+ <p>contents</p>
115
+ <p>contents</p>
116
+ <p>contents</p>
117
+ </ActionModal>
118
+ </>
119
+ );
120
+ },
121
+ args: {
122
+ ...defaultArgs,
123
+ fixedHeight: true,
124
+ },
125
+ };
126
+
127
+ export const Customized: Story = {
128
+ render: (args) => {
129
+ const [open, setOpen] = useState(false);
130
+
131
+ return (
132
+ <>
133
+ <button type="button" onClick={() => setOpen(true)}>
134
+ Open Modal
135
+ </button>
136
+ <ActionModal
137
+ {...args}
138
+ open={open}
139
+ onPrimaryAction={() => setOpen(false)}
140
+ onClose={() => setOpen(false)}
141
+ >
142
+ <p>Customized</p>
143
+ </ActionModal>
144
+ </>
145
+ );
146
+ },
147
+ args: {
148
+ ...defaultArgs,
149
+ header: "削除します",
150
+ primaryActionColor: "alert",
151
+ overlayOpacity: "darker",
152
+ closeLabel: "キャンセル",
153
+ },
154
+ };
155
+
156
+ export const CustomDataAttribute: Story = {
157
+ render: (args) => {
158
+ const [open, setOpen] = useState(false);
159
+
160
+ return (
161
+ <>
162
+ <button type="button" onClick={() => setOpen(true)}>
163
+ Open Modal
164
+ </button>
165
+ <ActionModal
166
+ {...args}
167
+ open={open}
168
+ onPrimaryAction={() => setOpen(false)}
169
+ onClose={() => setOpen(false)}
170
+ >
171
+ <p>Default</p>
172
+ </ActionModal>
173
+ </>
174
+ );
175
+ },
176
+ args: {
177
+ ...defaultArgs,
178
+ [`data-test-id`]: "some-id",
179
+ },
180
+ };
181
+
182
+ export const WithId: Story = {
183
+ render: (args) => {
184
+ const [open, setOpen] = useState(false);
185
+
186
+ return (
187
+ <>
188
+ <button type="button" onClick={() => setOpen(true)}>
189
+ Open Modal
190
+ </button>
191
+ <ActionModal
192
+ {...args}
193
+ open={open}
194
+ onPrimaryAction={() => setOpen(false)}
195
+ onClose={() => setOpen(false)}
196
+ >
197
+ <LongBody />
198
+ </ActionModal>
199
+ </>
200
+ );
201
+ },
202
+ args: {
203
+ ...defaultArgs,
204
+ id: "dialog-id",
205
+ },
206
+ };
207
+
208
+ export const CustomHeader: Story = {
209
+ render: (args) => {
210
+ const [open, setOpen] = useState(false);
211
+ const headerId = "header-id";
212
+
213
+ return (
214
+ <>
215
+ <button type="button" onClick={() => setOpen(true)}>
216
+ Open Modal
217
+ </button>
218
+ <ActionModal
219
+ {...args}
220
+ open={open}
221
+ onPrimaryAction={() => setOpen(false)}
222
+ onClose={() => setOpen(false)}
223
+ ariaLabelledby={headerId}
224
+ >
225
+ <h2 id={headerId} style={{ margin: "0 0 12px" }}>
226
+ Custom Heading
227
+ </h2>
228
+ <LongBody />
229
+ </ActionModal>
230
+ </>
231
+ );
232
+ },
233
+ args: {
234
+ ...defaultArgs,
235
+ header: undefined,
236
+ },
237
+ };
238
+
239
+ export const WithHero: Story = {
240
+ render: (args) => {
241
+ const [open, setOpen] = useState(false);
242
+
243
+ return (
244
+ <>
245
+ <button type="button" onClick={() => setOpen(true)}>
246
+ Open Modal
247
+ </button>
248
+ <ActionModal
249
+ hero={
250
+ <img
251
+ src="/images/placeholder.svg"
252
+ alt="Illustration: Modal"
253
+ style={{ width: "100%", height: "auto", verticalAlign: "bottom" }}
254
+ width={560}
255
+ height={315}
256
+ />
257
+ }
258
+ {...args}
259
+ open={open}
260
+ onPrimaryAction={() => setOpen(false)}
261
+ onClose={() => setOpen(false)}
262
+ >
263
+ <p style={{ margin: 0 }}>
264
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
265
+ has been the industry&apos;s standard dummy text ever since the 1500s, when an unknown
266
+ printer took a galley of type and scrambled it to make a type specimen book.
267
+ </p>
268
+ </ActionModal>
269
+ </>
270
+ );
271
+ },
272
+ args: {
273
+ ...defaultArgs,
274
+ },
275
+ };
276
+
277
+ export const StickyHeaderAndFooter: Story = {
278
+ render: (args) => {
279
+ const [open, setOpen] = useState(true);
280
+
281
+ return (
282
+ <>
283
+ <button type="button" onClick={() => setOpen(true)}>
284
+ Open Modal
285
+ </button>
286
+ <ActionModal
287
+ {...args}
288
+ open={open}
289
+ onPrimaryAction={() => setOpen(false)}
290
+ onClose={() => setOpen(false)}
291
+ >
292
+ <LongBody />
293
+ </ActionModal>
294
+ </>
295
+ );
296
+ },
297
+ args: {
298
+ ...defaultArgs,
299
+ stickyHeader: true,
300
+ stickyFooter: true,
301
+ },
302
+ };
@@ -0,0 +1,232 @@
1
+ "use client";
2
+
3
+ import { Dialog, DialogPanel, DialogTitle, Transition } from "@headlessui/react";
4
+ import clsx from "clsx";
5
+ import { type FC, Fragment, type ReactNode, useCallback, useRef } from "react";
6
+ import styles from "./ActionModal.module.css";
7
+ import { Button } from "../../";
8
+ import { useScrollable } from "../../hooks/useScrollable";
9
+ import { VisuallyHidden } from "../../sharedComponents/VisuallyHidden/VisuallyHidden";
10
+ import { CustomDataAttributeProps } from "../../types/attributes";
11
+ import { opacityToClassName } from "../../utils/style";
12
+ import { AllOrNone } from "../../utils/types";
13
+
14
+ type Opacity = "normal" | "darker";
15
+
16
+ type BaseProps = {
17
+ /**
18
+ * コンテンツとして表示する内容
19
+ */
20
+ children: ReactNode;
21
+ /**
22
+ * 閉じるアクションが実行された場合のコールバック
23
+ */
24
+ onClose: () => void;
25
+ /**
26
+ * プライマリーアクションボタンが実行された場合のコールバック
27
+ */
28
+ onPrimaryAction?: () => void;
29
+ /**
30
+ * ヘッダーに表示する見出しテキスト
31
+ */
32
+ header?: string;
33
+ /**
34
+ * プライマリーアクションボタンのラベル
35
+ */
36
+ primaryActionLabel?: string;
37
+ /**
38
+ * プライマリーアクションボタンのカラースキーム
39
+ */
40
+ primaryActionColor?: "primary" | "alert";
41
+ /**
42
+ * 閉じるボタンのラベル
43
+ * @default 閉じる
44
+ */
45
+ closeLabel?: string;
46
+ /**
47
+ * オーバーレイの透過度
48
+ * @default normal
49
+ */
50
+ overlayOpacity?: Opacity;
51
+ /**
52
+ * 画面を占有する高さで固定するかどうか
53
+ * @default false
54
+ */
55
+ fixedHeight?: boolean;
56
+ /**
57
+ * 閉じるボタンを表示するかどうか
58
+ * @default true
59
+ */
60
+ showClose?: boolean;
61
+ /**
62
+ * モーダルダイアログを開くかどうか
63
+ * @default true
64
+ */
65
+ open?: boolean;
66
+ /**
67
+ * openを無視してモーダルを開いたままにするかどうか。アニメーションライブラリとの連携で、ActionHalfModal自身が開閉に関与しない場合に使用
68
+ */
69
+ isStatic?: boolean;
70
+ /**
71
+ * ネイティブ要素のid属性。ページで固有のIDを指定
72
+ */
73
+ id?: string;
74
+ /**
75
+ * ネイティブのaria-labelledby属性。独自の見出しを実装する場合にダイアログとの紐づけに使用。ページで固有のIDを指定
76
+ */
77
+ ariaLabelledby?: string;
78
+ /**
79
+ * ヒーローエリア(見出しの更に上)に配置するコンテンツ
80
+ */
81
+ hero?: ReactNode;
82
+ /**
83
+ * ヘッダーを固定表示
84
+ * heroが指定されている場合は無効
85
+ */
86
+ stickyHeader?: boolean;
87
+ /**
88
+ * フッターを固定表示
89
+ */
90
+ stickyFooter?: boolean;
91
+ };
92
+
93
+ type SecondaryActionProps = {
94
+ /**
95
+ * セカンダリーアクションが実行された場合のコールバック
96
+ */
97
+ onSecondaryAction: () => void;
98
+ /**
99
+ * セカンダリーアクションボタンのラベル
100
+ */
101
+ secondaryActionLabel: string;
102
+ };
103
+
104
+ type Props = BaseProps & AllOrNone<SecondaryActionProps> & CustomDataAttributeProps;
105
+
106
+ export const ActionModal: FC<Props> = ({
107
+ children,
108
+ onClose,
109
+ onPrimaryAction,
110
+ onSecondaryAction,
111
+ header,
112
+ primaryActionLabel,
113
+ secondaryActionLabel,
114
+ primaryActionColor,
115
+ closeLabel = "閉じる",
116
+ overlayOpacity = "normal",
117
+ fixedHeight = false,
118
+ showClose = true,
119
+ open = true,
120
+ isStatic = false,
121
+ ariaLabelledby,
122
+ hero,
123
+ stickyHeader = false,
124
+ stickyFooter = false,
125
+ ...props
126
+ }) => {
127
+ const opacityClassName = opacityToClassName(overlayOpacity);
128
+
129
+ const initialFocusRef = useRef(null);
130
+
131
+ const dialogRef = useCallback(
132
+ (node: HTMLDivElement | null) => {
133
+ if (node !== null && header == null && ariaLabelledby != null) {
134
+ node.setAttribute("aria-labelledby", ariaLabelledby);
135
+ } else if (node !== null && header == null && ariaLabelledby == null) {
136
+ node.removeAttribute("aria-labelledby");
137
+ }
138
+ },
139
+ [ariaLabelledby, header],
140
+ );
141
+
142
+ const { scrollContainerRef, canScrollUp, canScrollDown } = useScrollable();
143
+
144
+ return (
145
+ <Transition
146
+ show={open}
147
+ as={Fragment}
148
+ enter={styles.panelEnter}
149
+ enterFrom={styles.panelEnterFrom}
150
+ enterTo={styles.panelEnterTo}
151
+ leave={styles.panelLeave}
152
+ leaveFrom={styles.panelLeaveFrom}
153
+ leaveTo={styles.panelLeaveTo}
154
+ >
155
+ <Dialog
156
+ ref={dialogRef}
157
+ static={isStatic}
158
+ onClose={onClose}
159
+ className={styles.modal}
160
+ aria-labelledby={ariaLabelledby}
161
+ initialFocus={initialFocusRef}
162
+ {...props}
163
+ >
164
+ <div className={clsx(styles.overlay, styles[opacityClassName])} />
165
+ <DialogPanel
166
+ className={clsx(styles.dialog, {
167
+ [styles.fixedHeight]: fixedHeight,
168
+ })}
169
+ >
170
+ {header === undefined ? (
171
+ <VisuallyHidden as="p" tabIndex={-1} ref={initialFocusRef}>
172
+ ダイアログ
173
+ </VisuallyHidden>
174
+ ) : null}
175
+ <div className={styles.scrollContainer} ref={scrollContainerRef}>
176
+ <div
177
+ className={clsx(styles.mainContent, {
178
+ [styles.headerLess]: header === undefined && hero === undefined,
179
+ [styles.fixedHeight]: fixedHeight,
180
+ })}
181
+ >
182
+ {hero !== undefined ? <div className={styles.hero}>{hero}</div> : null}
183
+ {header !== undefined ? (
184
+ <DialogTitle
185
+ tabIndex={-1}
186
+ ref={initialFocusRef}
187
+ className={clsx(
188
+ styles.header,
189
+ !hero && stickyHeader && styles.sticky,
190
+ canScrollUp && styles.canScroll,
191
+ )}
192
+ >
193
+ {header}
194
+ </DialogTitle>
195
+ ) : null}
196
+ <div
197
+ className={clsx(styles.body, {
198
+ [styles.fixedHeight]: fixedHeight,
199
+ })}
200
+ >
201
+ {children}
202
+ </div>
203
+ <div
204
+ className={clsx(
205
+ styles.buttonContainer,
206
+ stickyFooter && styles.sticky,
207
+ canScrollDown && styles.canScroll,
208
+ )}
209
+ >
210
+ {onPrimaryAction && primaryActionLabel && (
211
+ <Button block onClick={onPrimaryAction} variant={primaryActionColor}>
212
+ {primaryActionLabel}
213
+ </Button>
214
+ )}
215
+ {onSecondaryAction && secondaryActionLabel && (
216
+ <Button block variant="secondary" onClick={onSecondaryAction}>
217
+ {secondaryActionLabel}
218
+ </Button>
219
+ )}
220
+ {showClose && (
221
+ <Button variant="text" onClick={onClose}>
222
+ {closeLabel}
223
+ </Button>
224
+ )}
225
+ </div>
226
+ </div>
227
+ </div>
228
+ </DialogPanel>
229
+ </Dialog>
230
+ </Transition>
231
+ );
232
+ };
@@ -0,0 +1,4 @@
1
+ .bold {
2
+ font-style: normal;
3
+ font-weight: bold;
4
+ }
@@ -0,0 +1,24 @@
1
+ import { composeStory } from "@storybook/react-vite";
2
+ import { render, screen } from "@testing-library/react";
3
+ import Meta, { WithId, CustomDataAttribute } from "./Bold.stories";
4
+
5
+ const WithIdStory = composeStory(WithId, Meta);
6
+ const CustomDataAttributeStory = composeStory(CustomDataAttribute, Meta);
7
+
8
+ describe("Bold", () => {
9
+ test("Add id", async () => {
10
+ render(<WithIdStory />);
11
+
12
+ const boldElement = screen.queryByText("太字");
13
+
14
+ expect(boldElement).toHaveAttribute("id", "some-id");
15
+ });
16
+
17
+ test("Add custom data attribute", async () => {
18
+ render(<CustomDataAttributeStory />);
19
+
20
+ const boldElement = screen.queryByText("太字");
21
+
22
+ expect(boldElement).toHaveAttribute("data-test-id", "some-id");
23
+ });
24
+ });
@@ -0,0 +1,54 @@
1
+ import { StoryObj, Meta } from "@storybook/react-vite";
2
+ import { Bold } from "./Bold";
3
+ import { Stack } from "../Stack/Stack";
4
+ import { Text } from "../Text/Text";
5
+
6
+ export default {
7
+ title: "Typography/font/Bold",
8
+ component: Bold,
9
+ } satisfies Meta<typeof Bold>;
10
+
11
+ type Story = StoryObj<typeof Bold>;
12
+
13
+ export const AsVarations: Story = {
14
+ render: () => {
15
+ return (
16
+ <Stack spacing="md">
17
+ <Bold>default(span)</Bold>
18
+ <Bold as="span">span</Bold>
19
+ <Bold as="b">b</Bold>
20
+ <Bold as="strong">strong</Bold>
21
+ <Bold as="em">em</Bold>
22
+ <Bold as="i">i</Bold>
23
+ </Stack>
24
+ );
25
+ },
26
+ };
27
+
28
+ export const WithText: Story = {
29
+ render: () => {
30
+ return (
31
+ <Text type="body" size="lg" color="main">
32
+ 一部だけ<Bold>太字</Bold>にしたい
33
+ </Text>
34
+ );
35
+ },
36
+ };
37
+
38
+ export const WithId: Story = {
39
+ render: (args) => {
40
+ return <Bold {...args}>太字</Bold>;
41
+ },
42
+ args: {
43
+ id: "some-id",
44
+ },
45
+ };
46
+
47
+ export const CustomDataAttribute: Story = {
48
+ render: (args) => {
49
+ return <Bold {...args}>太字</Bold>;
50
+ },
51
+ args: {
52
+ [`data-test-id`]: "some-id",
53
+ },
54
+ };
@@ -0,0 +1,31 @@
1
+ import { type FC, type ReactNode } from "react";
2
+ import styles from "./Bold.module.css";
3
+ import { CustomDataAttributeProps } from "../../types/attributes";
4
+
5
+ type Props = {
6
+ /**
7
+ * 太字にするテキスト
8
+ * <p>や<div>などを子要素に指定しないでください(文法的にNGです)
9
+ *
10
+ */
11
+ children: ReactNode;
12
+ /**
13
+ * レンダリングされる要素
14
+ * @default span
15
+ */
16
+ as?: "span" | "b" | "strong" | "em" | "i";
17
+ /**
18
+ * ネイティブ要素の`id`属性。ページで固有のIDを指定
19
+ */
20
+ id?: string;
21
+ } & CustomDataAttributeProps;
22
+
23
+ export const Bold: FC<Props> = ({ as = "span", children, id, ...otherProps }) => {
24
+ const BoldComponent = as;
25
+
26
+ return (
27
+ <BoldComponent className={styles.bold} id={id} {...otherProps}>
28
+ {children}
29
+ </BoldComponent>
30
+ );
31
+ };
@@ -0,0 +1,46 @@
1
+ .box {
2
+ box-sizing: border-box;
3
+ display: block;
4
+ width: var(--width);
5
+ min-width: var(--min-width);
6
+ max-width: var(--max-width);
7
+ padding: var(--padding-top) var(--padding-right) var(--padding-bottom) var(--padding-left);
8
+ margin: var(--margin-top) var(--margin-right) var(--margin-bottom) var(--margin-left);
9
+ font-size: var(--text-size);
10
+ font-weight: var(--text-bold);
11
+ hyphens: auto;
12
+ line-height: var(--text-leading);
13
+ color: var(--text-color);
14
+ overflow-wrap: anywhere;
15
+ background-color: var(--background-color);
16
+ border: var(--border-width) solid var(--border-color);
17
+ border-radius: var(--radius);
18
+ }
19
+
20
+ .box.textBold {
21
+ font-weight: bold;
22
+ }
23
+
24
+ .box.textNormal {
25
+ font-weight: normal;
26
+ }
27
+
28
+ .box.textCenter {
29
+ text-align: center;
30
+ }
31
+
32
+ .box.textLeft {
33
+ text-align: left;
34
+ }
35
+
36
+ .box.textRight {
37
+ text-align: right;
38
+ }
39
+
40
+ .box.textNoWrap {
41
+ white-space: nowrap;
42
+ }
43
+
44
+ .box.inline {
45
+ display: inline-block;
46
+ }