@edu-tosel/design 1.0.325 → 1.0.326
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/layout/template/sign/AgreementsSet.d.ts +5 -0
- package/layout/template/sign/AgreementsSet.js +59 -0
- package/layout/template/sign/Button.js +7 -4
- package/layout/template/sign/Check.d.ts +9 -0
- package/layout/template/sign/Check.js +67 -1
- package/layout/template/sign/CustomCheck.d.ts +5 -0
- package/layout/template/sign/CustomCheck.js +5 -0
- package/layout/template/sign/Layout.js +6 -6
- package/package.json +2 -1
- package/version.txt +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { ConsentBox } from "./Check";
|
|
4
|
+
import { cn } from "../../../util";
|
|
5
|
+
export default function AgreementsSet({ onRequiredAgreementsChange, }) {
|
|
6
|
+
const [errorMessage, setErrorMessage] = useState("");
|
|
7
|
+
const [agreements, setAgreements] = useState({
|
|
8
|
+
terms: false,
|
|
9
|
+
privacy: false,
|
|
10
|
+
marketing: false,
|
|
11
|
+
});
|
|
12
|
+
const allAgreed = Object.values(agreements).every(Boolean);
|
|
13
|
+
const requiredAgreed = agreements.terms && agreements.privacy;
|
|
14
|
+
const agreeAll = () => {
|
|
15
|
+
setAgreements((prev) => ({
|
|
16
|
+
...prev,
|
|
17
|
+
terms: true,
|
|
18
|
+
privacy: true,
|
|
19
|
+
marketing: true,
|
|
20
|
+
}));
|
|
21
|
+
if (errorMessage) {
|
|
22
|
+
setErrorMessage("");
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const handleAgreementChange = (key) => {
|
|
26
|
+
setAgreements((prev) => ({
|
|
27
|
+
...prev,
|
|
28
|
+
[key]: !prev[key],
|
|
29
|
+
}));
|
|
30
|
+
// 동의 상태가 변경되면 에러 메시지 초기화
|
|
31
|
+
if (errorMessage) {
|
|
32
|
+
setErrorMessage("");
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
// 필수 약관 동의 상태가 변경될 때마다 부모 컴포넌트에 알림
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (onRequiredAgreementsChange) {
|
|
38
|
+
onRequiredAgreementsChange(requiredAgreed);
|
|
39
|
+
}
|
|
40
|
+
}, [requiredAgreed, onRequiredAgreementsChange]);
|
|
41
|
+
const buttonWrapper = {
|
|
42
|
+
displays: "flex flex-row justify-between items-start",
|
|
43
|
+
sizes: "w-full h-fit rounded-lg",
|
|
44
|
+
spacings: "p-5 gap-5",
|
|
45
|
+
textStyles: "text-sm font-regular",
|
|
46
|
+
boundaries: "border-1 border-green-dark/50",
|
|
47
|
+
backgrounds: "bg-green-light/50",
|
|
48
|
+
other: "font-pretendard-var",
|
|
49
|
+
};
|
|
50
|
+
const buttonStyles = {
|
|
51
|
+
displays: "flex justify-center items-center shrink-0",
|
|
52
|
+
spacings: "px-4 py-2 rounded-md",
|
|
53
|
+
animations: "transition-all duration-300",
|
|
54
|
+
textStyles: "text-xs text-white font-regular",
|
|
55
|
+
backgrounds: "bg-green-dark hover:shadow-green",
|
|
56
|
+
activeStyles: allAgreed ? "opacity-0 pointer-events-none" : "opacity-100",
|
|
57
|
+
};
|
|
58
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 h-full w-full", children: [!allAgreed && (_jsxs("div", { className: cn(buttonWrapper), children: [_jsxs("div", { className: "flex flex-col text-gray-500 ", children: [_jsx("div", { className: "text-green-dark font-bold", children: "\uBC84\uD2BC\uC744 \uB20C\uB7EC \uD55C\uBC88\uC5D0 \uB3D9\uC758\uD560 \uC218 \uC788\uC5B4\uC694" }), _jsx("div", { className: "text-xs text-green-dark font-medium", children: "\uAC1C\uC778\uC815\uBCF4 \uC218\uC9D1 \uBC0F \uC774\uC6A9, \uB300\uD654 \uAD00\uB9AC \uADDC\uC815, \uBD80\uC815\uD589\uC704\uC790 \uCC98\uB9AC\uADDC\uC815, \uD654\uBA74 \uB179\uD654\uC5D0 \uB300\uD55C \uC0AC\uC2E4\uC744 \uD655\uC778 \uD588\uC73C\uBA70, \uC774\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4." })] }), _jsx("button", { onClick: agreeAll, className: cn(buttonStyles), children: "\uD55C \uBC88\uC5D0 \uB3D9\uC758\uD558\uAE30" })] })), _jsx(ConsentBox, { title: "\uB300\uD68C \uAD00\uB9AC \uADDC\uC815 \uD655\uC778 \uBC0F \uB3D9\uC758", description: "\uB300\uD68C \uAD00\uB9AC \uADDC\uC815\uC744 \uC774\uD574\uD588\uC73C\uBA70, \uC774\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4.", isChecked: agreements.terms, onChange: () => handleAgreementChange("terms") }), _jsx(ConsentBox, { title: "\uBD80\uC815\uD589\uC704\uC790 \uCC98\uB9AC \uADDC\uC815 \uD655\uC778 \uBC0F \uB3D9\uC758", description: "\uBD80\uC815\uD589\uC704\uC790 \uCC98\uB9AC \uADDC\uC815\uC744 \uC774\uD574\uD588\uC73C\uBA70, \uC774\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4.", isChecked: agreements.privacy, onChange: () => handleAgreementChange("privacy") }), _jsx(ConsentBox, { title: "\uD654\uBA74 \uB179\uD654 \uB3D9\uC758", description: "\uBD80\uC815\uD589\uC704 \uBC29\uC9C0\uB97C \uC704\uD574 \uD654\uBA74\uC744 \uB179\uD654\uD558\uB294 \uAC83\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4.", isChecked: agreements.marketing, onChange: () => handleAgreementChange("marketing") })] }));
|
|
59
|
+
}
|
|
@@ -4,10 +4,13 @@ function Button({ title, onClick, disabled, size, icon, bg }) {
|
|
|
4
4
|
const container = {
|
|
5
5
|
sizes: size ?? "w-112.5 h-13.5",
|
|
6
6
|
displays: "flex items-center justify-center gap-4",
|
|
7
|
-
backgrounds: !disabled ? bg ?? "bg-green-dark" : "bg-gray-
|
|
8
|
-
cursors: !disabled
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
backgrounds: !disabled ? bg ?? "bg-green-dark" : "bg-gray-100",
|
|
8
|
+
cursors: !disabled
|
|
9
|
+
? "cursor-pointer hover:shadow-green "
|
|
10
|
+
: "cursor-not-allowed",
|
|
11
|
+
styles: "rounded-lgx font-medium text-lg",
|
|
12
|
+
textColors: !disabled ? "text-white" : "text-gray-400",
|
|
13
|
+
animations: "duration-300",
|
|
11
14
|
};
|
|
12
15
|
return (_jsxs("div", { onClick: () => {
|
|
13
16
|
if (disabled)
|
|
@@ -7,9 +7,18 @@ interface CheckProps {
|
|
|
7
7
|
declare function Check({ state, sizes, element }: CheckProps): import("react/jsx-runtime").JSX.Element;
|
|
8
8
|
declare namespace Check {
|
|
9
9
|
var Box: typeof CheckWithBox;
|
|
10
|
+
var ConsentBox: typeof import("./Check").ConsentBox;
|
|
10
11
|
}
|
|
11
12
|
declare function CheckWithBox({ state, element, }: {
|
|
12
13
|
state: State<boolean>;
|
|
13
14
|
element?: React.ReactNode;
|
|
14
15
|
}): import("react/jsx-runtime").JSX.Element;
|
|
15
16
|
export default Check;
|
|
17
|
+
interface ConsentBoxProps {
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
isChecked: boolean;
|
|
21
|
+
onChange: (isChecked: boolean) => void;
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare function ConsentBox({ title, description, isChecked, onChange, children, }: ConsentBoxProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from "../../../util";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import CustomCheck from "./CustomCheck";
|
|
5
|
+
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/solid";
|
|
3
6
|
function Check({ state, sizes, element }) {
|
|
4
7
|
const [value, setValue] = state;
|
|
5
8
|
const container = {
|
|
@@ -11,6 +14,7 @@ function Check({ state, sizes, element }) {
|
|
|
11
14
|
sizes: "w-6 h-6 ",
|
|
12
15
|
styles: "border-gray-light border-1 rounded-md",
|
|
13
16
|
backgrounds: value ? "bg-green-dark" : "bg-white",
|
|
17
|
+
animations: "hover:border-green-dark duration-300",
|
|
14
18
|
};
|
|
15
19
|
return (_jsxs("div", { className: cn(container), children: [_jsx("button", { onClick: () => setValue(!value), className: cn(checkbox), children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "11", viewBox: "0 0 12 11", fill: "none", children: _jsx("path", { d: "M1 6.14286L4.75 10L11 1", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("div", { children: element })] }));
|
|
16
20
|
}
|
|
@@ -19,8 +23,70 @@ function CheckWithBox({ state, element, }) {
|
|
|
19
23
|
displays: "flex items-center",
|
|
20
24
|
sizes: "w-112.5 h-15 pl-5",
|
|
21
25
|
styles: "box-shadow rounded-lgx",
|
|
26
|
+
cursor: "cursor-pointer",
|
|
22
27
|
};
|
|
23
|
-
return (_jsx("
|
|
28
|
+
return (_jsx("label", { className: cn(container), children: _jsx(Check, { state: state, sizes: "h-6", element: element }) }));
|
|
24
29
|
}
|
|
25
30
|
Check.Box = CheckWithBox;
|
|
31
|
+
Check.ConsentBox = ConsentBox;
|
|
26
32
|
export default Check;
|
|
33
|
+
export function ConsentBox({ title, description, isChecked, onChange, children, }) {
|
|
34
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (isChecked) {
|
|
37
|
+
setIsOpen(false);
|
|
38
|
+
}
|
|
39
|
+
}, [isChecked]);
|
|
40
|
+
const handleCheckboxChange = () => {
|
|
41
|
+
onChange(!isChecked);
|
|
42
|
+
if (!isChecked)
|
|
43
|
+
setIsOpen(false);
|
|
44
|
+
};
|
|
45
|
+
const styles = {
|
|
46
|
+
container: {
|
|
47
|
+
displays: "relative flex flex-col",
|
|
48
|
+
sizes: "h-fit w-full",
|
|
49
|
+
animations: "transition-all duration-300",
|
|
50
|
+
grouping: "group",
|
|
51
|
+
},
|
|
52
|
+
label: {
|
|
53
|
+
displays: "flex shrink-0 items-start cursor-pointer relative",
|
|
54
|
+
backgrounds: "group-hover:bg-green-light/50",
|
|
55
|
+
spacings: "p-4 gap-3",
|
|
56
|
+
sizes: "rounded-lg h-fit",
|
|
57
|
+
animations: "transition-all duration-300",
|
|
58
|
+
activeStyles: isChecked ? "bg-green-light/50" : "bg-gray-50",
|
|
59
|
+
},
|
|
60
|
+
input: {
|
|
61
|
+
reset: "appearance-none",
|
|
62
|
+
displays: "flex items-center justify-center relative",
|
|
63
|
+
sizes: "size-5 shrink-0",
|
|
64
|
+
boundaries: "border-1 border-gray-100 rounded-md ml-0",
|
|
65
|
+
backgrounds: "checked:bg-green-dark bg-white hover:border-green-dark",
|
|
66
|
+
animations: "transition-all duration-300",
|
|
67
|
+
},
|
|
68
|
+
titleText: {
|
|
69
|
+
displays: "font-medium text-gray-700",
|
|
70
|
+
},
|
|
71
|
+
descriptionText: {
|
|
72
|
+
displays: "text-sm text-gray-500",
|
|
73
|
+
},
|
|
74
|
+
openButton: {
|
|
75
|
+
displays: "absolute top-8 right-5 pointer-events-auto",
|
|
76
|
+
animations: "transition-all duration-300 group-hover:bg-blue-100",
|
|
77
|
+
sizes: "h-fit w-fit rounded-full",
|
|
78
|
+
spacings: "p-1",
|
|
79
|
+
activeStyles: isChecked ? "bg-green-light" : "bg-gray-100",
|
|
80
|
+
},
|
|
81
|
+
conditionsWrapper: {
|
|
82
|
+
displays: "flex flex-col gap-5 bg-white overflow-hidden px-5",
|
|
83
|
+
activeStyles: isOpen ? "opacity-100 py-5" : "max-h-0 opacity-0 py-0",
|
|
84
|
+
animations: "transition-all duration-300 ease-in-out",
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
// 동의 확인 섹션 컴포넌트
|
|
88
|
+
const ConsentConfirmation = ({ isChecked }) => (_jsx("div", { className: "flex flex-row justify-end items-center", children: _jsxs("label", { className: cn("w-fit h-fit py-2 px-4 flex flex-row gap-2 justify-center items-center rounded-md cursor-pointer hover:bg-green-light/50 hover:text-green-dark text-sm transition-all duration-300", isChecked ? "bg-green-light/50 text-green-dark" : "bg-gray-100 "), children: [_jsx("div", { children: "\uC704 \uB0B4\uC6A9\uC744 \uBAA8\uB450 \uD655\uC778 \uD558\uC600\uC73C\uBA70, \uC774\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4." }), _jsx("div", { className: "relative w-fit h-fit", children: _jsx(CustomCheck, { isChecked: isChecked, onChange: handleCheckboxChange, className: cn(styles.input) }) })] }) }));
|
|
89
|
+
// 토글 버튼 컴포넌트
|
|
90
|
+
const ToggleButton = () => (_jsx("div", { onClick: () => setIsOpen(!isOpen), className: cn(styles.openButton), children: isOpen ? (_jsx(ChevronUpIcon, { className: "size-4" })) : (_jsx(ChevronDownIcon, { className: "size-4" })) }));
|
|
91
|
+
return (_jsxs("div", { className: cn(styles.container), children: [_jsxs("label", { className: cn(styles.label), children: [_jsx(CustomCheck, { isChecked: isChecked, onChange: handleCheckboxChange, className: cn(styles.input) }), _jsxs("div", { className: "flex flex-col gap-2 w-full", children: [_jsx("div", { className: cn(styles.titleText), children: title }), _jsx("div", { className: cn(styles.descriptionText), children: description })] })] }), children && (_jsxs("div", { className: cn(styles.conditionsWrapper), children: [children, _jsx(ConsentConfirmation, { isChecked: isChecked })] })), children && _jsx(ToggleButton, {})] }));
|
|
92
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CheckIcon } from "@heroicons/react/24/solid";
|
|
3
|
+
export default function DefaultCheckBox({ isChecked, onChange, className, }) {
|
|
4
|
+
return (_jsxs("div", { className: "relative w-fit h-fit", children: [_jsx("input", { type: "checkbox", checked: isChecked, onChange: onChange, className: className }), isChecked && (_jsx("div", { className: "absolute top-1 left-1 size-5 pointer-events-none", children: _jsx(CheckIcon, { className: "size-3 text-white" }) })), _jsx(CheckIcon, { className: "size-3 text-white absolute top-1 left-1" })] }));
|
|
5
|
+
}
|
|
@@ -3,21 +3,21 @@ import { cn } from "../../../util";
|
|
|
3
3
|
export default function Layout({ children, steps, script, title, }) {
|
|
4
4
|
const container = {
|
|
5
5
|
positions: "relative",
|
|
6
|
-
sizes: "w-full min-h-screen h-screen
|
|
7
|
-
displays: "flex flex-col items-center
|
|
8
|
-
spacings: "px-3 xs:px-5 py-3 xs:py-5
|
|
9
|
-
other: "bg-
|
|
6
|
+
sizes: "w-full min-h-screen h-screen",
|
|
7
|
+
displays: "flex flex-col items-center",
|
|
8
|
+
spacings: "px-3 xs:px-5 py-3 xs:py-5",
|
|
9
|
+
other: "bg-white",
|
|
10
10
|
};
|
|
11
11
|
const headerBox = {
|
|
12
12
|
display: "flex flex-row justify-between items-center",
|
|
13
|
-
sizes: "h-15 shrink-0 w-full
|
|
13
|
+
sizes: "h-15 shrink-0 w-full sm:max-w-140",
|
|
14
14
|
spacings: "px-5 mb-5",
|
|
15
15
|
backgorunds: "bg-gradient-to-r from-green-dark to-crimson-burgundy rounded-lg",
|
|
16
16
|
};
|
|
17
17
|
const titleText = {
|
|
18
18
|
textStyles: "font-bold text-base text-white",
|
|
19
19
|
};
|
|
20
|
-
return (_jsxs("div", { className: cn(container), children: [_jsxs("div", { className: cn(headerBox), children: [_jsx("img", { src: "/images/logos/tosel-white-highdefinition.png", width: 93, height: 20, alt: "\uD1A0\uC140\uC758 \uBA54\uC778 \uB85C\uACE0" }), _jsx("div", { className: cn(titleText), children: title })] }), script && _jsx("div", { className: "font-medium text-sm", children: script }), steps && (_jsx("div", { className: "flex gap-5 my-5", children: steps?.map((step, index) => (_jsx(Light, { flag: step }, index))) })), children] }));
|
|
20
|
+
return (_jsxs("div", { className: cn(container), children: [_jsxs("div", { className: cn(headerBox), children: [_jsx("img", { src: "/images/logos/tosel-white-highdefinition.png", width: 93, height: 20, alt: "\uD1A0\uC140\uC758 \uBA54\uC778 \uB85C\uACE0" }), _jsx("div", { className: cn(titleText), children: title })] }), script && _jsx("div", { className: "font-medium text-sm", children: script }), steps && (_jsx("div", { className: "flex gap-5 my-5", children: steps?.map((step, index) => (_jsx(Light, { flag: step }, index))) })), _jsx("div", { className: "flex flex-col h-full w-full justify-start items-center max-w-140", children: children })] }));
|
|
21
21
|
}
|
|
22
22
|
function Light({ flag }) {
|
|
23
23
|
const container = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edu-tosel/design",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.326",
|
|
4
4
|
"description": "UI components for International TOSEL Committee",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jsx",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@edu-tosel/interface": "https://resource.tosel.co.kr/packages/interface/1.0.59",
|
|
18
18
|
"@edu-tosel/utils": "^0.0.30",
|
|
19
19
|
"@gsap/react": "^2.1.1",
|
|
20
|
+
"@heroicons/react": "^2.2.0",
|
|
20
21
|
"date-fns": "^2.30.0",
|
|
21
22
|
"date-fns-tz": "^2.0.1",
|
|
22
23
|
"dayjs": "^1.11.12",
|
package/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.0.
|
|
1
|
+
1.0.326
|