@uniai-fe/uds-primitives 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 (217) hide show
  1. package/README.md +63 -0
  2. package/package.json +85 -0
  3. package/src/components/alternate/hooks/index.ts +4 -0
  4. package/src/components/alternate/img/.gitkeep +0 -0
  5. package/src/components/alternate/index.scss +1 -0
  6. package/src/components/alternate/index.tsx +4 -0
  7. package/src/components/alternate/markup/index.tsx +4 -0
  8. package/src/components/alternate/styles/index.scss +3 -0
  9. package/src/components/alternate/types/index.ts +4 -0
  10. package/src/components/alternate/utils/index.ts +4 -0
  11. package/src/components/badge/hooks/index.ts +4 -0
  12. package/src/components/badge/img/.gitkeep +0 -0
  13. package/src/components/badge/index.scss +1 -0
  14. package/src/components/badge/index.tsx +6 -0
  15. package/src/components/badge/markup/Badge.tsx +51 -0
  16. package/src/components/badge/markup/index.tsx +1 -0
  17. package/src/components/badge/styles/index.scss +189 -0
  18. package/src/components/badge/types/index.ts +55 -0
  19. package/src/components/badge/utils/index.ts +21 -0
  20. package/src/components/button/hooks/index.ts +4 -0
  21. package/src/components/button/img/.gitkeep +0 -0
  22. package/src/components/button/index.scss +1 -0
  23. package/src/components/button/index.tsx +6 -0
  24. package/src/components/button/markup/Button.tsx +175 -0
  25. package/src/components/button/markup/index.tsx +1 -0
  26. package/src/components/button/styles/index.scss +847 -0
  27. package/src/components/button/types/index.ts +79 -0
  28. package/src/components/button/utils/index.ts +58 -0
  29. package/src/components/calendar/hooks/index.ts +4 -0
  30. package/src/components/calendar/img/.gitkeep +0 -0
  31. package/src/components/calendar/index.scss +1 -0
  32. package/src/components/calendar/index.tsx +4 -0
  33. package/src/components/calendar/markup/index.tsx +4 -0
  34. package/src/components/calendar/styles/index.scss +3 -0
  35. package/src/components/calendar/types/index.ts +4 -0
  36. package/src/components/calendar/utils/index.ts +4 -0
  37. package/src/components/checkbox/hooks/index.ts +4 -0
  38. package/src/components/checkbox/img/.gitkeep +0 -0
  39. package/src/components/checkbox/img/check-large.svg +3 -0
  40. package/src/components/checkbox/img/check-medium.svg +3 -0
  41. package/src/components/checkbox/img/check.svg +3 -0
  42. package/src/components/checkbox/index.scss +1 -0
  43. package/src/components/checkbox/index.tsx +4 -0
  44. package/src/components/checkbox/markup/Checkbox.tsx +127 -0
  45. package/src/components/checkbox/markup/index.ts +1 -0
  46. package/src/components/checkbox/styles/index.scss +164 -0
  47. package/src/components/checkbox/types/checkbox.ts +21 -0
  48. package/src/components/checkbox/types/index.ts +1 -0
  49. package/src/components/chip/hooks/index.ts +4 -0
  50. package/src/components/chip/img/.gitkeep +0 -0
  51. package/src/components/chip/img/remove.svg +3 -0
  52. package/src/components/chip/index.scss +1 -0
  53. package/src/components/chip/index.tsx +6 -0
  54. package/src/components/chip/markup/Chip.tsx +103 -0
  55. package/src/components/chip/markup/index.tsx +1 -0
  56. package/src/components/chip/styles/index.scss +140 -0
  57. package/src/components/chip/types/index.ts +52 -0
  58. package/src/components/chip/utils/index.ts +36 -0
  59. package/src/components/dialog/hooks/index.ts +4 -0
  60. package/src/components/dialog/img/.gitkeep +0 -0
  61. package/src/components/dialog/index.scss +1 -0
  62. package/src/components/dialog/index.tsx +3 -0
  63. package/src/components/dialog/markup/confirm-dialog.tsx +316 -0
  64. package/src/components/dialog/markup/index.tsx +4 -0
  65. package/src/components/dialog/markup/notice-dialog.tsx +191 -0
  66. package/src/components/dialog/styles/base.scss +153 -0
  67. package/src/components/dialog/styles/confirm.scss +58 -0
  68. package/src/components/dialog/styles/index.scss +3 -0
  69. package/src/components/dialog/styles/notice.scss +65 -0
  70. package/src/components/dialog/types/index.ts +70 -0
  71. package/src/components/dialog/utils/index.ts +4 -0
  72. package/src/components/drawer/hooks/index.ts +113 -0
  73. package/src/components/drawer/img/.gitkeep +0 -0
  74. package/src/components/drawer/img/close.svg +3 -0
  75. package/src/components/drawer/index.scss +1 -0
  76. package/src/components/drawer/index.tsx +3 -0
  77. package/src/components/drawer/markup/drawer.tsx +421 -0
  78. package/src/components/drawer/markup/index.tsx +3 -0
  79. package/src/components/drawer/styles/index.scss +232 -0
  80. package/src/components/drawer/types/index.ts +51 -0
  81. package/src/components/drawer/utils/context.ts +15 -0
  82. package/src/components/drawer/utils/index.tsx +77 -0
  83. package/src/components/dropdown/hooks/index.ts +4 -0
  84. package/src/components/dropdown/img/.gitkeep +0 -0
  85. package/src/components/dropdown/index.scss +1 -0
  86. package/src/components/dropdown/index.tsx +4 -0
  87. package/src/components/dropdown/markup/index.tsx +4 -0
  88. package/src/components/dropdown/styles/index.scss +3 -0
  89. package/src/components/dropdown/types/index.ts +4 -0
  90. package/src/components/dropdown/utils/index.ts +4 -0
  91. package/src/components/input/hooks/index.ts +4 -0
  92. package/src/components/input/img/.gitkeep +0 -0
  93. package/src/components/input/img/check-correct.svg +3 -0
  94. package/src/components/input/img/check-default.svg +3 -0
  95. package/src/components/input/img/check-incorrect.svg +3 -0
  96. package/src/components/input/img/error.svg +5 -0
  97. package/src/components/input/img/hide-off.svg +4 -0
  98. package/src/components/input/img/hide-on.svg +6 -0
  99. package/src/components/input/img/reset.svg +3 -0
  100. package/src/components/input/img/search.svg +4 -0
  101. package/src/components/input/img/success.svg +3 -0
  102. package/src/components/input/index.scss +1 -0
  103. package/src/components/input/index.tsx +6 -0
  104. package/src/components/input/markup/index.tsx +1 -0
  105. package/src/components/input/markup/text/Base.tsx +311 -0
  106. package/src/components/input/markup/text/Identification.tsx +145 -0
  107. package/src/components/input/markup/text/Password.tsx +71 -0
  108. package/src/components/input/markup/text/Phone.tsx +115 -0
  109. package/src/components/input/markup/text/Search.tsx +35 -0
  110. package/src/components/input/markup/text/index.ts +10 -0
  111. package/src/components/input/styles/index.scss +375 -0
  112. package/src/components/input/types/index.ts +56 -0
  113. package/src/components/input/utils/index.ts +54 -0
  114. package/src/components/label/hooks/index.ts +4 -0
  115. package/src/components/label/img/.gitkeep +0 -0
  116. package/src/components/label/index.scss +1 -0
  117. package/src/components/label/index.tsx +4 -0
  118. package/src/components/label/markup/index.tsx +4 -0
  119. package/src/components/label/styles/index.scss +3 -0
  120. package/src/components/label/types/index.ts +4 -0
  121. package/src/components/label/utils/index.ts +4 -0
  122. package/src/components/navigation/hooks/index.ts +4 -0
  123. package/src/components/navigation/img/.gitkeep +0 -0
  124. package/src/components/navigation/index.scss +1 -0
  125. package/src/components/navigation/index.tsx +8 -0
  126. package/src/components/navigation/markup/index.tsx +2 -0
  127. package/src/components/navigation/markup/mobile/BottomNavigation.tsx +127 -0
  128. package/src/components/navigation/markup/mobile/index.ts +1 -0
  129. package/src/components/navigation/markup/web/index.ts +4 -0
  130. package/src/components/navigation/styles/index.scss +133 -0
  131. package/src/components/navigation/types/index.ts +38 -0
  132. package/src/components/navigation/utils/index.ts +23 -0
  133. package/src/components/pagination/hooks/index.ts +4 -0
  134. package/src/components/pagination/img/.gitkeep +0 -0
  135. package/src/components/pagination/index.scss +1 -0
  136. package/src/components/pagination/index.tsx +6 -0
  137. package/src/components/pagination/markup/Carousel.tsx +76 -0
  138. package/src/components/pagination/markup/Count.tsx +54 -0
  139. package/src/components/pagination/markup/Pagination.tsx +83 -0
  140. package/src/components/pagination/markup/index.tsx +3 -0
  141. package/src/components/pagination/styles/index.scss +155 -0
  142. package/src/components/pagination/types/index.ts +68 -0
  143. package/src/components/pagination/utils/index.ts +58 -0
  144. package/src/components/radio/hooks/index.ts +4 -0
  145. package/src/components/radio/img/.gitkeep +0 -0
  146. package/src/components/radio/index.scss +1 -0
  147. package/src/components/radio/index.tsx +7 -0
  148. package/src/components/radio/markup/Radio.tsx +121 -0
  149. package/src/components/radio/markup/RadioCard.tsx +68 -0
  150. package/src/components/radio/markup/RadioCardGroup.tsx +75 -0
  151. package/src/components/radio/markup/index.tsx +3 -0
  152. package/src/components/radio/styles/index.scss +252 -0
  153. package/src/components/radio/types/index.ts +1 -0
  154. package/src/components/radio/types/radio.ts +63 -0
  155. package/src/components/radio/utils/index.ts +4 -0
  156. package/src/components/scrollbar/hooks/index.ts +4 -0
  157. package/src/components/scrollbar/img/.gitkeep +0 -0
  158. package/src/components/scrollbar/index.scss +1 -0
  159. package/src/components/scrollbar/index.tsx +4 -0
  160. package/src/components/scrollbar/markup/index.tsx +4 -0
  161. package/src/components/scrollbar/styles/index.scss +3 -0
  162. package/src/components/scrollbar/types/index.ts +4 -0
  163. package/src/components/scrollbar/utils/index.ts +4 -0
  164. package/src/components/segmented-control/index.scss +1 -0
  165. package/src/components/segmented-control/index.tsx +7 -0
  166. package/src/components/segmented-control/markup/SegmentedControl.tsx +117 -0
  167. package/src/components/segmented-control/markup/index.ts +1 -0
  168. package/src/components/segmented-control/styles/index.scss +113 -0
  169. package/src/components/segmented-control/types/index.ts +22 -0
  170. package/src/components/select/hooks/index.ts +4 -0
  171. package/src/components/select/img/.gitkeep +0 -0
  172. package/src/components/select/index.scss +1 -0
  173. package/src/components/select/index.tsx +4 -0
  174. package/src/components/select/markup/index.tsx +4 -0
  175. package/src/components/select/styles/index.scss +3 -0
  176. package/src/components/select/types/index.ts +4 -0
  177. package/src/components/select/utils/index.ts +4 -0
  178. package/src/components/spinner/hooks/index.ts +4 -0
  179. package/src/components/spinner/img/.gitkeep +0 -0
  180. package/src/components/spinner/index.scss +1 -0
  181. package/src/components/spinner/index.tsx +4 -0
  182. package/src/components/spinner/markup/index.tsx +4 -0
  183. package/src/components/spinner/styles/index.scss +3 -0
  184. package/src/components/spinner/types/index.ts +4 -0
  185. package/src/components/spinner/utils/index.ts +4 -0
  186. package/src/components/tab/hooks/index.ts +4 -0
  187. package/src/components/tab/img/.gitkeep +0 -0
  188. package/src/components/tab/index.scss +1 -0
  189. package/src/components/tab/index.tsx +6 -0
  190. package/src/components/tab/markup/TabContent.tsx +29 -0
  191. package/src/components/tab/markup/TabList.tsx +60 -0
  192. package/src/components/tab/markup/TabRoot.tsx +74 -0
  193. package/src/components/tab/markup/TabTrigger.tsx +47 -0
  194. package/src/components/tab/markup/index.tsx +4 -0
  195. package/src/components/tab/styles/index.scss +182 -0
  196. package/src/components/tab/types/index.ts +46 -0
  197. package/src/components/tab/utils/index.ts +5 -0
  198. package/src/components/tab/utils/tab-context.ts +20 -0
  199. package/src/components/table/hooks/index.ts +4 -0
  200. package/src/components/table/img/.gitkeep +0 -0
  201. package/src/components/table/index.scss +1 -0
  202. package/src/components/table/index.tsx +4 -0
  203. package/src/components/table/markup/index.tsx +4 -0
  204. package/src/components/table/styles/index.scss +3 -0
  205. package/src/components/table/types/index.ts +4 -0
  206. package/src/components/table/utils/index.ts +4 -0
  207. package/src/hooks/index.ts +4 -0
  208. package/src/img/.gitkeep +0 -0
  209. package/src/index.scss +3 -0
  210. package/src/index.tsx +26 -0
  211. package/src/init/dayjs.ts +14 -0
  212. package/src/theme/ThemeProvider.tsx +25 -0
  213. package/src/theme/config.ts +29 -0
  214. package/src/theme/index.ts +3 -0
  215. package/src/theme/overrides.scss +215 -0
  216. package/src/types/index.ts +4 -0
  217. package/src/utils/index.ts +4 -0
