@nurimedia/react-ui 0.1.1 → 0.1.2
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/dist/AlertDialog/index.cjs +4 -181
- package/dist/AlertDialog/index.cjs.map +1 -1
- package/dist/AlertDialog/index.js +4 -145
- package/dist/AlertDialog/index.js.map +1 -1
- package/dist/Button/index.cjs +4 -132
- package/dist/Button/index.cjs.map +1 -1
- package/dist/Button/index.js +4 -106
- package/dist/Button/index.js.map +1 -1
- package/dist/Checkbox/index.cjs +4 -79
- package/dist/Checkbox/index.cjs.map +1 -1
- package/dist/Checkbox/index.js +4 -43
- package/dist/Checkbox/index.js.map +1 -1
- package/dist/Input/index.cjs +4 -99
- package/dist/Input/index.cjs.map +1 -1
- package/dist/Input/index.js +4 -73
- package/dist/Input/index.js.map +1 -1
- package/dist/Modal/index.cjs +4 -116
- package/dist/Modal/index.cjs.map +1 -1
- package/dist/Modal/index.js +4 -80
- package/dist/Modal/index.js.map +1 -1
- package/dist/Radio/index.cjs +6 -82
- package/dist/Radio/index.cjs.map +1 -1
- package/dist/Radio/index.js +5 -44
- package/dist/Radio/index.js.map +1 -1
- package/dist/Select/index.cjs +4 -112
- package/dist/Select/index.cjs.map +1 -1
- package/dist/Select/index.js +4 -76
- package/dist/Select/index.js.map +1 -1
- package/dist/Switch/index.cjs +4 -67
- package/dist/Switch/index.cjs.map +1 -1
- package/dist/Switch/index.js +4 -31
- package/dist/Switch/index.js.map +1 -1
- package/dist/Textarea/index.cjs +4 -123
- package/dist/Textarea/index.cjs.map +1 -1
- package/dist/Textarea/index.js +4 -97
- package/dist/Textarea/index.js.map +1 -1
- package/dist/Toast/index.cjs +4 -178
- package/dist/Toast/index.cjs.map +1 -1
- package/dist/Toast/index.js +5 -142
- package/dist/Toast/index.js.map +1 -1
- package/dist/Tooltip/index.cjs +6 -101
- package/dist/Tooltip/index.cjs.map +1 -1
- package/dist/Tooltip/index.js +5 -63
- package/dist/Tooltip/index.js.map +1 -1
- package/dist/chunk-2LFW4MM6.cjs +47 -0
- package/dist/chunk-2LFW4MM6.cjs.map +1 -0
- package/dist/chunk-2WKLA5RC.cjs +82 -0
- package/dist/chunk-2WKLA5RC.cjs.map +1 -0
- package/dist/chunk-2YGYLCCA.js +66 -0
- package/dist/chunk-2YGYLCCA.js.map +1 -0
- package/dist/chunk-323VGYMK.cjs +147 -0
- package/dist/chunk-323VGYMK.cjs.map +1 -0
- package/dist/chunk-3H47QMKS.js +47 -0
- package/dist/chunk-3H47QMKS.js.map +1 -0
- package/dist/chunk-3QSLHLC2.cjs +45 -0
- package/dist/chunk-3QSLHLC2.cjs.map +1 -0
- package/dist/chunk-4N5JIGIU.js +82 -0
- package/dist/chunk-4N5JIGIU.js.map +1 -0
- package/dist/chunk-DTGPVOJK.js +99 -0
- package/dist/chunk-DTGPVOJK.js.map +1 -0
- package/dist/chunk-DTQE42F7.js +33 -0
- package/dist/chunk-DTQE42F7.js.map +1 -0
- package/dist/chunk-DYO4PIBB.js +75 -0
- package/dist/chunk-DYO4PIBB.js.map +1 -0
- package/dist/chunk-GBMYANHH.js +149 -0
- package/dist/chunk-GBMYANHH.js.map +1 -0
- package/dist/chunk-I7KJ7WTN.cjs +149 -0
- package/dist/chunk-I7KJ7WTN.cjs.map +1 -0
- package/dist/chunk-JM4HDCLU.cjs +110 -0
- package/dist/chunk-JM4HDCLU.cjs.map +1 -0
- package/dist/chunk-JXJ6G634.cjs +75 -0
- package/dist/chunk-JXJ6G634.cjs.map +1 -0
- package/dist/chunk-LAPTEQ5N.js +45 -0
- package/dist/chunk-LAPTEQ5N.js.map +1 -0
- package/dist/chunk-LRATCHCB.cjs +66 -0
- package/dist/chunk-LRATCHCB.cjs.map +1 -0
- package/dist/chunk-OM4QMC4F.js +110 -0
- package/dist/chunk-OM4QMC4F.js.map +1 -0
- package/dist/chunk-PAXRFQUJ.cjs +33 -0
- package/dist/chunk-PAXRFQUJ.cjs.map +1 -0
- package/dist/chunk-PC3B67B4.cjs +78 -0
- package/dist/chunk-PC3B67B4.cjs.map +1 -0
- package/dist/chunk-PS6QXS5Z.js +11 -0
- package/dist/chunk-PS6QXS5Z.js.map +1 -0
- package/dist/chunk-Q26BJSLP.cjs +99 -0
- package/dist/chunk-Q26BJSLP.cjs.map +1 -0
- package/dist/chunk-R4E4BIPC.cjs +11 -0
- package/dist/chunk-R4E4BIPC.cjs.map +1 -0
- package/dist/chunk-R757N7RU.js +78 -0
- package/dist/chunk-R757N7RU.js.map +1 -0
- package/dist/chunk-RC773ZEY.js +147 -0
- package/dist/chunk-RC773ZEY.js.map +1 -0
- package/dist/index.cjs +54 -900
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +37 -834
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkR4E4BIPCcjs = require('./chunk-R4E4BIPC.cjs');
|
|
5
|
+
|
|
6
|
+
// src/Radio/Radio.tsx
|
|
7
|
+
require('./Radio/styles.css');
|
|
8
|
+
var _reactradiogroup = require('@radix-ui/react-radio-group'); var RadixRadioGroup = _interopRequireWildcard(_reactradiogroup);
|
|
9
|
+
var _react = require('react');
|
|
10
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
11
|
+
var RadioGroup = _react.forwardRef.call(void 0, function RadioGroup2({ children, orientation = "vertical", className, ...rest }, ref) {
|
|
12
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
13
|
+
RadixRadioGroup.Root,
|
|
14
|
+
{
|
|
15
|
+
ref,
|
|
16
|
+
orientation,
|
|
17
|
+
className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-radio-group", `nuri-radio-group--${orientation}`, className),
|
|
18
|
+
...rest,
|
|
19
|
+
children
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
var Radio = _react.forwardRef.call(void 0, function Radio2({ value, label, disabled = false, id: idProp, className, ...rest }, ref) {
|
|
24
|
+
const reactId = _react.useId.call(void 0, );
|
|
25
|
+
const id = _nullishCoalesce(idProp, () => ( `nuri-radio-${reactId}`));
|
|
26
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-radio", className), children: [
|
|
27
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
28
|
+
RadixRadioGroup.Item,
|
|
29
|
+
{
|
|
30
|
+
ref,
|
|
31
|
+
id,
|
|
32
|
+
value,
|
|
33
|
+
disabled,
|
|
34
|
+
className: "nuri-radio__control",
|
|
35
|
+
...rest,
|
|
36
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RadixRadioGroup.Indicator, { className: "nuri-radio__indicator" })
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
label != null && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { htmlFor: id, className: "nuri-radio__label", children: label })
|
|
40
|
+
] });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
exports.RadioGroup = RadioGroup; exports.Radio = Radio;
|
|
47
|
+
//# sourceMappingURL=chunk-2LFW4MM6.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-2LFW4MM6.cjs","../src/Radio/Radio.tsx"],"names":["RadioGroup"],"mappings":"AAAA,2cAAY;AACZ;AACE;AACF,wDAA6B;AAC7B;AACA;ACHA,8BAAO;AACP,+HAAiC;AACjC,8BAAkC;AAsC9B,+CAAA;AALG,IAAM,WAAA,EAAa,+BAAA,SAAqDA,WAAAA,CAC7E,EAAE,QAAA,EAAU,YAAA,EAAc,UAAA,EAAY,SAAA,EAAW,GAAG,KAAK,CAAA,EACzD,GAAA,EACA;AACA,EAAA,uBACE,6BAAA;AAAA,IAAiB,eAAA,CAAA,IAAA;AAAA,IAAhB;AAAA,MACC,GAAA;AAAA,MACA,WAAA;AAAA,MACA,SAAA,EAAW,kCAAA,kBAAG,EAAoB,CAAA,kBAAA,EAAqB,WAAW,CAAA,CAAA;AAC9D,MAAA;AAEH,MAAA;AAAA,IAAA;AACH,EAAA;AAEH;AAemC;AAGZ,EAAA;AACoB,EAAA;AAGP,EAAA;AAC/B,oBAAA;AAAiB,MAAA;AAAhB,MAAA;AACC,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACU,QAAA;AACN,QAAA;AAEuB,QAAA;AAAkC,MAAA;AAC/D,IAAA;AAEsB,IAAA;AAIxB,EAAA;AAEH;ADlDwE;AACA;AACA;AACA;AACA","file":"/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-2LFW4MM6.cjs","sourcesContent":[null,"'use client';\n\nimport './styles.css';\nimport * as RadixRadioGroup from '@radix-ui/react-radio-group';\nimport { forwardRef, useId } from 'react';\nimport type { ReactNode } from 'react';\nimport { cx } from '../utils/cx.js';\n\nexport interface RadioGroupProps {\n children: ReactNode;\n /** 선택된 값 (제어형). */\n value?: string;\n /** 초기 값 (비제어형). */\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n /** 배치 방향 — 키보드 화살표 탐색 방향에도 반영됨. @default 'vertical' */\n orientation?: 'vertical' | 'horizontal';\n disabled?: boolean;\n /** 폼 전송용 name. */\n name?: string;\n required?: boolean;\n className?: string;\n /** 그룹의 접근 가능한 이름 (시각 제목이 없을 때 필수). */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n/**\n * 라디오 그룹. Radix RadioGroup 기반 — 화살표 키 그룹 탐색·단일 선택·폼 참여 자동.\n * 그룹에 `aria-label`(또는 aria-labelledby)을 지정한다.\n *\n * @example\n * <RadioGroup aria-label=\"정렬\" value={sort} onValueChange={setSort}>\n * <Radio value=\"latest\" label=\"최신순\" />\n * <Radio value=\"edited\" label=\"수정순\" />\n * </RadioGroup>\n */\nexport const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(function RadioGroup(\n { children, orientation = 'vertical', className, ...rest },\n ref,\n) {\n return (\n <RadixRadioGroup.Root\n ref={ref}\n orientation={orientation}\n className={cx('nuri-radio-group', `nuri-radio-group--${orientation}`, className)}\n {...rest}\n >\n {children}\n </RadixRadioGroup.Root>\n );\n});\n\nexport interface RadioProps {\n /** 이 항목이 나타내는 값. */\n value: string;\n /** 라벨 (컨트롤 우측). 없으면 `aria-label` 필수. */\n label?: ReactNode;\n disabled?: boolean;\n id?: string;\n className?: string;\n 'aria-label'?: string;\n}\n\n/** 라디오 항목 — 반드시 RadioGroup 안에서 사용. */\nexport const Radio = forwardRef<HTMLButtonElement, RadioProps>(function Radio(\n { value, label, disabled = false, id: idProp, className, ...rest },\n ref,\n) {\n const reactId = useId();\n const id = idProp ?? `nuri-radio-${reactId}`;\n\n return (\n <div className={cx('nuri-radio', className)}>\n <RadixRadioGroup.Item\n ref={ref}\n id={id}\n value={value}\n disabled={disabled}\n className=\"nuri-radio__control\"\n {...rest}\n >\n <RadixRadioGroup.Indicator className=\"nuri-radio__indicator\" />\n </RadixRadioGroup.Item>\n {label != null && (\n <label htmlFor={id} className=\"nuri-radio__label\">\n {label}\n </label>\n )}\n </div>\n );\n});\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkR4E4BIPCcjs = require('./chunk-R4E4BIPC.cjs');
|
|
5
|
+
|
|
6
|
+
// src/Modal/Modal.tsx
|
|
7
|
+
require('./Modal/styles.css');
|
|
8
|
+
var _reactdialog = require('@radix-ui/react-dialog'); var Dialog = _interopRequireWildcard(_reactdialog);
|
|
9
|
+
var _react = require('react');
|
|
10
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
11
|
+
var Root2 = (props) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Dialog.Root, { ...props });
|
|
12
|
+
Root2.displayName = "Modal";
|
|
13
|
+
var Trigger2 = Dialog.Trigger;
|
|
14
|
+
var Content2 = _react.forwardRef.call(void 0,
|
|
15
|
+
function ModalContent({ placement = "center", size = "md", overlay = true, container, className, children, ...rest }, ref) {
|
|
16
|
+
const classes = _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal", `nuri-modal--${placement}`, `nuri-modal--${size}`, className);
|
|
17
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, Dialog.Portal, { container, children: [
|
|
18
|
+
overlay && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Dialog.Overlay, { className: "nuri-modal__overlay" }),
|
|
19
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, Dialog.Content, { ref, className: classes, ...rest, children })
|
|
20
|
+
] });
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
var Header = _react.forwardRef.call(void 0, function ModalHeader({ className, ...rest }, ref) {
|
|
24
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref, className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal__header", className), ...rest });
|
|
25
|
+
});
|
|
26
|
+
var Title2 = _react.forwardRef.call(void 0, function ModalTitle({ visuallyHidden = false, className, ...rest }, ref) {
|
|
27
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
28
|
+
Dialog.Title,
|
|
29
|
+
{
|
|
30
|
+
ref,
|
|
31
|
+
className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal__title", visuallyHidden && "nuri-sr-only", className),
|
|
32
|
+
...rest
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
var Description2 = _react.forwardRef.call(void 0, function ModalDescription({ className, ...rest }, ref) {
|
|
37
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Dialog.Description, { ref, className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal__description", className), ...rest });
|
|
38
|
+
});
|
|
39
|
+
var Body = _react.forwardRef.call(void 0, function ModalBody({ className, ...rest }, ref) {
|
|
40
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { ref, className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal__body", className), ...rest });
|
|
41
|
+
});
|
|
42
|
+
var Footer = _react.forwardRef.call(void 0, function ModalFooter({ align = "end", className, ...rest }, ref) {
|
|
43
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
44
|
+
"div",
|
|
45
|
+
{
|
|
46
|
+
ref,
|
|
47
|
+
className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal__footer", `nuri-modal__footer--${align}`, className),
|
|
48
|
+
...rest
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
var Close2 = Dialog.Close;
|
|
53
|
+
var CloseIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
|
|
54
|
+
var CloseButton = _react.forwardRef.call(void 0, function ModalCloseButton({ className, "aria-label": ariaLabel = "\uB2EB\uAE30", children, ...rest }, ref) {
|
|
55
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Dialog.Close, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
56
|
+
"button",
|
|
57
|
+
{
|
|
58
|
+
ref,
|
|
59
|
+
type: "button",
|
|
60
|
+
"aria-label": ariaLabel,
|
|
61
|
+
className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-modal__close", className),
|
|
62
|
+
...rest,
|
|
63
|
+
children: _nullishCoalesce(children, () => ( /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CloseIcon, {})))
|
|
64
|
+
}
|
|
65
|
+
) });
|
|
66
|
+
});
|
|
67
|
+
var Modal = Object.assign(Root2, {
|
|
68
|
+
Trigger: Trigger2,
|
|
69
|
+
Content: Content2,
|
|
70
|
+
Header,
|
|
71
|
+
Title: Title2,
|
|
72
|
+
Description: Description2,
|
|
73
|
+
Body,
|
|
74
|
+
Footer,
|
|
75
|
+
Close: Close2,
|
|
76
|
+
CloseButton
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
exports.Modal = Modal;
|
|
82
|
+
//# sourceMappingURL=chunk-2WKLA5RC.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-2WKLA5RC.cjs","../src/Modal/Modal.tsx"],"names":["Root","Trigger","Content","Title","Description","Close"],"mappings":"AAAA,2cAAY;AACZ;AACE;AACF,wDAA6B;AAC7B;AACA;ACHA,8BAAO;AACP,yGAAwB;AACxB,8BAA2B;AAsB2C,+CAAA;AAAtE,IAAMA,MAAAA,EAAO,CAAC,KAAA,EAAA,mBAAwD,6BAAA,MAAQ,CAAA,IAAA,EAAP,EAAa,GAAG,MAAA,CAAO,CAAA;AAC9FA,KAAAA,CAAK,YAAA,EAAc,OAAA;AAGnB,IAAMC,SAAAA,EAAiB,MAAA,CAAA,OAAA;AAyBvB,IAAMC,SAAAA,EAAU,+BAAA;AAAA,EACd,SAAS,YAAA,CACP,EAAE,UAAA,EAAY,QAAA,EAAU,KAAA,EAAO,IAAA,EAAM,QAAA,EAAU,IAAA,EAAM,SAAA,EAAW,SAAA,EAAW,QAAA,EAAU,GAAG,KAAK,CAAA,EAC7F,GAAA,EACA;AACA,IAAA,MAAM,QAAA,EAAU,kCAAA,YAAG,EAAc,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA;AAIpD,IAAA;AAA2B,MAAA;AACS,sBAAA;AAGvC,IAAA;AAEJ,EAAA;AACF;AAIkB;AAGoB,EAAA;AACrC;AAaG;AAIA,EAAA;AAAQ,IAAA;AAAP,IAAA;AACC,MAAA;AACqD,MAAA;AACjD,MAAA;AAAA,IAAA;AACN,EAAA;AAEH;AAM6B;AAEI,EAAA;AAEjC;AAIsB;AAGe,EAAA;AACrC;AAiBkB;AAIf,EAAA;AAAC,IAAA;AAAA,IAAA;AACC,MAAA;AACoC,MAAA;AAChC,MAAA;AAAA,IAAA;AACN,EAAA;AAEH;AAMoB;AAGR;AAUT;AAKE,EAAA;AAAC,IAAA;AAAA,IAAA;AACC,MAAA;AACK,MAAA;AACO,MAAA;AACgC,MAAA;AACxC,MAAA;AAEoB,MAAA;AAAA,IAAA;AAE5B,EAAA;AAEH;AAEwC;AACvCD,EAAAA;AACAC,EAAAA;AACA,EAAA;AACAC,EAAAA;AACAC,EAAAA;AACA,EAAA;AACA,EAAA;AACAC,EAAAA;AACA,EAAA;AACD;ADrH6D;AACA;AACA;AACA","file":"/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-2WKLA5RC.cjs","sourcesContent":[null,"'use client';\n\nimport './styles.css';\nimport * as Dialog from '@radix-ui/react-dialog';\nimport { forwardRef } from 'react';\nimport type { ComponentPropsWithoutRef, ElementRef, ReactNode } from 'react';\nimport { cx } from '../utils/cx.js';\n\ntype Placement = 'center' | 'bottom';\ntype Size = 'sm' | 'md' | 'lg';\n\n/**\n * 모달 루트. open/onOpenChange로 제어하거나, Modal.Trigger와 함께 비제어로도 사용.\n * Radix Dialog 기반 — 포커스 트랩·Esc·스크롤 락·포커스 복귀·aria 연결을 자동 제공.\n *\n * @example 제어형\n * <Modal open={open} onOpenChange={setOpen}>\n * <Modal.Content>...</Modal.Content>\n * </Modal>\n *\n * @example 비제어 (트리거)\n * <Modal>\n * <Modal.Trigger asChild><Button>열기</Button></Modal.Trigger>\n * <Modal.Content>...</Modal.Content>\n * </Modal>\n */\nconst Root = (props: ComponentPropsWithoutRef<typeof Dialog.Root>) => <Dialog.Root {...props} />;\nRoot.displayName = 'Modal';\n\n/** 모달을 여는 트리거. `asChild`로 임의 엘리먼트(Button 등)에 위임. */\nconst Trigger = Dialog.Trigger;\n\nexport interface ModalContentProps extends ComponentPropsWithoutRef<typeof Dialog.Content> {\n /**\n * 표시 위치.\n * - `center`: 화면 중앙 다이얼로그 (기본)\n * - `bottom`: 하단 바텀시트 (모바일에서 아래에서 올라옴)\n * @default 'center'\n */\n placement?: Placement;\n /**\n * 최대 너비. **`placement=\"center\"`에서만 적용** (bottom 바텀시트는 항상 풀 width).\n * @default 'md'\n */\n size?: Size;\n /** 백드롭(오버레이) 표시 여부. @default true */\n overlay?: boolean;\n /** 포털 렌더 대상. 기본은 document.body. 다른 요소에 렌더하려면 지정. */\n container?: HTMLElement | null;\n}\n\n/**\n * 오버레이 + 포털 + 다이얼로그 패널을 한 번에 렌더.\n * 내부에 Modal.Header / Modal.Body / Modal.Footer를 자유롭게 합성.\n */\nconst Content = forwardRef<ElementRef<typeof Dialog.Content>, ModalContentProps>(\n function ModalContent(\n { placement = 'center', size = 'md', overlay = true, container, className, children, ...rest },\n ref,\n ) {\n const classes = cx('nuri-modal', `nuri-modal--${placement}`, `nuri-modal--${size}`, className);\n\n return (\n <Dialog.Portal container={container}>\n {overlay && <Dialog.Overlay className=\"nuri-modal__overlay\" />}\n <Dialog.Content ref={ref} className={classes} {...rest}>\n {children}\n </Dialog.Content>\n </Dialog.Portal>\n );\n },\n);\n\n/** 헤더 영역 (Title/Description/CloseButton을 담는 레이아웃 슬롯). */\nconst Header = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(function ModalHeader(\n { className, ...rest },\n ref,\n) {\n return <div ref={ref} className={cx('nuri-modal__header', className)} {...rest} />;\n});\n\nexport interface ModalTitleProps extends ComponentPropsWithoutRef<typeof Dialog.Title> {\n /**\n * 시각적으로는 숨기되 스크린리더에는 노출. 시각적 제목이 없는 모달도\n * 접근 가능한 이름을 가져야 하므로(Radix Dialog는 Title 필수), 이 옵션으로 처리.\n * @example <Modal.Title visuallyHidden>이미지 미리보기</Modal.Title>\n */\n visuallyHidden?: boolean;\n}\n\n/** 모달 제목. 렌더 시 자동으로 `aria-labelledby`로 연결됨 (Radix Dialog.Title). */\nconst Title = forwardRef<ElementRef<typeof Dialog.Title>, ModalTitleProps>(function ModalTitle(\n { visuallyHidden = false, className, ...rest },\n ref,\n) {\n return (\n <Dialog.Title\n ref={ref}\n className={cx('nuri-modal__title', visuallyHidden && 'nuri-sr-only', className)}\n {...rest}\n />\n );\n});\n\n/** 모달 설명. 렌더 시 자동으로 `aria-describedby`로 연결됨 (Radix Dialog.Description). */\nconst Description = forwardRef<\n ElementRef<typeof Dialog.Description>,\n ComponentPropsWithoutRef<typeof Dialog.Description>\n>(function ModalDescription({ className, ...rest }, ref) {\n return (\n <Dialog.Description ref={ref} className={cx('nuri-modal__description', className)} {...rest} />\n );\n});\n\n/** 본문 영역 (스크롤 가능). */\nconst Body = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(function ModalBody(\n { className, ...rest },\n ref,\n) {\n return <div ref={ref} className={cx('nuri-modal__body', className)} {...rest} />;\n});\n\nexport interface ModalFooterProps extends ComponentPropsWithoutRef<'div'> {\n /**\n * 액션 버튼 정렬.\n * - `end`: 우측 (기본, 데스크탑 관례)\n * - `start`: 좌측\n * - `center`: 가운데\n * - `between`: 양끝 분산 (예: 좌측 위험 액션 + 우측 확인)\n * - `full`: 버튼들이 가로를 균등하게 채움 (모바일 전체너비)\n * @default 'end'\n */\n align?: 'start' | 'center' | 'end' | 'between' | 'full';\n}\n\n/** 푸터 영역 (액션 버튼 배치). 정렬은 `align` prop으로 제어. */\nconst Footer = forwardRef<HTMLDivElement, ModalFooterProps>(function ModalFooter(\n { align = 'end', className, ...rest },\n ref,\n) {\n return (\n <div\n ref={ref}\n className={cx('nuri-modal__footer', `nuri-modal__footer--${align}`, className)}\n {...rest}\n />\n );\n});\n\n/**\n * 모달을 닫는 액션. `asChild`로 임의 엘리먼트에 위임.\n * @example <Modal.Close asChild><Button variant=\"outline\">취소</Button></Modal.Close>\n */\nconst Close = Dialog.Close;\n\nconst CloseIcon = () => (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M5 5l10 10M15 5L5 15\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n);\n\n/** 우상단 X 닫기 버튼 (미리 스타일링됨). 기본 `aria-label=\"닫기\"`. */\nconst CloseButton = forwardRef<\n HTMLButtonElement,\n Omit<ComponentPropsWithoutRef<'button'>, 'children'> & { children?: ReactNode }\n>(function ModalCloseButton(\n { className, 'aria-label': ariaLabel = '닫기', children, ...rest },\n ref,\n) {\n return (\n <Dialog.Close asChild>\n <button\n ref={ref}\n type=\"button\"\n aria-label={ariaLabel}\n className={cx('nuri-modal__close', className)}\n {...rest}\n >\n {children ?? <CloseIcon />}\n </button>\n </Dialog.Close>\n );\n});\n\nexport const Modal = Object.assign(Root, {\n Trigger,\n Content,\n Header,\n Title,\n Description,\n Body,\n Footer,\n Close,\n CloseButton,\n});\n"]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
cx
|
|
4
|
+
} from "./chunk-PS6QXS5Z.js";
|
|
5
|
+
|
|
6
|
+
// src/Tooltip/Tooltip.tsx
|
|
7
|
+
import "./Tooltip/styles.css";
|
|
8
|
+
import * as RadixTooltip from "@radix-ui/react-tooltip";
|
|
9
|
+
import { createContext, useContext } from "react";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var HasProviderContext = createContext(false);
|
|
12
|
+
function TooltipProvider({ children, ...props }) {
|
|
13
|
+
return /* @__PURE__ */ jsx(HasProviderContext.Provider, { value: true, children: /* @__PURE__ */ jsx(RadixTooltip.Provider, { ...props, children }) });
|
|
14
|
+
}
|
|
15
|
+
function Tooltip({
|
|
16
|
+
content,
|
|
17
|
+
children,
|
|
18
|
+
side = "top",
|
|
19
|
+
align = "center",
|
|
20
|
+
arrow = true,
|
|
21
|
+
delayDuration,
|
|
22
|
+
open,
|
|
23
|
+
defaultOpen,
|
|
24
|
+
onOpenChange,
|
|
25
|
+
disabled = false,
|
|
26
|
+
container,
|
|
27
|
+
className
|
|
28
|
+
}) {
|
|
29
|
+
const hasProvider = useContext(HasProviderContext);
|
|
30
|
+
if (disabled) return children;
|
|
31
|
+
const root = /* @__PURE__ */ jsxs(
|
|
32
|
+
RadixTooltip.Root,
|
|
33
|
+
{
|
|
34
|
+
open,
|
|
35
|
+
defaultOpen,
|
|
36
|
+
onOpenChange,
|
|
37
|
+
delayDuration,
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ jsx(RadixTooltip.Trigger, { asChild: true, children }),
|
|
40
|
+
/* @__PURE__ */ jsx(RadixTooltip.Portal, { container, children: /* @__PURE__ */ jsxs(
|
|
41
|
+
RadixTooltip.Content,
|
|
42
|
+
{
|
|
43
|
+
className: cx("nuri-tooltip", className),
|
|
44
|
+
side,
|
|
45
|
+
align,
|
|
46
|
+
sideOffset: 4,
|
|
47
|
+
collisionPadding: 8,
|
|
48
|
+
arrowPadding: 6,
|
|
49
|
+
hideWhenDetached: true,
|
|
50
|
+
children: [
|
|
51
|
+
content,
|
|
52
|
+
arrow && /* @__PURE__ */ jsx(RadixTooltip.Arrow, { className: "nuri-tooltip__arrow", width: 14, height: 7 })
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
) })
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
return hasProvider ? root : /* @__PURE__ */ jsx(RadixTooltip.Provider, { delayDuration: 100, children: root });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
TooltipProvider,
|
|
64
|
+
Tooltip
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=chunk-2YGYLCCA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Tooltip/Tooltip.tsx"],"sourcesContent":["'use client';\n\nimport './styles.css';\nimport * as RadixTooltip from '@radix-ui/react-tooltip';\nimport { createContext, useContext } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { cx } from '../utils/cx.js';\n\ntype Side = 'top' | 'bottom' | 'left' | 'right';\ntype Align = 'start' | 'center' | 'end';\n\nexport interface TooltipProps {\n /** 툴팁 내용. */\n content: ReactNode;\n /** 트리거 — 단일 엘리먼트에 asChild로 위임 (Button, 아이콘 버튼 등). */\n children: ReactElement;\n /**\n * 툴팁이 뜨는 방향. (디자인의 Direction은 꼬리 방향 기준이라 반대 —\n * 예: 디자인 Direction=Bottom ⇒ side=\"top\")\n * 공간이 부족하면 자동으로 반대쪽으로 반전된다.\n * @default 'top'\n */\n side?: Side;\n /** 트리거 기준 정렬. @default 'center' */\n align?: Align;\n /** 꼬리(화살표) 표시 여부 — 디자인의 showTail. @default true */\n arrow?: boolean;\n /**\n * 열림 지연 ms. 미지정 시 — 단독 사용은 100ms(거의 즉시, 스쳐 지나갈 때 깜빡임만 방지),\n * TooltipProvider 안에서는 프로바이더 설정을 따름. 0이면 즉시.\n * 키보드 포커스는 지연 없이 항상 즉시 표시된다.\n */\n delayDuration?: number;\n /** 열림 상태 제어 — 항상 표시(코치마크류)나 수동 제어에 사용. */\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n /** true면 툴팁 없이 트리거만 렌더 (조건부 툴팁). @default false */\n disabled?: boolean;\n /** 포털 렌더 대상. 기본 document.body. */\n container?: HTMLElement | null;\n /** 툴팁 패널에 추가할 className. */\n className?: string;\n}\n\n// TooltipProvider 존재 감지용 — 없으면 Tooltip이 자체 Provider로 감싼다(제로 셋업).\nconst HasProviderContext = createContext(false);\n\nexport type TooltipProviderProps = RadixTooltip.TooltipProviderProps;\n\n/**\n * 지연 시간을 공유하는 프로바이더 (선택). 앱 루트에 1회 두면 툴팁 하나를 본 직후\n * 인접 트리거로 이동할 때 지연 없이 바로 표시된다(skipDelayDuration).\n * 없어도 Tooltip은 단독으로 동작한다.\n *\n * @example\n * <TooltipProvider delayDuration={300}><App /></TooltipProvider>\n */\nexport function TooltipProvider({ children, ...props }: TooltipProviderProps) {\n return (\n <HasProviderContext.Provider value={true}>\n <RadixTooltip.Provider {...props}>{children}</RadixTooltip.Provider>\n </HasProviderContext.Provider>\n );\n}\n\n/**\n * 툴팁. Radix Tooltip 기반 — hover와 **키보드 포커스** 모두에서 열리고,\n * Esc로 닫히며, `aria-describedby`가 자동 연결된다. 포털 + 충돌 감지\n * 포지셔닝이라 부모 overflow에 잘리지 않고 화면 밖으로 나가지 않는다.\n *\n * 터치 기기에서는 표시되지 않는다(hover 개념 부재 — Radix 기본 동작).\n * 닫기 버튼이 있는 지속형 안내(코치마크)는 툴팁 범위가 아니다.\n *\n * @example\n * <Tooltip content=\"즐겨찾기에 추가\">\n * <Button iconOnly aria-label=\"즐겨찾기\">★</Button>\n * </Tooltip>\n */\nexport function Tooltip({\n content,\n children,\n side = 'top',\n align = 'center',\n arrow = true,\n delayDuration,\n open,\n defaultOpen,\n onOpenChange,\n disabled = false,\n container,\n className,\n}: TooltipProps) {\n const hasProvider = useContext(HasProviderContext);\n\n if (disabled) return children;\n\n const root = (\n <RadixTooltip.Root\n open={open}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n delayDuration={delayDuration}\n >\n <RadixTooltip.Trigger asChild>{children}</RadixTooltip.Trigger>\n <RadixTooltip.Portal container={container}>\n <RadixTooltip.Content\n className={cx('nuri-tooltip', className)}\n side={side}\n align={align}\n sideOffset={4}\n collisionPadding={8}\n arrowPadding={6}\n // 트리거가 뷰포트/스크롤 영역에서 완전히 사라지면 툴팁도 숨김\n // (기준 요소 없이 툴팁만 떠 있는 현상 방지)\n hideWhenDetached\n >\n {content}\n {arrow && <RadixTooltip.Arrow className=\"nuri-tooltip__arrow\" width={14} height={7} />}\n </RadixTooltip.Content>\n </RadixTooltip.Portal>\n </RadixTooltip.Root>\n );\n\n // 앱에 TooltipProvider가 없어도 동작하도록 자체 Provider로 폴백.\n // 앱 Provider가 있으면 감싸지 않는다 — 안쪽 컨텍스트가 이기므로 여기서 또 감싸면\n // 앱이 설정한 delayDuration·skipDelayDuration이 무시된다.\n // 폴백 지연 100ms — 거의 즉시로 느껴지되, 마우스가 스쳐 지나갈 때 연쇄 깜빡임은 방지\n // (버튼 하나를 가로지르는 데 ~30–50ms — 그보다 길게 머문 경우만 의도로 판정).\n return hasProvider ? (\n root\n ) : (\n <RadixTooltip.Provider delayDuration={100}>{root}</RadixTooltip.Provider>\n );\n}\n"],"mappings":";;;;;;AAEA,OAAO;AACP,YAAY,kBAAkB;AAC9B,SAAS,eAAe,kBAAkB;AAyDpC,cA6CE,YA7CF;AAfN,IAAM,qBAAqB,cAAc,KAAK;AAYvC,SAAS,gBAAgB,EAAE,UAAU,GAAG,MAAM,GAAyB;AAC5E,SACE,oBAAC,mBAAmB,UAAnB,EAA4B,OAAO,MAClC,8BAAc,uBAAb,EAAuB,GAAG,OAAQ,UAAS,GAC9C;AAEJ;AAeO,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAiB;AACf,QAAM,cAAc,WAAW,kBAAkB;AAEjD,MAAI,SAAU,QAAO;AAErB,QAAM,OACJ;AAAA,IAAc;AAAA,IAAb;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEA;AAAA,4BAAc,sBAAb,EAAqB,SAAO,MAAE,UAAS;AAAA,QACxC,oBAAc,qBAAb,EAAoB,WACnB;AAAA,UAAc;AAAA,UAAb;AAAA,YACC,WAAW,GAAG,gBAAgB,SAAS;AAAA,YACvC;AAAA,YACA;AAAA,YACA,YAAY;AAAA,YACZ,kBAAkB;AAAA,YAClB,cAAc;AAAA,YAGd,kBAAgB;AAAA,YAEf;AAAA;AAAA,cACA,SAAS,oBAAc,oBAAb,EAAmB,WAAU,uBAAsB,OAAO,IAAI,QAAQ,GAAG;AAAA;AAAA;AAAA,QACtF,GACF;AAAA;AAAA;AAAA,EACF;AAQF,SAAO,cACL,OAEA,oBAAc,uBAAb,EAAsB,eAAe,KAAM,gBAAK;AAErD;","names":[]}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkR4E4BIPCcjs = require('./chunk-R4E4BIPC.cjs');
|
|
5
|
+
|
|
6
|
+
// src/Toast/Toaster.tsx
|
|
7
|
+
require('./Toast/styles.css');
|
|
8
|
+
var _reacttoast = require('@radix-ui/react-toast'); var RadixToast = _interopRequireWildcard(_reacttoast);
|
|
9
|
+
|
|
10
|
+
// src/Toast/store.ts
|
|
11
|
+
var _react = require('react');
|
|
12
|
+
var toasts = [];
|
|
13
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
14
|
+
var EMPTY = [];
|
|
15
|
+
var counter = 0;
|
|
16
|
+
var emit = () => {
|
|
17
|
+
for (const l of listeners) l();
|
|
18
|
+
};
|
|
19
|
+
function add(message, options = {}) {
|
|
20
|
+
const id = _nullishCoalesce(options.id, () => ( `nuri-toast-${++counter}`));
|
|
21
|
+
const record = {
|
|
22
|
+
id,
|
|
23
|
+
message,
|
|
24
|
+
tone: _nullishCoalesce(options.tone, () => ( "default")),
|
|
25
|
+
duration: _nullishCoalesce(options.duration, () => ( 3e3))
|
|
26
|
+
};
|
|
27
|
+
const idx = toasts.findIndex((t) => t.id === id);
|
|
28
|
+
toasts = idx >= 0 ? toasts.map((t) => t.id === id ? record : t) : [...toasts, record];
|
|
29
|
+
emit();
|
|
30
|
+
return id;
|
|
31
|
+
}
|
|
32
|
+
function remove(id) {
|
|
33
|
+
toasts = toasts.filter((t) => t.id !== id);
|
|
34
|
+
emit();
|
|
35
|
+
}
|
|
36
|
+
function clear() {
|
|
37
|
+
toasts = [];
|
|
38
|
+
emit();
|
|
39
|
+
}
|
|
40
|
+
var toastStore = {
|
|
41
|
+
add,
|
|
42
|
+
remove,
|
|
43
|
+
clear,
|
|
44
|
+
subscribe(listener) {
|
|
45
|
+
listeners.add(listener);
|
|
46
|
+
return () => {
|
|
47
|
+
listeners.delete(listener);
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
getSnapshot: () => toasts,
|
|
51
|
+
getServerSnapshot: () => EMPTY
|
|
52
|
+
};
|
|
53
|
+
function useToasts() {
|
|
54
|
+
return _react.useSyncExternalStore.call(void 0,
|
|
55
|
+
toastStore.subscribe,
|
|
56
|
+
toastStore.getSnapshot,
|
|
57
|
+
toastStore.getServerSnapshot
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/Toast/icons.tsx
|
|
62
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
63
|
+
var CheckIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
64
|
+
"path",
|
|
65
|
+
{
|
|
66
|
+
d: "M3.5 8.5l3 3 6-6.5",
|
|
67
|
+
stroke: "currentColor",
|
|
68
|
+
strokeWidth: "1.6",
|
|
69
|
+
strokeLinecap: "round",
|
|
70
|
+
strokeLinejoin: "round"
|
|
71
|
+
}
|
|
72
|
+
) });
|
|
73
|
+
var ErrorIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
|
|
74
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8 4v4.5", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
75
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "8", cy: "11.3", r: "0.95", fill: "currentColor" })
|
|
76
|
+
] });
|
|
77
|
+
var InfoIcon = () => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
|
|
78
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M8 7.5v4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }),
|
|
79
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "circle", { cx: "8", cy: "4.7", r: "0.95", fill: "currentColor" })
|
|
80
|
+
] });
|
|
81
|
+
var toneIcon = {
|
|
82
|
+
success: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CheckIcon, {}),
|
|
83
|
+
error: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ErrorIcon, {}),
|
|
84
|
+
info: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, InfoIcon, {})
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// src/Toast/Toaster.tsx
|
|
88
|
+
|
|
89
|
+
function Toaster({
|
|
90
|
+
swipeDirection = "down",
|
|
91
|
+
swipeThreshold = 50,
|
|
92
|
+
className,
|
|
93
|
+
label = "\uC54C\uB9BC"
|
|
94
|
+
}) {
|
|
95
|
+
const toasts2 = useToasts();
|
|
96
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
97
|
+
RadixToast.Provider,
|
|
98
|
+
{
|
|
99
|
+
swipeDirection,
|
|
100
|
+
swipeThreshold,
|
|
101
|
+
label,
|
|
102
|
+
children: [
|
|
103
|
+
toasts2.map((t) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
104
|
+
RadixToast.Root,
|
|
105
|
+
{
|
|
106
|
+
duration: t.duration,
|
|
107
|
+
onOpenChange: (open) => {
|
|
108
|
+
if (!open) toastStore.remove(t.id);
|
|
109
|
+
},
|
|
110
|
+
type: t.tone === "error" ? "foreground" : "background",
|
|
111
|
+
className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-toast", t.tone !== "default" && `nuri-toast--${t.tone}`),
|
|
112
|
+
children: [
|
|
113
|
+
t.tone !== "default" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "nuri-toast__icon", "aria-hidden": "true", children: toneIcon[t.tone] }),
|
|
114
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, RadixToast.Title, { className: "nuri-toast__message", children: t.message })
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
t.id
|
|
118
|
+
)),
|
|
119
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
120
|
+
RadixToast.Viewport,
|
|
121
|
+
{
|
|
122
|
+
className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-toast__viewport", className),
|
|
123
|
+
label: `${label} ({hotkey})`
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/Toast/toast.ts
|
|
132
|
+
function toastFn(message, options) {
|
|
133
|
+
return toastStore.add(message, options);
|
|
134
|
+
}
|
|
135
|
+
var toast = Object.assign(toastFn, {
|
|
136
|
+
success: (message, options) => toastStore.add(message, { ...options, tone: "success" }),
|
|
137
|
+
error: (message, options) => toastStore.add(message, { ...options, tone: "error" }),
|
|
138
|
+
info: (message, options) => toastStore.add(message, { ...options, tone: "info" }),
|
|
139
|
+
/** id 지정 시 해당 토스트만, 없으면 전체 제거. */
|
|
140
|
+
dismiss: (id) => id ? toastStore.remove(id) : toastStore.clear()
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
exports.Toaster = Toaster; exports.toast = toast;
|
|
147
|
+
//# sourceMappingURL=chunk-323VGYMK.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-323VGYMK.cjs","../src/Toast/Toaster.tsx","../src/Toast/store.ts","../src/Toast/icons.tsx","../src/Toast/toast.ts"],"names":["jsxs","jsx"],"mappings":"AAAA,2cAAY;AACZ;AACE;AACF,wDAA6B;AAC7B;AACA;ACHA,8BAAO;AACP,0GAA4B;ADK5B;AACA;AEPA,8BAAqC;AAsBrC,IAAI,OAAA,EAAwB,CAAC,CAAA;AAC7B,IAAM,UAAA,kBAAY,IAAI,GAAA,CAAgB,CAAA;AACtC,IAAM,MAAA,EAAuB,CAAC,CAAA;AAC9B,IAAI,QAAA,EAAU,CAAA;AAEd,IAAM,KAAA,EAAO,CAAA,EAAA,GAAM;AACjB,EAAA,IAAA,CAAA,MAAW,EAAA,GAAK,SAAA,EAAW,CAAA,CAAE,CAAA;AAC/B,CAAA;AAEA,SAAS,GAAA,CAAI,OAAA,EAAoB,QAAA,EAAwB,CAAC,CAAA,EAAW;AACnE,EAAA,MAAM,GAAA,mBAAK,OAAA,CAAQ,EAAA,UAAM,CAAA,WAAA,EAAc,EAAE,OAAO,CAAA,GAAA;AACpB,EAAA;AAC1B,IAAA;AACA,IAAA;AACsB,IAAA;AACQ,IAAA;AAChC,EAAA;AAC+C,EAAA;AACC,EAAA;AAC3C,EAAA;AACE,EAAA;AACT;AAE4B;AACe,EAAA;AACpC,EAAA;AACP;AAEiB;AACL,EAAA;AACL,EAAA;AACP;AAE0B;AACxB,EAAA;AACA,EAAA;AACA,EAAA;AACgC,EAAA;AACR,IAAA;AACT,IAAA;AACc,MAAA;AAC3B,IAAA;AACF,EAAA;AACmB,EAAA;AACM,EAAA;AAC3B;AAG2C;AAClC,EAAA;AACM,IAAA;AACA,IAAA;AACA,IAAA;AACb,EAAA;AACF;AFnBmD;AACA;AGtD/C;AADG;AACF,EAAA;AAAA,EAAA;AACG,IAAA;AACK,IAAA;AACK,IAAA;AACE,IAAA;AACC,IAAA;AAAA,EAAA;AAEnB;AAIC;AACoB,kBAAA;AACD,kBAAA;AACpB;AAIK;AACgB,kBAAA;AACD,kBAAA;AACpB;AAIwE;AACpD,EAAA;AACF,EAAA;AACF,EAAA;AAClB;AHkDmD;AACA;ACtC3C;AAfgB;AACL,EAAA;AACA,EAAA;AACjB,EAAA;AACQ,EAAA;AACO;AACU,EAAA;AAGvBA,EAAAA;AAAY,IAAA;AAAX,IAAA;AACC,MAAA;AACA,MAAA;AACA,MAAA;AAEC,MAAA;AACCA,QAAAA;AAAY,UAAA;AAAX,UAAA;AAEa,YAAA;AACY,YAAA;AACW,cAAA;AACnC,YAAA;AAE2B,YAAA;AACY,YAAA;AAEtC,YAAA;AACC,cAAA;AAIU,8BAAA;AAAiD,YAAA;AAAA,UAAA;AAdtD,UAAA;AAgBV,QAAA;AAEDC,wBAAAA;AAAY,UAAA;AAAX,UAAA;AACuC,YAAA;AACvB,YAAA;AAAA,UAAA;AACjB,QAAA;AAAA,MAAA;AAAA,IAAA;AACF,EAAA;AAEJ;ADwDmD;AACA;AIlHkB;AAC7B,EAAA;AACxC;AAE4C;AAEzB,EAAA;AAEA,EAAA;AAEA,EAAA;AAAqC;AAEE,EAAA;AACzD;AJgHkD;AACA;AACA;AACA;AACA","file":"/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-323VGYMK.cjs","sourcesContent":[null,"'use client';\n\nimport './styles.css';\nimport * as RadixToast from '@radix-ui/react-toast';\nimport { cx } from '../utils/cx.js';\nimport { toastStore, useToasts } from './store.js';\nimport { toneIcon } from './icons.js';\n\nexport interface ToasterProps {\n /**\n * 스와이프로 닫는 방향. 하단 표시라 기본 `down`(아래로 밀어 닫기 — 터치·드래그 모두).\n * @default 'down'\n */\n swipeDirection?: RadixToast.ToastProviderProps['swipeDirection'];\n /** 스와이프 임계 거리(px). @default 50 */\n swipeThreshold?: number;\n /** 뷰포트에 추가할 className (위치 커스터마이즈 등). */\n className?: string;\n /** 스크린리더용 지역 라벨. @default '알림' */\n label?: string;\n}\n\n/**\n * 토스트 렌더러. **앱 루트에 1회만** 마운트하면 되고, 표시는 `toast()` 호출로 트리거한다.\n * (사용처마다 렌더할 필요 없음 — 모듈 store를 구독해 이 컴포넌트만 렌더)\n *\n * Radix Toast 기반이라 자동 닫힘 타이머·hover 시 일시정지·스와이프 닫기·\n * 스크린리더 announce(aria-live)를 표준으로 제공한다.\n *\n * @example\n * // app/layout.tsx\n * <body>{children}<Toaster /></body>\n */\nexport function Toaster({\n swipeDirection = 'down',\n swipeThreshold = 50,\n className,\n label = '알림',\n}: ToasterProps) {\n const toasts = useToasts();\n\n return (\n <RadixToast.Provider\n swipeDirection={swipeDirection}\n swipeThreshold={swipeThreshold}\n label={label}\n >\n {toasts.map((t) => (\n <RadixToast.Root\n key={t.id}\n duration={t.duration}\n onOpenChange={(open) => {\n if (!open) toastStore.remove(t.id);\n }}\n // error는 foreground(assertive)로 즉시 안내, 그 외는 background(polite)\n type={t.tone === 'error' ? 'foreground' : 'background'}\n className={cx('nuri-toast', t.tone !== 'default' && `nuri-toast--${t.tone}`)}\n >\n {t.tone !== 'default' && (\n <span className=\"nuri-toast__icon\" aria-hidden=\"true\">\n {toneIcon[t.tone]}\n </span>\n )}\n <RadixToast.Title className=\"nuri-toast__message\">{t.message}</RadixToast.Title>\n </RadixToast.Root>\n ))}\n {/* 랜드마크 이름 — 스크린리더 영역 탐색용. {hotkey}는 Radix가 실제 키(F8)로 치환 */}\n <RadixToast.Viewport\n className={cx('nuri-toast__viewport', className)}\n label={`${label} ({hotkey})`}\n />\n </RadixToast.Provider>\n );\n}\n","'use client';\n\nimport { useSyncExternalStore } from 'react';\nimport type { ReactNode } from 'react';\n\nexport type ToastTone = 'default' | 'success' | 'error' | 'info';\n\nexport interface ToastOptions {\n /** 톤 — 아이콘·색 결정. @default 'default' (아이콘 없음) */\n tone?: ToastTone;\n /** 자동 닫힘까지 ms. @default 3000 */\n duration?: number;\n /** id 직접 지정 (같은 id면 교체 — 중복 방지·수동 dismiss용). */\n id?: string;\n}\n\nexport interface ToastRecord {\n id: string;\n message: ReactNode;\n tone: ToastTone;\n duration: number;\n}\n\n// ── React 밖 모듈 싱글톤 store (아무 데서나 toast() 호출 가능한 이유) ──\nlet toasts: ToastRecord[] = [];\nconst listeners = new Set<() => void>();\nconst EMPTY: ToastRecord[] = []; // 서버 스냅샷용 안정 참조\nlet counter = 0;\n\nconst emit = () => {\n for (const l of listeners) l();\n};\n\nfunction add(message: ReactNode, options: ToastOptions = {}): string {\n const id = options.id ?? `nuri-toast-${++counter}`;\n const record: ToastRecord = {\n id,\n message,\n tone: options.tone ?? 'default',\n duration: options.duration ?? 3000,\n };\n const idx = toasts.findIndex((t) => t.id === id);\n toasts = idx >= 0 ? toasts.map((t) => (t.id === id ? record : t)) : [...toasts, record];\n emit();\n return id;\n}\n\nfunction remove(id: string) {\n toasts = toasts.filter((t) => t.id !== id);\n emit();\n}\n\nfunction clear() {\n toasts = [];\n emit();\n}\n\nexport const toastStore = {\n add,\n remove,\n clear,\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n getSnapshot: () => toasts,\n getServerSnapshot: () => EMPTY,\n};\n\n/** 현재 토스트 목록을 구독 (Toaster 내부 전용). */\nexport function useToasts(): ToastRecord[] {\n return useSyncExternalStore(\n toastStore.subscribe,\n toastStore.getSnapshot,\n toastStore.getServerSnapshot,\n );\n}\n","import type { ReactNode } from 'react';\nimport type { ToastTone } from './store.js';\n\n// 16px, currentColor — 색은 .nuri-toast--{tone}이 톤 토큰으로 지정.\nconst CheckIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M3.5 8.5l3 3 6-6.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\nconst ErrorIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 4v4.5\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"11.3\" r=\"0.95\" fill=\"currentColor\" />\n </svg>\n);\n\nconst InfoIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M8 7.5v4\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"4.7\" r=\"0.95\" fill=\"currentColor\" />\n </svg>\n);\n\n/** default 톤은 아이콘 없음. */\nexport const toneIcon: Record<Exclude<ToastTone, 'default'>, ReactNode> = {\n success: <CheckIcon />,\n error: <ErrorIcon />,\n info: <InfoIcon />,\n};\n","import type { ReactNode } from 'react';\nimport { toastStore } from './store.js';\nimport type { ToastOptions } from './store.js';\n\ntype ToneOptions = Omit<ToastOptions, 'tone'>;\n\n/**\n * 토스트를 띄운다. React 밖 모듈 함수라 컴포넌트·이벤트 핸들러·API 레이어 등\n * **어디서나** 호출 가능. 화면 렌더는 앱 루트에 1회 마운트한 `<Toaster/>`가 담당한다.\n *\n * @returns 토스트 id (수동 dismiss에 사용)\n * @example\n * toast.success('저장됐습니다');\n * const id = toast.error('오류', { duration: 5000 });\n * toast.dismiss(id);\n */\nfunction toastFn(message: ReactNode, options?: ToastOptions): string {\n return toastStore.add(message, options);\n}\n\nexport const toast = Object.assign(toastFn, {\n success: (message: ReactNode, options?: ToneOptions) =>\n toastStore.add(message, { ...options, tone: 'success' }),\n error: (message: ReactNode, options?: ToneOptions) =>\n toastStore.add(message, { ...options, tone: 'error' }),\n info: (message: ReactNode, options?: ToneOptions) =>\n toastStore.add(message, { ...options, tone: 'info' }),\n /** id 지정 시 해당 토스트만, 없으면 전체 제거. */\n dismiss: (id?: string) => (id ? toastStore.remove(id) : toastStore.clear()),\n});\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
cx
|
|
4
|
+
} from "./chunk-PS6QXS5Z.js";
|
|
5
|
+
|
|
6
|
+
// src/Radio/Radio.tsx
|
|
7
|
+
import "./Radio/styles.css";
|
|
8
|
+
import * as RadixRadioGroup from "@radix-ui/react-radio-group";
|
|
9
|
+
import { forwardRef, useId } from "react";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var RadioGroup = forwardRef(function RadioGroup2({ children, orientation = "vertical", className, ...rest }, ref) {
|
|
12
|
+
return /* @__PURE__ */ jsx(
|
|
13
|
+
RadixRadioGroup.Root,
|
|
14
|
+
{
|
|
15
|
+
ref,
|
|
16
|
+
orientation,
|
|
17
|
+
className: cx("nuri-radio-group", `nuri-radio-group--${orientation}`, className),
|
|
18
|
+
...rest,
|
|
19
|
+
children
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
var Radio = forwardRef(function Radio2({ value, label, disabled = false, id: idProp, className, ...rest }, ref) {
|
|
24
|
+
const reactId = useId();
|
|
25
|
+
const id = idProp ?? `nuri-radio-${reactId}`;
|
|
26
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("nuri-radio", className), children: [
|
|
27
|
+
/* @__PURE__ */ jsx(
|
|
28
|
+
RadixRadioGroup.Item,
|
|
29
|
+
{
|
|
30
|
+
ref,
|
|
31
|
+
id,
|
|
32
|
+
value,
|
|
33
|
+
disabled,
|
|
34
|
+
className: "nuri-radio__control",
|
|
35
|
+
...rest,
|
|
36
|
+
children: /* @__PURE__ */ jsx(RadixRadioGroup.Indicator, { className: "nuri-radio__indicator" })
|
|
37
|
+
}
|
|
38
|
+
),
|
|
39
|
+
label != null && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "nuri-radio__label", children: label })
|
|
40
|
+
] });
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
RadioGroup,
|
|
45
|
+
Radio
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=chunk-3H47QMKS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Radio/Radio.tsx"],"sourcesContent":["'use client';\n\nimport './styles.css';\nimport * as RadixRadioGroup from '@radix-ui/react-radio-group';\nimport { forwardRef, useId } from 'react';\nimport type { ReactNode } from 'react';\nimport { cx } from '../utils/cx.js';\n\nexport interface RadioGroupProps {\n children: ReactNode;\n /** 선택된 값 (제어형). */\n value?: string;\n /** 초기 값 (비제어형). */\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n /** 배치 방향 — 키보드 화살표 탐색 방향에도 반영됨. @default 'vertical' */\n orientation?: 'vertical' | 'horizontal';\n disabled?: boolean;\n /** 폼 전송용 name. */\n name?: string;\n required?: boolean;\n className?: string;\n /** 그룹의 접근 가능한 이름 (시각 제목이 없을 때 필수). */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n/**\n * 라디오 그룹. Radix RadioGroup 기반 — 화살표 키 그룹 탐색·단일 선택·폼 참여 자동.\n * 그룹에 `aria-label`(또는 aria-labelledby)을 지정한다.\n *\n * @example\n * <RadioGroup aria-label=\"정렬\" value={sort} onValueChange={setSort}>\n * <Radio value=\"latest\" label=\"최신순\" />\n * <Radio value=\"edited\" label=\"수정순\" />\n * </RadioGroup>\n */\nexport const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(function RadioGroup(\n { children, orientation = 'vertical', className, ...rest },\n ref,\n) {\n return (\n <RadixRadioGroup.Root\n ref={ref}\n orientation={orientation}\n className={cx('nuri-radio-group', `nuri-radio-group--${orientation}`, className)}\n {...rest}\n >\n {children}\n </RadixRadioGroup.Root>\n );\n});\n\nexport interface RadioProps {\n /** 이 항목이 나타내는 값. */\n value: string;\n /** 라벨 (컨트롤 우측). 없으면 `aria-label` 필수. */\n label?: ReactNode;\n disabled?: boolean;\n id?: string;\n className?: string;\n 'aria-label'?: string;\n}\n\n/** 라디오 항목 — 반드시 RadioGroup 안에서 사용. */\nexport const Radio = forwardRef<HTMLButtonElement, RadioProps>(function Radio(\n { value, label, disabled = false, id: idProp, className, ...rest },\n ref,\n) {\n const reactId = useId();\n const id = idProp ?? `nuri-radio-${reactId}`;\n\n return (\n <div className={cx('nuri-radio', className)}>\n <RadixRadioGroup.Item\n ref={ref}\n id={id}\n value={value}\n disabled={disabled}\n className=\"nuri-radio__control\"\n {...rest}\n >\n <RadixRadioGroup.Indicator className=\"nuri-radio__indicator\" />\n </RadixRadioGroup.Item>\n {label != null && (\n <label htmlFor={id} className=\"nuri-radio__label\">\n {label}\n </label>\n )}\n </div>\n );\n});\n"],"mappings":";;;;;;AAEA,OAAO;AACP,YAAY,qBAAqB;AACjC,SAAS,YAAY,aAAa;AAsC9B,cA+BA,YA/BA;AALG,IAAM,aAAa,WAA4C,SAASA,YAC7E,EAAE,UAAU,cAAc,YAAY,WAAW,GAAG,KAAK,GACzD,KACA;AACA,SACE;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA;AAAA,MACA,WAAW,GAAG,oBAAoB,qBAAqB,WAAW,IAAI,SAAS;AAAA,MAC9E,GAAG;AAAA,MAEH;AAAA;AAAA,EACH;AAEJ,CAAC;AAcM,IAAM,QAAQ,WAA0C,SAASC,OACtE,EAAE,OAAO,OAAO,WAAW,OAAO,IAAI,QAAQ,WAAW,GAAG,KAAK,GACjE,KACA;AACA,QAAM,UAAU,MAAM;AACtB,QAAM,KAAK,UAAU,cAAc,OAAO;AAE1C,SACE,qBAAC,SAAI,WAAW,GAAG,cAAc,SAAS,GACxC;AAAA;AAAA,MAAiB;AAAA,MAAhB;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAU;AAAA,QACT,GAAG;AAAA,QAEJ,8BAAiB,2BAAhB,EAA0B,WAAU,yBAAwB;AAAA;AAAA,IAC/D;AAAA,IACC,SAAS,QACR,oBAAC,WAAM,SAAS,IAAI,WAAU,qBAC3B,iBACH;AAAA,KAEJ;AAEJ,CAAC;","names":["RadioGroup","Radio"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkR4E4BIPCcjs = require('./chunk-R4E4BIPC.cjs');
|
|
5
|
+
|
|
6
|
+
// src/Checkbox/Checkbox.tsx
|
|
7
|
+
require('./Checkbox/styles.css');
|
|
8
|
+
var _reactcheckbox = require('@radix-ui/react-checkbox'); var RadixCheckbox = _interopRequireWildcard(_reactcheckbox);
|
|
9
|
+
var _react = require('react');
|
|
10
|
+
var _jsxruntime = require('react/jsx-runtime');
|
|
11
|
+
var CheckIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
12
|
+
"path",
|
|
13
|
+
{
|
|
14
|
+
d: "M2.5 6.2l2.4 2.4 4.6-5",
|
|
15
|
+
stroke: "currentColor",
|
|
16
|
+
strokeWidth: "1.6",
|
|
17
|
+
strokeLinecap: "round",
|
|
18
|
+
strokeLinejoin: "round"
|
|
19
|
+
}
|
|
20
|
+
) });
|
|
21
|
+
var IndeterminateIcon = () => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "svg", { viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "path", { d: "M2.8 6h6.4", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }) });
|
|
22
|
+
var Checkbox = _react.forwardRef.call(void 0, function Checkbox2({ label, size = "md", disabled = false, id: idProp, className, checked, ...rest }, ref) {
|
|
23
|
+
const reactId = _react.useId.call(void 0, );
|
|
24
|
+
const id = _nullishCoalesce(idProp, () => ( `nuri-checkbox-${reactId}`));
|
|
25
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkR4E4BIPCcjs.cx.call(void 0, "nuri-checkbox", `nuri-checkbox--${size}`, className), children: [
|
|
26
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
27
|
+
RadixCheckbox.Root,
|
|
28
|
+
{
|
|
29
|
+
ref,
|
|
30
|
+
id,
|
|
31
|
+
className: "nuri-checkbox__control",
|
|
32
|
+
disabled,
|
|
33
|
+
checked,
|
|
34
|
+
...rest,
|
|
35
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, RadixCheckbox.Indicator, { className: "nuri-checkbox__indicator", children: checked === "indeterminate" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, IndeterminateIcon, {}) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CheckIcon, {}) })
|
|
36
|
+
}
|
|
37
|
+
),
|
|
38
|
+
label != null && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { htmlFor: id, className: "nuri-checkbox__label", children: label })
|
|
39
|
+
] });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
exports.Checkbox = Checkbox;
|
|
45
|
+
//# sourceMappingURL=chunk-3QSLHLC2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-3QSLHLC2.cjs","../src/Checkbox/Checkbox.tsx"],"names":["Checkbox"],"mappings":"AAAA,2cAAY;AACZ;AACE;AACF,wDAA6B;AAC7B;AACA;ACHA,iCAAO;AACP,sHAA+B;AAC/B,8BAAkC;AAiC9B,+CAAA;AAFJ,IAAM,UAAA,EAAY,CAAA,EAAA,mBAChB,6BAAA,KAAC,EAAA,EAAI,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,aAAA,EAAY,MAAA,EAC/C,QAAA,kBAAA,6BAAA;AAAA,EAAC,MAAA;AAAA,EAAA;AAAA,IACC,CAAA,EAAE,wBAAA;AAAA,IACF,MAAA,EAAO,cAAA;AAAA,IACP,WAAA,EAAY,KAAA;AAAA,IACZ,aAAA,EAAc,OAAA;AAAA,IACd,cAAA,EAAe;AAAA,EAAA;AACjB,EAAA,CACF,CAAA;AAIF,IAAM,kBAAA,EAAoB,CAAA,EAAA,mBACxB,6BAAA,KAAC,EAAA,EAAI,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,aAAA,EAAY,MAAA,EAC/C,QAAA,kBAAA,6BAAA,MAAC,EAAA,EAAK,CAAA,EAAE,YAAA,EAAa,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,KAAA,EAAM,aAAA,EAAc,QAAA,CAAQ,EAAA,CACrF,CAAA;AAaK,IAAM,SAAA,EAAW,+BAAA,SAAsDA,SAAAA,CAC5E,EAAE,KAAA,EAAO,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW,KAAA,EAAO,EAAA,EAAI,MAAA,EAAQ,SAAA,EAAW,OAAA,EAAS,GAAG,KAAK,CAAA,EAChF,GAAA,EACA;AACA,EAAA,MAAM,QAAA,EAAU,0BAAA,CAAM;AACtB,EAAA,MAAM,GAAA,mBAAK,MAAA,UAAU,CAAA,cAAA,EAAiB,OAAO,CAAA,GAAA;AAGtC,EAAA;AACH,oBAAA;AAAe,MAAA;AAAd,MAAA;AACC,QAAA;AACA,QAAA;AACU,QAAA;AACV,QAAA;AACA,QAAA;AACI,QAAA;AAEW,QAAA;AAEf,MAAA;AACF,IAAA;AAEG,IAAA;AAIL,EAAA;AAEH;ADpD+C;AACA;AACA;AACA","file":"/Users/summerhoony/Desktop/projects/nuri-ui/dist/chunk-3QSLHLC2.cjs","sourcesContent":[null,"'use client';\n\nimport './styles.css';\nimport * as RadixCheckbox from '@radix-ui/react-checkbox';\nimport { forwardRef, useId } from 'react';\nimport type { ReactNode } from 'react';\nimport { cx } from '../utils/cx.js';\n\ntype Size = 'sm' | 'md';\n\nexport interface CheckboxProps {\n /** 라벨 (컨트롤 우측). 지정 시 클릭 영역에 포함되고 자동 연결됨. 없으면 `aria-label` 필수. */\n label?: ReactNode;\n /**\n * 사이즈. md 16px(디자인 Large, 기본) / sm 12px(디자인 Small).\n * @default 'md'\n */\n size?: Size;\n /** 체크 상태 (제어형). `'indeterminate'`는 부분 선택 표시. */\n checked?: boolean | 'indeterminate';\n /** 초기 체크 상태 (비제어형). */\n defaultChecked?: boolean;\n onCheckedChange?: (checked: boolean | 'indeterminate') => void;\n disabled?: boolean;\n /** 폼 전송용 name — 네이티브 checkbox처럼 폼에 참여. */\n name?: string;\n /** 폼 전송 시 값. @default 'on' */\n value?: string;\n required?: boolean;\n id?: string;\n className?: string;\n 'aria-label'?: string;\n}\n\n/** 체크마크. TODO(Figma 실측): 디자이너 아이콘으로 교체 예정 — 잠정 표준형. */\nconst CheckIcon = () => (\n <svg viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M2.5 6.2l2.4 2.4 4.6-5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n\n/** 부분 선택(indeterminate) 표시 — 가로 막대. */\nconst IndeterminateIcon = () => (\n <svg viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M2.8 6h6.4\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" />\n </svg>\n);\n\n/**\n * 체크박스. Radix Checkbox 기반 — Space 토글·aria-checked·폼 참여 자동.\n * 라벨을 지정하면 라벨 클릭으로도 토글된다.\n *\n * @example\n * <Checkbox label=\"이용약관에 동의합니다\" checked={agreed} onCheckedChange={setAgreed} />\n *\n * @example 부분 선택 (전체선택 헤더 등)\n * <Checkbox label=\"전체 선택\" checked={someChecked ? 'indeterminate' : allChecked} … />\n */\nexport const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(function Checkbox(\n { label, size = 'md', disabled = false, id: idProp, className, checked, ...rest },\n ref,\n) {\n const reactId = useId();\n const id = idProp ?? `nuri-checkbox-${reactId}`;\n\n return (\n <div className={cx('nuri-checkbox', `nuri-checkbox--${size}`, className)}>\n <RadixCheckbox.Root\n ref={ref}\n id={id}\n className=\"nuri-checkbox__control\"\n disabled={disabled}\n checked={checked}\n {...rest}\n >\n <RadixCheckbox.Indicator className=\"nuri-checkbox__indicator\">\n {checked === 'indeterminate' ? <IndeterminateIcon /> : <CheckIcon />}\n </RadixCheckbox.Indicator>\n </RadixCheckbox.Root>\n {label != null && (\n <label htmlFor={id} className=\"nuri-checkbox__label\">\n {label}\n </label>\n )}\n </div>\n );\n});\n"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import {
|
|
3
|
+
cx
|
|
4
|
+
} from "./chunk-PS6QXS5Z.js";
|
|
5
|
+
|
|
6
|
+
// src/Modal/Modal.tsx
|
|
7
|
+
import "./Modal/styles.css";
|
|
8
|
+
import * as Dialog from "@radix-ui/react-dialog";
|
|
9
|
+
import { forwardRef } from "react";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var Root2 = (props) => /* @__PURE__ */ jsx(Dialog.Root, { ...props });
|
|
12
|
+
Root2.displayName = "Modal";
|
|
13
|
+
var Trigger2 = Dialog.Trigger;
|
|
14
|
+
var Content2 = forwardRef(
|
|
15
|
+
function ModalContent({ placement = "center", size = "md", overlay = true, container, className, children, ...rest }, ref) {
|
|
16
|
+
const classes = cx("nuri-modal", `nuri-modal--${placement}`, `nuri-modal--${size}`, className);
|
|
17
|
+
return /* @__PURE__ */ jsxs(Dialog.Portal, { container, children: [
|
|
18
|
+
overlay && /* @__PURE__ */ jsx(Dialog.Overlay, { className: "nuri-modal__overlay" }),
|
|
19
|
+
/* @__PURE__ */ jsx(Dialog.Content, { ref, className: classes, ...rest, children })
|
|
20
|
+
] });
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
var Header = forwardRef(function ModalHeader({ className, ...rest }, ref) {
|
|
24
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cx("nuri-modal__header", className), ...rest });
|
|
25
|
+
});
|
|
26
|
+
var Title2 = forwardRef(function ModalTitle({ visuallyHidden = false, className, ...rest }, ref) {
|
|
27
|
+
return /* @__PURE__ */ jsx(
|
|
28
|
+
Dialog.Title,
|
|
29
|
+
{
|
|
30
|
+
ref,
|
|
31
|
+
className: cx("nuri-modal__title", visuallyHidden && "nuri-sr-only", className),
|
|
32
|
+
...rest
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
var Description2 = forwardRef(function ModalDescription({ className, ...rest }, ref) {
|
|
37
|
+
return /* @__PURE__ */ jsx(Dialog.Description, { ref, className: cx("nuri-modal__description", className), ...rest });
|
|
38
|
+
});
|
|
39
|
+
var Body = forwardRef(function ModalBody({ className, ...rest }, ref) {
|
|
40
|
+
return /* @__PURE__ */ jsx("div", { ref, className: cx("nuri-modal__body", className), ...rest });
|
|
41
|
+
});
|
|
42
|
+
var Footer = forwardRef(function ModalFooter({ align = "end", className, ...rest }, ref) {
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
"div",
|
|
45
|
+
{
|
|
46
|
+
ref,
|
|
47
|
+
className: cx("nuri-modal__footer", `nuri-modal__footer--${align}`, className),
|
|
48
|
+
...rest
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
var Close2 = Dialog.Close;
|
|
53
|
+
var CloseIcon = () => /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M5 5l10 10M15 5L5 15", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
|
|
54
|
+
var CloseButton = forwardRef(function ModalCloseButton({ className, "aria-label": ariaLabel = "\uB2EB\uAE30", children, ...rest }, ref) {
|
|
55
|
+
return /* @__PURE__ */ jsx(Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
56
|
+
"button",
|
|
57
|
+
{
|
|
58
|
+
ref,
|
|
59
|
+
type: "button",
|
|
60
|
+
"aria-label": ariaLabel,
|
|
61
|
+
className: cx("nuri-modal__close", className),
|
|
62
|
+
...rest,
|
|
63
|
+
children: children ?? /* @__PURE__ */ jsx(CloseIcon, {})
|
|
64
|
+
}
|
|
65
|
+
) });
|
|
66
|
+
});
|
|
67
|
+
var Modal = Object.assign(Root2, {
|
|
68
|
+
Trigger: Trigger2,
|
|
69
|
+
Content: Content2,
|
|
70
|
+
Header,
|
|
71
|
+
Title: Title2,
|
|
72
|
+
Description: Description2,
|
|
73
|
+
Body,
|
|
74
|
+
Footer,
|
|
75
|
+
Close: Close2,
|
|
76
|
+
CloseButton
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
Modal
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=chunk-4N5JIGIU.js.map
|