@uniai-fe/uds-templates 0.0.9 → 0.0.11

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 (44) hide show
  1. package/README.md +77 -1
  2. package/dist/styles.css +212 -267
  3. package/package.json +6 -4
  4. package/src/components/auth/index.tsx +11 -0
  5. package/src/components/auth/login/index.tsx +1 -1
  6. package/src/components/auth/login/markup/FormField.tsx +2 -2
  7. package/src/components/auth/login/types/props.ts +12 -12
  8. package/src/components/auth/login/types.ts +2 -2
  9. package/src/components/auth/signup/hooks/index.ts +3 -0
  10. package/src/components/auth/signup/hooks/useSignupAccountForm.ts +77 -0
  11. package/src/components/auth/signup/hooks/useSignupUserInfoForm.ts +81 -0
  12. package/src/components/auth/signup/hooks/useSignupVerificationForm.ts +77 -0
  13. package/src/components/auth/signup/index.ts +24 -0
  14. package/src/components/auth/signup/markup/AccountForm.tsx +124 -0
  15. package/src/components/auth/signup/markup/Complete.tsx +61 -0
  16. package/src/components/auth/signup/markup/UserInfoForm.tsx +97 -0
  17. package/src/components/auth/signup/markup/VerificationForm.tsx +155 -0
  18. package/src/components/auth/signup/markup/index.ts +4 -0
  19. package/src/components/auth/signup/styles/signup.scss +135 -0
  20. package/src/components/auth/signup/types/hooks.ts +85 -0
  21. package/src/components/auth/signup/types/index.ts +2 -0
  22. package/src/components/auth/signup/types/props.ts +105 -0
  23. package/src/components/auth/signup/utils/composeFieldProps.ts +50 -0
  24. package/src/components/modal/core/components/Container.tsx +41 -0
  25. package/src/components/modal/core/components/FooterButtons.tsx +132 -0
  26. package/src/components/modal/core/components/Provider.tsx +28 -0
  27. package/src/components/modal/core/components/Root.tsx +93 -0
  28. package/src/components/modal/core/hooks/useModal.ts +136 -0
  29. package/src/components/modal/core/jotai/atoms.ts +10 -0
  30. package/src/components/modal/index.scss +4 -0
  31. package/src/components/modal/index.tsx +16 -0
  32. package/src/components/modal/styles/animations.scss +24 -0
  33. package/src/components/modal/styles/base.scss +45 -0
  34. package/src/components/modal/styles/container.scss +138 -0
  35. package/src/components/modal/styles/dimmer.scss +23 -0
  36. package/src/components/modal/templates/Alert.tsx +104 -0
  37. package/src/components/modal/templates/Dialog.tsx +112 -0
  38. package/src/components/modal/types/footer.ts +36 -0
  39. package/src/components/modal/types/index.ts +21 -0
  40. package/src/components/modal/types/options.ts +6 -0
  41. package/src/components/modal/types/state.ts +31 -0
  42. package/src/components/modal/types/templates.ts +32 -0
  43. package/src/index.scss +1 -0
  44. package/src/index.tsx +1 -0
package/README.md CHANGED
@@ -29,7 +29,7 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
29
29
  - **templates**는 레이아웃/플로우/상태 표현까지 담당하고,
30
30
  - API 호출, 인증 토큰 관리, 라우팅, i18n 등 비즈니스 로직은 서비스 앱에서 구현합니다.
31
31
 
32
- ## 현재 제공 템플릿
32
+ ## 현재 제공 템플릿/모듈
33
33
 
34
34
  - `/auth/**`
35
35
  - 로그인 화면 템플릿 (Login)
@@ -39,6 +39,9 @@ Next.js 서비스에서 primitives와 동일한 방식으로 **Raw TypeScript**
39
39
  - `/page-frame/**`
40
40
  - `/page-frame/mobile`: 로그인 이후 화면을 위한 모바일 프레임(header/body/footer)
41
41
  - `/page-frame/pc`: 추후 확장 예정
