@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,269 @@
1
+ "use client";
2
+
3
+ import { Dialog, DialogPanel, Transition, TransitionChild } from "@headlessui/react";
4
+ import { clsx } from "clsx";
5
+ import { type FC, Fragment, type ReactNode, useCallback, useRef } from "react";
6
+ import styles from "./ActionHalfModal.module.css";
7
+ import { useScrollable } from "../../hooks/useScrollable";
8
+ import { VisuallyHidden } from "../../sharedComponents/VisuallyHidden/VisuallyHidden";
9
+ import { CustomDataAttributeProps } from "../../types/attributes";
10
+ import { opacityToClassName } from "../../utils/style";
11
+ import { AllOrNone } from "../../utils/types";
12
+ import { Button } from "../Button/Button";
13
+ import type { CSSMaxHeight } from "../../types/style";
14
+
15
+ type Opacity = "normal" | "darker";
16
+
17
+ type BaseProps = {
18
+ /**
19
+ * コンテンツとして表示する内容
20
+ */
21
+ children: ReactNode;
22
+ /**
23
+ * 閉じるアクションが実行された場合のコールバック
24
+ */
25
+ onClose: () => void;
26
+ /**
27
+ * ヘッダーに表示する見出しテキストまたはReactノード
28
+ */
29
+ header?: ReactNode;
30
+ /**
31
+ * プライマリーアクションボタンのカラースキーム
32
+ */
33
+ primaryActionColor?: "primary" | "alert";
34
+ /**
35
+ * 閉じるボタンのラベル
36
+ * @default 閉じる
37
+ */
38
+ closeLabel?: string;
39
+ /**
40
+ * オーバーレイの透過度
41
+ * @default normal
42
+ */
43
+ overlayOpacity?: Opacity;
44
+ /**
45
+ * 閉じるボタンを表示するかどうか
46
+ * @default true
47
+ */
48
+ showClose?: boolean;
49
+ /**
50
+ * モーダルを開くかどうか
51
+ * @default true
52
+ */
53
+ open?: boolean;
54
+ /**
55
+ * openを無視してモーダルを開いたままにするかどうか。アニメーションライブラリとの連携で、ActionHalfModal自身が開閉に関与しない場合に使用
56
+ */
57
+ isStatic?: boolean;
58
+ /**
59
+ * モーダルをフルスクリーンで表示するかどうか
60
+ */
61
+ fullscreen?: boolean;
62
+ /**
63
+ * ネイティブ要素のid属性。ページで固有のIDを指定
64
+ */
65
+ id?: string;
66
+ /**
67
+ * ネイティブのaria-labelledby属性。独自の見出しを実装する場合にダイアログとの紐づけに使用。ページで固有のIDを指定
68
+ */
69
+ ariaLabelledby?: string;
70
+ /**
71
+ * ヒーローエリア(見出しの更に上)に配置するコンテンツ
72
+ */
73
+ hero?: ReactNode;
74
+ /**
75
+ * ヘッダーを固定表示
76
+ */
77
+ stickyHeader?: boolean;
78
+ /**
79
+ * フッターを固定表示
80
+ */
81
+ stickyFooter?: boolean;
82
+ /**
83
+ * モーダルの最大の高さ
84
+ * @default calc(100% - 24px)
85
+ */
86
+ maxHeight?: CSSMaxHeight;
87
+ };
88
+
89
+ type PrimaryActionProps = {
90
+ /**
91
+ * プライマリーアクションボタンが実行された場合のコールバック
92
+ */
93
+ onPrimaryAction: () => void;
94
+ /**
95
+ * プライマリーアクションボタンのラベル
96
+ */
97
+ primaryActionLabel: string;
98
+ };
99
+
100
+ type SecondaryActionProps = {
101
+ /**
102
+ * セカンダリーアクションボタンが実行された場合のコールバック
103
+ */
104
+ onSecondaryAction: () => void;
105
+ /**
106
+ * セカンダリーアクションボタンのラベル
107
+ */
108
+ secondaryActionLabel: string;
109
+ };
110
+
111
+ type Props = BaseProps &
112
+ AllOrNone<PrimaryActionProps> &
113
+ AllOrNone<SecondaryActionProps> &
114
+ CustomDataAttributeProps;
115
+
116
+ export const ActionHalfModal: FC<Props> = ({
117
+ children,
118
+ onClose,
119
+ onPrimaryAction,
120
+ onSecondaryAction,
121
+ header,
122
+ primaryActionLabel,
123
+ secondaryActionLabel,
124
+ primaryActionColor,
125
+ closeLabel = "閉じる",
126
+ overlayOpacity = "normal",
127
+ showClose = true,
128
+ open = true,
129
+ isStatic = false,
130
+ fullscreen = false,
131
+ ariaLabelledby,
132
+ hero,
133
+ stickyHeader = false,
134
+ stickyFooter = false,
135
+ maxHeight = "calc(100% - 24px)",
136
+ ...props
137
+ }) => {
138
+ const opacityClassName = opacityToClassName(overlayOpacity);
139
+
140
+ const initialFocusRef = useRef(null);
141
+
142
+ const dialogRef = useCallback(
143
+ (node: HTMLDivElement | null) => {
144
+ if (node !== null && (header == null || header === undefined) && ariaLabelledby != null) {
145
+ node.setAttribute("aria-labelledby", ariaLabelledby);
146
+ } else if (
147
+ node !== null &&
148
+ (header == null || header === undefined) &&
149
+ ariaLabelledby == null
150
+ ) {
151
+ node.removeAttribute("aria-labelledby");
152
+ }
153
+ },
154
+ [ariaLabelledby, header],
155
+ );
156
+
157
+ const { scrollContainerRef, canScrollUp, canScrollDown } = useScrollable();
158
+
159
+ return (
160
+ <Transition show={open}>
161
+ <Dialog
162
+ ref={dialogRef}
163
+ static={isStatic}
164
+ onClose={onClose}
165
+ className={clsx(styles.modal, fullscreen && styles.fullscreen)}
166
+ initialFocus={initialFocusRef}
167
+ {...props}
168
+ >
169
+ <TransitionChild
170
+ as={Fragment}
171
+ enter={styles.overlayEnter}
172
+ enterFrom={styles.overlayEnterFrom}
173
+ enterTo={styles.overlayEnterTo}
174
+ leave={styles.overlayLeave}
175
+ leaveFrom={styles.overlayLeaveFrom}
176
+ leaveTo={styles.overlayLeaveTo}
177
+ >
178
+ <div className={clsx(styles.overlay, styles[opacityClassName])} />
179
+ </TransitionChild>
180
+ <TransitionChild
181
+ as={Fragment}
182
+ enter={styles.panelEnter}
183
+ enterFrom={styles.panelEnterFrom}
184
+ enterTo={styles.panelEnterTo}
185
+ leave={styles.panelLeave}
186
+ leaveFrom={styles.panelLeaveFrom}
187
+ leaveTo={styles.panelLeaveTo}
188
+ >
189
+ <DialogPanel
190
+ className={clsx(styles.dialog, {
191
+ [styles.fullscreen]: fullscreen,
192
+ })}
193
+ style={{ maxHeight }}
194
+ >
195
+ {header === undefined || header === null ? (
196
+ <VisuallyHidden as="p" tabIndex={-1} ref={initialFocusRef}>
197
+ ダイアログ
198
+ </VisuallyHidden>
199
+ ) : null}
200
+ <div className={styles.scrollContainer} ref={scrollContainerRef}>
201
+ <div
202
+ className={clsx(styles.mainContent, {
203
+ [styles.headerLess]:
204
+ (header === undefined || header === null) && hero === undefined,
205
+ [styles.fullscreen]: fullscreen,
206
+ })}
207
+ >
208
+ {hero !== undefined ? <div className={styles.hero}>{hero}</div> : null}
209
+ {header !== undefined && header !== null ? (
210
+ <Dialog.Title
211
+ tabIndex={-1}
212
+ ref={initialFocusRef}
213
+ className={clsx(
214
+ styles.header,
215
+ stickyHeader && styles.sticky,
216
+ canScrollUp && styles.canScroll,
217
+ )}
218
+ >
219
+ {header}
220
+ </Dialog.Title>
221
+ ) : null}
222
+ <div
223
+ className={clsx(styles.body, {
224
+ [styles.fullscreen]: fullscreen,
225
+ })}
226
+ >
227
+ {children}
228
+ </div>
229
+ <div
230
+ className={clsx(
231
+ styles.buttonContainer,
232
+ stickyFooter && styles.sticky,
233
+ canScrollDown && styles.canScroll,
234
+ )}
235
+ >
236
+ {onPrimaryAction && primaryActionLabel && (
237
+ <Button
238
+ block
239
+ onClick={onPrimaryAction}
240
+ aria-label={primaryActionLabel}
241
+ variant={primaryActionColor}
242
+ >
243
+ {primaryActionLabel}
244
+ </Button>
245
+ )}
246
+ {onSecondaryAction && secondaryActionLabel && (
247
+ <Button
248
+ block
249
+ variant="secondary"
250
+ onClick={onSecondaryAction}
251
+ aria-label={secondaryActionLabel}
252
+ >
253
+ {secondaryActionLabel}
254
+ </Button>
255
+ )}
256
+ {showClose && (
257
+ <Button variant="text" onClick={onClose} aria-label={closeLabel}>
258
+ {closeLabel}
259
+ </Button>
260
+ )}
261
+ </div>
262
+ </div>
263
+ </div>
264
+ </DialogPanel>
265
+ </TransitionChild>
266
+ </Dialog>
267
+ </Transition>
268
+ );
269
+ };
@@ -0,0 +1,145 @@
1
+ .modal {
2
+ position: fixed;
3
+ inset: 0;
4
+ z-index: var(--z-index-modal);
5
+ display: flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ }
9
+
10
+ .overlay {
11
+ position: fixed;
12
+ inset: 0;
13
+ }
14
+
15
+ .normalOverlay {
16
+ background: rgb(0 0 0 / 50%);
17
+ }
18
+
19
+ .darkerOverlay {
20
+ background: rgb(0 0 0 / 80%);
21
+ }
22
+
23
+ .dialog {
24
+ position: relative;
25
+ box-sizing: border-box;
26
+ display: flex;
27
+ flex-direction: column;
28
+ width: calc(100% - 32px);
29
+ max-width: 600px;
30
+ max-height: calc(100% - 48px);
31
+ margin: 0 auto;
32
+ overflow: hidden;
33
+ background: #fff;
34
+ border-radius: var(--radius-lg);
35
+ }
36
+
37
+ .dialog.fixedHeight {
38
+ height: calc(100% - 48px);
39
+ }
40
+
41
+ .scrollContainer {
42
+ height: 100%;
43
+ overflow-y: auto;
44
+ }
45
+
46
+ .mainContent {
47
+ box-sizing: border-box;
48
+ display: flex;
49
+ flex-direction: column;
50
+ }
51
+
52
+ .mainContent.fixedHeight {
53
+ min-height: 100%;
54
+ }
55
+
56
+ .mainContent.headerLess {
57
+ padding-top: var(--size-spacing-xl);
58
+ }
59
+
60
+ .header {
61
+ padding: var(--size-spacing-lg) var(--size-spacing-md);
62
+ font-size: var(--text-heading-xs-size);
63
+ font-weight: bold;
64
+ line-height: var(--text-heading-xs-line);
65
+ text-align: center;
66
+ white-space: pre-wrap;
67
+ background-color: var(--color-ubie-white);
68
+
69
+ /* May receive focus in the initial display. */
70
+ outline: none;
71
+ }
72
+
73
+ .header.sticky {
74
+ position: sticky;
75
+ top: 0;
76
+
77
+ /* Ensure sticky header appears above content that might overlap it (e.g., with position or transform) */
78
+ z-index: 1;
79
+ }
80
+
81
+ .header.sticky.canScroll {
82
+ border-bottom: 1px solid var(--color-border);
83
+ }
84
+
85
+ .body {
86
+ /*
87
+ * Ensure the header always appears in front of body content.
88
+ * - Place header and body in the same stacking context
89
+ * - Set body's z-index lower than header's z-index
90
+ * This prevents the header from being hidden by body content,
91
+ * regardless of how high z-index values are specified within the body.
92
+ */
93
+ z-index: 0;
94
+ padding-right: var(--size-spacing-md);
95
+ padding-left: var(--size-spacing-md);
96
+ }
97
+
98
+ .body.fixedHeight {
99
+ flex-grow: 1;
100
+ min-height: 400px;
101
+ overflow: hidden;
102
+ }
103
+
104
+ .buttonContainer {
105
+ display: grid;
106
+ gap: var(--size-spacing-md);
107
+ padding: var(--size-spacing-lg) var(--size-spacing-md) var(--size-spacing-md);
108
+ background-color: var(--color-ubie-white);
109
+ }
110
+
111
+ .buttonContainer.sticky {
112
+ position: sticky;
113
+ bottom: 0;
114
+ }
115
+
116
+ .buttonContainer.sticky.canScroll {
117
+ border-top: 1px solid var(--color-border);
118
+ }
119
+
120
+ .panelEnter {
121
+ transition-timing-function: ease-out;
122
+ transition-duration: 250ms;
123
+ transition-property: opacity;
124
+ }
125
+
126
+ .panelEnterFrom {
127
+ opacity: 0;
128
+ }
129
+
130
+ .panelEnterTo {
131
+ opacity: 1;
132
+ }
133
+
134
+ .panelLeave {
135
+ transition-timing-function: ease-in;
136
+ transition-duration: 200ms;
137
+ }
138
+
139
+ .panelLeaveFrom {
140
+ opacity: 1;
141
+ }
142
+
143
+ .panelLeaveTo {
144
+ opacity: 0;
145
+ }
@@ -0,0 +1,57 @@
1
+ import { composeStory } from "@storybook/react-vite";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { userEvent } from "@testing-library/user-event";
4
+ import Meta, { WithId, CustomHeader, Default } from "./ActionModal.stories";
5
+
6
+ const WithIdStory = composeStory(WithId, Meta);
7
+ const CustomHeaderStory = composeStory(CustomHeader, Meta);
8
+ const DefaultStory = composeStory(Default, Meta);
9
+
10
+ const user = userEvent.setup();
11
+
12
+ describe("ActionModal", () => {
13
+ test("Add id", async () => {
14
+ render(<WithIdStory />);
15
+
16
+ await user.click(await screen.findByRole("button"));
17
+
18
+ const dialogElement = await screen.findByRole("dialog");
19
+
20
+ expect(dialogElement).toHaveAttribute("id", "dialog-id");
21
+ });
22
+
23
+ test("Custom heading and dialogue can be tied together", async () => {
24
+ render(<CustomHeaderStory />);
25
+
26
+ await user.click(await screen.findByRole("button"));
27
+
28
+ const dialogElement = await screen.findByRole("dialog");
29
+ const dialogHeadingElement = await screen.findByRole("heading");
30
+
31
+ expect(dialogElement).toHaveAttribute("aria-labelledby", "header-id");
32
+ expect(dialogHeadingElement).toHaveAttribute("id", "header-id");
33
+ });
34
+
35
+ test("If no header prop is present, text is inserted that serves as the default heading", async () => {
36
+ render(<CustomHeaderStory />);
37
+
38
+ await user.click(await screen.findByRole("button"));
39
+
40
+ const dialogHeadingElement = await screen.findByText("ダイアログ");
41
+
42
+ expect(document.activeElement).toEqual(dialogHeadingElement);
43
+ });
44
+
45
+ test("header prop can be used to automatically link to a dialog", async () => {
46
+ render(<DefaultStory />);
47
+
48
+ const dialogElement = await screen.findByRole("dialog");
49
+ const dialogHeadingElement = await screen.findByRole("heading");
50
+
51
+ expect(dialogElement).toHaveAttribute("aria-labelledby");
52
+ expect(dialogHeadingElement).toHaveAttribute(
53
+ "id",
54
+ dialogElement.getAttribute("aria-labelledby"),
55
+ );
56
+ });
57
+ });