@nurimedia/react-ui 0.1.0

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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/dist/AlertDialog/index.cjs +185 -0
  4. package/dist/AlertDialog/index.cjs.map +1 -0
  5. package/dist/AlertDialog/index.d.cts +49 -0
  6. package/dist/AlertDialog/index.d.ts +49 -0
  7. package/dist/AlertDialog/index.js +148 -0
  8. package/dist/AlertDialog/index.js.map +1 -0
  9. package/dist/AlertDialog/styles.css +187 -0
  10. package/dist/Button/index.cjs +136 -0
  11. package/dist/Button/index.cjs.map +1 -0
  12. package/dist/Button/index.d.cts +65 -0
  13. package/dist/Button/index.d.ts +65 -0
  14. package/dist/Button/index.js +109 -0
  15. package/dist/Button/index.js.map +1 -0
  16. package/dist/Button/styles.css +181 -0
  17. package/dist/Checkbox/index.cjs +83 -0
  18. package/dist/Checkbox/index.cjs.map +1 -0
  19. package/dist/Checkbox/index.d.cts +40 -0
  20. package/dist/Checkbox/index.d.ts +40 -0
  21. package/dist/Checkbox/index.js +46 -0
  22. package/dist/Checkbox/index.js.map +1 -0
  23. package/dist/Checkbox/styles.css +78 -0
  24. package/dist/Input/index.cjs +103 -0
  25. package/dist/Input/index.cjs.map +1 -0
  26. package/dist/Input/index.d.cts +53 -0
  27. package/dist/Input/index.d.ts +53 -0
  28. package/dist/Input/index.js +76 -0
  29. package/dist/Input/index.js.map +1 -0
  30. package/dist/Input/styles.css +135 -0
  31. package/dist/Modal/index.cjs +120 -0
  32. package/dist/Modal/index.cjs.map +1 -0
  33. package/dist/Modal/index.d.cts +62 -0
  34. package/dist/Modal/index.d.ts +62 -0
  35. package/dist/Modal/index.js +83 -0
  36. package/dist/Modal/index.js.map +1 -0
  37. package/dist/Modal/styles.css +229 -0
  38. package/dist/Radio/index.cjs +86 -0
  39. package/dist/Radio/index.cjs.map +1 -0
  40. package/dist/Radio/index.d.cts +46 -0
  41. package/dist/Radio/index.d.ts +46 -0
  42. package/dist/Radio/index.js +48 -0
  43. package/dist/Radio/index.js.map +1 -0
  44. package/dist/Radio/styles.css +76 -0
  45. package/dist/Select/index.cjs +116 -0
  46. package/dist/Select/index.cjs.map +1 -0
  47. package/dist/Select/index.d.cts +61 -0
  48. package/dist/Select/index.d.ts +61 -0
  49. package/dist/Select/index.js +79 -0
  50. package/dist/Select/index.js.map +1 -0
  51. package/dist/Select/styles.css +157 -0
  52. package/dist/Switch/index.cjs +71 -0
  53. package/dist/Switch/index.cjs.map +1 -0
  54. package/dist/Switch/index.d.cts +34 -0
  55. package/dist/Switch/index.d.ts +34 -0
  56. package/dist/Switch/index.js +34 -0
  57. package/dist/Switch/index.js.map +1 -0
  58. package/dist/Switch/styles.css +71 -0
  59. package/dist/Textarea/index.cjs +127 -0
  60. package/dist/Textarea/index.cjs.map +1 -0
  61. package/dist/Textarea/index.d.cts +48 -0
  62. package/dist/Textarea/index.d.ts +48 -0
  63. package/dist/Textarea/index.js +100 -0
  64. package/dist/Textarea/index.js.map +1 -0
  65. package/dist/Textarea/styles.css +95 -0
  66. package/dist/Toast/index.cjs +184 -0
  67. package/dist/Toast/index.cjs.map +1 -0
  68. package/dist/Toast/index.d.cts +67 -0
  69. package/dist/Toast/index.d.ts +67 -0
  70. package/dist/Toast/index.js +146 -0
  71. package/dist/Toast/index.js.map +1 -0
  72. package/dist/Toast/styles.css +122 -0
  73. package/dist/Tooltip/index.cjs +105 -0
  74. package/dist/Tooltip/index.cjs.map +1 -0
  75. package/dist/Tooltip/index.d.cts +65 -0
  76. package/dist/Tooltip/index.d.ts +65 -0
  77. package/dist/Tooltip/index.js +67 -0
  78. package/dist/Tooltip/index.js.map +1 -0
  79. package/dist/Tooltip/styles.css +42 -0
  80. package/dist/index.cjs +900 -0
  81. package/dist/index.cjs.map +1 -0
  82. package/dist/index.d.cts +16 -0
  83. package/dist/index.d.ts +16 -0
  84. package/dist/index.js +850 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/styles.css +11 -0
  87. package/dist/tokens.css +232 -0
  88. package/dist/typography.css +104 -0
  89. package/llms.txt +369 -0
  90. package/package.json +183 -0