42
+ - `/modal/**`
43
+ - ui-legacy 스택 기반 모달 Provider/Root/Container + 템플릿(`Modal.Alert`, `Modal.Dialog`)
44
+ - Storybook(`apps/design-storybook/src/stories/templates/modal`)에서 Alert/Confirm 케이스를 검증한다.
42
45
 
43
46
  각 템플릿의 상세한 범위와 의사결정은 `CONTEXT-*.md` 문서에서 관리합니다.
44
47
 
@@ -111,6 +114,79 @@ export default function LoginPage() {
111
114
  > 위 예시는 개념을 설명하기 위한 형태이며,
112
115
  > 실제 props 구조/이름은 `CONTEXT-AUTH.md`에서 확정·관리합니다.
113
116
 
117
+ ## Modal 모듈 사용법
118
+
119
+ ui-legacy에서 사용하던 모달 스택/옵션을 templates 레이어로 옮겨왔습니다. 핵심 흐름은 다음과 같습니다.
120
+
121
+ 1. **Provider 1회 장착** — 서비스 레이아웃에서 `<Modal.Provider />`를 렌더합니다.
122
+ 2. **훅 사용** — `const { newModal, closeModal } = Modal.useModal();`
123
+ 3. **템플릿 팩토리** — `Modal.Alert`, `Modal.Dialog`이 `ModalState` 객체를 반환하므로 `newModal(...)`에 그대로 전달합니다.
124
+
125
+ ```tsx
126
+ // app/layout.tsx
127
+ import "@uniai-fe/uds-templates/styles";
128
+ import { Modal } from "@uniai-fe/uds-templates/modal";
129
+
130
+ export default function RootLayout({
131
+ children,
132
+ }: {
133
+ children: React.ReactNode;
134
+ }) {
135
+ return (
136
+ <html lang="ko">
137
+ <body>
138
+ {children}
139
+ <Modal.Provider />
140
+ </body>
141
+ </html>
142
+ );
143
+ }
144
+ ```
145
+
146
+ ```tsx
147
+ // 예: Alert/Confirm 호출
148
+ import { Modal } from "@uniai-fe/uds-templates/modal";
149
+
150
+ export function ExampleActions() {
151
+ const { newModal } = Modal.useModal();
152
+
153
+ const openAlert = () =>
154
+ newModal(
155
+ Modal.Alert({
156
+ stackKey: "sample/alert",
157
+ message: "필수 항목 동의에 체크해 주세요.",
158
+ confirm: { label: "확인" },
159
+ }),
160
+ );
161
+
162
+ const openConfirm = () =>
163
+ newModal(
164
+ Modal.Dialog({
165
+ stackKey: "sample/confirm",
166
+ title: "저장하시겠어요?",
167
+ content: "입력한 내용이 저장되며 되돌릴 수 없습니다.",
168
+ confirm: {
169
+ label: "저장",
170
+ onClick: () => {
171
+ // 서비스 동작
172
+ },
173
+ },
174
+ cancel: { label: "취소" },
175
+ }),
176
+ );
177
+
178
+ return (
179
+ <>
180
+ <button onClick={openAlert}>Alert</button>
181
+ <button onClick={openConfirm}>Confirm</button>
182
+ </>
183
+ );
184
+ }
185
+ ```
186
+
187
+ - footer 버튼은 ui-legacy와 동일하게 `stackKey`, `role`, `defaultOptions/linkOptions` 구조로 관리하며, Alert(Text)/Dialog(Solid) 규격은 templates 내부에서 보장합니다.
188
+ - 세부 가드레일·확장 기록은 `CONTEXT-MODAL.md`를 참고하고, 새 템플릿을 추가할 때 해당 문서를 선행 업데이트합니다.
189
+
114
190
  ## Scripts
115
191
 
116
192
  패키지 루트에서 실행 가능한 대표 명령:
package/dist/styles.css CHANGED
@@ -721,14 +721,18 @@
721
721
  --font-body-medium-line-height: 1.5em;
722
722
  --font-body-medium-letter-spacing: 0px;
723
723
  --font-body-medium-weight: 500;
724
- --font-body-small-size: 15px;
724
+ --font-body-small-size: 16px;
725
725
  --font-body-small-line-height: 1.5em;
726
726
  --font-body-small-letter-spacing: 0px;
727
727
  --font-body-small-weight: 400;
728
- --font-body-xsmall-size: 13px;
728
+ --font-body-xsmall-size: 15px;
729
729
  --font-body-xsmall-line-height: 1.5em;
730
730
  --font-body-xsmall-letter-spacing: 0px;
731
731
  --font-body-xsmall-weight: 400;
732
+ --font-body-xxsmall-size: 13px;
733
+ --font-body-xxsmall-line-height: 1.5em;
734
+ --font-body-xxsmall-letter-spacing: 0px;
735
+ --font-body-xxsmall-weight: 400;
732
736
  }
