@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
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ubie/vitals-ui-consumer",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"author": "Ubie Inc.",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.cts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"development": "./src/index.ts",
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"import": "./dist/index.mjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"clsx": "^2.1.1",
|
|
18
|
+
"@ubie/vitals-token-consumer": "0.0.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@chromatic-com/storybook": "^4.1.3",
|
|
22
|
+
"@headlessui/react": "^2.2.9",
|
|
23
|
+
"@storybook/addon-a11y": "^10.1.8",
|
|
24
|
+
"@storybook/addon-docs": "^10.1.8",
|
|
25
|
+
"@storybook/addon-onboarding": "^10.1.8",
|
|
26
|
+
"@storybook/addon-vitest": "^10.1.8",
|
|
27
|
+
"@storybook/react-vite": "^10.1.8",
|
|
28
|
+
"@testing-library/react": "^16.3.1",
|
|
29
|
+
"@testing-library/user-event": "^14.6.1",
|
|
30
|
+
"@tsdown/css": "^0.21.7",
|
|
31
|
+
"@types/bun": "^1.3.9",
|
|
32
|
+
"@types/react": "^19.2.7",
|
|
33
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
34
|
+
"debounce": "^3.0.0",
|
|
35
|
+
"playwright": "^1.57.0",
|
|
36
|
+
"react": "19.2.1",
|
|
37
|
+
"storybook": "^10.1.8",
|
|
38
|
+
"vite-plus": "latest",
|
|
39
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test@latest",
|
|
40
|
+
"@ubie/vitals-icon": "0.0.1"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "vp pack",
|
|
44
|
+
"dev": "storybook dev -p 6006",
|
|
45
|
+
"build-storybook": "storybook build"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
.container,
|
|
2
|
+
.container * {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.button {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: space-between;
|
|
10
|
+
width: auto;
|
|
11
|
+
hyphens: auto;
|
|
12
|
+
color: var(--color-on-surface);
|
|
13
|
+
overflow-wrap: anywhere;
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
background: none;
|
|
16
|
+
border: 1px solid var(--color-outline);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.button:hover {
|
|
20
|
+
background-color: var(--color-ubie-blue-100);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* for Safari */
|
|
24
|
+
.button::-webkit-details-marker {
|
|
25
|
+
display: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.medium .button {
|
|
29
|
+
width: 100%;
|
|
30
|
+
min-height: 2rem;
|
|
31
|
+
padding: var(--size-spacing-md);
|
|
32
|
+
font-weight: bold;
|
|
33
|
+
border-radius: var(--radius-md);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.small .button {
|
|
37
|
+
width: 100%;
|
|
38
|
+
min-height: 1.5rem;
|
|
39
|
+
padding: var(--size-spacing-xs);
|
|
40
|
+
font-size: var(--text-button-md-size);
|
|
41
|
+
border-right: none;
|
|
42
|
+
border-left: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
details[open] .button {
|
|
46
|
+
border-bottom: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
details[open].medium .button {
|
|
50
|
+
border-radius: var(--radius-md) var(--radius-md) 0 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.arrow {
|
|
54
|
+
flex: none;
|
|
55
|
+
width: 1.5rem;
|
|
56
|
+
height: 1.5rem;
|
|
57
|
+
margin-left: 1rem;
|
|
58
|
+
color: var(--color-ubie-blue-600);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
details[open] .arrow {
|
|
62
|
+
transform: rotate(180deg);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.medium .panel {
|
|
66
|
+
padding: var(--size-spacing-md);
|
|
67
|
+
border: 1px solid var(--color-outline);
|
|
68
|
+
border-top: none;
|
|
69
|
+
border-radius: 0 0 var(--radius-md) var(--radius-md);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.small .panel {
|
|
73
|
+
padding: var(--size-spacing-xs);
|
|
74
|
+
border-bottom: 1px solid var(--color-outline);
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { composeStory } from "@storybook/react-vite";
|
|
2
|
+
import { screen } from "@testing-library/react";
|
|
3
|
+
import Meta, { Id as IdStory } from "./Accordion.stories";
|
|
4
|
+
import { describe, expect, test } from "vite-plus/test";
|
|
5
|
+
|
|
6
|
+
const IdTest = composeStory(IdStory, Meta);
|
|
7
|
+
|
|
8
|
+
describe("Accorion", () => {
|
|
9
|
+
test("Add ids", async () => {
|
|
10
|
+
await IdTest.run();
|
|
11
|
+
|
|
12
|
+
const detailsElement = await screen.findByRole("group");
|
|
13
|
+
const summaryElement = detailsElement.querySelector("summary");
|
|
14
|
+
|
|
15
|
+
expect(detailsElement).toHaveAttribute("id", "wrapper-id");
|
|
16
|
+
expect(summaryElement).toHaveAttribute("id", "button-id");
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Accordion } from "./Accordion";
|
|
3
|
+
import type { ComponentProps } from "react";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
component: Accordion,
|
|
7
|
+
} satisfies Meta<typeof Accordion>;
|
|
8
|
+
|
|
9
|
+
type Story = StoryObj<typeof Accordion>;
|
|
10
|
+
|
|
11
|
+
const defaultArgs = {
|
|
12
|
+
header: "夏目漱石「私の個人主義」",
|
|
13
|
+
children:
|
|
14
|
+
"何は時分どうもどんな観念顔というののところを云ったいまし。とうてい今日に説明院は現にこういう反対たますくらいから思わて来るないにも撲殺なるたたて、始終にも願うただですん。",
|
|
15
|
+
description: "出版日:1978年8月8日",
|
|
16
|
+
} satisfies Partial<ComponentProps<typeof Accordion>>;
|
|
17
|
+
|
|
18
|
+
export const Default: Story = {
|
|
19
|
+
render: (args) => <Accordion {...args}></Accordion>,
|
|
20
|
+
args: defaultArgs,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Small: Story = {
|
|
24
|
+
render: (args) => <Accordion {...args}></Accordion>,
|
|
25
|
+
args: {
|
|
26
|
+
...defaultArgs,
|
|
27
|
+
size: "small",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const CustomDataAttribute: Story = {
|
|
32
|
+
render: (args) => <Accordion {...args}></Accordion>,
|
|
33
|
+
args: {
|
|
34
|
+
...defaultArgs,
|
|
35
|
+
["data-test-id"]: "some-id",
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Id: Story = {
|
|
40
|
+
render: () => (
|
|
41
|
+
<Accordion header="夏目漱石「私の個人主義」" id="wrapper-id" buttonId="button-id">
|
|
42
|
+
何は時分どうもどんな観念顔というののところを云ったいまし。とうてい今日に説明院は現にこういう反対たますくらいから思わて来るないにも撲殺なるたたて、始終にも願うただですん。
|
|
43
|
+
</Accordion>
|
|
44
|
+
),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const InitialOpen: Story = {
|
|
48
|
+
render: (args) => <Accordion {...args} />,
|
|
49
|
+
args: {
|
|
50
|
+
...defaultArgs,
|
|
51
|
+
initialOpen: true,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const WithOnToggle: Story = {
|
|
56
|
+
render: (args) => <Accordion {...args} />,
|
|
57
|
+
args: {
|
|
58
|
+
...defaultArgs,
|
|
59
|
+
onToggle: () => alert("アコーディオンが開閉されました!"),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ArrowBDownIcon } from "@ubie/vitals-icon";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import styles from "./Accordion.module.css";
|
|
6
|
+
import { CustomDataAttributeProps } from "../../types/attributes";
|
|
7
|
+
import { Stack } from "../Stack/Stack";
|
|
8
|
+
import { Text } from "../Text/Text";
|
|
9
|
+
import type { FC, ReactNode } from "react";
|
|
10
|
+
|
|
11
|
+
export type Size = "small" | "medium";
|
|
12
|
+
|
|
13
|
+
type Props = {
|
|
14
|
+
/**
|
|
15
|
+
* コンテンツとして表示する内容。開閉で表示・非表示が切り替わる
|
|
16
|
+
*/
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* 見出しに表示するテキスト
|
|
20
|
+
*/
|
|
21
|
+
header: string;
|
|
22
|
+
/**
|
|
23
|
+
* 見出しの下に表示する説明
|
|
24
|
+
*/
|
|
25
|
+
description?: string;
|
|
26
|
+
/**
|
|
27
|
+
* サイズ
|
|
28
|
+
* @default medium
|
|
29
|
+
*/
|
|
30
|
+
size?: Size;
|
|
31
|
+
/**
|
|
32
|
+
* ラッパーであるdetails要素に付与するネイティブ要素の`id`属性。ページで固有のIDを指定
|
|
33
|
+
*/
|
|
34
|
+
id?: string;
|
|
35
|
+
/**
|
|
36
|
+
* 開閉をトリガーするsummary要素に付与するネイティブ要素の`id`属性。ページで固有のIDを指定
|
|
37
|
+
*/
|
|
38
|
+
buttonId?: string;
|
|
39
|
+
/**
|
|
40
|
+
* 初期状態で開く
|
|
41
|
+
*/
|
|
42
|
+
initialOpen?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* 開閉時のイベントハンドラ
|
|
45
|
+
*/
|
|
46
|
+
onToggle?: () => void;
|
|
47
|
+
} & CustomDataAttributeProps;
|
|
48
|
+
|
|
49
|
+
export const Accordion: FC<Props> = ({
|
|
50
|
+
header,
|
|
51
|
+
description,
|
|
52
|
+
children,
|
|
53
|
+
size = "medium",
|
|
54
|
+
id,
|
|
55
|
+
buttonId,
|
|
56
|
+
initialOpen,
|
|
57
|
+
onToggle,
|
|
58
|
+
...props
|
|
59
|
+
}) => {
|
|
60
|
+
return (
|
|
61
|
+
<details
|
|
62
|
+
className={clsx(styles.container, styles[size])}
|
|
63
|
+
id={id}
|
|
64
|
+
{...props}
|
|
65
|
+
open={initialOpen}
|
|
66
|
+
onToggle={onToggle}
|
|
67
|
+
>
|
|
68
|
+
<summary id={buttonId} className={styles.button}>
|
|
69
|
+
<Stack spacing="xxs" as="span">
|
|
70
|
+
<Text
|
|
71
|
+
bold={size === "medium"}
|
|
72
|
+
leading="narrow"
|
|
73
|
+
as="span"
|
|
74
|
+
size={size === "medium" ? "md" : "sm"}
|
|
75
|
+
>
|
|
76
|
+
{header}
|
|
77
|
+
</Text>
|
|
78
|
+
{description && (
|
|
79
|
+
<Text color="sub" size="xs" as="span">
|
|
80
|
+
{description}
|
|
81
|
+
</Text>
|
|
82
|
+
)}
|
|
83
|
+
</Stack>
|
|
84
|
+
<ArrowBDownIcon aria-hidden className={styles.arrow} />
|
|
85
|
+
</summary>
|
|
86
|
+
<div className={styles.panel}>{children}</div>
|
|
87
|
+
</details>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
.modal {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
z-index: var(--z-index-modal);
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.overlay {
|
|
9
|
+
position: fixed;
|
|
10
|
+
inset: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.normalOverlay {
|
|
14
|
+
background: rgb(0 0 0 / 50%);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.darkerOverlay {
|
|
18
|
+
background: rgb(0 0 0 / 80%);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.contents {
|
|
22
|
+
padding: 0 var(--size-spacing-md);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.dialog {
|
|
26
|
+
position: fixed;
|
|
27
|
+
bottom: 0;
|
|
28
|
+
left: 50%;
|
|
29
|
+
display: flex;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
width: 100%;
|
|
32
|
+
max-width: 600px;
|
|
33
|
+
margin: 0 auto;
|
|
34
|
+
overflow-y: hidden;
|
|
35
|
+
background: #fff;
|
|
36
|
+
border-radius: 12px;
|
|
37
|
+
border-end-start-radius: 0;
|
|
38
|
+
border-end-end-radius: 0;
|
|
39
|
+
transform: translate3d(-50%, 0, 0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.dialog.fullscreen {
|
|
43
|
+
height: calc(100% - 24px);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.scrollContainer {
|
|
47
|
+
height: 100%;
|
|
48
|
+
overflow-y: auto;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.mainContent {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.mainContent.headerLess {
|
|
57
|
+
padding-top: var(--size-spacing-xl);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.mainContent.fullscreen {
|
|
61
|
+
min-height: 100%;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.header {
|
|
65
|
+
padding: var(--size-spacing-lg) var(--size-spacing-md);
|
|
66
|
+
font-size: var(--text-heading-xs-size);
|
|
67
|
+
font-weight: bold;
|
|
68
|
+
line-height: var(--text-heading-xs-line);
|
|
69
|
+
text-align: center;
|
|
70
|
+
white-space: pre-wrap;
|
|
71
|
+
background-color: var(--color-ubie-white);
|
|
72
|
+
|
|
73
|
+
/* May receive focus in the initial display. */
|
|
74
|
+
outline: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.header.sticky {
|
|
78
|
+
position: sticky;
|
|
79
|
+
top: 0;
|
|
80
|
+
|
|
81
|
+
/* Ensure sticky header appears above content that might overlap it (e.g., with position or transform) */
|
|
82
|
+
z-index: 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.header.sticky.canScroll {
|
|
86
|
+
border-bottom: 1px solid var(--color-border);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.body {
|
|
90
|
+
/*
|
|
91
|
+
* Ensure the header always appears in front of body content.
|
|
92
|
+
* - Place header and body in the same stacking context
|
|
93
|
+
* - Set body's z-index lower than header's z-index
|
|
94
|
+
* This prevents the header from being hidden by body content,
|
|
95
|
+
* regardless of how high z-index values are specified within the body.
|
|
96
|
+
*/
|
|
97
|
+
z-index: 0;
|
|
98
|
+
padding-right: var(--size-spacing-md);
|
|
99
|
+
padding-left: var(--size-spacing-md);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.body.fullscreen {
|
|
103
|
+
flex: 1;
|
|
104
|
+
min-height: 400px;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.buttonContainer {
|
|
109
|
+
display: grid;
|
|
110
|
+
gap: var(--size-spacing-md);
|
|
111
|
+
padding: var(--size-spacing-lg) var(--size-spacing-md) var(--size-spacing-md);
|
|
112
|
+
background-color: var(--color-ubie-white);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.buttonContainer.sticky {
|
|
116
|
+
position: sticky;
|
|
117
|
+
bottom: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.buttonContainer.sticky.canScroll {
|
|
121
|
+
border-top: 1px solid var(--color-border);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.overlayEnter {
|
|
125
|
+
transition-timing-function: ease-out;
|
|
126
|
+
transition-duration: 300ms;
|
|
127
|
+
transition-property: opacity;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.overlayEnterFrom {
|
|
131
|
+
opacity: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.overlayEnterTo {
|
|
135
|
+
opacity: 1;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.overlayLeave {
|
|
139
|
+
transition-timing-function: ease-in;
|
|
140
|
+
transition-duration: 200ms;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.overlayLeaveFrom {
|
|
144
|
+
opacity: 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.overlayLeaveTo {
|
|
148
|
+
opacity: 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.panelEnter {
|
|
152
|
+
transition-timing-function: ease-out;
|
|
153
|
+
transition-duration: 300ms;
|
|
154
|
+
transition-property: transform, opacity;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.panelEnterFrom {
|
|
158
|
+
opacity: 0;
|
|
159
|
+
transform: translate3d(-50%, 100%, 0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.panelEnterTo {
|
|
163
|
+
opacity: 1;
|
|
164
|
+
transform: translate3d(-50%, 0, 0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.panelLeave {
|
|
168
|
+
transition-timing-function: ease-in;
|
|
169
|
+
transition-duration: 200ms;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.panelLeaveFrom {
|
|
173
|
+
opacity: 1;
|
|
174
|
+
transform: translate3d(-50%, 0, 0);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.panelLeaveTo {
|
|
178
|
+
opacity: 0;
|
|
179
|
+
transform: translate3d(-50%, 100%, 0);
|
|
180
|
+
}
|
|
@@ -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 "./ActionHalfModal.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("ActionHalfModal", () => {
|
|
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
|
+
});
|