package/dist/index.js ADDED
@@ -0,0 +1,850 @@
1
+ // src/Button/Button.tsx
2
+ import "./Button/styles.css";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import { Children, cloneElement, forwardRef, isValidElement } from "react";
5
+
6
+ // src/Button/Spinner.tsx
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var Spinner = () => /* @__PURE__ */ jsx("span", { className: "nuri-button__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("svg", { className: "nuri-button__spinner", viewBox: "0 0 16 16", width: "16", height: "16", fill: "none", children: [
9
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "6", stroke: "currentColor", strokeOpacity: "0.25", strokeWidth: "2" }),
10
+ /* @__PURE__ */ jsx("path", { d: "M14 8a6 6 0 0 0-6-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
11
+ ] }) });
12
+
13
+ // src/utils/cx.ts
14
+ function cx(...classes) {
15
+ return classes.filter(Boolean).join(" ");
16
+ }
17
+
18
+ // src/Button/Button.tsx
19
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
20
+ var Button = forwardRef(function Button2({
21
+ variant = "primary",
22
+ size = "md",
23
+ iconLeft,
24
+ iconRight,
25
+ iconOnly = false,
26
+ block = false,
27
+ loading = false,
28
+ disabled = false,
29
+ asChild = false,
30
+ type = "button",
31
+ className,
32
+ children,
33
+ onClick,
34
+ ...rest
35
+ }, ref) {
36
+ const isBlocked = disabled || loading;
37
+ if (process.env.NODE_ENV !== "production" && iconOnly && !rest["aria-label"] && !rest["aria-labelledby"]) {
38
+ console.warn(
39
+ "[nuri/Button] `iconOnly` \uBC84\uD2BC\uC740 `aria-label`(\uB610\uB294 `aria-labelledby`)\uC774 \uD544\uC694\uD569\uB2C8\uB2E4."
40
+ );
41
+ }
42
+ const hasLeftSlot = !iconOnly && (loading || iconLeft != null);
43
+ const hasRightSlot = !iconOnly && !loading && iconRight != null;
44
+ const classes = cx(
45
+ "nuri-button",
46
+ `nuri-button--${variant}`,
47
+ `nuri-button--${size}`,
48
+ block && "nuri-button--block",
49
+ iconOnly && "nuri-button--icon-only",
50
+ isBlocked && "nuri-button--disabled",
51
+ loading && "nuri-button--loading",
52
+ hasLeftSlot && "nuri-button--has-left",
53
+ hasRightSlot && "nuri-button--has-right",
54
+ className
55
+ );
56
+ const handleClick = (e) => {
57
+ if (isBlocked) {
58
+ e.preventDefault();
59
+ e.stopPropagation();
60
+ return;
61
+ }
62
+ onClick?.(e);
63
+ };
64
+ const renderContent = (content) => {
65
+ if (iconOnly) {
66
+ return /* @__PURE__ */ jsx2("span", { className: "nuri-button__icon", "aria-hidden": "true", children: loading ? /* @__PURE__ */ jsx2(Spinner, {}) : content });
67
+ }
68
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
69
+ loading ? /* @__PURE__ */ jsx2(Spinner, {}) : iconLeft != null && /* @__PURE__ */ jsx2("span", { className: "nuri-button__icon nuri-button__icon--left", "aria-hidden": "true", children: iconLeft }),
70
+ content,
71
+ hasRightSlot && /* @__PURE__ */ jsx2("span", { className: "nuri-button__icon nuri-button__icon--right", "aria-hidden": "true", children: iconRight })
72
+ ] });
73
+ };
74
+ if (asChild) {
75
+ const child = Children.only(children);
76
+ if (!isValidElement(child)) return null;
77
+ const childElement = child;
78
+ return /* @__PURE__ */ jsx2(
79
+ Slot,
80
+ {
81
+ ref,
82
+ className: classes,
83
+ "aria-disabled": isBlocked || void 0,
84
+ "aria-busy": loading || void 0,
85
+ onClick: handleClick,
86
+ ...rest,
87
+ children: cloneElement(childElement, void 0, renderContent(childElement.props.children))
88
+ }
89
+ );
90
+ }
91
+ return /* @__PURE__ */ jsx2(
92
+ "button",
93
+ {
94
+ ref,
95
+ type,
96
+ className: classes,
97
+ disabled,
98
+ "aria-disabled": loading || void 0,
99
+ "aria-busy": loading || void 0,
100
+ onClick: handleClick,
101
+ ...rest,
102
+ children: renderContent(children)
103
+ }
104
+ );
105
+ });
106
+
107
+ // src/Input/Input.tsx
108
+ import "./Input/styles.css";
109
+ import { forwardRef as forwardRef2, useId } from "react";
110
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
111
+ var Input = forwardRef2(function Input2({
112
+ size = "md",
113
+ label,
114
+ hideLabel = false,
115
+ description,
116
+ invalid = false,
117
+ errorMessage,
118
+ iconLeft,
119
+ iconRight,
120
+ block = false,
121
+ disabled = false,
122
+ className,
123
+ id: idProp,
124
+ "aria-describedby": ariaDescribedby,
125
+ ...rest
126
+ }, ref) {
127
+ const reactId = useId();
128
+ const id = idProp ?? `nuri-input-${reactId}`;
129
+ const messageId = `${id}-message`;
130
+ const message = invalid && errorMessage != null ? errorMessage : description;
131
+ const hasMessage = message != null;
132
+ const describedBy = cx(hasMessage ? messageId : void 0, ariaDescribedby) || void 0;
133
+ return /* @__PURE__ */ jsxs3("div", { className: cx("nuri-input", block && "nuri-input--block", className), children: [
134
+ label != null && /* @__PURE__ */ jsx3("label", { htmlFor: id, className: cx("nuri-input__label", hideLabel && "nuri-sr-only"), children: label }),
135
+ /* @__PURE__ */ jsxs3(
136
+ "div",
137
+ {
138
+ className: cx(
139
+ "nuri-input__field",
140
+ `nuri-input__field--${size}`,
141
+ invalid && "nuri-input__field--invalid",
142
+ disabled && "nuri-input__field--disabled"
143
+ ),
144
+ children: [
145
+ iconLeft != null && /* @__PURE__ */ jsx3("span", { className: "nuri-input__icon", "aria-hidden": "true", children: iconLeft }),
146
+ /* @__PURE__ */ jsx3(
147
+ "input",
148
+ {
149
+ ref,
150
+ id,
151
+ className: "nuri-input__control",
152
+ disabled,
153
+ "aria-invalid": invalid || void 0,
154
+ "aria-describedby": describedBy,
155
+ ...rest
156
+ }
157
+ ),
158
+ iconRight != null && /* @__PURE__ */ jsx3("span", { className: "nuri-input__icon", "aria-hidden": "true", children: iconRight })
159
+ ]
160
+ }
161
+ ),
162
+ hasMessage && /* @__PURE__ */ jsx3(
163
+ "p",
164
+ {
165
+ id: messageId,
166
+ className: cx("nuri-input__message", invalid && "nuri-input__message--error"),
167
+ children: message
168
+ }
169
+ )
170
+ ] });
171
+ });
172
+
173
+ // src/Textarea/Textarea.tsx
174
+ import "./Textarea/styles.css";
175
+ import { forwardRef as forwardRef3, useCallback, useId as useId2, useLayoutEffect, useRef } from "react";
176
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
177
+ var Textarea = forwardRef3(function Textarea2({
178
+ label,
179
+ hideLabel = false,
180
+ description,
181
+ invalid = false,
182
+ errorMessage,
183
+ block = false,
184
+ resize = "vertical",
185
+ autosize = false,
186
+ maxRows,
187
+ rows = 3,
188
+ disabled = false,
189
+ className,
190
+ id: idProp,
191
+ value,
192
+ onChange,
193
+ "aria-describedby": ariaDescribedby,
194
+ ...rest
195
+ }, ref) {
196
+ const reactId = useId2();
197
+ const id = idProp ?? `nuri-textarea-${reactId}`;
198
+ const messageId = `${id}-message`;
199
+ const innerRef = useRef(null);
200
+ const setRefs = useCallback(
201
+ (node) => {
202
+ innerRef.current = node;
203
+ if (typeof ref === "function") ref(node);
204
+ else if (ref) ref.current = node;
205
+ },
206
+ [ref]
207
+ );
208
+ const fitHeight = useCallback(() => {
209
+ const el = innerRef.current;
210
+ if (!el) return;
211
+ const cs = getComputedStyle(el);
212
+ const borders = parseFloat(cs.borderTopWidth) + parseFloat(cs.borderBottomWidth);
213
+ const lineHeight = parseFloat(cs.lineHeight);
214
+ const maxHeight = maxRows != null && !Number.isNaN(lineHeight) ? maxRows * lineHeight + parseFloat(cs.paddingTop) + parseFloat(cs.paddingBottom) + borders : Infinity;
215
+ el.style.height = "auto";
216
+ const contentHeight = el.scrollHeight + borders;
217
+ const next = Math.min(contentHeight, maxHeight);
218
+ if (!Number.isNaN(next)) el.style.height = `${next}px`;
219
+ el.style.overflowY = contentHeight > maxHeight ? "auto" : "hidden";
220
+ }, [maxRows]);
221
+ useLayoutEffect(() => {
222
+ if (autosize) fitHeight();
223
+ }, [autosize, fitHeight, value]);
224
+ const handleChange = (e) => {
225
+ onChange?.(e);
226
+ if (autosize) fitHeight();
227
+ };
228
+ const message = invalid && errorMessage != null ? errorMessage : description;
229
+ const hasMessage = message != null;
230
+ const describedBy = cx(hasMessage ? messageId : void 0, ariaDescribedby) || void 0;
231
+ return /* @__PURE__ */ jsxs4("div", { className: cx("nuri-textarea", block && "nuri-textarea--block", className), children: [
232
+ label != null && /* @__PURE__ */ jsx4("label", { htmlFor: id, className: cx("nuri-textarea__label", hideLabel && "nuri-sr-only"), children: label }),
233
+ /* @__PURE__ */ jsx4(
234
+ "textarea",
235
+ {
236
+ ref: setRefs,
237
+ id,
238
+ rows,
239
+ value,
240
+ onChange: handleChange,
241
+ className: cx(
242
+ "nuri-textarea__control",
243
+ invalid && "nuri-textarea__control--invalid",
244
+ (resize === "none" || autosize) && "nuri-textarea__control--resize-none"
245
+ ),
246
+ disabled,
247
+ "aria-invalid": invalid || void 0,
248
+ "aria-describedby": describedBy,
249
+ ...rest
250
+ }
251
+ ),
252
+ hasMessage && /* @__PURE__ */ jsx4(
253
+ "p",
254
+ {
255
+ id: messageId,
256
+ className: cx("nuri-textarea__message", invalid && "nuri-textarea__message--error"),
257
+ children: message
258
+ }
259
+ )
260
+ ] });
261
+ });
262
+
263
+ // src/Checkbox/Checkbox.tsx
264
+ import "./Checkbox/styles.css";
265
+ import * as RadixCheckbox from "@radix-ui/react-checkbox";
266
+ import { forwardRef as forwardRef4, useId as useId3 } from "react";
267
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
268
+ var CheckIcon = () => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(
269
+ "path",
270
+ {
271
+ d: "M2.5 6.2l2.4 2.4 4.6-5",
272
+ stroke: "currentColor",
273
+ strokeWidth: "1.6",
274
+ strokeLinecap: "round",
275
+ strokeLinejoin: "round"
276
+ }
277
+ ) });
278
+ var IndeterminateIcon = () => /* @__PURE__ */ jsx5("svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx5("path", { d: "M2.8 6h6.4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }) });
279
+ var Checkbox = forwardRef4(function Checkbox2({ label, size = "md", disabled = false, id: idProp, className, checked, ...rest }, ref) {
280
+ const reactId = useId3();
281
+ const id = idProp ?? `nuri-checkbox-${reactId}`;
282
+ return /* @__PURE__ */ jsxs5("div", { className: cx("nuri-checkbox", `nuri-checkbox--${size}`, className), children: [
283
+ /* @__PURE__ */ jsx5(
284
+ RadixCheckbox.Root,
285
+ {
286
+ ref,
287
+ id,
288
+ className: "nuri-checkbox__control",
289
+ disabled,
290
+ checked,
291
+ ...rest,
292
+ children: /* @__PURE__ */ jsx5(RadixCheckbox.Indicator, { className: "nuri-checkbox__indicator", children: checked === "indeterminate" ? /* @__PURE__ */ jsx5(IndeterminateIcon, {}) : /* @__PURE__ */ jsx5(CheckIcon, {}) })
293
+ }
294
+ ),
295
+ label != null && /* @__PURE__ */ jsx5("label", { htmlFor: id, className: "nuri-checkbox__label", children: label })
296
+ ] });
297
+ });
298
+
299
+ // src/Radio/Radio.tsx
300
+ import "./Radio/styles.css";
301
+ import * as RadixRadioGroup from "@radix-ui/react-radio-group";
302
+ import { forwardRef as forwardRef5, useId as useId4 } from "react";
303
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
304
+ var RadioGroup = forwardRef5(function RadioGroup2({ children, orientation = "vertical", className, ...rest }, ref) {
305
+ return /* @__PURE__ */ jsx6(
306
+ RadixRadioGroup.Root,
307
+ {
308
+ ref,
309
+ orientation,
310
+ className: cx("nuri-radio-group", `nuri-radio-group--${orientation}`, className),
311
+ ...rest,
312
+ children
313
+ }
314
+ );
315
+ });
316
+ var Radio = forwardRef5(function Radio2({ value, label, disabled = false, id: idProp, className, ...rest }, ref) {
317
+ const reactId = useId4();
318
+ const id = idProp ?? `nuri-radio-${reactId}`;
319
+ return /* @__PURE__ */ jsxs6("div", { className: cx("nuri-radio", className), children: [
320
+ /* @__PURE__ */ jsx6(
321
+ RadixRadioGroup.Item,
322
+ {
323
+ ref,
324
+ id,
325
+ value,
326
+ disabled,
327
+ className: "nuri-radio__control",
328
+ ...rest,
329
+ children: /* @__PURE__ */ jsx6(RadixRadioGroup.Indicator, { className: "nuri-radio__indicator" })
330
+ }
331
+ ),
332
+ label != null && /* @__PURE__ */ jsx6("label", { htmlFor: id, className: "nuri-radio__label", children: label })
333
+ ] });
334
+ });
335
+
336
+ // src/Switch/Switch.tsx
337
+ import "./Switch/styles.css";
338
+ import * as RadixSwitch from "@radix-ui/react-switch";
339
+ import { forwardRef as forwardRef6, useId as useId5 } from "react";
340
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
341
+ var Switch = forwardRef6(function Switch2({ label, disabled = false, id: idProp, className, ...rest }, ref) {
342
+ const reactId = useId5();
343
+ const id = idProp ?? `nuri-switch-${reactId}`;
344
+ return /* @__PURE__ */ jsxs7("div", { className: cx("nuri-switch", className), children: [
345
+ /* @__PURE__ */ jsx7(
346
+ RadixSwitch.Root,
347
+ {
348
+ ref,
349
+ id,
350
+ className: "nuri-switch__control",
351
+ disabled,
352
+ ...rest,
353
+ children: /* @__PURE__ */ jsx7(RadixSwitch.Thumb, { className: "nuri-switch__thumb" })
354
+ }
355
+ ),
356
+ label != null && /* @__PURE__ */ jsx7("label", { htmlFor: id, className: "nuri-switch__label", children: label })
357
+ ] });
358
+ });
359
+
360
+ // src/Select/Select.tsx
361
+ import "./Select/styles.css";
362
+ import * as RadixSelect from "@radix-ui/react-select";
363
+ import { forwardRef as forwardRef7 } from "react";
364
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
365
+ var CaretIcon = () => /* @__PURE__ */ jsx8("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M1.1 2.5h5.8L4 5.9z", fill: "currentColor" }) });
366
+ var Select = forwardRef7(function Select2({
367
+ options,
368
+ size = "md",
369
+ placeholder,
370
+ value,
371
+ defaultValue,
372
+ onValueChange,
373
+ open,
374
+ defaultOpen,
375
+ onOpenChange,
376
+ disabled = false,
377
+ block = false,
378
+ name,
379
+ required,
380
+ container,
381
+ className,
382
+ "aria-label": ariaLabel
383
+ }, ref) {
384
+ return /* @__PURE__ */ jsxs8(
385
+ RadixSelect.Root,
386
+ {
387
+ value,
388
+ defaultValue,
389
+ onValueChange,
390
+ open,
391
+ defaultOpen,
392
+ onOpenChange,
393
+ disabled,
394
+ name,
395
+ required,
396
+ children: [
397
+ /* @__PURE__ */ jsxs8(
398
+ RadixSelect.Trigger,
399
+ {
400
+ ref,
401
+ "aria-label": ariaLabel,
402
+ className: cx(
403
+ "nuri-select__trigger",
404
+ `nuri-select__trigger--${size}`,
405
+ block && "nuri-select__trigger--block",
406
+ className
407
+ ),
408
+ children: [
409
+ /* @__PURE__ */ jsx8("span", { className: "nuri-select__value", children: /* @__PURE__ */ jsx8(RadixSelect.Value, { placeholder }) }),
410
+ /* @__PURE__ */ jsx8(RadixSelect.Icon, { className: "nuri-select__caret", children: /* @__PURE__ */ jsx8(CaretIcon, {}) })
411
+ ]
412
+ }
413
+ ),
414
+ /* @__PURE__ */ jsx8(RadixSelect.Portal, { container, children: /* @__PURE__ */ jsx8(RadixSelect.Content, { className: "nuri-select__content", position: "popper", sideOffset: 6, children: /* @__PURE__ */ jsx8(RadixSelect.Viewport, { className: "nuri-select__viewport", children: options.map((option) => /* @__PURE__ */ jsx8(
415
+ RadixSelect.Item,
416
+ {
417
+ value: option.value,
418
+ disabled: option.disabled,
419
+ className: "nuri-select__item",
420
+ children: /* @__PURE__ */ jsx8(RadixSelect.ItemText, { children: option.label })
421
+ },
422
+ option.value
423
+ )) }) }) })
424
+ ]
425
+ }
426
+ );
427
+ });
428
+
429
+ // src/Modal/Modal.tsx
430
+ import "./Modal/styles.css";
431
+ import * as Dialog from "@radix-ui/react-dialog";
432
+ import { forwardRef as forwardRef8 } from "react";
433
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
434
+ var Root6 = (props) => /* @__PURE__ */ jsx9(Dialog.Root, { ...props });
435
+ Root6.displayName = "Modal";
436
+ var Trigger3 = Dialog.Trigger;
437
+ var Content3 = forwardRef8(
438
+ function ModalContent({ placement = "center", size = "md", overlay = true, container, className, children, ...rest }, ref) {
439
+ const classes = cx("nuri-modal", `nuri-modal--${placement}`, `nuri-modal--${size}`, className);
440
+ return /* @__PURE__ */ jsxs9(Dialog.Portal, { container, children: [
441
+ overlay && /* @__PURE__ */ jsx9(Dialog.Overlay, { className: "nuri-modal__overlay" }),
442
+ /* @__PURE__ */ jsx9(Dialog.Content, { ref, className: classes, ...rest, children })
443
+ ] });
444
+ }
445
+ );
446
+ var Header = forwardRef8(function ModalHeader({ className, ...rest }, ref) {
447
+ return /* @__PURE__ */ jsx9("div", { ref, className: cx("nuri-modal__header", className), ...rest });
448
+ });
449
+ var Title2 = forwardRef8(function ModalTitle({ visuallyHidden = false, className, ...rest }, ref) {
450
+ return /* @__PURE__ */ jsx9(
451
+ Dialog.Title,
452
+ {
453
+ ref,
454
+ className: cx("nuri-modal__title", visuallyHidden && "nuri-sr-only", className),
455
+ ...rest
456
+ }
457
+ );
458
+ });
459
+ var Description2 = forwardRef8(function ModalDescription({ className, ...rest }, ref) {
460
+ return /* @__PURE__ */ jsx9(Dialog.Description, { ref, className: cx("nuri-modal__description", className), ...rest });
461
+ });
462
+ var Body = forwardRef8(function ModalBody({ className, ...rest }, ref) {
463
+ return /* @__PURE__ */ jsx9("div", { ref, className: cx("nuri-modal__body", className), ...rest });
464
+ });
465
+ var Footer = forwardRef8(function ModalFooter({ align = "end", className, ...rest }, ref) {
466
+ return /* @__PURE__ */ jsx9(
467
+ "div",
468
+ {
469
+ ref,
470
+ className: cx("nuri-modal__footer", `nuri-modal__footer--${align}`, className),
471
+ ...rest
472
+ }
473
+ );
474
+ });
475
+ var Close2 = Dialog.Close;
476
+ var CloseIcon = () => /* @__PURE__ */ jsx9("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx9("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
477
+ var CloseButton = forwardRef8(function ModalCloseButton({ className, "aria-label": ariaLabel = "\uB2EB\uAE30", children, ...rest }, ref) {
478
+ return /* @__PURE__ */ jsx9(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx9(
479
+ "button",
480
+ {
481
+ ref,
482
+ type: "button",
483
+ "aria-label": ariaLabel,
484
+ className: cx("nuri-modal__close", className),
485
+ ...rest,
486
+ children: children ?? /* @__PURE__ */ jsx9(CloseIcon, {})
487
+ }
488
+ ) });
489
+ });
490
+ var Modal = Object.assign(Root6, {
491
+ Trigger: Trigger3,
492
+ Content: Content3,
493
+ Header,
494
+ Title: Title2,
495
+ Description: Description2,
496
+ Body,
497
+ Footer,
498
+ Close: Close2,
499
+ CloseButton
500
+ });
501
+
502
+ // src/AlertDialog/AlertDialog.tsx
503
+ import "./AlertDialog/styles.css";
504
+ import * as Alert from "@radix-ui/react-alert-dialog";
505
+ import { forwardRef as forwardRef9 } from "react";
506
+
507
+ // src/AlertDialog/icons.tsx
508
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
509
+ var SuccessIcon = () => /* @__PURE__ */ jsxs10("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
510
+ /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "12", fill: "var(--nuri-alert-tone-success-bg)" }),
511
+ /* @__PURE__ */ jsx10(
512
+ "path",
513
+ {
514
+ d: "M15.77 9.58L10.65 14.70L8.90 12.95",
515
+ stroke: "var(--nuri-alert-tone-success-fg)",
516
+ strokeWidth: "2.5",
517
+ strokeLinecap: "round",
518
+ strokeLinejoin: "round"
519
+ }
520
+ )
521
+ ] });
522
+ var WarningIcon = () => /* @__PURE__ */ jsxs10("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
523
+ /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "12", fill: "var(--nuri-alert-tone-warning-bg)" }),
524
+ /* @__PURE__ */ jsx10(
525
+ "path",
526
+ {
527
+ d: "M12 6.75V12",
528
+ stroke: "var(--nuri-alert-tone-warning-fg)",
529
+ strokeWidth: "2.5",
530
+ strokeLinecap: "round"
531
+ }
532
+ ),
533
+ /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "16.31", r: "1.1", fill: "var(--nuri-alert-tone-warning-fg)" })
534
+ ] });
535
+ var InfoIcon = () => /* @__PURE__ */ jsxs10("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
536
+ /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "12", fill: "var(--nuri-alert-tone-info-bg)" }),
537
+ /* @__PURE__ */ jsx10(
538
+ "path",
539
+ {
540
+ d: "M12.25 7h0.01",
541
+ stroke: "var(--nuri-alert-tone-info-fg)",
542
+ strokeWidth: "3",
543
+ strokeLinecap: "round",
544
+ strokeLinejoin: "round"
545
+ }
546
+ ),
547
+ /* @__PURE__ */ jsx10(
548
+ "path",
549
+ {
550
+ d: "M11 12h1.25v5h1.25",
551
+ stroke: "var(--nuri-alert-tone-info-fg)",
552
+ strokeWidth: "2.5",
553
+ strokeLinecap: "round",
554
+ strokeLinejoin: "round"
555
+ }
556
+ )
557
+ ] });
558
+ var defaultToneIcon = {
559
+ info: /* @__PURE__ */ jsx10(InfoIcon, {}),
560
+ success: /* @__PURE__ */ jsx10(SuccessIcon, {}),
561
+ warning: /* @__PURE__ */ jsx10(WarningIcon, {})
562
+ };
563
+
564
+ // src/AlertDialog/AlertDialog.tsx
565
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
566
+ var Root8 = (props) => /* @__PURE__ */ jsx11(Alert.Root, { ...props });
567
+ Root8.displayName = "AlertDialog";
568
+ var Trigger5 = Alert.Trigger;
569
+ var Content5 = forwardRef9(
570
+ function AlertDialogContent({ tone = "info", icon, overlay = true, container, className, children, ...rest }, ref) {
571
+ const resolvedIcon = icon === void 0 ? defaultToneIcon[tone] : icon;
572
+ return /* @__PURE__ */ jsxs11(Alert.Portal, { container, children: [
573
+ overlay && /* @__PURE__ */ jsx11(Alert.Overlay, { className: "nuri-alert__overlay" }),
574
+ /* @__PURE__ */ jsxs11(
575
+ Alert.Content,
576
+ {
577
+ ref,
578
+ className: cx("nuri-alert", `nuri-alert--${tone}`, className),
579
+ ...rest,
580
+ children: [
581
+ resolvedIcon != null && /* @__PURE__ */ jsx11("div", { className: "nuri-alert__icon", "aria-hidden": "true", children: resolvedIcon }),
582
+ children
583
+ ]
584
+ }
585
+ )
586
+ ] });
587
+ }
588
+ );
589
+ var Header2 = forwardRef9(
590
+ function AlertDialogHeader({ className, ...rest }, ref) {
591
+ return /* @__PURE__ */ jsx11("div", { ref, className: cx("nuri-alert__header", className), ...rest });
592
+ }
593
+ );
594
+ var Title4 = forwardRef9(function AlertDialogTitle({ className, ...rest }, ref) {
595
+ return /* @__PURE__ */ jsx11(Alert.Title, { ref, className: cx("nuri-alert__title", className), ...rest });
596
+ });
597
+ var Description4 = forwardRef9(function AlertDialogDescription({ className, ...rest }, ref) {
598
+ return /* @__PURE__ */ jsx11(Alert.Description, { ref, className: cx("nuri-alert__description", className), ...rest });
599
+ });
600
+ var Body2 = forwardRef9(function AlertDialogBody({ className, ...rest }, ref) {
601
+ return /* @__PURE__ */ jsx11("div", { ref, className: cx("nuri-alert__body", className), ...rest });
602
+ });
603
+ var Footer2 = forwardRef9(function AlertDialogFooter({ align = "full", className, ...rest }, ref) {
604
+ return /* @__PURE__ */ jsx11(
605
+ "div",
606
+ {
607
+ ref,
608
+ className: cx("nuri-alert__footer", `nuri-alert__footer--${align}`, className),
609
+ ...rest
610
+ }
611
+ );
612
+ });
613
+ var Action2 = Alert.Action;
614
+ var Cancel2 = Alert.Cancel;
615
+ var CloseIcon2 = () => /* @__PURE__ */ jsx11("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx11("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
616
+ var CloseButton2 = forwardRef9(function AlertDialogCloseButton({ className, "aria-label": ariaLabel = "\uB2EB\uAE30", children, ...rest }, ref) {
617
+ return /* @__PURE__ */ jsx11(Alert.Cancel, { asChild: true, children: /* @__PURE__ */ jsx11(
618
+ "button",
619
+ {
620
+ ref,
621
+ type: "button",
622
+ "aria-label": ariaLabel,
623
+ className: cx("nuri-alert__close", className),
624
+ ...rest,
625
+ children: children ?? /* @__PURE__ */ jsx11(CloseIcon2, {})
626
+ }
627
+ ) });
628
+ });
629
+ var AlertDialog = Object.assign(Root8, {
630
+ Trigger: Trigger5,
631
+ Content: Content5,
632
+ Header: Header2,
633
+ Title: Title4,
634
+ Description: Description4,
635
+ Body: Body2,
636
+ Footer: Footer2,
637
+ Action: Action2,
638
+ Cancel: Cancel2,
639
+ CloseButton: CloseButton2
640
+ });
641
+
642
+ // src/Toast/Toaster.tsx
643
+ import "./Toast/styles.css";
644
+ import * as RadixToast from "@radix-ui/react-toast";
645
+
646
+ // src/Toast/store.ts
647
+ import { useSyncExternalStore } from "react";
648
+ var toasts = [];
649
+ var listeners = /* @__PURE__ */ new Set();
650
+ var EMPTY = [];
651
+ var counter = 0;
652
+ var emit = () => {
653
+ for (const l of listeners) l();
654
+ };
655
+ function add(message, options = {}) {
656
+ const id = options.id ?? `nuri-toast-${++counter}`;
657
+ const record = {
658
+ id,
659
+ message,
660
+ tone: options.tone ?? "default",
661
+ duration: options.duration ?? 3e3
662
+ };
663
+ const idx = toasts.findIndex((t) => t.id === id);
664
+ toasts = idx >= 0 ? toasts.map((t) => t.id === id ? record : t) : [...toasts, record];
665
+ emit();
666
+ return id;
667
+ }
668
+ function remove(id) {
669
+ toasts = toasts.filter((t) => t.id !== id);
670
+ emit();
671
+ }
672
+ function clear() {
673
+ toasts = [];
674
+ emit();
675
+ }
676
+ var toastStore = {
677
+ add,
678
+ remove,
679
+ clear,
680
+ subscribe(listener) {
681
+ listeners.add(listener);
682
+ return () => {
683
+ listeners.delete(listener);
684
+ };
685
+ },
686
+ getSnapshot: () => toasts,
687
+ getServerSnapshot: () => EMPTY
688
+ };
689
+ function useToasts() {
690
+ return useSyncExternalStore(
691
+ toastStore.subscribe,
692
+ toastStore.getSnapshot,
693
+ toastStore.getServerSnapshot
694
+ );
695
+ }
696
+
697
+ // src/Toast/icons.tsx
698
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
699
+ var CheckIcon2 = () => /* @__PURE__ */ jsx12("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx12(
700
+ "path",
701
+ {
702
+ d: "M3.5 8.5l3 3 6-6.5",
703
+ stroke: "currentColor",
704
+ strokeWidth: "1.6",
705
+ strokeLinecap: "round",
706
+ strokeLinejoin: "round"
707
+ }
708
+ ) });
709
+ var ErrorIcon = () => /* @__PURE__ */ jsxs12("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
710
+ /* @__PURE__ */ jsx12("path", { d: "M8 4v4.5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
711
+ /* @__PURE__ */ jsx12("circle", { cx: "8", cy: "11.3", r: "0.95", fill: "currentColor" })
712
+ ] });
713
+ var InfoIcon2 = () => /* @__PURE__ */ jsxs12("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
714
+ /* @__PURE__ */ jsx12("path", { d: "M8 7.5v4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
715
+ /* @__PURE__ */ jsx12("circle", { cx: "8", cy: "4.7", r: "0.95", fill: "currentColor" })
716
+ ] });
717
+ var toneIcon = {
718
+ success: /* @__PURE__ */ jsx12(CheckIcon2, {}),
719
+ error: /* @__PURE__ */ jsx12(ErrorIcon, {}),
720
+ info: /* @__PURE__ */ jsx12(InfoIcon2, {})
721
+ };
722
+
723
+ // src/Toast/Toaster.tsx
724
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
725
+ function Toaster({
726
+ swipeDirection = "down",
727
+ swipeThreshold = 50,
728
+ className,
729
+ label = "\uC54C\uB9BC"
730
+ }) {
731
+ const toasts2 = useToasts();
732
+ return /* @__PURE__ */ jsxs13(
733
+ RadixToast.Provider,
734
+ {
735
+ swipeDirection,
736
+ swipeThreshold,
737
+ label,
738
+ children: [
739
+ toasts2.map((t) => /* @__PURE__ */ jsxs13(
740
+ RadixToast.Root,
741
+ {
742
+ duration: t.duration,
743
+ onOpenChange: (open) => {
744
+ if (!open) toastStore.remove(t.id);
745
+ },
746
+ type: t.tone === "error" ? "foreground" : "background",
747
+ className: cx("nuri-toast", t.tone !== "default" && `nuri-toast--${t.tone}`),
748
+ children: [
749
+ t.tone !== "default" && /* @__PURE__ */ jsx13("span", { className: "nuri-toast__icon", "aria-hidden": "true", children: toneIcon[t.tone] }),
750
+ /* @__PURE__ */ jsx13(RadixToast.Title, { className: "nuri-toast__message", children: t.message })
751
+ ]
752
+ },
753
+ t.id
754
+ )),
755
+ /* @__PURE__ */ jsx13(
756
+ RadixToast.Viewport,
757
+ {
758
+ className: cx("nuri-toast__viewport", className),
759
+ label: `${label} ({hotkey})`
760
+ }
761
+ )
762
+ ]
763
+ }
764
+ );
765
+ }
766
+
767
+ // src/Toast/toast.ts
768
+ function toastFn(message, options) {
769
+ return toastStore.add(message, options);
770
+ }
771
+ var toast = Object.assign(toastFn, {
772
+ success: (message, options) => toastStore.add(message, { ...options, tone: "success" }),
773
+ error: (message, options) => toastStore.add(message, { ...options, tone: "error" }),
774
+ info: (message, options) => toastStore.add(message, { ...options, tone: "info" }),
775
+ /** id 지정 시 해당 토스트만, 없으면 전체 제거. */
776
+ dismiss: (id) => id ? toastStore.remove(id) : toastStore.clear()
777
+ });
778
+
779
+ // src/Tooltip/Tooltip.tsx
780
+ import "./Tooltip/styles.css";
781
+ import * as RadixTooltip from "@radix-ui/react-tooltip";
782
+ import { createContext, useContext } from "react";
783
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
784
+ var HasProviderContext = createContext(false);
785
+ function TooltipProvider({ children, ...props }) {
786
+ return /* @__PURE__ */ jsx14(HasProviderContext.Provider, { value: true, children: /* @__PURE__ */ jsx14(RadixTooltip.Provider, { ...props, children }) });
787
+ }
788
+ function Tooltip({
789
+ content,
790
+ children,
791
+ side = "top",
792
+ align = "center",
793
+ arrow = true,
794
+ delayDuration,
795
+ open,
796
+ defaultOpen,
797
+ onOpenChange,
798
+ disabled = false,
799
+ container,
800
+ className
801
+ }) {
802
+ const hasProvider = useContext(HasProviderContext);
803
+ if (disabled) return children;
804
+ const root = /* @__PURE__ */ jsxs14(
805
+ RadixTooltip.Root,
806
+ {
807
+ open,
808
+ defaultOpen,
809
+ onOpenChange,
810
+ delayDuration,
811
+ children: [
812
+ /* @__PURE__ */ jsx14(RadixTooltip.Trigger, { asChild: true, children }),
813
+ /* @__PURE__ */ jsx14(RadixTooltip.Portal, { container, children: /* @__PURE__ */ jsxs14(
814
+ RadixTooltip.Content,
815
+ {
816
+ className: cx("nuri-tooltip", className),
817
+ side,
818
+ align,
819
+ sideOffset: 4,
820
+ collisionPadding: 8,
821
+ arrowPadding: 6,
822
+ hideWhenDetached: true,
823
+ children: [
824
+ content,
825
+ arrow && /* @__PURE__ */ jsx14(RadixTooltip.Arrow, { className: "nuri-tooltip__arrow", width: 14, height: 7 })
826
+ ]
827
+ }
828
+ ) })
829
+ ]
830
+ }
831
+ );
832
+ return hasProvider ? root : /* @__PURE__ */ jsx14(RadixTooltip.Provider, { delayDuration: 100, children: root });
833
+ }
834
+ export {
835
+ AlertDialog,
836
+ Button,
837
+ Checkbox,
838
+ Input,
839
+ Modal,
840
+ Radio,
841
+ RadioGroup,
842
+ Select,
843
+ Switch,
844
+ Textarea,
845
+ Toaster,
846
+ Tooltip,
847
+ TooltipProvider,
848
+ toast
849
+ };
850
+ //# sourceMappingURL=index.js.map