cyberui-2045 2.3.0 → 2.4.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.
- package/AGENT.md +25 -23
- package/README.md +31 -28
- package/bin/init.js +11 -5
- package/bin/markers.js +18 -0
- package/bin/usage-content.js +136 -210
- package/dist/component-manifest.json +1454 -0
- package/dist/components/Badge.js +49 -0
- package/dist/components/Badge.js.map +1 -0
- package/dist/components/Button.js +62 -0
- package/dist/components/Button.js.map +1 -0
- package/dist/components/Card.js +31 -0
- package/dist/components/Card.js.map +1 -0
- package/dist/components/Carousel.js +585 -0
- package/dist/components/Carousel.js.map +1 -0
- package/dist/components/Checkbox.js +92 -0
- package/dist/components/Checkbox.js.map +1 -0
- package/dist/components/CircularProgress.js +87 -0
- package/dist/components/CircularProgress.js.map +1 -0
- package/dist/components/Divider.js +24 -0
- package/dist/components/Divider.js.map +1 -0
- package/dist/components/GradientText.js +27 -0
- package/dist/components/GradientText.js.map +1 -0
- package/dist/components/Image.js +369 -0
- package/dist/components/Image.js.map +1 -0
- package/dist/components/Input.js +70 -0
- package/dist/components/Input.js.map +1 -0
- package/dist/components/LinearProgress.js +39 -0
- package/dist/components/LinearProgress.js.map +1 -0
- package/dist/components/Modal.d.ts +19 -0
- package/dist/components/Modal.js +211 -0
- package/dist/components/Modal.js.map +1 -0
- package/dist/components/Notification.js +88 -0
- package/dist/components/Notification.js.map +1 -0
- package/dist/components/SectionTitle.js +33 -0
- package/dist/components/SectionTitle.js.map +1 -0
- package/dist/components/SegmentedProgress.js +82 -0
- package/dist/components/SegmentedProgress.js.map +1 -0
- package/dist/components/Select.js +93 -0
- package/dist/components/Select.js.map +1 -0
- package/dist/components/Skeleton.js +106 -0
- package/dist/components/Skeleton.js.map +1 -0
- package/dist/components/Steps.js +88 -0
- package/dist/components/Steps.js.map +1 -0
- package/dist/components/TabNavigation.js +153 -0
- package/dist/components/TabNavigation.js.map +1 -0
- package/dist/components/Timeline.js +99 -0
- package/dist/components/Timeline.js.map +1 -0
- package/dist/components/Toggle.js +73 -0
- package/dist/components/Toggle.js.map +1 -0
- package/dist/contexts/NotificationContext.js +100 -0
- package/dist/contexts/NotificationContext.js.map +1 -0
- package/dist/contexts/NotificationContextBase.js +6 -0
- package/dist/contexts/NotificationContextBase.js.map +1 -0
- package/dist/hooks/useAnimatedProgress.js +17 -0
- package/dist/hooks/useAnimatedProgress.js.map +1 -0
- package/dist/hooks/useCyberNotifications.js +14 -0
- package/dist/hooks/useCyberNotifications.js.map +1 -0
- package/dist/hooks/useCyberScrollbar.js +254 -0
- package/dist/hooks/useCyberScrollbar.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +63 -5954
- package/dist/index.js +13 -13
- package/dist/utils/cn.js +9 -0
- package/dist/utils/cn.js.map +1 -0
- package/dist/utils/devWarn.d.ts +5 -0
- package/dist/utils/devWarn.js +8 -0
- package/dist/utils/devWarn.js.map +1 -0
- package/dist/utils/responsive.js +120 -0
- package/dist/utils/responsive.js.map +1 -0
- package/package.json +158 -125
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { j as t } from "../_virtual/jsx-runtime.js";
|
|
2
|
+
import { memo as V, useMemo as R, useState as S, useRef as m, useCallback as i, useEffect as A } from "react";
|
|
3
|
+
import { createPortal as X } from "react-dom";
|
|
4
|
+
import T from "./Button.js";
|
|
5
|
+
import { cn as f } from "../utils/cn.js";
|
|
6
|
+
const Y = {
|
|
7
|
+
openDuration: 600,
|
|
8
|
+
closeDuration: 400,
|
|
9
|
+
crtEffects: !0
|
|
10
|
+
}, O = {
|
|
11
|
+
sm: "max-w-md",
|
|
12
|
+
md: "max-w-lg",
|
|
13
|
+
lg: "max-w-2xl",
|
|
14
|
+
xl: "max-w-4xl",
|
|
15
|
+
fullscreen: "max-w-none w-full h-full"
|
|
16
|
+
}, ee = V(
|
|
17
|
+
({
|
|
18
|
+
isOpen: c,
|
|
19
|
+
onClose: b,
|
|
20
|
+
title: p,
|
|
21
|
+
children: W,
|
|
22
|
+
footer: x,
|
|
23
|
+
onCancel: d,
|
|
24
|
+
onConfirm: u,
|
|
25
|
+
cancelText: z = "Cancel",
|
|
26
|
+
confirmText: F = "Confirm",
|
|
27
|
+
confirmLoading: P = !1,
|
|
28
|
+
showCancel: U = !0,
|
|
29
|
+
showConfirm: _ = !0,
|
|
30
|
+
size: g = "lg",
|
|
31
|
+
variant: l = "default",
|
|
32
|
+
closeOnOverlayClick: w = !0,
|
|
33
|
+
closeOnEscape: v = !0,
|
|
34
|
+
animation: k,
|
|
35
|
+
className: j = "",
|
|
36
|
+
overlayClassName: B = "",
|
|
37
|
+
showCloseButton: G = !0,
|
|
38
|
+
onOpen: N,
|
|
39
|
+
onCRTBootComplete: E
|
|
40
|
+
}) => {
|
|
41
|
+
const a = R(
|
|
42
|
+
() => ({ ...Y, ...k }),
|
|
43
|
+
[k]
|
|
44
|
+
), [n, $] = S(!1), [o, h] = S(!0), C = m(null), D = m(null), I = m(null), L = m(`modal-title-${Math.random().toString(36).slice(2)}`), r = i(() => {
|
|
45
|
+
$(!0), setTimeout(() => {
|
|
46
|
+
$(!1), h(!0), b();
|
|
47
|
+
}, a.closeDuration);
|
|
48
|
+
}, [b, a.closeDuration]);
|
|
49
|
+
A(() => {
|
|
50
|
+
c && !n && (I.current = document.activeElement || null, h(!0), N?.(), setTimeout(() => {
|
|
51
|
+
h(!1), E?.(), D.current?.focus();
|
|
52
|
+
}, a.openDuration));
|
|
53
|
+
}, [
|
|
54
|
+
c,
|
|
55
|
+
n,
|
|
56
|
+
N,
|
|
57
|
+
E,
|
|
58
|
+
a.openDuration
|
|
59
|
+
]);
|
|
60
|
+
const K = i(() => {
|
|
61
|
+
d?.(), r();
|
|
62
|
+
}, [d, r]), Z = i(() => {
|
|
63
|
+
u?.(), r();
|
|
64
|
+
}, [u, r]), q = i(
|
|
65
|
+
(e) => {
|
|
66
|
+
w && (e.target === C.current || e.target === e.currentTarget) && r();
|
|
67
|
+
},
|
|
68
|
+
[r, w]
|
|
69
|
+
), y = i(
|
|
70
|
+
(e) => {
|
|
71
|
+
v && e.key === "Escape" && r();
|
|
72
|
+
},
|
|
73
|
+
[r, v]
|
|
74
|
+
);
|
|
75
|
+
A(() => {
|
|
76
|
+
if (c) {
|
|
77
|
+
document.addEventListener("keydown", y);
|
|
78
|
+
const e = document.body.style.overflow, s = window.innerWidth - document.documentElement.clientWidth;
|
|
79
|
+
return document.body.style.overflow = "hidden", document.body.style.paddingRight = `${s}px`, () => {
|
|
80
|
+
document.removeEventListener("keydown", y), document.body.style.overflow = e, document.body.style.paddingRight = "", I.current?.focus?.();
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}, [c, y]);
|
|
84
|
+
const H = R(() => {
|
|
85
|
+
const e = l === "danger", s = e ? "border-error" : "border-accent", M = e ? "shadow-error" : "shadow-lg-accent", J = e ? "shadow-error/50" : "shadow-input-accent/50", Q = e ? "animate-danger-glow" : "animate-rgb-glow";
|
|
86
|
+
return f(
|
|
87
|
+
"relative bg-surface border-2 rounded-lg max-h-[90vh] overflow-hidden flex flex-col transform transition-all duration-300",
|
|
88
|
+
O[g],
|
|
89
|
+
a.crtEffects && o ? `animate-crt-power-on ${s} ${M}` : a.crtEffects && n ? `animate-crt-power-off ${s} ${M}` : n ? `scale-95 opacity-0 ${s}/20` : o ? `scale-105 opacity-90 ${s} ${J}` : `scale-100 opacity-100 ${Q}`,
|
|
90
|
+
j
|
|
91
|
+
);
|
|
92
|
+
}, [g, a.crtEffects, n, o, j, l]);
|
|
93
|
+
return c ? X(
|
|
94
|
+
/* @__PURE__ */ t.jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
ref: C,
|
|
98
|
+
className: `fixed z-50 flex items-center justify-center p-4 transition-all ease-out ${B} ${n ? "bg-black/0 backdrop-blur-none opacity-0 duration-800" : o ? "bg-black/30 backdrop-blur-md opacity-100 duration-500" : "bg-black/30 backdrop-blur-sm opacity-100 duration-300"}`,
|
|
99
|
+
style: {
|
|
100
|
+
top: 0,
|
|
101
|
+
left: 0,
|
|
102
|
+
width: "100vw",
|
|
103
|
+
height: "100vh"
|
|
104
|
+
},
|
|
105
|
+
onClick: q,
|
|
106
|
+
"aria-hidden": !0,
|
|
107
|
+
children: /* @__PURE__ */ t.jsxs(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
ref: D,
|
|
111
|
+
className: H,
|
|
112
|
+
onClick: (e) => e.stopPropagation(),
|
|
113
|
+
role: "dialog",
|
|
114
|
+
"aria-modal": "true",
|
|
115
|
+
"aria-labelledby": p ? L.current : void 0,
|
|
116
|
+
tabIndex: -1,
|
|
117
|
+
children: [
|
|
118
|
+
G && /* @__PURE__ */ t.jsx(
|
|
119
|
+
"button",
|
|
120
|
+
{
|
|
121
|
+
onClick: r,
|
|
122
|
+
className: `absolute top-4 right-4 text-muted hover:text-accent transition-all duration-300 z-20 rounded-full w-8 h-8 flex items-center justify-center cursor-pointer transform ${n ? "scale-0 rotate-180 opacity-0" : o ? "scale-0 opacity-0" : "scale-100 opacity-100 hover:scale-110 hover:bg-accent/10"}`,
|
|
123
|
+
"aria-label": "Close modal",
|
|
124
|
+
children: /* @__PURE__ */ t.jsx(
|
|
125
|
+
"svg",
|
|
126
|
+
{
|
|
127
|
+
width: "14",
|
|
128
|
+
height: "14",
|
|
129
|
+
viewBox: "0 0 16 16",
|
|
130
|
+
fill: "none",
|
|
131
|
+
className: "relative",
|
|
132
|
+
children: /* @__PURE__ */ t.jsx(
|
|
133
|
+
"path",
|
|
134
|
+
{
|
|
135
|
+
d: "M12 4L4 12M4 4L12 12",
|
|
136
|
+
stroke: "currentColor",
|
|
137
|
+
strokeWidth: "2",
|
|
138
|
+
strokeLinecap: "round",
|
|
139
|
+
strokeLinejoin: "round"
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
),
|
|
146
|
+
p && /* @__PURE__ */ t.jsx(
|
|
147
|
+
"div",
|
|
148
|
+
{
|
|
149
|
+
className: f(
|
|
150
|
+
"px-6 py-4 border-b flex-shrink-0 transition-all duration-300",
|
|
151
|
+
l === "danger" ? "border-error/20" : "border-accent/20",
|
|
152
|
+
o ? "opacity-0 translate-y-2" : "opacity-100 translate-y-0"
|
|
153
|
+
),
|
|
154
|
+
children: /* @__PURE__ */ t.jsx(
|
|
155
|
+
"h2",
|
|
156
|
+
{
|
|
157
|
+
id: L.current,
|
|
158
|
+
className: f("text-lg font-semibold", l === "danger" ? "text-error" : "text-primary"),
|
|
159
|
+
children: p
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
),
|
|
164
|
+
/* @__PURE__ */ t.jsx(
|
|
165
|
+
"div",
|
|
166
|
+
{
|
|
167
|
+
className: `flex-1 overflow-auto p-6 transition-all duration-500 ${o ? "opacity-0 translate-y-4" : "opacity-100 translate-y-0"}`,
|
|
168
|
+
children: W
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
(x || d || u) && /* @__PURE__ */ t.jsx(
|
|
172
|
+
"div",
|
|
173
|
+
{
|
|
174
|
+
className: f(
|
|
175
|
+
"px-6 py-4 border-t flex-shrink-0 transition-all duration-300",
|
|
176
|
+
l === "danger" ? "border-error/20" : "border-accent/20",
|
|
177
|
+
o ? "opacity-0 translate-y-2" : "opacity-100 translate-y-0"
|
|
178
|
+
),
|
|
179
|
+
children: x || /* @__PURE__ */ t.jsxs("div", { className: "flex flex-col-reverse sm:flex-row justify-between items-center gap-3", children: [
|
|
180
|
+
/* @__PURE__ */ t.jsx("span", { className: "text-muted text-xs font-mono hidden sm:block", children: "> ESC to abort" }),
|
|
181
|
+
/* @__PURE__ */ t.jsxs("div", { className: "flex gap-3 w-full sm:w-auto", children: [
|
|
182
|
+
U && d && /* @__PURE__ */ t.jsx(T, { variant: "ghost", size: "sm", onClick: K, className: "flex-1 sm:flex-none", children: z }),
|
|
183
|
+
_ && u && /* @__PURE__ */ t.jsx(
|
|
184
|
+
T,
|
|
185
|
+
{
|
|
186
|
+
variant: l === "danger" ? "danger" : "primary",
|
|
187
|
+
size: "sm",
|
|
188
|
+
onClick: Z,
|
|
189
|
+
disabled: P,
|
|
190
|
+
className: "flex-1 sm:flex-none",
|
|
191
|
+
children: F
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
] })
|
|
195
|
+
] })
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
),
|
|
203
|
+
document.body
|
|
204
|
+
) : null;
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
ee.displayName = "CyberUI.Modal";
|
|
208
|
+
export {
|
|
209
|
+
ee as default
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=Modal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Modal.js","sources":["../../src/components/Modal.tsx"],"sourcesContent":["import React, {\r\n useState,\r\n useEffect,\r\n useRef,\r\n useCallback,\r\n memo,\r\n useMemo,\r\n} from \"react\";\r\nimport { createPortal } from \"react-dom\";\r\nimport Button from \"./Button\";\r\nimport { cn } from \"../utils/cn\";\r\n\r\n/**\r\n * Controls CRT animation timing and effects.\r\n * Pass this as the `animation` prop on `<Modal>`:\r\n * ```tsx\r\n * <Modal animation={{ openDuration: 300, crtEffects: false }} ... />\r\n * ```\r\n */\r\nexport interface ModalAnimationConfig {\r\n /** Duration of the open (CRT boot) animation in ms. @default 600 */\r\n openDuration?: number;\r\n /** Duration of the close (CRT off) animation in ms. @default 400 */\r\n closeDuration?: number;\r\n /** Enable CRT scanline power-on/off effects. @default true */\r\n crtEffects?: boolean;\r\n}\r\n\r\n/**\r\n * Lifecycle event handlers for the modal.\r\n * These are flat props on `<Modal>` — not nested under `animation`:\r\n * ```tsx\r\n * <Modal onOpen={track} onClose={cleanup} ... />\r\n * ```\r\n */\r\nexport interface ModalCallbacks {\r\n /** Fired when the modal begins opening (before animation completes). */\r\n onOpen?: () => void;\r\n /** Fired when the modal has fully closed. Alias of `onClose` for clarity. */\r\n onClose?: () => void;\r\n /** Fired when the CRT boot animation finishes and the modal is fully visible. */\r\n onCRTBootComplete?: () => void;\r\n}\r\n\r\n/**\r\n * A CRT-styled modal dialog with retro animation effects.\r\n *\r\n * @example\r\n * // Basic modal\r\n * <Modal isOpen={isOpen} onClose={close} title=\"System Alert\">\r\n * <p>Breach detected in sector 7.</p>\r\n * </Modal>\r\n *\r\n * @example\r\n * // Confirmation modal with custom actions\r\n * <Modal\r\n * isOpen={isOpen}\r\n * onClose={close}\r\n * title=\"Confirm Override\"\r\n * onConfirm={handleConfirm}\r\n * confirmText=\"EXECUTE\"\r\n * variant=\"danger\"\r\n * >\r\n * Are you sure you want to override safety protocols?\r\n * </Modal>\r\n */\r\nexport interface ModalProps extends ModalCallbacks {\r\n /**\r\n * Whether the modal is visible.\r\n */\r\n isOpen: boolean;\r\n /**\r\n * Callback when the modal requests to close.\r\n */\r\n onClose: () => void;\r\n /** Title text shown in the modal header. */\r\n title?: string;\r\n /** The content to be rendered inside the modal body. */\r\n children: React.ReactNode;\r\n /**\r\n * Custom footer content. Overrides the default Cancel/Confirm action buttons\r\n * (`onCancel`/`onConfirm` and related props are ignored when `footer` is set).\r\n */\r\n footer?: React.ReactNode;\r\n // Action props (Ant Design pattern) — rendered as the default footer when `footer` is not set.\r\n /** Fired when the Cancel button is clicked. Only rendered if provided. */\r\n onCancel?: () => void;\r\n /** Fired when the Confirm button is clicked. Only rendered if provided. */\r\n onConfirm?: () => void;\r\n /** Label for the Cancel button. @default 'Cancel' */\r\n cancelText?: string;\r\n /** Label for the Confirm button. @default 'Confirm' */\r\n confirmText?: string;\r\n /** Shows a loading state and disables the Confirm button. @default false */\r\n confirmLoading?: boolean;\r\n /** Whether to render the Cancel button (requires `onCancel`). @default true */\r\n showCancel?: boolean;\r\n /** Whether to render the Confirm button (requires `onConfirm`). @default true */\r\n showConfirm?: boolean;\r\n /**\r\n * Width of the modal.\r\n * - sm: 448px, md: 512px, lg: 672px, xl: 896px\r\n * Use `lg` or `xl` for content-heavy modals (forms, tables, multi-step flows).\r\n * @default 'lg'\r\n */\r\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"fullscreen\";\r\n /**\r\n * Visual variant of the modal.\r\n * - `default`: Standard RGB glow border.\r\n * - `danger`: Red error glow — use for destructive confirmations.\r\n * @default 'default'\r\n */\r\n variant?: \"default\" | \"danger\";\r\n /** Whether clicking the overlay backdrop closes the modal. @default true */\r\n closeOnOverlayClick?: boolean;\r\n /** Whether pressing Escape closes the modal. @default true */\r\n closeOnEscape?: boolean;\r\n /** CRT open/close animation timing and effects. */\r\n animation?: ModalAnimationConfig;\r\n /** Additional CSS classes for the modal panel. */\r\n className?: string;\r\n /** Additional CSS classes for the overlay backdrop. */\r\n overlayClassName?: string;\r\n /** Whether to render the header close (×) button. @default true */\r\n showCloseButton?: boolean;\r\n}\r\n\r\nconst DEFAULT_ANIMATION: Required<ModalAnimationConfig> = {\r\n openDuration: 600,\r\n closeDuration: 400,\r\n crtEffects: true,\r\n};\r\n\r\nconst SIZE_CLASSES = {\r\n sm: \"max-w-md\",\r\n md: \"max-w-lg\",\r\n lg: \"max-w-2xl\",\r\n xl: \"max-w-4xl\",\r\n fullscreen: \"max-w-none w-full h-full\",\r\n};\r\n\r\n/**\r\n * A cinematic Cyberpunk modal with CRT boot-up effects, RGB glow, and immersive animations.\r\n * \r\n * @example\r\n * <Modal \r\n * isOpen={isOpen} \r\n * onClose={() => setOpen(false)} \r\n * title=\"DANGER: SYSTEM OVERLOAD\"\r\n * onConfirm={initPurge}\r\n * >\r\n * <p>Initiate emergency cooling sequence?</p>\r\n * </Modal>\r\n */\r\nconst Modal: React.FC<ModalProps> = memo(\r\n ({\r\n isOpen,\r\n onClose,\r\n title,\r\n children,\r\n footer,\r\n onCancel,\r\n onConfirm,\r\n cancelText = \"Cancel\",\r\n confirmText = \"Confirm\",\r\n confirmLoading = false,\r\n showCancel = true,\r\n showConfirm = true,\r\n size = \"lg\",\r\n variant = \"default\",\r\n closeOnOverlayClick = true,\r\n closeOnEscape = true,\r\n animation,\r\n className = \"\",\r\n overlayClassName = \"\",\r\n showCloseButton = true,\r\n onOpen,\r\n onCRTBootComplete,\r\n }) => {\r\n const animationConfig = useMemo(\r\n () => ({ ...DEFAULT_ANIMATION, ...animation }),\r\n [animation]\r\n );\r\n\r\n const [isClosing, setIsClosing] = useState(false);\r\n const [isOpening, setIsOpening] = useState(true);\r\n\r\n const overlayRef = useRef<HTMLDivElement>(null);\r\n const modalRef = useRef<HTMLDivElement>(null);\r\n const previouslyFocusedRef = useRef<HTMLElement | null>(null);\r\n const titleIdRef = useRef<string>(`modal-title-${Math.random().toString(36).slice(2)}`);\r\n\r\n const closeModal = useCallback(() => {\r\n setIsClosing(true);\r\n\r\n setTimeout(() => {\r\n setIsClosing(false);\r\n setIsOpening(true);\r\n onClose();\r\n }, animationConfig.closeDuration);\r\n }, [onClose, animationConfig.closeDuration]);\r\n\r\n useEffect(() => {\r\n if (isOpen && !isClosing) {\r\n previouslyFocusedRef.current = (document.activeElement as HTMLElement) || null;\r\n setIsOpening(true);\r\n onOpen?.();\r\n\r\n setTimeout(() => {\r\n setIsOpening(false);\r\n onCRTBootComplete?.();\r\n // Focus the modal container for accessibility\r\n modalRef.current?.focus();\r\n }, animationConfig.openDuration);\r\n }\r\n }, [\r\n isOpen,\r\n isClosing,\r\n onOpen,\r\n onCRTBootComplete,\r\n animationConfig.openDuration,\r\n ]);\r\n\r\n // Wrapped footer actions that use closeModal logic\r\n const wrappedCancel = useCallback(() => {\r\n onCancel?.();\r\n closeModal();\r\n }, [onCancel, closeModal]);\r\n\r\n const wrappedConfirm = useCallback(() => {\r\n onConfirm?.();\r\n closeModal();\r\n }, [onConfirm, closeModal]);\r\n\r\n const handleOverlayClick = useCallback(\r\n (e: React.MouseEvent) => {\r\n if (\r\n closeOnOverlayClick &&\r\n (e.target === overlayRef.current || e.target === e.currentTarget)\r\n ) {\r\n closeModal();\r\n }\r\n },\r\n [closeModal, closeOnOverlayClick]\r\n );\r\n\r\n const handleKeyDown = useCallback(\r\n (e: KeyboardEvent) => {\r\n if (closeOnEscape && e.key === \"Escape\") {\r\n closeModal();\r\n }\r\n },\r\n [closeModal, closeOnEscape]\r\n );\r\n\r\n useEffect(() => {\r\n if (isOpen) {\r\n document.addEventListener(\"keydown\", handleKeyDown);\r\n const originalOverflow = document.body.style.overflow;\r\n const scrollbarWidth =\r\n window.innerWidth - document.documentElement.clientWidth;\r\n\r\n document.body.style.overflow = \"hidden\";\r\n document.body.style.paddingRight = `${scrollbarWidth}px`;\r\n\r\n return () => {\r\n document.removeEventListener(\"keydown\", handleKeyDown);\r\n document.body.style.overflow = originalOverflow;\r\n document.body.style.paddingRight = \"\";\r\n // Restore focus to the previously focused element if possible\r\n previouslyFocusedRef.current?.focus?.();\r\n };\r\n }\r\n }, [isOpen, handleKeyDown]);\r\n\r\n const modalClasses = useMemo(() => {\r\n const danger = variant === \"danger\";\r\n const border = danger ? \"border-error\" : \"border-accent\";\r\n const glow = danger ? \"shadow-error\" : \"shadow-lg-accent\";\r\n const inputGlow = danger ? \"shadow-error/50\" : \"shadow-input-accent/50\";\r\n const idleAnim = danger ? \"animate-danger-glow\" : \"animate-rgb-glow\";\r\n\r\n return cn(\r\n \"relative bg-surface border-2 rounded-lg max-h-[90vh] overflow-hidden flex flex-col transform transition-all duration-300\",\r\n SIZE_CLASSES[size],\r\n animationConfig.crtEffects && isOpening\r\n ? `animate-crt-power-on ${border} ${glow}`\r\n : animationConfig.crtEffects && isClosing\r\n ? `animate-crt-power-off ${border} ${glow}`\r\n : isClosing\r\n ? `scale-95 opacity-0 ${border}/20`\r\n : isOpening\r\n ? `scale-105 opacity-90 ${border} ${inputGlow}`\r\n : `scale-100 opacity-100 ${idleAnim}`,\r\n className\r\n );\r\n }, [size, animationConfig.crtEffects, isClosing, isOpening, className, variant]);\r\n\r\n if (!isOpen) return null;\r\n\r\n return createPortal(\r\n <div\r\n ref={overlayRef}\r\n className={`fixed z-50 flex items-center justify-center p-4 transition-all ease-out ${overlayClassName} ${\r\n isClosing\r\n ? \"bg-black/0 backdrop-blur-none opacity-0 duration-800\"\r\n : isOpening\r\n ? \"bg-black/30 backdrop-blur-md opacity-100 duration-500\"\r\n : \"bg-black/30 backdrop-blur-sm opacity-100 duration-300\"\r\n }`}\r\n style={{\r\n top: 0,\r\n left: 0,\r\n width: \"100vw\",\r\n height: \"100vh\",\r\n }}\r\n onClick={handleOverlayClick}\r\n aria-hidden={true}\r\n >\r\n <div\r\n ref={modalRef}\r\n className={modalClasses}\r\n onClick={(e) => e.stopPropagation()}\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby={title ? titleIdRef.current : undefined}\r\n tabIndex={-1}\r\n >\r\n {showCloseButton && (\r\n <button\r\n onClick={closeModal}\r\n className={`absolute top-4 right-4 text-muted hover:text-accent transition-all duration-300 z-20 rounded-full w-8 h-8 flex items-center justify-center cursor-pointer transform ${\r\n isClosing\r\n ? \"scale-0 rotate-180 opacity-0\"\r\n : isOpening\r\n ? \"scale-0 opacity-0\"\r\n : \"scale-100 opacity-100 hover:scale-110 hover:bg-accent/10\"\r\n }`}\r\n aria-label=\"Close modal\"\r\n >\r\n <svg\r\n width=\"14\"\r\n height=\"14\"\r\n viewBox=\"0 0 16 16\"\r\n fill=\"none\"\r\n className=\"relative\"\r\n >\r\n <path\r\n d=\"M12 4L4 12M4 4L12 12\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n />\r\n </svg>\r\n </button>\r\n )}\r\n\r\n {title && (\r\n <div\r\n className={cn(\r\n \"px-6 py-4 border-b flex-shrink-0 transition-all duration-300\",\r\n variant === \"danger\" ? \"border-error/20\" : \"border-accent/20\",\r\n !isOpening ? \"opacity-100 translate-y-0\" : \"opacity-0 translate-y-2\"\r\n )}\r\n >\r\n <h2\r\n id={titleIdRef.current}\r\n className={cn(\"text-lg font-semibold\", variant === \"danger\" ? \"text-error\" : \"text-primary\")}\r\n >\r\n {title}\r\n </h2>\r\n </div>\r\n )}\r\n\r\n <div\r\n className={`flex-1 overflow-auto p-6 transition-all duration-500 ${\r\n !isOpening\r\n ? \"opacity-100 translate-y-0\"\r\n : \"opacity-0 translate-y-4\"\r\n }`}\r\n >\r\n {children}\r\n </div>\r\n\r\n {(footer || onCancel || onConfirm) && (\r\n <div\r\n className={cn(\r\n \"px-6 py-4 border-t flex-shrink-0 transition-all duration-300\",\r\n variant === \"danger\" ? \"border-error/20\" : \"border-accent/20\",\r\n !isOpening ? \"opacity-100 translate-y-0\" : \"opacity-0 translate-y-2\"\r\n )}\r\n >\r\n {footer ? (\r\n footer\r\n ) : (\r\n <div className=\"flex flex-col-reverse sm:flex-row justify-between items-center gap-3\">\r\n <span className=\"text-muted text-xs font-mono hidden sm:block\">\r\n > ESC to abort\r\n </span>\r\n <div className=\"flex gap-3 w-full sm:w-auto\">\r\n {showCancel && onCancel && (\r\n <Button variant=\"ghost\" size=\"sm\" onClick={wrappedCancel} className=\"flex-1 sm:flex-none\">\r\n {cancelText}\r\n </Button>\r\n )}\r\n {showConfirm && onConfirm && (\r\n <Button\r\n variant={variant === \"danger\" ? \"danger\" : \"primary\"}\r\n size=\"sm\"\r\n onClick={wrappedConfirm}\r\n disabled={confirmLoading}\r\n className=\"flex-1 sm:flex-none\"\r\n >\r\n {confirmText}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n </div>,\r\n document.body\r\n );\r\n }\r\n);\r\n\r\nModal.displayName = \"CyberUI.Modal\";\r\n\r\nexport default Modal;\r\n"],"names":["DEFAULT_ANIMATION","SIZE_CLASSES","Modal","memo","isOpen","onClose","title","children","footer","onCancel","onConfirm","cancelText","confirmText","confirmLoading","showCancel","showConfirm","size","variant","closeOnOverlayClick","closeOnEscape","animation","className","overlayClassName","showCloseButton","onOpen","onCRTBootComplete","animationConfig","useMemo","isClosing","setIsClosing","useState","isOpening","setIsOpening","overlayRef","useRef","modalRef","previouslyFocusedRef","titleIdRef","closeModal","useCallback","useEffect","wrappedCancel","wrappedConfirm","handleOverlayClick","handleKeyDown","originalOverflow","scrollbarWidth","modalClasses","danger","border","glow","inputGlow","idleAnim","cn","createPortal","jsx","jsxs","Button"],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { j as e } from "../_virtual/jsx-runtime.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { getResponsiveClasses as u, RESPONSIVE_SIZE_MAPS as h } from "../utils/responsive.js";
|
|
4
|
+
const f = ({
|
|
5
|
+
type: t,
|
|
6
|
+
title: l,
|
|
7
|
+
message: a,
|
|
8
|
+
size: o = "md",
|
|
9
|
+
onClose: r
|
|
10
|
+
}) => {
|
|
11
|
+
const i = (x) => u(x, h.notification), s = (() => {
|
|
12
|
+
switch (t) {
|
|
13
|
+
case "success":
|
|
14
|
+
return {
|
|
15
|
+
container: "bg-linear-(--gradient-accent) shadow-lg-accent",
|
|
16
|
+
textColor: "text-base",
|
|
17
|
+
icon: /* @__PURE__ */ e.jsx("svg", { className: "w-6 h-6 text-base", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e.jsx(
|
|
18
|
+
"path",
|
|
19
|
+
{
|
|
20
|
+
fillRule: "evenodd",
|
|
21
|
+
d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",
|
|
22
|
+
clipRule: "evenodd"
|
|
23
|
+
}
|
|
24
|
+
) })
|
|
25
|
+
};
|
|
26
|
+
case "warning":
|
|
27
|
+
return {
|
|
28
|
+
container: "bg-surface border-l-4 border-secondary shadow-lg",
|
|
29
|
+
textColor: "text-default",
|
|
30
|
+
icon: /* @__PURE__ */ e.jsx("svg", { className: "w-6 h-6 text-secondary", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e.jsx(
|
|
31
|
+
"path",
|
|
32
|
+
{
|
|
33
|
+
fillRule: "evenodd",
|
|
34
|
+
d: "M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z",
|
|
35
|
+
clipRule: "evenodd"
|
|
36
|
+
}
|
|
37
|
+
) })
|
|
38
|
+
};
|
|
39
|
+
case "error":
|
|
40
|
+
return {
|
|
41
|
+
container: "bg-error shadow-error",
|
|
42
|
+
textColor: "text-base",
|
|
43
|
+
icon: /* @__PURE__ */ e.jsx("svg", { className: "w-6 h-6 text-base", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e.jsx(
|
|
44
|
+
"path",
|
|
45
|
+
{
|
|
46
|
+
fillRule: "evenodd",
|
|
47
|
+
d: "M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z",
|
|
48
|
+
clipRule: "evenodd"
|
|
49
|
+
}
|
|
50
|
+
) })
|
|
51
|
+
};
|
|
52
|
+
default:
|
|
53
|
+
return {
|
|
54
|
+
container: "bg-surface border-l-4 border-secondary shadow-lg",
|
|
55
|
+
textColor: "text-default",
|
|
56
|
+
icon: null
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
})(), n = i(o), c = t === "error" ? "alert" : "status", d = t === "warning" ? "hover:text-default/70" : "hover:text-base/70";
|
|
60
|
+
return /* @__PURE__ */ e.jsxs("div", { className: `flex items-start rounded-lg ${n} ${s.container}`, role: c, "aria-atomic": "true", children: [
|
|
61
|
+
/* @__PURE__ */ e.jsx("div", { className: "flex-shrink-0", children: s.icon }),
|
|
62
|
+
/* @__PURE__ */ e.jsxs("div", { className: "flex-1", children: [
|
|
63
|
+
/* @__PURE__ */ e.jsx("h4", { className: `font-bold ${s.textColor}`, children: l }),
|
|
64
|
+
/* @__PURE__ */ e.jsx("p", { className: `${t === "success" || t === "error" ? "text-base/80" : "text-muted"} text-sm mt-1`, children: a })
|
|
65
|
+
] }),
|
|
66
|
+
r && /* @__PURE__ */ e.jsx(
|
|
67
|
+
"button",
|
|
68
|
+
{
|
|
69
|
+
className: `flex-shrink-0 ${s.textColor} ${d} transition-colors cursor-pointer`,
|
|
70
|
+
onClick: r,
|
|
71
|
+
"aria-label": "Close notification",
|
|
72
|
+
children: /* @__PURE__ */ e.jsx("svg", { className: "w-5 h-5", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e.jsx(
|
|
73
|
+
"path",
|
|
74
|
+
{
|
|
75
|
+
fillRule: "evenodd",
|
|
76
|
+
d: "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
|
|
77
|
+
clipRule: "evenodd"
|
|
78
|
+
}
|
|
79
|
+
) })
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
] });
|
|
83
|
+
};
|
|
84
|
+
f.displayName = "CyberUI.Notification";
|
|
85
|
+
export {
|
|
86
|
+
f as default
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=Notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Notification.js","sources":["../../src/components/Notification.tsx"],"sourcesContent":["import React from 'react';\r\nimport type { ResponsiveValue } from '../utils/responsive';\r\nimport { getResponsiveClasses, RESPONSIVE_SIZE_MAPS } from '../utils/responsive';\r\n\r\n/**\r\n * A toast notification component with status indicators.\r\n *\r\n * @example\r\n * // Success notification\r\n * <Notification\r\n * type=\"success\"\r\n * title=\"Upload Complete\"\r\n * message=\"Data transfer finished successfully.\"\r\n * />\r\n *\r\n * @example\r\n * // Error notification with close handler\r\n * <Notification\r\n * type=\"error\"\r\n * title=\"Connection Failed\"\r\n * message=\"Unable to reach the mainframe.\"\r\n * onClose={handleClose}\r\n * />\r\n */\r\nexport interface NotificationProps {\r\n /**\r\n * Semantic type of the notification.\r\n */\r\n type: 'success' | 'warning' | 'error';\r\n /** Bold title for the notification */\r\n title: string;\r\n /** Detailed message content */\r\n message: string;\r\n /**\r\n * Size of the notification.\r\n * @default 'md'\r\n */\r\n size?: ResponsiveValue<'sm' | 'md' | 'lg'>;\r\n /** Optional callback for when the close button is clicked */\r\n onClose?: () => void;\r\n}\r\n\r\n/**\r\n * A cyberpunk-themed toast or inline notification for system alerts and status updates.\r\n * \r\n * @example\r\n * <Notification \r\n * type=\"success\" \r\n * title=\"Neural Link Established\" \r\n * message=\"Connection stable at 0.3ms latency.\" \r\n * />\r\n */\r\nconst Notification: React.FC<NotificationProps> = ({\r\n type,\r\n title,\r\n message,\r\n size = 'md',\r\n onClose\r\n}) => {\r\n const getSizeClasses = (size: ResponsiveValue<'sm' | 'md' | 'lg'>): string => {\r\n return getResponsiveClasses(size, RESPONSIVE_SIZE_MAPS.notification);\r\n };\r\n\r\n const getNotificationStyles = () => {\r\n switch (type) {\r\n case 'success':\r\n return {\r\n container: 'bg-linear-(--gradient-accent) shadow-lg-accent',\r\n textColor: 'text-base',\r\n icon: (\r\n <svg className=\"w-6 h-6 text-base\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path\r\n fillRule=\"evenodd\"\r\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\r\n clipRule=\"evenodd\"\r\n />\r\n </svg>\r\n )\r\n };\r\n case 'warning':\r\n return {\r\n container: 'bg-surface border-l-4 border-secondary shadow-lg',\r\n textColor: 'text-default',\r\n icon: (\r\n <svg className=\"w-6 h-6 text-secondary\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path\r\n fillRule=\"evenodd\"\r\n d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\"\r\n clipRule=\"evenodd\"\r\n />\r\n </svg>\r\n )\r\n };\r\n case 'error':\r\n return {\r\n container: 'bg-error shadow-error',\r\n textColor: 'text-base',\r\n icon: (\r\n <svg className=\"w-6 h-6 text-base\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path\r\n fillRule=\"evenodd\"\r\n d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\r\n clipRule=\"evenodd\"\r\n />\r\n </svg>\r\n )\r\n };\r\n default:\r\n return {\r\n container: 'bg-surface border-l-4 border-secondary shadow-lg',\r\n textColor: 'text-default',\r\n icon: null\r\n };\r\n }\r\n };\r\n\r\n const styles = getNotificationStyles();\r\n const sizeClasses = getSizeClasses(size);\r\n const role = type === 'error' ? 'alert' : 'status';\r\n const hoverTextClass = type === 'warning' ? 'hover:text-default/70' : 'hover:text-base/70';\r\n\r\n return (\r\n <div className={`flex items-start rounded-lg ${sizeClasses} ${styles.container}`} role={role} aria-atomic=\"true\">\r\n <div className=\"flex-shrink-0\">\r\n {styles.icon}\r\n </div>\r\n <div className=\"flex-1\">\r\n <h4 className={`font-bold ${styles.textColor}`}>\r\n {title}\r\n </h4>\r\n <p className={`${type === 'success' || type === 'error' ? 'text-base/80' : 'text-muted'} text-sm mt-1`}>\r\n {message}\r\n </p>\r\n </div>\r\n {onClose && (\r\n <button\r\n className={`flex-shrink-0 ${styles.textColor} ${hoverTextClass} transition-colors cursor-pointer`}\r\n onClick={onClose}\r\n aria-label=\"Close notification\"\r\n >\r\n <svg className=\"w-5 h-5\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\r\n <path\r\n fillRule=\"evenodd\"\r\n d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\"\r\n clipRule=\"evenodd\"\r\n />\r\n </svg>\r\n </button>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nNotification.displayName = \"CyberUI.Notification\";\r\n\r\nexport default Notification;\r\n"],"names":["Notification","type","title","message","size","onClose","getSizeClasses","getResponsiveClasses","RESPONSIVE_SIZE_MAPS","styles","jsx","sizeClasses","role","hoverTextClass","jsxs"],"mappings":";;;AAoDA,MAAMA,IAA4C,CAAC;AAAA,EACjD,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,SAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,SAAAC;AACF,MAAM;AACJ,QAAMC,IAAiB,CAACF,MACfG,EAAqBH,GAAMI,EAAqB,YAAY,GAwD/DC,KArDwB,MAAM;AAClC,YAAQR,GAAA;AAAA,MACN,KAAK;AACH,eAAO;AAAA,UACL,WAAW;AAAA,UACX,WAAW;AAAA,UACX,4BACG,OAAA,EAAI,WAAU,qBAAoB,MAAK,gBAAe,SAAQ,aAC7D,UAAAS,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,UAAS;AAAA,cACT,GAAE;AAAA,cACF,UAAS;AAAA,YAAA;AAAA,UAAA,EACX,CACF;AAAA,QAAA;AAAA,MAGN,KAAK;AACH,eAAO;AAAA,UACL,WAAW;AAAA,UACX,WAAW;AAAA,UACX,4BACG,OAAA,EAAI,WAAU,0BAAyB,MAAK,gBAAe,SAAQ,aAClE,UAAAA,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,UAAS;AAAA,cACT,GAAE;AAAA,cACF,UAAS;AAAA,YAAA;AAAA,UAAA,EACX,CACF;AAAA,QAAA;AAAA,MAGN,KAAK;AACH,eAAO;AAAA,UACL,WAAW;AAAA,UACX,WAAW;AAAA,UACX,4BACG,OAAA,EAAI,WAAU,qBAAoB,MAAK,gBAAe,SAAQ,aAC7D,UAAAA,gBAAAA,EAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC,UAAS;AAAA,cACT,GAAE;AAAA,cACF,UAAS;AAAA,YAAA;AAAA,UAAA,EACX,CACF;AAAA,QAAA;AAAA,MAGN;AACE,eAAO;AAAA,UACL,WAAW;AAAA,UACX,WAAW;AAAA,UACX,MAAM;AAAA,QAAA;AAAA,IACR;AAAA,EAEN,GAEe,GACTC,IAAcL,EAAeF,CAAI,GACjCQ,IAAOX,MAAS,UAAU,UAAU,UACpCY,IAAiBZ,MAAS,YAAY,0BAA0B;AAEtE,SACEa,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAW,+BAA+BH,CAAW,IAAIF,EAAO,SAAS,IAAI,MAAAG,GAAY,eAAY,QACxG,UAAA;AAAA,IAAAF,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WAAU,iBACZ,UAAAD,EAAO,MACV;AAAA,IACAK,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,UACb,UAAA;AAAA,MAAAJ,gBAAAA,EAAAA,IAAC,QAAG,WAAW,aAAaD,EAAO,SAAS,IACzC,UAAAP,GACH;AAAA,MACAQ,gBAAAA,EAAAA,IAAC,KAAA,EAAE,WAAW,GAAGT,MAAS,aAAaA,MAAS,UAAU,iBAAiB,YAAY,iBACpF,UAAAE,EAAA,CACH;AAAA,IAAA,GACF;AAAA,IACCE,KACCK,gBAAAA,EAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,iBAAiBD,EAAO,SAAS,IAAII,CAAc;AAAA,QAC9D,SAASR;AAAA,QACT,cAAW;AAAA,QAEX,gCAAC,OAAA,EAAI,WAAU,WAAU,MAAK,gBAAe,SAAQ,aACnD,UAAAK,gBAAAA,EAAAA;AAAAA,UAAC;AAAA,UAAA;AAAA,YACC,UAAS;AAAA,YACT,GAAE;AAAA,YACF,UAAS;AAAA,UAAA;AAAA,QAAA,EACX,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EACF,GAEJ;AAEJ;AAEAV,EAAa,cAAc;"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { j as e } from "../_virtual/jsx-runtime.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { getResponsiveClasses as t } from "../utils/responsive.js";
|
|
4
|
+
import { cn as a } from "../utils/cn.js";
|
|
5
|
+
const C = ({
|
|
6
|
+
children: n,
|
|
7
|
+
showLine: o = !0,
|
|
8
|
+
size: s = "md",
|
|
9
|
+
className: m = ""
|
|
10
|
+
}) => {
|
|
11
|
+
const r = {
|
|
12
|
+
sm: "text-xs",
|
|
13
|
+
md: "text-sm",
|
|
14
|
+
lg: "text-base"
|
|
15
|
+
}, l = {
|
|
16
|
+
sm: "mb-4",
|
|
17
|
+
md: "mb-6",
|
|
18
|
+
lg: "mb-8"
|
|
19
|
+
}, c = {
|
|
20
|
+
sm: "gap-3",
|
|
21
|
+
md: "gap-4",
|
|
22
|
+
lg: "gap-5"
|
|
23
|
+
}, i = t(s, r), p = t(s, l), x = t(s, c), g = a("flex items-center", x, p), d = a("uppercase tracking-[0.2em] text-secondary font-bold whitespace-nowrap", i);
|
|
24
|
+
return /* @__PURE__ */ e.jsxs("div", { className: a(g, m), children: [
|
|
25
|
+
/* @__PURE__ */ e.jsx("h2", { className: d, children: n }),
|
|
26
|
+
o && /* @__PURE__ */ e.jsx("div", { className: "h-[1px] w-full bg-gradient-to-r from-secondary/50 to-transparent" })
|
|
27
|
+
] });
|
|
28
|
+
};
|
|
29
|
+
C.displayName = "CyberUI.SectionTitle";
|
|
30
|
+
export {
|
|
31
|
+
C as default
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=SectionTitle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SectionTitle.js","sources":["../../src/components/SectionTitle.tsx"],"sourcesContent":["import React from 'react';\r\nimport type { ResponsiveValue } from \"../utils/responsive\";\r\nimport { getResponsiveClasses } from \"../utils/responsive\";\r\nimport { cn } from '../utils/cn';\r\n\r\n/**\r\n * A standardized section title with cyberpunk styling.\r\n *\r\n * Features uppercase text, wide letter spacing, and an optional decorative gradient line.\r\n *\r\n * @example\r\n * // Standard title with gradient line\r\n * <SectionTitle>System Status</SectionTitle>\r\n *\r\n * @example\r\n * // Title without decorative line\r\n * <SectionTitle showLine={false}>Heading Only</SectionTitle>\r\n *\r\n * @example\r\n * // With custom styling\r\n * <SectionTitle className=\"mb-8\">Custom Spacing</SectionTitle>\r\n */\r\nexport interface SectionTitleProps {\r\n /**\r\n * The title text content.\r\n */\r\n children: React.ReactNode;\r\n /**\r\n * Whether to show a decorative gradient line after the title.\r\n * @default true\r\n */\r\n showLine?: boolean;\r\n /**\r\n * Size of the section title. Supports responsive values.\r\n * @default 'md'\r\n */\r\n size?: ResponsiveValue<'sm' | 'md' | 'lg'>;\r\n /**\r\n * Additional CSS classes.\r\n */\r\n className?: string;\r\n}\r\n\r\nconst SectionTitle: React.FC<SectionTitleProps> = ({\r\n children,\r\n showLine = true,\r\n size = 'md',\r\n className = '',\r\n}) => {\r\n const textSizeMap = {\r\n sm: 'text-xs',\r\n md: 'text-sm',\r\n lg: 'text-base',\r\n };\r\n\r\n const marginMap = {\r\n sm: 'mb-4',\r\n md: 'mb-6',\r\n lg: 'mb-8',\r\n };\r\n\r\n const gapMap = {\r\n sm: 'gap-3',\r\n md: 'gap-4',\r\n lg: 'gap-5',\r\n };\r\n\r\n const textClasses = getResponsiveClasses(size, textSizeMap);\r\n const marginClasses = getResponsiveClasses(size, marginMap);\r\n const gapClasses = getResponsiveClasses(size, gapMap);\r\n\r\n const baseClasses = cn('flex items-center', gapClasses, marginClasses);\r\n const titleClasses = cn('uppercase tracking-[0.2em] text-secondary font-bold whitespace-nowrap', textClasses);\r\n const lineClasses = 'h-[1px] w-full bg-gradient-to-r from-secondary/50 to-transparent';\r\n\r\n return (\r\n <div className={cn(baseClasses, className)}>\r\n <h2 className={titleClasses}>\r\n {children}\r\n </h2>\r\n {showLine && (\r\n <div className={lineClasses} />\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\nSectionTitle.displayName = \"CyberUI.SectionTitle\";\r\n\r\nexport default SectionTitle;\r\n\r\n"],"names":["SectionTitle","children","showLine","size","className","textSizeMap","marginMap","gapMap","textClasses","getResponsiveClasses","marginClasses","gapClasses","baseClasses","cn","titleClasses","jsx"],"mappings":";;;;AA2CA,MAAMA,IAA4C,CAAC;AAAA,EACjD,UAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AACd,MAAM;AACJ,QAAMC,IAAc;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA,GAGAC,IAAY;AAAA,IAChB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA,GAGAC,IAAS;AAAA,IACb,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA,GAGAC,IAAcC,EAAqBN,GAAME,CAAW,GACpDK,IAAgBD,EAAqBN,GAAMG,CAAS,GACpDK,IAAaF,EAAqBN,GAAMI,CAAM,GAE9CK,IAAcC,EAAG,qBAAqBF,GAAYD,CAAa,GAC/DI,IAAeD,EAAG,yEAAyEL,CAAW;AAG5G,gCACG,OAAA,EAAI,WAAWK,EAAGD,GAAaR,CAAS,GACvC,UAAA;AAAA,IAAAW,gBAAAA,EAAAA,IAAC,MAAA,EAAG,WAAWD,GACZ,UAAAb,EAAA,CACH;AAAA,IACCC,KACCa,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WARS,mEAQE,CAAa;AAAA,EAAA,GAEjC;AAEJ;AAEAf,EAAa,cAAc;"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { j as o } from "../_virtual/jsx-runtime.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { cn as y } from "../utils/cn.js";
|
|
4
|
+
import { PROGRESS_CONFIG as R } from "../constants/index.js";
|
|
5
|
+
const S = {
|
|
6
|
+
sm: "w-16 h-16",
|
|
7
|
+
md: "w-24 h-24",
|
|
8
|
+
lg: "w-32 h-32",
|
|
9
|
+
xl: "w-40 h-40"
|
|
10
|
+
}, w = ({ progress: a, size: l = "md", className: m, children: i }) => {
|
|
11
|
+
const {
|
|
12
|
+
SEGMENT_COUNT: x,
|
|
13
|
+
SEGMENT_ANGLE: M,
|
|
14
|
+
GAP_ANGLE: e,
|
|
15
|
+
INNER_RADIUS: r,
|
|
16
|
+
OUTER_RADIUS: h,
|
|
17
|
+
OUTER_TICK_RADIUS: d
|
|
18
|
+
} = R, I = M - e;
|
|
19
|
+
return /* @__PURE__ */ o.jsxs("div", { className: y("relative", S[l], m), children: [
|
|
20
|
+
/* @__PURE__ */ o.jsxs("svg", { className: "w-full h-full", viewBox: "0 0 60 60", style: { overflow: "visible" }, children: [
|
|
21
|
+
[...Array(60)].map((_, n) => {
|
|
22
|
+
const s = 6 * n, t = n % 5 === 0 ? 6 : 3, u = 30 + d * Math.cos(s * Math.PI / 180), v = 30 + d * Math.sin(s * Math.PI / 180), f = 30 + (d - t) * Math.cos(s * Math.PI / 180), g = 30 + (d - t) * Math.sin(s * Math.PI / 180);
|
|
23
|
+
return /* @__PURE__ */ o.jsx(
|
|
24
|
+
"line",
|
|
25
|
+
{
|
|
26
|
+
x1: u,
|
|
27
|
+
y1: v,
|
|
28
|
+
x2: f,
|
|
29
|
+
y2: g,
|
|
30
|
+
stroke: "var(--color-muted)",
|
|
31
|
+
strokeWidth: 1,
|
|
32
|
+
strokeLinecap: "round",
|
|
33
|
+
opacity: 0.7
|
|
34
|
+
},
|
|
35
|
+
`tick-${n}`
|
|
36
|
+
);
|
|
37
|
+
}),
|
|
38
|
+
[...Array(x)].map((_, n) => {
|
|
39
|
+
const s = M * n - 90 + e / 2, c = s + I, t = (j) => j * Math.PI / 180, u = 30 + r * Math.cos(t(s)), v = 30 + r * Math.sin(t(s)), f = 30 + h * Math.cos(t(s)), g = 30 + h * Math.sin(t(s)), E = 30 + h * Math.cos(t(c)), N = 30 + h * Math.sin(t(c)), p = 30 + r * Math.cos(t(c)), P = 30 + r * Math.sin(t(c)), A = n < Math.floor(a / 5);
|
|
40
|
+
return /* @__PURE__ */ o.jsx(
|
|
41
|
+
"path",
|
|
42
|
+
{
|
|
43
|
+
d: `M ${u} ${v} L ${f} ${g} L ${E} ${N} L ${p} ${P} Z`,
|
|
44
|
+
fill: A ? "var(--color-accent)" : "var(--color-border-default)",
|
|
45
|
+
style: {
|
|
46
|
+
filter: A ? "drop-shadow(0 0 6px var(--color-accent))" : "none",
|
|
47
|
+
transition: "fill 0.3s ease"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
`segment-${n}`
|
|
51
|
+
);
|
|
52
|
+
})
|
|
53
|
+
] }),
|
|
54
|
+
i && /* @__PURE__ */ o.jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: i })
|
|
55
|
+
] });
|
|
56
|
+
}, $ = {
|
|
57
|
+
sm: "h-3",
|
|
58
|
+
md: "h-5",
|
|
59
|
+
lg: "h-7",
|
|
60
|
+
xl: "h-9"
|
|
61
|
+
}, k = ({ progress: a, segments: l = 10, size: m = "md", className: i }) => {
|
|
62
|
+
const x = Math.round(Math.min(100, Math.max(0, a)) / 100 * l);
|
|
63
|
+
return /* @__PURE__ */ o.jsx("div", { className: y("flex gap-1 w-full", i), children: [...Array(l)].map((M, e) => {
|
|
64
|
+
const r = e < x;
|
|
65
|
+
return /* @__PURE__ */ o.jsx(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
className: y("flex-1 rounded-sm transition-all duration-300", $[m]),
|
|
69
|
+
style: {
|
|
70
|
+
backgroundColor: r ? "var(--color-accent)" : "var(--color-border-default)",
|
|
71
|
+
boxShadow: r ? "0 0 6px var(--color-accent)" : "none"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
e
|
|
75
|
+
);
|
|
76
|
+
}) });
|
|
77
|
+
}, L = (a) => a.variant === "block" ? /* @__PURE__ */ o.jsx(k, { ...a }) : /* @__PURE__ */ o.jsx(w, { ...a });
|
|
78
|
+
L.displayName = "CyberUI.SegmentedProgress";
|
|
79
|
+
export {
|
|
80
|
+
L as default
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=SegmentedProgress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SegmentedProgress.js","sources":["../../src/components/SegmentedProgress.tsx"],"sourcesContent":["import React from 'react';\r\nimport { cn } from '../utils/cn';\r\nimport { PROGRESS_CONFIG } from '../constants';\r\n\r\n// ── Shared ────────────────────────────────────────────────────────────────────\r\n\r\ntype Size = 'sm' | 'md' | 'lg' | 'xl';\r\n\r\nconst RADIAL_SIZE_MAP: Record<Size, string> = {\r\n sm: 'w-16 h-16',\r\n md: 'w-24 h-24',\r\n lg: 'w-32 h-32',\r\n xl: 'w-40 h-40',\r\n};\r\n\r\n// ── Discriminated union props ─────────────────────────────────────────────────\r\n\r\ninterface RadialProps {\r\n /**\r\n * Renders a **radial/circular** gauge — discrete arc segments arranged in a ring.\r\n * This is the original behaviour and the default.\r\n */\r\n variant?: 'radial';\r\n /** Size of the circular gauge. Sets width and height automatically.\r\n * - sm: 64px, md: 96px, lg: 128px, xl: 160px\r\n * @default 'md'\r\n */\r\n size?: Size;\r\n /** Optional content to render in the center of the gauge. */\r\n children?: React.ReactNode;\r\n /** Progress value (0–100). */\r\n progress: number;\r\n /** Optional custom class name. */\r\n className?: string;\r\n}\r\n\r\ninterface BlockProps {\r\n /**\r\n * Renders a **linear block bar** — discrete filled rectangles in a row\r\n * (think health bar or loading indicator divided into blocks: ▮▮▮▮▯▯).\r\n */\r\n variant: 'block';\r\n /**\r\n * Number of discrete blocks.\r\n * @default 10\r\n */\r\n segments?: number;\r\n /** Size controls block height.\r\n * - sm: h-3, md: h-5, lg: h-7, xl: h-9\r\n * @default 'md'\r\n */\r\n size?: Size;\r\n /** Progress value (0–100). */\r\n progress: number;\r\n /** Optional custom class name. */\r\n className?: string;\r\n children?: never;\r\n}\r\n\r\nexport type SegmentedProgressProps = RadialProps | BlockProps;\r\n\r\n// ── Radial variant (original) ─────────────────────────────────────────────────\r\n\r\n/**\r\n * A segmented progress indicator with two display modes.\r\n *\r\n * **Radial** (default) — circular gauge reminiscent of radar or power meters:\r\n * @example\r\n * <SegmentedProgress progress={45} size=\"md\">\r\n * <div className=\"text-primary font-bold\">LVL 4</div>\r\n * </SegmentedProgress>\r\n *\r\n * **Block** — linear discrete-block bar (▮▮▮▮▯▯), great for health bars or\r\n * step-based loading indicators:\r\n * @example\r\n * <SegmentedProgress variant=\"block\" progress={60} segments={10} size=\"md\" />\r\n */\r\nconst RadialProgress: React.FC<RadialProps> = ({ progress, size = 'md', className, children }) => {\r\n const {\r\n SEGMENT_COUNT,\r\n SEGMENT_ANGLE,\r\n GAP_ANGLE,\r\n INNER_RADIUS,\r\n OUTER_RADIUS,\r\n OUTER_TICK_RADIUS\r\n } = PROGRESS_CONFIG;\r\n\r\n const activeAngle = SEGMENT_ANGLE - GAP_ANGLE;\r\n\r\n return (\r\n <div className={cn('relative', RADIAL_SIZE_MAP[size], className)}>\r\n <svg className=\"w-full h-full\" viewBox=\"0 0 60 60\" style={{ overflow: 'visible' }}>\r\n {/* Outer tick marks */}\r\n {[...Array(60)].map((_, i) => {\r\n const angle = (360 / 60) * i;\r\n const isHourMark = i % 5 === 0;\r\n const lineLength = isHourMark ? 6 : 3;\r\n const x1 = 30 + OUTER_TICK_RADIUS * Math.cos((angle * Math.PI) / 180);\r\n const y1 = 30 + OUTER_TICK_RADIUS * Math.sin((angle * Math.PI) / 180);\r\n const x2 = 30 + (OUTER_TICK_RADIUS - lineLength) * Math.cos((angle * Math.PI) / 180);\r\n const y2 = 30 + (OUTER_TICK_RADIUS - lineLength) * Math.sin((angle * Math.PI) / 180);\r\n return (\r\n <line\r\n key={`tick-${i}`}\r\n x1={x1} y1={y1} x2={x2} y2={y2}\r\n stroke=\"var(--color-muted)\"\r\n strokeWidth={1}\r\n strokeLinecap=\"round\"\r\n opacity={0.7}\r\n />\r\n );\r\n })}\r\n\r\n {/* Progress segments */}\r\n {[...Array(SEGMENT_COUNT)].map((_, i) => {\r\n const angleStart = SEGMENT_ANGLE * i - 90 + GAP_ANGLE / 2;\r\n const angleEnd = angleStart + activeAngle;\r\n const toRad = (deg: number) => (deg * Math.PI) / 180;\r\n const x1 = 30 + INNER_RADIUS * Math.cos(toRad(angleStart));\r\n const y1 = 30 + INNER_RADIUS * Math.sin(toRad(angleStart));\r\n const x2 = 30 + OUTER_RADIUS * Math.cos(toRad(angleStart));\r\n const y2 = 30 + OUTER_RADIUS * Math.sin(toRad(angleStart));\r\n const x3 = 30 + OUTER_RADIUS * Math.cos(toRad(angleEnd));\r\n const y3 = 30 + OUTER_RADIUS * Math.sin(toRad(angleEnd));\r\n const x4 = 30 + INNER_RADIUS * Math.cos(toRad(angleEnd));\r\n const y4 = 30 + INNER_RADIUS * Math.sin(toRad(angleEnd));\r\n const isActive = i < Math.floor(progress / 5);\r\n return (\r\n <path\r\n key={`segment-${i}`}\r\n d={`M ${x1} ${y1} L ${x2} ${y2} L ${x3} ${y3} L ${x4} ${y4} Z`}\r\n fill={isActive ? 'var(--color-accent)' : 'var(--color-border-default)'}\r\n style={{\r\n filter: isActive ? 'drop-shadow(0 0 6px var(--color-accent))' : 'none',\r\n transition: 'fill 0.3s ease',\r\n }}\r\n />\r\n );\r\n })}\r\n </svg>\r\n {children && (\r\n <div className=\"absolute inset-0 flex items-center justify-center\">\r\n {children}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n};\r\n\r\n// ── Block variant (new) ───────────────────────────────────────────────────────\r\n\r\nconst BLOCK_HEIGHT_MAP: Record<Size, string> = {\r\n sm: 'h-3',\r\n md: 'h-5',\r\n lg: 'h-7',\r\n xl: 'h-9',\r\n};\r\n\r\nconst BlockProgress: React.FC<BlockProps> = ({ progress, segments = 10, size = 'md', className }) => {\r\n const activeCount = Math.round((Math.min(100, Math.max(0, progress)) / 100) * segments);\r\n\r\n return (\r\n <div className={cn('flex gap-1 w-full', className)}>\r\n {[...Array(segments)].map((_, i) => {\r\n const isActive = i < activeCount;\r\n return (\r\n <div\r\n key={i}\r\n className={cn('flex-1 rounded-sm transition-all duration-300', BLOCK_HEIGHT_MAP[size])}\r\n style={{\r\n backgroundColor: isActive ? 'var(--color-accent)' : 'var(--color-border-default)',\r\n boxShadow: isActive ? '0 0 6px var(--color-accent)' : 'none',\r\n }}\r\n />\r\n );\r\n })}\r\n </div>\r\n );\r\n};\r\n\r\n// ── Unified component ─────────────────────────────────────────────────────────\r\n\r\nconst SegmentedProgress: React.FC<SegmentedProgressProps> = (props) => {\r\n if (props.variant === 'block') {\r\n return <BlockProgress {...props} />;\r\n }\r\n return <RadialProgress {...props} />;\r\n};\r\n\r\nSegmentedProgress.displayName = \"CyberUI.SegmentedProgress\";\r\n\r\nexport default SegmentedProgress;\r\n"],"names":["RADIAL_SIZE_MAP","RadialProgress","progress","size","className","children","SEGMENT_COUNT","SEGMENT_ANGLE","GAP_ANGLE","INNER_RADIUS","OUTER_RADIUS","OUTER_TICK_RADIUS","PROGRESS_CONFIG","activeAngle","jsxs","cn","i","angle","lineLength","x1","y1","x2","y2","jsx","angleStart","angleEnd","toRad","deg","x3","y3","x4","y4","isActive","BLOCK_HEIGHT_MAP","BlockProgress","segments","activeCount","_","SegmentedProgress","props"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { j as r } from "../_virtual/jsx-runtime.js";
|
|
2
|
+
import { useId as M } from "react";
|
|
3
|
+
import { getResponsiveClasses as P, RESPONSIVE_SIZE_MAPS as V } from "../utils/responsive.js";
|
|
4
|
+
import { cn as a } from "../utils/cn.js";
|
|
5
|
+
const _ = ({
|
|
6
|
+
label: n,
|
|
7
|
+
size: i = "md",
|
|
8
|
+
variant: u = "primary",
|
|
9
|
+
options: f,
|
|
10
|
+
placeholder: c,
|
|
11
|
+
helperText: l,
|
|
12
|
+
error: s,
|
|
13
|
+
className: m = "",
|
|
14
|
+
disabled: t = !1,
|
|
15
|
+
id: x,
|
|
16
|
+
name: b,
|
|
17
|
+
onValueChange: g,
|
|
18
|
+
onChange: p,
|
|
19
|
+
...h
|
|
20
|
+
}) => {
|
|
21
|
+
const v = (e) => {
|
|
22
|
+
p?.(e), g?.(e.target.value);
|
|
23
|
+
}, y = M(), o = x || y, j = b || o, w = (e) => P(e, V.input), C = (e, E, z) => {
|
|
24
|
+
if (E)
|
|
25
|
+
return "bg-base border-2 border-border-default/30 text-muted/50 cursor-not-allowed opacity-50";
|
|
26
|
+
if (z)
|
|
27
|
+
return "bg-surface border-2 border-error text-default focus:ring-2 focus:ring-error focus:border-error shadow-error";
|
|
28
|
+
const d = {
|
|
29
|
+
primary: "bg-surface border-2 border-border-default text-default focus:ring-2 focus:ring-primary focus:border-primary shadow-primary",
|
|
30
|
+
secondary: "bg-surface border-2 border-secondary text-default focus:ring-2 focus:ring-secondary focus:border-secondary shadow-secondary/30",
|
|
31
|
+
danger: "bg-surface border-2 border-error text-default focus:ring-2 focus:ring-error focus:border-error shadow-error/30",
|
|
32
|
+
ghost: "bg-base border-2 border-accent/20 text-default focus:ring-2 focus:ring-accent focus:border-accent shadow-secondary"
|
|
33
|
+
};
|
|
34
|
+
return d[e] || d.primary;
|
|
35
|
+
}, N = a(
|
|
36
|
+
"appearance-none w-full rounded-lg font-mono transition-all duration-300 focus:outline-none px-4 pr-10",
|
|
37
|
+
w(i),
|
|
38
|
+
C(u, t, !!s),
|
|
39
|
+
m
|
|
40
|
+
), S = "relative w-full", I = a(
|
|
41
|
+
"block text-sm font-medium mb-2 transition-colors duration-200",
|
|
42
|
+
t ? "text-muted opacity-50" : s ? "text-error" : "text-default"
|
|
43
|
+
), R = a("mt-2 text-xs transition-colors duration-200", s ? "text-error" : "text-muted");
|
|
44
|
+
return /* @__PURE__ */ r.jsxs("div", { className: "w-full", children: [
|
|
45
|
+
n && /* @__PURE__ */ r.jsx("label", { htmlFor: o, className: I, children: n }),
|
|
46
|
+
/* @__PURE__ */ r.jsxs("div", { className: S, children: [
|
|
47
|
+
/* @__PURE__ */ r.jsxs(
|
|
48
|
+
"select",
|
|
49
|
+
{
|
|
50
|
+
className: N,
|
|
51
|
+
disabled: t,
|
|
52
|
+
id: o,
|
|
53
|
+
name: j,
|
|
54
|
+
onChange: v,
|
|
55
|
+
...h,
|
|
56
|
+
children: [
|
|
57
|
+
c && /* @__PURE__ */ r.jsx("option", { value: "", disabled: !0, children: c }),
|
|
58
|
+
f.map((e) => /* @__PURE__ */ r.jsx(
|
|
59
|
+
"option",
|
|
60
|
+
{
|
|
61
|
+
value: e.value,
|
|
62
|
+
disabled: e.disabled,
|
|
63
|
+
className: "bg-surface text-default",
|
|
64
|
+
children: e.label
|
|
65
|
+
},
|
|
66
|
+
e.value
|
|
67
|
+
))
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
),
|
|
71
|
+
/* @__PURE__ */ r.jsx(
|
|
72
|
+
"div",
|
|
73
|
+
{
|
|
74
|
+
className: `pointer-events-none absolute inset-y-0 right-0 flex items-center px-3 ${t ? "text-muted/50" : s ? "text-error" : "text-accent"}`,
|
|
75
|
+
children: /* @__PURE__ */ r.jsx("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ r.jsx(
|
|
76
|
+
"path",
|
|
77
|
+
{
|
|
78
|
+
fillRule: "evenodd",
|
|
79
|
+
d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z",
|
|
80
|
+
clipRule: "evenodd"
|
|
81
|
+
}
|
|
82
|
+
) })
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
] }),
|
|
86
|
+
(l || s) && /* @__PURE__ */ r.jsx("div", { className: R, children: s || l })
|
|
87
|
+
] });
|
|
88
|
+
};
|
|
89
|
+
_.displayName = "CyberUI.Select";
|
|
90
|
+
export {
|
|
91
|
+
_ as default
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=Select.js.map
|