@@ -0,0 +1,140 @@
1
+ @use "@uniai-fe/uds-foundation/css";
2
+
3
+ /* Chip 기본 토큰 래핑 */
4
+ :where(.radix-themes, .theme-root, :root) {
5
+ --theme-chip-height: var(--theme-size-small-3, 32px);
6
+ --theme-chip-padding-inline: var(--spacing-padding-5, 12px);
7
+ --theme-chip-radius: var(--theme-radius-medium-3, 8px);
8
+ --theme-chip-rounded-radius: var(--theme-radius-large-2, 16px);
9
+ --theme-chip-font-family: var(--font-body-medium-family, "Pretendard");
10
+ --theme-chip-font-size: var(--font-body-xsmall-size, 13px);
11
+ --theme-chip-font-weight: var(--font-body-xsmall-weight, 400);
12
+ }
13
+
14
+ .chip {
15
+ --chip-gap: var(--spacing-gap-1, 4px);
16
+ --chip-bg: transparent;
17
+ --chip-border-color: transparent;
18
+ --chip-label-color: var(--color-label-standard, #3d3f43);
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ gap: var(--chip-gap);
23
+ height: var(--theme-chip-height);
24
+ padding-inline: var(--theme-chip-padding-inline);
25
+ padding-block: 0;
26
+ border-radius: var(--theme-chip-radius);
27
+ border: 1px solid var(--chip-border-color);
28
+ background-color: var(--chip-bg);
29
+ color: var(--chip-label-color);
30
+ font-family: var(--theme-chip-font-family);
31
+ font-size: var(--theme-chip-font-size);
32
+ font-weight: var(--theme-chip-font-weight);
33
+ line-height: 1;
34
+ letter-spacing: 0.2px;
35
+ box-sizing: border-box;
36
+ margin: 0;
37
+ width: fit-content;
38
+ transition:
39
+ background-color 0.16s ease,
40
+ color 0.16s ease,
41
+ border-color 0.16s ease,
42
+ opacity 0.16s ease;
43
+ }
44
+
45
+ button.chip {
46
+ appearance: none;
47
+ cursor: pointer;
48
+ }
49
+
50
+ figure.chip {
51
+ margin: 0;
52
+ }
53
+
54
+ .chip:focus-visible {
55
+ outline: 2px solid var(--color-primary-default, #1a6aff);
56
+ outline-offset: 2px;
57
+ }
58
+
59
+ .chip:where([data-kind="filter"]),
60
+ .chip:where([data-kind="filter-rounded"]) {
61
+ --chip-bg: var(--color-bg-surface-standard, #f2f2f3);
62
+ --chip-label-color: var(--color-label-neutral, #797e86);
63
+ --chip-border-color: transparent;
64
+ }
65
+
66
+ .chip:where([data-kind="filter"][data-selected="true"]),
67
+ .chip:where([data-kind="filter-rounded"][data-selected="true"]) {
68
+ --chip-bg: var(--color-bg-surface-heavy, #313235);
69
+ --chip-label-color: var(--color-common-100, #ffffff);
70
+ }
71
+
72
+ .chip:where([data-kind="filter-rounded"]) {
73
+ border-radius: var(--theme-chip-rounded-radius);
74
+ }
75
+
76
+ .chip:where([data-kind="assist"]) {
77
+ --chip-bg: var(--color-bg-surface-static-neutral, #f2f2f2);
78
+ --chip-label-color: var(--color-label-strong, #18191b);
79
+ --chip-gap: var(--spacing-gap-2, 8px);
80
+ --chip-border-color: transparent;
81
+ }
82
+
83
+ .chip:where([data-kind="assist"][data-selected="true"]) {
84
+ --chip-label-color: var(--color-primary-default, #1a6aff);
85
+ }
86
+
87
+ .chip:where([data-kind="input"]) {
88
+ --chip-gap: var(--spacing-gap-1, 4px);
89
+ --chip-bg: var(--color-common-100, #ffffff);
90
+ --chip-label-color: var(--color-label-standard, #3d3f43);
91
+ --chip-border-color: var(--color-border-standard-assistive, #e4e5e7);
92
+ padding-inline-start: var(--spacing-padding-4, 8px);
93
+ padding-inline-end: var(--spacing-padding-2, 4px);
94
+ }
95
+
96
+ .chip:where([data-kind="input"][data-selected="true"]) {
97
+ --chip-border-color: var(--color-border-standard-blue, #ccdeff);
98
+ }
99
+
100
+ .chip-leading {
101
+ display: inline-flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ color: inherit;
105
+ flex-shrink: 0;
106
+ }
107
+
108
+ .chip-label {
109
+ display: inline-flex;
110
+ align-items: center;
111
+ gap: var(--spacing-gap-1, 4px);
112
+ color: inherit;
113
+ line-height: 1;
114
+ white-space: nowrap;
115
+ }
116
+
117
+ .chip-remove-button {
118
+ display: inline-flex;
119
+ align-items: center;
120
+ justify-content: center;
121
+ width: 16px;
122
+ height: 16px;
123
+ border: none;
124
+ background: transparent;
125
+ color: var(--color-label-neutral, #797e86);
126
+ cursor: pointer;
127
+ padding: 0;
128
+ transition: color 0.16s ease;
129
+ }
130
+
131
+ .chip-remove-button:hover,
132
+ .chip-remove-button:focus-visible {
133
+ color: var(--color-label-strong, #18191b);
134
+ }
135
+
136
+ .chip-remove-button svg {
137
+ display: block;
138
+ width: 100%;
139
+ height: 100%;
140
+ }
@@ -0,0 +1,52 @@
1
+ import type { ComponentPropsWithoutRef, MouseEvent, ReactNode } from "react";
2
+
3
+ export const CHIP_KINDS = [
4
+ "filter",
5
+ "filter-rounded",
6
+ "assist",
7
+ "input",
8
+ ] as const;
9
+
10
+ export type ChipKind = (typeof CHIP_KINDS)[number];
11
+ export type InteractiveChipKind = Exclude<ChipKind, "input">;
12
+
13
+ type ButtonProps = Omit<ComponentPropsWithoutRef<"button">, "children">;
14
+ type FigureProps = Omit<ComponentPropsWithoutRef<"figure">, "children">;
15
+
16
+ export interface ChipCommonProps {
17
+ /**
18
+ * 표시할 라벨.
19
+ */
20
+ children?: ReactNode;
21
+ /**
22
+ * 선택 상태. filter 계열에서 외부 상태로 제어한다.
23
+ */
24
+ selected?: boolean;
25
+ /**
26
+ * assist kind 전용 leading slot.
27
+ */
28
+ leading?: ReactNode;
29
+ /**
30
+ * input kind 전용 제거 버튼 aria-label.
31
+ */
32
+ removeButtonLabel?: string;
33
+ }
34
+
35
+ export interface ChipInteractiveProps extends ChipCommonProps, ButtonProps {
36
+ kind?: InteractiveChipKind;
37
+ }
38
+
39
+ export interface ChipInputProps extends ChipCommonProps, FigureProps {
40
+ kind: "input";
41
+ onRemove?: (event: MouseEvent<HTMLButtonElement>) => void;
42
+ }
43
+
44
+ export type ChipProps = ChipInteractiveProps | ChipInputProps;
45
+
46
+ export interface ChipClassNameOptions {
47
+ kind: ChipKind;
48
+ selected?: boolean;
49
+ hasLeading?: boolean;
50
+ removable?: boolean;
51
+ className?: string;
52
+ }
@@ -0,0 +1,36 @@
1
+ import clsx from "clsx";
2
+ import type { ChipClassNameOptions } from "../types";
3
+
4
+ const CHIP_CLASSNAME = "chip";
5
+ const CHIP_LEADING_CLASSNAME = "chip-leading";
6
+ const CHIP_LABEL_CLASSNAME = "chip-label";
7
+ const CHIP_REMOVE_BUTTON_CLASSNAME = "chip-remove-button";
8
+
9
+ /**
10
+ * Chip은 kind/selected/slot 여부에 따른 modifier class가 많아 helper로 묶는다.
11
+ */
12
+ const composeChipClassName = ({
13
+ kind,
14
+ selected,
15
+ hasLeading,
16
+ removable,
17
+ className,
18
+ }: ChipClassNameOptions) =>
19
+ clsx(
20
+ CHIP_CLASSNAME,
21
+ `${CHIP_CLASSNAME}--kind-${kind}`,
22
+ {
23
+ [`${CHIP_CLASSNAME}--selected`]: Boolean(selected),
24
+ [`${CHIP_CLASSNAME}--has-leading`]: Boolean(hasLeading),
25
+ [`${CHIP_CLASSNAME}--removable`]: Boolean(removable),
26
+ },
27
+ className,
28
+ );
29
+
30
+ export {
31
+ CHIP_CLASSNAME,
32
+ CHIP_LABEL_CLASSNAME,
33
+ CHIP_LEADING_CLASSNAME,
34
+ CHIP_REMOVE_BUTTON_CLASSNAME,
35
+ composeChipClassName,
36
+ };
@@ -0,0 +1,4 @@
1
+ /**
2
+ * TODO(dialog): 접근성/상태 계산 hook을 정의한다.
3
+ */
4
+ export {};
File without changes
@@ -0,0 +1 @@
1
+ @use "./styles/index.scss";
@@ -0,0 +1,3 @@
1
+ import "./index.scss";
2
+
3
+ export * from "./markup";
@@ -0,0 +1,316 @@
1
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
2
+ import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
3
+ import clsx from "clsx";
4
+ import { createContext, forwardRef, useContext, useState } from "react";
5
+ import type {
6
+ ConfirmDialogActionProps,
7
+ ConfirmDialogCancelProps,
8
+ ConfirmDialogContentProps,
9
+ ConfirmDialogDescriptionProps,
10
+ ConfirmDialogOverlayProps,
11
+ ConfirmDialogSectionProps,
12
+ ConfirmDialogTitleProps,
13
+ ConfirmDialogRootProps,
14
+ } from "../types";
15
+ import type { PointerEvent } from "react";
16
+
17
+ type ConfirmDialogInternalContextValue = {
18
+ requestClose: () => void;
19
+ };
20
+
21
+ const ConfirmDialogInternalContext = createContext<
22
+ ConfirmDialogInternalContextValue | undefined
23
+ >(undefined);
24
+
25
+ const useConfirmDialogInternalContext = () => {
26
+ const context = useContext(ConfirmDialogInternalContext);
27
+ if (!context) {
28
+ throw new Error(
29
+ "ConfirmDialog components must be used within ConfirmDialogRoot",
30
+ );
31
+ }
32
+ return context;
33
+ };
34
+
35
+ /**
36
+ * ConfirmDialogRoot; AlertDialog 루트
37
+ * @component
38
+ * @param {ConfirmDialogRootProps} props
39
+ */
40
+ const ConfirmDialogRoot = ({
41
+ open: openProp,
42
+ defaultOpen,
43
+ onOpenChange,
44
+ children,
45
+ ...restProps
46
+ }: ConfirmDialogRootProps) => {
47
+ const isControlled = openProp !== undefined;
48
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(
49
+ defaultOpen ?? false,
50
+ );
51
+ const resolvedOpen = isControlled ? openProp : uncontrolledOpen;
52
+
53
+ const handleOpenChange = (nextOpen: boolean) => {
54
+ if (!isControlled) {
55
+ setUncontrolledOpen(nextOpen);
56
+ }
57
+ onOpenChange?.(nextOpen);
58
+ };
59
+
60
+ return (
61
+ <ConfirmDialogInternalContext.Provider
62
+ value={{
63
+ requestClose: () => handleOpenChange(false),
64
+ }}
65
+ >
66
+ <AlertDialogPrimitive.Root
67
+ {...restProps}
68
+ open={resolvedOpen}
69
+ onOpenChange={handleOpenChange}
70
+ >
71
+ {children}
72
+ </AlertDialogPrimitive.Root>
73
+ </ConfirmDialogInternalContext.Provider>
74
+ );
75
+ };
76
+ const ConfirmDialogTrigger = AlertDialogPrimitive.Trigger;
77
+ const ConfirmDialogPortal = AlertDialogPrimitive.Portal;
78
+
79
+ /**
80
+ * ConfirmDialogOverlay; 취소 성격의 바깥 dim
81
+ * @component
82
+ * @param {ConfirmDialogOverlayProps} props
83
+ */
84
+ const ConfirmDialogOverlay = forwardRef<
85
+ HTMLDivElement,
86
+ ConfirmDialogOverlayProps
87
+ >(
88
+ (
89
+ { className, disableOutsideClose = false, onPointerDown, ...props },
90
+ forwardedRef,
91
+ ) => {
92
+ const { requestClose } = useConfirmDialogInternalContext();
93
+
94
+ const handlePointerDown = (event: PointerEvent<HTMLDivElement>) => {
95
+ onPointerDown?.(event);
96
+ if (event.defaultPrevented) {
97
+ return;
98
+ }
99
+ if (disableOutsideClose) {
100
+ return;
101
+ }
102
+ requestClose();
103
+ };
104
+
105
+ return (
106
+ <AlertDialogPrimitive.Overlay
107
+ {...props}
108
+ ref={forwardedRef}
109
+ className={clsx("dialog-overlay confirm-dialog-overlay", className)}
110
+ data-variant="confirm"
111
+ onPointerDown={handlePointerDown}
112
+ />
113
+ );
114
+ },
115
+ );
116
+
117
+ ConfirmDialogOverlay.displayName = "ConfirmDialogOverlay";
118
+
119
+ /**
120
+ * ConfirmDialogContent; AlertDialog 패널
121
+ * @component
122
+ * @param {ConfirmDialogContentProps} props
123
+ */
124
+ const ConfirmDialogContent = forwardRef<
125
+ HTMLDivElement,
126
+ ConfirmDialogContentProps
127
+ >(({ className, children, ...props }, forwardedRef) => (
128
+ <AlertDialogPrimitive.Content
129
+ {...props}
130
+ ref={forwardedRef}
131
+ className={clsx("dialog-content confirm-dialog-content", className)}
132
+ data-variant="confirm"
133
+ >
134
+ {children}
135
+ </AlertDialogPrimitive.Content>
136
+ ));
137
+
138
+ ConfirmDialogContent.displayName = "ConfirmDialogContent";
139
+
140
+ /**
141
+ * ConfirmDialogTitle; AlertDialog 제목
142
+ * @component
143
+ * @param {ConfirmDialogTitleProps} props
144
+ */
145
+ const ConfirmDialogTitle = forwardRef<
146
+ HTMLHeadingElement,
147
+ ConfirmDialogTitleProps
148
+ >(({ className, visuallyHidden = false, children, ...props }, forwardedRef) => {
149
+ const titleNode = (
150
+ <AlertDialogPrimitive.Title
151
+ {...props}
152
+ ref={forwardedRef}
153
+ className={clsx("dialog-title confirm-dialog-title", className)}
154
+ data-variant="confirm"
155
+ >
156
+ {children}
157
+ </AlertDialogPrimitive.Title>
158
+ );
159
+
160
+ if (visuallyHidden) {
161
+ return <VisuallyHidden asChild>{titleNode}</VisuallyHidden>;
162
+ }
163
+
164
+ return titleNode;
165
+ });
166
+
167
+ ConfirmDialogTitle.displayName = "ConfirmDialogTitle";
168
+
169
+ /**
170
+ * ConfirmDialogDescription; AlertDialog 설명
171
+ * @component
172
+ * @param {ConfirmDialogDescriptionProps} props
173
+ */
174
+ const ConfirmDialogDescription = forwardRef<
175
+ HTMLParagraphElement,
176
+ ConfirmDialogDescriptionProps
177
+ >(({ className, visuallyHidden = false, children, ...props }, forwardedRef) => {
178
+ const descriptionNode = (
179
+ <AlertDialogPrimitive.Description
180
+ {...props}
181
+ ref={forwardedRef}
182
+ className={clsx(
183
+ "dialog-description confirm-dialog-description",
184
+ className,
185
+ )}
186
+ data-variant="confirm"
187
+ >
188
+ {children}
189
+ </AlertDialogPrimitive.Description>
190
+ );
191
+
192
+ if (visuallyHidden) {
193
+ return <VisuallyHidden asChild>{descriptionNode}</VisuallyHidden>;
194
+ }
195
+
196
+ return descriptionNode;
197
+ });
198
+
199
+ ConfirmDialogDescription.displayName = "ConfirmDialogDescription";
200
+
201
+ /**
202
+ * ConfirmDialogHeader; 헤더 영역
203
+ * @component
204
+ * @param {ConfirmDialogSectionProps} props
205
+ */
206
+ const ConfirmDialogHeader = forwardRef<
207
+ HTMLDivElement,
208
+ ConfirmDialogSectionProps
209
+ >(({ className, ...props }, forwardedRef) => (
210
+ <div
211
+ {...props}
212
+ ref={forwardedRef}
213
+ className={clsx("dialog-section confirm-dialog-header", className)}
214
+ data-section="header"
215
+ />
216
+ ));
217
+
218
+ ConfirmDialogHeader.displayName = "ConfirmDialogHeader";
219
+
220
+ /**
221
+ * ConfirmDialogBody; 본문 영역
222
+ * @component
223
+ * @param {ConfirmDialogSectionProps} props
224
+ */
225
+ const ConfirmDialogBody = forwardRef<HTMLDivElement, ConfirmDialogSectionProps>(
226
+ ({ className, ...props }, forwardedRef) => (
227
+ <div
228
+ {...props}
229
+ ref={forwardedRef}
230
+ className={clsx("dialog-section confirm-dialog-body", className)}
231
+ data-section="body"
232
+ />
233
+ ),
234
+ );
235
+
236
+ ConfirmDialogBody.displayName = "ConfirmDialogBody";
237
+
238
+ /**
239
+ * ConfirmDialogActions; 버튼 영역
240
+ * @component
241
+ * @param {ConfirmDialogSectionProps} props
242
+ */
243
+ const ConfirmDialogActions = forwardRef<
244
+ HTMLDivElement,
245
+ ConfirmDialogSectionProps
246
+ >(({ className, ...props }, forwardedRef) => (
247
+ <div
248
+ {...props}
249
+ ref={forwardedRef}
250
+ className={clsx("dialog-section confirm-dialog-actions", className)}
251
+ data-section="actions"
252
+ />
253
+ ));
254
+
255
+ ConfirmDialogActions.displayName = "ConfirmDialogActions";
256
+
257
+ /**
258
+ * ConfirmDialogCancelButton; AlertDialog Cancel wrapper
259
+ * @component
260
+ * @param {ConfirmDialogCancelProps} props
261
+ */
262
+ const ConfirmDialogCancel = forwardRef<
263
+ HTMLButtonElement,
264
+ ConfirmDialogCancelProps
265
+ >(({ className, asChild, ...props }, forwardedRef) => (
266
+ <AlertDialogPrimitive.Cancel
267
+ {...props}
268
+ asChild={asChild}
269
+ ref={forwardedRef}
270
+ className={clsx(
271
+ !asChild && "dialog-button confirm-dialog-cancel",
272
+ className,
273
+ )}
274
+ data-native-element={asChild ? undefined : "true"}
275
+ />
276
+ ));
277
+
278
+ ConfirmDialogCancel.displayName = "ConfirmDialogCancel";
279
+
280
+ /**
281
+ * ConfirmDialogActionButton; AlertDialog Action wrapper
282
+ * @component
283
+ * @param {ConfirmDialogActionProps} props
284
+ */
285
+ const ConfirmDialogAction = forwardRef<
286
+ HTMLButtonElement,
287
+ ConfirmDialogActionProps
288
+ >(({ className, asChild, ...props }, forwardedRef) => (
289
+ <AlertDialogPrimitive.Action
290
+ {...props}
291
+ asChild={asChild}
292
+ ref={forwardedRef}
293
+ className={clsx(
294
+ !asChild && "dialog-button confirm-dialog-action",
295
+ className,
296
+ )}
297
+ data-native-element={asChild ? undefined : "true"}
298
+ />
299
+ ));
300
+
301
+ ConfirmDialogAction.displayName = "ConfirmDialogAction";
302
+
303
+ export {
304
+ ConfirmDialogRoot,
305
+ ConfirmDialogTrigger,
306
+ ConfirmDialogPortal,
307
+ ConfirmDialogOverlay,
308
+ ConfirmDialogContent,
309
+ ConfirmDialogTitle,
310
+ ConfirmDialogDescription,
311
+ ConfirmDialogHeader,
312
+ ConfirmDialogBody,
313
+ ConfirmDialogActions,
314
+ ConfirmDialogCancel,
315
+ ConfirmDialogAction,
316
+ };
@@ -0,0 +1,4 @@
1
+ "use client";
2
+
3
+ export * from "./notice-dialog";
4
+ export * from "./confirm-dialog";