733
737
  }
734
738
  @layer theme.tokens.typography {
@@ -1928,271 +1932,6 @@ figure.chip {
1928
1932
  height: 100%;
1929
1933
  }
1930
1934
 
1931
- :where(.radix-themes, .theme-root, :root) {
1932
- /* dialog essentials */
1933
- --dialog-overlay-bg: rgba(5, 6, 12, 0.55);
1934
- --dialog-panel-width: 360px;
1935
- --dialog-panel-max-width: calc(100vw - var(--spacing-padding-10) * 2);
1936
- --dialog-panel-bg: var(--color-bg-surface-static-white);
1937
- --dialog-panel-radius: var(--theme-radius-large-1);
1938
- --dialog-panel-shadow: 0px 18px 40px rgba(8, 11, 30, 0.18);
1939
- --dialog-border-color: var(--color-border-standard-cool-gray);
1940
- --dialog-title-color: var(--color-label-strong);
1941
- --dialog-title-font-size: var(--font-heading-xsmall-size);
1942
- --dialog-title-line-height: var(--font-heading-xsmall-line-height);
1943
- --dialog-title-weight: var(--font-heading-xsmall-weight);
1944
- --dialog-body-color: var(--color-label-standard);
1945
- --dialog-body-font-size: var(--font-body-small-size);
1946
- --dialog-body-line-height: var(--font-body-small-line-height);
1947
- --dialog-description-color: var(--color-label-standard);
1948
- --dialog-description-font-size: var(--font-body-small-size);
1949
- --dialog-description-line-height: var(--font-body-small-line-height);
1950
- /* alert(notice) defaults */
1951
- --notice-dialog-section-padding-x: var(--spacing-padding-8);
1952
- --notice-dialog-section-padding-y: var(--spacing-padding-10);
1953
- --notice-dialog-action-height: 52px;
1954
- /* confirm defaults */
1955
- --confirm-dialog-header-padding-x: var(--spacing-padding-6);
1956
- --confirm-dialog-header-padding-y: var(--spacing-padding-7);
1957
- --confirm-dialog-body-padding-x: var(--spacing-padding-6);
1958
- --confirm-dialog-body-padding-y: var(--spacing-padding-7);
1959
- --confirm-dialog-footer-padding-x: var(--spacing-padding-6);
1960
- --confirm-dialog-footer-padding-y: var(--spacing-padding-7);
1961
- --confirm-dialog-actions-gap: var(--spacing-gap-5);
1962
- }
1963
-
1964
- .dialog-overlay {
1965
- position: fixed;
1966
- inset: 0;
1967
- background-color: var(--dialog-overlay-bg);
1968
- opacity: 0;
1969
- transition: opacity 0.2s ease;
1970
- will-change: opacity;
1971
- }
1972
- .dialog-overlay[data-state=open] {
1973
- opacity: 1;
1974
- }
1975
- .dialog-overlay[data-state=closed] {
1976
- opacity: 0;
1977
- pointer-events: none;
1978
- }
1979
-
1980
- @media (prefers-reduced-motion: reduce) {
1981
- .dialog-overlay {
1982
- transition: none;
1983
- }
1984
- }
1985
- .dialog-content {
1986
- position: fixed;
1987
- top: 50%;
1988
- left: 50%;
1989
- transform: translate(-50%, -50%);
1990
- width: min(var(--dialog-panel-width), var(--dialog-panel-max-width));
1991
- max-width: var(--dialog-panel-max-width);
1992
- max-height: calc(100vh - var(--spacing-padding-10) * 2);
1993
- background-color: var(--dialog-panel-bg);
1994
- border-radius: var(--dialog-panel-radius);
1995
- box-shadow: var(--dialog-panel-shadow);
1996
- display: flex;
1997
- flex-direction: column;
1998
- overflow: hidden;
1999
- overflow-y: auto;
2000
- overscroll-behavior: contain;
2001
- outline: none;
2002
- border: none;
2003
- gap: 0;
2004
- opacity: 0;
2005
- transition: opacity 0.2s ease, transform 0.2s ease;
2006
- }
2007
- .dialog-content[data-state=open] {
2008
- opacity: 1;
2009
- transform: translate(-50%, -50%);
2010
- }
2011
- .dialog-content[data-state=closed] {
2012
- opacity: 0;
2013
- transform: translate(-50%, calc(-50% + 12px));
2014
- pointer-events: none;
2015
- }
2016
-
2017
- @media (prefers-reduced-motion: reduce) {
2018
- .dialog-content {
2019
- transition: none;
2020
- }
2021
- }
2022
- .dialog-section {
2023
- padding: 0;
2024
- }
2025
- .dialog-section[data-section=actions] {
2026
- flex-shrink: 0;
2027
- }
2028
-
2029
- .dialog-title {
2030
- margin: 0;
2031
- color: var(--dialog-title-color);
2032
- font-size: var(--dialog-title-font-size);
2033
- line-height: var(--dialog-title-line-height);
2034
- font-weight: var(--dialog-title-weight);
2035
- }
2036
-
2037
- .dialog-description {
2038
- margin: 0;
2039
- color: var(--dialog-description-color);
2040
- font-size: var(--dialog-description-font-size);
2041
- line-height: var(--dialog-description-line-height);
2042
- }
2043
-
2044
- .dialog-button {
2045
- display: flex;
2046
- align-items: center;
2047
- justify-content: center;
2048
- width: 100%;
2049
- border: none;
2050
- border-radius: 0;
2051
- margin: 0;
2052
- padding: 0;
2053
- font-size: var(--font-body-medium-size);
2054
- line-height: var(--font-body-medium-line-height);
2055
- font-weight: var(--font-body-medium-weight);
2056
- cursor: pointer;
2057
- background: transparent;
2058
- color: var(--color-label-strong);
2059
- transition: background-color 0.15s ease, color 0.15s ease;
2060
- }
2061
-
2062
- .dialog-button[data-native-element=true] {
2063
- appearance: none;
2064
- }
2065
-
2066
- .notice-dialog-header,
2067
- .notice-dialog-body {
2068
- padding: var(--notice-dialog-section-padding-y) var(--notice-dialog-section-padding-x);
2069
- }
2070
-
2071
- .notice-dialog-header {
2072
- display: flex;
2073
- flex-direction: column;
2074
- gap: var(--spacing-gap-3);
2075
- text-align: center;
2076
- }
2077
-
2078
- .notice-dialog-body {
2079
- text-align: center;
2080
- }
2081
-
2082
- .notice-dialog-body p {
2083
- margin: 0 0 var(--spacing-gap-2);
2084
- color: var(--dialog-body-color);
2085
- font-size: var(--dialog-body-font-size);
2086
- line-height: 1.5em;
2087
- font-weight: var(--font-body-small-weight);
2088
- word-break: keep-all;
2089
- }
2090
-
2091
- .notice-dialog-body p:last-child {
2092
- margin-bottom: 0;
2093
- }
2094
-
2095
- .notice-dialog-actions {
2096
- border-top: 1px solid var(--dialog-border-color);
2097
- display: flex;
2098
- align-items: stretch;
2099
- flex-direction: row;
2100
- padding: 0;
2101
- gap: 0;
2102
- justify-content: center;
2103
- overflow: hidden;
2104
- --button-min-height: var(--notice-dialog-action-height);
2105
- --button-padding-inline: 0;
2106
- --button-padding-block: 0;
2107
- --button-border-radius: 0;
2108
- }
2109
-
2110
- .notice-dialog-actions > * {
2111
- flex: 1;
2112
- }
2113
-
2114
- .notice-dialog-actions .button {
2115
- display: flex;
2116
- align-items: center;
2117
- justify-content: center;
2118
- width: 100%;
2119
- border: none;
2120
- border-radius: 0;
2121
- margin: 0;
2122
- padding: 0;
2123
- font-size: var(--font-body-medium-size);
2124
- line-height: var(--font-body-medium-line-height);
2125
- font-weight: var(--font-body-medium-weight);
2126
- cursor: pointer;
2127
- background: transparent;
2128
- color: var(--color-label-strong);
2129
- transition: background-color 0.15s ease, color 0.15s ease;
2130
- background-color: var(--color-common-100);
2131
- color: var(--color-primary-default);
2132
- }
2133
- .notice-dialog-actions .button:hover {
2134
- background-color: var(--color-bg-surface-static-cool-gray);
2135
- }
2136
-
2137
- .notice-dialog-actions .button:not(:first-child),
2138
- .notice-dialog-actions [data-native-element=true]:not(:first-child) {
2139
- border-left: 1px solid var(--dialog-border-color);
2140
- }
2141
-
2142
- .confirm-dialog-header {
2143
- padding: var(--confirm-dialog-header-padding-y) var(--confirm-dialog-header-padding-x);
2144
- }
2145
-
2146
- .confirm-dialog-body {
2147
- padding: var(--confirm-dialog-body-padding-y) var(--confirm-dialog-body-padding-x);
2148
- }
2149
-
2150
- .confirm-dialog-header {
2151
- display: flex;
2152
- flex-direction: column;
2153
- gap: var(--spacing-gap-2);
2154
- text-align: center;
2155
- }
2156
-
2157
- .confirm-dialog-body {
2158
- display: flex;
2159
- flex-direction: column;
2160
- align-items: center;
2161
- gap: var(--spacing-gap-2);
2162
- text-align: center;
2163
- }
2164
-
2165
- .confirm-dialog-body p {
2166
- margin: 0;
2167
- color: var(--dialog-body-color);
2168
- font-size: var(--dialog-body-font-size);
2169
- line-height: 1.5em;
2170
- font-weight: var(--font-body-small-weight);
2171
- word-break: keep-all;
2172
- }
2173
-
2174
- .confirm-dialog-description {
2175
- margin: 0;
2176
- color: var(--dialog-body-color);
2177
- font-size: var(--dialog-body-font-size);
2178
- line-height: 1.5em;
2179
- font-weight: var(--font-body-small-weight);
2180
- word-break: keep-all;
2181
- }
2182
-
2183
- .confirm-dialog-actions {
2184
- display: flex;
2185
- align-items: stretch;
2186
- flex-direction: row;
2187
- padding: var(--confirm-dialog-footer-padding-y) var(--confirm-dialog-footer-padding-x);
2188
- gap: var(--confirm-dialog-actions-gap);
2189
- justify-content: center;
2190
- }
2191
-
2192
- .confirm-dialog-actions > * {
2193
- flex: 1;
2194
- }
2195
-
2196
1935
  :where(.radix-themes, .theme-root, :root) {
2197
1936
  --drawer-overlay-bg: rgba(0, 0, 0, 0.44);
2198
1937
  --drawer-surface-bg: var(--color-bg-surface-static-white);
@@ -2734,6 +2473,18 @@ figure.chip {
2734
2473
  color: var(--theme-input-helper-color);
2735
2474
  }
2736
2475
 
2476
+ .email-verification {
2477
+ display: flex;
2478
+ flex-direction: column;
2479
+ gap: var(--spacing-gap-4);
2480
+ }
2481
+
2482
+ .email-verification__countdown {
2483
+ font-size: var(--font-caption-medium-size);
2484
+ line-height: var(--font-caption-medium-line-height);
2485
+ color: var(--theme-input-helper-color);
2486
+ }
2487
+
2737
2488
  /* TODO(label): 스타일을 SOT 토큰 값으로 정의한다. */
2738
2489
  :where(.radix-themes, .theme-root, :root) {
2739
2490
  --theme-navigation-height: 86px;
@@ -3630,3 +3381,197 @@ figure.chip {
3630
3381
  .page-frame-navigation {
3631
3382
  width: 100%;
3632
3383
  }
3384
+
3385
+ :where(.radix-themes, .theme-root, :root) {
3386
+ --uds-modal-overlay-bg: var(--dialog-overlay-bg, rgba(5, 6, 12, 0.55));
3387
+ --uds-modal-surface-bg: var(--color-bg-surface-static-white);
3388
+ --uds-modal-surface-radius: var(--theme-radius-large-1);
3389
+ --uds-modal-surface-shadow: 0px 18px 40px rgba(8, 11, 30, 0.18);
3390
+ --uds-modal-max-width: min(
3391
+ 360px,
3392
+ calc(100vw - var(--spacing-padding-10) * 2)
3393
+ );
3394
+ --uds-modal-max-height: calc(100vh - var(--spacing-padding-10) * 2);
3395
+ }
3396
+
3397
+ .uds-modal-root {
3398
+ position: fixed;
3399
+ inset: 0;
3400
+ z-index: calc(400 + var(--uds-modal-index, 0));
3401
+ display: flex;
3402
+ align-items: center;
3403
+ justify-content: center;
3404
+ padding: var(--spacing-padding-6);
3405
+ pointer-events: none;
3406
+ }
3407
+
3408
+ .uds-modal-surface {
3409
+ position: relative;
3410
+ width: 100%;
3411
+ max-width: var(--uds-modal-max-width);
3412
+ max-height: var(--uds-modal-max-height);
3413
+ background-color: var(--uds-modal-surface-bg);
3414
+ border-radius: var(--uds-modal-surface-radius);
3415
+ box-shadow: var(--uds-modal-surface-shadow);
3416
+ pointer-events: auto;
3417
+ display: flex;
3418
+ flex-direction: column;
3419
+ overflow: hidden;
3420
+ }
3421
+
3422
+ .uds-modal-dimmer {
3423
+ position: absolute;
3424
+ inset: 0;
3425
+ background-color: var(--uds-modal-overlay-bg);
3426
+ pointer-events: auto;
3427
+ }
3428
+
3429
+ .uds-modal-root[data-state=init], .uds-modal-root[data-state=open] {
3430
+ pointer-events: auto;
3431
+ }
3432
+ .uds-modal-root[data-state=closed] {
3433
+ pointer-events: none;
3434
+ }
3435
+
3436
+ .uds-modal-dimmer {
3437
+ opacity: 0;
3438
+ transition: opacity 0.2s ease;
3439
+ }
3440
+ .uds-modal-root[data-state=open] .uds-modal-dimmer {
3441
+ opacity: 1;
3442
+ }
3443
+ .uds-modal-root[data-state=closed] .uds-modal-dimmer {
3444
+ opacity: 0;
3445
+ }
3446
+
3447
+ .uds-modal-container {
3448
+ display: flex;
3449
+ flex-direction: column;
3450
+ width: 100%;
3451
+ }
3452
+
3453
+ .uds-modal-header,
3454
+ .uds-modal-body {
3455
+ padding: 0;
3456
+ margin: 0;
3457
+ }
3458
+
3459
+ .uds-modal-footer {
3460
+ padding: 0;
3461
+ border-top: none;
3462
+ }
3463
+
3464
+ .uds-modal-footer-buttons {
3465
+ display: flex;
3466
+ width: 100%;
3467
+ gap: var(--spacing-gap-4, 16px);
3468
+ padding: var(--spacing-padding-6, 16px);
3469
+ align-items: stretch;
3470
+ }
3471
+ .uds-modal-footer-buttons[data-count="1"] .uds-modal-footer-button {
3472
+ width: 100%;
3473
+ }
3474
+ .uds-modal-footer-buttons[data-count="2"] .uds-modal-footer-button {
3475
+ flex: 1 1 0;
3476
+ }
3477
+ .uds-modal-footer-buttons[data-appearance=text] {
3478
+ padding: 0;
3479
+ gap: 0;
3480
+ min-height: var(--notice-dialog-action-height, 56px);
3481
+ border-top: 1px solid var(--uds-modal-footer-border-color, var(--dialog-border-color, var(--color-border-standard-cool-gray, #e4e5e7)));
3482
+ }
3483
+ .uds-modal-footer-buttons[data-appearance=text] .uds-modal-footer-button {
3484
+ border-radius: 0;
3485
+ }
3486
+ .uds-modal-footer-buttons[data-appearance=text] .uds-modal-footer-button + .uds-modal-footer-button {
3487
+ border-left: 1px solid var(--uds-modal-footer-border-color, var(--dialog-border-color, var(--color-border-standard-cool-gray, #e4e5e7)));
3488
+ }
3489
+
3490
+ .uds-modal-footer-button-solid {
3491
+ min-height: 48px;
3492
+ }
3493
+
3494
+ .uds-modal-footer-button-text {
3495
+ min-height: 56px;
3496
+ justify-content: center;
3497
+ border-radius: 0;
3498
+ }
3499
+
3500
+ .uds-modal-alert-message {
3501
+ padding: var(--spacing-padding-10, 32px) var(--spacing-padding-8, 24px);
3502
+ text-align: center;
3503
+ color: var(--dialog-body-color);
3504
+ word-break: keep-all;
3505
+ }
3506
+ .uds-modal-alert-message > p,
3507
+ .uds-modal-alert-message > span,
3508
+ .uds-modal-alert-message > strong,
3509
+ .uds-modal-alert-message > em {
3510
+ margin: 0;
3511
+ font-size: var(--dialog-body-font-size);
3512
+ line-height: 1.5em;
3513
+ font-weight: var(--font-body-small-weight, 400);
3514
+ word-break: inherit;
3515
+ }
3516
+ .uds-modal-alert-message > * + * {
3517
+ margin-top: var(--spacing-gap-2, 8px);
3518
+ }
3519
+
3520
+ .uds-modal-dialog-header,
3521
+ .uds-modal-dialog-body {
3522
+ padding: 0;
3523
+ margin: 0;
3524
+ }
3525
+
3526
+ .uds-modal-dialog-header-content {
3527
+ padding: var(--spacing-padding-7, 20px) var(--spacing-padding-6, 16px);
3528
+ text-align: center;
3529
+ }
3530
+ .uds-modal-dialog-header-content > h3 {
3531
+ margin: 0;
3532
+ color: var(--dialog-title-color);
3533
+ font-size: var(--dialog-title-font-size);
3534
+ line-height: var(--dialog-title-line-height);
3535
+ font-weight: var(--dialog-title-weight);
3536
+ }
3537
+
3538
+ .uds-modal-dialog-body-content {
3539
+ padding: var(--spacing-padding-7, 20px) var(--spacing-padding-6, 16px);
3540
+ text-align: center;
3541
+ color: var(--dialog-body-color);
3542
+ word-break: keep-all;
3543
+ }
3544
+ .uds-modal-dialog-body-content > p,
3545
+ .uds-modal-dialog-body-content > span,
3546
+ .uds-modal-dialog-body-content > strong,
3547
+ .uds-modal-dialog-body-content > em {
3548
+ margin: 0;
3549
+ font-size: var(--dialog-body-font-size);
3550
+ line-height: 1.5em;
3551
+ font-weight: var(--font-body-small-weight, 400);
3552
+ word-break: inherit;
3553
+ }
3554
+ .uds-modal-dialog-body-content > * + * {
3555
+ margin-top: var(--spacing-gap-2, 8px);
3556
+ }
3557
+
3558
+ .uds-modal-surface {
3559
+ opacity: 0;
3560
+ transform: translate3d(0, 12px, 0);
3561
+ transition: opacity 0.2s ease, transform 0.2s ease;
3562
+ }
3563
+ .uds-modal-root[data-state=open] .uds-modal-surface {
3564
+ opacity: 1;
3565
+ transform: translate3d(0, 0, 0);
3566
+ }
3567
+ .uds-modal-root[data-state=closed] .uds-modal-surface {
3568
+ opacity: 0;
3569
+ transform: translate3d(0, 12px, 0);
3570
+ pointer-events: none;
3571
+ }
3572
+
3573
+ @media (prefers-reduced-motion: reduce) {
3574
+ .uds-modal-surface {
3575
+ transition: none;
3576
+ }
3577
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniai-fe/uds-templates",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "UNIAI Design System; UI Templates Package",
5
5
  "type": "module",
6
6
  "private": false,
@@ -53,7 +53,8 @@
53
53
  "react": ">= 19",
54
54
  "react-dom": ">= 19",
55
55
  "react-hook-form": ">= 7",
56
- "next": "^15"
56
+ "next": "^15",
57
+ "jotai": ">= 2"
57
58
  },
58
59
  "dependencies": {
59
60
  "clsx": "^2.1.1",
@@ -72,8 +73,9 @@
72
73
  "eslint": "^9.39.2",
73
74
  "next": "^15.5.9",
74
75
  "prettier": "^3.7.4",
75
- "react-hook-form": "^7.68.0",
76
- "sass": "^1.97.0",
76
+ "react-hook-form": "^7.69.0",
77
+ "jotai": "^2.16.0",
78
+ "sass": "^1.97.1",
77
79
  "typescript": "~5.9.3"
78
80
  }
79
81
  }
@@ -2,8 +2,19 @@ import "./login/index.scss";
2
2
 
3
3
  import { AuthContainer } from "./container";
4
4
  import { AuthLogin } from "./login";
5
+ import { AuthSignup } from "./signup";
5
6
 
6
7
  export const Auth = {
7
8
  Container: AuthContainer,
8
9
  Login: AuthLogin,
10
+ Signup: AuthSignup,
9
11
  };
12
+
13
+ export {
14
+ useSignupUserInfoForm,
15
+ useSignupVerificationForm,
16
+ useSignupAccountForm,
17
+ } from "./signup";
18
+
19
+ export type * from "./login";
20
+ export type * from "./signup";
@@ -1,6 +1,6 @@
1
1
  import "./index.scss";
2
2
 
3
- export type { AuthLoginProps as AuthLoginTemplateProps } from "./types";
3
+ export type * from "./types";
4
4
  export * from "./hooks";
5
5
 
6
6
  import AuthLoginContainer from "./markup/Container";
@@ -9,8 +9,8 @@ import {
9
9
  type InputState,
10
10
  } from "@uniai-fe/uds-primitives";
11
11
  import type {
12
- AuthLoginFieldConfig,
13
12
  AuthLoginFieldOptions,
13
+ AuthLoginFieldProps,
14
14
  AuthLoginFields,
15
15
  AuthLoginFormValues,
16
16
  } from "../types";
@@ -29,7 +29,7 @@ type HelperState = {
29
29
  };
30
30
 
31
31
  const composeFieldProps = <TProps extends InputProps>(
32
- config: AuthLoginFieldConfig<TProps>,
32
+ config: AuthLoginFieldProps<TProps>,
33
33
  helper?: HelperState,
34
34
  ): TProps => {
35
35
  const baseProps = {